1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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