summaryrefslogtreecommitdiff
path: root/posix
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1998-03-22 09:04:23 +0000
committerUlrich Drepper <drepper@redhat.com>1998-03-22 09:04:23 +0000
commit1f4a9ebd1c1269c9fd77f425bb4da8964efb4cca (patch)
treef866f7d66ce410ee3e3f5b8f7910738c4960cc30 /posix
parent2c8d89e729e6296b06f5aa504f360bd131d5ff7e (diff)
Update.
1998-03-22 Ulrich Drepper <drepper@cygnus.com> * posix/wordexp.c: Rewrite parse_param. Patch by Tim Waugh and. Andreas Schwab.
Diffstat (limited to 'posix')
-rw-r--r--posix/wordexp.c469
1 files changed, 227 insertions, 242 deletions
diff --git a/posix/wordexp.c b/posix/wordexp.c
index 1df552a66f..2a58b6061a 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -1067,16 +1067,115 @@ parse_param (char **word, size_t *word_length, size_t *max_length,
int free_value = 0;
int pattern_is_quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
int error;
+ int special = 0;
+ char buffer[21];
int brace = words[*offset] == '{';
if (brace)
++*offset;
- for (; words[*offset]; ++(*offset))
+ /* First collect the parameter name. */
+
+ if (words[*offset] == '#')
+ {
+ seen_hash = 1;
+ if (!brace)
+ goto envsubst;
+ ++*offset;
+ }
+
+ if (isalpha (words[*offset]) || words[*offset] == '_')
+ {
+ /* Normal parameter name. */
+ do
+ {
+ env = w_addchar (env, &env_length, &env_maxlen,
+ words[*offset]);
+ if (env == NULL)
+ goto no_space;
+ }
+ while (isalnum (words[++*offset]) || words[*offset] == '_');
+ }
+ else if (isdigit (words[*offset]))
{
- int special;
+ /* Numeric parameter name. */
+ special = 1;
+ do
+ {
+ env = w_addchar (env, &env_length, &env_maxlen,
+ words[*offset]);
+ if (env == NULL)
+ goto no_space;
+ if (!brace)
+ goto envsubst;
+ }
+ while (isdigit(words[++*offset]));
+ }
+ else if (strchr ("*@$", words[*offset]) != NULL)
+ {
+ /* Special parameter. */
+ special = 1;
+ env = w_addchar (env, &env_length, &env_maxlen,
+ words[*offset]);
+ if (env == NULL)
+ goto no_space;
+ ++*offset;
+ }
+ else
+ {
+ if (brace)
+ goto syntax;
+ }
+
+ if (brace)
+ {
+ /* Check for special action to be applied to the value. */
+ switch (words[*offset])
+ {
+ case '}':
+ /* Evalute. */
+ goto envsubst;
+
+ case '#':
+ action = ACT_RP_SHORT_LEFT;
+ if (words[1 + *offset] == '#')
+ {
+ ++*offset;
+ action = ACT_RP_LONG_LEFT;
+ }
+ break;
+
+ case '%':
+ action = ACT_RP_SHORT_RIGHT;
+ if (words[1 + *offset] == '%')
+ {
+ ++*offset;
+ action = ACT_RP_LONG_RIGHT;
+ }
+ break;
+
+ case ':':
+ if (strchr ("-=?+", words[1 + *offset]) == NULL)
+ goto syntax;
+
+ colon_seen = 1;
+ action = words[++*offset];
+ break;
- if (action != ACT_NONE)
+ case '-':
+ case '=':
+ case '?':
+ case '+':
+ action = words[*offset];
+ break;
+
+ default:
+ goto syntax;
+ }
+
+ /* Now collect the pattern. */
+ ++*offset;
+ for (; words[*offset]; ++(*offset))
{
switch (words[*offset])
{
@@ -1120,197 +1219,63 @@ parse_param (char **word, size_t *word_length, size_t *max_length,
words[*offset]);
if (pattern == NULL)
goto no_space;
-
- continue;
- }
-
- switch (words[*offset])
- {
- case '}':
- if (!brace)
- goto end_of_word;
-
- if (env == NULL)
- goto syntax;
-
- /* Evaluate. */
- goto envsubst;
-
- case '#':
- /* '#' only has special meaning inside braces or as the very
- * first character after $ */
- if (*offset == start)
- {
- seen_hash = 1;
- goto envsubst;
- }
-
- if (!brace)
- /* Evaluate */
- /* (and re-parse this character) */
- goto end_of_word;
-
- /* At the start? (i.e. 'string length') */
- if (env == NULL)
- {
- seen_hash = 1;
- continue;
- }
- else if (seen_hash)
- goto syntax;
-
- action = ACT_RP_SHORT_LEFT;
- if (words[1 + *offset] == '#')
- {
- ++*offset;
- action = ACT_RP_LONG_LEFT;
- }
-
- continue;
-
- case '%':
- if (!brace)
- /* Re-parse this character after substitution */
- goto end_of_word;
-
- if (!env || !*env)
- goto syntax;
-
- if (seen_hash)
- goto syntax;
-
- action = ACT_RP_SHORT_RIGHT;
- if (words[1 + *offset] == '%')
- {
- ++*offset;
- action = ACT_RP_LONG_RIGHT;
- }
-
- continue;
-
- case ':':
- if (!brace)
- goto end_of_word;
-
- if (!env || !*env)
- goto syntax;
-
- if (seen_hash)
- goto syntax;
-
- if (words[1 + *offset] != '-' && words[1 + *offset] != '='
- && words[1 + *offset] != '?' && words[1 + *offset] != '+')
- goto syntax;
-
- colon_seen = 1;
- action = words[++*offset];
- continue;
-
- case '-':
- case '=':
- case '?':
- case '+':
- if (!brace)
- goto end_of_word;
-
- if (!env || !*env)
- goto syntax;
-
- action = words[*offset];
- continue;
- }
-
- special = strchr ("*@$", words[*offset]) != NULL;
-
- if (!isalnum (words[*offset]) && !special)
- /* Stop and evaluate, remembering char we stopped at */
- break;
-
- env = w_addchar (env, &env_length, &env_maxlen,
- words[*offset]);
- if (env == NULL)
- goto no_space;
-
- if (special)
- {
- if (brace)
- ++*offset;
- goto envsubst;
}
}
- /* End of input string -- remember to reparse the character that we stopped
- * at. */
-end_of_word:
+ /* End of input string -- remember to reparse the character that we
+ * stopped at. */
--(*offset);
envsubst:
if (words[start] == '{' && words[*offset] != '}')
goto syntax;
- if (!env || !*env)
+ if (env == NULL)
{
if (seen_hash)
{
/* $# expands to the number of positional parameters */
- char buffer[21];
buffer[20] = '\0';
- *word = w_addstr (*word, word_length, max_length,
- _itoa_word (__libc_argc - 1, &buffer[20], 10, 0));
+ value = _itoa_word (__libc_argc - 1, &buffer[20], 10, 0);
+ seen_hash = 0;
}
else
{
/* Just $ on its own */
*offset = start - 1;
*word = w_addchar (*word, word_length, max_length, '$');
+ return *word ? 0 : WRDE_NOSPACE;
}
-
- if (env)
- free (env);
-
- return *word ? 0 : WRDE_NOSPACE;
}
+ /* Is it a numberic parameter? */
+ else if (isdigit (env[0]))
+ {
+ int n = atoi (env);
+ if (n >= __libc_argc)
+ /* Substitute NULL. */
+ value = NULL;
+ else
+ /* Replace with appropriate positional parameter. */
+ value = __libc_argv[n];
+ }
/* Is it a special parameter? */
- if (strpbrk (env, "*@$") || isdigit (*env))
+ else if (special)
{
- if ((isdigit(*env) && strcspn (env, "1234567890")) ||
- (!isdigit(*env) && env[1] != '\0'))
- {
- /* Bad substitution if it isn't "*", "@", "$", or just a number. */
- bad_subst:
- free (env);
- fprintf (stderr, "${%s}: bad substitution\n", env);
- return WRDE_SYNTAX;
- }
-
- /* Is it a digit? */
- if (isdigit(*env))
+ /* Is it `$$'? */
+ if (*env == '$')
{
- char *endp;
- int n = strtol (env, &endp, 10);
-
- if (*endp != '\0')
- goto bad_subst;
-
- free (env);
- if (n >= __libc_argc)
- /* Substitute NULL */
- return 0;
-
- /* Replace with the appropriate positional parameter */
- value = __libc_argv[n];
- goto maybe_fieldsplit;
+ buffer[20] = '\0';
+ value = _itoa_word (getpid (), &buffer[20], 10, 0);
}
- /* Is it `$$' ? */
- else if (*env == '$')
+ /* Is it `${#*}' or `${#@}'? */
+ else if ((*env == '*' || *env == '@') && seen_hash)
{
- char pidstr[21];
-
+ buffer[20] = '\0';
+ value = _itoa_word (__libc_argc > 0 ? __libc_argc - 1 : 0,
+ &buffer[20], 10, 0);
+ *word = w_addstr (*word, word_length, max_length, value);
free (env);
- pidstr[20] = '\0';
- *word = w_addstr (*word, word_length, max_length,
- _itoa_word (getpid(), &pidstr[20], 10, 0));
return *word ? 0 : WRDE_NOSPACE;
}
/* Is it `$*' or `$@' (unquoted) ? */
@@ -1320,7 +1285,6 @@ envsubst:
int p;
/* Build up value parameter by parameter (copy them) */
- free (env);
for (p = 1; __libc_argv[p]; ++p)
{
char *old_pointer = value;
@@ -1334,7 +1298,7 @@ envsubst:
/* First realloc will act as malloc because value is
* initialised to NULL. */
- value = realloc (value, plist_len);
+ value = realloc (value, plist_len); /* ### re-work this */
if (value == NULL)
{
free (old_pointer);
@@ -1350,46 +1314,58 @@ envsubst:
}
free_value = 1;
- if (value)
- goto maybe_fieldsplit;
-
- return 0;
}
+ else
+ {
+ /* Must be a quoted `$@' */
+ assert (*env == '@' && quoted);
- /* Must be a quoted `$@' */
- assert (*env == '@');
- assert (quoted);
- free (env);
+ /* Each parameter is a separate word ("$@") */
+ if (__libc_argc == 2)
+ {
+ value = __strdup (__libc_argv[1]);
+ if (value == NULL)
+ goto no_space;
+ }
+ else if (__libc_argc > 2)
+ {
+ int p;
- /* Each parameter is a separate word ("$@") */
- if (__libc_argv[0] != NULL && __libc_argv[1] != NULL)
- {
- /* Append first parameter to current word. */
- int p;
+ /* Append first parameter to current word. */
+ value = w_addstr (*word, word_length, max_length,
+ __libc_argv[1]);
+ if (value == NULL || w_addword (pwordexp, value))
+ goto no_space;
- *word = w_addstr (*word, word_length, max_length, __libc_argv[1]);
- if (*word == NULL)
- return WRDE_NOSPACE;
+ for (p = 2; __libc_argv[p + 1]; p++)
+ {
+ char *newword = __strdup (__libc_argv[p]);
+ if (newword == NULL || w_addword (pwordexp, newword))
+ goto no_space;
+ }
- for (p = 2; __libc_argv[p]; p++)
+ /* Start a new word with the last parameter. */
+ *word = NULL;
+ *max_length = *word_length = 0;
+ value = __strdup (__libc_argv[p]);
+ if (value == NULL)
+ goto no_space;
+ }
+ else
{
- size_t len;
- char *s;
- if (w_addword (pwordexp, *word))
- return WRDE_NOSPACE;
- len = strlen (__libc_argv[p]) + 1;
- s = malloc (len);
- if (s == NULL)
- return WRDE_NOSPACE;
- *word = memcpy (s, __libc_argv[p], len);
- *max_length = *word_length = len - 1;
+ free (env);
+ free (pattern);
+ return 0;
}
}
-
- return 0;
}
-
- value = getenv (env);
+ else
+ {
+ value = getenv (env);
+ if (value == NULL && (flags & WRDE_UNDEF))
+ /* Variable not defined. */
+ return WRDE_BADVAL;
+ }
if (action != ACT_NONE)
{
@@ -1404,14 +1380,11 @@ envsubst:
char c;
char *end;
- if (!pattern || !*pattern)
+ if (value == NULL || pattern == NULL || *pattern == '\0')
break;
end = value + strlen (value);
- if (value == NULL)
- break;
-
switch (action)
{
case ACT_RP_SHORT_LEFT:
@@ -1451,7 +1424,15 @@ envsubst:
{
if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
{
- *p = '\0';
+ char *newval;
+ newval = malloc (p - value + 1);
+ if (newval == NULL)
+ goto no_space;
+ *(char *) __mempcpy (newval, value, p - value) = '\0';
+ if (free_value)
+ free (value);
+ value = newval;
+ free_value = 1;
break;
}
}
@@ -1463,7 +1444,15 @@ envsubst:
{
if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
{
- *p = '\0';
+ char *newval;
+ newval = malloc (p - value + 1);
+ if (newval == NULL)
+ goto no_space;
+ *(char *) __mempcpy (newval, value, p - value) = '\0';
+ if (free_value)
+ free (value);
+ value = newval;
+ free_value = 1;
break;
}
}
@@ -1483,14 +1472,9 @@ envsubst:
break;
if (!colon_seen && value)
- {
- /* Substitute NULL */
- free (env);
- free (pattern);
- return 0;
- }
-
- if (*pattern)
+ /* Substitute NULL */
+ error = 0;
+ else if (*pattern)
{
/* Expand 'pattern' and write it to stderr */
wordexp_t we;
@@ -1513,15 +1497,16 @@ envsubst:
}
wordfree (&we);
- free (env);
- free (pattern);
- return error;
+ }
+ else
+ {
+ fprintf (stderr, "%s: parameter null or not set\n", env);
+ error = WRDE_BADVAL;
}
- fprintf (stderr, "%s: parameter null or not set\n", env);
free (env);
free (pattern);
- return WRDE_BADVAL;
+ return error;
case ACT_NULL_SUBST:
if (value && *value)
@@ -1586,6 +1571,10 @@ envsubst:
char *cp;
size_t words_size = 0;
+ if (special)
+ /* Cannot assign special parameters. */
+ goto syntax;
+
for (i = 0; i < we.we_wordc; i++)
words_size += strlen (we.we_wordv[i]) + 1; /* for <space> */
words_size++;
@@ -1598,13 +1587,15 @@ envsubst:
*cp++ = ' ';
}
- __stpcpy (cp, we.we_wordv[i]);
+ strcpy (cp, we.we_wordv[i]);
/* Also assign */
setenv (env, words, 1);
}
wordfree (&we);
+ free (env);
+ free (pattern);
return 0;
}
@@ -1644,25 +1635,25 @@ envsubst:
free (env);
free (pattern);
- if (value == NULL)
- {
- /* Variable not defined */
- if (flags & WRDE_UNDEF)
- return WRDE_BADVAL;
-
- return 0;
- }
-
if (seen_hash)
{
char param_length[21];
param_length[20] = '\0';
*word = w_addstr (*word, word_length, max_length,
- _itoa_word (strlen (value), &param_length[20], 10, 0));
+ _itoa_word (value ? strlen (value) : 0,
+ &param_length[20], 10, 0));
+ if (free_value)
+ {
+ assert (value != NULL);
+ free (value);
+ }
+
return *word ? 0 : WRDE_NOSPACE;
}
- maybe_fieldsplit:
+ if (value == NULL)
+ return 0;
+
if (quoted || !pwordexp)
{
/* Quoted - no field split */
@@ -1704,28 +1695,22 @@ envsubst:
}
/* Skip IFS whitespace before the field */
- while (*field_begin && strchr (ifs_white, *field_begin) != NULL)
- field_begin++;
+ field_begin += strspn (field_begin, ifs_white);
if (!seen_nonws_ifs && *field_begin == 0)
/* Nothing but whitespace */
break;
/* Search for the end of the field */
- field_end = field_begin;
- while (*field_end && strchr (ifs, *field_end) == NULL)
- field_end++;
-
- /* Set up pointer to the character after end of field */
- next_field = *field_end ? field_end : NULL;
+ field_end = field_begin + strcspn (field_begin, ifs);
- /* Skip whitespace IFS after the field */
- while (next_field && *next_field && strchr (ifs_white, *next_field))
- next_field++;
+ /* Set up pointer to the character after end of field and
+ skip whitespace IFS after it. */
+ next_field = field_end + strspn (field_end, ifs_white);
/* Skip at most one non-whitespace IFS character after the field */
seen_nonws_ifs = 0;
- if (next_field && *next_field && strchr (ifs, *next_field))
+ if (*next_field && strchr (ifs, *next_field))
{
seen_nonws_ifs = 1;
next_field++;
@@ -1745,7 +1730,7 @@ envsubst:
field_begin = next_field;
}
- while (seen_nonws_ifs || (field_begin != NULL && *field_begin));
+ while (seen_nonws_ifs || *field_begin);
free (value_copy);
}