about summary refs log tree commit diff
path: root/posix/wordexp.c
diff options
context:
space:
mode:
Diffstat (limited to 'posix/wordexp.c')
-rw-r--r--posix/wordexp.c49
1 files changed, 31 insertions, 18 deletions
diff --git a/posix/wordexp.c b/posix/wordexp.c
index 0c89e02234..5e0e985006 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -1018,6 +1018,7 @@ parse_param (char **word, size_t *word_length, size_t *max_length,
   int colon_seen = 0;
   int depth = 0;
   int seen_hash = 0;
+  int free_value = 0;
   int error;
 
   for (; words[*offset]; ++(*offset))
@@ -1285,7 +1286,6 @@ envsubst:
       if (isdigit(*env))
 	{
 	  int n = *env - '0';
-	  char *param;
 
 	  free (env);
 	  if (n >= __libc_argc)
@@ -1293,12 +1293,8 @@ envsubst:
 	    return 0;
 
 	  /* Replace with the appropriate positional parameter */
-	  param = __strdup (__libc_argv[n]);
-	  if (!param)
-	    return WRDE_NOSPACE;
-
-	  *word = w_addstr (*word, word_length, max_length, param);
-	  return *word ? 0 : WRDE_NOSPACE;
+	  value = __libc_argv[n];
+	  goto maybe_fieldsplit;
 	}
       /* Is it `$$' ? */
       else if (*env == '$')
@@ -1347,6 +1343,7 @@ envsubst:
 		}
 	    }
 
+	  free_value = 1;
 	  if (value)
 	    goto maybe_fieldsplit;
 
@@ -1666,31 +1663,42 @@ envsubst:
       return *word ? 0 : WRDE_NOSPACE;
     }
 
-
  maybe_fieldsplit:
   if (quoted || !pwordexp)
     {
       /* Quoted - no field split */
       *word = w_addstr (*word, word_length, max_length, value);
+      if (free_value)
+	free (value);
+
       return *word ? 0 : WRDE_NOSPACE;
     }
   else
     {
       /* Need to field-split */
-      char *field_begin = value;
+      char *value_copy = __strdup (value); /* Don't modify value */
+      char *field_begin = value_copy;
       int seen_nonws_ifs = 0;
 
+      if (free_value)
+	free (value);
+
+      if (value_copy == NULL)
+	return WRDE_NOSPACE;
+
       do
 	{
 	  char *field_end = field_begin;
 	  char *next_field;
-	  char ch;
 
 	  /* If this isn't the first field, start a new word */
-	  if (field_begin != value)
+	  if (field_begin != value_copy)
 	    {
 	      if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
-		return WRDE_NOSPACE;
+		{
+		  free (value_copy);
+		  return WRDE_NOSPACE;
+		}
 
 	      *word = NULL;
 	      *word_length = *max_length = 0;
@@ -1710,8 +1718,7 @@ envsubst:
 	    field_end++;
 
 	  /* Set up pointer to the character after end of field */
-	  ch = *field_end;
-	  next_field = ch ? field_end : NULL;
+	  next_field = *field_end ? field_end : NULL;
 
 	  /* Skip whitespace IFS after the field */
 	  while (next_field && *next_field && strchr (ifs_white, *next_field))
@@ -1729,13 +1736,19 @@ envsubst:
 	  *field_end = 0;
 
 	  /* Tag a copy onto the current word */
-	  *word = w_addstr (*word, word_length, max_length,
-			    __strdup (field_begin));
+	  *word = w_addstr (*word, word_length, max_length, field_begin);
+
 	  if (*word == NULL)
-	    return WRDE_NOSPACE;
+	    {
+	      free (value_copy);
+	      return WRDE_NOSPACE;
+	    }
 
 	  field_begin = next_field;
-	} while (seen_nonws_ifs || (field_begin && *field_begin));
+	}
+      while (seen_nonws_ifs || (field_begin != NULL && *field_begin));
+
+      free (value_copy);
     }
 
   return 0;