1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * David Korn <dgk@research.att.com> * 18 * * 19 ***********************************************************************/ 20 #pragma prototyped 21 22 #include <ast.h> 23 #include <cdt.h> 24 25 #define env_change() (++ast.env_serial) 26 27 typedef struct _venv_ Evar_t; 28 struct _venv_ 29 { 30 union 31 { 32 Evar_t *next; 33 char *ptr; 34 } un; 35 Dtlink_t link; 36 int index; 37 }; 38 39 typedef struct _env_ 40 { 41 Dt_t *dt; 42 Evar_t *freelist; 43 char **env; 44 int count; 45 int extra; 46 int max; 47 int flags; 48 } Env_t; 49 50 #define _BLD_env 1 51 #include <env.h> 52 53 #define ENV_VALID 2 /* set if env is valid */ 54 #define ENV_PMALLOC 1 /* set if Evar_t->un.ptr *s malloced */ 55 #define ENV_VMALLOC 2 /* set of Evar_t was malloced */ 56 #define ENV_BITS 3 57 58 /* 59 * Compares the name portion of name=... only. 60 */ 61 static int compare(Dt_t *dt, Void_t* key1, Void_t* key2, Dtdisc_t* disc) 62 { 63 register int c,d; 64 const unsigned char *s1=(unsigned const char*)key1; 65 const unsigned char *s2=(unsigned const char*)key2; 66 while((c= *s1++) && c!='=' && c==*s2) 67 s2++; 68 if(c=='=') 69 c = 0; 70 if((d=*s2)=='=') 71 d = 0; 72 return(c-d); 73 } 74 75 static Dtdisc_t env_disc = 76 { 77 0, -1, 78 sizeof(char*), 79 0, 80 0, 81 compare 82 }; 83 84 /* 85 * return a pointer to the environment in sorted order 86 * NULL is returned if there if there is nospace 87 */ 88 char **env_get(Env_t* ep) 89 { 90 register Evar_t *vp; 91 register int n=ep->extra; 92 if(ep->flags&ENV_VALID) 93 return(ep->env+n); 94 if(ep->count > ep->max) 95 { 96 if(ep->flags&ENV_MALLOCED) 97 free((void*)ep->env); 98 if(!(ep->env = (char**)malloc(sizeof(char*)*(ep->count+1)))) 99 return(0); 100 ep->flags |= ENV_MALLOCED; 101 ep->max = ep->count; 102 } 103 for(vp=(Evar_t*)dtfirst(ep->dt);vp; vp=(Evar_t*)dtnext(ep->dt,vp)) 104 { 105 vp->index = (n<<ENV_BITS) | (vp->index&((1<<ENV_BITS)-1)); 106 ep->env[n++] = vp->un.ptr; 107 } 108 ep->env[n] = 0; 109 ep->flags |= ENV_VALID; 110 environ = ep->env+ep->extra; 111 return(ep->env+ep->extra); 112 } 113 114 /* 115 * add name=value pair given by <str> to <ep> 116 * if malloced is set, the variable will be freed when reassigned 117 * The environment list may become invalidated 118 * Returns 1 for success, 0 for failure 119 */ 120 int env_add(Env_t *ep, const char *str, int flags) 121 { 122 Evar_t *vp = (Evar_t*)dtmatch(ep->dt,(void*)str); 123 if(vp && strcmp(str,vp->un.ptr)==0) 124 return(1); 125 if(flags&ENV_STRDUP) 126 str = strdup(str); 127 if(vp) 128 { 129 if(vp->index&ENV_PMALLOC) 130 free((void*)vp->un.ptr); 131 vp->un.ptr = (char*)str; 132 if(ep->env && (ep->flags&ENV_VALID)) 133 ep->env[vp->index>>ENV_BITS] = vp->un.ptr; 134 } 135 else 136 { 137 ep->flags &= ~ENV_VALID; 138 if(vp = ep->freelist) 139 ep->freelist = vp->un.next; 140 else if(vp = newof((Evar_t*)0,Evar_t,2,0)) 141 { 142 vp->index = ENV_VMALLOC; 143 ep->freelist = (vp+1); 144 ep->freelist->un.next = 0; 145 } 146 else 147 return(0); 148 vp->un.ptr = (void*)str; 149 if(!(vp=dtinsert(ep->dt,vp))) 150 return(0); 151 ep->count++; 152 } 153 if(flags) 154 vp->index |= ENV_PMALLOC; 155 else 156 vp->index &= ~ENV_PMALLOC; 157 env_change(); 158 return(1); 159 } 160 161 /* 162 * delete name from <ep> 163 * The environment list may become invalidated 164 * Returns 1 for success, 0 for if name is not present 165 */ 166 int env_delete(Env_t *ep, const char *str) 167 { 168 Evar_t *vp = (Evar_t*)dtmatch(ep->dt,(void*)str); 169 if(!vp) 170 return(0); 171 ep->flags &= ~ENV_VALID; 172 if(vp->index&ENV_PMALLOC) 173 free((void*)vp->un.ptr); 174 dtdelete(ep->dt,vp); 175 vp->un.next = ep->freelist; 176 ep->freelist = vp; 177 env_change(); 178 return(1); 179 } 180 181 /* 182 * open up a structure to support environment variables 183 * initialize with environment give by <envp> 184 * If <extra> > 0, <extra> slots will be left at beginning of 185 * environment list when env_get() is involed. 186 * If <extra>==ENV_USABLE, then the original environ can be 187 * used and returned. Otherwise, a new one will be returned 188 */ 189 Env_t *env_open(char **envp, int extra) 190 { 191 char **env; 192 Env_t *ep; 193 Evar_t *vp; 194 int n=2; 195 if(!(ep = newof((Env_t*)0,Env_t,1,0))) 196 return(0); 197 if(!(ep->dt = dtopen(&env_disc,Dtoset))) 198 return(0); 199 if(env=envp) 200 { 201 while(*env++); 202 n = (env+2)-envp; 203 } 204 if(extra==ENV_STABLE) 205 { 206 ep->env = envp; 207 ep->max = n-1; 208 } 209 else 210 ep->count = ep->extra = extra; 211 ep->freelist = vp = newof((Evar_t*)0,Evar_t,n,0); 212 vp->index = ENV_VMALLOC; 213 while(--n>0) 214 { 215 vp->un.next = (vp+1); 216 vp++; 217 } 218 vp->un.next = 0; 219 if(env) 220 { 221 for(env=envp; *env; env++) 222 env_add(ep,*env,0); 223 } 224 return(ep); 225 } 226 227 /* 228 * close <ep> and free up all space used by it 229 */ 230 void env_close(Env_t *ep) 231 { 232 Evar_t *vp, *vpnext,*top; 233 if(ep->env && (ep->flags&ENV_MALLOCED)) 234 free((void*)ep->env); 235 for(vp=(Evar_t*)dtfirst(ep->dt);vp; vp=vpnext) 236 { 237 vpnext = (Evar_t*)dtnext(ep->dt,vp); 238 env_delete(ep,vp->un.ptr); 239 } 240 for(top=0,vp = ep->freelist; vp; vp = vpnext) 241 { 242 vpnext = vp->un.next; 243 if(vp->index&ENV_VMALLOC) 244 { 245 vp->un.next = top; 246 top = vp; 247 } 248 } 249 for(vp=top; vp; vp = vpnext) 250 { 251 vpnext = vp->un.next; 252 free((void*)vp); 253 } 254 dtclose(ep->dt); 255 } 256