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