Line data Source code
1 : /* expr.c -- arithmetic expression evaluation. */
2 :
3 : /* Copyright (C) 1990-2015 Free Software Foundation, Inc.
4 :
5 : This file is part of GNU Bash, the Bourne Again SHell.
6 :
7 : Bash is free software: you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation, either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : Bash is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with Bash. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : /*
22 : All arithmetic is done as intmax_t integers with no checking for overflow
23 : (though division by 0 is caught and flagged as an error).
24 :
25 : The following operators are handled, grouped into a set of levels in
26 : order of decreasing precedence.
27 :
28 : "id++", "id--" [post-increment and post-decrement]
29 : "++id", "--id" [pre-increment and pre-decrement]
30 : "-", "+" [(unary operators)]
31 : "!", "~"
32 : "**" [(exponentiation)]
33 : "*", "/", "%"
34 : "+", "-"
35 : "<<", ">>"
36 : "<=", ">=", "<", ">"
37 : "==", "!="
38 : "&"
39 : "^"
40 : "|"
41 : "&&"
42 : "||"
43 : "expr ? expr : expr"
44 : "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="
45 : , [comma]
46 :
47 : (Note that most of these operators have special meaning to bash, and an
48 : entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure
49 : that it is passed intact to the evaluator when using `let'. When using
50 : the $[] or $(( )) forms, the text between the `[' and `]' or `((' and `))'
51 : is treated as if in double quotes.)
52 :
53 : Sub-expressions within parentheses have a precedence level greater than
54 : all of the above levels and are evaluated first. Within a single prece-
55 : dence group, evaluation is left-to-right, except for the arithmetic
56 : assignment operator (`='), which is evaluated right-to-left (as in C).
57 :
58 : The expression evaluator returns the value of the expression (assignment
59 : statements have as a value what is returned by the RHS). The `let'
60 : builtin, on the other hand, returns 0 if the last expression evaluates to
61 : a non-zero, and 1 otherwise.
62 :
63 : Implementation is a recursive-descent parser.
64 :
65 : Chet Ramey
66 : chet@po.cwru.edu
67 : */
68 :
69 : #include "config.h"
70 :
71 : #include <stdio.h>
72 : #include "bashansi.h"
73 :
74 : #if defined (HAVE_UNISTD_H)
75 : # ifdef _MINIX
76 : # include <sys/types.h>
77 : # endif
78 : # include <unistd.h>
79 : #endif
80 :
81 : #include "chartypes.h"
82 : #include "bashintl.h"
83 :
84 : #include "shell.h"
85 : #include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */
86 :
87 : /* Because of the $((...)) construct, expressions may include newlines.
88 : Here is a macro which accepts newlines, tabs and spaces as whitespace. */
89 : #define cr_whitespace(c) (whitespace(c) || ((c) == '\n'))
90 :
91 : /* Size be which the expression stack grows when necessary. */
92 : #define EXPR_STACK_GROW_SIZE 10
93 :
94 : /* Maximum amount of recursion allowed. This prevents a non-integer
95 : variable such as "num=num+2" from infinitely adding to itself when
96 : "let num=num+2" is given. */
97 : #define MAX_EXPR_RECURSION_LEVEL 1024
98 :
99 : /* The Tokens. Singing "The Lion Sleeps Tonight". */
100 :
101 : #define EQEQ 1 /* "==" */
102 : #define NEQ 2 /* "!=" */
103 : #define LEQ 3 /* "<=" */
104 : #define GEQ 4 /* ">=" */
105 : #define STR 5 /* string */
106 : #define NUM 6 /* number */
107 : #define LAND 7 /* "&&" Logical AND */
108 : #define LOR 8 /* "||" Logical OR */
109 : #define LSH 9 /* "<<" Left SHift */
110 : #define RSH 10 /* ">>" Right SHift */
111 : #define OP_ASSIGN 11 /* op= expassign as in Posix.2 */
112 : #define COND 12 /* exp1 ? exp2 : exp3 */
113 : #define POWER 13 /* exp1**exp2 */
114 : #define PREINC 14 /* ++var */
115 : #define PREDEC 15 /* --var */
116 : #define POSTINC 16 /* var++ */
117 : #define POSTDEC 17 /* var-- */
118 : #define EQ '='
119 : #define GT '>'
120 : #define LT '<'
121 : #define PLUS '+'
122 : #define MINUS '-'
123 : #define MUL '*'
124 : #define DIV '/'
125 : #define MOD '%'
126 : #define NOT '!'
127 : #define LPAR '('
128 : #define RPAR ')'
129 : #define BAND '&' /* Bitwise AND */
130 : #define BOR '|' /* Bitwise OR. */
131 : #define BXOR '^' /* Bitwise eXclusive OR. */
132 : #define BNOT '~' /* Bitwise NOT; Two's complement. */
133 : #define QUES '?'
134 : #define COL ':'
135 : #define COMMA ','
136 :
137 : /* This should be the function corresponding to the operator with the
138 : highest precedence. */
139 : #define EXP_HIGHEST expcomma
140 :
141 : #ifndef MAX_INT_LEN
142 : # define MAX_INT_LEN 32
143 : #endif
144 :
145 : struct lvalue
146 : {
147 : char *tokstr; /* possibly-rewritten lvalue if not NULL */
148 : intmax_t tokval; /* expression evaluated value */
149 : SHELL_VAR *tokvar; /* variable described by array or var reference */
150 : intmax_t ind; /* array index if not -1 */
151 : };
152 :
153 : /* A structure defining a single expression context. */
154 : typedef struct {
155 : int curtok, lasttok;
156 : char *expression, *tp, *lasttp;
157 : intmax_t tokval;
158 : char *tokstr;
159 : int noeval;
160 : struct lvalue lval;
161 : } EXPR_CONTEXT;
162 :
163 : static char *expression; /* The current expression */
164 : static char *tp; /* token lexical position */
165 : static char *lasttp; /* pointer to last token position */
166 : static int curtok; /* the current token */
167 : static int lasttok; /* the previous token */
168 : static int assigntok; /* the OP in OP= */
169 : static char *tokstr; /* current token string */
170 : static intmax_t tokval; /* current token value */
171 : static int noeval; /* set to 1 if no assignment to be done */
172 : static procenv_t evalbuf;
173 :
174 : static struct lvalue curlval = {0, 0, 0, -1};
175 : static struct lvalue lastlval = {0, 0, 0, -1};
176 :
177 : static int _is_arithop __P((int));
178 : static void readtok __P((void)); /* lexical analyzer */
179 :
180 : static void init_lvalue __P((struct lvalue *));
181 : #if 0
182 : static struct lvalue *alloc_lvalue __P((void));
183 : static void free_lvalue __P((struct lvalue *));
184 : #endif
185 :
186 : static intmax_t expr_streval __P((char *, int, struct lvalue *));
187 : static intmax_t strlong __P((char *));
188 : static void evalerror __P((const char *));
189 :
190 : static void pushexp __P((void));
191 : static void popexp __P((void));
192 : static void expr_unwind __P((void));
193 : static void expr_bind_variable __P((char *, char *));
194 : #if defined (ARRAY_VARS)
195 : static void expr_bind_array_element __P((char *, arrayind_t, char *));
196 : #endif
197 :
198 : static intmax_t subexpr __P((char *));
199 :
200 : static intmax_t expcomma __P((void));
201 : static intmax_t expassign __P((void));
202 : static intmax_t expcond __P((void));
203 : static intmax_t explor __P((void));
204 : static intmax_t expland __P((void));
205 : static intmax_t expbor __P((void));
206 : static intmax_t expbxor __P((void));
207 : static intmax_t expband __P((void));
208 : static intmax_t exp5 __P((void));
209 : static intmax_t exp4 __P((void));
210 : static intmax_t expshift __P((void));
211 : static intmax_t exp3 __P((void));
212 : static intmax_t bash_exp2 __P((void));
213 : static intmax_t exppower __P((void));
214 : static intmax_t exp1 __P((void));
215 : static intmax_t exp0 __P((void));
216 :
217 : /* Global var which contains the stack of expression contexts. */
218 : static EXPR_CONTEXT **expr_stack;
219 : static int expr_depth; /* Location in the stack. */
220 : static int expr_stack_size; /* Number of slots already allocated. */
221 :
222 : extern char *this_command_name;
223 : extern int unbound_vars_is_error, last_command_exit_value;
224 :
225 : #if defined (ARRAY_VARS)
226 : extern const char * const bash_badsub_errmsg;
227 : #endif
228 :
229 : #define SAVETOK(X) \
230 : do { \
231 : (X)->curtok = curtok; \
232 : (X)->lasttok = lasttok; \
233 : (X)->tp = tp; \
234 : (X)->lasttp = lasttp; \
235 : (X)->tokval = tokval; \
236 : (X)->tokstr = tokstr; \
237 : (X)->noeval = noeval; \
238 : (X)->lval = curlval; \
239 : } while (0)
240 :
241 : #define RESTORETOK(X) \
242 : do { \
243 : curtok = (X)->curtok; \
244 : lasttok = (X)->lasttok; \
245 : tp = (X)->tp; \
246 : lasttp = (X)->lasttp; \
247 : tokval = (X)->tokval; \
248 : tokstr = (X)->tokstr; \
249 : noeval = (X)->noeval; \
250 : curlval = (X)->lval; \
251 : } while (0)
252 :
253 : /* Push and save away the contents of the globals describing the
254 : current expression context. */
255 : static void
256 101 : pushexp ()
257 : {
258 101 : EXPR_CONTEXT *context;
259 :
260 101 : if (expr_depth >= MAX_EXPR_RECURSION_LEVEL)
261 0 : evalerror (_("expression recursion level exceeded"));
262 :
263 101 : if (expr_depth >= expr_stack_size)
264 : {
265 83 : expr_stack_size += EXPR_STACK_GROW_SIZE;
266 83 : expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *));
267 : }
268 :
269 101 : context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT));
270 :
271 101 : context->expression = expression;
272 101 : SAVETOK(context);
273 :
274 101 : expr_stack[expr_depth++] = context;
275 101 : }
276 :
277 : /* Pop the the contents of the expression context stack into the
278 : globals describing the current expression context. */
279 : static void
280 36 : popexp ()
281 : {
282 36 : EXPR_CONTEXT *context;
283 :
284 36 : if (expr_depth == 0)
285 0 : evalerror (_("recursion stack underflow"));
286 :
287 36 : context = expr_stack[--expr_depth];
288 :
289 36 : expression = context->expression;
290 36 : RESTORETOK (context);
291 :
292 36 : free (context);
293 36 : }
294 :
295 : static void
296 65 : expr_unwind ()
297 : {
298 65 : while (--expr_depth > 0)
299 : {
300 0 : if (expr_stack[expr_depth]->tokstr)
301 0 : free (expr_stack[expr_depth]->tokstr);
302 :
303 0 : if (expr_stack[expr_depth]->expression)
304 0 : free (expr_stack[expr_depth]->expression);
305 :
306 0 : free (expr_stack[expr_depth]);
307 : }
308 65 : free (expr_stack[expr_depth]); /* free the allocated EXPR_CONTEXT */
309 :
310 65 : noeval = 0; /* XXX */
311 65 : }
312 :
313 : static void
314 0 : expr_bind_variable (lhs, rhs)
315 : char *lhs, *rhs;
316 : {
317 0 : SHELL_VAR *v;
318 :
319 0 : v = bind_int_variable (lhs, rhs);
320 0 : if (v && (readonly_p (v) || noassign_p (v)))
321 0 : sh_longjmp (evalbuf, 1); /* variable assignment error */
322 0 : stupidly_hack_special_variables (lhs);
323 0 : }
324 :
325 : #if defined (ARRAY_VARS)
326 : /* Rewrite tok, which is of the form vname[expression], to vname[ind], where
327 : IND is the already-calculated value of expression. */
328 : static void
329 0 : expr_bind_array_element (tok, ind, rhs)
330 : char *tok;
331 : arrayind_t ind;
332 : char *rhs;
333 : {
334 0 : char *lhs, *vname;
335 0 : size_t llen;
336 0 : char ibuf[INT_STRLEN_BOUND (arrayind_t) + 1], *istr;
337 :
338 0 : istr = fmtumax (ind, 10, ibuf, sizeof (ibuf), 0);
339 0 : vname = array_variable_name (tok, (char **)NULL, (int *)NULL);
340 :
341 0 : llen = strlen (vname) + sizeof (ibuf) + 3;
342 0 : lhs = xmalloc (llen);
343 :
344 0 : sprintf (lhs, "%s[%s]", vname, istr); /* XXX */
345 :
346 : /*itrace("expr_bind_array_element: %s=%s", lhs, rhs);*/
347 0 : expr_bind_variable (lhs, rhs);
348 0 : free (vname);
349 0 : free (lhs);
350 0 : }
351 : #endif /* ARRAY_VARS */
352 :
353 : /* Evaluate EXPR, and return the arithmetic result. If VALIDP is
354 : non-null, a zero is stored into the location to which it points
355 : if the expression is invalid, non-zero otherwise. If a non-zero
356 : value is returned in *VALIDP, the return value of evalexp() may
357 : be used.
358 :
359 : The `while' loop after the longjmp is caught relies on the above
360 : implementation of pushexp and popexp leaving in expr_stack[0] the
361 : values that the variables had when the program started. That is,
362 : the first things saved are the initial values of the variables that
363 : were assigned at program startup or by the compiler. Therefore, it is
364 : safe to let the loop terminate when expr_depth == 0, without freeing up
365 : any of the expr_depth[0] stuff. */
366 : intmax_t
367 101 : evalexp (expr, validp)
368 : char *expr;
369 : int *validp;
370 : {
371 101 : intmax_t val;
372 101 : int c;
373 101 : procenv_t oevalbuf;
374 :
375 101 : val = 0;
376 101 : noeval = 0;
377 :
378 101 : FASTCOPY (evalbuf, oevalbuf, sizeof (evalbuf));
379 :
380 166 : c = setjmp_nosigs (evalbuf);
381 :
382 166 : if (c)
383 : {
384 65 : FREE (tokstr);
385 65 : FREE (expression);
386 65 : tokstr = expression = (char *)NULL;
387 :
388 65 : expr_unwind ();
389 :
390 65 : if (validp)
391 65 : *validp = 0;
392 65 : return (0);
393 : }
394 :
395 101 : val = subexpr (expr);
396 :
397 36 : if (validp)
398 36 : *validp = 1;
399 :
400 36 : FASTCOPY (oevalbuf, evalbuf, sizeof (evalbuf));
401 :
402 36 : return (val);
403 : }
404 :
405 : static intmax_t
406 101 : subexpr (expr)
407 : char *expr;
408 : {
409 101 : intmax_t val;
410 101 : char *p;
411 :
412 137 : for (p = expr; p && *p && cr_whitespace (*p); p++)
413 36 : ;
414 :
415 101 : if (p == NULL || *p == '\0')
416 : return (0);
417 :
418 101 : pushexp ();
419 101 : expression = savestring (expr);
420 101 : tp = expression;
421 :
422 101 : curtok = lasttok = 0;
423 101 : tokstr = (char *)NULL;
424 101 : tokval = 0;
425 202 : init_lvalue (&curlval);
426 101 : lastlval = curlval;
427 :
428 101 : readtok ();
429 :
430 63 : val = EXP_HIGHEST ();
431 :
432 36 : if (curtok != 0)
433 0 : evalerror (_("syntax error in expression"));
434 :
435 36 : FREE (tokstr);
436 36 : FREE (expression);
437 :
438 36 : popexp ();
439 :
440 36 : return val;
441 : }
442 :
443 : static intmax_t
444 63 : expcomma ()
445 : {
446 63 : register intmax_t value;
447 :
448 63 : value = expassign ();
449 63 : while (curtok == COMMA)
450 : {
451 0 : readtok ();
452 0 : value = expassign ();
453 : }
454 :
455 36 : return value;
456 : }
457 :
458 : static intmax_t
459 63 : expassign ()
460 : {
461 63 : register intmax_t value;
462 63 : char *lhs, *rhs;
463 63 : arrayind_t lind;
464 : #if defined (HAVE_IMAXDIV)
465 63 : imaxdiv_t idiv;
466 : #endif
467 :
468 63 : value = expcond ();
469 36 : if (curtok == EQ || curtok == OP_ASSIGN)
470 : {
471 0 : int special, op;
472 0 : intmax_t lvalue;
473 :
474 0 : special = curtok == OP_ASSIGN;
475 :
476 0 : if (lasttok != STR)
477 0 : evalerror (_("attempted assignment to non-variable"));
478 :
479 0 : if (special)
480 : {
481 0 : op = assigntok; /* a OP= b */
482 0 : lvalue = value;
483 : }
484 :
485 : /* XXX - watch out for pointer aliasing issues here */
486 0 : lhs = savestring (tokstr);
487 : /* save ind in case rhs is string var and evaluation overwrites it */
488 0 : lind = curlval.ind;
489 0 : readtok ();
490 0 : value = expassign ();
491 :
492 0 : if (special)
493 : {
494 0 : if ((op == DIV || op == MOD) && value == 0)
495 : {
496 0 : if (noeval == 0)
497 0 : evalerror (_("division by 0"));
498 : else
499 : value = 1;
500 : }
501 :
502 0 : switch (op)
503 : {
504 0 : case MUL:
505 0 : lvalue *= value;
506 0 : break;
507 0 : case DIV:
508 : case MOD:
509 0 : if (lvalue == INTMAX_MIN && value == -1)
510 0 : lvalue = (op == DIV) ? INTMAX_MIN : 0;
511 : else
512 : #if HAVE_IMAXDIV
513 : {
514 0 : idiv = imaxdiv (lvalue, value);
515 0 : lvalue = (op == DIV) ? idiv.quot : idiv.rem;
516 : }
517 : #else
518 : lvalue = (op == DIV) ? lvalue / value : lvalue % value;
519 : #endif
520 : break;
521 0 : case PLUS:
522 0 : lvalue += value;
523 0 : break;
524 0 : case MINUS:
525 0 : lvalue -= value;
526 0 : break;
527 0 : case LSH:
528 0 : lvalue <<= value;
529 0 : break;
530 0 : case RSH:
531 0 : lvalue >>= value;
532 0 : break;
533 0 : case BAND:
534 0 : lvalue &= value;
535 0 : break;
536 0 : case BOR:
537 0 : lvalue |= value;
538 0 : break;
539 0 : case BXOR:
540 0 : lvalue ^= value;
541 0 : break;
542 0 : default:
543 0 : free (lhs);
544 0 : evalerror (_("bug: bad expassign token"));
545 : break;
546 : }
547 : value = lvalue;
548 : }
549 :
550 0 : rhs = itos (value);
551 0 : if (noeval == 0)
552 : {
553 : #if defined (ARRAY_VARS)
554 0 : if (lind != -1)
555 0 : expr_bind_array_element (lhs, lind, rhs);
556 : else
557 : #endif
558 0 : expr_bind_variable (lhs, rhs);
559 : }
560 0 : if (curlval.tokstr && curlval.tokstr == tokstr)
561 0 : init_lvalue (&curlval);
562 :
563 0 : free (rhs);
564 0 : free (lhs);
565 0 : FREE (tokstr);
566 0 : tokstr = (char *)NULL; /* For freeing on errors. */
567 : }
568 :
569 36 : return (value);
570 : }
571 :
572 : /* Conditional expression (expr?expr:expr) */
573 : static intmax_t
574 63 : expcond ()
575 : {
576 63 : intmax_t cval, val1, val2, rval;
577 63 : int set_noeval;
578 :
579 63 : set_noeval = 0;
580 63 : rval = cval = explor ();
581 36 : if (curtok == QUES) /* found conditional expr */
582 : {
583 0 : if (cval == 0)
584 : {
585 0 : set_noeval = 1;
586 0 : noeval++;
587 : }
588 :
589 0 : readtok ();
590 0 : if (curtok == 0 || curtok == COL)
591 0 : evalerror (_("expression expected"));
592 :
593 0 : val1 = EXP_HIGHEST ();
594 :
595 0 : if (set_noeval)
596 0 : noeval--;
597 0 : if (curtok != COL)
598 0 : evalerror (_("`:' expected for conditional expression"));
599 :
600 0 : set_noeval = 0;
601 0 : if (cval)
602 : {
603 0 : set_noeval = 1;
604 0 : noeval++;
605 : }
606 :
607 0 : readtok ();
608 0 : if (curtok == 0)
609 0 : evalerror (_("expression expected"));
610 0 : val2 = expcond ();
611 :
612 0 : if (set_noeval)
613 0 : noeval--;
614 0 : rval = cval ? val1 : val2;
615 0 : lasttok = COND;
616 : }
617 36 : return rval;
618 : }
619 :
620 : /* Logical OR. */
621 : static intmax_t
622 63 : explor ()
623 : {
624 63 : register intmax_t val1, val2;
625 63 : int set_noeval;
626 :
627 63 : val1 = expland ();
628 :
629 63 : while (curtok == LOR)
630 : {
631 0 : set_noeval = 0;
632 0 : if (val1 != 0)
633 : {
634 0 : noeval++;
635 0 : set_noeval = 1;
636 : }
637 0 : readtok ();
638 0 : val2 = expland ();
639 0 : if (set_noeval)
640 0 : noeval--;
641 0 : val1 = val1 || val2;
642 0 : lasttok = LOR;
643 : }
644 :
645 36 : return (val1);
646 : }
647 :
648 : /* Logical AND. */
649 : static intmax_t
650 63 : expland ()
651 : {
652 63 : register intmax_t val1, val2;
653 63 : int set_noeval;
654 :
655 63 : val1 = expbor ();
656 :
657 63 : while (curtok == LAND)
658 : {
659 0 : set_noeval = 0;
660 0 : if (val1 == 0)
661 : {
662 0 : set_noeval = 1;
663 0 : noeval++;
664 : }
665 0 : readtok ();
666 0 : val2 = expbor ();
667 0 : if (set_noeval)
668 0 : noeval--;
669 0 : val1 = val1 && val2;
670 0 : lasttok = LAND;
671 : }
672 :
673 36 : return (val1);
674 : }
675 :
676 : /* Bitwise OR. */
677 : static intmax_t
678 63 : expbor ()
679 : {
680 63 : register intmax_t val1, val2;
681 :
682 63 : val1 = expbxor ();
683 :
684 63 : while (curtok == BOR)
685 : {
686 0 : readtok ();
687 0 : val2 = expbxor ();
688 0 : val1 = val1 | val2;
689 0 : lasttok = NUM;
690 : }
691 :
692 36 : return (val1);
693 : }
694 :
695 : /* Bitwise XOR. */
696 : static intmax_t
697 63 : expbxor ()
698 : {
699 63 : register intmax_t val1, val2;
700 :
701 63 : val1 = expband ();
702 :
703 63 : while (curtok == BXOR)
704 : {
705 0 : readtok ();
706 0 : val2 = expband ();
707 0 : val1 = val1 ^ val2;
708 0 : lasttok = NUM;
709 : }
710 :
711 36 : return (val1);
712 : }
713 :
714 : /* Bitwise AND. */
715 : static intmax_t
716 63 : expband ()
717 : {
718 63 : register intmax_t val1, val2;
719 :
720 63 : val1 = exp5 ();
721 :
722 63 : while (curtok == BAND)
723 : {
724 0 : readtok ();
725 0 : val2 = exp5 ();
726 0 : val1 = val1 & val2;
727 0 : lasttok = NUM;
728 : }
729 :
730 36 : return (val1);
731 : }
732 :
733 : static intmax_t
734 63 : exp5 ()
735 : {
736 63 : register intmax_t val1, val2;
737 :
738 63 : val1 = exp4 ();
739 :
740 63 : while ((curtok == EQEQ) || (curtok == NEQ))
741 : {
742 0 : int op = curtok;
743 :
744 0 : readtok ();
745 0 : val2 = exp4 ();
746 0 : if (op == EQEQ)
747 0 : val1 = (val1 == val2);
748 0 : else if (op == NEQ)
749 0 : val1 = (val1 != val2);
750 0 : lasttok = NUM;
751 : }
752 36 : return (val1);
753 : }
754 :
755 : static intmax_t
756 63 : exp4 ()
757 : {
758 63 : register intmax_t val1, val2;
759 :
760 63 : val1 = expshift ();
761 63 : while ((curtok == LEQ) ||
762 36 : (curtok == GEQ) ||
763 36 : (curtok == LT) ||
764 : (curtok == GT))
765 : {
766 0 : int op = curtok;
767 :
768 0 : readtok ();
769 0 : val2 = expshift ();
770 :
771 0 : if (op == LEQ)
772 0 : val1 = val1 <= val2;
773 0 : else if (op == GEQ)
774 0 : val1 = val1 >= val2;
775 0 : else if (op == LT)
776 0 : val1 = val1 < val2;
777 : else /* (op == GT) */
778 0 : val1 = val1 > val2;
779 0 : lasttok = NUM;
780 : }
781 36 : return (val1);
782 : }
783 :
784 : /* Left and right shifts. */
785 : static intmax_t
786 63 : expshift ()
787 : {
788 63 : register intmax_t val1, val2;
789 :
790 63 : val1 = exp3 ();
791 :
792 63 : while ((curtok == LSH) || (curtok == RSH))
793 : {
794 0 : int op = curtok;
795 :
796 0 : readtok ();
797 0 : val2 = exp3 ();
798 :
799 0 : if (op == LSH)
800 0 : val1 = val1 << val2;
801 : else
802 0 : val1 = val1 >> val2;
803 0 : lasttok = NUM;
804 : }
805 :
806 36 : return (val1);
807 : }
808 :
809 : static intmax_t
810 63 : exp3 ()
811 : {
812 63 : register intmax_t val1, val2;
813 :
814 63 : val1 = bash_exp2 ();
815 :
816 63 : while ((curtok == PLUS) || (curtok == MINUS))
817 : {
818 0 : int op = curtok;
819 :
820 0 : readtok ();
821 0 : val2 = bash_exp2 ();
822 :
823 0 : if (op == PLUS)
824 0 : val1 += val2;
825 0 : else if (op == MINUS)
826 0 : val1 -= val2;
827 0 : lasttok = NUM;
828 : }
829 36 : return (val1);
830 : }
831 :
832 : static intmax_t
833 63 : bash_exp2 ()
834 : {
835 63 : register intmax_t val1, val2;
836 : #if defined (HAVE_IMAXDIV)
837 63 : imaxdiv_t idiv;
838 : #endif
839 :
840 63 : val1 = exppower ();
841 :
842 63 : while ((curtok == MUL) ||
843 36 : (curtok == DIV) ||
844 : (curtok == MOD))
845 : {
846 27 : int op = curtok;
847 27 : char *stp, *sltp;
848 :
849 27 : stp = tp;
850 27 : readtok ();
851 :
852 27 : val2 = exppower ();
853 :
854 : /* Handle division by 0 and twos-complement arithmetic overflow */
855 27 : if (((op == DIV) || (op == MOD)) && (val2 == 0))
856 : {
857 27 : if (noeval == 0)
858 : {
859 27 : sltp = lasttp;
860 27 : lasttp = stp;
861 27 : while (lasttp && *lasttp && whitespace (*lasttp))
862 0 : lasttp++;
863 27 : evalerror (_("division by 0"));
864 : lasttp = sltp;
865 : }
866 : else
867 : val2 = 1;
868 : }
869 0 : else if (op == MOD && val1 == INTMAX_MIN && val2 == -1)
870 : {
871 : val1 = 0;
872 : continue;
873 : }
874 0 : else if (op == DIV && val1 == INTMAX_MIN && val2 == -1)
875 0 : val2 = 1;
876 :
877 0 : if (op == MUL)
878 0 : val1 *= val2;
879 0 : else if (op == DIV || op == MOD)
880 : #if defined (HAVE_IMAXDIV)
881 : {
882 0 : idiv = imaxdiv (val1, val2);
883 0 : val1 = (op == DIV) ? idiv.quot : idiv.rem;
884 : }
885 : #else
886 : val1 = (op == DIV) ? val1 / val2 : val1 % val2;
887 : #endif
888 0 : lasttok = NUM;
889 : }
890 36 : return (val1);
891 : }
892 :
893 : static intmax_t
894 : ipow (base, exp)
895 : intmax_t base, exp;
896 : {
897 : intmax_t result;
898 :
899 : result = 1;
900 0 : while (exp)
901 : {
902 0 : if (exp & 1)
903 0 : result *= base;
904 0 : exp >>= 1;
905 0 : base *= base;
906 : }
907 : return result;
908 : }
909 :
910 : static intmax_t
911 90 : exppower ()
912 : {
913 90 : register intmax_t val1, val2;
914 :
915 90 : val1 = exp1 ();
916 90 : while (curtok == POWER)
917 : {
918 0 : readtok ();
919 0 : val2 = exppower (); /* exponentiation is right-associative */
920 0 : lasttok = NUM;
921 0 : if (val2 == 0)
922 : return (1);
923 0 : if (val2 < 0)
924 0 : evalerror (_("exponent less than 0"));
925 : val1 = ipow (val1, val2);
926 : }
927 : return (val1);
928 : }
929 :
930 : static intmax_t
931 126 : exp1 ()
932 : {
933 126 : register intmax_t val;
934 :
935 126 : if (curtok == NOT)
936 : {
937 0 : readtok ();
938 0 : val = !exp1 ();
939 0 : lasttok = NUM;
940 : }
941 126 : else if (curtok == BNOT)
942 : {
943 0 : readtok ();
944 0 : val = ~exp1 ();
945 0 : lasttok = NUM;
946 : }
947 126 : else if (curtok == MINUS)
948 : {
949 36 : readtok ();
950 36 : val = - exp1 ();
951 36 : lasttok = NUM;
952 : }
953 90 : else if (curtok == PLUS)
954 : {
955 0 : readtok ();
956 0 : val = exp1 ();
957 0 : lasttok = NUM;
958 : }
959 : else
960 90 : val = exp0 ();
961 :
962 126 : return (val);
963 : }
964 :
965 : static intmax_t
966 90 : exp0 ()
967 : {
968 90 : register intmax_t val = 0, v2;
969 90 : char *vincdec;
970 90 : int stok;
971 90 : EXPR_CONTEXT ec;
972 :
973 : /* XXX - might need additional logic here to decide whether or not
974 : pre-increment or pre-decrement is legal at this point. */
975 90 : if (curtok == PREINC || curtok == PREDEC)
976 : {
977 0 : stok = lasttok = curtok;
978 0 : readtok ();
979 0 : if (curtok != STR)
980 : /* readtok() catches this */
981 0 : evalerror (_("identifier expected after pre-increment or pre-decrement"));
982 :
983 0 : v2 = tokval + ((stok == PREINC) ? 1 : -1);
984 0 : vincdec = itos (v2);
985 0 : if (noeval == 0)
986 : {
987 : #if defined (ARRAY_VARS)
988 0 : if (curlval.ind != -1)
989 0 : expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec);
990 : else
991 : #endif
992 0 : expr_bind_variable (tokstr, vincdec);
993 : }
994 0 : free (vincdec);
995 0 : val = v2;
996 :
997 0 : curtok = NUM; /* make sure --x=7 is flagged as an error */
998 0 : readtok ();
999 : }
1000 90 : else if (curtok == LPAR)
1001 : {
1002 : /* XXX - save curlval here? Or entire expression context? */
1003 0 : readtok ();
1004 0 : val = EXP_HIGHEST ();
1005 :
1006 0 : if (curtok != RPAR) /* ( */
1007 0 : evalerror (_("missing `)'"));
1008 :
1009 : /* Skip over closing paren. */
1010 0 : readtok ();
1011 : }
1012 90 : else if ((curtok == NUM) || (curtok == STR))
1013 : {
1014 90 : val = tokval;
1015 90 : if (curtok == STR)
1016 : {
1017 90 : SAVETOK (&ec);
1018 90 : tokstr = (char *)NULL; /* keep it from being freed */
1019 90 : noeval = 1;
1020 90 : readtok ();
1021 90 : stok = curtok;
1022 :
1023 : /* post-increment or post-decrement */
1024 90 : if (stok == POSTINC || stok == POSTDEC)
1025 : {
1026 : /* restore certain portions of EC */
1027 0 : tokstr = ec.tokstr;
1028 0 : noeval = ec.noeval;
1029 0 : curlval = ec.lval;
1030 0 : lasttok = STR; /* ec.curtok */
1031 :
1032 0 : v2 = val + ((stok == POSTINC) ? 1 : -1);
1033 0 : vincdec = itos (v2);
1034 0 : if (noeval == 0)
1035 : {
1036 : #if defined (ARRAY_VARS)
1037 0 : if (curlval.ind != -1)
1038 0 : expr_bind_array_element (curlval.tokstr, curlval.ind, vincdec);
1039 : else
1040 : #endif
1041 0 : expr_bind_variable (tokstr, vincdec);
1042 : }
1043 0 : free (vincdec);
1044 0 : curtok = NUM; /* make sure x++=7 is flagged as an error */
1045 : }
1046 : else
1047 : {
1048 : /* XXX - watch out for pointer aliasing issues here */
1049 90 : if (stok == STR) /* free new tokstr before old one is restored */
1050 0 : FREE (tokstr);
1051 90 : RESTORETOK (&ec);
1052 : }
1053 : }
1054 :
1055 90 : readtok ();
1056 : }
1057 : else
1058 0 : evalerror (_("syntax error: operand expected"));
1059 :
1060 90 : return (val);
1061 : }
1062 :
1063 : static void
1064 : init_lvalue (lv)
1065 : struct lvalue *lv;
1066 : {
1067 128 : lv->tokstr = 0;
1068 128 : lv->tokvar = 0;
1069 101 : lv->tokval = lv->ind = -1;
1070 : }
1071 :
1072 : #if 0
1073 : static struct lvalue *
1074 : alloc_lvalue ()
1075 : {
1076 : struct lvalue *lv;
1077 :
1078 : lv = xmalloc (sizeof (struct lvalue));
1079 : init_lvalue (lv);
1080 : return (lv);
1081 : }
1082 : #endif
1083 :
1084 : #if 0
1085 : static void
1086 : free_lvalue (lv)
1087 : struct lvalue *lv;
1088 : {
1089 : free (lv); /* should be inlined */
1090 : }
1091 : #endif
1092 :
1093 : static intmax_t
1094 90 : expr_streval (tok, e, lvalue)
1095 : char *tok;
1096 : int e;
1097 : struct lvalue *lvalue;
1098 : {
1099 90 : SHELL_VAR *v;
1100 90 : char *value;
1101 90 : intmax_t tval;
1102 : #if defined (ARRAY_VARS)
1103 90 : arrayind_t ind;
1104 : #endif
1105 :
1106 : /*itrace("expr_streval: %s: noeval = %d", tok, noeval);*/
1107 : /* If we are suppressing evaluation, just short-circuit here instead of
1108 : going through the rest of the evaluator. */
1109 90 : if (noeval)
1110 : return (0);
1111 :
1112 : /* [[[[[ */
1113 : #if defined (ARRAY_VARS)
1114 90 : v = (e == ']') ? array_variable_part (tok, (char **)0, (int *)0) : find_variable (tok);
1115 : #else
1116 : v = find_variable (tok);
1117 : #endif
1118 :
1119 90 : if ((v == 0 || invisible_p (v)) && unbound_vars_is_error)
1120 : {
1121 : #if defined (ARRAY_VARS)
1122 0 : value = (e == ']') ? array_variable_name (tok, (char **)0, (int *)0) : tok;
1123 : #else
1124 : value = tok;
1125 : #endif
1126 :
1127 0 : last_command_exit_value = EXECUTION_FAILURE;
1128 0 : err_unboundvar (value);
1129 :
1130 : #if defined (ARRAY_VARS)
1131 0 : if (e == ']')
1132 0 : FREE (value); /* array_variable_name returns new memory */
1133 : #endif
1134 :
1135 0 : if (no_longjmp_on_fatal_error && interactive_shell)
1136 0 : sh_longjmp (evalbuf, 1);
1137 :
1138 0 : if (interactive_shell)
1139 : {
1140 0 : expr_unwind ();
1141 0 : top_level_cleanup ();
1142 0 : jump_to_top_level (DISCARD);
1143 : }
1144 : else
1145 0 : jump_to_top_level (FORCE_EOF);
1146 : }
1147 :
1148 : #if defined (ARRAY_VARS)
1149 90 : ind = -1;
1150 : /* Second argument of 0 to get_array_value means that we don't allow
1151 : references like array[@]. In this case, get_array_value is just
1152 : like get_variable_value in that it does not return newly-allocated
1153 : memory or quote the results. */
1154 90 : value = (e == ']') ? get_array_value (tok, 0, (int *)NULL, &ind) : get_variable_value (v);
1155 : #else
1156 : value = get_variable_value (v);
1157 : #endif
1158 :
1159 90 : tval = (value && *value) ? subexpr (value) : 0;
1160 :
1161 90 : if (lvalue)
1162 : {
1163 90 : lvalue->tokstr = tok; /* XXX */
1164 90 : lvalue->tokval = tval;
1165 90 : lvalue->tokvar = v; /* XXX */
1166 : #if defined (ARRAY_VARS)
1167 90 : lvalue->ind = ind;
1168 : #else
1169 : lvalue->ind = -1;
1170 : #endif
1171 : }
1172 :
1173 : return (tval);
1174 : }
1175 :
1176 : static int
1177 : _is_multiop (c)
1178 : int c;
1179 : {
1180 9 : switch (c)
1181 : {
1182 : case EQEQ:
1183 : case NEQ:
1184 : case LEQ:
1185 : case GEQ:
1186 : case LAND:
1187 : case LOR:
1188 : case LSH:
1189 : case RSH:
1190 : case OP_ASSIGN:
1191 : case COND:
1192 : case POWER:
1193 : case PREINC:
1194 : case PREDEC:
1195 : case POSTINC:
1196 : case POSTDEC:
1197 : return 1;
1198 : default:
1199 : return 0;
1200 : }
1201 : }
1202 :
1203 : static int
1204 245 : _is_arithop (c)
1205 : int c;
1206 : {
1207 245 : switch (c)
1208 : {
1209 : case EQ:
1210 : case GT:
1211 : case LT:
1212 : case PLUS:
1213 : case MINUS:
1214 : case MUL:
1215 : case DIV:
1216 : case MOD:
1217 : case NOT:
1218 : case LPAR:
1219 : case RPAR:
1220 : case BAND:
1221 : case BOR:
1222 : case BXOR:
1223 : case BNOT:
1224 : return 1; /* operator tokens */
1225 : case QUES:
1226 : case COL:
1227 : case COMMA:
1228 : return 1; /* questionable */
1229 47 : default:
1230 47 : return 0; /* anything else is invalid */
1231 : }
1232 : }
1233 :
1234 : /* Lexical analyzer/token reader for the expression evaluator. Reads the
1235 : next token and puts its value into curtok, while advancing past it.
1236 : Updates value of tp. May also set tokval (for number) or tokstr (for
1237 : string). */
1238 : static void
1239 443 : readtok ()
1240 : {
1241 443 : register char *cp, *xp;
1242 443 : register unsigned char c, c1;
1243 443 : register int e;
1244 :
1245 : /* Skip leading whitespace. */
1246 443 : cp = tp;
1247 443 : c = e = 0;
1248 614 : while (cp && (c = *cp) && (cr_whitespace (c)))
1249 171 : cp++;
1250 :
1251 443 : if (c)
1252 335 : cp++;
1253 :
1254 443 : if (c == '\0')
1255 : {
1256 108 : lasttok = curtok;
1257 108 : curtok = 0;
1258 108 : tp = cp;
1259 108 : return;
1260 : }
1261 335 : lasttp = tp = cp - 1;
1262 :
1263 335 : if (legal_variable_starter (c))
1264 90 : {
1265 : /* variable names not preceded with a dollar sign are shell variables. */
1266 : char *savecp;
1267 : EXPR_CONTEXT ec;
1268 : int peektok;
1269 :
1270 351 : while (legal_variable_char (c))
1271 252 : c = *cp++;
1272 :
1273 99 : c = *--cp;
1274 :
1275 : #if defined (ARRAY_VARS)
1276 99 : if (c == '[')
1277 : {
1278 0 : e = skipsubscript (cp, 0, 0);
1279 0 : if (cp[e] == ']')
1280 : {
1281 0 : cp += e + 1;
1282 0 : c = *cp;
1283 0 : e = ']';
1284 : }
1285 : else
1286 0 : evalerror (bash_badsub_errmsg);
1287 : }
1288 : #endif /* ARRAY_VARS */
1289 :
1290 99 : *cp = '\0';
1291 : /* XXX - watch out for pointer aliasing issues here */
1292 99 : if (curlval.tokstr && curlval.tokstr == tokstr)
1293 27 : init_lvalue (&curlval);
1294 :
1295 99 : FREE (tokstr);
1296 99 : tokstr = savestring (tp);
1297 99 : *cp = c;
1298 :
1299 : /* XXX - make peektok part of saved token state? */
1300 99 : SAVETOK (&ec);
1301 99 : tokstr = (char *)NULL; /* keep it from being freed */
1302 99 : tp = savecp = cp;
1303 99 : noeval = 1;
1304 99 : curtok = STR;
1305 99 : readtok ();
1306 90 : peektok = curtok;
1307 90 : if (peektok == STR) /* free new tokstr before old one is restored */
1308 0 : FREE (tokstr);
1309 90 : RESTORETOK (&ec);
1310 90 : cp = savecp;
1311 :
1312 : /* The tests for PREINC and PREDEC aren't strictly correct, but they
1313 : preserve old behavior if a construct like --x=9 is given. */
1314 90 : if (lasttok == PREINC || lasttok == PREDEC || peektok != EQ)
1315 : {
1316 90 : lastlval = curlval;
1317 90 : tokval = expr_streval (tokstr, e, &curlval);
1318 : }
1319 : else
1320 0 : tokval = 0;
1321 :
1322 90 : lasttok = curtok;
1323 90 : curtok = STR;
1324 : }
1325 236 : else if (DIGIT(c))
1326 : {
1327 0 : while (ISALNUM (c) || c == '#' || c == '@' || c == '_')
1328 0 : c = *cp++;
1329 :
1330 0 : c = *--cp;
1331 0 : *cp = '\0';
1332 :
1333 0 : tokval = strlong (tp);
1334 0 : *cp = c;
1335 0 : lasttok = curtok;
1336 0 : curtok = NUM;
1337 : }
1338 : else
1339 : {
1340 236 : c1 = *cp++;
1341 236 : if ((c == EQ) && (c1 == EQ))
1342 : c = EQEQ;
1343 236 : else if ((c == NOT) && (c1 == EQ))
1344 : c = NEQ;
1345 236 : else if ((c == GT) && (c1 == EQ))
1346 : c = GEQ;
1347 236 : else if ((c == LT) && (c1 == EQ))
1348 : c = LEQ;
1349 236 : else if ((c == LT) && (c1 == LT))
1350 : {
1351 0 : if (*cp == '=') /* a <<= b */
1352 : {
1353 0 : assigntok = LSH;
1354 0 : c = OP_ASSIGN;
1355 0 : cp++;
1356 : }
1357 : else
1358 : c = LSH;
1359 : }
1360 236 : else if ((c == GT) && (c1 == GT))
1361 : {
1362 0 : if (*cp == '=')
1363 : {
1364 0 : assigntok = RSH; /* a >>= b */
1365 0 : c = OP_ASSIGN;
1366 0 : cp++;
1367 : }
1368 : else
1369 : c = RSH;
1370 : }
1371 236 : else if ((c == BAND) && (c1 == BAND))
1372 : c = LAND;
1373 236 : else if ((c == BOR) && (c1 == BOR))
1374 : c = LOR;
1375 236 : else if ((c == '*') && (c1 == '*'))
1376 : c = POWER;
1377 236 : else if ((c == '-' || c == '+') && c1 == c && curtok == STR)
1378 0 : c = (c == '-') ? POSTDEC : POSTINC;
1379 236 : else if ((c == '-' || c == '+') && c1 == c)
1380 : {
1381 : /* Quickly scan forward to see if this is followed by optional
1382 : whitespace and an identifier. */
1383 : xp = cp;
1384 0 : while (xp && *xp && cr_whitespace (*xp))
1385 0 : xp++;
1386 0 : if (legal_variable_starter ((unsigned char)*xp))
1387 0 : c = (c == '-') ? PREDEC : PREINC;
1388 : else
1389 : cp--; /* not preinc or predec, so unget the character */
1390 : }
1391 236 : else if (c1 == EQ && member (c, "*/%+-&^|"))
1392 : {
1393 0 : assigntok = c; /* a OP= b */
1394 0 : c = OP_ASSIGN;
1395 : }
1396 236 : else if (_is_arithop (c) == 0)
1397 : {
1398 38 : cp--;
1399 : /* use curtok, since it hasn't been copied to lasttok yet */
1400 38 : if (curtok == 0 || _is_arithop (curtok) || _is_multiop (curtok))
1401 29 : evalerror (_("syntax error: operand expected"));
1402 : else
1403 9 : evalerror (_("syntax error: invalid arithmetic operator"));
1404 : }
1405 : else
1406 : cp--; /* `unget' the character */
1407 :
1408 : /* Should check here to make sure that the current character is one
1409 : of the recognized operators and flag an error if not. Could create
1410 : a character map the first time through and check it on subsequent
1411 : calls. */
1412 198 : lasttok = curtok;
1413 198 : curtok = c;
1414 : }
1415 288 : tp = cp;
1416 : }
1417 :
1418 : static void
1419 65 : evalerror (msg)
1420 : const char *msg;
1421 : {
1422 65 : char *name, *t;
1423 :
1424 65 : name = this_command_name;
1425 92 : for (t = expression; whitespace (*t); t++)
1426 27 : ;
1427 153 : internal_error (_("%s%s%s: %s (error token is \"%s\")"),
1428 : name ? name : "", name ? ": " : "", t,
1429 65 : msg, (lasttp && *lasttp) ? lasttp : "");
1430 65 : sh_longjmp (evalbuf, 1);
1431 : }
1432 :
1433 : /* Convert a string to an intmax_t integer, with an arbitrary base.
1434 : 0nnn -> base 8
1435 : 0[Xx]nn -> base 16
1436 : Anything else: [base#]number (this is implemented to match ksh93)
1437 :
1438 : Base may be >=2 and <=64. If base is <= 36, the numbers are drawn
1439 : from [0-9][a-zA-Z], and lowercase and uppercase letters may be used
1440 : interchangably. If base is > 36 and <= 64, the numbers are drawn
1441 : from [0-9][a-z][A-Z]_@ (a = 10, z = 35, A = 36, Z = 61, @ = 62, _ = 63 --
1442 : you get the picture). */
1443 :
1444 : static intmax_t
1445 0 : strlong (num)
1446 : char *num;
1447 : {
1448 0 : register char *s;
1449 0 : register unsigned char c;
1450 0 : int base, foundbase;
1451 0 : intmax_t val;
1452 :
1453 0 : s = num;
1454 :
1455 0 : base = 10;
1456 0 : foundbase = 0;
1457 0 : if (*s == '0')
1458 : {
1459 0 : s++;
1460 :
1461 0 : if (*s == '\0')
1462 : return 0;
1463 :
1464 : /* Base 16? */
1465 0 : if (*s == 'x' || *s == 'X')
1466 : {
1467 0 : base = 16;
1468 0 : s++;
1469 : }
1470 : else
1471 : base = 8;
1472 : foundbase++;
1473 : }
1474 :
1475 0 : val = 0;
1476 0 : for (c = *s++; c; c = *s++)
1477 : {
1478 0 : if (c == '#')
1479 : {
1480 0 : if (foundbase)
1481 0 : evalerror (_("invalid number"));
1482 :
1483 : /* Illegal base specifications raise an evaluation error. */
1484 0 : if (val < 2 || val > 64)
1485 0 : evalerror (_("invalid arithmetic base"));
1486 :
1487 0 : base = val;
1488 0 : val = 0;
1489 0 : foundbase++;
1490 : }
1491 0 : else if (ISALNUM(c) || (c == '_') || (c == '@'))
1492 : {
1493 0 : if (DIGIT(c))
1494 : c = TODIGIT(c);
1495 0 : else if (c >= 'a' && c <= 'z')
1496 0 : c -= 'a' - 10;
1497 0 : else if (c >= 'A' && c <= 'Z')
1498 0 : c -= 'A' - ((base <= 36) ? 10 : 36);
1499 0 : else if (c == '@')
1500 : c = 62;
1501 0 : else if (c == '_')
1502 0 : c = 63;
1503 :
1504 0 : if (c >= base)
1505 0 : evalerror (_("value too great for base"));
1506 :
1507 0 : val = (val * base) + c;
1508 : }
1509 : else
1510 : break;
1511 : }
1512 :
1513 : return (val);
1514 : }
1515 :
1516 : #if defined (EXPR_TEST)
1517 : void *
1518 : xmalloc (n)
1519 : int n;
1520 : {
1521 : return (malloc (n));
1522 : }
1523 :
1524 : void *
1525 : xrealloc (s, n)
1526 : char *s;
1527 : int n;
1528 : {
1529 : return (realloc (s, n));
1530 : }
1531 :
1532 : SHELL_VAR *find_variable () { return 0;}
1533 : SHELL_VAR *bind_variable () { return 0; }
1534 :
1535 : char *get_string_value () { return 0; }
1536 :
1537 : procenv_t top_level;
1538 :
1539 : main (argc, argv)
1540 : int argc;
1541 : char **argv;
1542 : {
1543 : register int i;
1544 : intmax_t v;
1545 : int expok;
1546 :
1547 : if (setjmp (top_level))
1548 : exit (0);
1549 :
1550 : for (i = 1; i < argc; i++)
1551 : {
1552 : v = evalexp (argv[i], &expok);
1553 : if (expok == 0)
1554 : fprintf (stderr, _("%s: expression error\n"), argv[i]);
1555 : else
1556 : printf ("'%s' -> %ld\n", argv[i], v);
1557 : }
1558 : exit (0);
1559 : }
1560 :
1561 : int
1562 : builtin_error (format, arg1, arg2, arg3, arg4, arg5)
1563 : char *format;
1564 : {
1565 : fprintf (stderr, "expr: ");
1566 : fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
1567 : fprintf (stderr, "\n");
1568 : return 0;
1569 : }
1570 :
1571 : char *
1572 : itos (n)
1573 : intmax_t n;
1574 : {
1575 : return ("42");
1576 : }
1577 :
1578 : #endif /* EXPR_TEST */
|