about summary refs log tree commit diff
path: root/posix
diff options
context:
space:
mode:
Diffstat (limited to 'posix')
-rw-r--r--posix/wordexp-test.c2
-rwxr-xr-xposix/wordexp-tst.sh15
-rw-r--r--posix/wordexp.c240
3 files changed, 139 insertions, 118 deletions
diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c
index 1797a7a42e..d9ecadcaa4 100644
--- a/posix/wordexp-test.c
+++ b/posix/wordexp-test.c
@@ -115,6 +115,8 @@ struct test_case_struct
     { 0, NULL, "${var=one two} \"$var\"", 0, 3, { "one", "two", "one two", } },
     { 0, "1", "$(( $(echo 3)+$var ))", 0, 1, { "4", } },
     { 0, NULL, "\"$(echo \"*\")\"", 0, 1, { "*", } },
+    { 0, "foo", "*$var*", 0, 1, { "*foo*", } },
+    { 0, "o thr", "*$var*", 0, 2, { "two", "three" } },
 
     /* Other things that should succeed */
     { 0, NULL, "\\*\"|&;<>\"\\(\\)\\{\\}", 0, 1, { "*|&;<>(){}", } },
diff --git a/posix/wordexp-tst.sh b/posix/wordexp-tst.sh
index 57ef01383b..43dc0a5ac9 100755
--- a/posix/wordexp-tst.sh
+++ b/posix/wordexp-tst.sh
@@ -19,7 +19,6 @@ IFS=" 	\
 "
 export IFS
 
-
 ${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
 ${common_objpfx}posix/wordexp-test '$*' > ${testout}1
 cat <<"EOF" | cmp - ${testout}1 || failed=1
@@ -92,4 +91,18 @@ we_wordv[1] = "c"
 we_wordv[2] = "d b"
 EOF
 
+${elf_objpfx}${rtld_installed_name} --library-path ${common_objpfx} \
+${common_objpfx}posix/wordexp-test '${#@} ${#2} *$**' two 3 4 > ${testout}10
+cat <<"EOF" | cmp - ${testout}10 || failed=1
+wordexp returned 0
+we_wordv[0] = "4"
+we_wordv[1] = "3"
+we_wordv[2] = "*${#@}"
+we_wordv[3] = "${#2}"
+we_wordv[4] = "*$**"
+we_wordv[5] = "two"
+we_wordv[6] = "3"
+we_wordv[7] = "4*"
+EOF
+
 exit $failed
diff --git a/posix/wordexp.c b/posix/wordexp.c
index 2a58b6061a..64d5b3c5a5 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -75,6 +75,13 @@ static int eval_expr (char *expr, long int *result) internal_function;
 #define W_CHUNK	(100)
 
 static inline char *
+w_newword (size_t *actlen, size_t *maxlen)
+{
+  *actlen = *maxlen = 0;
+  return NULL;
+}
+
+static inline char *
 w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch)
      /* (lengths exclude trailing zero) */
 {
@@ -337,6 +344,64 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
   return *word ? 0 : WRDE_NOSPACE;
 }
 
