1 /*
2  * From: TCP Wrapper.
3  *
4  * Many systems have putenv() but no setenv(). Other systems have setenv() but
5  * no putenv() (MIPS). Still other systems have neither (NeXT). This is a
6  * re-implementation that hopefully ends all problems.
7  *
8  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
9  */
10#include "sys_defs.h"
11
12#ifdef MISSING_SETENV_PUTENV
13
14#include <stdio.h>
15#include <string.h>
16#include <stdlib.h>
17
18extern char **environ;
19
20static int addenv(char *);		/* append entry to environment */
21static int allocated = 0;		/* environ is, or is not, allocated */
22
23#define DO_CLOBBER      1
24
25/* namelength - determine length of name in "name=whatever" */
26
27static ssize_t namelength(const char *name)
28{
29    char   *equal;
30
31    equal = strchr(name, '=');
32    return ((equal == 0) ? strlen(name) : (equal - name));
33}
34
35/* findenv - given name, locate name=value */
36
37static char **findenv(const char *name, ssize_t len)
38{
39    char  **envp;
40
41    for (envp = environ; envp && *envp; envp++)
42	if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
43	    return (envp);
44    return (0);
45}
46
47#if 0
48
49/* getenv - given name, locate value */
50
51char   *getenv(const char *name)
52{
53    ssize_t len = namelength(name);
54    char  **envp = findenv(name, len);
55
56    return (envp ? *envp + len + 1 : 0);
57}
58
59/* putenv - update or append environment (name,value) pair */
60
61int     putenv(const char *nameval)
62{
63    char   *equal = strchr(nameval, '=');
64    char   *value = (equal ? equal : "");
65
66    return (setenv(nameval, value, DO_CLOBBER));
67}
68
69/* unsetenv - remove variable from environment */
70
71void    unsetenv(const char *name)
72{
73    char  **envp;
74
75    while ((envp = findenv(name, namelength(name))) != 0)
76	while (envp[0] = envp[1])
77	    envp++;
78}
79
80#endif
81
82/* setenv - update or append environment (name,value) pair */
83
84int     setenv(const char *name, const char *value, int clobber)
85{
86    char   *destination;
87    char  **envp;
88    ssize_t l_name;			/* length of name part */
89    unsigned int l_nameval;		/* length of name=value */
90
91    /* Permit name= and =value. */
92
93    l_name = namelength(name);
94    envp = findenv(name, l_name);
95    if (envp != 0 && clobber == 0)
96	return (0);
97    if (*value == '=')
98	value++;
99    l_nameval = l_name + strlen(value) + 1;
100
101    /*
102     * Use available memory if the old value is long enough. Never free an
103     * old name=value entry because it may not be allocated.
104     */
105
106    destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
107	*envp : malloc(l_nameval + 1);
108    if (destination == 0)
109	return (-1);
110    strncpy(destination, name, l_name);
111    destination[l_name] = '=';
112    strlcpy(destination + l_name + 1, value, l_nameval - l_name); /* APPLE */
113    return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
114}
115
116/* cmalloc - malloc and copy block of memory */
117
118static char *cmalloc(ssize_t new_len, char *old, ssize_t old_len)
119{
120    char   *new = malloc(new_len);
121
122    if (new != 0)
123	memcpy(new, old, old_len);
124    return (new);
125}
126
127/* addenv - append environment entry */
128
129static int addenv(char *nameval)
130{
131    char  **envp;
132    ssize_t n_used;			/* number of environment entries */
133    ssize_t l_used;			/* bytes used excl. terminator */
134    ssize_t l_need;			/* bytes needed incl. terminator */
135
136    for (envp = environ; envp && *envp; envp++)
137	 /* void */ ;
138    n_used = envp - environ;
139    l_used = n_used * sizeof(*envp);
140    l_need = l_used + 2 * sizeof(*envp);
141
142    envp = allocated ?
143	(char **) realloc((char *) environ, l_need) :
144	(char **) cmalloc(l_need, (char *) environ, l_used);
145    if (envp == 0) {
146	return (-1);
147    } else {
148	allocated = 1;
149	environ = envp;
150	environ[n_used++] = nameval;		/* add new entry */
151	environ[n_used] = 0;			/* terminate list */
152	return (0);
153    }
154}
155
156#endif
157