Hello. My patch for allow recursive variable inderection in arith and simplify allow $(( )). Originaly from my arith in busybox Before patch: $ a=b b=2; echo $((a)) dash: 1: Illegal number: b After patch: $ a=b b=2; echo $((a)) 2 a=b b="a*2"; echo $((a)) ./dash: 4: arithmetic expression: expression recursion loop detected: "a" --w vodz
--- arith_yacc.c.orig 2020-12-23 11:58:12.000000000 +0400 +++ arith_yacc.c 2021-01-31 13:19:00.790119536 +0400 @@ -34,6 +34,7 @@ #include <inttypes.h> #include <stdlib.h> +#include <string.h> #include "arith_yacc.h" #include "expand.h" #include "shell.h" @@ -134,6 +135,50 @@ static intmax_t assignment(int var, int noeval); +typedef struct CHK_VAR_RECURSIVE_LOOPED { + const char *name; + struct CHK_VAR_RECURSIVE_LOOPED *next; +} chk_var_recursive_looped_t; + +static chk_var_recursive_looped_t *prev_chk_var_recursive; + +static intmax_t arith_lookup_val(const char *name) +{ + const char * p = lookupvar(name); + + if(p) { + intmax_t ret; + + /* recursive try as expression */ + chk_var_recursive_looped_t *cur; + chk_var_recursive_looped_t cur_save; + const char *arith_buf_s; + int lt; + + for(cur = prev_chk_var_recursive; cur; cur = cur->next) { + if(!strcmp(cur->name, name)) + yyerror("expression recursion loop detected"); + } + /* save current lookuped var name */ + cur = prev_chk_var_recursive; + cur_save.name = name; + cur_save.next = cur; + prev_chk_var_recursive = &cur_save; + + arith_buf_s = arith_buf; + lt = last_token; + ret = arith (p, 1); + /* restore previous after recursiving */ + prev_chk_var_recursive = cur; + arith_buf = arith_buf_s; + last_token = lt; + return ret; + } else { + /* allow undefined var as 0 */ + return 0; + } +} + static intmax_t primary(int token, union yystype *val, int op, int noeval) { intmax_t result; @@ -151,7 +196,7 @@ return val->val; case ARITH_VAR: last_token = op; - return noeval ? val->val : lookupvarint(val->name); + return noeval ? val->val : arith_lookup_val(val->name); case ARITH_ADD: token = op; *val = yylval; @@ -286,16 +331,27 @@ return setvarint(val.name, op == ARITH_ASS ? result : - do_binop(op - 11, lookupvarint(val.name), result), 0); + do_binop(op - 11, arith_lookup_val(val.name), result), 0); } -intmax_t arith(const char *s) +intmax_t arith(const char *s, int r) { intmax_t result; + int l0; - arith_buf = arith_startbuf = s; + arith_buf = s; + last_token = 0; - result = assignment(yylex(), 0); + if(!r) { + prev_chk_var_recursive = (chk_var_recursive_looped_t *)0; + arith_startbuf = s; + } + l0 = yylex(); + if (l0 == 0) { + /* $(( )) */ + return 0; + } + result = assignment(l0, 0); if (last_token) yyerror("expecting EOF"); --- expand.c.orig 2020-12-23 11:58:12.000000000 +0400 +++ expand.c 2021-01-31 12:39:07.083194412 +0400 @@ -460,7 +460,7 @@ rmescapes(start); pushstackmark(&sm, endoff); - result = arith(start); + result = arith(start, 0); popstackmark(&sm); len = cvtnum(result, flag); --- expand.h.orig 2020-12-23 11:58:12.000000000 +0400 +++ expand.h 2021-01-31 12:39:09.435194338 +0400 @@ -73,7 +73,7 @@ void ifsfree(void); /* From arith.y */ -intmax_t arith(const char *); +intmax_t arith(const char *, int r); int expcmd(int , char **); #ifdef USE_LEX void arith_lex_reset(void); --- var.c.orig 2020-12-23 11:58:12.000000000 +0400 +++ var.c 2021-01-31 12:30:38.894210308 +0400 @@ -322,12 +322,6 @@ return NULL; } -intmax_t lookupvarint(const char *name) -{ - return atomax(lookupvar(name) ?: nullstr, 0); -} - - /* --- var.h.orig 2020-12-23 11:58:12.000000000 +0400 +++ var.h 2021-01-31 12:30:45.150210113 +0400 @@ -140,7 +140,6 @@ struct var *setvareq(char *s, int flags); struct strlist; char *lookupvar(const char *); -intmax_t lookupvarint(const char *); char **listvars(int, int, char ***); #define environment() listvars(VEXPORT, VUNSET, 0) int showvars(const char *, int, int);