+
+static int
+internal_function
+do_parse_glob (const char *glob_word, char **word, size_t *word_length,
+	       size_t *max_length, wordexp_t *pwordexp, const char *ifs,
+	       const char *ifs_white)
+{
+  int error;
+  int match;
+  glob_t globbuf;
+
+  error = glob (glob_word, GLOB_NOCHECK, NULL, &globbuf);
+
+  if (error != 0)
+    {
+      /* We can only run into memory problems.  */
+      assert (error == GLOB_NOSPACE);
+      return WRDE_NOSPACE;
+    }
+
+  if (ifs && !*ifs)
+    {
+      /* No field splitting allowed. */
+      assert (globbuf.gl_pathv[0] != NULL);
+      *word = w_addstr (*word, word_length, max_length, globbuf.gl_pathv[0]);
+      for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
+	{
+	  *word = w_addchar (*word, word_length, max_length, ' ');
+	  if (*word != NULL)
+	    *word = w_addstr (*word, word_length, max_length,
+			      globbuf.gl_pathv[match]);
+	}
+
+      globfree (&globbuf);
+      return *word ? 0 : WRDE_NOSPACE;
+    }
+
+  assert (ifs == NULL || *ifs != '\0');
+  if (*word != NULL)
+    {
+      free (*word);
+      *word = w_newword (word_length, max_length);
+    }
+
+  for (match = 0; match < globbuf.gl_pathc; ++match)
+    {
+      char *matching_word = __strdup (globbuf.gl_pathv[match]);
+      if (matching_word == NULL || w_addword (pwordexp, matching_word))
+	{
+	  globfree (&globbuf);
+	  return WRDE_NOSPACE;
+	}
+    }
+
+  globfree (&globbuf);
+  return 0;
+}
+
 static int
 internal_function
 parse_glob (char **word, size_t *word_length, size_t *max_length,
@@ -344,13 +409,15 @@ parse_glob (char **word, size_t *word_length, size_t *max_length,
 	    wordexp_t *pwordexp, const char *ifs, const char *ifs_white)
 {
   /* We are poised just after a '*', a '[' or a '?'. */
-  int error;
-  glob_t globbuf;
-  int match;
-  char *matching_word;
+  int error = WRDE_NOSPACE;
   int quoted = 0; /* 1 if singly-quoted, 2 if doubly */
+  int i;
+  wordexp_t glob_list; /* List of words to glob */
 
-  for (; words[*offset]; (*offset)++)
+  glob_list.we_wordc = 0;
+  glob_list.we_wordv = NULL;
+  glob_list.we_offs = 0;
+  for (; words[*offset] != '\0'; ++*offset)
     {
       if ((ifs && strchr (ifs, words[*offset])) ||
 	  (!ifs && strchr (" \t\n", words[*offset])))
@@ -384,103 +451,48 @@ parse_glob (char **word, size_t *word_length, size_t *max_length,
       /* Sort out other special characters */
       if (quoted != 1 && words[*offset] == '$')
 	{
-	  error = parse_dollars (word, word_length, max_length, words, offset,
-				 flags, pwordexp, ifs, ifs_white, quoted == 2);
+	  error = parse_dollars (word, word_length, max_length, words,
+				 offset, flags, &glob_list, ifs, ifs_white,
+				 quoted == 2);
 	  if (error)
-	    return error;
+	    goto tidy_up;
 
 	  continue;
 	}
       else if (words[*offset] == '\\')
 	{
 	  if (quoted)
-	    error = parse_qtd_backslash (word, word_length, max_length, words,
-					 offset);
+	    error = parse_qtd_backslash (word, word_length, max_length,
+					 words, offset);
 	  else
-	    error = parse_backslash (word, word_length, max_length, words,
-				     offset);
+	    error = parse_backslash (word, word_length, max_length,
+				     words, offset);
 
 	  if (error)
-	    return error;
+	    goto tidy_up;
 
 	  continue;
 	}
 
       *word = w_addchar (*word, word_length, max_length, words[*offset]);
       if (*word == NULL)
-	return WRDE_NOSPACE;
+	goto tidy_up;
     }
 
-  error = glob (*word, GLOB_NOCHECK, NULL, &globbuf);
+  /* Don't forget to re-parse the character we stopped at. */
+  --*offset;
 
-  if (error != 0)
-    {
-      /* We can only run into memory problems.  */
-      assert (error == GLOB_NOSPACE);
-
-      return WRDE_NOSPACE;
-    }
+  /* Glob the words */
+  error = w_addword (&glob_list, *word);
+  *word = w_newword (word_length, max_length);
+  for (i = 0; error == 0 && i < glob_list.we_wordc; i++)
+    error = do_parse_glob (glob_list.we_wordv[i], word, word_length,
+			   max_length, pwordexp, ifs, ifs_white);
 
-  if (ifs && !*ifs)
-    {
-      /* No field splitting allowed */
-      size_t length = strlen (globbuf.gl_pathv[0]);
-      char *old_word = *word;
-      *word = realloc (*word, length + 1);
-      if (*word == NULL)
-	{
-	  free (old_word);
-	  goto no_space;
-	}
-
-      memcpy (*word, globbuf.gl_pathv[0], length + 1);
-      *word_length = length;
-
-      for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match)
-	{
-	  *word = w_addchar (*word, word_length, max_length, ' ');
-	  if (*word != NULL)
-	    *word = w_addstr (*word, word_length, max_length,
-			      globbuf.gl_pathv[match]);
-	}
-
-      /* Re-parse white space on return */
-      globfree (&globbuf);
-      --(*offset);
-      return *word ? 0 : WRDE_NOSPACE;
-    }
-
-  /* here ifs != "" */
-  free (*word);
-  *word = NULL;
-  *word_length = 0;
-
-  matching_word = __strdup (globbuf.gl_pathv[0]);
-  if (matching_word == NULL)
-    goto no_space;
-
-  if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
-    goto no_space;
-
-  for (match = 1; match < globbuf.gl_pathc; ++match)
-    {
-      matching_word = __strdup (globbuf.gl_pathv[match]);
-      if (matching_word == NULL)
-	goto no_space;
-
-      if (w_addword (pwordexp, matching_word) == WRDE_NOSPACE)
-	goto no_space;
-    }
-
-  globfree (&globbuf);
-
-  /* Re-parse white space on return */
-  --(*offset);
-  return 0;
-
-no_space:
-  globfree (&globbuf);
-  return WRDE_NOSPACE;
+  /* Now tidy up */
+tidy_up:
+  wordfree (&glob_list);
+  return error;
 }
 
 static int
@@ -638,10 +650,11 @@ parse_arith (char **word, size_t *word_length, size_t *max_length,
   /* We are poised just after "$((" or "$[" */
   int error;
   int paren_depth = 1;
-  size_t expr_length = 0;
-  size_t expr_maxlen = 0;
-  char *expr = NULL;
+  size_t expr_length;
+  size_t expr_maxlen;
+  char *expr;
 
+  expr = w_newword (&expr_length, &expr_maxlen);
   for (; words[*offset]; ++(*offset))
     {
       switch (words[*offset])
@@ -934,9 +947,7 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
 		      return WRDE_NOSPACE;
 		    }
 
-		  *word = NULL;
-		  *word_length = 0;
-		  *max_length = 0;
+		  *word = w_newword (word_length, max_length);
 		  /* fall back round the loop.. */
 		}
 	      else
@@ -974,10 +985,10 @@ parse_comm (char **word, size_t *word_length, size_t *max_length,
   /* We are poised just after "$(" */
   int paren_depth = 1;
   int error = 0;
-  size_t comm_length = 0;
-  size_t comm_maxlen = 0;
-  char *comm = NULL;
   int quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
+  size_t comm_length;
+  size_t comm_maxlen;
+  char *comm = w_newword (&comm_length, &comm_maxlen);
 
   for (; words[*offset]; ++(*offset))
     {
@@ -1052,13 +1063,13 @@ parse_param (char **word, size_t *word_length, size_t *max_length,
     ACT_NONNULL_SUBST = '+',
     ACT_NULL_ASSIGN = '='
   };
-  size_t env_length = 0;
-  size_t env_maxlen = 0;
-  size_t pat_length = 0;
-  size_t pat_maxlen = 0;
+  size_t env_length;
+  size_t env_maxlen;
+  size_t pat_length;
+  size_t pat_maxlen;
   size_t start = *offset;
-  char *env = NULL;
-  char *pattern = NULL;
+  char *env;
+  char *pattern;
   char *value = NULL;
   enum action action = ACT_NONE;
   int depth = 0;
@@ -1071,6 +1082,9 @@ parse_param (char **word, size_t *word_length, size_t *max_length,
   char buffer[21];
   int brace = words[*offset] == '{';
 
+  env = w_newword (&env_length, &env_maxlen);
+  pattern = w_newword (&pat_length, &pat_maxlen);
+
   if (brace)
     ++*offset;
 
@@ -1247,7 +1261,7 @@ envsubst:
 	  return *word ? 0 : WRDE_NOSPACE;
 	}
     }
-  /* Is it a numberic parameter? */
+  /* Is it a numeric parameter? */
   else if (isdigit (env[0]))
     {
       int n = atoi (env);
@@ -1345,8 +1359,7 @@ envsubst:
 		}
 
 	      /* Start a new word with the last parameter. */
-	      *word = NULL;
-	      *max_length = *word_length = 0;
+	      *word = w_newword (word_length, max_length);
 	      value = __strdup (__libc_argv[p]);
 	      if (value == NULL)
 		goto no_space;
@@ -1690,8 +1703,7 @@ envsubst:
 		  return WRDE_NOSPACE;
 		}
 
-	      *word = NULL;
-	      *word_length = *max_length = 0;
+	      *word = w_newword (word_length, max_length);
 	    }
 
 	  /* Skip IFS whitespace before the field */
