diff options
Diffstat (limited to 'src/util/envp.c')
| -rw-r--r-- | src/util/envp.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/src/util/envp.c b/src/util/envp.c new file mode 100644 index 0000000..808d9b8 --- /dev/null +++ b/src/util/envp.c @@ -0,0 +1,182 @@ +#include "envp.h" + +#include "string.h" + +#include <stdlib.h> + +extern char **environ; + +static inline bool _envp_string_match_key( + const char *restrict string, const char *restrict key) { + for (size_t i = 0; ; ++i) { + if ('\0' == key[i]) { + return ('=' == string[i]); + } else if ('\0' == string[i]) { + return false; + } else if (string[i] != key[i]) { + return false; + } + } +} + + +static int _envp_append(envp_t *envp, char *string) { + /* find the end */ + envp_t p = *envp; + size_t i = 0; + while (NULL != p[i]) i++; + + /* make space for one more element */ + p = realloc(p, ((i+2) * sizeof(char *))); + if (NULL == p) { + return -1; + } + *envp = p; + + /* append element */ + p[i+1] = 0; + p[i] = string; + + return 0; +} + +static int _envp_replace(char **old, char *new) { + char *oldv = *old; + *old = new; + free(oldv); + + return 0; +} + + +envp_t *envp_alloc(void) { + envp_t envp = calloc(1, sizeof(*envp)); + envp_t *envpp = malloc(sizeof(envpp)); + *envpp = envp; + return envpp; +} + +envp_t *envp_dup(void) { + envp_t *envp = envp_alloc(); + + for (size_t i = 0; NULL != environ[i]; ++i) { + (void)_envp_append(envp, strdup(environ[i])); + } + + return envp; +} + +static char **_envp_find_elem(envp_t envp, const char *restrict name) { + for (size_t i = 0; NULL != envp[i]; ++i) { + if (_envp_string_match_key(envp[i], name)) { + return &envp[i]; + } + } + + return NULL; +} + +static char *_envp_get_elem(envp_t envp, const char *restrict name) { + char **elem = _envp_find_elem(envp, name); + return (elem ? *elem : NULL); +} + +char *envp_get(envp_t *envp, const char *name) { + if (NULL == envp) return NULL; + + char *elem = _envp_get_elem(*envp, name); + + if (NULL != elem) { + elem = strchr(elem, '='); + if (NULL != elem) elem++; /* skip over = */ + } + + return elem; +} + + +int envp_put(envp_t *envp, char *string) { + char envname[strchr(string, '=')-string+1]; + strncpy(envname, string, sizeof(envname)); + + char **elem = _envp_find_elem(*envp, envname); + + if (NULL != elem) { + return _envp_replace(elem, string); + } else { + return _envp_append(envp, string); + } +} + +int envp_set( + envp_t *envp, const char *restrict envname, const char *restrict envval, + bool overwrite) { + char **elem = _envp_find_elem(*envp, envname); + + char *string = NULL; + if (NULL == elem || overwrite) { + size_t slen = (strlen(envname) + strlen (envval) + 2); + string = malloc(slen * sizeof(char)); + snprintf(string, slen, "%s=%s", envname, envval); + } + + if (NULL != elem) { + if (overwrite) { + return _envp_replace(elem, string); + } else { + /* no change */ + return 0; + } + } else { + return _envp_append(envp, string); + } +} + +int envp_unset(envp_t *envp, const char *restrict name) { + size_t i; + + /* find element */ + for (i = 0; NULL != (*envp)[i]; ++i) { + if (_envp_string_match_key((*envp)[i], name)) { + break; + } + } + + char *elem = (*envp)[i]; + if (NULL == elem) { + /* not found -> ok */ + return 0; + } + + /* shift rest of elements */ + for (; NULL != (*envp)[i]; ++i) { + (*envp)[i] = (*envp)[i+1]; + } + + /* delete match */ + free(elem); + + return 0; +} + +void envp_merge(envp_t *dest, envp_t *const src) { + if (NULL == src) return; + + for (size_t i = 0; NULL != (*src)[i]; ++i) { + envp_put(dest, strdup((*src)[i])); + } +} + +void envp_print(envp_t *envp, FILE *restrict stream) { + for (size_t i = 0; NULL != (*envp)[i]; ++i) { + fprintf(stream, "%s\n", (*envp)[i]); + } +} + +void envp_free(envp_t *envp) { + for (size_t i = 0; NULL != (*envp)[i]; ++i) { + free((*envp)[i]); + } + free(*envp); + free(envp); +} |
