xref: /illumos-gate/usr/src/contrib/ast/src/lib/libcmd/expr.c (revision bbf215553c7233fbab8a0afdf1fac74c44781867)
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