blob: 839715776ad69dd0566aa7bc299b8f2b32a01cf3 [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
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200235
Mike Frysinger98c52642009-04-02 10:02:37 +0000236typedef struct {
237 arith_t val;
238 arith_t contidional_second_val;
239 char contidional_second_val_initialized;
240 char *var; /* if NULL then is regular number,
241 else is variable name */
242} v_n_t;
243
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200244typedef struct remembered_name {
245 struct remembered_name *next;
Mike Frysinger98c52642009-04-02 10:02:37 +0000246 const char *var;
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200247} remembered_name;
Mike Frysinger98c52642009-04-02 10:02:37 +0000248
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200249
250static arith_t FAST_FUNC
251evaluate_string(arith_state_t *math_state, const char *expr);
Mike Frysinger98c52642009-04-02 10:02:37 +0000252
253static int
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200254arith_lookup_val(arith_state_t *math_state, v_n_t *t)
Mike Frysinger98c52642009-04-02 10:02:37 +0000255{
256 if (t->var) {
Denys Vlasenko76ace252009-10-12 15:25:01 +0200257 const char *p = lookupvar(t->var);
Mike Frysinger98c52642009-04-02 10:02:37 +0000258 if (p) {
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200259 remembered_name *cur;
260 remembered_name cur_save;
Mike Frysinger98c52642009-04-02 10:02:37 +0000261
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200262 /* did we already see this name?
263 * testcase: a=b; b=a; echo $((a))
264 */
265 for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
Mike Frysinger98c52642009-04-02 10:02:37 +0000266 if (strcmp(cur->var, t->var) == 0) {
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200267 /* Yes. Expression recursion loop detected */
Mike Frysinger98c52642009-04-02 10:02:37 +0000268 return -5;
269 }
270 }
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200271
272 /* push current var name */
273 cur = math_state->list_of_recursed_names;
Mike Frysinger98c52642009-04-02 10:02:37 +0000274 cur_save.var = t->var;
275 cur_save.next = cur;
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200276 math_state->list_of_recursed_names = &cur_save;
Mike Frysinger98c52642009-04-02 10:02:37 +0000277
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200278 /* recursively evaluate p as expression */
279 t->val = evaluate_string(math_state, p);
280
281 /* pop current var name */
282 math_state->list_of_recursed_names = cur;
283
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200284 return math_state->errcode;
Mike Frysinger98c52642009-04-02 10:02:37 +0000285 }
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200286 /* treat undefined var as 0 */
Mike Frysinger98c52642009-04-02 10:02:37 +0000287 t->val = 0;
288 }
289 return 0;
290}
291
Denys Vlasenkobd147702010-09-13 11:11:40 +0200292/* "Applying" a token means performing it on the top elements on the integer
293 * stack. For an unary operator it will only change the top element, but a
294 * binary operator will pop two arguments and push the result */
Denys Vlasenkoa7bb3c12009-10-08 12:28:08 +0200295static NOINLINE int
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200296arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **numstackptr)
Mike Frysinger98c52642009-04-02 10:02:37 +0000297{
Denys Vlasenkobd147702010-09-13 11:11:40 +0200298#define NUMPTR (*numstackptr)
299
Mike Frysinger98c52642009-04-02 10:02:37 +0000300 v_n_t *numptr_m1;
301 arith_t numptr_val, rez;
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200302 int err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000303
304 /* There is no operator that can work without arguments */
Denys Vlasenkobd147702010-09-13 11:11:40 +0200305 if (NUMPTR == numstack)
306 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000307 numptr_m1 = NUMPTR - 1;
308
Denys Vlasenkobd147702010-09-13 11:11:40 +0200309 /* Check operand is var with noninteger value */
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200310 err = arith_lookup_val(math_state, numptr_m1);
311 if (err)
312 return err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000313
314 rez = numptr_m1->val;
315 if (op == TOK_UMINUS)
316 rez *= -1;
317 else if (op == TOK_NOT)
318 rez = !rez;
319 else if (op == TOK_BNOT)
320 rez = ~rez;
321 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
322 rez++;
323 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
324 rez--;
325 else if (op != TOK_UPLUS) {
326 /* Binary operators */
327
328 /* check and binary operators need two arguments */
329 if (numptr_m1 == numstack) goto err;
330
331 /* ... and they pop one */
332 --NUMPTR;
333 numptr_val = rez;
334 if (op == TOK_CONDITIONAL) {
335 if (!numptr_m1->contidional_second_val_initialized) {
336 /* protect $((expr1 ? expr2)) without ": expr" */
337 goto err;
338 }
339 rez = numptr_m1->contidional_second_val;
340 } else if (numptr_m1->contidional_second_val_initialized) {
341 /* protect $((expr1 : expr2)) without "expr ? " */
342 goto err;
343 }
344 numptr_m1 = NUMPTR - 1;
345 if (op != TOK_ASSIGN) {
346 /* check operand is var with noninteger value for not '=' */
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200347 err = arith_lookup_val(math_state, numptr_m1);
348 if (err)
349 return err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000350 }
351 if (op == TOK_CONDITIONAL) {
352 numptr_m1->contidional_second_val = rez;
353 }
354 rez = numptr_m1->val;
355 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
356 rez |= numptr_val;
357 else if (op == TOK_OR)
358 rez = numptr_val || rez;
359 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
360 rez &= numptr_val;
361 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
362 rez ^= numptr_val;
363 else if (op == TOK_AND)
364 rez = rez && numptr_val;
365 else if (op == TOK_EQ)
366 rez = (rez == numptr_val);
367 else if (op == TOK_NE)
368 rez = (rez != numptr_val);
369 else if (op == TOK_GE)
370 rez = (rez >= numptr_val);
371 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
372 rez >>= numptr_val;
373 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
374 rez <<= numptr_val;
375 else if (op == TOK_GT)
376 rez = (rez > numptr_val);
377 else if (op == TOK_LT)
378 rez = (rez < numptr_val);
379 else if (op == TOK_LE)
380 rez = (rez <= numptr_val);
381 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
382 rez *= numptr_val;
383 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
384 rez += numptr_val;
385 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
386 rez -= numptr_val;
387 else if (op == TOK_ASSIGN || op == TOK_COMMA)
388 rez = numptr_val;
389 else if (op == TOK_CONDITIONAL_SEP) {
390 if (numptr_m1 == numstack) {
391 /* protect $((expr : expr)) without "expr ? " */
392 goto err;
393 }
394 numptr_m1->contidional_second_val_initialized = op;
395 numptr_m1->contidional_second_val = numptr_val;
396 } else if (op == TOK_CONDITIONAL) {
397 rez = rez ?
398 numptr_val : numptr_m1->contidional_second_val;
399 } else if (op == TOK_EXPONENT) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200400 arith_t c;
Mike Frysinger98c52642009-04-02 10:02:37 +0000401 if (numptr_val < 0)
402 return -3; /* exponent less than 0 */
Denys Vlasenkobd147702010-09-13 11:11:40 +0200403 c = 1;
404 while (--numptr_val >= 0)
405 c *= rez;
406 rez = c;
Mike Frysinger98c52642009-04-02 10:02:37 +0000407 } else if (numptr_val==0) /* zero divisor check */
408 return -2;
409 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
410 rez /= numptr_val;
411 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
412 rez %= numptr_val;
413 }
414 if (tok_have_assign(op)) {
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000415 char buf[sizeof(arith_t)*3 + 2];
Mike Frysinger98c52642009-04-02 10:02:37 +0000416
417 if (numptr_m1->var == NULL) {
418 /* Hmm, 1=2 ? */
419 goto err;
420 }
421 /* save to shell variable */
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000422 sprintf(buf, arith_t_fmt, rez);
Denys Vlasenko03dad222010-01-12 23:29:57 +0100423 setvar(numptr_m1->var, buf);
Mike Frysinger98c52642009-04-02 10:02:37 +0000424 /* after saving, make previous value for v++ or v-- */
425 if (op == TOK_POST_INC)
426 rez--;
427 else if (op == TOK_POST_DEC)
428 rez++;
429 }
430 numptr_m1->val = rez;
Denys Vlasenkobd147702010-09-13 11:11:40 +0200431 /* erase var name, it is just a number now */
Mike Frysinger98c52642009-04-02 10:02:37 +0000432 numptr_m1->var = NULL;
433 return 0;
434 err:
435 return -1;
Denys Vlasenkobd147702010-09-13 11:11:40 +0200436#undef NUMPTR
Mike Frysinger98c52642009-04-02 10:02:37 +0000437}
438
439/* longest must be first */
440static const char op_tokens[] ALIGN1 = {
441 '<','<','=',0, TOK_LSHIFT_ASSIGN,
442 '>','>','=',0, TOK_RSHIFT_ASSIGN,
443 '<','<', 0, TOK_LSHIFT,
444 '>','>', 0, TOK_RSHIFT,
445 '|','|', 0, TOK_OR,
446 '&','&', 0, TOK_AND,
447 '!','=', 0, TOK_NE,
448 '<','=', 0, TOK_LE,
449 '>','=', 0, TOK_GE,
450 '=','=', 0, TOK_EQ,
451 '|','=', 0, TOK_OR_ASSIGN,
452 '&','=', 0, TOK_AND_ASSIGN,
453 '*','=', 0, TOK_MUL_ASSIGN,
454 '/','=', 0, TOK_DIV_ASSIGN,
455 '%','=', 0, TOK_REM_ASSIGN,
456 '+','=', 0, TOK_PLUS_ASSIGN,
457 '-','=', 0, TOK_MINUS_ASSIGN,
458 '-','-', 0, TOK_POST_DEC,
459 '^','=', 0, TOK_XOR_ASSIGN,
460 '+','+', 0, TOK_POST_INC,
461 '*','*', 0, TOK_EXPONENT,
462 '!', 0, TOK_NOT,
463 '<', 0, TOK_LT,
464 '>', 0, TOK_GT,
465 '=', 0, TOK_ASSIGN,
466 '|', 0, TOK_BOR,
467 '&', 0, TOK_BAND,
468 '*', 0, TOK_MUL,
469 '/', 0, TOK_DIV,
470 '%', 0, TOK_REM,
471 '+', 0, TOK_ADD,
472 '-', 0, TOK_SUB,
473 '^', 0, TOK_BXOR,
474 /* uniq */
475 '~', 0, TOK_BNOT,
476 ',', 0, TOK_COMMA,
477 '?', 0, TOK_CONDITIONAL,
478 ':', 0, TOK_CONDITIONAL_SEP,
479 ')', 0, TOK_RPAREN,
480 '(', 0, TOK_LPAREN,
481 0
482};
Denys Vlasenkob771c652010-09-13 00:34:26 +0200483#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
Mike Frysinger98c52642009-04-02 10:02:37 +0000484
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +0200485const char* FAST_FUNC
486endofname(const char *name)
487{
488 if (!is_name(*name))
489 return name;
490 while (*++name) {
491 if (!is_in_name(*name))
492 break;
493 }
494 return name;
495}
496
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200497static arith_t FAST_FUNC
498evaluate_string(arith_state_t *math_state, const char *expr)
Mike Frysinger98c52642009-04-02 10:02:37 +0000499{
Denys Vlasenkob771c652010-09-13 00:34:26 +0200500 operator lasttok;
Mike Frysinger98c52642009-04-02 10:02:37 +0000501 int errcode;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200502 const char *start_expr = expr = skip_whitespace(expr);
503 unsigned expr_len = strlen(expr) + 2;
Mike Frysinger98c52642009-04-02 10:02:37 +0000504 /* Stack of integers */
505 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
506 * in any given correct or incorrect expression is left as an exercise to
507 * the reader. */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200508 v_n_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
509 v_n_t *numstackptr = numstack;
Mike Frysinger98c52642009-04-02 10:02:37 +0000510 /* Stack of operator tokens */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200511 operator *const stack = alloca(expr_len * sizeof(stack[0]));
512 operator *stackptr = stack;
Mike Frysinger98c52642009-04-02 10:02:37 +0000513
514 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200515 errcode = 0;
Mike Frysinger98c52642009-04-02 10:02:37 +0000516
517 while (1) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200518 const char *p;
519 operator op;
520 operator prec;
521 char arithval;
522
523 expr = skip_whitespace(expr);
Mike Frysinger98c52642009-04-02 10:02:37 +0000524 arithval = *expr;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200525 if (arithval == '\0') {
526 if (expr == start_expr) {
Mike Frysinger98c52642009-04-02 10:02:37 +0000527 /* Null expression. */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200528 numstack->val = 0;
529 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000530 }
531
532 /* This is only reached after all tokens have been extracted from the
533 * input stream. If there are still tokens on the operator stack, they
534 * are to be applied in order. At the end, there should be a final
535 * result on the integer stack */
536
Denys Vlasenkob771c652010-09-13 00:34:26 +0200537 if (expr != ptr_to_rparen + 1) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200538 /* If we haven't done so already,
539 * append a closing right paren
540 * and let the loop process it */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200541 expr = ptr_to_rparen;
Mike Frysinger98c52642009-04-02 10:02:37 +0000542 continue;
543 }
Denys Vlasenkobd147702010-09-13 11:11:40 +0200544 /* At this point, we're done with the expression */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200545 if (numstackptr != numstack + 1) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200546 /* ...but if there isn't, it's bad */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200547 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000548 }
549 if (numstack->var) {
550 /* expression is $((var)) only, lookup now */
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200551 errcode = arith_lookup_val(math_state, numstack);
Mike Frysinger98c52642009-04-02 10:02:37 +0000552 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200553 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000554 }
555
Mike Frysinger98c52642009-04-02 10:02:37 +0000556 p = endofname(expr);
557 if (p != expr) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200558 /* Name */
559 size_t var_name_size = (p-expr) + 1; /* +1 for NUL */
Mike Frysinger98c52642009-04-02 10:02:37 +0000560 numstackptr->var = alloca(var_name_size);
561 safe_strncpy(numstackptr->var, expr, var_name_size);
562 expr = p;
563 num:
564 numstackptr->contidional_second_val_initialized = 0;
565 numstackptr++;
566 lasttok = TOK_NUM;
567 continue;
568 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200569
Mike Frysinger98c52642009-04-02 10:02:37 +0000570 if (isdigit(arithval)) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200571 /* Number */
Mike Frysinger98c52642009-04-02 10:02:37 +0000572 numstackptr->var = NULL;
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200573 errno = 0;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200574 numstackptr->val = strto_arith_t(expr, (char**) &expr, 0);
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200575 if (errno)
576 numstackptr->val = 0; /* bash compat */
Mike Frysinger98c52642009-04-02 10:02:37 +0000577 goto num;
578 }
Mike Frysinger98c52642009-04-02 10:02:37 +0000579
Denys Vlasenkob771c652010-09-13 00:34:26 +0200580 /* Should be an operator */
581 p = op_tokens;
582 while (1) {
583 const char *e = expr;
584 /* Compare expr to current op_tokens[] element */
585 while (*p && *e == *p)
586 p++, e++;
587 if (*p == '\0') { /* match: operator is found */
588 expr = e;
Mike Frysinger98c52642009-04-02 10:02:37 +0000589 break;
590 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200591 /* Go to next element of op_tokens[] */
Mike Frysinger98c52642009-04-02 10:02:37 +0000592 while (*p)
593 p++;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200594 p += 2; /* skip NUL and TOK_foo bytes */
595 if (*p == '\0') /* no next element, operator not found */
596 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000597 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200598 op = p[1]; /* fetch TOK_foo value */
599 /* NB: expr now points past the operator */
Mike Frysinger98c52642009-04-02 10:02:37 +0000600
601 /* post grammar: a++ reduce to num */
602 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
603 lasttok = TOK_NUM;
604
605 /* Plus and minus are binary (not unary) _only_ if the last
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200606 * token was a number, or a right paren (which pretends to be
Mike Frysinger98c52642009-04-02 10:02:37 +0000607 * a number, since it evaluates to one). Think about it.
608 * It makes sense. */
609 if (lasttok != TOK_NUM) {
610 switch (op) {
611 case TOK_ADD:
612 op = TOK_UPLUS;
613 break;
614 case TOK_SUB:
615 op = TOK_UMINUS;
616 break;
617 case TOK_POST_INC:
618 op = TOK_PRE_INC;
619 break;
620 case TOK_POST_DEC:
621 op = TOK_PRE_DEC;
622 break;
623 }
624 }
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200625 /* We don't want an unary operator to cause recursive descent on the
Mike Frysinger98c52642009-04-02 10:02:37 +0000626 * stack, because there can be many in a row and it could cause an
627 * operator to be evaluated before its argument is pushed onto the
Denys Vlasenkobd147702010-09-13 11:11:40 +0200628 * integer stack.
629 * But for binary operators, "apply" everything on the operator
Mike Frysinger98c52642009-04-02 10:02:37 +0000630 * stack until we find an operator with a lesser priority than the
Denys Vlasenkobd147702010-09-13 11:11:40 +0200631 * one we have just extracted.
632 * Left paren is given the lowest priority so it will never be
Mike Frysinger98c52642009-04-02 10:02:37 +0000633 * "applied" in this way.
634 * if associativity is right and priority eq, applied also skip
635 */
636 prec = PREC(op);
637 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
638 /* not left paren or unary */
639 if (lasttok != TOK_NUM) {
640 /* binary op must be preceded by a num */
641 goto err;
642 }
643 while (stackptr != stack) {
Denys Vlasenko51850c82010-09-13 01:09:11 +0200644 operator prev_op = *--stackptr;
Mike Frysinger98c52642009-04-02 10:02:37 +0000645 if (op == TOK_RPAREN) {
646 /* The algorithm employed here is simple: while we don't
647 * hit an open paren nor the bottom of the stack, pop
648 * tokens and apply them */
Denys Vlasenko51850c82010-09-13 01:09:11 +0200649 if (prev_op == TOK_LPAREN) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200650 /* Any operator directly after a
651 * close paren should consider itself binary */
Mike Frysinger98c52642009-04-02 10:02:37 +0000652 lasttok = TOK_NUM;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200653 goto next;
Mike Frysinger98c52642009-04-02 10:02:37 +0000654 }
655 } else {
Denys Vlasenko51850c82010-09-13 01:09:11 +0200656 operator prev_prec = PREC(prev_op);
Denys Vlasenkobd147702010-09-13 11:11:40 +0200657 fix_assignment_prec(prec);
658 fix_assignment_prec(prev_prec);
Denys Vlasenko51850c82010-09-13 01:09:11 +0200659 if (prev_prec < prec
Denys Vlasenkobd147702010-09-13 11:11:40 +0200660 || (prev_prec == prec && is_right_associative(prec))
Denys Vlasenko51850c82010-09-13 01:09:11 +0200661 ) {
662 stackptr++;
Mike Frysinger98c52642009-04-02 10:02:37 +0000663 break;
Denys Vlasenko51850c82010-09-13 01:09:11 +0200664 }
Mike Frysinger98c52642009-04-02 10:02:37 +0000665 }
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200666 errcode = arith_apply(math_state, prev_op, numstack, &numstackptr);
Denys Vlasenkob771c652010-09-13 00:34:26 +0200667 if (errcode)
668 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000669 }
670 if (op == TOK_RPAREN) {
671 goto err;
672 }
673 }
674
675 /* Push this operator to the stack and remember it. */
676 *stackptr++ = lasttok = op;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200677 next: ;
678 } /* while (1) */
679
680 err:
681 numstack->val = errcode = -1;
682 ret:
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200683 math_state->errcode = errcode;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200684 return numstack->val;
Mike Frysinger98c52642009-04-02 10:02:37 +0000685}
686
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200687arith_t FAST_FUNC
688arith(arith_state_t *math_state, const char *expr)
689{
690 math_state->list_of_recursed_names = NULL;
691 return evaluate_string(math_state, expr);
692}
693
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000694/*
Mike Frysinger98c52642009-04-02 10:02:37 +0000695 * Copyright (c) 1989, 1991, 1993, 1994
696 * The Regents of the University of California. All rights reserved.
697 *
698 * This code is derived from software contributed to Berkeley by
699 * Kenneth Almquist.
700 *
701 * Redistribution and use in source and binary forms, with or without
702 * modification, are permitted provided that the following conditions
703 * are met:
704 * 1. Redistributions of source code must retain the above copyright
705 * notice, this list of conditions and the following disclaimer.
706 * 2. Redistributions in binary form must reproduce the above copyright
707 * notice, this list of conditions and the following disclaimer in the
708 * documentation and/or other materials provided with the distribution.
709 * 3. Neither the name of the University nor the names of its contributors
710 * may be used to endorse or promote products derived from this software
711 * without specific prior written permission.
712 *
713 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
714 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
715 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
716 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
717 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
718 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
719 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
720 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
721 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
722 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
723 * SUCH DAMAGE.
724 */