1da2e3ebdSchin /*********************************************************************** 2da2e3ebdSchin * * 3da2e3ebdSchin * This software is part of the ast package * 4*7c2fbfb3SApril Chin * Copyright (c) 1992-2008 AT&T Intellectual Property * 5da2e3ebdSchin * and is licensed under the * 6da2e3ebdSchin * Common Public License, Version 1.0 * 7*7c2fbfb3SApril Chin * by AT&T Intellectual Property * 8da2e3ebdSchin * * 9da2e3ebdSchin * A copy of the License is available at * 10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt * 11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12da2e3ebdSchin * * 13da2e3ebdSchin * Information and Software Systems Research * 14da2e3ebdSchin * AT&T Research * 15da2e3ebdSchin * Florham Park NJ * 16da2e3ebdSchin * * 17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> * 18da2e3ebdSchin * David Korn <dgk@research.att.com> * 19da2e3ebdSchin * * 20da2e3ebdSchin ***********************************************************************/ 21da2e3ebdSchin #pragma prototyped 22da2e3ebdSchin 23da2e3ebdSchin /* 24da2e3ebdSchin * expr.c 25da2e3ebdSchin * Written by David Korn 26da2e3ebdSchin * Tue Oct 31 08:48:11 EST 1995 27da2e3ebdSchin */ 28da2e3ebdSchin 29da2e3ebdSchin static const char usage[] = 30*7c2fbfb3SApril Chin "[-?\n@(#)$Id: expr (AT&T Research) 2008-01-30 $\n]" 31da2e3ebdSchin USAGE_LICENSE 32da2e3ebdSchin "[+NAME?expr - evaluate arguments as an expression]" 33da2e3ebdSchin "[+DESCRIPTION?\bexpr\b evaluates an expression given as arguments and writes " 34da2e3ebdSchin "the result to standard output. The character \b0\b will be written " 35da2e3ebdSchin "to indicate a zero value and nothing will be written to indicate an " 36da2e3ebdSchin "empty string.]" 37da2e3ebdSchin "[+?Most of the functionality of \bexpr\b is provided in a more natural " 38da2e3ebdSchin "way by the shell, \bsh\b(1), and \bexpr\b is provided primarily " 39da2e3ebdSchin "for backward compatibility.]" 40da2e3ebdSchin "[+?Terms of the expression must be separate arguments. A string argument is " 41da2e3ebdSchin "one that can not be identified as an integer. Integer-valued " 42da2e3ebdSchin "arguments may be preceded by a unary plus or minus sign. Because " 43da2e3ebdSchin "many of the operators use characters that have special meaning to " 44da2e3ebdSchin "the shell, they must be quoted when entered from the shell.]" 45da2e3ebdSchin 46da2e3ebdSchin "[+?Expressions are formed from the operators listed below in order " 47da2e3ebdSchin "of increasing precedence within groups. All of the operators are " 48da2e3ebdSchin "left associative. The symbols \aexpr1\a and \aexpr2\a represent " 49da2e3ebdSchin "expressions formed from strings and integers and the following " 50da2e3ebdSchin "operators:]{" 51da2e3ebdSchin "[+\aexpr1\a \b|\b \aexpr2\a?Returns the evaluation of \aexpr1\a if " 52da2e3ebdSchin "it is neither null nor 0, otherwise returns the evaluation of expr2.]" 53da2e3ebdSchin 54da2e3ebdSchin "[+\aexpr1\a \b&\b \aexpr2\a?Returns the evaluation of \aexpr1\a if " 55da2e3ebdSchin "neither expression evaluates to null or 0, otherwise returns 0.]" 56da2e3ebdSchin 57da2e3ebdSchin "[+\aexpr1\a \aop\a \aexpr2\a?Returns the result of a decimal integer " 58da2e3ebdSchin "comparison if both arguments are integers; otherwise, returns the " 59da2e3ebdSchin "result of a string comparison using the locale-specific collation " 60da2e3ebdSchin "sequence. The result of each comparison will be 1 if the specified " 61da2e3ebdSchin "relationship is true, or 0 if the relationship is false. \aop\a " 62da2e3ebdSchin "can be one of the following:]{" 63da2e3ebdSchin "[+=?Equal.]" 64da2e3ebdSchin "[+==?Equal.]" 65da2e3ebdSchin "[+>?Greater than.]" 66da2e3ebdSchin "[+>=?Greater than or equal to.]" 67da2e3ebdSchin "[+<?Less than.]" 68da2e3ebdSchin "[+<=?Less than or equal to.]" 69da2e3ebdSchin "[+!=?Not equal to.]" 70da2e3ebdSchin "}" 71da2e3ebdSchin 72da2e3ebdSchin "[+\aexpr1\a \aop\a \aexpr2\a?Where \aop\a is \b+\b or \b-\b; " 73da2e3ebdSchin "addition or subtraction of decimal integer-valued arguments.]" 74da2e3ebdSchin "[+\aexpr1\a \aop\a \aexpr2\a?Where \aop\a is \b*\b, \b/\b or \b%\b; " 75da2e3ebdSchin "multiplication, division, or remainder of the decimal " 76da2e3ebdSchin "integer-valued arguments.]" 77da2e3ebdSchin "[+\aexpr1\a \b::\b \aexpr2\a?The matching operator : compares " 78da2e3ebdSchin "\aexpr1\a with \aexpr2\a, which must be a BRE. Normally, " 79da2e3ebdSchin "the matching operator returns the number of bytes matched " 80da2e3ebdSchin "and 0 on failure. However, if the pattern contains at " 81da2e3ebdSchin "least one sub-expression [\\( . . .\\)]], the string " 82da2e3ebdSchin "corresponding to \\1 will be returned.]" 83da2e3ebdSchin "[+( \aexpr1\a )?Grouping symbols. An expression can " 84da2e3ebdSchin "be placed within parenthesis to change precedence.]" 85da2e3ebdSchin "[+match\b \astring\a \aexpr\a?Equivalent to \astring\a \b:\b " 86da2e3ebdSchin "\aexpr\a.]" 87da2e3ebdSchin "[+substr\b \astring\a \apos\a \alength\a?\alength\a character " 88da2e3ebdSchin "substring of \astring\a starting at \apos\a " 89da2e3ebdSchin "(counting from 1).]" 90da2e3ebdSchin "[+index\b \astring\a \achars\a?The position in \astring\a " 91da2e3ebdSchin "(counting from 1) of the leftmost occurrence of any " 92da2e3ebdSchin "character in \achars\a.]" 93da2e3ebdSchin "[+length\b \astring\a?The number of characters in \astring\a.]" 94da2e3ebdSchin "[+quote\b \atoken\a?Treat \atoken\a as a string operand.]" 95da2e3ebdSchin "}" 96da2e3ebdSchin "[+?For backwards compatibility, unrecognized options beginning with " 97da2e3ebdSchin "a \b-\b will be treated as operands. Portable applications " 98da2e3ebdSchin "should use \b--\b to indicate end of options.]" 99da2e3ebdSchin 100da2e3ebdSchin "\n" 101da2e3ebdSchin "\n operand ...\n" 102da2e3ebdSchin "\n" 103da2e3ebdSchin 104da2e3ebdSchin "[+EXIT STATUS?]{" 105da2e3ebdSchin "[+0?The expression is neither null nor 0.]" 106da2e3ebdSchin "[+1?The expression is null or 0.]" 107da2e3ebdSchin "[+2?Invalid expressions.]" 108da2e3ebdSchin "[+>2?An error occurred.]" 109da2e3ebdSchin "}" 110da2e3ebdSchin "[+SEE ALSO?\bregcomp\b(5), \bgrep\b(1), \bsh\b(1)]" 111da2e3ebdSchin ; 112da2e3ebdSchin 113da2e3ebdSchin #include <cmd.h> 114da2e3ebdSchin #include <regex.h> 115da2e3ebdSchin 116da2e3ebdSchin #define T_ADD 0x100 117da2e3ebdSchin #define T_MULT 0x200 118da2e3ebdSchin #define T_CMP 0x400 119da2e3ebdSchin #define T_FUN 0x800 120da2e3ebdSchin #define T_OP 7 121da2e3ebdSchin #define T_NUM 1 122da2e3ebdSchin #define T_STR 2 123da2e3ebdSchin 124da2e3ebdSchin #define OP_EQ (T_CMP|0) 125da2e3ebdSchin #define OP_GT (T_CMP|1) 126da2e3ebdSchin #define OP_LT (T_CMP|2) 127da2e3ebdSchin #define OP_GE (T_CMP|3) 128da2e3ebdSchin #define OP_LE (T_CMP|4) 129da2e3ebdSchin #define OP_NE (T_CMP|5) 130da2e3ebdSchin #define OP_PLUS (T_ADD|0) 131da2e3ebdSchin #define OP_MINUS (T_ADD|1) 132da2e3ebdSchin #define OP_MULT (T_MULT|0) 133da2e3ebdSchin #define OP_DIV (T_MULT|1) 134da2e3ebdSchin #define OP_MOD (T_MULT|2) 135da2e3ebdSchin #define OP_INDEX (T_FUN|0) 136da2e3ebdSchin #define OP_LENGTH (T_FUN|1) 137da2e3ebdSchin #define OP_MATCH (T_FUN|2) 138da2e3ebdSchin #define OP_QUOTE (T_FUN|3) 139da2e3ebdSchin #define OP_SUBSTR (T_FUN|4) 140da2e3ebdSchin 141da2e3ebdSchin #define numeric(np) ((np)->type&T_NUM) 142da2e3ebdSchin 143da2e3ebdSchin static const struct Optable_s 144da2e3ebdSchin { 145da2e3ebdSchin const char opname[3]; 146da2e3ebdSchin int op; 147da2e3ebdSchin } 148da2e3ebdSchin optable[] = 149da2e3ebdSchin { 150da2e3ebdSchin "|", '|', 151da2e3ebdSchin "&", '&', 152da2e3ebdSchin "=", OP_EQ, 153da2e3ebdSchin "==", OP_EQ, 154da2e3ebdSchin ">", OP_GT, 155da2e3ebdSchin "<", OP_LT, 156da2e3ebdSchin ">=", OP_GE, 157da2e3ebdSchin "<=", OP_LE, 158da2e3ebdSchin "!=", OP_NE, 159da2e3ebdSchin "+", OP_PLUS, 160da2e3ebdSchin "-", OP_MINUS, 161da2e3ebdSchin "*", OP_MULT, 162da2e3ebdSchin "/", OP_DIV, 163da2e3ebdSchin "%", OP_MOD, 164da2e3ebdSchin ":", ':', 165da2e3ebdSchin "(", '(', 166da2e3ebdSchin ")", ')' 167da2e3ebdSchin }; 168da2e3ebdSchin 169da2e3ebdSchin typedef struct Node_s 170da2e3ebdSchin { 171da2e3ebdSchin int type; 172da2e3ebdSchin long num; 173da2e3ebdSchin char *str; 174da2e3ebdSchin } Node_t; 175da2e3ebdSchin 176da2e3ebdSchin typedef struct State_s 177da2e3ebdSchin { 178da2e3ebdSchin int standard; 179da2e3ebdSchin char** arglist; 180da2e3ebdSchin char buf[36]; 181da2e3ebdSchin } State_t; 182da2e3ebdSchin 183da2e3ebdSchin static int expr_or(State_t*, Node_t*); 184da2e3ebdSchin 185da2e3ebdSchin static int getnode(State_t* state, Node_t *np) 186da2e3ebdSchin { 187da2e3ebdSchin register char* sp; 188da2e3ebdSchin register char* cp; 189da2e3ebdSchin register int i; 190da2e3ebdSchin register int j; 191da2e3ebdSchin register int k; 192da2e3ebdSchin register int tok; 193da2e3ebdSchin char* ep; 194da2e3ebdSchin 195da2e3ebdSchin if (!(cp = *state->arglist++)) 196da2e3ebdSchin error(ERROR_exit(2), "argument expected"); 197da2e3ebdSchin if (!state->standard) 198da2e3ebdSchin switch (cp[0]) 199da2e3ebdSchin { 200da2e3ebdSchin case 'i': 201da2e3ebdSchin if (cp[1] == 'n' && !strcmp(cp, "index")) 202da2e3ebdSchin { 203da2e3ebdSchin if (!(cp = *state->arglist++)) 204da2e3ebdSchin error(ERROR_exit(2), "string argument expected"); 205da2e3ebdSchin if (!(ep = *state->arglist++)) 206da2e3ebdSchin error(ERROR_exit(2), "chars argument expected"); 207da2e3ebdSchin np->num = (ep = strpbrk(cp, ep)) ? (ep - cp + 1) : 0; 208da2e3ebdSchin np->type = T_NUM; 209da2e3ebdSchin goto next; 210da2e3ebdSchin } 211da2e3ebdSchin break; 212da2e3ebdSchin case 'l': 213da2e3ebdSchin if (cp[1] == 'e' && !strcmp(cp, "length")) 214da2e3ebdSchin { 215da2e3ebdSchin if (!(cp = *state->arglist++)) 216da2e3ebdSchin error(ERROR_exit(2), "string argument expected"); 217da2e3ebdSchin np->num = strlen(cp); 218da2e3ebdSchin np->type = T_NUM; 219da2e3ebdSchin goto next; 220da2e3ebdSchin } 221da2e3ebdSchin break; 222da2e3ebdSchin case 'm': 223da2e3ebdSchin if (cp[1] == 'a' && !strcmp(cp, "match")) 224da2e3ebdSchin { 225da2e3ebdSchin if (!(np->str = *state->arglist++)) 226da2e3ebdSchin error(ERROR_exit(2), "pattern argument expected"); 227da2e3ebdSchin np->type = T_STR; 228da2e3ebdSchin return ':'; 229da2e3ebdSchin } 230da2e3ebdSchin break; 231da2e3ebdSchin case 'q': 232da2e3ebdSchin if (cp[1] == 'u' && !strcmp(cp, "quote") && !(cp = *state->arglist++)) 233da2e3ebdSchin error(ERROR_exit(2), "string argument expected"); 234da2e3ebdSchin break; 235da2e3ebdSchin case 's': 236da2e3ebdSchin if (cp[1] == 'u' && !strcmp(cp, "substr")) 237da2e3ebdSchin { 238da2e3ebdSchin if (!(sp = *state->arglist++)) 239da2e3ebdSchin error(ERROR_exit(2), "string argument expected"); 240da2e3ebdSchin if (!(cp = *state->arglist++)) 241da2e3ebdSchin error(ERROR_exit(2), "position argument expected"); 242da2e3ebdSchin i = strtol(cp, &ep, 10); 243*7c2fbfb3SApril Chin if (*ep || --i < 0) 244da2e3ebdSchin i = -1; 245da2e3ebdSchin if (!(cp = *state->arglist++)) 246da2e3ebdSchin error(ERROR_exit(2), "length argument expected"); 247da2e3ebdSchin j = strtol(cp, &ep, 10); 248da2e3ebdSchin if (*ep) 249da2e3ebdSchin j = -1; 250da2e3ebdSchin k = strlen(sp); 251da2e3ebdSchin if (i < 0 || i >= k || j < 0) 252da2e3ebdSchin sp = ""; 253da2e3ebdSchin else 254da2e3ebdSchin { 255da2e3ebdSchin sp += i; 256da2e3ebdSchin k -= i; 257da2e3ebdSchin if (j < k) 258da2e3ebdSchin sp[j] = 0; 259da2e3ebdSchin } 260da2e3ebdSchin np->type = T_STR; 261da2e3ebdSchin np->str = sp; 262da2e3ebdSchin goto next; 263da2e3ebdSchin } 264da2e3ebdSchin break; 265da2e3ebdSchin } 266da2e3ebdSchin if (*cp=='(' && cp[1]==0) 267da2e3ebdSchin { 268da2e3ebdSchin tok = expr_or(state, np); 269da2e3ebdSchin if (tok != ')') 270da2e3ebdSchin error(ERROR_exit(2),"closing parenthesis missing"); 271da2e3ebdSchin } 272da2e3ebdSchin else 273da2e3ebdSchin { 274da2e3ebdSchin np->type = T_STR; 275da2e3ebdSchin np->str = cp; 276da2e3ebdSchin if (*cp) 277da2e3ebdSchin { 278da2e3ebdSchin np->num = strtol(np->str,&ep,10); 279da2e3ebdSchin if (!*ep) 280da2e3ebdSchin np->type |= T_NUM; 281da2e3ebdSchin } 282da2e3ebdSchin } 283da2e3ebdSchin next: 284da2e3ebdSchin if (!(cp = *state->arglist)) 285da2e3ebdSchin return 0; 286da2e3ebdSchin state->arglist++; 287da2e3ebdSchin for (i=0; i < sizeof(optable)/sizeof(*optable); i++) 288da2e3ebdSchin if (*cp==optable[i].opname[0] && cp[1]==optable[i].opname[1]) 289da2e3ebdSchin return optable[i].op; 290da2e3ebdSchin error(ERROR_exit(2),"%s: unknown operator argument",cp); 291da2e3ebdSchin return 0; 292da2e3ebdSchin } 293da2e3ebdSchin 294da2e3ebdSchin static int expr_cond(State_t* state, Node_t *np) 295da2e3ebdSchin { 296da2e3ebdSchin register int tok = getnode(state, np); 297da2e3ebdSchin 298da2e3ebdSchin while (tok==':') 299da2e3ebdSchin { 300da2e3ebdSchin regex_t re; 301da2e3ebdSchin regmatch_t match[2]; 302da2e3ebdSchin int n; 303da2e3ebdSchin Node_t rp; 304da2e3ebdSchin char *cp; 305da2e3ebdSchin tok = getnode(state, &rp); 306da2e3ebdSchin if (np->type&T_STR) 307da2e3ebdSchin cp = np->str; 308da2e3ebdSchin else 309da2e3ebdSchin sfsprintf(cp=state->buf,sizeof(state->buf),"%d",np->num); 310da2e3ebdSchin np->num = 0; 311da2e3ebdSchin np->type = T_NUM; 312da2e3ebdSchin if (n = regcomp(&re, rp.str, REG_LEFT|REG_LENIENT)) 313da2e3ebdSchin regfatal(&re, ERROR_exit(2), n); 314da2e3ebdSchin if (!(n = regexec(&re, cp, elementsof(match), match, 0))) 315da2e3ebdSchin { 316da2e3ebdSchin if (re.re_nsub > 0) 317da2e3ebdSchin { 318da2e3ebdSchin np->type = T_STR; 319da2e3ebdSchin if (match[1].rm_so >= 0) 320da2e3ebdSchin { 321da2e3ebdSchin np->str = cp + match[1].rm_so; 322da2e3ebdSchin np->str[match[1].rm_eo - match[1].rm_so] = 0; 323da2e3ebdSchin np->num = strtol(np->str,&cp,10); 324da2e3ebdSchin if (cp!=np->str && *cp==0) 325da2e3ebdSchin np->type |= T_NUM; 326da2e3ebdSchin } 327da2e3ebdSchin else 328da2e3ebdSchin np->str = ""; 329da2e3ebdSchin } 330da2e3ebdSchin else 331da2e3ebdSchin np->num = match[0].rm_eo - match[0].rm_so; 332da2e3ebdSchin } 333da2e3ebdSchin else if (n != REG_NOMATCH) 334da2e3ebdSchin regfatal(&re, ERROR_exit(2), n); 335da2e3ebdSchin else if (re.re_nsub) 336da2e3ebdSchin { 337da2e3ebdSchin np->str = ""; 338da2e3ebdSchin np->type = T_STR; 339da2e3ebdSchin } 340da2e3ebdSchin regfree(&re); 341da2e3ebdSchin } 342da2e3ebdSchin return tok; 343da2e3ebdSchin } 344da2e3ebdSchin 345da2e3ebdSchin static int expr_mult(State_t* state, Node_t *np) 346da2e3ebdSchin { 347da2e3ebdSchin register int tok = expr_cond(state, np); 348da2e3ebdSchin 349da2e3ebdSchin while ((tok&~T_OP)==T_MULT) 350da2e3ebdSchin { 351da2e3ebdSchin Node_t rp; 352da2e3ebdSchin int op = (tok&T_OP); 353da2e3ebdSchin tok = expr_cond(state, &rp); 354da2e3ebdSchin if (!numeric(np) || !numeric(&rp)) 355da2e3ebdSchin error(ERROR_exit(2),"non-numeric argument"); 356da2e3ebdSchin if (op && rp.num==0) 357da2e3ebdSchin error(ERROR_exit(2),"division by zero"); 358da2e3ebdSchin switch(op) 359da2e3ebdSchin { 360da2e3ebdSchin case 0: 361da2e3ebdSchin np->num *= rp.num; 362da2e3ebdSchin break; 363da2e3ebdSchin case 1: 364da2e3ebdSchin np->num /= rp.num; 365da2e3ebdSchin break; 366da2e3ebdSchin case 2: 367da2e3ebdSchin np->num %= rp.num; 368da2e3ebdSchin } 369da2e3ebdSchin np->type = T_NUM; 370da2e3ebdSchin } 371da2e3ebdSchin return tok; 372da2e3ebdSchin } 373da2e3ebdSchin 374da2e3ebdSchin static int expr_add(State_t* state, Node_t *np) 375da2e3ebdSchin { 376da2e3ebdSchin register int tok = expr_mult(state, np); 377da2e3ebdSchin 378da2e3ebdSchin while ((tok&~T_OP)==T_ADD) 379da2e3ebdSchin { 380da2e3ebdSchin Node_t rp; 381da2e3ebdSchin int op = (tok&T_OP); 382da2e3ebdSchin tok = expr_mult(state, &rp); 383da2e3ebdSchin if (!numeric(np) || !numeric(&rp)) 384da2e3ebdSchin error(ERROR_exit(2),"non-numeric argument"); 385da2e3ebdSchin if (op) 386da2e3ebdSchin np->num -= rp.num; 387da2e3ebdSchin else 388da2e3ebdSchin np->num += rp.num; 389da2e3ebdSchin np->type = T_NUM; 390da2e3ebdSchin } 391da2e3ebdSchin return tok; 392da2e3ebdSchin } 393da2e3ebdSchin 394da2e3ebdSchin static int expr_cmp(State_t* state, Node_t *np) 395da2e3ebdSchin { 396da2e3ebdSchin register int tok = expr_add(state, np); 397da2e3ebdSchin 398da2e3ebdSchin while ((tok&~T_OP)==T_CMP) 399da2e3ebdSchin { 400da2e3ebdSchin Node_t rp; 401da2e3ebdSchin register char *left,*right; 402da2e3ebdSchin char buff1[36],buff2[36]; 403da2e3ebdSchin int op = (tok&T_OP); 404da2e3ebdSchin tok = expr_add(state, &rp); 405da2e3ebdSchin if (numeric(&rp) && numeric(np)) 406da2e3ebdSchin op |= 010; 407da2e3ebdSchin else 408da2e3ebdSchin { 409da2e3ebdSchin if (np->type&T_STR) 410da2e3ebdSchin left = np->str; 411da2e3ebdSchin else 412da2e3ebdSchin sfsprintf(left=buff1,sizeof(buff1),"%d",np->num); 413da2e3ebdSchin if (rp.type&T_STR) 414da2e3ebdSchin right = rp.str; 415da2e3ebdSchin else 416da2e3ebdSchin sfsprintf(right=buff2,sizeof(buff2),"%d",rp.num); 417da2e3ebdSchin } 418da2e3ebdSchin switch(op) 419da2e3ebdSchin { 420da2e3ebdSchin case 0: 421da2e3ebdSchin np->num = streq(left,right); 422da2e3ebdSchin break; 423da2e3ebdSchin case 1: 424da2e3ebdSchin np->num = (strcoll(left,right)>0); 425da2e3ebdSchin break; 426da2e3ebdSchin case 2: 427da2e3ebdSchin np->num = (strcoll(left,right)<0); 428da2e3ebdSchin break; 429da2e3ebdSchin case 3: 430da2e3ebdSchin np->num = (strcoll(left,right)>=0); 431da2e3ebdSchin break; 432da2e3ebdSchin case 4: 433da2e3ebdSchin np->num = (strcoll(left,right)<=0); 434da2e3ebdSchin break; 435da2e3ebdSchin case 5: 436da2e3ebdSchin np->num = !streq(left,right); 437da2e3ebdSchin break; 438da2e3ebdSchin case 010: 439da2e3ebdSchin np->num = (np->num==rp.num); 440da2e3ebdSchin break; 441da2e3ebdSchin case 011: 442da2e3ebdSchin np->num = (np->num>rp.num); 443da2e3ebdSchin break; 444da2e3ebdSchin case 012: 445da2e3ebdSchin np->num = (np->num<rp.num); 446da2e3ebdSchin break; 447da2e3ebdSchin case 013: 448da2e3ebdSchin np->num = (np->num>=rp.num); 449da2e3ebdSchin break; 450da2e3ebdSchin case 014: 451da2e3ebdSchin np->num = (np->num<=rp.num); 452da2e3ebdSchin break; 453da2e3ebdSchin case 015: 454da2e3ebdSchin np->num = (np->num!=rp.num); 455da2e3ebdSchin break; 456da2e3ebdSchin } 457da2e3ebdSchin np->type = T_NUM; 458da2e3ebdSchin } 459da2e3ebdSchin return tok; 460da2e3ebdSchin } 461da2e3ebdSchin 462da2e3ebdSchin static int expr_and(State_t* state, Node_t *np) 463da2e3ebdSchin { 464da2e3ebdSchin register int tok = expr_cmp(state, np); 465da2e3ebdSchin while (tok=='&') 466da2e3ebdSchin { 467da2e3ebdSchin Node_t rp; 468da2e3ebdSchin tok = expr_cmp(state, &rp); 469da2e3ebdSchin if ((numeric(&rp) && rp.num==0) || *rp.str==0) 470da2e3ebdSchin { 471da2e3ebdSchin np->num = 0; 472da2e3ebdSchin np->type=T_NUM; 473da2e3ebdSchin } 474da2e3ebdSchin } 475da2e3ebdSchin return tok; 476da2e3ebdSchin } 477da2e3ebdSchin 478da2e3ebdSchin static int expr_or(State_t* state, Node_t *np) 479da2e3ebdSchin { 480da2e3ebdSchin register int tok = expr_and(state, np); 481da2e3ebdSchin while (tok=='|') 482da2e3ebdSchin { 483da2e3ebdSchin Node_t rp; 484da2e3ebdSchin tok = expr_and(state, &rp); 485da2e3ebdSchin if ((numeric(np) && np->num==0) || *np->str==0) 486da2e3ebdSchin *np = rp; 487da2e3ebdSchin } 488da2e3ebdSchin return tok; 489da2e3ebdSchin } 490da2e3ebdSchin 491da2e3ebdSchin int 492da2e3ebdSchin b_expr(int argc, char *argv[], void *context) 493da2e3ebdSchin { 494da2e3ebdSchin State_t state; 495da2e3ebdSchin Node_t node; 496da2e3ebdSchin int n; 497da2e3ebdSchin 498da2e3ebdSchin cmdinit(argc, argv,context, ERROR_CATALOG, 0); 499da2e3ebdSchin state.standard = !strcmp(astconf("CONFORMANCE", NiL, NiL), "standard"); 500da2e3ebdSchin #if 0 501da2e3ebdSchin if (state.standard) 502da2e3ebdSchin state.arglist = argv+1; 503da2e3ebdSchin else 504da2e3ebdSchin #endif 505da2e3ebdSchin { 506da2e3ebdSchin while (n=optget(argv, usage)) 507da2e3ebdSchin { 508da2e3ebdSchin /* 509da2e3ebdSchin * NOTE: this loop ignores all but literal -- and -? 510da2e3ebdSchin * out of kindness for obsolescent usage 511da2e3ebdSchin * (and is ok with the standard) but strict 512da2e3ebdSchin * getopt conformance would give usage for all 513da2e3ebdSchin * unknown - options 514da2e3ebdSchin */ 515da2e3ebdSchin if(n=='?') 516da2e3ebdSchin error(ERROR_usage(2), "%s", opt_info.arg); 517da2e3ebdSchin if (opt_info.option[1] != '?') 518da2e3ebdSchin break; 519da2e3ebdSchin error(ERROR_usage(2), "%s", opt_info.arg); 520da2e3ebdSchin } 521da2e3ebdSchin if (error_info.errors) 522da2e3ebdSchin error(ERROR_usage(2),"%s",optusage((char*)0)); 523da2e3ebdSchin state.arglist = argv+opt_info.index; 524da2e3ebdSchin } 525da2e3ebdSchin if (expr_or(&state, &node)) 526da2e3ebdSchin error(ERROR_exit(2),"syntax error"); 527da2e3ebdSchin if (node.type&T_STR) 528da2e3ebdSchin { 529da2e3ebdSchin if (*node.str) 530da2e3ebdSchin sfprintf(sfstdout,"%s\n",node.str); 531da2e3ebdSchin } 532da2e3ebdSchin else 533da2e3ebdSchin sfprintf(sfstdout,"%d\n",node.num); 534da2e3ebdSchin return numeric(&node)?node.num==0:*node.str==0; 535da2e3ebdSchin } 536