@@ -1825,10 +1837,10 @@ parse_backtick (char **word, size_t *word_length, size_t *max_length,
 {
   /* We are poised just after "`" */
   int error;
-  size_t comm_length = 0;
-  size_t comm_maxlen = 0;
-  char *comm = NULL;
   int squoting = 0;
+  size_t comm_length;
+  size_t comm_maxlen;
+  char *comm = w_newword (&comm_length, &comm_maxlen);
 
   for (; words[*offset]; ++(*offset))
     {
@@ -1974,9 +1986,9 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
 {
   size_t wordv_offset;
   size_t words_offset;
-  size_t word_length = 0;
-  size_t max_length = 0;
-  char *word = NULL;
+  size_t word_length;
+  size_t max_length;
+  char *word = w_newword (&word_length, &max_length);
   int error;
   char *ifs;
   char ifs_white[4];
@@ -2169,17 +2181,13 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
 		goto do_error;
 	      }
 
-	    word = NULL;
-	    word_length = 0;
-	    max_length = 0;
+	    word = w_newword (&word_length, &max_length);
 	    break;
 	  }
 
 	/* It's a non-whitespace IFS char */
 
-	/* Multiple non-whitespace IFS chars are treated as one;
-	 * IS THIS CORRECT?
-	 */
+	/* Multiple non-whitespace IFS chars are treated as one.  */
 	if (word != NULL)
 	  {
 	    if (w_addword (pwordexp, word) == WRDE_NOSPACE)
@@ -2189,9 +2197,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
 	      }
 	  }
 
-	word = NULL;
-	word_length = 0;
-	max_length = 0;
+	word = w_newword (&word_length, &max_length);
       }
 
   /* End of string */