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