1 /*
2 * Many systems have putenv() but no setenv(). Other systems have setenv()
3 * but no putenv() (MIPS). Still other systems have neither (NeXT). This is a
4 * re-implementation that hopefully ends all problems.
5 *
6 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
7 */
8
9 #ifndef lint
10 static char sccsid[] = "@(#) environ.c 1.2 94/03/23 16:09:46";
11 #endif
12
13 /* System libraries. */
14
15 extern char **environ;
16 extern char *strchr();
17 extern char *strcpy();
18 extern char *strncpy();
19 extern char *malloc();
20 extern char *realloc();
21 extern int strncmp();
22 extern void free();
23
24 #ifdef no_memcpy
25 #define memcpy(d,s,l) bcopy(s,d,l)
26 #else
27 extern char *memcpy();
28 #endif
29
30 /* Local stuff. */
31
32 static int addenv(); /* append entry to environment */
33
34 static int allocated = 0; /* environ is, or is not, allocated */
35
36 #define DO_CLOBBER 1
37
38 /* namelength - determine length of name in "name=whatever" */
39
namelength(name)40 static int namelength(name)
41 char *name;
42 {
43 char *equal;
44
45 equal = strchr(name, '=');
46 return ((equal == 0) ? strlen(name) : (equal - name));
47 }
48
49 /* findenv - given name, locate name=value */
50
findenv(name,len)51 static char **findenv(name, len)
52 char *name;
53 int len;
54 {
55 char **envp;
56
57 for (envp = environ; envp && *envp; envp++)
58 if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
59 return (envp);
60 return (0);
61 }
62
63 /* getenv - given name, locate value */
64
getenv(name)65 char *getenv(name)
66 char *name;
67 {
68 int len = namelength(name);
69 char **envp = findenv(name, len);
70
71 return (envp ? *envp + len + 1 : 0);
72 }
73
74 /* putenv - update or append environment (name,value) pair */
75
putenv(nameval)76 int putenv(nameval)
77 char *nameval;
78 {
79 char *equal = strchr(nameval, '=');
80 char *value = (equal ? equal : "");
81
82 return (setenv(nameval, value, DO_CLOBBER));
83 }
84
85 /* unsetenv - remove variable from environment */
86
unsetenv(name)87 void unsetenv(name)
88 char *name;
89 {
90 char **envp;
91
92 if ((envp = findenv(name, namelength(name))) != 0)
93 while (envp[0] = envp[1])
94 envp++;
95 }
96
97 /* setenv - update or append environment (name,value) pair */
98
setenv(name,value,clobber)99 int setenv(name, value, clobber)
100 char *name;
101 char *value;
102 int clobber;
103 {
104 char *destination;
105 char **envp;
106 int l_name; /* length of name part */
107 int l_nameval; /* length of name=value */
108
109 /* Permit name= and =value. */
110
111 l_name = namelength(name);
112 envp = findenv(name, l_name);
113 if (envp != 0 && clobber == 0)
114 return (0);
115 if (*value == '=')
116 value++;
117 l_nameval = l_name + strlen(value) + 1;
118
119 /*
120 * Use available memory if the old value is long enough. Never free an
121 * old name=value entry because it may not be allocated.
122 */
123
124 destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
125 *envp : malloc(l_nameval + 1);
126 if (destination == 0)
127 return (-1);
128 strncpy(destination, name, l_name);
129 destination[l_name] = '=';
130 strcpy(destination + l_name + 1, value);
131 return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
132 }
133
134 /* cmalloc - malloc and copy block of memory */
135
cmalloc(new_len,old,old_len)136 static char *cmalloc(new_len, old, old_len)
137 char *old;
138 int old_len;
139 {
140 char *new = malloc(new_len);
141
142 if (new != 0)
143 memcpy(new, old, old_len);
144 return (new);
145 }
146
147 /* addenv - append environment entry */
148
addenv(nameval)149 static int addenv(nameval)
150 char *nameval;
151 {
152 char **envp;
153 int n_used; /* number of environment entries */
154 int l_used; /* bytes used excl. terminator */
155 int l_need; /* bytes needed incl. terminator */
156
157 for (envp = environ; envp && *envp; envp++)
158 /* void */ ;
159 n_used = envp - environ;
160 l_used = n_used * sizeof(*envp);
161 l_need = l_used + 2 * sizeof(*envp);
162
163 envp = allocated ?
164 (char **) realloc((char *) environ, l_need) :
165 (char **) cmalloc(l_need, (char *) environ, l_used);
166 if (envp == 0) {
167 return (-1);
168 } else {
169 allocated = 1;
170 environ = envp;
171 environ[n_used++] = nameval; /* add new entry */
172 environ[n_used] = 0; /* terminate list */
173 return (0);
174 }
175 }
176
177 #ifdef TEST
178
179 /*
180 * Stand-alone program for test purposes.
181 */
182
183 /* printenv - display environment */
184
printenv()185 static void printenv()
186 {
187 char **envp;
188
189 for (envp = environ; envp && *envp; envp++)
190 printf("%s\n", *envp);
191 }
192
main(argc,argv)193 int main(argc, argv)
194 int argc;
195 char **argv;
196 {
197 char *cp;
198 int changed = 0;
199
200 if (argc < 2) {
201 printf("usage: %s name[=value]...\n", argv[0]);
202 return (1);
203 }
204 while (--argc && *++argv) {
205 if (argv[0][0] == '-') { /* unsetenv() test */
206 unsetenv(argv[0] + 1);
207 changed = 1;
208 } else if (strchr(argv[0], '=') == 0) { /* getenv() test */
209 cp = getenv(argv[0]);
210 printf("%s: %s\n", argv[0], cp ? cp : "not found");
211 } else { /* putenv() test */
212 if (putenv(argv[0])) {
213 perror("putenv");
214 return (1);
215 }
216 changed = 1;
217 }
218 }
219 if (changed)
220 printenv();
221 return (0);
222 }
223
224 #endif /* TEST */
225