blob: 555559a26ced9a20b34ed481ca495e302198eb9f [file] [log] [blame]
Mike Frysinger98c52642009-04-02 10:02:37 +00001/*
2 * arithmetic code ripped out of ash shell for code sharing
3 *
Denys Vlasenko73067272010-01-12 22:11:24 +01004 * This code is derived from software contributed to Berkeley by
5 * Kenneth Almquist.
6 *
7 * Original BSD copyright notice is retained at the end of this file.
8 *
Mike Frysinger98c52642009-04-02 10:02:37 +00009 * Copyright (c) 1989, 1991, 1993, 1994
10 * The Regents of the University of California. All rights reserved.
11 *
12 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
13 * was re-ported from NetBSD and debianized.
14 *
Mike Frysinger98c52642009-04-02 10:02:37 +000015 * rewrite arith.y to micro stack based cryptic algorithm by
16 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
17 *
18 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
19 * dynamic variables.
20 *
21 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
22 * used in busybox and size optimizations,
23 * rewrote arith (see notes to this), added locale support,
24 * rewrote dynamic variables.
Denys Vlasenko73067272010-01-12 22:11:24 +010025 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020026 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Mike Frysinger98c52642009-04-02 10:02:37 +000027 */
Mike Frysinger98c52642009-04-02 10:02:37 +000028/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
29
30 Permission is hereby granted, free of charge, to any person obtaining
31 a copy of this software and associated documentation files (the
32 "Software"), to deal in the Software without restriction, including
33 without limitation the rights to use, copy, modify, merge, publish,
34 distribute, sublicense, and/or sell copies of the Software, and to
35 permit persons to whom the Software is furnished to do so, subject to
36 the following conditions:
37
38 The above copyright notice and this permission notice shall be
39 included in all copies or substantial portions of the Software.
40
41 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
42 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
43 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
44 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
45 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
46 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
47 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48*/
49
50/* This is my infix parser/evaluator. It is optimized for size, intended
51 * as a replacement for yacc-based parsers. However, it may well be faster
52 * than a comparable parser written in yacc. The supported operators are
53 * listed in #defines below. Parens, order of operations, and error handling
54 * are supported. This code is thread safe. The exact expression format should
Denys Vlasenkobd147702010-09-13 11:11:40 +020055 * be that which POSIX specifies for shells.
56 *
57 * The code uses a simple two-stack algorithm. See
Mike Frysinger98c52642009-04-02 10:02:37 +000058 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
59 * for a detailed explanation of the infix-to-postfix algorithm on which
60 * this is based (this code differs in that it applies operators immediately
61 * to the stack instead of adding them to a queue to end up with an
Denys Vlasenkobd147702010-09-13 11:11:40 +020062 * expression).
63 *
64 * To use the routine, call it with an expression string and error return
65 * pointer
66 */
Mike Frysinger98c52642009-04-02 10:02:37 +000067
68/*
69 * Aug 24, 2001 Manuel Novoa III
70 *
71 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
72 *
73 * 1) In arith_apply():
74 * a) Cached values of *numptr and &(numptr[-1]).
75 * b) Removed redundant test for zero denominator.
76 *
77 * 2) In arith():
78 * a) Eliminated redundant code for processing operator tokens by moving
79 * to a table-based implementation. Also folded handling of parens
80 * into the table.
81 * b) Combined all 3 loops which called arith_apply to reduce generated
82 * code size at the cost of speed.
83 *
84 * 3) The following expressions were treated as valid by the original code:
85 * 1() , 0! , 1 ( *3 ) .
86 * These bugs have been fixed by internally enclosing the expression in
87 * parens and then checking that all binary ops and right parens are
88 * preceded by a valid expression (NUM_TOKEN).
89 *
90 * Note: It may be desirable to replace Aaron's test for whitespace with
91 * ctype's isspace() if it is used by another busybox applet or if additional
92 * whitespace chars should be considered. Look below the "#include"s for a
93 * precompiler test.
94 */
Mike Frysinger98c52642009-04-02 10:02:37 +000095/*
96 * Aug 26, 2001 Manuel Novoa III
97 *
98 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
99 *
100 * Merge in Aaron's comments previously posted to the busybox list,
101 * modified slightly to take account of my changes to the code.
102 *
103 */
Mike Frysinger98c52642009-04-02 10:02:37 +0000104/*
105 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
106 *
107 * - allow access to variable,
Denys Vlasenkobd147702010-09-13 11:11:40 +0200108 * use recursive value indirection: c="2*2"; a="c"; echo $((a+=2)) produce 6
109 * - implement assign syntax (VAR=expr, +=, *= etc)
110 * - implement exponentiation (** operator)
111 * - implement comma separated - expr, expr
112 * - implement ++expr --expr expr++ expr--
113 * - implement expr ? expr : expr (but second expr is always calculated)
Mike Frysinger98c52642009-04-02 10:02:37 +0000114 * - allow hexadecimal and octal numbers
Denys Vlasenkobd147702010-09-13 11:11:40 +0200115 * - restore lost XOR operator
116 * - protect $((num num)) as true zero expr (Manuel's error)
Mike Frysinger98c52642009-04-02 10:02:37 +0000117 * - always use special isspace(), see comment from bash ;-)
118 */
Denys Vlasenko03dad222010-01-12 23:29:57 +0100119#include "libbb.h"
120#include "math.h"
121
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200122#define lookupvar (math_state->lookupvar)
123#define setvar (math_state->setvar )
124//#define endofname (math_state->endofname)
Mike Frysinger98c52642009-04-02 10:02:37 +0000125
Mike Frysinger98c52642009-04-02 10:02:37 +0000126typedef unsigned char operator;
127
128/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
129 * precedence, and 3 high bits are an ID unique across operators of that
130 * precedence. The ID portion is so that multiple operators can have the
131 * same precedence, ensuring that the leftmost one is evaluated first.
Denys Vlasenkobd147702010-09-13 11:11:40 +0200132 * Consider * and /
133 */
134#define tok_decl(prec,id) (((id)<<5) | (prec))
135#define PREC(op) ((op) & 0x1F)
Mike Frysinger98c52642009-04-02 10:02:37 +0000136
Denys Vlasenkobd147702010-09-13 11:11:40 +0200137#define TOK_LPAREN tok_decl(0,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000138
Denys Vlasenkobd147702010-09-13 11:11:40 +0200139#define TOK_COMMA tok_decl(1,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000140
Denys Vlasenkobd147702010-09-13 11:11:40 +0200141/* All assignments are right associative and have the same precedence,
142 * but there are 11 of them, which doesn't fit into 3 bits for unique id.
143 * Abusing another precedence level:
144 */
145#define TOK_ASSIGN tok_decl(2,0)
146#define TOK_AND_ASSIGN tok_decl(2,1)
147#define TOK_OR_ASSIGN tok_decl(2,2)
148#define TOK_XOR_ASSIGN tok_decl(2,3)
149#define TOK_PLUS_ASSIGN tok_decl(2,4)
150#define TOK_MINUS_ASSIGN tok_decl(2,5)
151#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
152#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
Mike Frysinger98c52642009-04-02 10:02:37 +0000153
Denys Vlasenkobd147702010-09-13 11:11:40 +0200154#define TOK_MUL_ASSIGN tok_decl(3,0)
155#define TOK_DIV_ASSIGN tok_decl(3,1)
156#define TOK_REM_ASSIGN tok_decl(3,2)
Mike Frysinger98c52642009-04-02 10:02:37 +0000157
Denys Vlasenkobd147702010-09-13 11:11:40 +0200158#define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000159
Denys Vlasenkobd147702010-09-13 11:11:40 +0200160/* ternary conditional operator is right associative too */
161#define TOK_CONDITIONAL tok_decl(4,0)
162#define TOK_CONDITIONAL_SEP tok_decl(4,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000163
Denys Vlasenkobd147702010-09-13 11:11:40 +0200164#define TOK_OR tok_decl(5,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000165
Denys Vlasenkobd147702010-09-13 11:11:40 +0200166#define TOK_AND tok_decl(6,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000167
Denys Vlasenkobd147702010-09-13 11:11:40 +0200168#define TOK_BOR tok_decl(7,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000169
Denys Vlasenkobd147702010-09-13 11:11:40 +0200170#define TOK_BXOR tok_decl(8,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000171
Denys Vlasenkobd147702010-09-13 11:11:40 +0200172#define TOK_BAND tok_decl(9,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000173
Denys Vlasenkobd147702010-09-13 11:11:40 +0200174#define TOK_EQ tok_decl(10,0)
175#define TOK_NE tok_decl(10,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000176
Denys Vlasenkobd147702010-09-13 11:11:40 +0200177#define TOK_LT tok_decl(11,0)
178#define TOK_GT tok_decl(11,1)
179#define TOK_GE tok_decl(11,2)
180#define TOK_LE tok_decl(11,3)
Mike Frysinger98c52642009-04-02 10:02:37 +0000181
Denys Vlasenkobd147702010-09-13 11:11:40 +0200182#define TOK_LSHIFT tok_decl(12,0)
183#define TOK_RSHIFT tok_decl(12,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000184
Denys Vlasenkobd147702010-09-13 11:11:40 +0200185#define TOK_ADD tok_decl(13,0)
186#define TOK_SUB tok_decl(13,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000187
Denys Vlasenkobd147702010-09-13 11:11:40 +0200188#define TOK_MUL tok_decl(14,0)
189#define TOK_DIV tok_decl(14,1)
190#define TOK_REM tok_decl(14,2)
Mike Frysinger98c52642009-04-02 10:02:37 +0000191
Denys Vlasenkobd147702010-09-13 11:11:40 +0200192/* exponent is right associative */
193#define TOK_EXPONENT tok_decl(15,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000194
Denys Vlasenkobd147702010-09-13 11:11:40 +0200195/* unary operators */
196#define UNARYPREC 16
197#define TOK_BNOT tok_decl(UNARYPREC,0)
198#define TOK_NOT tok_decl(UNARYPREC,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000199
Denys Vlasenkobd147702010-09-13 11:11:40 +0200200#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
201#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000202
Denys Vlasenkobd147702010-09-13 11:11:40 +0200203#define PREC_PRE (UNARYPREC+2)
Mike Frysinger98c52642009-04-02 10:02:37 +0000204
Denys Vlasenkobd147702010-09-13 11:11:40 +0200205#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
206#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000207
Denys Vlasenkobd147702010-09-13 11:11:40 +0200208#define PREC_POST (UNARYPREC+3)
Mike Frysinger98c52642009-04-02 10:02:37 +0000209
Denys Vlasenkobd147702010-09-13 11:11:40 +0200210#define TOK_POST_INC tok_decl(PREC_POST, 0)
211#define TOK_POST_DEC tok_decl(PREC_POST, 1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000212
Denys Vlasenkobd147702010-09-13 11:11:40 +0200213#define SPEC_PREC (UNARYPREC+4)
Mike Frysinger98c52642009-04-02 10:02:37 +0000214
Denys Vlasenkobd147702010-09-13 11:11:40 +0200215#define TOK_NUM tok_decl(SPEC_PREC, 0)
216#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000217
218static int
219tok_have_assign(operator op)
220{
221 operator prec = PREC(op);
222
Denys Vlasenkobd147702010-09-13 11:11:40 +0200223 fix_assignment_prec(prec);
Mike Frysinger98c52642009-04-02 10:02:37 +0000224 return (prec == PREC(TOK_ASSIGN) ||
225 prec == PREC_PRE || prec == PREC_POST);
226}
227
228static int
Denys Vlasenkobd147702010-09-13 11:11:40 +0200229is_right_associative(operator prec)
Mike Frysinger98c52642009-04-02 10:02:37 +0000230{
231 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
232 || prec == PREC(TOK_CONDITIONAL));
233}
234
235typedef struct {
236 arith_t val;
237 arith_t contidional_second_val;
238 char contidional_second_val_initialized;
239 char *var; /* if NULL then is regular number,
240 else is variable name */
241} v_n_t;
242
243typedef struct chk_var_recursive_looped_t {
244 const char *var;
245 struct chk_var_recursive_looped_t *next;
246} chk_var_recursive_looped_t;
247
248static chk_var_recursive_looped_t *prev_chk_var_recursive;
249
250static int
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200251arith_lookup_val(arith_state_t *math_state, v_n_t *t)
Mike Frysinger98c52642009-04-02 10:02:37 +0000252{
253 if (t->var) {
Denys Vlasenko76ace252009-10-12 15:25:01 +0200254 const char *p = lookupvar(t->var);
Mike Frysinger98c52642009-04-02 10:02:37 +0000255
256 if (p) {
Mike Frysinger98c52642009-04-02 10:02:37 +0000257 chk_var_recursive_looped_t *cur;
258 chk_var_recursive_looped_t cur_save;
259
Denys Vlasenkobd147702010-09-13 11:11:40 +0200260 /* recursively try p as expression */
261
Mike Frysinger98c52642009-04-02 10:02:37 +0000262 for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
263 if (strcmp(cur->var, t->var) == 0) {
264 /* expression recursion loop detected */
265 return -5;
266 }
267 }
Denys Vlasenkobd147702010-09-13 11:11:40 +0200268 /* save current var name */
Mike Frysinger98c52642009-04-02 10:02:37 +0000269 cur = prev_chk_var_recursive;
270 cur_save.var = t->var;
271 cur_save.next = cur;
272 prev_chk_var_recursive = &cur_save;
273
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200274 t->val = arith(math_state, p);
Denys Vlasenkobd147702010-09-13 11:11:40 +0200275 /* restore previous ptr after recursion */
Mike Frysinger98c52642009-04-02 10:02:37 +0000276 prev_chk_var_recursive = cur;
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200277 return math_state->errcode;
Mike Frysinger98c52642009-04-02 10:02:37 +0000278 }
279 /* allow undefined var as 0 */
280 t->val = 0;
281 }
282 return 0;
283}
284
Denys Vlasenkobd147702010-09-13 11:11:40 +0200285/* "Applying" a token means performing it on the top elements on the integer
286 * stack. For an unary operator it will only change the top element, but a
287 * binary operator will pop two arguments and push the result */
Denys Vlasenkoa7bb3c12009-10-08 12:28:08 +0200288static NOINLINE int
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200289arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **numstackptr)
Mike Frysinger98c52642009-04-02 10:02:37 +0000290{
Denys Vlasenkobd147702010-09-13 11:11:40 +0200291#define NUMPTR (*numstackptr)
292
Mike Frysinger98c52642009-04-02 10:02:37 +0000293 v_n_t *numptr_m1;
294 arith_t numptr_val, rez;
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200295 int err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000296
297 /* There is no operator that can work without arguments */
Denys Vlasenkobd147702010-09-13 11:11:40 +0200298 if (NUMPTR == numstack)
299 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000300 numptr_m1 = NUMPTR - 1;
301
Denys Vlasenkobd147702010-09-13 11:11:40 +0200302 /* Check operand is var with noninteger value */
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200303 err = arith_lookup_val(math_state, numptr_m1);
304 if (err)
305 return err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000306
307 rez = numptr_m1->val;
308 if (op == TOK_UMINUS)
309 rez *= -1;
310 else if (op == TOK_NOT)
311 rez = !rez;
312 else if (op == TOK_BNOT)
313 rez = ~rez;
314 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
315 rez++;
316 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
317 rez--;
318 else if (op != TOK_UPLUS) {
319 /* Binary operators */
320
321 /* check and binary operators need two arguments */
322 if (numptr_m1 == numstack) goto err;
323
324 /* ... and they pop one */
325 --NUMPTR;
326 numptr_val = rez;
327 if (op == TOK_CONDITIONAL) {
328 if (!numptr_m1->contidional_second_val_initialized) {
329 /* protect $((expr1 ? expr2)) without ": expr" */
330 goto err;
331 }
332 rez = numptr_m1->contidional_second_val;
333 } else if (numptr_m1->contidional_second_val_initialized) {
334 /* protect $((expr1 : expr2)) without "expr ? " */
335 goto err;
336 }
337 numptr_m1 = NUMPTR - 1;
338 if (op != TOK_ASSIGN) {
339 /* check operand is var with noninteger value for not '=' */
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200340 err = arith_lookup_val(math_state, numptr_m1);
341 if (err)
342 return err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000343 }
344 if (op == TOK_CONDITIONAL) {
345 numptr_m1->contidional_second_val = rez;
346 }
347 rez = numptr_m1->val;
348 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
349 rez |= numptr_val;
350 else if (op == TOK_OR)
351 rez = numptr_val || rez;
352 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
353 rez &= numptr_val;
354 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
355 rez ^= numptr_val;
356 else if (op == TOK_AND)
357 rez = rez && numptr_val;
358 else if (op == TOK_EQ)
359 rez = (rez == numptr_val);
360 else if (op == TOK_NE)
361 rez = (rez != numptr_val);
362 else if (op == TOK_GE)
363 rez = (rez >= numptr_val);
364 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
365 rez >>= numptr_val;
366 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
367 rez <<= numptr_val;
368 else if (op == TOK_GT)
369 rez = (rez > numptr_val);
370 else if (op == TOK_LT)
371 rez = (rez < numptr_val);
372 else if (op == TOK_LE)
373 rez = (rez <= numptr_val);
374 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
375 rez *= numptr_val;
376 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
377 rez += numptr_val;
378 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
379 rez -= numptr_val;
380 else if (op == TOK_ASSIGN || op == TOK_COMMA)
381 rez = numptr_val;
382 else if (op == TOK_CONDITIONAL_SEP) {
383 if (numptr_m1 == numstack) {
384 /* protect $((expr : expr)) without "expr ? " */
385 goto err;
386 }
387 numptr_m1->contidional_second_val_initialized = op;
388 numptr_m1->contidional_second_val = numptr_val;
389 } else if (op == TOK_CONDITIONAL) {
390 rez = rez ?
391 numptr_val : numptr_m1->contidional_second_val;
392 } else if (op == TOK_EXPONENT) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200393 arith_t c;
Mike Frysinger98c52642009-04-02 10:02:37 +0000394 if (numptr_val < 0)
395 return -3; /* exponent less than 0 */
Denys Vlasenkobd147702010-09-13 11:11:40 +0200396 c = 1;
397 while (--numptr_val >= 0)
398 c *= rez;
399 rez = c;
Mike Frysinger98c52642009-04-02 10:02:37 +0000400 } else if (numptr_val==0) /* zero divisor check */
401 return -2;
402 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
403 rez /= numptr_val;
404 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
405 rez %= numptr_val;
406 }
407 if (tok_have_assign(op)) {
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000408 char buf[sizeof(arith_t)*3 + 2];
Mike Frysinger98c52642009-04-02 10:02:37 +0000409
410 if (numptr_m1->var == NULL) {
411 /* Hmm, 1=2 ? */
412 goto err;
413 }
414 /* save to shell variable */
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000415 sprintf(buf, arith_t_fmt, rez);
Denys Vlasenko03dad222010-01-12 23:29:57 +0100416 setvar(numptr_m1->var, buf);
Mike Frysinger98c52642009-04-02 10:02:37 +0000417 /* after saving, make previous value for v++ or v-- */
418 if (op == TOK_POST_INC)
419 rez--;
420 else if (op == TOK_POST_DEC)
421 rez++;
422 }
423 numptr_m1->val = rez;
Denys Vlasenkobd147702010-09-13 11:11:40 +0200424 /* erase var name, it is just a number now */
Mike Frysinger98c52642009-04-02 10:02:37 +0000425 numptr_m1->var = NULL;
426 return 0;
427 err:
428 return -1;
Denys Vlasenkobd147702010-09-13 11:11:40 +0200429#undef NUMPTR
Mike Frysinger98c52642009-04-02 10:02:37 +0000430}
431
432/* longest must be first */
433static const char op_tokens[] ALIGN1 = {
434 '<','<','=',0, TOK_LSHIFT_ASSIGN,
435 '>','>','=',0, TOK_RSHIFT_ASSIGN,
436 '<','<', 0, TOK_LSHIFT,
437 '>','>', 0, TOK_RSHIFT,
438 '|','|', 0, TOK_OR,
439 '&','&', 0, TOK_AND,
440 '!','=', 0, TOK_NE,
441 '<','=', 0, TOK_LE,
442 '>','=', 0, TOK_GE,
443 '=','=', 0, TOK_EQ,
444 '|','=', 0, TOK_OR_ASSIGN,
445 '&','=', 0, TOK_AND_ASSIGN,
446 '*','=', 0, TOK_MUL_ASSIGN,
447 '/','=', 0, TOK_DIV_ASSIGN,
448 '%','=', 0, TOK_REM_ASSIGN,
449 '+','=', 0, TOK_PLUS_ASSIGN,
450 '-','=', 0, TOK_MINUS_ASSIGN,
451 '-','-', 0, TOK_POST_DEC,
452 '^','=', 0, TOK_XOR_ASSIGN,
453 '+','+', 0, TOK_POST_INC,
454 '*','*', 0, TOK_EXPONENT,
455 '!', 0, TOK_NOT,
456 '<', 0, TOK_LT,
457 '>', 0, TOK_GT,
458 '=', 0, TOK_ASSIGN,
459 '|', 0, TOK_BOR,
460 '&', 0, TOK_BAND,
461 '*', 0, TOK_MUL,
462 '/', 0, TOK_DIV,
463 '%', 0, TOK_REM,
464 '+', 0, TOK_ADD,
465 '-', 0, TOK_SUB,
466 '^', 0, TOK_BXOR,
467 /* uniq */
468 '~', 0, TOK_BNOT,
469 ',', 0, TOK_COMMA,
470 '?', 0, TOK_CONDITIONAL,
471 ':', 0, TOK_CONDITIONAL_SEP,
472 ')', 0, TOK_RPAREN,
473 '(', 0, TOK_LPAREN,
474 0
475};
Denys Vlasenkob771c652010-09-13 00:34:26 +0200476#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
Mike Frysinger98c52642009-04-02 10:02:37 +0000477
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +0200478const char* FAST_FUNC
479endofname(const char *name)
480{
481 if (!is_name(*name))
482 return name;
483 while (*++name) {
484 if (!is_in_name(*name))
485 break;
486 }
487 return name;
488}
489
Mike Frysinger98c52642009-04-02 10:02:37 +0000490arith_t
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200491arith(arith_state_t *math_state, const char *expr)
Mike Frysinger98c52642009-04-02 10:02:37 +0000492{
Denys Vlasenkob771c652010-09-13 00:34:26 +0200493 operator lasttok;
Mike Frysinger98c52642009-04-02 10:02:37 +0000494 int errcode;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200495 const char *start_expr = expr = skip_whitespace(expr);
496 unsigned expr_len = strlen(expr) + 2;
Mike Frysinger98c52642009-04-02 10:02:37 +0000497 /* Stack of integers */
498 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
499 * in any given correct or incorrect expression is left as an exercise to
500 * the reader. */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200501 v_n_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
502 v_n_t *numstackptr = numstack;
Mike Frysinger98c52642009-04-02 10:02:37 +0000503 /* Stack of operator tokens */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200504 operator *const stack = alloca(expr_len * sizeof(stack[0]));
505 operator *stackptr = stack;
Mike Frysinger98c52642009-04-02 10:02:37 +0000506
507 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200508 errcode = 0;
Mike Frysinger98c52642009-04-02 10:02:37 +0000509
510 while (1) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200511 const char *p;
512 operator op;
513 operator prec;
514 char arithval;
515
516 expr = skip_whitespace(expr);
Mike Frysinger98c52642009-04-02 10:02:37 +0000517 arithval = *expr;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200518 if (arithval == '\0') {
519 if (expr == start_expr) {
Mike Frysinger98c52642009-04-02 10:02:37 +0000520 /* Null expression. */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200521 numstack->val = 0;
522 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000523 }
524
525 /* This is only reached after all tokens have been extracted from the
526 * input stream. If there are still tokens on the operator stack, they
527 * are to be applied in order. At the end, there should be a final
528 * result on the integer stack */
529
Denys Vlasenkob771c652010-09-13 00:34:26 +0200530 if (expr != ptr_to_rparen + 1) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200531 /* If we haven't done so already,
532 * append a closing right paren
533 * and let the loop process it */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200534 expr = ptr_to_rparen;
Mike Frysinger98c52642009-04-02 10:02:37 +0000535 continue;
536 }
Denys Vlasenkobd147702010-09-13 11:11:40 +0200537 /* At this point, we're done with the expression */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200538 if (numstackptr != numstack + 1) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200539 /* ...but if there isn't, it's bad */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200540 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000541 }
542 if (numstack->var) {
543 /* expression is $((var)) only, lookup now */
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200544 errcode = arith_lookup_val(math_state, numstack);
Mike Frysinger98c52642009-04-02 10:02:37 +0000545 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200546 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000547 }
548
Mike Frysinger98c52642009-04-02 10:02:37 +0000549 p = endofname(expr);
550 if (p != expr) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200551 /* Name */
552 size_t var_name_size = (p-expr) + 1; /* +1 for NUL */
Mike Frysinger98c52642009-04-02 10:02:37 +0000553 numstackptr->var = alloca(var_name_size);
554 safe_strncpy(numstackptr->var, expr, var_name_size);
555 expr = p;
556 num:
557 numstackptr->contidional_second_val_initialized = 0;
558 numstackptr++;
559 lasttok = TOK_NUM;
560 continue;
561 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200562
Mike Frysinger98c52642009-04-02 10:02:37 +0000563 if (isdigit(arithval)) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200564 /* Number */
Mike Frysinger98c52642009-04-02 10:02:37 +0000565 numstackptr->var = NULL;
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200566 errno = 0;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200567 numstackptr->val = strto_arith_t(expr, (char**) &expr, 0);
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200568 if (errno)
569 numstackptr->val = 0; /* bash compat */
Mike Frysinger98c52642009-04-02 10:02:37 +0000570 goto num;
571 }
Mike Frysinger98c52642009-04-02 10:02:37 +0000572
Denys Vlasenkob771c652010-09-13 00:34:26 +0200573 /* Should be an operator */
574 p = op_tokens;
575 while (1) {
576 const char *e = expr;
577 /* Compare expr to current op_tokens[] element */
578 while (*p && *e == *p)
579 p++, e++;
580 if (*p == '\0') { /* match: operator is found */
581 expr = e;
Mike Frysinger98c52642009-04-02 10:02:37 +0000582 break;
583 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200584 /* Go to next element of op_tokens[] */
Mike Frysinger98c52642009-04-02 10:02:37 +0000585 while (*p)
586 p++;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200587 p += 2; /* skip NUL and TOK_foo bytes */
588 if (*p == '\0') /* no next element, operator not found */
589 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000590 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200591 op = p[1]; /* fetch TOK_foo value */
592 /* NB: expr now points past the operator */
Mike Frysinger98c52642009-04-02 10:02:37 +0000593
594 /* post grammar: a++ reduce to num */
595 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
596 lasttok = TOK_NUM;
597
598 /* Plus and minus are binary (not unary) _only_ if the last
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200599 * token was a number, or a right paren (which pretends to be
Mike Frysinger98c52642009-04-02 10:02:37 +0000600 * a number, since it evaluates to one). Think about it.
601 * It makes sense. */
602 if (lasttok != TOK_NUM) {
603 switch (op) {
604 case TOK_ADD:
605 op = TOK_UPLUS;
606 break;
607 case TOK_SUB:
608 op = TOK_UMINUS;
609 break;
610 case TOK_POST_INC:
611 op = TOK_PRE_INC;
612 break;
613 case TOK_POST_DEC:
614 op = TOK_PRE_DEC;
615 break;
616 }
617 }
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200618 /* We don't want an unary operator to cause recursive descent on the
Mike Frysinger98c52642009-04-02 10:02:37 +0000619 * stack, because there can be many in a row and it could cause an
620 * operator to be evaluated before its argument is pushed onto the
Denys Vlasenkobd147702010-09-13 11:11:40 +0200621 * integer stack.
622 * But for binary operators, "apply" everything on the operator
Mike Frysinger98c52642009-04-02 10:02:37 +0000623 * stack until we find an operator with a lesser priority than the
Denys Vlasenkobd147702010-09-13 11:11:40 +0200624 * one we have just extracted.
625 * Left paren is given the lowest priority so it will never be
Mike Frysinger98c52642009-04-02 10:02:37 +0000626 * "applied" in this way.
627 * if associativity is right and priority eq, applied also skip
628 */
629 prec = PREC(op);
630 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
631 /* not left paren or unary */
632 if (lasttok != TOK_NUM) {
633 /* binary op must be preceded by a num */
634 goto err;
635 }
636 while (stackptr != stack) {
Denys Vlasenko51850c82010-09-13 01:09:11 +0200637 operator prev_op = *--stackptr;
Mike Frysinger98c52642009-04-02 10:02:37 +0000638 if (op == TOK_RPAREN) {
639 /* The algorithm employed here is simple: while we don't
640 * hit an open paren nor the bottom of the stack, pop
641 * tokens and apply them */
Denys Vlasenko51850c82010-09-13 01:09:11 +0200642 if (prev_op == TOK_LPAREN) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200643 /* Any operator directly after a
644 * close paren should consider itself binary */
Mike Frysinger98c52642009-04-02 10:02:37 +0000645 lasttok = TOK_NUM;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200646 goto next;
Mike Frysinger98c52642009-04-02 10:02:37 +0000647 }
648 } else {
Denys Vlasenko51850c82010-09-13 01:09:11 +0200649 operator prev_prec = PREC(prev_op);
Denys Vlasenkobd147702010-09-13 11:11:40 +0200650 fix_assignment_prec(prec);
651 fix_assignment_prec(prev_prec);
Denys Vlasenko51850c82010-09-13 01:09:11 +0200652 if (prev_prec < prec
Denys Vlasenkobd147702010-09-13 11:11:40 +0200653 || (prev_prec == prec && is_right_associative(prec))
Denys Vlasenko51850c82010-09-13 01:09:11 +0200654 ) {
655 stackptr++;
Mike Frysinger98c52642009-04-02 10:02:37 +0000656 break;
Denys Vlasenko51850c82010-09-13 01:09:11 +0200657 }
Mike Frysinger98c52642009-04-02 10:02:37 +0000658 }
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200659 errcode = arith_apply(math_state, prev_op, numstack, &numstackptr);
Denys Vlasenkob771c652010-09-13 00:34:26 +0200660 if (errcode)
661 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000662 }
663 if (op == TOK_RPAREN) {
664 goto err;
665 }
666 }
667
668 /* Push this operator to the stack and remember it. */
669 *stackptr++ = lasttok = op;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200670 next: ;
671 } /* while (1) */
672
673 err:
674 numstack->val = errcode = -1;
675 ret:
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200676 math_state->errcode = errcode;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200677 return numstack->val;
Mike Frysinger98c52642009-04-02 10:02:37 +0000678}
679
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000680/*
Mike Frysinger98c52642009-04-02 10:02:37 +0000681 * Copyright (c) 1989, 1991, 1993, 1994
682 * The Regents of the University of California. All rights reserved.
683 *
684 * This code is derived from software contributed to Berkeley by
685 * Kenneth Almquist.
686 *
687 * Redistribution and use in source and binary forms, with or without
688 * modification, are permitted provided that the following conditions
689 * are met:
690 * 1. Redistributions of source code must retain the above copyright
691 * notice, this list of conditions and the following disclaimer.
692 * 2. Redistributions in binary form must reproduce the above copyright
693 * notice, this list of conditions and the following disclaimer in the
694 * documentation and/or other materials provided with the distribution.
695 * 3. Neither the name of the University nor the names of its contributors
696 * may be used to endorse or promote products derived from this software
697 * without specific prior written permission.
698 *
699 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
700 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
701 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
702 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
703 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
704 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
705 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
706 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
707 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
708 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
709 * SUCH DAMAGE.
710 */