diff options
author | Mike Frysinger <vapier@gentoo.org> | 2009-04-02 10:02:37 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-04-02 10:02:37 +0000 |
commit | 98c52645c02dacebccae7d68d6c2627f9318fcf7 (patch) | |
tree | e0c64b5b24206f95e72fd060336f74cb459f2109 /shell/ash.c | |
parent | 551ffdccea39a9223ad451954db40fd7a6e20e79 (diff) |
split math code out of ash and into a standalone library so we can use it in any shell (like hush!)
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 734 |
1 files changed, 35 insertions, 699 deletions
diff --git a/shell/ash.c b/shell/ash.c index 4f7f38f6d..0d3ab0ff5 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -17,19 +17,6 @@ */ /* - * rewrite arith.y to micro stack based cryptic algorithm by - * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> - * - * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support - * dynamic variables. - * - * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be - * used in busybox and size optimizations, - * rewrote arith (see notes to this), added locale support, - * rewrote dynamic variables. - */ - -/* * The following should be set to reflect the type of system you have: * JOBS -> 1 if you have Berkeley job control, 0 otherwise. * define SYSV if you are running under System V. @@ -63,6 +50,7 @@ #include <paths.h> #include <setjmp.h> #include <fnmatch.h> +#include "math.h" #if defined SINGLE_APPLET_MAIN /* STANDALONE does not make sense, and won't compile */ @@ -197,6 +185,10 @@ struct globals_misc { #define debug optlist[15] #endif +#if ENABLE_SH_MATH_SUPPORT + arith_eval_hooks_t math_hooks; +#endif + /* trap handler commands */ /* * Sigmode records the current value of the signal handlers for the various @@ -246,6 +238,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc; #define random_LCG (G_misc.random_LCG ) #define backgndpid (G_misc.backgndpid ) #define job_warning (G_misc.job_warning) +#define math_hooks (G_misc.math_hooks ) #define INIT_G_misc() do { \ (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ barrier(); \ @@ -1998,7 +1991,7 @@ findvar(struct var **vpp, const char *name) /* * Find the value of a variable. Returns NULL if not set. */ -static char * +static const char * lookupvar(const char *name) { struct var *v; @@ -2024,7 +2017,7 @@ lookupvar(const char *name) /* * Search the environment of a builtin command. */ -static char * +static const char * bltinlookup(const char *name) { struct strlist *sp; @@ -2637,7 +2630,7 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) #define USE_SIT_FUNCTION #endif -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT static const char S_I_T[][4] = { #if ENABLE_ASH_ALIAS { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */ @@ -2681,7 +2674,7 @@ static const char S_I_T[][3] = { { CCTL, CCTL, CCTL } /* 14, CTLESC ... */ #endif }; -#endif /* ASH_MATH_SUPPORT */ +#endif /* SH_MATH_SUPPORT */ #ifdef USE_SIT_FUNCTION @@ -4273,7 +4266,7 @@ cmdputs(const char *s) case CTLBACKQ+CTLQUOTE: str = "\"$(...)\""; goto dostr; -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT case CTLARI: str = "$(("; goto dostr; @@ -5258,17 +5251,8 @@ redirectsafe(union node *redir, int flags) * We have to deal with backquotes, shell variables, and file metacharacters. */ -#if ENABLE_ASH_MATH_SUPPORT_64 -typedef int64_t arith_t; -#define arith_t_type long long -#else -typedef long arith_t; -#define arith_t_type long -#endif - -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT static arith_t dash_arith(const char *); -static arith_t arith(const char *expr, int *perrcode); #endif /* @@ -5328,11 +5312,7 @@ cvtnum(arith_t num) int len; expdest = makestrspace(32, expdest); -#if ENABLE_ASH_MATH_SUPPORT_64 - len = fmtstr(expdest, 32, "%lld", (long long) num); -#else - len = fmtstr(expdest, 32, "%ld", num); -#endif + len = fmtstr(expdest, 32, arith_t_fmt, num); STADJUST(len, expdest); return len; } @@ -5696,7 +5676,7 @@ expbackq(union node *cmd, int quoted, int quotes) stackblock() + startloc)); } -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT /* * Expand arithmetic expression. Backup to start of expression, * evaluate, place result in (backed up) result, adjust string position. @@ -5782,7 +5762,7 @@ argstr(char *p, int flag, struct strlist *var_str_list) CTLVAR, CTLBACKQ, CTLBACKQ | CTLQUOTE, -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT CTLENDARI, #endif 0 @@ -5819,7 +5799,7 @@ argstr(char *p, int flag, struct strlist *var_str_list) length += strcspn(p + length, reject); c = p[length]; if (c && (!(c & 0x80) -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT || c == CTLENDARI #endif )) { @@ -5897,7 +5877,7 @@ argstr(char *p, int flag, struct strlist *var_str_list) expbackq(argbackq->n, c, quotes); argbackq = argbackq->next; goto start; -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT case CTLENDARI: p--; expari(quotes); @@ -6291,7 +6271,7 @@ static ssize_t varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) { int num; - char *p; + const char *p; int i; int sep = 0; int sepq = 0; @@ -6324,14 +6304,13 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) len = cvtnum(num); break; case '-': - p = makestrspace(NOPTS, expdest); + expdest = makestrspace(NOPTS, expdest); for (i = NOPTS - 1; i >= 0; i--) { if (optlist[i]) { - USTPUTC(optletters(i), p); + USTPUTC(optletters(i), expdest); len++; } } - expdest = p; break; case '@': if (sep) @@ -8710,7 +8689,7 @@ static int getoptscmd(int, char **); #if !ENABLE_FEATURE_SH_EXTRA_QUIET static int helpcmd(int, char **); #endif -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT static int letcmd(int, char **); #endif static int readcmd(int, char **); @@ -8792,7 +8771,7 @@ static const struct builtincmd builtintab[] = { { BUILTIN_REGULAR "jobs", jobscmd }, { BUILTIN_REGULAR "kill", killcmd }, #endif -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT { BUILTIN_NOSPEC "let", letcmd }, #endif { BUILTIN_ASSIGN "local", localcmd }, @@ -10935,7 +10914,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) USTPUTC(c, out); } break; -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT case CLP: /* '(' in arithmetic */ parenlevel++; USTPUTC(c, out); @@ -10991,7 +10970,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) } /* for (;;) */ } endword: -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT if (syntax == ARISYNTAX) raise_error_syntax("missing '))'"); #endif @@ -11168,7 +11147,7 @@ parsesub: { pungetc(); } else if (c == '(') { /* $(command) or $((arith)) */ if (pgetc() == '(') { -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT PARSEARITH(); #else raise_error_syntax("you disabled math support for $((arith)) syntax"); @@ -11423,7 +11402,7 @@ parsebackq: { goto parsebackq_newreturn; } -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT /* * Parse an arithmetic expansion (indicate start of one and set state) */ @@ -12384,7 +12363,7 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) return 0; } -#if ENABLE_ASH_MATH_SUPPORT +#if ENABLE_SH_MATH_SUPPORT static arith_t dash_arith(const char *s) { @@ -12392,7 +12371,7 @@ dash_arith(const char *s) int errcode = 0; INT_OFF; - result = arith(s, &errcode); + result = arith(s, &errcode, &math_hooks); if (errcode < 0) { if (errcode == -3) ash_msg_and_raise_error("exponent less than 0"); @@ -12427,7 +12406,7 @@ letcmd(int argc UNUSED_PARAM, char **argv) return !i; } -#endif /* ASH_MATH_SUPPORT */ +#endif /* SH_MATH_SUPPORT */ /* ============ miscbltin.c @@ -12951,654 +12930,6 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) return 0; } - -/* ============ Math support */ - -#if ENABLE_ASH_MATH_SUPPORT - -/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* This is my infix parser/evaluator. It is optimized for size, intended - * as a replacement for yacc-based parsers. However, it may well be faster - * than a comparable parser written in yacc. The supported operators are - * listed in #defines below. Parens, order of operations, and error handling - * are supported. This code is thread safe. The exact expression format should - * be that which POSIX specifies for shells. */ - -/* The code uses a simple two-stack algorithm. See - * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html - * for a detailed explanation of the infix-to-postfix algorithm on which - * this is based (this code differs in that it applies operators immediately - * to the stack instead of adding them to a queue to end up with an - * expression). */ - -/* To use the routine, call it with an expression string and error return - * pointer */ - -/* - * Aug 24, 2001 Manuel Novoa III - * - * Reduced the generated code size by about 30% (i386) and fixed several bugs. - * - * 1) In arith_apply(): - * a) Cached values of *numptr and &(numptr[-1]). - * b) Removed redundant test for zero denominator. - * - * 2) In arith(): - * a) Eliminated redundant code for processing operator tokens by moving - * to a table-based implementation. Also folded handling of parens - * into the table. - * b) Combined all 3 loops which called arith_apply to reduce generated - * code size at the cost of speed. - * - * 3) The following expressions were treated as valid by the original code: - * 1() , 0! , 1 ( *3 ) . - * These bugs have been fixed by internally enclosing the expression in - * parens and then checking that all binary ops and right parens are - * preceded by a valid expression (NUM_TOKEN). - * - * Note: It may be desirable to replace Aaron's test for whitespace with - * ctype's isspace() if it is used by another busybox applet or if additional - * whitespace chars should be considered. Look below the "#include"s for a - * precompiler test. - */ - -/* - * Aug 26, 2001 Manuel Novoa III - * - * Return 0 for null expressions. Pointed out by Vladimir Oleynik. - * - * Merge in Aaron's comments previously posted to the busybox list, - * modified slightly to take account of my changes to the code. - * - */ - -/* - * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> - * - * - allow access to variable, - * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6) - * - realize assign syntax (VAR=expr, +=, *= etc) - * - realize exponentiation (** operator) - * - realize comma separated - expr, expr - * - realise ++expr --expr expr++ expr-- - * - realise expr ? expr : expr (but, second expr calculate always) - * - allow hexadecimal and octal numbers - * - was restored loses XOR operator - * - remove one goto label, added three ;-) - * - protect $((num num)) as true zero expr (Manuel`s error) - * - always use special isspace(), see comment from bash ;-) - */ - -#define arith_isspace(arithval) \ - (arithval == ' ' || arithval == '\n' || arithval == '\t') - -typedef unsigned char operator; - -/* An operator's token id is a bit of a bitfield. The lower 5 bits are the - * precedence, and 3 high bits are an ID unique across operators of that - * precedence. The ID portion is so that multiple operators can have the - * same precedence, ensuring that the leftmost one is evaluated first. - * Consider * and /. */ - -#define tok_decl(prec,id) (((id)<<5)|(prec)) -#define PREC(op) ((op) & 0x1F) - -#define TOK_LPAREN tok_decl(0,0) - -#define TOK_COMMA tok_decl(1,0) - -#define TOK_ASSIGN tok_decl(2,0) -#define TOK_AND_ASSIGN tok_decl(2,1) -#define TOK_OR_ASSIGN tok_decl(2,2) -#define TOK_XOR_ASSIGN tok_decl(2,3) -#define TOK_PLUS_ASSIGN tok_decl(2,4) -#define TOK_MINUS_ASSIGN tok_decl(2,5) -#define TOK_LSHIFT_ASSIGN tok_decl(2,6) -#define TOK_RSHIFT_ASSIGN tok_decl(2,7) - -#define TOK_MUL_ASSIGN tok_decl(3,0) -#define TOK_DIV_ASSIGN tok_decl(3,1) -#define TOK_REM_ASSIGN tok_decl(3,2) - -/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ -#define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0) - -/* conditional is right associativity too */ -#define TOK_CONDITIONAL tok_decl(4,0) -#define TOK_CONDITIONAL_SEP tok_decl(4,1) - -#define TOK_OR tok_decl(5,0) - -#define TOK_AND tok_decl(6,0) - -#define TOK_BOR tok_decl(7,0) - -#define TOK_BXOR tok_decl(8,0) - -#define TOK_BAND tok_decl(9,0) - -#define TOK_EQ tok_decl(10,0) -#define TOK_NE tok_decl(10,1) - -#define TOK_LT tok_decl(11,0) -#define TOK_GT tok_decl(11,1) -#define TOK_GE tok_decl(11,2) -#define TOK_LE tok_decl(11,3) - -#define TOK_LSHIFT tok_decl(12,0) -#define TOK_RSHIFT tok_decl(12,1) - -#define TOK_ADD tok_decl(13,0) -#define TOK_SUB tok_decl(13,1) - -#define TOK_MUL tok_decl(14,0) -#define TOK_DIV tok_decl(14,1) -#define TOK_REM tok_decl(14,2) - -/* exponent is right associativity */ -#define TOK_EXPONENT tok_decl(15,1) - -/* For now unary operators. */ -#define UNARYPREC 16 -#define TOK_BNOT tok_decl(UNARYPREC,0) -#define TOK_NOT tok_decl(UNARYPREC,1) - -#define TOK_UMINUS tok_decl(UNARYPREC+1,0) -#define TOK_UPLUS tok_decl(UNARYPREC+1,1) - -#define PREC_PRE (UNARYPREC+2) - -#define TOK_PRE_INC tok_decl(PREC_PRE, 0) -#define TOK_PRE_DEC tok_decl(PREC_PRE, 1) - -#define PREC_POST (UNARYPREC+3) - -#define TOK_POST_INC tok_decl(PREC_POST, 0) -#define TOK_POST_DEC tok_decl(PREC_POST, 1) - -#define SPEC_PREC (UNARYPREC+4) - -#define TOK_NUM tok_decl(SPEC_PREC, 0) -#define TOK_RPAREN tok_decl(SPEC_PREC, 1) - -#define NUMPTR (*numstackptr) - -static int -tok_have_assign(operator op) -{ - operator prec = PREC(op); - - convert_prec_is_assing(prec); - return (prec == PREC(TOK_ASSIGN) || - prec == PREC_PRE || prec == PREC_POST); -} - -static int -is_right_associativity(operator prec) -{ - return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) - || prec == PREC(TOK_CONDITIONAL)); -} - -typedef struct { - arith_t val; - arith_t contidional_second_val; - char contidional_second_val_initialized; - char *var; /* if NULL then is regular number, - else is variable name */ -} v_n_t; - -typedef struct chk_var_recursive_looped_t { - const char *var; - struct chk_var_recursive_looped_t *next; -} chk_var_recursive_looped_t; - -static chk_var_recursive_looped_t *prev_chk_var_recursive; - -static int -arith_lookup_val(v_n_t *t) -{ - if (t->var) { - const char * p = lookupvar(t->var); - - if (p) { - int errcode; - - /* recursive try as expression */ - chk_var_recursive_looped_t *cur; - chk_var_recursive_looped_t cur_save; - - for (cur = prev_chk_var_recursive; cur; cur = cur->next) { - if (strcmp(cur->var, t->var) == 0) { - /* expression recursion loop detected */ - return -5; - } - } - /* save current lookuped var name */ - cur = prev_chk_var_recursive; - cur_save.var = t->var; - cur_save.next = cur; - prev_chk_var_recursive = &cur_save; - - t->val = arith (p, &errcode); - /* restore previous ptr after recursiving */ - prev_chk_var_recursive = cur; - return errcode; - } - /* allow undefined var as 0 */ - t->val = 0; - } - return 0; -} - -/* "applying" a token means performing it on the top elements on the integer - * stack. For a unary operator it will only change the top element, but a - * binary operator will pop two arguments and push a result */ -static int -arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) -{ - v_n_t *numptr_m1; - arith_t numptr_val, rez; - int ret_arith_lookup_val; - - /* There is no operator that can work without arguments */ - if (NUMPTR == numstack) goto err; - numptr_m1 = NUMPTR - 1; - - /* check operand is var with noninteger value */ - ret_arith_lookup_val = arith_lookup_val(numptr_m1); - if (ret_arith_lookup_val) - return ret_arith_lookup_val; - - rez = numptr_m1->val; - if (op == TOK_UMINUS) - rez *= -1; - else if (op == TOK_NOT) - rez = !rez; - else if (op == TOK_BNOT) - rez = ~rez; - else if (op == TOK_POST_INC || op == TOK_PRE_INC) - rez++; - else if (op == TOK_POST_DEC || op == TOK_PRE_DEC) - rez--; - else if (op != TOK_UPLUS) { - /* Binary operators */ - - /* check and binary operators need two arguments */ - if (numptr_m1 == numstack) goto err; - - /* ... and they pop one */ - --NUMPTR; - numptr_val = rez; - if (op == TOK_CONDITIONAL) { - if (!numptr_m1->contidional_second_val_initialized) { - /* protect $((expr1 ? expr2)) without ": expr" */ - goto err; - } - rez = numptr_m1->contidional_second_val; - } else if (numptr_m1->contidional_second_val_initialized) { - /* protect $((expr1 : expr2)) without "expr ? " */ - goto err; - } - numptr_m1 = NUMPTR - 1; - if (op != TOK_ASSIGN) { - /* check operand is var with noninteger value for not '=' */ - ret_arith_lookup_val = arith_lookup_val(numptr_m1); - if (ret_arith_lookup_val) - return ret_arith_lookup_val; - } - if (op == TOK_CONDITIONAL) { - numptr_m1->contidional_second_val = rez; - } - rez = numptr_m1->val; - if (op == TOK_BOR || op == TOK_OR_ASSIGN) - rez |= numptr_val; - else if (op == TOK_OR) - rez = numptr_val || rez; - else if (op == TOK_BAND || op == TOK_AND_ASSIGN) - rez &= numptr_val; - else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) - rez ^= numptr_val; - else if (op == TOK_AND) - rez = rez && numptr_val; - else if (op == TOK_EQ) - rez = (rez == numptr_val); - else if (op == TOK_NE) - rez = (rez != numptr_val); - else if (op == TOK_GE) - rez = (rez >= numptr_val); - else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) - rez >>= numptr_val; - else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) - rez <<= numptr_val; - else if (op == TOK_GT) - rez = (rez > numptr_val); - else if (op == TOK_LT) - rez = (rez < numptr_val); - else if (op == TOK_LE) - rez = (rez <= numptr_val); - else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) - rez *= numptr_val; - else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) - rez += numptr_val; - else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) - rez -= numptr_val; - else if (op == TOK_ASSIGN || op == TOK_COMMA) - rez = numptr_val; - else if (op == TOK_CONDITIONAL_SEP) { - if (numptr_m1 == numstack) { - /* protect $((expr : expr)) without "expr ? " */ - goto err; - } - numptr_m1->contidional_second_val_initialized = op; - numptr_m1->contidional_second_val = numptr_val; - } else if (op == TOK_CONDITIONAL) { - rez = rez ? - numptr_val : numptr_m1->contidional_second_val; - } else if (op == TOK_EXPONENT) { - if (numptr_val < 0) - return -3; /* exponent less than 0 */ - else { - arith_t c = 1; - - if (numptr_val) - while (numptr_val--) - c *= rez; - rez = c; - } - } else if (numptr_val==0) /* zero divisor check */ - return -2; - else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) - rez /= numptr_val; - else if (op == TOK_REM || op == TOK_REM_ASSIGN) - rez %= numptr_val; - } - if (tok_have_assign(op)) { - char buf[sizeof(arith_t_type)*3 + 2]; - - if (numptr_m1->var == NULL) { - /* Hmm, 1=2 ? */ - goto err; - } - /* save to shell variable */ -#if ENABLE_ASH_MATH_SUPPORT_64 - snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez); -#else - snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez); -#endif - setvar(numptr_m1->var, buf, 0); - /* after saving, make previous value for v++ or v-- */ - if (op == TOK_POST_INC) - rez--; - else if (op == TOK_POST_DEC) - rez++; - } - numptr_m1->val = rez; - /* protect geting var value, is number now */ - numptr_m1->var = NULL; - return 0; - err: - return -1; -} - -/* longest must be first */ -static const char op_tokens[] ALIGN1 = { - '<','<','=',0, TOK_LSHIFT_ASSIGN, - '>','>','=',0, TOK_RSHIFT_ASSIGN, - '<','<', 0, TOK_LSHIFT, - '>','>', 0, TOK_RSHIFT, - '|','|', 0, TOK_OR, - '&','&', 0, TOK_AND, - '!','=', 0, TOK_NE, - '<','=', 0, TOK_LE, - '>','=', 0, TOK_GE, - '=','=', 0, TOK_EQ, - '|','=', 0, TOK_OR_ASSIGN, - '&','=', 0, TOK_AND_ASSIGN, - '*','=', 0, TOK_MUL_ASSIGN, - '/','=', 0, TOK_DIV_ASSIGN, - '%','=', 0, TOK_REM_ASSIGN, - '+','=', 0, TOK_PLUS_ASSIGN, - '-','=', 0, TOK_MINUS_ASSIGN, - '-','-', 0, TOK_POST_DEC, - '^','=', 0, TOK_XOR_ASSIGN, - '+','+', 0, TOK_POST_INC, - '*','*', 0, TOK_EXPONENT, - '!', 0, TOK_NOT, - '<', 0, TOK_LT, - '>', 0, TOK_GT, - '=', 0, TOK_ASSIGN, - '|', 0, TOK_BOR, - '&', 0, TOK_BAND, - '*', 0, TOK_MUL, - '/', 0, TOK_DIV, - '%', 0, TOK_REM, - '+', 0, TOK_ADD, - '-', 0, TOK_SUB, - '^', 0, TOK_BXOR, - /* uniq */ - '~', 0, TOK_BNOT, - ',', 0, TOK_COMMA, - '?', 0, TOK_CONDITIONAL, - ':', 0, TOK_CONDITIONAL_SEP, - ')', 0, TOK_RPAREN, - '(', 0, TOK_LPAREN, - 0 -}; -/* ptr to ")" */ -#define endexpression (&op_tokens[sizeof(op_tokens)-7]) - -static arith_t -arith(const char *expr, int *perrcode) -{ - char arithval; /* Current character under analysis */ - operator lasttok, op; - operator prec; - operator *stack, *stackptr; - const char *p = endexpression; - int errcode; - v_n_t *numstack, *numstackptr; - unsigned datasizes = strlen(expr) + 2; - - /* Stack of integers */ - /* The proof that there can be no more than strlen(startbuf)/2+1 integers - * in any given correct or incorrect expression is left as an exercise to - * the reader. */ - numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0])); - /* Stack of operator tokens */ - stackptr = stack = alloca(datasizes * sizeof(stack[0])); - - *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ - *perrcode = errcode = 0; - - while (1) { - arithval = *expr; - if (arithval == 0) { - if (p == endexpression) { - /* Null expression. */ - return 0; - } - - /* This is only reached after all tokens have been extracted from the - * input stream. If there are still tokens on the operator stack, they - * are to be applied in order. At the end, there should be a final - * result on the integer stack */ - - if (expr != endexpression + 1) { - /* If we haven't done so already, */ - /* append a closing right paren */ - expr = endexpression; - /* and let the loop process it. */ - continue; - } - /* At this point, we're done with the expression. */ - if (numstackptr != numstack+1) { - /* ... but if there isn't, it's bad */ - err: - *perrcode = -1; - return *perrcode; - } - if (numstack->var) { - /* expression is $((var)) only, lookup now */ - errcode = arith_lookup_val(numstack); - } - ret: - *perrcode = errcode; - return numstack->val; - } - - /* Continue processing the expression. */ - if (arith_isspace(arithval)) { - /* Skip whitespace */ - goto prologue; - } - p = endofname(expr); - if (p != expr) { - size_t var_name_size = (p-expr) + 1; /* trailing zero */ - - numstackptr->var = alloca(var_name_size); - safe_strncpy(numstackptr->var, expr, var_name_size); - expr = p; - num: - numstackptr->contidional_second_val_initialized = 0; - numstackptr++; - lasttok = TOK_NUM; - continue; - } - if (isdigit(arithval)) { - numstackptr->var = NULL; -#if ENABLE_ASH_MATH_SUPPORT_64 - numstackptr->val = strtoll(expr, (char **) &expr, 0); -#else - numstackptr->val = strtol(expr, (char **) &expr, 0); -#endif - goto num; - } - for (p = op_tokens; ; p++) { - const char *o; - - if (*p == 0) { - /* strange operator not found */ - goto err; - } - for (o = expr; *p && *o == *p; p++) - o++; - if (!*p) { - /* found */ - expr = o - 1; - break; - } - /* skip tail uncompared token */ - while (*p) - p++; - /* skip zero delim */ - p++; - } - op = p[1]; - - /* post grammar: a++ reduce to num */ - if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) - lasttok = TOK_NUM; - - /* Plus and minus are binary (not unary) _only_ if the last - * token was as number, or a right paren (which pretends to be - * a number, since it evaluates to one). Think about it. - * It makes sense. */ - if (lasttok != TOK_NUM) { - switch (op) { - case TOK_ADD: - op = TOK_UPLUS; - break; - case TOK_SUB: - op = TOK_UMINUS; - break; - case TOK_POST_INC: - op = TOK_PRE_INC; - break; - case TOK_POST_DEC: - op = TOK_PRE_DEC; - break; - } - } - /* We don't want a unary operator to cause recursive descent on the - * stack, because there can be many in a row and it could cause an - * operator to be evaluated before its argument is pushed onto the - * integer stack. */ - /* But for binary operators, "apply" everything on the operator - * stack until we find an operator with a lesser priority than the - * one we have just extracted. */ - /* Left paren is given the lowest priority so it will never be - * "applied" in this way. - * if associativity is right and priority eq, applied also skip - */ - prec = PREC(op); - if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { - /* not left paren or unary */ - if (lasttok != TOK_NUM) { - /* binary op must be preceded by a num */ - goto err; - } - while (stackptr != stack) { - if (op == TOK_RPAREN) { - /* The algorithm employed here is simple: while we don't - * hit an open paren nor the bottom of the stack, pop - * tokens and apply them */ - if (stackptr[-1] == TOK_LPAREN) { - --stackptr; - /* Any operator directly after a */ - lasttok = TOK_NUM; - /* close paren should consider itself binary */ - goto prologue; - } - } else { - operator prev_prec = PREC(stackptr[-1]); - - convert_prec_is_assing(prec); - convert_prec_is_assing(prev_prec); - if (prev_prec < prec) - break; - /* check right assoc */ - if (prev_prec == prec && is_right_associativity(prec)) - break; - } - errcode = arith_apply(*--stackptr, numstack, &numstackptr); - if (errcode) goto ret; - } - if (op == TOK_RPAREN) { - goto err; - } - } - - /* Push this operator to the stack and remember it. */ - *stackptr++ = lasttok = op; - prologue: - ++expr; - } /* while */ -} -#endif /* ASH_MATH_SUPPORT */ - - /* ============ main() and helpers */ /* @@ -13786,7 +13117,7 @@ extern int etext(); int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int ash_main(int argc UNUSED_PARAM, char **argv) { - char *shinit; + const char *shinit; volatile smallint state; struct jmploc jmploc; struct stackmark smark; @@ -13799,6 +13130,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) INIT_G_alias(); #endif INIT_G_cmdtable(); +#if ENABLE_SH_MATH_SUPPORT + math_hooks.lookupvar = lookupvar; + math_hooks.setvar = setvar; + math_hooks.endofname = endofname; +#endif #if PROFILE monitor(4, etext, profile_buf, sizeof(profile_buf), 50); |