From cee62ab20bf767c3a07562ad30c67126ea3bab32 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sat, 20 Aug 2016 09:23:48 +0300 Subject: Fix environment modification code Port fixes from GNU rush --- src/progman.c | 82 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/progman.c b/src/progman.c index fdb829a..43aff48 100644 --- a/src/progman.c +++ b/src/progman.c @@ -657,26 +657,48 @@ add_env (const char *name, const char *value) environ[i] = p; } -static char * -find_env (const char *name, int val) +/* Find variable NAME in environment ENV. + On success, store the index of the ENV slot in *IDX, + the offset of the value (position right past '=') in *VALOFF, and + return 0 (IDX and/or VALOFF can be NULL, if that info is not needed). + Return -1 if NAME was not found. */ +static int +find_env_pos (char **env, char *name, size_t *idx, size_t *valoff) { - if (environ) - { - int nlen = strcspn (name, "+="); - int i; + size_t nlen = strcspn (name, "+="); + size_t i; - for (i = 0; environ[i]; i++) + for (i = 0; env[i]; i++) + { + size_t elen = strcspn (env[i], "="); + if (elen == nlen && memcmp (name, env[i], nlen) == 0) { - size_t elen = strcspn (environ[i], "="); - if (elen == nlen && memcmp (name, environ[i], nlen) == 0) - return val ? environ[i] + elen + 1 : environ[i]; + if (idx) + *idx = i; + if (valoff) + *valoff = elen + 1; + return 0; } } - return NULL; + return -1; +} + +/* Find variable NAME in environment ENV. + On success, return pointer to the variable assignment (if VAL is 0), + or to the value (if VAL is 1). + Return NULL if NAME is not present in ENV. */ +static char * +find_env_ptr (char **env, char *name, int val) +{ + size_t i, j; + if (find_env_pos (env, name, &i, &j)) + return NULL; + return val ? env[i] + j : env[i]; } +/* Return 1 if ENV contains a matching unset statement for variable NAME. */ static int -locate_unset (char **env, const char *name) +var_is_unset (char **env, const char *name) { int i; int nlen = strcspn (name, "="); @@ -708,7 +730,7 @@ env_concat (const char *name, size_t namelen, const char *a, const char *b) { res = grecs_malloc (namelen + 1 + strlen (a) + strlen (b) + 1); strcpy (res + namelen + 1, a); - strcat (res, b); + strcat (res + namelen + 1, b); } else if (a) { @@ -737,7 +759,7 @@ environ_setup (char **hint) { char **old_env = environ; char **new_env; - size_t count, i, n; + size_t count, i, j, n; if (!hint) return; @@ -766,7 +788,7 @@ environ_setup (char **hint) if (old_env) for (i = 0; old_env[i]; i++) { - if (!locate_unset (hint, old_env[i])) + if (!var_is_unset (hint, old_env[i])) new_env[n++] = old_env[i]; } @@ -779,25 +801,35 @@ environ_setup (char **hint) /* Skip unset directives. */ continue; } + + /* Find the slot for the variable. Use next available + slot if there's no such variable in new_env */ + if (find_env_pos (new_env, hint[i], &j, NULL)) + j = n; + if ((p = strchr (hint[i], '='))) { if (p == hint[i]) continue; /* Ignore erroneous entry */ if (p[-1] == '+') - new_env[n++] = env_concat (hint[i], p - hint[i] - 1, - find_env(hint[i], 1), p + 1); + new_env[j] = env_concat (hint[i], p - hint[i] - 1, + find_env_ptr (environ, hint[i], 1), + p + 1); else if (p[1] == '+') - new_env[n++] = env_concat (hint[i], p - hint[i], - p + 2, find_env(hint[i], 1)); + new_env[j] = env_concat (hint[i], p - hint[i], + p + 2, + find_env_ptr (environ, hint[i], 1)); else - new_env[n++] = hint[i]; + new_env[j] = hint[i]; } + else if ((p = find_env_ptr (environ, hint[i], 0))) + new_env[j] = p; else - { - p = find_env (hint[i], 0); - if (p) - new_env[n++] = p; - } + continue; + + /* Adjust environment size */ + if (j == n) + ++n; } new_env[n] = NULL; -- cgit v1.2.1