home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / setenv < prev    next >
Text File  |  1989-03-07  |  7KB  |  345 lines

  1. Newsgroups: comp.sources.misc
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Subject: v06i056: setenv.c - a sorted environment package
  4. Message-Id:  <8902222357.aa04304@solo9.cs.vu.nl>
  5. Reply-To: Maarten Litmaath <maart@cs.vu.nl>
  6.  
  7. Posting-number: Volume 6, Issue 56
  8. Submitted-by: Maarten Litmaath <maart@cs.vu.nl>
  9. Archive-name: setenv
  10.  
  11. setenv() is better than putenv() in 3 ways:
  12.  
  13.     1) the call is setenv(var, value), which is both easier and more
  14.        natural than putenv(string)
  15.        compare
  16.         setenv("HOME", home);
  17.        with
  18.         strcpy(buf, "HOME=");
  19.         strcat(buf, home);
  20.         putenv(buf);
  21.  
  22.     2) it isn't an error to invoke setenv() with a local (automatic)
  23.        variable, because setenv() uses a malloc() + copy scheme (it needn't
  24.        be blistering fast, you know)
  25.  
  26.     3) it keeps the environment sorted, both for its own purposes and as a
  27.        service to the user
  28.  
  29. Regards & thanks for your attention,
  30.                     Maarten Litmaath @ VU Amsterdam:
  31.                     maart@cs.vu.nl, mcvax!botter!maart
  32.  
  33. : This is a shar archive.  Extract with sh, not csh.
  34. : This archive ends with exit, so do not worry about trailing junk.
  35. : --------------------------- cut here --------------------------
  36. PATH=/bin:/usr/bin:/usr/ucb
  37. echo Extracting 'setenv.c'
  38. sed 's/^X//' > 'setenv.c' << '+ END-OF-FILE ''setenv.c'
  39. Xstatic    char    id[] = "@(#)setenv.c 2.1 89/02/22 Maarten Litmaath";
  40. X
  41. X/*
  42. X * setenv.c
  43. X *
  44. X * Sorted environment package.
  45. X *
  46. X * char *setenv(char *var, char *value);
  47. X * Returns a pointer to the new "var=value" string if `value' has been
  48. X * assigned to `var', (char *) NULL if the number of environment variables
  49. X * exceeds MAX_ENV, or `var' is a NULL pointer or a malloc error occurred.
  50. X * If `value' is a NULL pointer, the empty string is assigned to `var'.
  51. X *
  52. X * int unsetenv(char *var);
  53. X * If `var' is the NULL pointer, the complete environment is unset.
  54. X * Returns -1 if the initial number of environment variables exceeds MAX_ENV
  55. X * or a malloc error occurred, else 0.
  56. X *
  57. X * int _envc;
  58. X * The current number of environment variables.
  59. X */
  60. X
  61. X#include    "setenv.h"
  62. X#include    <stdio.h>
  63. X
  64. Xstatic    char    *envbuf[MAX_ENV] = { 0 };
  65. Xstatic    int    initialized = 0, initenv(), envsearch();
  66. Xint    _envc = 0;
  67. Xextern    void    free();
  68. X
  69. X
  70. Xchar    *setenv(var, value)
  71. Xchar    *var, *value;
  72. X{
  73. X    extern    char    *malloc();
  74. X    char    **env, *buf;
  75. X    int    n;
  76. X
  77. X
  78. X    if (!initialized && initenv() == -1)
  79. X        return NULL;
  80. X
  81. X    if (!var)
  82. X        return NULL;
  83. X
  84. X    if (!value)
  85. X        value = "";
  86. X
  87. X    n = strlen(var);
  88. X
  89. X    if (!(buf = malloc(n + strlen(value) + 2)))
  90. X        return NULL;
  91. X
  92. X    (void) sprintf(buf, "%s=%s", var, value);
  93. X
  94. X    if (envsearch(var, n, &env) == 0) {
  95. X        free(*env);            /* unsetenv old value */
  96. X        *env = buf;            /* setenv new value */
  97. X    } else
  98. X        if (_envc == MAX_ENV)
  99. X            return NULL;
  100. X    else
  101. X        if (env == envbuf + _envc++) {
  102. X            *env++ = buf;
  103. X            *env = 0;
  104. X        }
  105. X    else {                    /* *env > var */
  106. X        register char    **p, **q;
  107. X
  108. X
  109. X        p = envbuf + _envc;
  110. X        q = p++;
  111. X        while (q > env)
  112. X            *--p = *--q;        /* shift down */
  113. X        *env = buf;            /* insert new var */
  114. X    }
  115. X
  116. X    return buf;
  117. X}
  118. X
  119. X
  120. Xint    unsetenv(var)
  121. Xchar    *var;
  122. X{
  123. X    register char    **p, **q;
  124. X    char    **env;
  125. X
  126. X
  127. X    if (!var)
  128. X        if (!initialized) {
  129. X            environ = envbuf;
  130. X            return 0;
  131. X        } else {
  132. X            for (p = envbuf; *p; )
  133. X                free(*p++);
  134. X            *envbuf = 0;
  135. X            _envc = 0;
  136. X            return 0;
  137. X        }
  138. X
  139. X    if (!initialized && initenv() == -1)
  140. X        return -1;
  141. X
  142. X    if (envsearch(var, strlen(var), &env) == 1)
  143. X        return 0;
  144. X
  145. X    free(*env);            /* unsetenv var */
  146. X
  147. X    p = env++;
  148. X    q = env;
  149. X    while (*p++ = *q++)        /* shift up rest of environment */
  150. X        ;
  151. X    --_envc;
  152. X
  153. X    return 0;
  154. X}
  155. X
  156. X
  157. X/*
  158. X * int initenv();
  159. X * Copy environment to private area, sort the copy, set environ to copy,
  160. X * initialize _envc.
  161. X * Return -1 if the environment exceeds MAX_ENV or a malloc error occurred,
  162. X * else 0.
  163. X */
  164. X
  165. Xstatic    int    initenv()
  166. X{
  167. X    register char    **p = environ, **env = envbuf;
  168. X    extern    char    *malloc(), *strcpy();
  169. X    extern    void    qsort();
  170. X    static    int    error = 0;
  171. X    int    istrcmp();
  172. X
  173. X
  174. X    if (error == -1)
  175. X        return -1;
  176. X
  177. X    if (p)
  178. X        while (*p && p < environ + MAX_ENV)
  179. X            if (!(*env = malloc(strlen(*p) + 1)))
  180. X                return error = -1;
  181. X            else
  182. X                (void) strcpy(*env++, *p++);
  183. X
  184. X    if (p >= environ + MAX_ENV)
  185. X        return error = -1;
  186. X
  187. X    *env = 0;
  188. X    _envc = env - envbuf;
  189. X    qsort((char *) envbuf, _envc, sizeof *envbuf, istrcmp);
  190. X    environ = envbuf;
  191. X    initialized = 1;
  192. X    return 0;
  193. X}
  194. X
  195. X
  196. X/*
  197. X * int envsearch(char *var, int n, char ***pos);
  198. X * Binarily search environment for `var', whose length is `n'.
  199. X * If it is present, `*pos' is set to the address of `var' in the environment
  200. X * and 0 is returned, else `*pos' is set to the address of the first variable
  201. X * lexicographically greater than `var', or to the end of the environment,
  202. X * and 1 is returned.
  203. X */
  204. X
  205. Xstatic    int    envsearch(var, n, pos)
  206. Xregister char    *var;
  207. Xregister int    n;
  208. Xchar    ***pos;
  209. X{
  210. X    register char    **env, **first = envbuf, **last = envbuf + _envc;
  211. X    register int    m;
  212. X    extern    int    strncmp();
  213. X
  214. X
  215. X    while (first < last) {
  216. X        env = first + ((last - first) >> 1);
  217. X        if ((m = strncmp(*env, var, n)) < 0) {
  218. X            first = env + 1;
  219. X            continue;
  220. X        }
  221. X        if (m > 0) {
  222. X            last = env;
  223. X            continue;
  224. X        }
  225. X        if ((m = (*env)[n] - '=') == 0) {
  226. X            *pos = env;
  227. X            return 0;
  228. X        }
  229. X        if (m < 0) {
  230. X            first = env + 1;
  231. X            continue;
  232. X        }
  233. X        last = env;
  234. X    }
  235. X
  236. X    *pos = last;
  237. X    return 1;
  238. X}
  239. X
  240. X
  241. Xstatic    int    istrcmp(p, q)            /* indirect strcmp */
  242. Xchar    **p, **q;
  243. X{
  244. X    register char    *s1 = *p, *s2 = *q;
  245. X
  246. X    while (*s1 == *s2++)
  247. X        if (!*s1++)
  248. X            return 0;
  249. X    return *s1 - *--s2;
  250. X}
  251. X
  252. X
  253. X#ifdef    STANDALONE
  254. X
  255. Xmain(argc)
  256. Xint    argc;
  257. X{
  258. X    void    set(), unset(), printenv();
  259. X
  260. X
  261. X    printenv();
  262. X
  263. X    if (argc > 1)
  264. X        unset((char *) 0);
  265. X
  266. X    unset("SHELL");
  267. X    unset("PATH");
  268. X    set("SHELL", "/foo/bar/baz");
  269. X    set("FOO", "BAR");
  270. X    unset("FOOO");
  271. X    unset("FO");
  272. X    unset((char *) 0);
  273. X    set("ZORK", (char *) 0);
  274. X    set("TMP", "/tmp");
  275. X}
  276. X
  277. X
  278. Xvoid    set(p, q)
  279. Xchar    *p, *q;
  280. X{
  281. X    void    printenv();
  282. X
  283. X
  284. X    printf("%s -> %s\n\n", p ? p : "(null)", (q = setenv(p, q)) ? q : "?");
  285. X    printenv();
  286. X}
  287. X
  288. X
  289. Xvoid    unset(p)
  290. Xchar    *p;
  291. X{
  292. X    void    printenv();
  293. X
  294. X
  295. X    printf("%s: %d\n\n", p ? p : "(null)", unsetenv(p));
  296. X    printenv();
  297. X}
  298. X
  299. X
  300. Xvoid    printenv()
  301. X{
  302. X    register char    **env;
  303. X
  304. X
  305. X    for (env = environ; *env; ++env)
  306. X        printf("%s\n", *env);
  307. X    printf("\n_envc=%d\n\n", _envc);
  308. X}
  309. X
  310. X#endif    STANDALONE
  311. + END-OF-FILE setenv.c
  312. chmod 'u=rw,g=r,o=r' 'setenv.c'
  313. set `wc -c 'setenv.c'`
  314. count=$1
  315. case $count in
  316. 4740)    :;;
  317. *)    echo 'Bad character count in ''setenv.c' >&2
  318.         echo 'Count should be 4740' >&2
  319. esac
  320. echo Extracting 'setenv.h'
  321. sed 's/^X//' > 'setenv.h' << '+ END-OF-FILE ''setenv.h'
  322. X/*
  323. X * setenv.h
  324. X */
  325. X
  326. X#ifndef    SETENV_H
  327. X#define        SETENV_H
  328. X
  329. X#define        MAX_ENV        256
  330. X
  331. Xextern    char    **environ, *setenv();
  332. Xextern    int    unsetenv(), _envc;
  333. X
  334. X#endif    !SETENV_H
  335. + END-OF-FILE setenv.h
  336. chmod 'u=rw,g=r,o=r' 'setenv.h'
  337. set `wc -c 'setenv.h'`
  338. count=$1
  339. case $count in
  340. 161)    :;;
  341. *)    echo 'Bad character count in ''setenv.h' >&2
  342.         echo 'Count should be 161' >&2
  343. esac
  344. exit 0
  345.