environment.c revision 38451
1/* 2 * Copyright (c) 1998 Michael Smith. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id$ 27 * 28 */ 29 30/* 31 * Manage an environment-like space in which string variables may be stored. 32 * Provide support for some method-like operations for setting/retrieving 33 * variables in order to allow some type strength. 34 */ 35 36#include "stand.h" 37 38#include <string.h> 39 40static void env_discard(struct env_var *ev); 41 42struct env_var *environ = NULL; 43 44/* 45 * Look up (name) and return it's env_var structure. 46 */ 47struct env_var * 48env_getenv(const char *name) 49{ 50 struct env_var *ev; 51 52 for (ev = environ; ev != NULL; ev = ev->ev_next) 53 if (!strcmp(ev->ev_name, name)) 54 break; 55 return(ev); 56} 57 58/* 59 * Some notes: 60 * 61 * If the EV_VOLATILE flag is set, a copy of the variable is made. 62 * If EV_DYNAMIC is set, the the variable has been allocated with 63 * malloc and ownership transferred to the environment. 64 * If (value) is NULL, the variable is set but has no value. 65 */ 66int 67env_setenv(const char *name, int flags, void *value, ev_sethook_t sethook, 68 ev_unsethook_t unsethook) 69{ 70 struct env_var *ev, *curr, *last; 71 72 if ((ev = env_getenv(name)) != NULL) { 73 74 /* 75 * If there's a set hook, let it do the work (unless we are working 76 * for one already. 77 */ 78 if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK)) 79 return(ev->ev_sethook(ev, flags, value)); 80 } else { 81 ev = malloc(sizeof(struct env_var)); 82 ev->ev_name = strdup(name); 83 ev->ev_value = NULL; 84 /* hooks can only be set when the variable is instantiated */ 85 ev->ev_sethook = sethook; 86 ev->ev_unsethook = unsethook; 87 } 88 89 /* If there is data in the variable, discard it */ 90 if (ev->ev_value != NULL) 91 free(ev->ev_value); 92 93 /* If we have a new value, use it */ 94 if (flags & EV_VOLATILE) { 95 ev->ev_value = strdup(value); 96 } else { 97 ev->ev_value = value; 98 } 99 100 /* Keep the flag components that are relevant */ 101 ev->ev_flags = flags & (EV_DYNAMIC); 102 103 /* Sort into list */ 104 ev->ev_prev = NULL; 105 ev->ev_next = NULL; 106 107 /* Search for the record to insert before */ 108 for (last = NULL, curr = environ; 109 curr != NULL; 110 last = curr, curr = curr->ev_next) { 111 112 if (strcmp(ev->ev_name, curr->ev_name) < 0) { 113 if (curr->ev_prev) { 114 curr->ev_prev->ev_next = ev; 115 } else { 116 environ = ev; 117 } 118 ev->ev_next = curr; 119 ev->ev_prev = curr->ev_prev; 120 curr->ev_prev = ev; 121 break; 122 } 123 } 124 if (curr == NULL) { 125 if (last == NULL) { 126 environ = ev; 127 } else { 128 last->ev_next = ev; 129 ev->ev_prev = last; 130 } 131 } 132 return(0); 133} 134 135char * 136getenv(const char *name) 137{ 138 struct env_var *ev; 139 140 /* Set but no value gives empty string */ 141 if ((ev = env_getenv(name)) != NULL) { 142 if (ev->ev_value != NULL) 143 return(ev->ev_value); 144 return(""); 145 } 146 return(NULL); 147} 148 149int 150setenv(const char *name, char *value, int overwrite) 151{ 152 /* No guarantees about state, always assume volatile */ 153 if (overwrite || (env_getenv(name) == NULL)) 154 return(env_setenv(name, EV_VOLATILE, value, NULL, NULL)); 155 return(0); 156} 157 158int 159putenv(const char *string) 160{ 161 char *value; 162 163 if ((value = strchr(string, '=')) != NULL) 164 *(value++) = 0; 165 return(setenv(string, value, 1)); 166} 167 168int 169unsetenv(const char *name) 170{ 171 struct env_var *ev; 172 int err; 173 174 err = 0; 175 if ((ev = env_getenv(name)) == NULL) { 176 err = ENOENT; 177 } else { 178 if (ev->ev_unsethook != NULL) 179 err = ev->ev_unsethook(ev); 180 if (err == 0) { 181 env_discard(ev); 182 } 183 } 184 return(err); 185} 186 187static void 188env_discard(struct env_var *ev) 189{ 190 if (ev->ev_prev) 191 ev->ev_prev->ev_next = ev->ev_next; 192 if (ev->ev_next) 193 ev->ev_next->ev_prev = ev->ev_prev; 194 if (environ == ev) 195 environ = ev->ev_next; 196 free(ev->ev_name); 197 if (ev->ev_flags & EV_DYNAMIC) 198 free(ev->ev_value); 199 free(ev); 200} 201 202int 203env_noset(struct env_var *ev, int flags, void *value) 204{ 205 return(EPERM); 206} 207 208int 209env_nounset(struct env_var *ev) 210{ 211 return(EPERM); 212} 213