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