From: Chet Ramey Date: Mon, 25 Mar 2024 14:32:07 +0000 (-0400) Subject: change to test builtin for parenthesized expressions when there are more than four... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8af5a8e0ca7d75f91eac7d81783af7d06d32dd50;p=thirdparty%2Fbash.git change to test builtin for parenthesized expressions when there are more than four arguments to test; tentative change to @A transformation to output declare commands for local variables --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index c5e0c78a..725b576b 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -8830,14 +8830,14 @@ builtins/printf.def overflow, since we don't call printf - printstr,printwidestr: set field width and precision on integer overflow the way we do in printf_builtin - From a report by Paul Eggert + From a report and patch by Paul Eggert bashtypes.h - PRIdMAX: move redefinition here after including inttypes.h builtins/printf.def,examples/loadables/seq.c,examples/loadables/getconf.h - remove PRIdMAX redefinitions, since it's now fixed in bashtypes.h - From a report by Paul Eggert + From a report and patch by Paul Eggert 3/15 ---- @@ -8895,4 +8895,31 @@ braces.c sprintf family has trouble when width > INT_MAX - expand_seqterm: use size_t instead of int for length and width variables - From a report by Paul Eggert + From a report and patch by Paul Eggert + + 3/18 + ---- +builtins/printf.def + - printstr,bexpand: changed size/length arguments to be size_t; changed + callers + +subst.c + - string_var_assignment: if the variable is a local variable at the + current scope, output a declare command even if there are no + attributes or value. Still tagged as tentative + + 3/23 + ---- +test.c + - posixtest: takes an argument, the number of test arguments to parse + - two_arguments,three_arguments: use advance() instead of accessing + and manipulating pos directly + - posixtest,three_arguments,two_arguments: don't set pos = argc + directly, rely on functions to advance pos appropriately + Picked up from coreutils test + - term: if we see a left paren, scan forward for a closing right paren + and use posixtest() if there are 1-4 arguments between the parens to + avoid ambiguous behavior for expressions like true -a \( ! -a \), + which a user would expect to return false instead of an error + message + Picked up from coreutils test diff --git a/builtins/printf.def b/builtins/printf.def index 2327bd5d..c033407b 100644 --- a/builtins/printf.def +++ b/builtins/printf.def @@ -193,9 +193,9 @@ extern int vsnprintf (char *, size_t, const char *, va_list) __attribute__((__fo static inline void printf_erange (char *); static inline void report_erange (char *, char *); -static int printstr (char *, char *, int, int, int); +static int printstr (char *, char *, size_t, int, int); static int tescape (char *, char *, int *, int *); -static char *bexpand (char *, int, int *, int *); +static char *bexpand (char *, size_t, int *, size_t *); static char *vbadd (char *, int); static int vbprintf (const char *, ...) __attribute__((__format__ (printf, 1, 2))); static char *mklong (char *, char *, size_t); @@ -552,10 +552,12 @@ printf_builtin (WORD_LIST *list) case 'b': /* expand escapes in argument */ { char *p, *xp; - int rlen, r; + size_t rlen; + int r; p = getstr (); - ch = rlen = r = 0; + ch = r = 0; + rlen = 0; xp = bexpand (p, strlen (p), &ch, &rlen); if (xp) @@ -846,7 +848,7 @@ report_erange (char *s, char *e) Returns -1 on detectable write error, 0 otherwise. */ static int -printstr (char *fmt, char *string, int len, int fieldwidth, int precision) +printstr (char *fmt, char *string, size_t len, int fieldwidth, int precision) { #if 0 char *s; @@ -1161,7 +1163,7 @@ tescape (char *estart, char *cp, int *lenp, int *sawc) } static char * -bexpand (char *string, int len, int *sawc, int *lenp) +bexpand (char *string, size_t len, int *sawc, size_t *lenp) { int temp, c; char *ret, *r, *s, *send; diff --git a/subst.c b/subst.c index 2c51021b..f4254b13 100644 --- a/subst.c +++ b/subst.c @@ -8639,15 +8639,26 @@ string_var_assignment (SHELL_VAR *v, char *s) val = (v && (invisible_p (v) || var_isset (v) == 0)) ? (char *)NULL : sh_quote_reusable (s, 0); i = var_attribute_string (v, 0, flags); +#if 0 /*TAG: notyet */ + if (v && local_p (v) == 0 && variable_context > 0) + flags[i++] = 'g'; +#endif /* i = strlen (flags) */ - if (i == 0 && val == 0) + if (i == 0 && val == 0 && (local_p (v) == 0 || v->context != variable_context)) return (char *)NULL; ret = (char *)xmalloc (i + STRLEN (val) + strlen (v->name) + 16 + MAX_ATTRIBUTES); + if (i > 0 && val == 0) - sprintf (ret, "declare -%s %s", flags, v->name); + sprintf (ret, "declare -%s %s", flags, v->name); /* just attributes, unset */ else if (i > 0) - sprintf (ret, "declare -%s %s=%s", flags, v->name, val); + sprintf (ret, "declare -%s %s=%s", flags, v->name, val); /* attributes, set */ +#if 1 /*TAG: tentative */ + else if (i == 0 && val && local_p (v) && variable_context == v->context) + sprintf (ret, "declare %s=%s", v->name, val); /* set local variable at current scope */ + else if (i == 0 && val == 0 && local_p (v) && variable_context == v->context) + sprintf (ret, "declare %s", v->name); /* unset local variable at current scope, unset */ +#endif else sprintf (ret, "%s=%s", v->name, val); free (val); diff --git a/test.c b/test.c index 6967ef95..09dc1478 100644 --- a/test.c +++ b/test.c @@ -74,6 +74,9 @@ extern int errno; #define ISPRIMARY(s, c) (s[0] == '-' && s[1] == c && s[2] == '\0') #define ANDOR(s) (s[0] == '-' && (s[1] == 'a' || s[1] == 'o') && s[2] == 0) +/* single-character tokens like `!', `(', and `)' */ +#define ISTOKEN(s, c) (s[0] == (c) && s[1] == '\0') + #if !defined (R_OK) #define R_OK 4 #define W_OK 2 @@ -125,7 +128,7 @@ static int unary_operator (void); static int binary_operator (void); static int two_arguments (void); static int three_arguments (void); -static int posixtest (void); +static int posixtest (int); static int expr (void); static int term (void); @@ -264,8 +267,16 @@ term (void) /* A paren-bracketed argument. */ if (argv[pos][0] == '(' && argv[pos][1] == '\0') /* ) */ { + int nargs; + advance (1); - value = expr (); + /* Steal an idea from coreutils and scan forward to check where the right + paren appears to prevent some ambiguity. If we find a valid sub- + expression that has 1-4 arguments, call posixtest on it ( */ + for (nargs = 1; pos + nargs < argc && ISTOKEN (argv[pos+nargs], ')') == 0; nargs++) + ; + /* only do this if we have a valid parenthesized expression */ + value = (pos + nargs < argc && nargs <= 4) ? posixtest (nargs) : expr (); if (argv[pos] == 0) /* ( */ test_syntax_error (_("`)' expected"), (char *)NULL); else if (argv[pos][0] != ')' || argv[pos][1]) /* ( */ @@ -758,7 +769,10 @@ static int two_arguments (void) { if (argv[pos][0] == '!' && argv[pos][1] == '\0') - return (argv[pos + 1][0] == '\0'); + { + advance (0); + return (argv[pos++][0] == '\0'); + } else if (argv[pos][0] == '-' && argv[pos][1] && argv[pos][2] == '\0') { if (test_unop (argv[pos])) @@ -782,28 +796,25 @@ three_arguments (void) int value; if (test_binop (argv[pos+1])) - { - value = binary_operator (); - pos = argc; - } + value = binary_operator (); else if (ANDOR (argv[pos+1])) { if (argv[pos+1][1] == 'a') value = ONE_ARG_TEST(argv[pos]) && ONE_ARG_TEST(argv[pos+2]); else value = ONE_ARG_TEST(argv[pos]) || ONE_ARG_TEST(argv[pos+2]); - pos = argc; + pos += 3; } else if (argv[pos][0] == '!' && argv[pos][1] == '\0') { advance (1); value = !two_arguments (); - pos = argc; } - else if (argv[pos][0] == '(' && argv[pos+2][0] == ')') + else if (ISTOKEN (argv[pos], '(') && ISTOKEN (argv[pos+2], ')')) { - value = ONE_ARG_TEST(argv[pos+1]); - pos = argc; + advance (0); + value = ONE_ARG_TEST(argv[pos]); + pos += 2; } else test_syntax_error (_("%s: binary operator expected"), argv[pos+1]); @@ -813,25 +824,23 @@ three_arguments (void) /* This is an implementation of a Posix.2 proposal by David Korn. */ static int -posixtest (void) +posixtest (int nargs) { int value; - switch (argc - 1) /* one extra passed in */ + switch (nargs) { case 0: value = FALSE; - pos = argc; break; case 1: value = ONE_ARG_TEST(argv[1]); - pos = argc; + advance (0); break; case 2: value = two_arguments (); - pos = argc; break; case 3: @@ -845,11 +854,11 @@ posixtest (void) value = !three_arguments (); break; } - else if (argv[pos][0] == '(' && argv[pos][1] == '\0' && argv[argc-1][0] == ')' && argv[argc-1][1] == '\0') + else if (ISTOKEN (argv[pos], '(') && ISTOKEN (argv[pos+3], ')')) { advance (1); value = two_arguments (); - pos = argc; + advance (0); break; } /* FALLTHROUGH */ @@ -916,7 +925,7 @@ test_command (int margc, char **margv) test_exit (SHELL_BOOLEAN (FALSE)); noeval = 0; - value = posixtest (); + value = posixtest (argc - 1); if (pos != argc) { diff --git a/tests/test.right b/tests/test.right index cb3f94dd..522dd6e2 100644 --- a/tests/test.right +++ b/tests/test.right @@ -323,6 +323,15 @@ t -t /dev/tty4444444... 2 ./test.tests: line 26: test: : integer expected 2 +1 +0 +0 +./test.tests: line 26: test: `)' expected +2 +./test.tests: line 26: test: (: unary operator expected +2 +./test.tests: line 26: test: `)' expected +2 t -p /dev/fd/6 1 t -p /dev/fd/6 diff --git a/tests/test.tests b/tests/test.tests index 117918d8..412e7834 100644 --- a/tests/test.tests +++ b/tests/test.tests @@ -494,4 +494,15 @@ t -t /dev/tty4444444... # fixed in bash-4.0-beta t -t ' ' +# ambiguous parenthesized test expressions with more than 4 arguments + +t true -a \( ! -a \) +t true -a \( -n foo \) +t true -a \( foo \) + +t 1 = 1 -a \( \) +t \( \) + +t 1 = 1 -a \( \) -a -n "" + ${THIS_SH} ./test1.sub