1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
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 */
compare(Dt_t * dt,Void_t * key1,Void_t * key2,Dtdisc_t * disc)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 */
env_get(Env_t * ep)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 */
env_add(Env_t * ep,const char * str,int flags)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 */
env_delete(Env_t * ep,const char * str)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 */
env_open(char ** envp,int extra)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 */
env_close(Env_t * ep)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