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 */ 225