blob: 871c06c3ee19a73be530e19640918a9063df1d26 [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>
Denys Vlasenko063847d2010-09-15 13:33:02 +020029 *
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 */
Mike Frysinger98c52642009-04-02 10:02:37 +000049
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).
Denys Vlasenkobd147702010-09-13 11:11:40 +020063 */
Mike Frysinger98c52642009-04-02 10:02:37 +000064
65/*
66 * Aug 24, 2001 Manuel Novoa III
67 *
68 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
69 *
70 * 1) In arith_apply():
71 * a) Cached values of *numptr and &(numptr[-1]).
72 * b) Removed redundant test for zero denominator.
73 *
74 * 2) In arith():
75 * a) Eliminated redundant code for processing operator tokens by moving
76 * to a table-based implementation. Also folded handling of parens
77 * into the table.
78 * b) Combined all 3 loops which called arith_apply to reduce generated
79 * code size at the cost of speed.
80 *
81 * 3) The following expressions were treated as valid by the original code:
82 * 1() , 0! , 1 ( *3 ) .
83 * These bugs have been fixed by internally enclosing the expression in
84 * parens and then checking that all binary ops and right parens are
85 * preceded by a valid expression (NUM_TOKEN).
86 *
87 * Note: It may be desirable to replace Aaron's test for whitespace with
88 * ctype's isspace() if it is used by another busybox applet or if additional
89 * whitespace chars should be considered. Look below the "#include"s for a
90 * precompiler test.
91 */
Mike Frysinger98c52642009-04-02 10:02:37 +000092/*
93 * Aug 26, 2001 Manuel Novoa III
94 *
95 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
96 *
97 * Merge in Aaron's comments previously posted to the busybox list,
98 * modified slightly to take account of my changes to the code.
99 *
100 */
Mike Frysinger98c52642009-04-02 10:02:37 +0000101/*
102 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
103 *
104 * - allow access to variable,
Denys Vlasenkobd147702010-09-13 11:11:40 +0200105 * use recursive value indirection: c="2*2"; a="c"; echo $((a+=2)) produce 6
106 * - implement assign syntax (VAR=expr, +=, *= etc)
107 * - implement exponentiation (** operator)
108 * - implement comma separated - expr, expr
109 * - implement ++expr --expr expr++ expr--
110 * - implement expr ? expr : expr (but second expr is always calculated)
Mike Frysinger98c52642009-04-02 10:02:37 +0000111 * - allow hexadecimal and octal numbers
Denys Vlasenkobd147702010-09-13 11:11:40 +0200112 * - restore lost XOR operator
113 * - protect $((num num)) as true zero expr (Manuel's error)
Mike Frysinger98c52642009-04-02 10:02:37 +0000114 * - always use special isspace(), see comment from bash ;-)
115 */
Denys Vlasenko03dad222010-01-12 23:29:57 +0100116#include "libbb.h"
117#include "math.h"
118
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200119#define lookupvar (math_state->lookupvar)
120#define setvar (math_state->setvar )
121//#define endofname (math_state->endofname)
Mike Frysinger98c52642009-04-02 10:02:37 +0000122
Mike Frysinger98c52642009-04-02 10:02:37 +0000123typedef unsigned char operator;
124
125/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
126 * precedence, and 3 high bits are an ID unique across operators of that
127 * precedence. The ID portion is so that multiple operators can have the
128 * same precedence, ensuring that the leftmost one is evaluated first.
Denys Vlasenkobd147702010-09-13 11:11:40 +0200129 * Consider * and /
130 */
131#define tok_decl(prec,id) (((id)<<5) | (prec))
132#define PREC(op) ((op) & 0x1F)
Mike Frysinger98c52642009-04-02 10:02:37 +0000133
Denys Vlasenkobd147702010-09-13 11:11:40 +0200134#define TOK_LPAREN tok_decl(0,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000135
Denys Vlasenkobd147702010-09-13 11:11:40 +0200136#define TOK_COMMA tok_decl(1,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000137
Denys Vlasenkobd147702010-09-13 11:11:40 +0200138/* All assignments are right associative and have the same precedence,
139 * but there are 11 of them, which doesn't fit into 3 bits for unique id.
140 * Abusing another precedence level:
141 */
142#define TOK_ASSIGN tok_decl(2,0)
143#define TOK_AND_ASSIGN tok_decl(2,1)
144#define TOK_OR_ASSIGN tok_decl(2,2)
145#define TOK_XOR_ASSIGN tok_decl(2,3)
146#define TOK_PLUS_ASSIGN tok_decl(2,4)
147#define TOK_MINUS_ASSIGN tok_decl(2,5)
148#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
149#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
Mike Frysinger98c52642009-04-02 10:02:37 +0000150
Denys Vlasenkobd147702010-09-13 11:11:40 +0200151#define TOK_MUL_ASSIGN tok_decl(3,0)
152#define TOK_DIV_ASSIGN tok_decl(3,1)
153#define TOK_REM_ASSIGN tok_decl(3,2)
Mike Frysinger98c52642009-04-02 10:02:37 +0000154
Denys Vlasenkobd147702010-09-13 11:11:40 +0200155#define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000156
Denys Vlasenkobd147702010-09-13 11:11:40 +0200157/* ternary conditional operator is right associative too */
158#define TOK_CONDITIONAL tok_decl(4,0)
159#define TOK_CONDITIONAL_SEP tok_decl(4,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000160
Denys Vlasenkobd147702010-09-13 11:11:40 +0200161#define TOK_OR tok_decl(5,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000162
Denys Vlasenkobd147702010-09-13 11:11:40 +0200163#define TOK_AND tok_decl(6,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000164
Denys Vlasenkobd147702010-09-13 11:11:40 +0200165#define TOK_BOR tok_decl(7,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000166
Denys Vlasenkobd147702010-09-13 11:11:40 +0200167#define TOK_BXOR tok_decl(8,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000168
Denys Vlasenkobd147702010-09-13 11:11:40 +0200169#define TOK_BAND tok_decl(9,0)
Mike Frysinger98c52642009-04-02 10:02:37 +0000170
Denys Vlasenkobd147702010-09-13 11:11:40 +0200171#define TOK_EQ tok_decl(10,0)
172#define TOK_NE tok_decl(10,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000173
Denys Vlasenkobd147702010-09-13 11:11:40 +0200174#define TOK_LT tok_decl(11,0)
175#define TOK_GT tok_decl(11,1)
176#define TOK_GE tok_decl(11,2)
177#define TOK_LE tok_decl(11,3)
Mike Frysinger98c52642009-04-02 10:02:37 +0000178
Denys Vlasenkobd147702010-09-13 11:11:40 +0200179#define TOK_LSHIFT tok_decl(12,0)
180#define TOK_RSHIFT tok_decl(12,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000181
Denys Vlasenkobd147702010-09-13 11:11:40 +0200182#define TOK_ADD tok_decl(13,0)
183#define TOK_SUB tok_decl(13,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000184
Denys Vlasenkobd147702010-09-13 11:11:40 +0200185#define TOK_MUL tok_decl(14,0)
186#define TOK_DIV tok_decl(14,1)
187#define TOK_REM tok_decl(14,2)
Mike Frysinger98c52642009-04-02 10:02:37 +0000188
Denys Vlasenkobd147702010-09-13 11:11:40 +0200189/* exponent is right associative */
190#define TOK_EXPONENT tok_decl(15,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000191
Denys Vlasenkobd147702010-09-13 11:11:40 +0200192/* unary operators */
193#define UNARYPREC 16
194#define TOK_BNOT tok_decl(UNARYPREC,0)
195#define TOK_NOT tok_decl(UNARYPREC,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000196
Denys Vlasenkobd147702010-09-13 11:11:40 +0200197#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
198#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000199
Denys Vlasenkobd147702010-09-13 11:11:40 +0200200#define PREC_PRE (UNARYPREC+2)
Mike Frysinger98c52642009-04-02 10:02:37 +0000201
Denys Vlasenkobd147702010-09-13 11:11:40 +0200202#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
203#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000204
Denys Vlasenkobd147702010-09-13 11:11:40 +0200205#define PREC_POST (UNARYPREC+3)
Mike Frysinger98c52642009-04-02 10:02:37 +0000206
Denys Vlasenkobd147702010-09-13 11:11:40 +0200207#define TOK_POST_INC tok_decl(PREC_POST, 0)
208#define TOK_POST_DEC tok_decl(PREC_POST, 1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000209
Denys Vlasenkobd147702010-09-13 11:11:40 +0200210#define SPEC_PREC (UNARYPREC+4)
Mike Frysinger98c52642009-04-02 10:02:37 +0000211
Denys Vlasenkobd147702010-09-13 11:11:40 +0200212#define TOK_NUM tok_decl(SPEC_PREC, 0)
213#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
Mike Frysinger98c52642009-04-02 10:02:37 +0000214
215static int
216tok_have_assign(operator op)
217{
218 operator prec = PREC(op);
219
Denys Vlasenkobd147702010-09-13 11:11:40 +0200220 fix_assignment_prec(prec);
Mike Frysinger98c52642009-04-02 10:02:37 +0000221 return (prec == PREC(TOK_ASSIGN) ||
222 prec == PREC_PRE || prec == PREC_POST);
223}
224
225static int
Denys Vlasenkobd147702010-09-13 11:11:40 +0200226is_right_associative(operator prec)
Mike Frysinger98c52642009-04-02 10:02:37 +0000227{
228 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
229 || prec == PREC(TOK_CONDITIONAL));
230}
231
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200232
Mike Frysinger98c52642009-04-02 10:02:37 +0000233typedef struct {
234 arith_t val;
235 arith_t contidional_second_val;
236 char contidional_second_val_initialized;
237 char *var; /* if NULL then is regular number,
238 else is variable name */
239} v_n_t;
240
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200241typedef struct remembered_name {
242 struct remembered_name *next;
Mike Frysinger98c52642009-04-02 10:02:37 +0000243 const char *var;
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200244} remembered_name;
Mike Frysinger98c52642009-04-02 10:02:37 +0000245
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200246
247static arith_t FAST_FUNC
248evaluate_string(arith_state_t *math_state, const char *expr);
Mike Frysinger98c52642009-04-02 10:02:37 +0000249
Denys Vlasenko063847d2010-09-15 13:33:02 +0200250static const char*
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 if (p) {
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200256 remembered_name *cur;
257 remembered_name cur_save;
Mike Frysinger98c52642009-04-02 10:02:37 +0000258
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200259 /* did we already see this name?
260 * testcase: a=b; b=a; echo $((a))
261 */
262 for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
Mike Frysinger98c52642009-04-02 10:02:37 +0000263 if (strcmp(cur->var, t->var) == 0) {
Denys Vlasenko063847d2010-09-15 13:33:02 +0200264 /* Yes */
265 return "expression recursion loop detected";
Mike Frysinger98c52642009-04-02 10:02:37 +0000266 }
267 }
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200268
269 /* push current var name */
270 cur = math_state->list_of_recursed_names;
Mike Frysinger98c52642009-04-02 10:02:37 +0000271 cur_save.var = t->var;
272 cur_save.next = cur;
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200273 math_state->list_of_recursed_names = &cur_save;
Mike Frysinger98c52642009-04-02 10:02:37 +0000274
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200275 /* recursively evaluate p as expression */
276 t->val = evaluate_string(math_state, p);
277
278 /* pop current var name */
279 math_state->list_of_recursed_names = cur;
280
Denys Vlasenko063847d2010-09-15 13:33:02 +0200281 return math_state->errmsg;
Mike Frysinger98c52642009-04-02 10:02:37 +0000282 }
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200283 /* treat undefined var as 0 */
Mike Frysinger98c52642009-04-02 10:02:37 +0000284 t->val = 0;
285 }
286 return 0;
287}
288
Denys Vlasenkobd147702010-09-13 11:11:40 +0200289/* "Applying" a token means performing it on the top elements on the integer
290 * stack. For an unary operator it will only change the top element, but a
291 * binary operator will pop two arguments and push the result */
Denys Vlasenko063847d2010-09-15 13:33:02 +0200292static NOINLINE const char*
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200293arith_apply(arith_state_t *math_state, operator op, v_n_t *numstack, v_n_t **numstackptr)
Mike Frysinger98c52642009-04-02 10:02:37 +0000294{
Denys Vlasenkobd147702010-09-13 11:11:40 +0200295#define NUMPTR (*numstackptr)
296
Mike Frysinger98c52642009-04-02 10:02:37 +0000297 v_n_t *numptr_m1;
298 arith_t numptr_val, rez;
Denys Vlasenko063847d2010-09-15 13:33:02 +0200299 const char *err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000300
301 /* There is no operator that can work without arguments */
Denys Vlasenkobd147702010-09-13 11:11:40 +0200302 if (NUMPTR == numstack)
303 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000304 numptr_m1 = NUMPTR - 1;
305
Denys Vlasenkobd147702010-09-13 11:11:40 +0200306 /* Check operand is var with noninteger value */
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200307 err = arith_lookup_val(math_state, numptr_m1);
308 if (err)
309 return err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000310
311 rez = numptr_m1->val;
312 if (op == TOK_UMINUS)
313 rez *= -1;
314 else if (op == TOK_NOT)
315 rez = !rez;
316 else if (op == TOK_BNOT)
317 rez = ~rez;
318 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
319 rez++;
320 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
321 rez--;
322 else if (op != TOK_UPLUS) {
323 /* Binary operators */
324
325 /* check and binary operators need two arguments */
326 if (numptr_m1 == numstack) goto err;
327
328 /* ... and they pop one */
329 --NUMPTR;
330 numptr_val = rez;
331 if (op == TOK_CONDITIONAL) {
332 if (!numptr_m1->contidional_second_val_initialized) {
333 /* protect $((expr1 ? expr2)) without ": expr" */
334 goto err;
335 }
336 rez = numptr_m1->contidional_second_val;
337 } else if (numptr_m1->contidional_second_val_initialized) {
338 /* protect $((expr1 : expr2)) without "expr ? " */
339 goto err;
340 }
341 numptr_m1 = NUMPTR - 1;
342 if (op != TOK_ASSIGN) {
343 /* check operand is var with noninteger value for not '=' */
Denys Vlasenko06d44d72010-09-13 12:49:03 +0200344 err = arith_lookup_val(math_state, numptr_m1);
345 if (err)
346 return err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000347 }
348 if (op == TOK_CONDITIONAL) {
349 numptr_m1->contidional_second_val = rez;
350 }
351 rez = numptr_m1->val;
352 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
353 rez |= numptr_val;
354 else if (op == TOK_OR)
355 rez = numptr_val || rez;
356 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
357 rez &= numptr_val;
358 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
359 rez ^= numptr_val;
360 else if (op == TOK_AND)
361 rez = rez && numptr_val;
362 else if (op == TOK_EQ)
363 rez = (rez == numptr_val);
364 else if (op == TOK_NE)
365 rez = (rez != numptr_val);
366 else if (op == TOK_GE)
367 rez = (rez >= numptr_val);
368 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
369 rez >>= numptr_val;
370 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
371 rez <<= numptr_val;
372 else if (op == TOK_GT)
373 rez = (rez > numptr_val);
374 else if (op == TOK_LT)
375 rez = (rez < numptr_val);
376 else if (op == TOK_LE)
377 rez = (rez <= numptr_val);
378 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
379 rez *= numptr_val;
380 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
381 rez += numptr_val;
382 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
383 rez -= numptr_val;
384 else if (op == TOK_ASSIGN || op == TOK_COMMA)
385 rez = numptr_val;
386 else if (op == TOK_CONDITIONAL_SEP) {
387 if (numptr_m1 == numstack) {
388 /* protect $((expr : expr)) without "expr ? " */
389 goto err;
390 }
391 numptr_m1->contidional_second_val_initialized = op;
392 numptr_m1->contidional_second_val = numptr_val;
393 } else if (op == TOK_CONDITIONAL) {
394 rez = rez ?
395 numptr_val : numptr_m1->contidional_second_val;
396 } else if (op == TOK_EXPONENT) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200397 arith_t c;
Mike Frysinger98c52642009-04-02 10:02:37 +0000398 if (numptr_val < 0)
Denys Vlasenko063847d2010-09-15 13:33:02 +0200399 return "exponent less than 0";
Denys Vlasenkobd147702010-09-13 11:11:40 +0200400 c = 1;
401 while (--numptr_val >= 0)
402 c *= rez;
403 rez = c;
Denys Vlasenko063847d2010-09-15 13:33:02 +0200404 } else if (numptr_val == 0)
405 return "divide by zero";
Mike Frysinger98c52642009-04-02 10:02:37 +0000406 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
407 rez /= numptr_val;
408 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
409 rez %= numptr_val;
410 }
411 if (tok_have_assign(op)) {
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000412 char buf[sizeof(arith_t)*3 + 2];
Mike Frysinger98c52642009-04-02 10:02:37 +0000413
414 if (numptr_m1->var == NULL) {
415 /* Hmm, 1=2 ? */
416 goto err;
417 }
418 /* save to shell variable */
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000419 sprintf(buf, arith_t_fmt, rez);
Denys Vlasenko03dad222010-01-12 23:29:57 +0100420 setvar(numptr_m1->var, buf);
Mike Frysinger98c52642009-04-02 10:02:37 +0000421 /* after saving, make previous value for v++ or v-- */
422 if (op == TOK_POST_INC)
423 rez--;
424 else if (op == TOK_POST_DEC)
425 rez++;
426 }
427 numptr_m1->val = rez;
Denys Vlasenkobd147702010-09-13 11:11:40 +0200428 /* erase var name, it is just a number now */
Mike Frysinger98c52642009-04-02 10:02:37 +0000429 numptr_m1->var = NULL;
Denys Vlasenko063847d2010-09-15 13:33:02 +0200430 return NULL;
Mike Frysinger98c52642009-04-02 10:02:37 +0000431 err:
Denys Vlasenko063847d2010-09-15 13:33:02 +0200432 return "arithmetic syntax error";
Denys Vlasenkobd147702010-09-13 11:11:40 +0200433#undef NUMPTR
Mike Frysinger98c52642009-04-02 10:02:37 +0000434}
435
436/* longest must be first */
437static const char op_tokens[] ALIGN1 = {
438 '<','<','=',0, TOK_LSHIFT_ASSIGN,
439 '>','>','=',0, TOK_RSHIFT_ASSIGN,
440 '<','<', 0, TOK_LSHIFT,
441 '>','>', 0, TOK_RSHIFT,
442 '|','|', 0, TOK_OR,
443 '&','&', 0, TOK_AND,
444 '!','=', 0, TOK_NE,
445 '<','=', 0, TOK_LE,
446 '>','=', 0, TOK_GE,
447 '=','=', 0, TOK_EQ,
448 '|','=', 0, TOK_OR_ASSIGN,
449 '&','=', 0, TOK_AND_ASSIGN,
450 '*','=', 0, TOK_MUL_ASSIGN,
451 '/','=', 0, TOK_DIV_ASSIGN,
452 '%','=', 0, TOK_REM_ASSIGN,
453 '+','=', 0, TOK_PLUS_ASSIGN,
454 '-','=', 0, TOK_MINUS_ASSIGN,
455 '-','-', 0, TOK_POST_DEC,
456 '^','=', 0, TOK_XOR_ASSIGN,
457 '+','+', 0, TOK_POST_INC,
458 '*','*', 0, TOK_EXPONENT,
459 '!', 0, TOK_NOT,
460 '<', 0, TOK_LT,
461 '>', 0, TOK_GT,
462 '=', 0, TOK_ASSIGN,
463 '|', 0, TOK_BOR,
464 '&', 0, TOK_BAND,
465 '*', 0, TOK_MUL,
466 '/', 0, TOK_DIV,
467 '%', 0, TOK_REM,
468 '+', 0, TOK_ADD,
469 '-', 0, TOK_SUB,
470 '^', 0, TOK_BXOR,
471 /* uniq */
472 '~', 0, TOK_BNOT,
473 ',', 0, TOK_COMMA,
474 '?', 0, TOK_CONDITIONAL,
475 ':', 0, TOK_CONDITIONAL_SEP,
476 ')', 0, TOK_RPAREN,
477 '(', 0, TOK_LPAREN,
478 0
479};
Denys Vlasenkob771c652010-09-13 00:34:26 +0200480#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
Mike Frysinger98c52642009-04-02 10:02:37 +0000481
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +0200482const char* FAST_FUNC
483endofname(const char *name)
484{
485 if (!is_name(*name))
486 return name;
487 while (*++name) {
488 if (!is_in_name(*name))
489 break;
490 }
491 return name;
492}
493
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200494static arith_t FAST_FUNC
495evaluate_string(arith_state_t *math_state, const char *expr)
Mike Frysinger98c52642009-04-02 10:02:37 +0000496{
Denys Vlasenkob771c652010-09-13 00:34:26 +0200497 operator lasttok;
Denys Vlasenko063847d2010-09-15 13:33:02 +0200498 const char *errmsg;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200499 const char *start_expr = expr = skip_whitespace(expr);
500 unsigned expr_len = strlen(expr) + 2;
Mike Frysinger98c52642009-04-02 10:02:37 +0000501 /* Stack of integers */
502 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
503 * in any given correct or incorrect expression is left as an exercise to
504 * the reader. */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200505 v_n_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
506 v_n_t *numstackptr = numstack;
Mike Frysinger98c52642009-04-02 10:02:37 +0000507 /* Stack of operator tokens */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200508 operator *const stack = alloca(expr_len * sizeof(stack[0]));
509 operator *stackptr = stack;
Mike Frysinger98c52642009-04-02 10:02:37 +0000510
511 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
Denys Vlasenko063847d2010-09-15 13:33:02 +0200512 errmsg = NULL;
Mike Frysinger98c52642009-04-02 10:02:37 +0000513
514 while (1) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200515 const char *p;
516 operator op;
517 operator prec;
518 char arithval;
519
520 expr = skip_whitespace(expr);
Mike Frysinger98c52642009-04-02 10:02:37 +0000521 arithval = *expr;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200522 if (arithval == '\0') {
523 if (expr == start_expr) {
Mike Frysinger98c52642009-04-02 10:02:37 +0000524 /* Null expression. */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200525 numstack->val = 0;
526 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000527 }
528
529 /* This is only reached after all tokens have been extracted from the
530 * input stream. If there are still tokens on the operator stack, they
531 * are to be applied in order. At the end, there should be a final
532 * result on the integer stack */
533
Denys Vlasenkob771c652010-09-13 00:34:26 +0200534 if (expr != ptr_to_rparen + 1) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200535 /* If we haven't done so already,
536 * append a closing right paren
537 * and let the loop process it */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200538 expr = ptr_to_rparen;
Mike Frysinger98c52642009-04-02 10:02:37 +0000539 continue;
540 }
Denys Vlasenkobd147702010-09-13 11:11:40 +0200541 /* At this point, we're done with the expression */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200542 if (numstackptr != numstack + 1) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200543 /* ...but if there isn't, it's bad */
Denys Vlasenkob771c652010-09-13 00:34:26 +0200544 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000545 }
546 if (numstack->var) {
547 /* expression is $((var)) only, lookup now */
Denys Vlasenko063847d2010-09-15 13:33:02 +0200548 errmsg = arith_lookup_val(math_state, numstack);
Mike Frysinger98c52642009-04-02 10:02:37 +0000549 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200550 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000551 }
552
Mike Frysinger98c52642009-04-02 10:02:37 +0000553 p = endofname(expr);
554 if (p != expr) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200555 /* Name */
556 size_t var_name_size = (p-expr) + 1; /* +1 for NUL */
Mike Frysinger98c52642009-04-02 10:02:37 +0000557 numstackptr->var = alloca(var_name_size);
558 safe_strncpy(numstackptr->var, expr, var_name_size);
559 expr = p;
560 num:
561 numstackptr->contidional_second_val_initialized = 0;
562 numstackptr++;
563 lasttok = TOK_NUM;
564 continue;
565 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200566
Mike Frysinger98c52642009-04-02 10:02:37 +0000567 if (isdigit(arithval)) {
Denys Vlasenkob771c652010-09-13 00:34:26 +0200568 /* Number */
Mike Frysinger98c52642009-04-02 10:02:37 +0000569 numstackptr->var = NULL;
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200570 errno = 0;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200571 numstackptr->val = strto_arith_t(expr, (char**) &expr, 0);
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200572 if (errno)
573 numstackptr->val = 0; /* bash compat */
Mike Frysinger98c52642009-04-02 10:02:37 +0000574 goto num;
575 }
Mike Frysinger98c52642009-04-02 10:02:37 +0000576
Denys Vlasenkob771c652010-09-13 00:34:26 +0200577 /* Should be an operator */
578 p = op_tokens;
579 while (1) {
580 const char *e = expr;
581 /* Compare expr to current op_tokens[] element */
582 while (*p && *e == *p)
583 p++, e++;
584 if (*p == '\0') { /* match: operator is found */
585 expr = e;
Mike Frysinger98c52642009-04-02 10:02:37 +0000586 break;
587 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200588 /* Go to next element of op_tokens[] */
Mike Frysinger98c52642009-04-02 10:02:37 +0000589 while (*p)
590 p++;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200591 p += 2; /* skip NUL and TOK_foo bytes */
592 if (*p == '\0') /* no next element, operator not found */
593 goto err;
Mike Frysinger98c52642009-04-02 10:02:37 +0000594 }
Denys Vlasenkob771c652010-09-13 00:34:26 +0200595 op = p[1]; /* fetch TOK_foo value */
596 /* NB: expr now points past the operator */
Mike Frysinger98c52642009-04-02 10:02:37 +0000597
598 /* post grammar: a++ reduce to num */
599 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
600 lasttok = TOK_NUM;
601
602 /* Plus and minus are binary (not unary) _only_ if the last
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200603 * token was a number, or a right paren (which pretends to be
Mike Frysinger98c52642009-04-02 10:02:37 +0000604 * a number, since it evaluates to one). Think about it.
605 * It makes sense. */
606 if (lasttok != TOK_NUM) {
607 switch (op) {
608 case TOK_ADD:
609 op = TOK_UPLUS;
610 break;
611 case TOK_SUB:
612 op = TOK_UMINUS;
613 break;
614 case TOK_POST_INC:
615 op = TOK_PRE_INC;
616 break;
617 case TOK_POST_DEC:
618 op = TOK_PRE_DEC;
619 break;
620 }
621 }
Denys Vlasenko71016ba2009-06-05 16:24:29 +0200622 /* We don't want an unary operator to cause recursive descent on the
Mike Frysinger98c52642009-04-02 10:02:37 +0000623 * stack, because there can be many in a row and it could cause an
624 * operator to be evaluated before its argument is pushed onto the
Denys Vlasenkobd147702010-09-13 11:11:40 +0200625 * integer stack.
626 * But for binary operators, "apply" everything on the operator
Mike Frysinger98c52642009-04-02 10:02:37 +0000627 * stack until we find an operator with a lesser priority than the
Denys Vlasenkobd147702010-09-13 11:11:40 +0200628 * one we have just extracted.
629 * Left paren is given the lowest priority so it will never be
Mike Frysinger98c52642009-04-02 10:02:37 +0000630 * "applied" in this way.
631 * if associativity is right and priority eq, applied also skip
632 */
633 prec = PREC(op);
634 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
635 /* not left paren or unary */
636 if (lasttok != TOK_NUM) {
637 /* binary op must be preceded by a num */
638 goto err;
639 }
640 while (stackptr != stack) {
Denys Vlasenko51850c82010-09-13 01:09:11 +0200641 operator prev_op = *--stackptr;
Mike Frysinger98c52642009-04-02 10:02:37 +0000642 if (op == TOK_RPAREN) {
643 /* The algorithm employed here is simple: while we don't
644 * hit an open paren nor the bottom of the stack, pop
645 * tokens and apply them */
Denys Vlasenko51850c82010-09-13 01:09:11 +0200646 if (prev_op == TOK_LPAREN) {
Denys Vlasenkobd147702010-09-13 11:11:40 +0200647 /* Any operator directly after a
648 * close paren should consider itself binary */
Mike Frysinger98c52642009-04-02 10:02:37 +0000649 lasttok = TOK_NUM;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200650 goto next;
Mike Frysinger98c52642009-04-02 10:02:37 +0000651 }
652 } else {
Denys Vlasenko51850c82010-09-13 01:09:11 +0200653 operator prev_prec = PREC(prev_op);
Denys Vlasenkobd147702010-09-13 11:11:40 +0200654 fix_assignment_prec(prec);
655 fix_assignment_prec(prev_prec);
Denys Vlasenko51850c82010-09-13 01:09:11 +0200656 if (prev_prec < prec
Denys Vlasenkobd147702010-09-13 11:11:40 +0200657 || (prev_prec == prec && is_right_associative(prec))
Denys Vlasenko51850c82010-09-13 01:09:11 +0200658 ) {
659 stackptr++;
Mike Frysinger98c52642009-04-02 10:02:37 +0000660 break;
Denys Vlasenko51850c82010-09-13 01:09:11 +0200661 }
Mike Frysinger98c52642009-04-02 10:02:37 +0000662 }
Denys Vlasenko063847d2010-09-15 13:33:02 +0200663 errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr);
664 if (errmsg)
Denys Vlasenkob771c652010-09-13 00:34:26 +0200665 goto ret;
Mike Frysinger98c52642009-04-02 10:02:37 +0000666 }
667 if (op == TOK_RPAREN) {
668 goto err;
669 }
670 }
671
672 /* Push this operator to the stack and remember it. */
673 *stackptr++ = lasttok = op;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200674 next: ;
675 } /* while (1) */
676
677 err:
Denys Vlasenko063847d2010-09-15 13:33:02 +0200678 numstack->val = -1;
679 errmsg = "arithmetic syntax error";
Denys Vlasenkob771c652010-09-13 00:34:26 +0200680 ret:
Denys Vlasenko063847d2010-09-15 13:33:02 +0200681 math_state->errmsg = errmsg;
Denys Vlasenkob771c652010-09-13 00:34:26 +0200682 return numstack->val;
Mike Frysinger98c52642009-04-02 10:02:37 +0000683}
684
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200685arith_t FAST_FUNC
686arith(arith_state_t *math_state, const char *expr)
687{
Denys Vlasenko063847d2010-09-15 13:33:02 +0200688 math_state->errmsg = NULL;
Denys Vlasenko0eac8ff2010-09-13 12:49:52 +0200689 math_state->list_of_recursed_names = NULL;
690 return evaluate_string(math_state, expr);
691}
692
Denis Vlasenkocc8289d2009-04-03 21:13:31 +0000693/*
Mike Frysinger98c52642009-04-02 10:02:37 +0000694 * Copyright (c) 1989, 1991, 1993, 1994
695 * The Regents of the University of California. All rights reserved.
696 *
697 * This code is derived from software contributed to Berkeley by
698 * Kenneth Almquist.
699 *
700 * Redistribution and use in source and binary forms, with or without
701 * modification, are permitted provided that the following conditions
702 * are met:
703 * 1. Redistributions of source code must retain the above copyright
704 * notice, this list of conditions and the following disclaimer.
705 * 2. Redistributions in binary form must reproduce the above copyright
706 * notice, this list of conditions and the following disclaimer in the
707 * documentation and/or other materials provided with the distribution.
708 * 3. Neither the name of the University nor the names of its contributors
709 * may be used to endorse or promote products derived from this software
710 * without specific prior written permission.
711 *
712 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
713 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
714 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
715 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
716 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
717 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
718 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
719 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
720 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
721 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
722 * SUCH DAMAGE.
723 */