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