Configurable order of lookups if both WRDSF_ENV and WRDSF_GETVAR are set

* src/wordsplit.h (WRDSO_GETVARPREF): New option.
* src/wordsplit.c (wordsplit_find_env): Rewrite as wsplt_env_lookup
wsplt_env_getvar): New function.
(expvar): Select preference of wsplt_env_lookup vs. wsplt_env_getvar
depending on the value if WRDSO_GETVARPREF option.
This commit is contained in:
Sergey Poznyakoff 2019-06-13 14:20:20 +03:00
parent 188bbb90d6
commit f00da62cde
2 changed files with 46 additions and 27 deletions

View file

@ -216,7 +216,8 @@ struct wordsplit
#define WRDSO_FAILGLOB 0x00000002
/* Allow a leading period to be matched by metacharacters. */
#define WRDSO_DOTGLOB 0x00000004
/* Unused value: 0x00000008 */
/* Prefer ws_getvar over lookup in ws_env, if both are supplied */
#define WRDSO_GETVARPREF 0x00000008
/* Keep backslash in unrecognized escape sequences in words */
#define WRDSO_BSKEEP_WORD 0x00000010
/* Handle octal escapes in words */

View file

@ -1034,15 +1034,13 @@ find_closing_paren (const char *str, size_t i, size_t len, size_t *poff,
return 1;
}
static int
wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len,
char const **ret)
static char const *
wsplt_env_find (struct wordsplit *wsp, const char *name, size_t len)
{
size_t i;
if (!(wsp->ws_flags & WRDSF_ENV))
return WRDSE_UNDEF;
if (!wsp->ws_env)
return NULL;
if (wsp->ws_flags & WRDSF_ENV_KV)
{
/* A key-value pair environment */
@ -1050,17 +1048,14 @@ 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)
{
*ret = wsp->ws_env[i + 1];
return WRDSE_OK;
}
return wsp->ws_env[i + 1];
/* Skip the value. Break the loop if it is NULL. */
i++;
if (wsp->ws_env[i] == NULL)
break;
}
}
else if (wsp->ws_env)
else
{
/* Usual (A=B) environment. */
for (i = 0; wsp->ws_env[i]; i++)
@ -1072,15 +1067,38 @@ wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len,
if (name[j] != var[j])
break;
if (j == len && var[j] == '=')
{
*ret = var + j + 1;
return WRDSE_OK;
}
return var + j + 1;
}
}
return NULL;
}
static int
wsplt_env_lookup (struct wordsplit *wsp, const char *name, size_t len,
char **ret)
{
if (wsp->ws_flags & WRDSF_ENV)
{
char const *val = wsplt_env_find (wsp, name, len);
if (val)
{
char *retval = strdup (val);
if (!retval)
return WRDSE_NOSPACE;
*ret = retval;
return WRDSE_OK;
}
}
return WRDSE_UNDEF;
}
static int
wsplt_env_getvar (struct wordsplit *wsp, const char *name, size_t len,
char **ret)
{
return wsp->ws_getvar (ret, name, len, wsp->ws_closure);
}
static int
wsplt_assign_var (struct wordsplit *wsp, const char *name, size_t namelen,
char const *value)
@ -1356,7 +1374,6 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
size_t i = 0;
const char *defstr = NULL;
char *value;
const char *vptr;
struct wordsplit_node *newnode;
const char *start = str - 1;
int rc;
@ -1497,22 +1514,23 @@ expvar (struct wordsplit *wsp, const char *str, size_t len,
}
else
{
rc = wordsplit_find_env (wsp, str, i, &vptr);
if (rc == WRDSE_OK)
if (wsp->ws_flags & WRDSF_GETVAR)
{
if (vptr)
if (wsp->ws_options & WRDSO_GETVARPREF)
{
value = strdup (vptr);
if (!value)
rc = WRDSE_NOSPACE;
rc = wsplt_env_getvar (wsp, str, i, &value);
if (rc == WRDSE_UNDEF)
rc = wsplt_env_lookup (wsp, str, i, &value);
}
else
rc = WRDSE_UNDEF;
{
rc = wsplt_env_lookup (wsp, str, i, &value);
if (rc == WRDSE_UNDEF)
rc = wsplt_env_getvar (wsp, str, i, &value);
}
}
else if (wsp->ws_flags & WRDSF_GETVAR)
rc = wsp->ws_getvar (&value, str, i, wsp->ws_closure);
else
rc = WRDSE_UNDEF;
rc = wsplt_env_lookup (wsp, str, i, &value);
}
if (rc == WRDSE_OK