aboutsummaryrefslogtreecommitdiff
path: root/posix
diff options
context:
space:
mode:
Diffstat (limited to 'posix')
-rw-r--r--posix/wordexp.c430
1 files changed, 202 insertions, 228 deletions
diff --git a/posix/wordexp.c b/posix/wordexp.c
index 443dc46..54f830c 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -973,45 +973,63 @@ parse_comm (char **word, size_t *word_length, size_t *max_length,
{
/* We are poised just after "$(" */
int paren_depth = 1;
- int error;
+ 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 */
for (; words[*offset]; ++(*offset))
{
switch (words[*offset])
{
+ case '\'':
+ if (quoted == 0)
+ quoted = 1;
+ else if (quoted == 1)
+ quoted = 0;
+
+ break;
+
+ case '"':
+ if (quoted == 0)
+ quoted = 2;
+ else if (quoted == 2)
+ quoted = 0;
+
+ break;
+
case ')':
- if (--paren_depth == 0)
+ if (!quoted && --paren_depth == 0)
{
/* Go -- give script to the shell */
- error = exec_comm (comm, word, word_length, max_length, flags,
- pwordexp, ifs, ifs_white);
- free (comm);
+ if (comm)
+ {
+ error = exec_comm (comm, word, word_length, max_length,
+ flags, pwordexp, ifs, ifs_white);
+ free (comm);
+ }
+
return error;
}
/* This is just part of the script */
- comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
- if (comm == NULL)
- return WRDE_NOSPACE;
-
break;
case '(':
- ++paren_depth;
- default:
- comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
- if (comm == NULL)
- return WRDE_NOSPACE;
-
- break;
+ if (!quoted)
+ ++paren_depth;
}
+
+ comm = w_addchar (comm, &comm_length, &comm_maxlen, words[*offset]);
+ if (comm == NULL)
+ return WRDE_NOSPACE;
}
/* Premature end */
- free (comm);
+ if (comm)
+ free (comm);
+
return WRDE_SYNTAX;
}
@@ -1022,73 +1040,100 @@ parse_param (char **word, size_t *word_length, size_t *max_length,
const char *ifs, const char *ifs_white, int quoted)
{
/* We are poised just after "$" */
- enum remove_pattern_enum
+ enum action
{
- RP_NONE = 0,
- RP_SHORT_LEFT,
- RP_LONG_LEFT,
- RP_SHORT_RIGHT,
- RP_LONG_RIGHT
+ ACT_NONE,
+ ACT_RP_SHORT_LEFT = '#',
+ ACT_RP_LONG_LEFT = 'L',
+ ACT_RP_SHORT_RIGHT = '%',
+ ACT_RP_LONG_RIGHT = 'R',
+ ACT_NULL_ERROR = '?',
+ ACT_NULL_SUBST = '-',
+ ACT_NONNULL_SUBST = '+',
+ ACT_NULL_ASSIGN = '='
};
- size_t start = *offset;
size_t env_length = 0;
size_t env_maxlen = 0;
size_t pat_length = 0;
size_t pat_maxlen = 0;
+ size_t start = *offset;
char *env = NULL;
char *pattern = NULL;
char *value = NULL;
- char action = '\0';
- enum remove_pattern_enum remove = RP_NONE;
- int colon_seen = 0;
+ enum action action = ACT_NONE;
int depth = 0;
+ int colon_seen = 0;
int seen_hash = 0;
int free_value = 0;
+ int pattern_is_quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
int error;
+ int brace = words[*offset] == '{';
+
+ if (brace)
+ ++*offset;
for (; words[*offset]; ++(*offset))
{
- switch (words[*offset])
- {
- case '{':
- ++depth;
+ int special;
- if (action != '\0' || remove != RP_NONE)
+ if (action != ACT_NONE)
+ {
+ switch (words[*offset])
{
- pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
- words[*offset]);
- if (pattern == NULL)
- goto no_space;
+ case '{':
+ if (!pattern_is_quoted)
+ ++depth;
+ break;
+ case '}':
+ if (!pattern_is_quoted)
+ {
+ if (depth == 0)
+ goto envsubst;
+ --depth;
+ }
break;
- }
- if (*offset == start)
- break;
+ case '\\':
+ if (!pattern_is_quoted && words[++*offset] == '\0')
+ goto syntax;
+ break;
- /* Otherwise evaluate */
- /* (and re-parse this character) */
- --(*offset);
- goto envsubst;
+ case '\'':
+ if (pattern_is_quoted == 0)
+ pattern_is_quoted = 1;
+ else if (pattern_is_quoted == 1)
+ pattern_is_quoted = 0;
- case '}':
- if (words[start] != '{')
- --(*offset);
+ break;
- if (action != '\0' || remove != RP_NONE)
- {
- if (--depth)
- {
- pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
- words[*offset]);
- if (pattern == NULL)
- goto no_space;
+ case '"':
+ if (pattern_is_quoted == 0)
+ pattern_is_quoted = 2;
+ else if (pattern_is_quoted == 2)
+ pattern_is_quoted = 0;
- break;
- }
+ break;
}
- /* Evaluate */
+ pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
+ 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 '#':
@@ -1100,173 +1145,104 @@ parse_param (char **word, size_t *word_length, size_t *max_length,
goto envsubst;
}
- if (words[start] != '{')
- {
- /* Evaluate */
- /* (and re-parse this character) */
- --(*offset);
- goto envsubst;
- }
+ if (!brace)
+ /* Evaluate */
+ /* (and re-parse this character) */
+ goto end_of_word;
/* At the start? (i.e. 'string length') */
- if (*offset == start + 1)
+ if (env == NULL)
{
seen_hash = 1;
- break;
+ continue;
}
else if (seen_hash)
goto syntax;
- /* Separating variable name from prefix pattern? */
- if (remove == RP_NONE)
- {
- remove = RP_SHORT_LEFT;
- break;
- }
- else if (remove == RP_SHORT_LEFT)
+ action = ACT_RP_SHORT_LEFT;
+ if (words[1 + *offset] == '#')
{
- remove = RP_LONG_LEFT;
- break;
+ ++*offset;
+ action = ACT_RP_LONG_LEFT;
}
- /* Must be part of prefix/suffix pattern. */
- pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
- words[*offset]);
- if (pattern == NULL)
- goto no_space;
-
- break;
+ continue;
case '%':
+ if (!brace)
+ /* Re-parse this character after substitution */
+ goto end_of_word;
+
if (!env || !*env)
goto syntax;
- /* Separating variable name from suffix pattern? */
- if (remove == RP_NONE)
- {
- remove = RP_SHORT_RIGHT;
- break;
- }
- else if (remove == RP_SHORT_RIGHT)
+ if (seen_hash)
+ goto syntax;
+
+ action = ACT_RP_SHORT_RIGHT;
+ if (words[1 + *offset] == '%')
{
- remove = RP_LONG_RIGHT;
- break;
+ ++*offset;
+ action = ACT_RP_LONG_RIGHT;
}
- /* Must be part of prefix/suffix pattern. */
- pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
- words[*offset]);
- if (pattern == NULL)
- goto no_space;
-
- break;
+ continue;
case ':':
+ if (!brace)
+ goto end_of_word;
+
if (!env || !*env)
goto syntax;
- if (action != '\0' || remove != RP_NONE)
- {
- pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
- words[*offset]);
- if (pattern == NULL)
- goto no_space;
-
- break;
- }
+ if (seen_hash)
+ goto syntax;
- if ((words[1 + *offset] == '-') || (words[1 + *offset] == '=')
- || (words[1 + *offset] == '?') || (words[1 + *offset] == '+'))
- {
- colon_seen = 1;
- break;
- }
+ if (words[1 + *offset] != '-' && words[1 + *offset] != '='
+ && words[1 + *offset] != '?' && words[1 + *offset] != '+')
+ goto syntax;
- goto syntax;
+ colon_seen = 1;
+ action = words[++*offset];
+ continue;
case '-':
case '=':
case '?':
case '+':
- if (!env || !*env)
- goto syntax;
+ if (!brace)
+ goto end_of_word;
- if (seen_hash)
+ if (!env || !*env)
goto syntax;
- if (action != '\0' || remove != RP_NONE)
- {
- pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
- words[*offset]);
- if (pattern == NULL)
- goto no_space;
-
- break;
- }
-
action = words[*offset];
- break;
-
- case '\\':
- if (action != '\0' || remove != RP_NONE)
- {
- /* Um. Is this right? */
- error = parse_qtd_backslash (word, word_length, max_length,
- words, offset);
- if (error == 0)
- break;
- }
- else
- {
- error = WRDE_SYNTAX;
- }
-
- if (env)
- free (env);
-
- if (pattern != NULL)
- free (pattern);
-
- return error;
-
- default:
- if (action != '\0' || remove != RP_NONE)
- {
- pattern = w_addchar (pattern, &pat_length, &pat_maxlen,
- words[*offset]);
- if (pattern == NULL)
- goto no_space;
-
- break;
- }
- else
- {
- int special = (strchr ("*@$", words[*offset]) != NULL
- || isdigit (words[*offset]));
+ continue;
+ }
- if (isalpha (words[*offset]) || special)
- {
- env = w_addchar (env, &env_length, &env_maxlen,
- words[*offset]);
- if (env == NULL)
- goto no_space;
+ special = (strchr ("*@$", words[*offset]) != NULL
+ || isdigit (words[*offset]));
- if (special && words[start] != '{')
- goto envsubst;
+ if (!isalpha (words[*offset]) && !special)
+ /* Stop and evaluate, remembering char we stopped at */
+ break;
- /* Keep going (get next char) */
- break;
- }
+ env = w_addchar (env, &env_length, &env_maxlen,
+ words[*offset]);
+ if (env == NULL)
+ goto no_space;
- /* Stop and evaluate, remembering char we stopped at */
- --(*offset);
- goto envsubst;
- }
+ if (special)
+ {
+ if (brace)
+ ++*offset;
+ goto envsubst;
}
}
/* End of input string -- remember to reparse the character that we stopped
* at. */
+end_of_word:
--(*offset);
envsubst:
@@ -1381,53 +1357,39 @@ envsubst:
free (env);
/* Each parameter is a separate word ("$@") */
- if (__libc_argv[0] == NULL)
- {
- /* This can happen if the application is started without any
- parameter, not even a name. This is legal according to
- POSIX since the giving parameters is only a "should" rule. */
- *word = __strdup ("");
- *max_length = *word_length = 0;
- }
- else
+ if (__libc_argv[0] != NULL && __libc_argv[1] != NULL)
{
+ /* Append first parameter to current word. */
int p;
- for (p = 1; __libc_argv[p + 1]; p++)
- {
- char *copy = __strdup (__libc_argv[p]);
- if (copy == NULL)
- return WRDE_NOSPACE;
-
- error = w_addword (pwordexp, copy);
- if (error)
- {
- free (copy);
- return error;
- }
- }
+ *word = w_addstr (*word, word_length, max_length, __libc_argv[1]);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
- /* Last parameter becomes current word */
- if (__libc_argv[p])
+ for (p = 1; __libc_argv[p]; p++)
{
+ if (w_addword (pwordexp, *word))
+ return WRDE_NOSPACE;
*word = __strdup (__libc_argv[p]);
+ *max_length = *word_length = strlen (*word);
if (*word == NULL)
return WRDE_NOSPACE;
-
- *max_length = *word_length = strlen (*word);
}
}
-
+
return 0;
}
value = getenv (env);
- if (action != '\0' || remove != RP_NONE)
+ if (action != ACT_NONE)
{
switch (action)
{
- case 0:
+ case ACT_RP_SHORT_LEFT:
+ case ACT_RP_LONG_LEFT:
+ case ACT_RP_SHORT_RIGHT:
+ case ACT_RP_LONG_RIGHT:
{
char *p;
char c;
@@ -1441,9 +1403,9 @@ envsubst:
if (value == NULL)
break;
- switch (remove)
+ switch (action)
{
- case RP_SHORT_LEFT:
+ case ACT_RP_SHORT_LEFT:
for (p = value; p <= end; ++p)
{
c = *p;
@@ -1459,7 +1421,7 @@ envsubst:
break;
- case RP_LONG_LEFT:
+ case ACT_RP_LONG_LEFT:
for (p = end; p >= value; --p)
{
c = *p;
@@ -1475,7 +1437,7 @@ envsubst:
break;
- case RP_SHORT_RIGHT:
+ case ACT_RP_SHORT_RIGHT:
for (p = end; p >= value; --p)
{
if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
@@ -1487,7 +1449,7 @@ envsubst:
break;
- case RP_LONG_RIGHT:
+ case ACT_RP_LONG_RIGHT:
for (p = value; p <= end; ++p)
{
if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
@@ -1500,13 +1462,13 @@ envsubst:
break;
default:
- assert (! "Unexpected `remove' value\n");
+ break;
}
break;
}
- case '?':
+ case ACT_NULL_ERROR:
if (value && *value)
/* Substitute parameter */
break;
@@ -1519,9 +1481,6 @@ envsubst:
return 0;
}
- /* Error - exit */
- fprintf (stderr, "%s: ", env);
-
if (*pattern)
{
/* Expand 'pattern' and write it to stderr */
@@ -1533,9 +1492,11 @@ envsubst:
{
int i;
+ fprintf (stderr, "%s:", env);
+
for (i = 0; i < we.we_wordc; ++i)
{
- fprintf (stderr, "%s%s", i ? " " : "", we.we_wordv[i]);
+ fprintf (stderr, " %s", we.we_wordv[i]);
}
fprintf (stderr, "\n");
@@ -1548,12 +1509,12 @@ envsubst:
return error;
}
- fprintf (stderr, "parameter null or not set\n");
+ fprintf (stderr, "%s: parameter null or not set\n", env);
free (env);
free (pattern);
return WRDE_BADVAL;
- case '-':
+ case ACT_NULL_SUBST:
if (value && *value)
/* Substitute parameter */
break;
@@ -1577,11 +1538,15 @@ envsubst:
/* No field-splitting is allowed, so imagine
quotes around the word. */
char *qtd_pattern = malloc (3 + strlen (pattern));
- sprintf (qtd_pattern, "\"%s\"", pattern);
+ if (qtd_pattern)
+ sprintf (qtd_pattern, "\"%s\"", pattern);
free (pattern);
pattern = qtd_pattern;
}
+ if (pattern == NULL && (pattern = __strdup("")) == NULL)
+ goto no_space;
+
error = wordexp (pattern, &we, flags);
if (error)
{
@@ -1606,7 +1571,7 @@ envsubst:
goto no_space;
}
- if (action == '=')
+ if (action == ACT_NULL_ASSIGN)
{
char *words;
char *cp;
@@ -1634,7 +1599,7 @@ envsubst:
return 0;
}
- case '+':
+ case ACT_NONNULL_SUBST:
if (value && *value)
goto subst_word;
@@ -1646,7 +1611,7 @@ envsubst:
free (pattern);
return 0;
- case '=':
+ case ACT_NULL_ASSIGN:
if (value && *value)
/* Substitute parameter */
break;
@@ -1818,8 +1783,17 @@ parse_dollars (char **word, size_t *word_length, size_t *max_length,
{
/* Differentiate between $((1+3)) and $((echo);(ls)) */
int i = 3 + *offset;
- while (words[i] && words[i] != ')')
- ++i;
+ int depth = 0;
+ while (words[i] && !(depth == 0 && words[i] == ')'))
+ {
+ if (words[i] == '(')
+ ++depth;
+ else if (words[i] == ')')
+ --depth;
+
+ ++i;
+ }
+
if (words[i] == ')' && words[i + 1] == ')')
{
(*offset) += 3;