allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (03/08/89)
Posting-number: Volume 6, Issue 56 Submitted-by: Maarten Litmaath <maart@cs.vu.nl> Archive-name: setenv setenv() is better than putenv() in 3 ways: 1) the call is setenv(var, value), which is both easier and more natural than putenv(string) compare setenv("HOME", home); with strcpy(buf, "HOME="); strcat(buf, home); putenv(buf); 2) it isn't an error to invoke setenv() with a local (automatic) variable, because setenv() uses a malloc() + copy scheme (it needn't be blistering fast, you know) 3) it keeps the environment sorted, both for its own purposes and as a service to the user Regards & thanks for your attention, Maarten Litmaath @ VU Amsterdam: maart@cs.vu.nl, mcvax!botter!maart : This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. : --------------------------- cut here -------------------------- PATH=/bin:/usr/bin:/usr/ucb echo Extracting 'setenv.c' sed 's/^X//' > 'setenv.c' << '+ END-OF-FILE ''setenv.c' Xstatic char id[] = "@(#)setenv.c 2.1 89/02/22 Maarten Litmaath"; X X/* X * setenv.c X * X * Sorted environment package. X * X * char *setenv(char *var, char *value); X * Returns a pointer to the new "var=value" string if `value' has been X * assigned to `var', (char *) NULL if the number of environment variables X * exceeds MAX_ENV, or `var' is a NULL pointer or a malloc error occurred. X * If `value' is a NULL pointer, the empty string is assigned to `var'. X * X * int unsetenv(char *var); X * If `var' is the NULL pointer, the complete environment is unset. X * Returns -1 if the initial number of environment variables exceeds MAX_ENV X * or a malloc error occurred, else 0. X * X * int _envc; X * The current number of environment variables. X */ X X#include "setenv.h" X#include <stdio.h> X Xstatic char *envbuf[MAX_ENV] = { 0 }; Xstatic int initialized = 0, initenv(), envsearch(); Xint _envc = 0; Xextern void free(); X X Xchar *setenv(var, value) Xchar *var, *value; X{ X extern char *malloc(); X char **env, *buf; X int n; X X X if (!initialized && initenv() == -1) X return NULL; X X if (!var) X return NULL; X X if (!value) X value = ""; X X n = strlen(var); X X if (!(buf = malloc(n + strlen(value) + 2))) X return NULL; X X (void) sprintf(buf, "%s=%s", var, value); X X if (envsearch(var, n, &env) == 0) { X free(*env); /* unsetenv old value */ X *env = buf; /* setenv new value */ X } else X if (_envc == MAX_ENV) X return NULL; X else X if (env == envbuf + _envc++) { X *env++ = buf; X *env = 0; X } X else { /* *env > var */ X register char **p, **q; X X X p = envbuf + _envc; X q = p++; X while (q > env) X *--p = *--q; /* shift down */ X *env = buf; /* insert new var */ X } X X return buf; X} X X Xint unsetenv(var) Xchar *var; X{ X register char **p, **q; X char **env; X X X if (!var) X if (!initialized) { X environ = envbuf; X return 0; X } else { X for (p = envbuf; *p; ) X free(*p++); X *envbuf = 0; X _envc = 0; X return 0; X } X X if (!initialized && initenv() == -1) X return -1; X X if (envsearch(var, strlen(var), &env) == 1) X return 0; X X free(*env); /* unsetenv var */ X X p = env++; X q = env; X while (*p++ = *q++) /* shift up rest of environment */ X ; X --_envc; X X return 0; X} X X X/* X * int initenv(); X * Copy environment to private area, sort the copy, set environ to copy, X * initialize _envc. X * Return -1 if the environment exceeds MAX_ENV or a malloc error occurred, X * else 0. X */ X Xstatic int initenv() X{ X register char **p = environ, **env = envbuf; X extern char *malloc(), *strcpy(); X extern void qsort(); X static int error = 0; X int istrcmp(); X X X if (error == -1) X return -1; X X if (p) X while (*p && p < environ + MAX_ENV) X if (!(*env = malloc(strlen(*p) + 1))) X return error = -1; X else X (void) strcpy(*env++, *p++); X X if (p >= environ + MAX_ENV) X return error = -1; X X *env = 0; X _envc = env - envbuf; X qsort((char *) envbuf, _envc, sizeof *envbuf, istrcmp); X environ = envbuf; X initialized = 1; X return 0; X} X X X/* X * int envsearch(char *var, int n, char ***pos); X * Binarily search environment for `var', whose length is `n'. X * If it is present, `*pos' is set to the address of `var' in the environment X * and 0 is returned, else `*pos' is set to the address of the first variable X * lexicographically greater than `var', or to the end of the environment, X * and 1 is returned. X */ X Xstatic int envsearch(var, n, pos) Xregister char *var; Xregister int n; Xchar ***pos; X{ X register char **env, **first = envbuf, **last = envbuf + _envc; X register int m; X extern int strncmp(); X X X while (first < last) { X env = first + ((last - first) >> 1); X if ((m = strncmp(*env, var, n)) < 0) { X first = env + 1; X continue; X } X if (m > 0) { X last = env; X continue; X } X if ((m = (*env)[n] - '=') == 0) { X *pos = env; X return 0; X } X if (m < 0) { X first = env + 1; X continue; X } X last = env; X } X X *pos = last; X return 1; X} X X Xstatic int istrcmp(p, q) /* indirect strcmp */ Xchar **p, **q; X{ X register char *s1 = *p, *s2 = *q; X X while (*s1 == *s2++) X if (!*s1++) X return 0; X return *s1 - *--s2; X} X X X#ifdef STANDALONE X Xmain(argc) Xint argc; X{ X void set(), unset(), printenv(); X X X printenv(); X X if (argc > 1) X unset((char *) 0); X X unset("SHELL"); X unset("PATH"); X set("SHELL", "/foo/bar/baz"); X set("FOO", "BAR"); X unset("FOOO"); X unset("FO"); X unset((char *) 0); X set("ZORK", (char *) 0); X set("TMP", "/tmp"); X} X X Xvoid set(p, q) Xchar *p, *q; X{ X void printenv(); X X X printf("%s -> %s\n\n", p ? p : "(null)", (q = setenv(p, q)) ? q : "?"); X printenv(); X} X X Xvoid unset(p) Xchar *p; X{ X void printenv(); X X X printf("%s: %d\n\n", p ? p : "(null)", unsetenv(p)); X printenv(); X} X X Xvoid printenv() X{ X register char **env; X X X for (env = environ; *env; ++env) X printf("%s\n", *env); X printf("\n_envc=%d\n\n", _envc); X} X X#endif STANDALONE + END-OF-FILE setenv.c chmod 'u=rw,g=r,o=r' 'setenv.c' set `wc -c 'setenv.c'` count=$1 case $count in 4740) :;; *) echo 'Bad character count in ''setenv.c' >&2 echo 'Count should be 4740' >&2 esac echo Extracting 'setenv.h' sed 's/^X//' > 'setenv.h' << '+ END-OF-FILE ''setenv.h' X/* X * setenv.h X */ X X#ifndef SETENV_H X#define SETENV_H X X#define MAX_ENV 256 X Xextern char **environ, *setenv(); Xextern int unsetenv(), _envc; X X#endif !SETENV_H + END-OF-FILE setenv.h chmod 'u=rw,g=r,o=r' 'setenv.h' set `wc -c 'setenv.h'` count=$1 case $count in 161) :;; *) echo 'Bad character count in ''setenv.h' >&2 echo 'Count should be 161' >&2 esac exit 0