]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
change to test builtin for parenthesized expressions when there are more than four...
authorChet Ramey <chet.ramey@case.edu>
Mon, 25 Mar 2024 14:32:07 +0000 (10:32 -0400)
committerChet Ramey <chet.ramey@case.edu>
Mon, 25 Mar 2024 14:32:07 +0000 (10:32 -0400)
CWRU/CWRU.chlog
builtins/printf.def
subst.c
test.c
tests/test.right
tests/test.tests

index c5e0c78a03ba3c50a2f08ed876ac434d12d48595..725b576bb6c589858e82816f00f3dd9e4c66dd29 100644 (file)
@@ -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 <eggert@cs.ucla.edu>
+         From a report and patch by Paul Eggert <eggert@cs.ucla.edu>
 
 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 <eggert@cs.ucla.edu>
+         From a report and patch by Paul Eggert <eggert@cs.ucla.edu>
 
                                   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 <eggert@cs.ucla.edu>
+         From a report and patch by Paul Eggert <eggert@cs.ucla.edu>
+
+                                  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
index 2327bd5d62f2fbaf75781b2f3976280fc448186f..c033407be9f6139b8729e38d657d0ae51d2b9ef6 100644 (file)
@@ -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 2c51021bf2ec0c03ae4232566e7633570ee24797..f4254b1308bfa319e8248c91d2445127a146664c 100644 (file)
--- 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 6967ef95d9814bb309e451f5f550705d50727ddf..09dc147813293645728ac8036736c39e44c3ee79 100644 (file)
--- 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)
     {
index cb3f94dd307ce48ea1c07202d89887ef9103a59b..522dd6e2c5949c5d6a2da8fb68a18e09ef200c2c 100644 (file)
@@ -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
index 117918d88ee22cd7690822f31cb418f5c10b2261..412e78347faba3862c9e59b6a9282e9e30f487df 100644 (file)
@@ -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