summaryrefslogtreecommitdiff
path: root/src/util/envp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/envp.c')
-rw-r--r--src/util/envp.c182
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);
+}