1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1992-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril 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[] =
307c2fbfb3SApril 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
getnode(State_t * state,Node_t * np)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);
2437c2fbfb3SApril 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
expr_cond(State_t * state,Node_t * np)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
expr_mult(State_t * state,Node_t * np)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
expr_add(State_t * state,Node_t * np)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
expr_cmp(State_t * state,Node_t * np)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
expr_and(State_t * state,Node_t * np)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
expr_or(State_t * state,Node_t * np)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
b_expr(int argc,char * argv[],void * context)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