Home | History | Annotate | Line # | Download | only in dist
environ.c revision 1.5
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2009 Nicholas Marriott <nicm (at) users.sourceforge.net>
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  */
     18 
     19 #include <sys/types.h>
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 
     24 #include "tmux.h"
     25 
     26 /*
     27  * Environment - manipulate a set of environment variables.
     28  */
     29 
     30 RB_GENERATE(environ, environ_entry, entry, environ_cmp);
     31 
     32 int
     33 environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2)
     34 {
     35 	return (strcmp(envent1->name, envent2->name));
     36 }
     37 
     38 /* Initialise the environment. */
     39 void
     40 environ_init(struct environ *env)
     41 {
     42 	RB_INIT(env);
     43 }
     44 
     45 /* Free an environment. */
     46 void
     47 environ_free(struct environ *env)
     48 {
     49 	struct environ_entry	*envent;
     50 
     51 	while (!RB_EMPTY(env)) {
     52 		envent = RB_ROOT(env);
     53 		RB_REMOVE(environ, env, envent);
     54 		free(envent->name);
     55 		free(envent->value);
     56 		free(envent);
     57 	}
     58 }
     59 
     60 /* Copy one environment into another. */
     61 void
     62 environ_copy(struct environ *srcenv, struct environ *dstenv)
     63 {
     64 	struct environ_entry	*envent;
     65 
     66 	RB_FOREACH(envent, environ, srcenv)
     67 		environ_set(dstenv, envent->name, envent->value);
     68 }
     69 
     70 /* Find an environment variable. */
     71 struct environ_entry *
     72 environ_find(struct environ *env, const char *name)
     73 {
     74 	struct environ_entry	envent;
     75 
     76 	envent.name = __UNCONST(name);
     77 	return (RB_FIND(environ, env, &envent));
     78 }
     79 
     80 /* Set an environment variable. */
     81 void
     82 environ_set(struct environ *env, const char *name, const char *value)
     83 {
     84 	struct environ_entry	*envent;
     85 
     86 	if ((envent = environ_find(env, name)) != NULL) {
     87 		free(envent->value);
     88 		if (value != NULL)
     89 			envent->value = xstrdup(value);
     90 		else
     91 			envent->value = NULL;
     92 	} else {
     93 		envent = xmalloc(sizeof *envent);
     94 		envent->name = xstrdup(name);
     95 		if (value != NULL)
     96 			envent->value = xstrdup(value);
     97 		else
     98 			envent->value = NULL;
     99 		RB_INSERT(environ, env, envent);
    100 	}
    101 }
    102 
    103 /* Set an environment variable from a NAME=VALUE string. */
    104 void
    105 environ_put(struct environ *env, const char *var)
    106 {
    107 	char	*name, *value;
    108 
    109 	value = strchr(var, '=');
    110 	if (value == NULL)
    111 		return;
    112 	value++;
    113 
    114 	name = xstrdup(var);
    115 	name[strcspn(name, "=")] = '\0';
    116 
    117 	environ_set(env, name, value);
    118 	free(name);
    119 }
    120 
    121 /* Unset an environment variable. */
    122 void
    123 environ_unset(struct environ *env, const char *name)
    124 {
    125 	struct environ_entry	*envent;
    126 
    127 	if ((envent = environ_find(env, name)) == NULL)
    128 		return;
    129 	RB_REMOVE(environ, env, envent);
    130 	free(envent->name);
    131 	free(envent->value);
    132 	free(envent);
    133 }
    134 
    135 /*
    136  * Copy a space-separated list of variables from a destination into a source
    137  * environment.
    138  */
    139 void
    140 environ_update(const char *vars, struct environ *srcenv,
    141     struct environ *dstenv)
    142 {
    143 	struct environ_entry	*envent;
    144 	char			*copyvars, *var, *next;
    145 
    146 	copyvars = next = xstrdup(vars);
    147 	while ((var = strsep(&next, " ")) != NULL) {
    148 		if ((envent = environ_find(srcenv, var)) == NULL)
    149 			environ_set(dstenv, var, NULL);
    150 		else
    151 			environ_set(dstenv, envent->name, envent->value);
    152 	}
    153 	free(copyvars);
    154 }
    155 
    156 /* Push environment into the real environment - use after fork(). */
    157 void
    158 environ_push(struct environ *env)
    159 {
    160 	struct environ_entry	 *envent;
    161 	char			**vp, *v;
    162 
    163 	for (vp = environ; *vp != NULL; vp++) {
    164 		v = xstrdup(*vp);
    165 		v[strcspn(v, "=")] = '\0';
    166 
    167 		unsetenv(v);
    168 		free(v);
    169 	}
    170 
    171 	RB_FOREACH(envent, environ, env) {
    172 		if (envent->value != NULL)
    173 			setenv(envent->name, envent->value, 1);
    174 	}
    175 }
    176