Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / contrib / tcp_wrappers / environ.c
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
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
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
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
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
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
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
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
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
185 static void printenv()
186 {
187     char  **envp;
188
189     for (envp = environ; envp && *envp; envp++)
190         printf("%s\n", *envp);
191 }
192
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 */