diff options
Diffstat (limited to 'src/wordsplit.c')
-rw-r--r-- | src/wordsplit.c | 367 |
1 files changed, 285 insertions, 82 deletions
diff --git a/src/wordsplit.c b/src/wordsplit.c index 4a69725..c726239 100644 --- a/src/wordsplit.c +++ b/src/wordsplit.c @@ -114,11 +114,30 @@ _wsplt_subsplit (struct wordsplit *wsp, struct wordsplit *wss, wss->ws_error = wsp->ws_error; wss->ws_alloc_die = wsp->ws_alloc_die; + if (!(flags & WRDSF_NOVAR)) + { + wss->ws_env = wsp->ws_env; + wss->ws_getvar = wsp->ws_getvar; + flags |= wsp->ws_flags & (WRDSF_ENV | WRDSF_ENV_KV | WRDSF_GETVAR); + } + if (!(flags & WRDSF_NOCMD)) + { + wss->ws_command = wsp->ws_command; + } + + if ((flags & (WRDSF_NOVAR|WRDSF_NOCMD)) != (WRDSF_NOVAR|WRDSF_NOCMD)) + { + wss->ws_closure = wsp->ws_closure; + flags |= wsp->ws_flags & WRDSF_CLOSURE; + } + + wss->ws_options = wsp->ws_options; + flags |= WRDSF_DELIM | WRDSF_ALLOC_DIE | WRDSF_ERROR | WRDSF_DEBUG - | (wsp->ws_flags & (WRDSF_SHOWDBG | WRDSF_SHOWERR)); + | (wsp->ws_flags & (WRDSF_SHOWDBG | WRDSF_SHOWERR | WRDSF_OPTIONS)); return wordsplit_run (str, len, wss, flags, wsp->ws_lvl + 1); } @@ -168,12 +187,11 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, if (!(wsp->ws_flags & WRDSF_ERROR)) wsp->ws_error = _wsplt_error; - if (!(wsp->ws_flags & WRDSF_NOVAR) - && !(wsp->ws_flags & (WRDSF_ENV | WRDSF_GETVAR))) + if (!(wsp->ws_flags & WRDSF_NOVAR)) { - _wsplt_seterr (wsp, WRDSE_USAGE); - errno = EINVAL; - return wsp->ws_errno; + /* These will be initialized on first variable assignment */ + wsp->ws_envidx = wsp->ws_envsiz = 0; + wsp->ws_envbuf = NULL; } if (!(wsp->ws_flags & WRDSF_NOCMD)) @@ -214,6 +232,9 @@ wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, if (!(wsp->ws_flags & WRDSF_CLOSURE)) wsp->ws_closure = NULL; + if (!(wsp->ws_flags & WRDSF_OPTIONS)) + wsp->ws_options = 0; + wsp->ws_endp = 0; wordsplit_init0 (wsp); @@ -717,13 +738,14 @@ find_closing_paren (const char *str, size_t i, size_t len, size_t *poff, return 1; } -static const char * -wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len) +static int +wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len, + char const **ret) { size_t i; if (!(wsp->ws_flags & WRDSF_ENV)) - return NULL; + return WRDSE_UNDEF; if (wsp->ws_flags & WRDSF_ENV_KV) { @@ -732,14 +754,17 @@ wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len) { size_t elen = strlen (wsp->ws_env[i]); if (elen == len && memcmp (wsp->ws_env[i], name, elen) == 0) - return wsp->ws_env[i + 1]; + { + *ret = wsp->ws_env[i + 1]; + return WRDSE_OK; + } /* Skip the value. Break the loop if it is NULL. */ i++; if (wsp->ws_env[i] == NULL) break; } } - else + else if (wsp->ws_env) { /* Usual (A=B) environment. */ for (i = 0; wsp->ws_env[i]; i++) @@ -751,10 +776,117 @@ wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len) if (name[j] != var[j]) break; if (j == len && var[j] == '=') - return var + j + 1; + { + *ret = var + j + 1; + return WRDSE_OK; + } + } + } + return WRDSE_UNDEF; +} + +static int +wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen, + char *value) +{ + int n = (wsp->ws_flags & WRDSF_ENV_KV) ? 2 : 1; + char *v; + + if (wsp->ws_envidx + n >= wsp->ws_envsiz) + { + size_t sz; + char **newenv; + + if (!wsp->ws_envbuf) + { + if (wsp->ws_flags & WRDSF_ENV) + { + size_t i = 0, j; + + if (wsp->ws_env) + { + for (; wsp->ws_env[i]; i++) + ; + } + + sz = i + n + 1; + + newenv = calloc (sz, sizeof(newenv[0])); + if (!newenv) + return _wsplt_nomem (wsp); + + for (j = 0; j < i; j++) + { + newenv[j] = strdup (wsp->ws_env[j]); + if (!newenv[j]) + { + for (; j > 1; j--) + free (newenv[j-1]); + free (newenv[j-1]); + return _wsplt_nomem (wsp); + } + } + newenv[j] = NULL; + + wsp->ws_envbuf = newenv; + wsp->ws_envidx = i; + wsp->ws_envsiz = sz; + wsp->ws_env = (const char**) wsp->ws_envbuf; + } + else + { + newenv = calloc (WORDSPLIT_ENV_INIT, sizeof(newenv[0])); + if (!newenv) + return _wsplt_nomem (wsp); + wsp->ws_envbuf = newenv; + wsp->ws_envidx = 0; + wsp->ws_envsiz = WORDSPLIT_ENV_INIT; + wsp->ws_env = (const char**) wsp->ws_envbuf; + wsp->ws_flags |= WRDSF_ENV; + } + } + else + { + wsp->ws_envsiz *= 2; + newenv = realloc (wsp->ws_envbuf, + wsp->ws_envsiz * sizeof (wsp->ws_envbuf[0])); + if (!newenv) + return _wsplt_nomem (wsp); + wsp->ws_envbuf = newenv; + wsp->ws_env = (const char**) wsp->ws_envbuf; } } - return NULL; + + if (wsp->ws_flags & WRDSF_ENV_KV) + { + /* A key-value pair environment */ + char *p = malloc (namelen + 1); + if (!p) + return _wsplt_nomem (wsp); + memcpy (p, name, namelen); + p[namelen] = 0; + + v = strdup (value); + if (!v) + { + free (p); + return _wsplt_nomem (wsp); + } + wsp->ws_env[wsp->ws_envidx++] = p; + wsp->ws_env[wsp->ws_envidx++] = v; + } + else + { + v = malloc (namelen + strlen(value) + 2); + if (!v) + return _wsplt_nomem (wsp); + memcpy (v, name, namelen); + v[namelen++] = '='; + strcpy(v + namelen, value); + wsp->ws_env[wsp->ws_envidx++] = v; + } + wsp->ws_env[wsp->ws_envidx++] = NULL; + return WRDSE_OK; } static int @@ -767,7 +899,9 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, const char *vptr; struct wordsplit_node *newnode; const char *start = str - 1; - + int rc; + struct wordsplit ws; + if (ISVARBEG (str[0])) { for (i = 1; i < len; i++) @@ -780,22 +914,35 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, str++; len--; for (i = 1; i < len; i++) - if (str[i] == '}' || str[i] == ':') - break; - if (str[i] == ':') - { - size_t j; - - defstr = str + i + 1; - if (find_closing_paren (str, i + 1, len, &j, "{}")) - return _wsplt_seterr (wsp, WRDSE_CBRACE); - *pend = str + j; - } - else if (str[i] == '}') { - *pend = str + i; + if (str[i] == ':') + { + size_t j; + + defstr = str + i + 1; + if (find_closing_paren (str, i + 1, len, &j, "{}")) + return _wsplt_seterr (wsp, WRDSE_CBRACE); + *pend = str + j; + break; + } + else if (str[i] == '}') + { + defstr = NULL; + *pend = str + i; + break; + } + else if (strchr ("-+?=", str[i])) + { + size_t j; + + defstr = str + i; + if (find_closing_paren (str, i, len, &j, "{}")) + return _wsplt_seterr (wsp, WRDSE_CBRACE); + *pend = str + j; + break; + } } - else + if (i == len) return _wsplt_seterr (wsp, WRDSE_CBRACE); } else @@ -820,64 +967,99 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, i - its length defstr - default replacement str */ - vptr = wordsplit_find_env (wsp, str, i); - if (vptr) + if (defstr && strchr("-+?=", defstr[0]) == 0) { - value = strdup (vptr); - if (!value) - return _wsplt_nomem (wsp); + rc = WRDSE_UNDEF; + defstr = NULL; } - else if (wsp->ws_flags & WRDSF_GETVAR) + else { - int rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure); - switch (rc) + rc = wordsplit_find_env (wsp, str, i, &vptr); + if (rc == WRDSE_OK) { - case WRDSE_OK: - break; - - case WRDSE_NOSPACE: - return _wsplt_nomem (wsp); - - case WRDSE_UNDEF: - value = NULL; - break; + value = strdup (vptr); + if (!value) + rc = WRDSE_NOSPACE; + } + else if (wsp->ws_flags & WRDSF_GETVAR) + rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure); + else + rc = WRDSE_UNDEF; - case WRDSE_USERERR: - if (wsp->ws_errno == WRDSE_USERERR) - free (wsp->ws_usererr); - wsp->ws_usererr = value; - /* fall through */ - default: - _wsplt_seterr (wsp, rc); - return 1; + if (rc == WRDSE_OK && value[0] == 0 && defstr && defstr[-1] == ':') + { + free (value); + rc = WRDSE_UNDEF; } } - else - value = NULL; - if (!value) + switch (rc) { + case WRDSE_OK: + if (defstr && *defstr == '+') + { + size_t size = *pend - ++defstr; + + rc = _wsplt_subsplit (wsp, &ws, defstr, size, + WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE | + (wsp->ws_flags & + (WRDSF_NOVAR | WRDSF_NOCMD))); + if (rc) + return rc; + free (value); + value = ws.ws_wordv[0]; + ws.ws_wordv[0] = NULL; + wordsplit_free (&ws); + } + break; + + case WRDSE_UNDEF: if (defstr) { size_t size; - if (*defstr == '-') + if (*defstr == '-' || *defstr == '=') { size = *pend - ++defstr; - value = malloc (size + 1); - if (!value) - return _wsplt_nomem (wsp); - memcpy (value, defstr, size); - value[size] = 0; + + rc = _wsplt_subsplit (wsp, &ws, defstr, size, + WRDSF_NOSPLIT | WRDSF_WS | WRDSF_QUOTE | + (wsp->ws_flags & + (WRDSF_NOVAR | WRDSF_NOCMD))); + if (rc) + return rc; + + value = ws.ws_wordv[0]; + ws.ws_wordv[0] = NULL; + wordsplit_free (&ws); + + if (defstr[-1] == '=') + wsplt_assign_var (wsp, str, i, value); } - else if (*defstr == '?') + else { - size = *pend - ++defstr; - if (size == 0) - wsp->ws_error (_("%.*s: variable null or not set"), - (int) i, str); - else - wsp->ws_error ("%.*s: %.*s", - (int) i, str, (int) size, defstr); + if (*defstr == '?') + { + size = *pend - ++defstr; + if (size == 0) + wsp->ws_error (_("%.*s: variable null or not set"), + (int) i, str); + else + { + rc = _wsplt_subsplit (wsp, &ws, defstr, size, + WRDSF_NOSPLIT | WRDSF_WS | + WRDSF_QUOTE | + (wsp->ws_flags & + (WRDSF_NOVAR | WRDSF_NOCMD))); + if (rc == 0) + wsp->ws_error ("%.*s: %s", + (int) i, str, ws.ws_wordv[0]); + else + wsp->ws_error (_("%.*s: %.*s"), + (int) i, str, (int) size, defstr); + wordsplit_free (&ws); + } + } + value = NULL; } } else if (wsp->ws_flags & WRDSF_UNDEF) @@ -899,18 +1081,21 @@ expvar (struct wordsplit *wsp, const char *str, size_t len, return _wsplt_nomem (wsp); } } + break; + + case WRDSE_NOSPACE: + return _wsplt_nomem (wsp); + + case WRDSE_USERERR: + if (wsp->ws_errno == WRDSE_USERERR) + free (wsp->ws_usererr); + wsp->ws_usererr = value; + /* fall through */ + default: + _wsplt_seterr (wsp, rc); + return 1; } - else if (defstr && *defstr == '+') - { - size_t size = *pend - ++defstr; - free (value); - value = malloc (size + 1); - if (!value) - return _wsplt_nomem (wsp); - memcpy (value, defstr, size); - value[size] = 0; - } - + if (value) { if (flg & _WSNF_QUOTE) @@ -1111,7 +1296,7 @@ expcmd (struct wordsplit *wsp, const char *str, size_t len, } *pend = str + j; - if (wsp->ws_flags & WRDSF_ARGV) + if (wsp->ws_options & WRDSO_ARGV) { struct wordsplit ws; @@ -2034,6 +2219,23 @@ wordsplit_free_words (struct wordsplit *ws) } void +wordsplit_free_envbuf (struct wordsplit *ws) +{ + if (ws->ws_flags & WRDSF_NOCMD) + return; + if (ws->ws_envbuf) + { + size_t i; + + for (i = 0; ws->ws_envbuf[i]; i++) + free (ws->ws_envbuf[i]); + free (ws->ws_envbuf); + ws->ws_envidx = ws->ws_envsiz = 0; + ws->ws_envbuf = NULL; + } +} + +void wordsplit_clearerr (struct wordsplit *ws) { if (ws->ws_errno == WRDSE_USERERR) @@ -2048,6 +2250,7 @@ wordsplit_free (struct wordsplit *ws) wordsplit_free_words (ws); free (ws->ws_wordv); ws->ws_wordv = NULL; + wordsplit_free_envbuf (ws); } const char *_wordsplit_errstr[] = { |