14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin
224887Schin #include <ast.h>
234887Schin #include <cdt.h>
244887Schin
254887Schin #define env_change() (++ast.env_serial)
264887Schin
274887Schin typedef struct _venv_ Evar_t;
284887Schin struct _venv_
294887Schin {
304887Schin union
314887Schin {
324887Schin Evar_t *next;
334887Schin char *ptr;
344887Schin } un;
354887Schin Dtlink_t link;
364887Schin int index;
374887Schin };
384887Schin
394887Schin typedef struct _env_
404887Schin {
414887Schin Dt_t *dt;
424887Schin Evar_t *freelist;
434887Schin char **env;
444887Schin int count;
454887Schin int extra;
464887Schin int max;
474887Schin int flags;
484887Schin } Env_t;
494887Schin
504887Schin #define _BLD_env 1
514887Schin #include <env.h>
524887Schin
534887Schin #define ENV_VALID 2 /* set if env is valid */
544887Schin #define ENV_PMALLOC 1 /* set if Evar_t->un.ptr *s malloced */
554887Schin #define ENV_VMALLOC 2 /* set of Evar_t was malloced */
564887Schin #define ENV_BITS 3
574887Schin
584887Schin /*
594887Schin * Compares the name portion of name=... only.
604887Schin */
compare(Dt_t * dt,Void_t * key1,Void_t * key2,Dtdisc_t * disc)614887Schin static int compare(Dt_t *dt, Void_t* key1, Void_t* key2, Dtdisc_t* disc)
624887Schin {
634887Schin register int c,d;
644887Schin const unsigned char *s1=(unsigned const char*)key1;
654887Schin const unsigned char *s2=(unsigned const char*)key2;
664887Schin while((c= *s1++) && c!='=' && c==*s2)
674887Schin s2++;
684887Schin if(c=='=')
694887Schin c = 0;
704887Schin if((d=*s2)=='=')
714887Schin d = 0;
724887Schin return(c-d);
734887Schin }
744887Schin
754887Schin static Dtdisc_t env_disc =
764887Schin {
774887Schin 0, -1,
784887Schin sizeof(char*),
794887Schin 0,
804887Schin 0,
814887Schin compare
824887Schin };
834887Schin
844887Schin /*
854887Schin * return a pointer to the environment in sorted order
864887Schin * NULL is returned if there if there is nospace
874887Schin */
env_get(Env_t * ep)884887Schin char **env_get(Env_t* ep)
894887Schin {
904887Schin register Evar_t *vp;
914887Schin register int n=ep->extra;
924887Schin if(ep->flags&ENV_VALID)
934887Schin return(ep->env+n);
944887Schin if(ep->count > ep->max)
954887Schin {
964887Schin if(ep->flags&ENV_MALLOCED)
974887Schin free((void*)ep->env);
984887Schin if(!(ep->env = (char**)malloc(sizeof(char*)*(ep->count+1))))
994887Schin return(0);
1004887Schin ep->flags |= ENV_MALLOCED;
1014887Schin ep->max = ep->count;
1024887Schin }
1034887Schin for(vp=(Evar_t*)dtfirst(ep->dt);vp; vp=(Evar_t*)dtnext(ep->dt,vp))
1044887Schin {
1054887Schin vp->index = (n<<ENV_BITS) | (vp->index&((1<<ENV_BITS)-1));
1064887Schin ep->env[n++] = vp->un.ptr;
1074887Schin }
1084887Schin ep->env[n] = 0;
1094887Schin ep->flags |= ENV_VALID;
1104887Schin environ = ep->env+ep->extra;
1114887Schin return(ep->env+ep->extra);
1124887Schin }
1134887Schin
1144887Schin /*
1154887Schin * add name=value pair given by <str> to <ep>
1164887Schin * if malloced is set, the variable will be freed when reassigned
1174887Schin * The environment list may become invalidated
1184887Schin * Returns 1 for success, 0 for failure
1194887Schin */
env_add(Env_t * ep,const char * str,int flags)1204887Schin int env_add(Env_t *ep, const char *str, int flags)
1214887Schin {
1224887Schin Evar_t *vp = (Evar_t*)dtmatch(ep->dt,(void*)str);
1234887Schin if(vp && strcmp(str,vp->un.ptr)==0)
1244887Schin return(1);
1254887Schin if(flags&ENV_STRDUP)
1264887Schin str = strdup(str);
1274887Schin if(vp)
1284887Schin {
1294887Schin if(vp->index&ENV_PMALLOC)
1304887Schin free((void*)vp->un.ptr);
1314887Schin vp->un.ptr = (char*)str;
1324887Schin if(ep->env && (ep->flags&ENV_VALID))
1334887Schin ep->env[vp->index>>ENV_BITS] = vp->un.ptr;
1344887Schin }
1354887Schin else
1364887Schin {
1374887Schin ep->flags &= ~ENV_VALID;
1384887Schin if(vp = ep->freelist)
1394887Schin ep->freelist = vp->un.next;
1404887Schin else if(vp = newof((Evar_t*)0,Evar_t,2,0))
1414887Schin {
1424887Schin vp->index = ENV_VMALLOC;
1434887Schin ep->freelist = (vp+1);
1444887Schin ep->freelist->un.next = 0;
1454887Schin }
1464887Schin else
1474887Schin return(0);
1484887Schin vp->un.ptr = (void*)str;
1494887Schin if(!(vp=dtinsert(ep->dt,vp)))
1504887Schin return(0);
1514887Schin ep->count++;
1524887Schin }
1534887Schin if(flags)
1544887Schin vp->index |= ENV_PMALLOC;
1554887Schin else
1564887Schin vp->index &= ~ENV_PMALLOC;
1574887Schin env_change();
1584887Schin return(1);
1594887Schin }
1604887Schin
1614887Schin /*
1624887Schin * delete name from <ep>
1634887Schin * The environment list may become invalidated
1644887Schin * Returns 1 for success, 0 for if name is not present
1654887Schin */
env_delete(Env_t * ep,const char * str)1664887Schin int env_delete(Env_t *ep, const char *str)
1674887Schin {
1684887Schin Evar_t *vp = (Evar_t*)dtmatch(ep->dt,(void*)str);
1694887Schin if(!vp)
1704887Schin return(0);
1714887Schin ep->flags &= ~ENV_VALID;
1724887Schin if(vp->index&ENV_PMALLOC)
1734887Schin free((void*)vp->un.ptr);
1744887Schin dtdelete(ep->dt,vp);
1754887Schin vp->un.next = ep->freelist;
1764887Schin ep->freelist = vp;
1774887Schin env_change();
1784887Schin return(1);
1794887Schin }
1804887Schin
1814887Schin /*
1824887Schin * open up a structure to support environment variables
1834887Schin * initialize with environment give by <envp>
1844887Schin * If <extra> > 0, <extra> slots will be left at beginning of
1854887Schin * environment list when env_get() is involed.
1864887Schin * If <extra>==ENV_USABLE, then the original environ can be
1874887Schin * used and returned. Otherwise, a new one will be returned
1884887Schin */
env_open(char ** envp,int extra)1894887Schin Env_t *env_open(char **envp, int extra)
1904887Schin {
1914887Schin char **env;
1924887Schin Env_t *ep;
1934887Schin Evar_t *vp;
1944887Schin int n=2;
1954887Schin if(!(ep = newof((Env_t*)0,Env_t,1,0)))
1964887Schin return(0);
1974887Schin if(!(ep->dt = dtopen(&env_disc,Dtoset)))
1984887Schin return(0);
1994887Schin if(env=envp)
2004887Schin {
2014887Schin while(*env++);
2024887Schin n = (env+2)-envp;
2034887Schin }
2044887Schin if(extra==ENV_STABLE)
2054887Schin {
2064887Schin ep->env = envp;
2074887Schin ep->max = n-1;
2084887Schin }
2094887Schin else
2104887Schin ep->count = ep->extra = extra;
2114887Schin ep->freelist = vp = newof((Evar_t*)0,Evar_t,n,0);
2124887Schin vp->index = ENV_VMALLOC;
2134887Schin while(--n>0)
2144887Schin {
2154887Schin vp->un.next = (vp+1);
2164887Schin vp++;
2174887Schin }
2184887Schin vp->un.next = 0;
2194887Schin if(env)
2204887Schin {
2214887Schin for(env=envp; *env; env++)
2224887Schin env_add(ep,*env,0);
2234887Schin }
2244887Schin return(ep);
2254887Schin }
2264887Schin
2274887Schin /*
2284887Schin * close <ep> and free up all space used by it
2294887Schin */
env_close(Env_t * ep)2304887Schin void env_close(Env_t *ep)
2314887Schin {
2324887Schin Evar_t *vp, *vpnext,*top;
2334887Schin if(ep->env && (ep->flags&ENV_MALLOCED))
2344887Schin free((void*)ep->env);
2354887Schin for(vp=(Evar_t*)dtfirst(ep->dt);vp; vp=vpnext)
2364887Schin {
2374887Schin vpnext = (Evar_t*)dtnext(ep->dt,vp);
2384887Schin env_delete(ep,vp->un.ptr);
2394887Schin }
2404887Schin for(top=0,vp = ep->freelist; vp; vp = vpnext)
2414887Schin {
2424887Schin vpnext = vp->un.next;
2434887Schin if(vp->index&ENV_VMALLOC)
2444887Schin {
2454887Schin vp->un.next = top;
2464887Schin top = vp;
2474887Schin }
2484887Schin }
2494887Schin for(vp=top; vp; vp = vpnext)
2504887Schin {
2514887Schin vpnext = vp->un.next;
2524887Schin free((void*)vp);
2534887Schin }
2544887Schin dtclose(ep->dt);
2554887Schin }
256