aboutsummaryrefslogtreecommitdiff
path: root/src/progman.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2016-08-20 09:23:48 +0300
committerSergey Poznyakoff <gray@gnu.org>2016-08-20 09:23:48 +0300
commitcee62ab20bf767c3a07562ad30c67126ea3bab32 (patch)
treef432c01460d9d820cf92de7a55b17109715cf12d /src/progman.c
parent6dd16ac66166ef62fcfc499c184a1b86ca82b227 (diff)
downloadpies-cee62ab20bf767c3a07562ad30c67126ea3bab32.tar.gz
pies-cee62ab20bf767c3a07562ad30c67126ea3bab32.tar.bz2
Fix environment modification code
Port fixes from GNU rush
Diffstat (limited to 'src/progman.c')
-rw-r--r--src/progman.c82
1 files changed, 57 insertions, 25 deletions
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;

Return to:

Send suggestions and report system problems to the System administrator.