# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. # # Copyright (c) 2018, Joyent, Inc. PROG= expr XPG4PROG= expr XPG6PROG= expr EXPROBJ= exprobjs/expr.o exprobjs/compile.o XPG4EXPROBJ= exprobjs.xpg4/expr.o exprobjs.xpg4/compile.o XPG6EXPROBJ= exprobjs.xpg6/expr.o exprobjs.xpg6/compile.o OBJS= $(EXPROBJ) $(XPG4EXPROBJ) $(XPG6EXPROBJ) SRCS= expr.c compile.c include ../Makefile.cmd include ../Makefile.essbin CFLAGS += $(CCVERBOSE) CERRWARN += $(CNOWARN_UNINIT) CERRWARN += -Wno-extra # "missing type for func" SMATCH=off $(XPG4) : CFLAGS += -DXPG4 $(XPG6) : CFLAGS += -DXPG6 XGETFLAGS += -a -x expr.xcl LDLIBS += -lgen MAPFILES = $(MAPFILE.INT) $(MAPFILE.NGB) LDFLAGS += $(MAPFILES:%=-Wl,-M%) .KEEP_STATE: all: $(PROG) $(XPG4) $(XPG6) install: all $(ROOTPROG) $(ROOTXPG4PROG) $(ROOTXPG6PROG) $(ROOTUSRBINLINKS) $(PROG): exprobjs $(EXPROBJ) $(MAPFILES) $(LINK.c) $(EXPROBJ) -o $@ $(LDLIBS) $(POST_PROCESS) $(XPG4): exprobjs.xpg4 $(XPG4EXPROBJ) $(MAPFILES) $(LINK.c) $(XPG4EXPROBJ) -o $@ $(LDLIBS) $(POST_PROCESS) $(XPG6): exprobjs.xpg6 $(XPG6EXPROBJ) $(MAPFILES) $(LINK.c) $(XPG6EXPROBJ) -o $@ $(LDLIBS) $(POST_PROCESS) exprobjs/%.o: %.c $(COMPILE.c) -o $@ $< exprobjs.xpg4/%.o: %.c $(COMPILE.c) -o $@ $< exprobjs.xpg6/%.o: %.c $(COMPILE.c) -o $@ $< exprobjs: -@mkdir -p $@ exprobjs.xpg4: -@mkdir -p $@ exprobjs.xpg6: -@mkdir -p $@ clean: $(RM) $(OBJS) include ../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 1995-2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright (c) 2016 by Delphix. All rights reserved. */ /* * xcompile, xstep, xadvance: simulate compile(3gen), step(3gen), advance(3gen) * using regcomp(3c), regexec(3c) interfaces. This is an XCU4 * porting aid. switches out to libgen compile/step if collation * table not present. * * Goal is to work with vi and sed/ed. * Returns expbuf in dhl format (encoding of first two bytes). * Note also that this is profoundly single threaded. You * cannot call compile twice with two separate search strings * because the second call will wipe out the earlier stored string. * This must be fixed, plus a general cleanup should be performed * if this is to be integrated into libc. * */ #include #include #include #include #include #include #include #include #include #include /* * psuedo compile/step/advance global variables */ extern int nbra; extern char *locs; /* for stopping execess recursion */ extern char *loc1; /* 1st character which matched RE */ extern char *loc2; /* char after lst char in matched RE */ extern char *braslist[]; /* start of nbra subexp */ extern char *braelist[]; /* end of nbra subexp */ extern int regerrno; extern int reglength; int regcomp_flags; /* interface to specify cflags for regcomp */ void regex_comp_free(void *a); static int dhl_step(const char *str, const char *ep); static int dhl_advance(const char *str, const char *ep); static int map_errnos(int); /* Convert regcomp error */ static int dhl_doit(const char *, const regex_t *, const int flags); static char *dhl_compile(const char *instr, char *ep, char *endbuf); /* * # of sub re's: NOTE: For now limit on bra list defined here * but fix is to add maxbra define to to regex.h * One problem is that a bigger number is a performance hit since * regexec() has a slow initialization loop that goes around SEPSIZE times */ #define SEPSIZE 20 static regmatch_t rm[SEPSIZE]; /* ptr to list of RE matches */ /* * Structure to contain dl encoded first two bytes for vi, plus hold two * regex structures, one for advance and one for step. */ static struct regex_comp { char r_head[2]; /* Header for DL encoding for vi */ regex_t r_stp; /* For use by step */ regex_t r_adv; /* For use by advance */ } reg_comp; /* * global value for the size of a regex_comp structure: */ size_t regexc_size = sizeof (reg_comp); char * compile(const char *instr, char *expbuf, char *endbuf) { return (dhl_compile(instr, expbuf, endbuf)); } int step(const char *instr, const char *expbuf) { return (dhl_step(instr, expbuf)); } int advance(const char *instr, const char *expbuf) { return (dhl_advance(instr, expbuf)); } /* * the compile and step routines here simulate the old libgen routines of * compile/step Re: regexpr(3GEN). in order to do this, we must assume * that expbuf[] consists of the following format: * 1) the first two bytes consist of a special encoding - see below. * 2) the next part is a regex_t used by regexec()/regcomp() for step * 3) the final part is a regex_t used by regexec()/regcomp() for advance * * the special encoding of the first two bytes is referenced throughout * vi. apparently expbuf[0] is set to: * = 0 upon initialization * = 1 if the first char of the RE is a ^ * = 0 if the first char of the RE isn't a ^ * and expbuf[1-35+] = bitmap of the type of RE chars in the expression. * this is apparently 0 if there's no RE. * Here, we use expbuf[0] in a similar fashion; and expbuf[1] is non-zero * if there's at least 1 RE in the string. * I say "apparently" as the code to compile()/step() is poorly written. */ static char * dhl_compile(const char *instr, /* the regular expression */ char *expbuf, /* where the compiled RE gets placed */ char *endbuf) /* ending addr of expbuf */ { int rv; int alloc = 0; char adv_instr[4096]; /* PLENTY big temp buffer */ char *instrp; /* PLENTY big temp buffer */ if (*instr == '\0') { regerrno = 41; return (NULL); } /* * Check values of expbuf and endbuf */ if (expbuf == NULL) { if ((expbuf = malloc(regexc_size)) == NULL) { regerrno = 50; return (NULL); } memset(®_comp, 0, regexc_size); alloc = 1; endbuf = expbuf + regexc_size; } else { /* Check if enough memory was allocated */ if (expbuf + regexc_size > endbuf) { regerrno = 50; return (NULL); } memcpy(®_comp, expbuf, regexc_size); } /* * Clear global flags */ nbra = 0; regerrno = 0; /* * Free any data being held for previous search strings */ regex_comp_free(®_comp); /* * We call regcomp twice, once to get a regex_t for use by step() * and then again with for use by advance() */ if ((rv = regcomp(®_comp.r_stp, instr, regcomp_flags)) != 0) { regerrno = map_errnos(rv); /* Convert regcomp error */ goto out; } /* * To support advance, which assumes an implicit ^ to match at start * of line we prepend a ^ to the pattern by copying to a temp buffer */ if (instr[0] == '^') instrp = (char *)instr; /* String already has leading ^ */ else { adv_instr[0] = '^'; strncpy(&adv_instr[1], instr, 2048); instrp = adv_instr; } if ((rv = regcomp(®_comp.r_adv, instrp, regcomp_flags)) != 0) { regerrno = map_errnos(rv); /* Convert regcomp error */ goto out; } /* * update global variables */ nbra = (int)reg_comp.r_adv.re_nsub > 0 ? (int)reg_comp.r_adv.re_nsub : 0; regerrno = 0; /* * Set the header flags for use by vi */ if (instr[0] == '^') /* if beginning of string, */ reg_comp.r_head[0] = 1; /* set special flag */ else reg_comp.r_head[0] = 0; /* clear special flag */ /* * note that for a single BRE, nbra will be 0 here. * we're guaranteed that, at this point, a RE has been found. */ reg_comp.r_head[1] = 1; /* set special flag */ /* * Copy our reg_comp structure to expbuf */ (void) memcpy(expbuf, (char *)®_comp, regexc_size); out: /* * Return code from libgen regcomp with mods. Note weird return * value - if space is malloc'd return pointer to start of space, * if user provided their own space, return pointer to 1+last byte * of that space. */ if (regerrno != 0) { if (alloc) free(expbuf); return (NULL); } reglength = regexc_size; if (alloc) return (expbuf); else return (expbuf + regexc_size); } /* * dhl_step: step through a string until a RE match is found, or end of str */ static int dhl_step(const char *str, /* characters to be checked for a match */ const char *ep) /* compiled RE from dhl_compile() */ { /* * Check if we're passed a null ep */ if (ep == NULL) { regerrno = 41; /* No remembered search string error */ return (0); } /* * Call common routine with r_stp (step) structure */ return (dhl_doit(str, &(((struct regex_comp *)ep)->r_stp), ((locs != NULL) ? REG_NOTBOL : 0))); } /* * dhl_advance: implement advance */ static int dhl_advance(const char *str, /* characters to be checked for a match */ const char *ep) /* compiled RE from dhl_compile() */ { int rv; /* * Check if we're passed a null ep */ if (ep == NULL) { regerrno = 41; /* No remembered search string error */ return (0); } /* * Call common routine with r_adv (advance) structure */ rv = dhl_doit(str, &(((struct regex_comp *)ep)->r_adv), 0); loc1 = NULL; /* Clear it per the compile man page */ return (rv); } /* * dhl_doit - common code for step and advance */ static int dhl_doit(const char *str, /* characters to be checked for a match */ const regex_t *rep, const int flags) /* flags to be passed to regexec directly */ { int rv; int i; regmatch_t *prm; /* ptr to current regmatch_t */ /* * Check if we're passed a null regex_t */ if (rep == NULL) { regerrno = 41; /* No remembered search string error */ return (0); } regerrno = 0; prm = &rm[0]; if ((rv = regexec(rep, str, SEPSIZE, prm, flags)) != REG_OK) { if (rv == REG_NOMATCH) return (0); regerrno = map_errnos(rv); return (0); } loc1 = (char *)str + prm->rm_so; loc2 = (char *)str + prm->rm_eo; /* * Now we need to fill up the bra lists with all of the sub re's * Note we subtract nsub -1, and preincrement prm. */ for (i = 0; i <= rep->re_nsub; i++) { prm++; /* XXX inc past first subexp */ braslist[i] = (char *)str + prm->rm_so; braelist[i] = (char *)str + prm->rm_eo; if (i >= SEPSIZE) { regerrno = 50; /* regex overflow */ return (0); } } /* * Inverse logic, a zero from regexec - success, is a 1 * from advance/step. */ return (rv == 0); } /* * regerrno to compile/step error mapping: * This is really a big compromise. Some errors don't map at all * like regcomp error 15 is generated by both compile() error types * 44 & 46. So which one should we map to? * Note REG_ESUB Can't happen- 9 is no longer max num of subexpressions * To do your errors right use xregerr() to get the regcomp error * string and print that. * * | regcomp/regexec | Compile/step/advance | * +---------------------------------+--------------------------------------+ * 0 REG_OK Pattern matched 1 - Pattern matched * 1 REG_NOMATCH No match 0 - Pattern didn't match * 2 REG_ECOLLATE Bad collation elmnt. 67 - Returned by compile on mbtowc err * 3 REG_EESCAPE trailing \ in patrn 45 - } expected after \. * 4 REG_ENEWLINE \n before end pattrn 36 - Illegal or missing delimiter. * 5 REG_ENSUB Over 9 \( \) pairs 43 - Too many \( * 6 REG_ESUBREG Bad number in \[0-9] 25 - ``\digit'' out of range. * 7 REG_EBRACK [ ] inbalance 49 - [ ] imbalance. * 8 REG_EPAREN ( ) inbalance 42 - \(~\) imbalance. * 9 REG_EBRACE \{ \} inbalance 45 - } expected after \. * 10 REG_ERANGE bad range endpoint 11 - Range endpoint too large. * 11 REG_ESPACE no memory for pattern 50 - Regular expression overflow. * 12 REG_BADRPT invalid repetition 36 - Illegal or missing delimiter. * 13 REG_ECTYPE invalid char-class 67 - illegal byte sequence * 14 REG_BADPAT syntax error 50 - Regular expression overflow. * 15 REG_BADBR \{ \} contents bad 46 - First number exceeds 2nd in \{~\} * 16 REG_EFATAL internal error 50 - Regular expression overflow. * 17 REG_ECHAR bad mulitbyte char 67 - illegal byte sequence * 18 REG_STACK stack overflow 50 - Regular expression overflow. * 19 REG_ENOSYS function not supported 50- Regular expression overflow. * * For reference here's the compile/step errno's. We don't generate * 41 here - it's done earlier, nor 44 since we can't tell if from 46. * * 11 - Range endpoint too large. * 16 - Bad number. * 25 - ``\digit'' out of range. * 36 - Illegal or missing delimiter. * 41 - No remembered search string. * 42 - \(~\) imbalance. * 43 - Too many \(. * 44 - More than 2 numbers given in "\{~\}" * 45 - } expected after \. * 46 - First number exceeds 2nd in "\{~\}" * 49 - [ ] imbalance. * 50 - Regular expression overflow. */ static int map_errnos(int Errno) { switch (Errno) { case REG_ECOLLATE: regerrno = 67; break; case REG_EESCAPE: regerrno = 45; break; case REG_ENEWLINE: regerrno = 36; break; case REG_ENSUB: regerrno = 43; break; case REG_ESUBREG: regerrno = 25; break; case REG_EBRACK: regerrno = 49; break; case REG_EPAREN: regerrno = 42; break; case REG_EBRACE: regerrno = 45; break; case REG_ERANGE: regerrno = 11; break; case REG_ESPACE: regerrno = 50; break; case REG_BADRPT: regerrno = 36; break; case REG_ECTYPE: regerrno = 67; break; case REG_BADPAT: regerrno = 50; break; case REG_BADBR: regerrno = 46; break; case REG_EFATAL: regerrno = 50; break; case REG_ECHAR: regerrno = 67; break; case REG_STACK: regerrno = 50; break; case REG_ENOSYS: regerrno = 50; break; default: regerrno = 50; break; } return (regerrno); } /* * This is a routine to clean up the subtle substructure of the struct * regex_comp type for use by clients of this module. Since the struct * type is private, we use a generic interface, and trust the * application to be damn sure that this operation is valid for the * named memory. */ void regex_comp_free(void *a) { /* * Free any data being held for previous search strings */ if (a == NULL) { return; } regfree(&((struct regex_comp *)a)->r_stp); regfree(&((struct regex_comp *)a)->r_adv); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #define A_STRING 258 #define NOARG 259 #define OR 260 #define AND 261 #define EQ 262 #define LT 263 #define GT 264 #define GEQ 265 #define LEQ 266 #define NEQ 267 #define ADD 268 #define SUBT 269 #define MULT 270 #define DIV 271 #define REM 272 #define MCH 273 #define MATCH 274 #define SUBSTR 275 #define LENGTH 276 #define INDEX 277 /* size of subexpression array */ #define MSIZE LINE_MAX #define error(c) errxx() #define EQL(x, y) (strcmp(x, y) == 0) #define ERROR(c) errxx() #define MAX_MATCH 20 static int ematch(char *, char *); static void yyerror(char *); static void errxx(); static void *exprmalloc(size_t size); static char *ltoa(); static char *lltoa(); static char **Av; static char *buf; static int Ac; static int Argi; static int noarg; static int paren; /* * Array used to store subexpressions in regular expressions * Only one subexpression allowed per regular expression currently */ static char Mstring[1][MSIZE]; static char *operator[] = { "|", "&", "+", "-", "*", "/", "%", ":", "=", "==", "<", "<=", ">", ">=", "!=", "match", "substr", "length", "index", "\0" }; static int op[] = { OR, AND, ADD, SUBT, MULT, DIV, REM, MCH, EQ, EQ, LT, LEQ, GT, GEQ, NEQ, MATCH, SUBSTR, LENGTH, INDEX }; static int pri[] = { 1, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6, 7, 7, 7, 7 }; /* * clean_buf - XCU4 mod to remove leading zeros from negative signed * numeric output, e.g., -00001 becomes -1 */ static void clean_buf(char *buf) { int i = 0; int is_a_num = 1; int len; long long num; if (buf[0] == '\0') return; len = strlen(buf); if (len <= 0) return; if (buf[0] == '-') { i++; /* Skip the leading '-' see while loop */ if (len <= 1) /* Is it a '-' all by itself? */ return; /* Yes, so return */ while (i < len) { if (! isdigit(buf[i])) { is_a_num = 0; break; } i++; } if (is_a_num) { (void) sscanf(buf, "%lld", &num); (void) sprintf(buf, "%lld", num); } } } /* * End XCU4 mods. */ static int yylex(void) { char *p; int i; if (Argi >= Ac) return (NOARG); p = Av[Argi]; if ((*p == '(' || *p == ')') && p[1] == '\0') return ((int)*p); for (i = 0; *operator[i]; ++i) if (EQL(operator[i], p)) return (op[i]); return (A_STRING); } static char * rel(int oper, char *r1, char *r2) { long long i, l1, l2; if (ematch(r1, "-\\{0,1\\}[0-9]*$") && ematch(r2, "-\\{0,1\\}[0-9]*$")) { errno = 0; l1 = strtoll(r1, (char **)NULL, 10); l2 = strtoll(r2, (char **)NULL, 10); if (errno) { #ifdef XPG6 /* XPG6: stdout will always contain newline even on error */ (void) write(1, "\n", 1); #endif if (errno == ERANGE) { (void) fprintf(stderr, gettext( "expr: Integer argument too large\n")); exit(3); } else { perror("expr"); exit(3); } } switch (oper) { case EQ: i = (l1 == l2); break; case GT: i = (l1 > l2); break; case GEQ: i = (l1 >= l2); break; case LT: i = (l1 < l2); break; case LEQ: i = (l1 <= l2); break; case NEQ: i = (l1 != l2); break; } } else { i = strcoll(r1, r2); switch (oper) { case EQ: i = i == 0; break; case GT: i = i > 0; break; case GEQ: i = i >= 0; break; case LT: i = i < 0; break; case LEQ: i = i <= 0; break; case NEQ: i = i != 0; break; } } return (i ? "1": "0"); } static char * arith(int oper, char *r1, char *r2) { long long i1, i2; char *rv; if (!(ematch(r1, "-\\{0,1\\}[0-9]*$") && ematch(r2, "-\\{0,1\\}[0-9]*$"))) yyerror("non-numeric argument"); errno = 0; i1 = strtoll(r1, (char **)NULL, 10); i2 = strtoll(r2, (char **)NULL, 10); if (errno) { #ifdef XPG6 /* XPG6: stdout will always contain newline even on error */ (void) write(1, "\n", 1); #endif if (errno == ERANGE) { (void) fprintf(stderr, gettext( "expr: Integer argument too large\n")); exit(3); } else { perror("expr"); exit(3); } } switch (oper) { case ADD: i1 = i1 + i2; break; case SUBT: i1 = i1 - i2; break; case MULT: i1 = i1 * i2; break; case DIV: if (i2 == 0) yyerror("division by zero"); i1 = i1 / i2; break; case REM: if (i2 == 0) yyerror("division by zero"); i1 = i1 % i2; break; } rv = exprmalloc(25); (void) strcpy(rv, lltoa(i1)); return (rv); } static char *conj(int oper, char *r1, char *r2) { char *rv; switch (oper) { case OR: if (EQL(r1, "0") || EQL(r1, "")) { if (EQL(r2, "0") || EQL(r2, "")) rv = "0"; else rv = r2; } else rv = r1; break; case AND: if (EQL(r1, "0") || EQL(r1, "")) rv = "0"; else if (EQL(r2, "0") || EQL(r2, "")) rv = "0"; else rv = r1; break; } return (rv); } char * substr(char *v, char *s, char *w) { int si, wi; char *res; si = atol(s); wi = atol(w); while (--si) if (*v) ++v; res = v; while (wi--) if (*v) ++v; *v = '\0'; return (res); } char * index(char *s, char *t) { long i, j; char *rv; for (i = 0; s[i]; ++i) for (j = 0; t[j]; ++j) if (s[i] == t[j]) { (void) strcpy(rv = exprmalloc(8), ltoa(++i)); return (rv); } return ("0"); } char * length(char *s) { long i = 0; char *rv; while (*s++) ++i; rv = exprmalloc(8); (void) strcpy(rv, ltoa(i)); return (rv); } static char * match(char *s, char *p) { char *rv; long val; /* XCU4 */ (void) strcpy(rv = exprmalloc(8), ltoa(val = (long)ematch(s, p))); if (nbra /* && val != 0 */) { rv = exprmalloc((unsigned)strlen(Mstring[0]) + 1); (void) strcpy(rv, Mstring[0]); } return (rv); } /* * ematch - XCU4 mods involve calling compile/advance which simulate * the obsolete compile/advance functions using regcomp/regexec */ static int ematch(char *s, char *p) { static char *expbuf; char *nexpbuf; int num; #ifdef XPG4 int nmatch; /* number of matched bytes */ char tempbuf[256]; char *tmptr1 = 0; /* If tempbuf is not large enough */ char *tmptr; int nmbchars; /* number characters in multibyte string */ #endif nexpbuf = compile(p, (char *)0, (char *)0); /* XCU4 regex mod */ if (0 /* XXX nbra > 1*/) yyerror("Too many '\\('s"); if (regerrno) { if (regerrno != 41 || expbuf == NULL) errxx(); } else { if (expbuf) free(expbuf); expbuf = nexpbuf; } if (advance(s, expbuf)) { if (nbra > 0) { p = braslist[0]; num = braelist[0] - p; if ((num > MSIZE - 1) || (num < 0)) yyerror("string too long"); (void) strncpy(Mstring[0], p, num); Mstring[0][num] = '\0'; } #ifdef XPG4 /* * Use mbstowcs to find the number of multibyte characters * in the multibyte string beginning at s, and * ending at loc2. Create a separate string * of the substring, so it can be passed to mbstowcs. */ nmatch = loc2 - s; if (nmatch > ((sizeof (tempbuf) / sizeof (char)) - 1)) { tmptr1 = exprmalloc(nmatch + 1); tmptr = tmptr1; } else { tmptr = tempbuf; } memcpy(tmptr, s, nmatch); *(tmptr + nmatch) = '\0'; if ((nmbchars = mbstowcs(NULL, tmptr, 0)) == -1) { yyerror("invalid multibyte character encountered"); if (tmptr1 != NULL) free(tmptr1); return (0); } if (tmptr1 != NULL) free(tmptr1); return (nmbchars); #else return (loc2-s); #endif } return (0); } static void errxx() { yyerror("RE error"); } static void yyerror(char *s) { #ifdef XPG6 /* XPG6: stdout will always contain newline even on error */ (void) write(1, "\n", 1); #endif (void) write(2, "expr: ", 6); (void) write(2, gettext(s), (unsigned)strlen(gettext(s))); (void) write(2, "\n", 1); exit(2); /* NOTREACHED */ } static char * ltoa(long l) { static char str[20]; char *sp = &str[18]; /* u370 */ int i; int neg = 0; if ((unsigned long)l == 0x80000000UL) return ("-2147483648"); if (l < 0) ++neg, l = -l; str[19] = '\0'; do { i = l % 10; *sp-- = '0' + i; l /= 10; } while (l); if (neg) *sp-- = '-'; return (++sp); } static char * lltoa(long long l) { static char str[25]; char *sp = &str[23]; int i; int neg = 0; if (l == 0x8000000000000000ULL) return ("-9223372036854775808"); if (l < 0) ++neg, l = -l; str[24] = '\0'; do { i = l % 10; *sp-- = '0' + i; l /= 10; } while (l); if (neg) *sp-- = '-'; return (++sp); } static char * expres(int prior, int par) { int ylex, temp, op1; char *r1, *ra, *rb, *rc; ylex = yylex(); if (ylex >= NOARG && ylex < MATCH) { yyerror("syntax error"); } if (ylex == A_STRING) { r1 = Av[Argi++]; temp = Argi; } else { if (ylex == '(') { paren++; Argi++; r1 = expres(0, Argi); Argi--; } } lop: ylex = yylex(); if (ylex > NOARG && ylex < MATCH) { op1 = ylex; Argi++; if (pri[op1-OR] <= prior) return (r1); else { switch (op1) { case OR: case AND: r1 = conj(op1, r1, expres(pri[op1-OR], 0)); break; case EQ: case LT: case GT: case LEQ: case GEQ: case NEQ: r1 = rel(op1, r1, expres(pri[op1-OR], 0)); break; case ADD: case SUBT: case MULT: case DIV: case REM: r1 = arith(op1, r1, expres(pri[op1-OR], 0)); break; case MCH: r1 = match(r1, expres(pri[op1-OR], 0)); break; } if (noarg == 1) { return (r1); } Argi--; goto lop; } } ylex = yylex(); if (ylex == ')') { if (par == Argi) { yyerror("syntax error"); } if (par != 0) { paren--; Argi++; } Argi++; return (r1); } ylex = yylex(); if (ylex > MCH && ylex <= INDEX) { if (Argi == temp) { return (r1); } op1 = ylex; Argi++; switch (op1) { case MATCH: rb = expres(pri[op1-OR], 0); ra = expres(pri[op1-OR], 0); break; case SUBSTR: rc = expres(pri[op1-OR], 0); rb = expres(pri[op1-OR], 0); ra = expres(pri[op1-OR], 0); break; case LENGTH: ra = expres(pri[op1-OR], 0); break; case INDEX: rb = expres(pri[op1-OR], 0); ra = expres(pri[op1-OR], 0); break; } switch (op1) { case MATCH: r1 = match(rb, ra); break; case SUBSTR: r1 = substr(rc, rb, ra); break; case LENGTH: r1 = length(ra); break; case INDEX: r1 = index(rb, ra); break; } if (noarg == 1) { return (r1); } Argi--; goto lop; } ylex = yylex(); if (ylex == NOARG) { noarg = 1; } return (r1); } void * exprmalloc(size_t size) { void *rv; if ((rv = malloc(size)) == NULL) { char *s = gettext("malloc error"); (void) write(2, "expr: ", 6); (void) write(2, s, (unsigned)strlen(s)); (void) write(2, "\n", 1); exit(3); } return (rv); } int main(int argc, char **argv) { /* * XCU4 allow "--" as argument */ if (argc > 1 && strcmp(argv[1], "--") == 0) argv++, argc--; /* * XCU4 - print usage message when invoked without args */ if (argc < 2) { #ifdef XPG6 /* XPG6: stdout will always contain newline even on error */ (void) write(1, "\n", 1); #endif (void) fprintf(stderr, gettext("Usage: expr expression\n")); exit(3); } Ac = argc; Argi = 1; noarg = 0; paren = 0; Av = argv; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); buf = expres(0, 1); if (Ac != Argi || paren != 0) { yyerror("syntax error"); } /* * XCU4 - strip leading zeros from numeric output */ clean_buf(buf); (void) write(1, buf, (unsigned)strlen(buf)); (void) write(1, "\n", 1); return ((strcmp(buf, "0") == 0 || buf[0] == 0) ? 1 : 0); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # msgid "" msgid "!=" msgid "%" msgid "&" msgid "*" msgid "+" msgid "-" msgid "-2147483648" msgid "-\\{0,1\\}[0-9]*$" msgid "/" msgid "0" msgid "1" msgid ":" msgid "<" msgid "<=" msgid "=" msgid "==" msgid ">" msgid ">=" msgid "\0" msgid "\n" msgid "expr: " msgid "match" msgid "|" # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 # expr provides its own versions of advance, compile, and step - define # these explicitly as interposers. SYMBOL_SCOPE { global: advance { FLAGS = INTERPOSE }; compile { FLAGS = INTERPOSE }; step { FLAGS = INTERPOSE }; };