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