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