environment.c revision 38451
138451Smsmith/* 238451Smsmith * Copyright (c) 1998 Michael Smith. 338451Smsmith * All rights reserved. 438451Smsmith * 538451Smsmith * Redistribution and use in source and binary forms, with or without 638451Smsmith * modification, are permitted provided that the following conditions 738451Smsmith * are met: 838451Smsmith * 1. Redistributions of source code must retain the above copyright 938451Smsmith * notice, this list of conditions and the following disclaimer. 1038451Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1138451Smsmith * notice, this list of conditions and the following disclaimer in the 1238451Smsmith * documentation and/or other materials provided with the distribution. 1338451Smsmith * 1438451Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738451Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438451Smsmith * SUCH DAMAGE. 2538451Smsmith * 2638451Smsmith * $Id$ 2738451Smsmith * 2838451Smsmith */ 2938451Smsmith 3038451Smsmith/* 3138451Smsmith * Manage an environment-like space in which string variables may be stored. 3238451Smsmith * Provide support for some method-like operations for setting/retrieving 3338451Smsmith * variables in order to allow some type strength. 3438451Smsmith */ 3538451Smsmith 3638451Smsmith#include "stand.h" 3738451Smsmith 3838451Smsmith#include <string.h> 3938451Smsmith 4038451Smsmithstatic void env_discard(struct env_var *ev); 4138451Smsmith 4238451Smsmithstruct env_var *environ = NULL; 4338451Smsmith 4438451Smsmith/* 4538451Smsmith * Look up (name) and return it's env_var structure. 4638451Smsmith */ 4738451Smsmithstruct env_var * 4838451Smsmithenv_getenv(const char *name) 4938451Smsmith{ 5038451Smsmith struct env_var *ev; 5138451Smsmith 5238451Smsmith for (ev = environ; ev != NULL; ev = ev->ev_next) 5338451Smsmith if (!strcmp(ev->ev_name, name)) 5438451Smsmith break; 5538451Smsmith return(ev); 5638451Smsmith} 5738451Smsmith 5838451Smsmith/* 5938451Smsmith * Some notes: 6038451Smsmith * 6138451Smsmith * If the EV_VOLATILE flag is set, a copy of the variable is made. 6238451Smsmith * If EV_DYNAMIC is set, the the variable has been allocated with 6338451Smsmith * malloc and ownership transferred to the environment. 6438451Smsmith * If (value) is NULL, the variable is set but has no value. 6538451Smsmith */ 6638451Smsmithint 6738451Smsmithenv_setenv(const char *name, int flags, void *value, ev_sethook_t sethook, 6838451Smsmith ev_unsethook_t unsethook) 6938451Smsmith{ 7038451Smsmith struct env_var *ev, *curr, *last; 7138451Smsmith 7238451Smsmith if ((ev = env_getenv(name)) != NULL) { 7338451Smsmith 7438451Smsmith /* 7538451Smsmith * If there's a set hook, let it do the work (unless we are working 7638451Smsmith * for one already. 7738451Smsmith */ 7838451Smsmith if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK)) 7938451Smsmith return(ev->ev_sethook(ev, flags, value)); 8038451Smsmith } else { 8138451Smsmith ev = malloc(sizeof(struct env_var)); 8238451Smsmith ev->ev_name = strdup(name); 8338451Smsmith ev->ev_value = NULL; 8438451Smsmith /* hooks can only be set when the variable is instantiated */ 8538451Smsmith ev->ev_sethook = sethook; 8638451Smsmith ev->ev_unsethook = unsethook; 8738451Smsmith } 8838451Smsmith 8938451Smsmith /* If there is data in the variable, discard it */ 9038451Smsmith if (ev->ev_value != NULL) 9138451Smsmith free(ev->ev_value); 9238451Smsmith 9338451Smsmith /* If we have a new value, use it */ 9438451Smsmith if (flags & EV_VOLATILE) { 9538451Smsmith ev->ev_value = strdup(value); 9638451Smsmith } else { 9738451Smsmith ev->ev_value = value; 9838451Smsmith } 9938451Smsmith 10038451Smsmith /* Keep the flag components that are relevant */ 10138451Smsmith ev->ev_flags = flags & (EV_DYNAMIC); 10238451Smsmith 10338451Smsmith /* Sort into list */ 10438451Smsmith ev->ev_prev = NULL; 10538451Smsmith ev->ev_next = NULL; 10638451Smsmith 10738451Smsmith /* Search for the record to insert before */ 10838451Smsmith for (last = NULL, curr = environ; 10938451Smsmith curr != NULL; 11038451Smsmith last = curr, curr = curr->ev_next) { 11138451Smsmith 11238451Smsmith if (strcmp(ev->ev_name, curr->ev_name) < 0) { 11338451Smsmith if (curr->ev_prev) { 11438451Smsmith curr->ev_prev->ev_next = ev; 11538451Smsmith } else { 11638451Smsmith environ = ev; 11738451Smsmith } 11838451Smsmith ev->ev_next = curr; 11938451Smsmith ev->ev_prev = curr->ev_prev; 12038451Smsmith curr->ev_prev = ev; 12138451Smsmith break; 12238451Smsmith } 12338451Smsmith } 12438451Smsmith if (curr == NULL) { 12538451Smsmith if (last == NULL) { 12638451Smsmith environ = ev; 12738451Smsmith } else { 12838451Smsmith last->ev_next = ev; 12938451Smsmith ev->ev_prev = last; 13038451Smsmith } 13138451Smsmith } 13238451Smsmith return(0); 13338451Smsmith} 13438451Smsmith 13538451Smsmithchar * 13638451Smsmithgetenv(const char *name) 13738451Smsmith{ 13838451Smsmith struct env_var *ev; 13938451Smsmith 14038451Smsmith /* Set but no value gives empty string */ 14138451Smsmith if ((ev = env_getenv(name)) != NULL) { 14238451Smsmith if (ev->ev_value != NULL) 14338451Smsmith return(ev->ev_value); 14438451Smsmith return(""); 14538451Smsmith } 14638451Smsmith return(NULL); 14738451Smsmith} 14838451Smsmith 14938451Smsmithint 15038451Smsmithsetenv(const char *name, char *value, int overwrite) 15138451Smsmith{ 15238451Smsmith /* No guarantees about state, always assume volatile */ 15338451Smsmith if (overwrite || (env_getenv(name) == NULL)) 15438451Smsmith return(env_setenv(name, EV_VOLATILE, value, NULL, NULL)); 15538451Smsmith return(0); 15638451Smsmith} 15738451Smsmith 15838451Smsmithint 15938451Smsmithputenv(const char *string) 16038451Smsmith{ 16138451Smsmith char *value; 16238451Smsmith 16338451Smsmith if ((value = strchr(string, '=')) != NULL) 16438451Smsmith *(value++) = 0; 16538451Smsmith return(setenv(string, value, 1)); 16638451Smsmith} 16738451Smsmith 16838451Smsmithint 16938451Smsmithunsetenv(const char *name) 17038451Smsmith{ 17138451Smsmith struct env_var *ev; 17238451Smsmith int err; 17338451Smsmith 17438451Smsmith err = 0; 17538451Smsmith if ((ev = env_getenv(name)) == NULL) { 17638451Smsmith err = ENOENT; 17738451Smsmith } else { 17838451Smsmith if (ev->ev_unsethook != NULL) 17938451Smsmith err = ev->ev_unsethook(ev); 18038451Smsmith if (err == 0) { 18138451Smsmith env_discard(ev); 18238451Smsmith } 18338451Smsmith } 18438451Smsmith return(err); 18538451Smsmith} 18638451Smsmith 18738451Smsmithstatic void 18838451Smsmithenv_discard(struct env_var *ev) 18938451Smsmith{ 19038451Smsmith if (ev->ev_prev) 19138451Smsmith ev->ev_prev->ev_next = ev->ev_next; 19238451Smsmith if (ev->ev_next) 19338451Smsmith ev->ev_next->ev_prev = ev->ev_prev; 19438451Smsmith if (environ == ev) 19538451Smsmith environ = ev->ev_next; 19638451Smsmith free(ev->ev_name); 19738451Smsmith if (ev->ev_flags & EV_DYNAMIC) 19838451Smsmith free(ev->ev_value); 19938451Smsmith free(ev); 20038451Smsmith} 20138451Smsmith 20238451Smsmithint 20338451Smsmithenv_noset(struct env_var *ev, int flags, void *value) 20438451Smsmith{ 20538451Smsmith return(EPERM); 20638451Smsmith} 20738451Smsmith 20838451Smsmithint 20938451Smsmithenv_nounset(struct env_var *ev) 21038451Smsmith{ 21138451Smsmith return(EPERM); 21238451Smsmith} 213