| /* |
| * __put_env.c - common code for putenv() and setenv() |
| */ |
| |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include "env.h" |
| |
| static size_t __environ_size; |
| static char **__environ_alloc; |
| |
| /* str should be a duplicated version of the input string; |
| len is the length of the key including the = sign */ |
| |
| int __put_env(char *str, size_t len, int overwrite) |
| { |
| static char *const null_environ = { NULL }; |
| char **p, *q; |
| char **newenv; |
| size_t n; |
| |
| if (!environ) |
| environ = (char **)null_environ; |
| |
| n = 1; /* Include space for final NULL */ |
| for (p = environ; (q = *p); p++) { |
| n++; |
| if (!strncmp(q, str, len)) { |
| if (!overwrite) |
| free(str); |
| else |
| *p = str; /* Possible memory leak... */ |
| return 0; |
| } |
| } |
| |
| if (__environ_alloc && environ != __environ_alloc) { |
| free(__environ_alloc); |
| __environ_alloc = NULL; |
| } |
| |
| /* Need to extend the environment */ |
| if (n < __environ_size) { |
| p[1] = NULL; |
| *p = str; |
| return 0; |
| } else { |
| if (__environ_alloc) { |
| newenv = |
| realloc(__environ_alloc, |
| (__environ_size << 1) * sizeof(char *)); |
| if (!newenv) |
| return -1; |
| |
| __environ_size <<= 1; |
| } else { |
| /* Make a reasonable guess how much more space |
| we need */ |
| size_t newsize = n + 32; |
| newenv = malloc(newsize * sizeof(char *)); |
| if (!newenv) |
| return -1; |
| |
| memcpy(newenv, environ, n * sizeof(char *)); |
| __environ_size = newsize; |
| } |
| newenv[n-1] = str; /* Old NULL position */ |
| newenv[n] = NULL; |
| environ = newenv; |
| } |
| return 0; |
| } |