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(char *name) 41 { 42 char *equal; 43 44 equal = strchr(name, '='); 45 return ((equal == 0) ? strlen(name) : (equal - name)); 46 } 47 48 /* findenv - given name, locate name=value */ 49 50 static char **findenv(char *name, int len) 51 { 52 char **envp; 53 54 for (envp = environ; envp && *envp; envp++) 55 if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=') 56 return (envp); 57 return (0); 58 } 59 60 /* getenv - given name, locate value */ 61 62 char *getenv(char *name) 63 { 64 int len = namelength(name); 65 char **envp = findenv(name, len); 66 67 return (envp ? *envp + len + 1 : 0); 68 } 69 70 /* putenv - update or append environment (name,value) pair */ 71 72 int putenv(char *nameval) 73 { 74 char *equal = strchr(nameval, '='); 75 char *value = (equal ? equal : ""); 76 77 return (setenv(nameval, value, DO_CLOBBER)); 78 } 79 80 /* unsetenv - remove variable from environment */ 81 82 void unsetenv(char *name) 83 { 84 char **envp; 85 86 if ((envp = findenv(name, namelength(name))) != 0) 87 while (envp[0] = envp[1]) 88 envp++; 89 } 90 91 /* setenv - update or append environment (name,value) pair */ 92 93 int setenv(char *name, char *value, int clobber) 94 { 95 char *destination; 96 char **envp; 97 int l_name; /* length of name part */ 98 int l_nameval; /* length of name=value */ 99 100 /* Permit name= and =value. */ 101 102 l_name = namelength(name); 103 envp = findenv(name, l_name); 104 if (envp != 0 && clobber == 0) 105 return (0); 106 if (*value == '=') 107 value++; 108 l_nameval = l_name + strlen(value) + 1; 109 110 /* 111 * Use available memory if the old value is long enough. Never free an 112 * old name=value entry because it may not be allocated. 113 */ 114 115 destination = (envp != 0 && strlen(*envp) >= l_nameval) ? 116 *envp : malloc(l_nameval + 1); 117 if (destination == 0) 118 return (-1); 119 strncpy(destination, name, l_name); 120 destination[l_name] = '='; 121 strcpy(destination + l_name + 1, value); 122 return ((envp == 0) ? addenv(destination) : (*envp = destination, 0)); 123 } 124 125 /* cmalloc - malloc and copy block of memory */ 126 127 static char *cmalloc(int new_len, char *old, int old_len) 128 { 129 char *new = malloc(new_len); 130 131 if (new != 0) 132 memcpy(new, old, old_len); 133 return (new); 134 } 135 136 /* addenv - append environment entry */ 137 138 static int addenv(char *nameval) 139 { 140 char **envp; 141 int n_used; /* number of environment entries */ 142 int l_used; /* bytes used excl. terminator */ 143 int l_need; /* bytes needed incl. terminator */ 144 145 for (envp = environ; envp && *envp; envp++) 146 /* void */ ; 147 n_used = envp - environ; 148 l_used = n_used * sizeof(*envp); 149 l_need = l_used + 2 * sizeof(*envp); 150 151 envp = allocated ? 152 (char **) realloc((char *) environ, l_need) : 153 (char **) cmalloc(l_need, (char *) environ, l_used); 154 if (envp == 0) { 155 return (-1); 156 } else { 157 allocated = 1; 158 environ = envp; 159 environ[n_used++] = nameval; /* add new entry */ 160 environ[n_used] = 0; /* terminate list */ 161 return (0); 162 } 163 } 164 165 #ifdef TEST 166 167 /* 168 * Stand-alone program for test purposes. 169 */ 170 171 /* printenv - display environment */ 172 173 static void printenv() 174 { 175 char **envp; 176 177 for (envp = environ; envp && *envp; envp++) 178 printf("%s\n", *envp); 179 } 180 181 int main(int argc, char **argv) 182 { 183 char *cp; 184 int changed = 0; 185 186 if (argc < 2) { 187 printf("usage: %s name[=value]...\n", argv[0]); 188 return (1); 189 } 190 while (--argc && *++argv) { 191 if (argv[0][0] == '-') { /* unsetenv() test */ 192 unsetenv(argv[0] + 1); 193 changed = 1; 194 } else if (strchr(argv[0], '=') == 0) { /* getenv() test */ 195 cp = getenv(argv[0]); 196 printf("%s: %s\n", argv[0], cp ? cp : "not found"); 197 } else { /* putenv() test */ 198 if (putenv(argv[0])) { 199 perror("putenv"); 200 return (1); 201 } 202 changed = 1; 203 } 204 } 205 if (changed) 206 printenv(); 207 return (0); 208 } 209 210 #endif /* TEST */ 211