xref: /onnv-gate/usr/src/lib/libshell/common/sh/env.c (revision 12068:08a39a083754)
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