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