Rev 2714 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2714 | Rev 2782 | ||
---|---|---|---|
1 | /* $NetBSD: var.c,v 1.26 2000/12/20 00:15:10 cgd Exp $ */ |
1 | /* $NetBSD: var.c,v 1.26 2000/12/20 00:15:10 cgd Exp $ */ |
2 | 2 | ||
3 | /*- |
3 | /*- |
4 | * Copyright (c) 1991, 1993 |
4 | * Copyright (c) 1991, 1993 |
5 | * The Regents of the University of California. All rights reserved. |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
6 | * |
7 | * This code is derived from software contributed to Berkeley by |
7 | * This code is derived from software contributed to Berkeley by |
8 | * Kenneth Almquist. |
8 | * Kenneth Almquist. |
9 | * |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. All advertising materials mentioning features or use of this software |
18 | * 3. All advertising materials mentioning features or use of this software |
19 | * must display the following acknowledgement: |
19 | * must display the following acknowledgement: |
20 | * This product includes software developed by the University of |
20 | * This product includes software developed by the University of |
21 | * California, Berkeley and its contributors. |
21 | * California, Berkeley and its contributors. |
22 | * 4. Neither the name of the University nor the names of its contributors |
22 | * 4. Neither the name of the University nor the names of its contributors |
23 | * may be used to endorse or promote products derived from this software |
23 | * may be used to endorse or promote products derived from this software |
24 | * without specific prior written permission. |
24 | * without specific prior written permission. |
25 | * |
25 | * |
26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
36 | * SUCH DAMAGE. |
36 | * SUCH DAMAGE. |
37 | */ |
37 | */ |
38 | 38 | ||
39 | #include <sys/cdefs.h> |
39 | #include <sys/cdefs.h> |
40 | #ifndef lint |
40 | #ifndef lint |
41 | #if 0 |
41 | #if 0 |
42 | static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95"; |
42 | static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95"; |
43 | #else |
43 | #else |
44 | __RCSID("$NetBSD: var.c,v 1.26 2000/12/20 00:15:10 cgd Exp $"); |
44 | __RCSID("$NetBSD: var.c,v 1.26 2000/12/20 00:15:10 cgd Exp $"); |
45 | #endif |
45 | #endif |
46 | #endif /* not lint */ |
46 | #endif /* not lint */ |
47 | 47 | ||
48 | #include <unistd.h> |
48 | #include <unistd.h> |
49 | #include <stdlib.h> |
49 | #include <stdlib.h> |
50 | #include <paths.h> |
50 | #include <paths.h> |
51 | 51 | ||
52 | /* |
52 | /* |
53 | * Shell variables. |
53 | * Shell variables. |
54 | */ |
54 | */ |
55 | 55 | ||
56 | #include "shell.h" |
56 | #include "shell.h" |
57 | #include "output.h" |
57 | #include "output.h" |
58 | #include "expand.h" |
58 | #include "expand.h" |
59 | #include "nodes.h" /* for other headers */ |
59 | #include "nodes.h" /* for other headers */ |
60 | #include "eval.h" /* defines cmdenviron */ |
60 | #include "eval.h" /* defines cmdenviron */ |
61 | #include "exec.h" |
61 | #include "exec.h" |
62 | #include "syntax.h" |
62 | #include "syntax.h" |
63 | #include "options.h" |
63 | #include "options.h" |
64 | #include "mail.h" |
64 | #include "mail.h" |
65 | #include "var.h" |
65 | #include "var.h" |
66 | #include "memalloc.h" |
66 | #include "memalloc.h" |
67 | #include "error.h" |
67 | #include "error.h" |
68 | #include "mystring.h" |
68 | #include "mystring.h" |
69 | #include "parser.h" |
69 | #include "parser.h" |
70 | #ifndef SMALL |
70 | #ifndef SMALL |
71 | #include "myhistedit.h" |
71 | #include "myhistedit.h" |
72 | #endif |
72 | #endif |
73 | 73 | ||
74 | 74 | ||
75 | #define VTABSIZE 39 |
75 | #define VTABSIZE 39 |
76 | 76 | ||
77 | 77 | ||
78 | struct varinit { |
78 | struct varinit { |
79 | struct var *var; |
79 | struct var *var; |
80 | int flags; |
80 | int flags; |
81 | const char *text; |
81 | const char *text; |
82 | void (*func) (const char *); |
82 | void (*func) (const char *); |
83 | }; |
83 | }; |
84 | 84 | ||
85 | 85 | ||
86 | #if ATTY |
86 | #if ATTY |
87 | struct var vatty; |
87 | struct var vatty; |
88 | #endif |
88 | #endif |
89 | #ifndef SMALL |
89 | #ifndef SMALL |
90 | struct var vhistsize; |
90 | struct var vhistsize; |
91 | struct var vterm; |
91 | struct var vterm; |
92 | #endif |
92 | #endif |
93 | struct var vifs; |
93 | struct var vifs; |
94 | struct var vmail; |
94 | struct var vmail; |
95 | struct var vmpath; |
95 | struct var vmpath; |
96 | struct var vpath; |
96 | struct var vpath; |
97 | struct var vps1; |
97 | struct var vps1; |
98 | struct var vps2; |
98 | struct var vps2; |
99 | struct var vvers; |
99 | struct var vvers; |
100 | struct var voptind; |
100 | struct var voptind; |
101 | 101 | ||
102 | const struct varinit varinit[] = { |
102 | const struct varinit varinit[] = { |
103 | #if ATTY |
103 | #if ATTY |
104 | { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=", |
104 | { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=", |
105 | NULL }, |
105 | NULL }, |
106 | #endif |
106 | #endif |
107 | #ifndef SMALL |
107 | #ifndef SMALL |
108 | { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", |
108 | { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", |
109 | sethistsize }, |
109 | sethistsize }, |
110 | #endif |
110 | #endif |
111 | { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n", |
111 | { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n", |
112 | NULL }, |
112 | NULL }, |
113 | { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", |
113 | { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", |
114 | NULL }, |
114 | NULL }, |
115 | { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", |
115 | { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", |
116 | NULL }, |
116 | NULL }, |
117 | { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
117 | { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", |
118 | changepath }, |
118 | changepath }, |
119 | /* |
119 | /* |
120 | * vps1 depends on uid |
120 | * vps1 depends on uid |
121 | */ |
121 | */ |
122 | { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", |
122 | { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", |
123 | NULL }, |
123 | NULL }, |
124 | #ifndef SMALL |
124 | #ifndef SMALL |
125 | { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=", |
125 | { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=", |
126 | setterm }, |
126 | setterm }, |
127 | #endif |
127 | #endif |
128 | { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", |
128 | { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", |
129 | getoptsreset }, |
129 | getoptsreset }, |
130 | { NULL, 0, NULL, |
130 | { NULL, 0, NULL, |
131 | NULL } |
131 | NULL } |
132 | }; |
132 | }; |
133 | 133 | ||
134 | struct var *vartab[VTABSIZE]; |
134 | struct var *vartab[VTABSIZE]; |
135 | 135 | ||
136 | STATIC struct var **hashvar (const char *); |
136 | STATIC struct var **hashvar (const char *); |
137 | STATIC int varequal (const char *, const char *); |
137 | STATIC int varequal (const char *, const char *); |
138 | 138 | ||
139 | /* |
139 | /* |
140 | * Initialize the varable symbol tables and import the environment |
140 | * Initialize the varable symbol tables and import the environment |
141 | * Setting PWD added by herbert |
141 | * Setting PWD added by herbert |
142 | */ |
142 | */ |
143 | 143 | ||
144 | #ifdef mkinit |
144 | #ifdef mkinit |
145 | INCLUDE "cd.h" |
145 | INCLUDE "cd.h" |
146 | INCLUDE "var.h" |
146 | INCLUDE "var.h" |
147 | INIT { |
147 | INIT { |
148 | char **envp; |
148 | char **envp; |
149 | extern char **environ; |
149 | extern char **environ; |
150 | extern char *curdir; |
150 | extern char *curdir; |
151 | 151 | ||
152 | initvar(); |
152 | initvar(); |
153 | for (envp = environ ; *envp ; envp++) { |
153 | for (envp = environ ; *envp ; envp++) { |
154 | if (strchr(*envp, '=')) { |
154 | if (strchr(*envp, '=')) { |
155 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
155 | setvareq(*envp, VEXPORT|VTEXTFIXED); |
156 | } |
156 | } |
157 | } |
157 | } |
158 | 158 | ||
159 | getpwd(); |
159 | getpwd(); |
160 | setvar("PWD", curdir, VEXPORT|VTEXTFIXED); |
160 | setvar("PWD", curdir, VEXPORT|VTEXTFIXED); |
161 | } |
161 | } |
162 | #endif |
162 | #endif |
163 | 163 | ||
164 | 164 | ||
165 | /* |
165 | /* |
166 | * This routine initializes the builtin variables. It is called when the |
166 | * This routine initializes the builtin variables. It is called when the |
167 | * shell is initialized and again when a shell procedure is spawned. |
167 | * shell is initialized and again when a shell procedure is spawned. |
168 | */ |
168 | */ |
169 | 169 | ||
170 | void |
170 | void |
171 | initvar() { |
171 | initvar() { |
172 | const struct varinit *ip; |
172 | const struct varinit *ip; |
173 | struct var *vp; |
173 | struct var *vp; |
174 | struct var **vpp; |
174 | struct var **vpp; |
175 | char ppid[30]; |
175 | char ppid[30]; |
176 | 176 | ||
177 | for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { |
177 | for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { |
178 | if ((vp->flags & VEXPORT) == 0) { |
178 | if ((vp->flags & VEXPORT) == 0) { |
179 | vpp = hashvar(ip->text); |
179 | vpp = hashvar(ip->text); |
180 | vp->next = *vpp; |
180 | vp->next = *vpp; |
181 | *vpp = vp; |
181 | *vpp = vp; |
182 | vp->text = strdup(ip->text); |
182 | vp->text = strdup(ip->text); |
183 | vp->flags = ip->flags; |
183 | vp->flags = ip->flags; |
184 | vp->func = ip->func; |
184 | vp->func = ip->func; |
185 | } |
185 | } |
186 | } |
186 | } |
187 | /* |
187 | /* |
188 | * PS1 depends on uid |
188 | * PS1 depends on uid |
189 | */ |
189 | */ |
190 | if ((vps1.flags & VEXPORT) == 0) { |
190 | if ((vps1.flags & VEXPORT) == 0) { |
191 | vpp = hashvar("PS1="); |
191 | vpp = hashvar("PS1="); |
192 | vps1.next = *vpp; |
192 | vps1.next = *vpp; |
193 | *vpp = &vps1; |
193 | *vpp = &vps1; |
194 | vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# "); |
194 | vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# "); |
195 | vps1.flags = VSTRFIXED|VTEXTFIXED; |
195 | vps1.flags = VSTRFIXED|VTEXTFIXED; |
196 | } |
196 | } |
197 | 197 | ||
198 | snprintf(ppid, 29, "%ld", (long)getppid()); |
198 | snprintf(ppid, 29, "%ld", (long)getppid()); |
199 | setvar("PPID", ppid, VREADONLY|VNOFUNC); |
199 | setvar("PPID", ppid, VREADONLY|VNOFUNC); |
200 | } |
200 | } |
201 | 201 | ||
202 | /* |
202 | /* |
203 | * Safe version of setvar, returns 1 on success 0 on failure. |
203 | * Safe version of setvar, returns 1 on success 0 on failure. |
204 | */ |
204 | */ |
205 | 205 | ||
206 | int |
206 | int |
207 | setvarsafe(name, val, flags) |
207 | setvarsafe(name, val, flags) |
208 | const char *name, *val; |
208 | const char *name, *val; |
209 | int flags; |
209 | int flags; |
210 | { |
210 | { |
211 | struct jmploc jmploc; |
211 | struct jmploc jmploc; |
212 | struct jmploc *volatile savehandler = handler; |
212 | struct jmploc *volatile savehandler = handler; |
213 | int err = 0; |
213 | int err = 0; |
214 | #ifdef __GNUC__ |
214 | #ifdef __GNUC__ |
215 | (void) &err; |
215 | (void) &err; |
216 | #endif |
216 | #endif |
217 | 217 | ||
218 | if (setjmp(jmploc.loc)) |
218 | if (setjmp(jmploc.loc)) |
219 | err = 1; |
219 | err = 1; |
220 | else { |
220 | else { |
221 | handler = &jmploc; |
221 | handler = &jmploc; |
222 | setvar(name, val, flags); |
222 | setvar(name, val, flags); |
223 | } |
223 | } |
224 | handler = savehandler; |
224 | handler = savehandler; |
225 | return err; |
225 | return err; |
226 | } |
226 | } |
227 | 227 | ||
228 | /* |
228 | /* |
229 | * Set the value of a variable. The flags argument is ored with the |
229 | * Set the value of a variable. The flags argument is ored with the |
230 | * flags of the variable. If val is NULL, the variable is unset. |
230 | * flags of the variable. If val is NULL, the variable is unset. |
231 | */ |
231 | */ |
232 | 232 | ||
233 | void |
233 | void |
234 | setvar(name, val, flags) |
234 | setvar(name, val, flags) |
235 | const char *name, *val; |
235 | const char *name, *val; |
236 | int flags; |
236 | int flags; |
237 | { |
237 | { |
238 | const char *p; |
238 | const char *p; |
239 | const char *q; |
239 | const char *q; |
240 | char *d; |
240 | char *d; |
241 | int len; |
241 | int len; |
242 | int namelen; |
242 | int namelen; |
243 | char *nameeq; |
243 | char *nameeq; |
244 | int isbad; |
244 | int isbad; |
245 | 245 | ||
246 | isbad = 0; |
246 | isbad = 0; |
247 | p = name; |
247 | p = name; |
248 | if (! is_name(*p)) |
248 | if (! is_name(*p)) |
249 | isbad = 1; |
249 | isbad = 1; |
250 | p++; |
250 | p++; |
251 | for (;;) { |
251 | for (;;) { |
252 | if (! is_in_name(*p)) { |
252 | if (! is_in_name(*p)) { |
253 | if (*p == '\0' || *p == '=') |
253 | if (*p == '\0' || *p == '=') |
254 | break; |
254 | break; |
255 | isbad = 1; |
255 | isbad = 1; |
256 | } |
256 | } |
257 | p++; |
257 | p++; |
258 | } |
258 | } |
259 | namelen = p - name; |
259 | namelen = p - name; |
260 | if (isbad) |
260 | if (isbad) |
261 | error("%.*s: bad variable name", namelen, name); |
261 | error("%.*s: bad variable name", namelen, name); |
262 | len = namelen + 2; /* 2 is space for '=' and '\0' */ |
262 | len = namelen + 2; /* 2 is space for '=' and '\0' */ |
263 | if (val == NULL) { |
263 | if (val == NULL) { |
264 | flags |= VUNSET; |
264 | flags |= VUNSET; |
265 | } else { |
265 | } else { |
266 | len += strlen(val); |
266 | len += strlen(val); |
267 | } |
267 | } |
268 | d = nameeq = ckmalloc(len); |
268 | d = nameeq = ckmalloc(len); |
269 | q = name; |
269 | q = name; |
270 | while (--namelen >= 0) |
270 | while (--namelen >= 0) |
271 | *d++ = *q++; |
271 | *d++ = *q++; |
272 | *d++ = '='; |
272 | *d++ = '='; |
273 | *d = '\0'; |
273 | *d = '\0'; |
274 | if (val) |
274 | if (val) |
275 | scopy(val, d); |
275 | scopy(val, d); |
276 | setvareq(nameeq, flags); |
276 | setvareq(nameeq, flags); |
277 | } |
277 | } |
278 | 278 | ||
279 | 279 | ||
280 | 280 | ||
281 | /* |
281 | /* |
282 | * Same as setvar except that the variable and value are passed in |
282 | * Same as setvar except that the variable and value are passed in |
283 | * the first argument as name=value. Since the first argument will |
283 | * the first argument as name=value. Since the first argument will |
284 | * be actually stored in the table, it should not be a string that |
284 | * be actually stored in the table, it should not be a string that |
285 | * will go away. |
285 | * will go away. |
286 | */ |
286 | */ |
287 | 287 | ||
288 | void |
288 | void |
289 | setvareq(s, flags) |
289 | setvareq(s, flags) |
290 | char *s; |
290 | char *s; |
291 | int flags; |
291 | int flags; |
292 | { |
292 | { |
293 | struct var *vp, **vpp; |
293 | struct var *vp, **vpp; |
294 | 294 | ||
295 | vpp = hashvar(s); |
295 | vpp = hashvar(s); |
296 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); |
296 | flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); |
297 | for (vp = *vpp ; vp ; vp = vp->next) { |
297 | for (vp = *vpp ; vp ; vp = vp->next) { |
298 | if (varequal(s, vp->text)) { |
298 | if (varequal(s, vp->text)) { |
299 | if (vp->flags & VREADONLY) { |
299 | if (vp->flags & VREADONLY) { |
300 | size_t len = strchr(s, '=') - s; |
300 | size_t len = strchr(s, '=') - s; |
301 | error("%.*s: is read only", len, s); |
301 | error("%.*s: is read only", len, s); |
302 | } |
302 | } |
303 | INTOFF; |
303 | INTOFF; |
304 | 304 | ||
305 | if (vp->func && (flags & VNOFUNC) == 0) |
305 | if (vp->func && (flags & VNOFUNC) == 0) |
306 | (*vp->func)(strchr(s, '=') + 1); |
306 | (*vp->func)(strchr(s, '=') + 1); |
307 | 307 | ||
308 | if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) |
308 | if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) |
309 | ckfree(vp->text); |
309 | ckfree(vp->text); |
310 | 310 | ||
311 | vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); |
311 | vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); |
312 | vp->flags |= flags; |
312 | vp->flags |= flags; |
313 | vp->text = s; |
313 | vp->text = s; |
314 | 314 | ||
315 | /* |
315 | /* |
316 | * We could roll this to a function, to handle it as |
316 | * We could roll this to a function, to handle it as |
317 | * a regular variable function callback, but why bother? |
317 | * a regular variable function callback, but why bother? |
318 | */ |
318 | */ |
319 | if (iflag && |
319 | if (iflag && |
320 | (vp == &vmpath || (vp == &vmail && ! mpathset()))) |
320 | (vp == &vmpath || (vp == &vmail && ! mpathset()))) |
321 | chkmail(1); |
321 | chkmail(1); |
322 | INTON; |
322 | INTON; |
323 | return; |
323 | return; |
324 | } |
324 | } |
325 | } |
325 | } |
326 | /* not found */ |
326 | /* not found */ |
327 | vp = ckmalloc(sizeof (*vp)); |
327 | vp = ckmalloc(sizeof (*vp)); |
328 | vp->flags = flags; |
328 | vp->flags = flags; |
329 | vp->text = s; |
329 | vp->text = s; |
330 | vp->next = *vpp; |
330 | vp->next = *vpp; |
331 | vp->func = NULL; |
331 | vp->func = NULL; |
332 | *vpp = vp; |
332 | *vpp = vp; |
333 | } |
333 | } |
334 | 334 | ||
335 | 335 | ||
336 | 336 | ||
337 | /* |
337 | /* |
338 | * Process a linked list of variable assignments. |
338 | * Process a linked list of variable assignments. |
339 | */ |
339 | */ |
340 | 340 | ||
341 | void |
341 | void |
342 | listsetvar(list) |
342 | listsetvar(list) |
343 | struct strlist *list; |
343 | struct strlist *list; |
344 | { |
344 | { |
345 | struct strlist *lp; |
345 | struct strlist *lp; |
346 | 346 | ||
347 | INTOFF; |
347 | INTOFF; |
348 | for (lp = list ; lp ; lp = lp->next) { |
348 | for (lp = list ; lp ; lp = lp->next) { |
349 | setvareq(savestr(lp->text), 0); |
349 | setvareq(savestr(lp->text), 0); |
350 | } |
350 | } |
351 | INTON; |
351 | INTON; |
352 | } |
352 | } |
353 | 353 | ||
354 | 354 | ||
355 | 355 | ||
356 | /* |
356 | /* |
357 | * Find the value of a variable. Returns NULL if not set. |
357 | * Find the value of a variable. Returns NULL if not set. |
358 | */ |
358 | */ |
359 | 359 | ||
360 | char * |
360 | char * |
361 | lookupvar(name) |
361 | lookupvar(name) |
362 | const char *name; |
362 | const char *name; |
363 | { |
363 | { |
364 | struct var *v; |
364 | struct var *v; |
365 | 365 | ||
366 | for (v = *hashvar(name) ; v ; v = v->next) { |
366 | for (v = *hashvar(name) ; v ; v = v->next) { |
367 | if (varequal(v->text, name)) { |
367 | if (varequal(v->text, name)) { |
368 | if (v->flags & VUNSET) |
368 | if (v->flags & VUNSET) |
369 | return NULL; |
369 | return NULL; |
370 | return strchr(v->text, '=') + 1; |
370 | return strchr(v->text, '=') + 1; |
371 | } |
371 | } |
372 | } |
372 | } |
373 | return NULL; |
373 | return NULL; |
374 | } |
374 | } |
375 | 375 | ||
376 | 376 | ||
377 | 377 | ||
378 | /* |
378 | /* |
379 | * Search the environment of a builtin command. If the second argument |
379 | * Search the environment of a builtin command. If the second argument |
380 | * is nonzero, return the value of a variable even if it hasn't been |
380 | * is nonzero, return the value of a variable even if it hasn't been |
381 | * exported. |
381 | * exported. |
382 | */ |
382 | */ |
383 | 383 | ||
384 | char * |
384 | char * |
385 | bltinlookup(name, doall) |
385 | bltinlookup(name, doall) |
386 | const char *name; |
386 | const char *name; |
387 | int doall; |
387 | int doall; |
388 | { |
388 | { |
389 | struct strlist *sp; |
389 | struct strlist *sp; |
390 | struct var *v; |
390 | struct var *v; |
391 | 391 | ||
392 | for (sp = cmdenviron ; sp ; sp = sp->next) { |
392 | for (sp = cmdenviron ; sp ; sp = sp->next) { |
393 | if (varequal(sp->text, name)) |
393 | if (varequal(sp->text, name)) |
394 | return strchr(sp->text, '=') + 1; |
394 | return strchr(sp->text, '=') + 1; |
395 | } |
395 | } |
396 | for (v = *hashvar(name) ; v ; v = v->next) { |
396 | for (v = *hashvar(name) ; v ; v = v->next) { |
397 | if (varequal(v->text, name)) { |
397 | if (varequal(v->text, name)) { |
398 | if ((v->flags & VUNSET) |
398 | if ((v->flags & VUNSET) |
399 | || (!doall && (v->flags & VEXPORT) == 0)) |
399 | || (!doall && (v->flags & VEXPORT) == 0)) |
400 | return NULL; |
400 | return NULL; |
401 | return strchr(v->text, '=') + 1; |
401 | return strchr(v->text, '=') + 1; |
402 | } |
402 | } |
403 | } |
403 | } |
404 | return NULL; |
404 | return NULL; |
405 | } |
405 | } |
406 | 406 | ||
407 | 407 | ||
408 | 408 | ||
409 | /* |
409 | /* |
410 | * Generate a list of exported variables. This routine is used to construct |
410 | * Generate a list of exported variables. This routine is used to construct |
411 | * the third argument to execve when executing a program. |
411 | * the third argument to execve when executing a program. |
412 | */ |
412 | */ |
413 | 413 | ||
414 | char ** |
414 | char ** |
415 | environment() { |
415 | environment() { |
416 | int nenv; |
416 | int nenv; |
417 | struct var **vpp; |
417 | struct var **vpp; |
418 | struct var *vp; |
418 | struct var *vp; |
419 | char **env; |
419 | char **env; |
420 | char **ep; |
420 | char **ep; |
421 | 421 | ||
422 | nenv = 0; |
422 | nenv = 0; |
423 | for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { |
423 | for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { |
424 | for (vp = *vpp ; vp ; vp = vp->next) |
424 | for (vp = *vpp ; vp ; vp = vp->next) |
425 | if (vp->flags & VEXPORT) |
425 | if (vp->flags & VEXPORT) |
426 | nenv++; |
426 | nenv++; |
427 | } |
427 | } |
428 | ep = env = stalloc((nenv + 1) * sizeof *env); |
428 | ep = env = stalloc((nenv + 1) * sizeof *env); |
429 | for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { |
429 | for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { |
430 | for (vp = *vpp ; vp ; vp = vp->next) |
430 | for (vp = *vpp ; vp ; vp = vp->next) |
431 | if (vp->flags & VEXPORT) |
431 | if (vp->flags & VEXPORT) |
432 | *ep++ = vp->text; |
432 | *ep++ = vp->text; |
433 | } |
433 | } |
434 | *ep = NULL; |
434 | *ep = NULL; |
435 | return env; |
435 | return env; |
436 | } |
436 | } |
437 | 437 | ||
438 | 438 | ||
439 | /* |
439 | /* |
440 | * Called when a shell procedure is invoked to clear out nonexported |
440 | * Called when a shell procedure is invoked to clear out nonexported |
441 | * variables. It is also necessary to reallocate variables of with |
441 | * variables. It is also necessary to reallocate variables of with |
442 | * VSTACK set since these are currently allocated on the stack. |
442 | * VSTACK set since these are currently allocated on the stack. |
443 | */ |
443 | */ |
444 | 444 | ||
445 | #ifdef mkinit |
445 | #ifdef mkinit |
446 | MKINIT void shprocvar (void); |
446 | MKINIT void shprocvar (void); |
447 | 447 | ||
448 | SHELLPROC { |
448 | SHELLPROC { |
449 | shprocvar(); |
449 | shprocvar(); |
450 | } |
450 | } |
451 | #endif |
451 | #endif |
452 | 452 | ||
453 | void |
453 | void |
454 | shprocvar() { |
454 | shprocvar() { |
455 | struct var **vpp; |
455 | struct var **vpp; |
456 | struct var *vp, **prev; |
456 | struct var *vp, **prev; |
457 | 457 | ||
458 | for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { |
458 | for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { |
459 | for (prev = vpp ; (vp = *prev) != NULL ; ) { |
459 | for (prev = vpp ; (vp = *prev) != NULL ; ) { |
460 | if ((vp->flags & VEXPORT) == 0) { |
460 | if ((vp->flags & VEXPORT) == 0) { |
461 | *prev = vp->next; |
461 | *prev = vp->next; |
462 | if ((vp->flags & VTEXTFIXED) == 0) |
462 | if ((vp->flags & VTEXTFIXED) == 0) |
463 | ckfree(vp->text); |
463 | ckfree(vp->text); |
464 | if ((vp->flags & VSTRFIXED) == 0) |
464 | if ((vp->flags & VSTRFIXED) == 0) |
465 | ckfree(vp); |
465 | ckfree(vp); |
466 | } else { |
466 | } else { |
467 | if (vp->flags & VSTACK) { |
467 | if (vp->flags & VSTACK) { |
468 | vp->text = savestr(vp->text); |
468 | vp->text = savestr(vp->text); |
469 | vp->flags &=~ VSTACK; |
469 | vp->flags &=~ VSTACK; |
470 | } |
470 | } |
471 | prev = &vp->next; |
471 | prev = &vp->next; |
472 | } |
472 | } |
473 | } |
473 | } |
474 | } |
474 | } |
475 | initvar(); |
475 | initvar(); |
476 | } |
476 | } |
477 | 477 | ||
478 | 478 | ||
479 | 479 | ||
480 | /* |
480 | /* |
481 | * Command to list all variables which are set. Currently this command |
481 | * Command to list all variables which are set. Currently this command |
482 | * is invoked from the set command when the set command is called without |
482 | * is invoked from the set command when the set command is called without |
483 | * any variables. |
483 | * any variables. |
484 | */ |
484 | */ |
485 | 485 | ||
486 | int |
486 | int |
487 | showvarscmd(argc, argv) |
487 | showvarscmd(argc, argv) |
488 | int argc; |
488 | int argc; |
489 | char **argv; |
489 | char **argv; |
490 | { |
490 | { |
491 | struct var **vpp; |
491 | struct var **vpp; |
492 | struct var *vp; |
492 | struct var *vp; |
493 | 493 | ||
494 | for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { |
494 | for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { |
495 | for (vp = *vpp ; vp ; vp = vp->next) { |
495 | for (vp = *vpp ; vp ; vp = vp->next) { |
496 | if ((vp->flags & VUNSET) == 0) |
496 | if ((vp->flags & VUNSET) == 0) |
497 | out1fmt("%s\n", vp->text); |
497 | out1fmt("%s\n", vp->text); |
498 | } |
498 | } |
499 | } |
499 | } |
500 | return 0; |
500 | return 0; |
501 | } |
501 | } |
502 | 502 | ||
503 | 503 | ||
504 | 504 | ||
505 | /* |
505 | /* |
506 | * The export and readonly commands. |
506 | * The export and readonly commands. |
507 | */ |
507 | */ |
508 | 508 | ||
509 | int |
509 | int |
510 | exportcmd(argc, argv) |
510 | exportcmd(argc, argv) |
511 | int argc; |
511 | int argc; |
512 | char **argv; |
512 | char **argv; |
513 | { |
513 | { |
514 | struct var **vpp; |
514 | struct var **vpp; |
515 | struct var *vp; |
515 | struct var *vp; |
516 | char *name; |
516 | char *name; |
517 | const char *p; |
517 | const char *p; |
518 | int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; |
518 | int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; |
519 | int pflag; |
519 | int pflag; |
520 | 520 | ||
521 | listsetvar(cmdenviron); |
521 | listsetvar(cmdenviron); |
522 | pflag = (nextopt("p") == 'p'); |
522 | pflag = (nextopt("p") == 'p'); |
523 | if (argc > 1 && !pflag) { |
523 | if (argc > 1 && !pflag) { |
524 | while ((name = *argptr++) != NULL) { |
524 | while ((name = *argptr++) != NULL) { |
525 | if ((p = strchr(name, '=')) != NULL) { |
525 | if ((p = strchr(name, '=')) != NULL) { |
526 | p++; |
526 | p++; |
527 | } else { |
527 | } else { |
528 | vpp = hashvar(name); |
528 | vpp = hashvar(name); |
529 | for (vp = *vpp ; vp ; vp = vp->next) { |
529 | for (vp = *vpp ; vp ; vp = vp->next) { |
530 | if (varequal(vp->text, name)) { |
530 | if (varequal(vp->text, name)) { |
531 | vp->flags |= flag; |
531 | vp->flags |= flag; |
532 | goto found; |
532 | goto found; |
533 | } |
533 | } |
534 | } |
534 | } |
535 | } |
535 | } |
536 | setvar(name, p, flag); |
536 | setvar(name, p, flag); |
537 | found:; |
537 | found:; |
538 | } |
538 | } |
539 | } else { |
539 | } else { |
540 | for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { |
540 | for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { |
541 | for (vp = *vpp ; vp ; vp = vp->next) { |
541 | for (vp = *vpp ; vp ; vp = vp->next) { |
542 | if ((vp->flags & flag) == 0) |
542 | if ((vp->flags & flag) == 0) |
543 | continue; |
543 | continue; |
544 | if (pflag) { |
544 | if (pflag) { |
545 | out1fmt("%s %s\n", argv[0], vp->text); |
545 | out1fmt("%s %s\n", argv[0], vp->text); |
546 | } else { |
546 | } else { |
547 | for (p = vp->text ; *p != '=' ; p++) |
547 | for (p = vp->text ; *p != '=' ; p++) |
548 | out1c(*p); |
548 | out1c(*p); |
549 | out1c('\n'); |
549 | out1c('\n'); |
550 | } |
550 | } |
551 | } |
551 | } |
552 | } |
552 | } |
553 | } |
553 | } |
554 | return 0; |
554 | return 0; |
555 | } |
555 | } |
556 | 556 | ||
557 | 557 | ||
558 | /* |
558 | /* |
559 | * The "local" command. |
559 | * The "local" command. |
560 | */ |
560 | */ |
561 | 561 | ||
562 | int |
562 | int |
563 | localcmd(argc, argv) |
563 | localcmd(argc, argv) |
564 | int argc; |
564 | int argc; |
565 | char **argv; |
565 | char **argv; |
566 | { |
566 | { |
567 | char *name; |
567 | char *name; |
568 | 568 | ||
569 | if (! in_function()) |
569 | if (! in_function()) |
570 | error("Not in a function"); |
570 | error("Not in a function"); |
571 | while ((name = *argptr++) != NULL) { |
571 | while ((name = *argptr++) != NULL) { |
572 | mklocal(name); |
572 | mklocal(name); |
573 | } |
573 | } |
574 | return 0; |
574 | return 0; |
575 | } |
575 | } |
576 | 576 | ||
577 | 577 | ||
578 | /* |
578 | /* |
579 | * Make a variable a local variable. When a variable is made local, it's |
579 | * Make a variable a local variable. When a variable is made local, it's |
580 | * value and flags are saved in a localvar structure. The saved values |
580 | * value and flags are saved in a localvar structure. The saved values |
581 | * will be restored when the shell function returns. We handle the name |
581 | * will be restored when the shell function returns. We handle the name |
582 | * "-" as a special case. |
582 | * "-" as a special case. |
583 | */ |
583 | */ |
584 | 584 | ||
585 | void |
585 | void |
586 | mklocal(name) |
586 | mklocal(name) |
587 | char *name; |
587 | char *name; |
588 | { |
588 | { |
589 | struct localvar *lvp; |
589 | struct localvar *lvp; |
590 | struct var **vpp; |
590 | struct var **vpp; |
591 | struct var *vp; |
591 | struct var *vp; |
592 | 592 | ||
593 | INTOFF; |
593 | INTOFF; |
594 | lvp = ckmalloc(sizeof (struct localvar)); |
594 | lvp = ckmalloc(sizeof (struct localvar)); |
595 | if (name[0] == '-' && name[1] == '\0') { |
595 | if (name[0] == '-' && name[1] == '\0') { |
596 | char *p; |
596 | char *p; |
597 | p = ckmalloc(sizeof optlist); |
597 | p = ckmalloc(sizeof optlist); |
598 | lvp->text = memcpy(p, optlist, sizeof optlist); |
598 | lvp->text = memcpy(p, optlist, sizeof optlist); |
599 | vp = NULL; |
599 | vp = NULL; |
600 | } else { |
600 | } else { |
601 | vpp = hashvar(name); |
601 | vpp = hashvar(name); |
602 | for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next); |
602 | for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next); |
603 | if (vp == NULL) { |
603 | if (vp == NULL) { |
604 | if (strchr(name, '=')) |
604 | if (strchr(name, '=')) |
605 | setvareq(savestr(name), VSTRFIXED); |
605 | setvareq(savestr(name), VSTRFIXED); |
606 | else |
606 | else |
607 | setvar(name, NULL, VSTRFIXED); |
607 | setvar(name, NULL, VSTRFIXED); |
608 | vp = *vpp; /* the new variable */ |
608 | vp = *vpp; /* the new variable */ |
609 | lvp->text = NULL; |
609 | lvp->text = NULL; |
610 | lvp->flags = VUNSET; |
610 | lvp->flags = VUNSET; |
611 | } else { |
611 | } else { |
612 | lvp->text = vp->text; |
612 | lvp->text = vp->text; |
613 | lvp->flags = vp->flags; |
613 | lvp->flags = vp->flags; |
614 | vp->flags |= VSTRFIXED|VTEXTFIXED; |
614 | vp->flags |= VSTRFIXED|VTEXTFIXED; |
615 | if (strchr(name, '=')) |
615 | if (strchr(name, '=')) |
616 | setvareq(savestr(name), 0); |
616 | setvareq(savestr(name), 0); |
617 | } |
617 | } |
618 | } |
618 | } |
619 | lvp->vp = vp; |
619 | lvp->vp = vp; |
620 | lvp->next = localvars; |
620 | lvp->next = localvars; |
621 | localvars = lvp; |
621 | localvars = lvp; |
622 | INTON; |
622 | INTON; |
623 | } |
623 | } |
624 | 624 | ||
625 | 625 | ||
626 | /* |
626 | /* |
627 | * Called after a function returns. |
627 | * Called after a function returns. |
628 | */ |
628 | */ |
629 | 629 | ||
630 | void |
630 | void |
631 | poplocalvars() { |
631 | poplocalvars() { |
632 | struct localvar *lvp; |
632 | struct localvar *lvp; |
633 | struct var *vp; |
633 | struct var *vp; |
634 | 634 | ||
635 | while ((lvp = localvars) != NULL) { |
635 | while ((lvp = localvars) != NULL) { |
636 | localvars = lvp->next; |
636 | localvars = lvp->next; |
637 | vp = lvp->vp; |
637 | vp = lvp->vp; |
638 | if (vp == NULL) { /* $- saved */ |
638 | if (vp == NULL) { /* $- saved */ |
639 | memcpy(optlist, lvp->text, sizeof optlist); |
639 | memcpy(optlist, lvp->text, sizeof optlist); |
640 | ckfree(lvp->text); |
640 | ckfree(lvp->text); |
641 | } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { |
641 | } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { |
642 | (void)unsetvar(vp->text); |
642 | (void)unsetvar(vp->text); |
643 | } else { |
643 | } else { |
644 | if ((vp->flags & VTEXTFIXED) == 0) |
644 | if ((vp->flags & VTEXTFIXED) == 0) |
645 | ckfree(vp->text); |
645 | ckfree(vp->text); |
646 | vp->flags = lvp->flags; |
646 | vp->flags = lvp->flags; |
647 | vp->text = lvp->text; |
647 | vp->text = lvp->text; |
648 | } |
648 | } |
649 | ckfree(lvp); |
649 | ckfree(lvp); |
650 | } |
650 | } |
651 | } |
651 | } |
652 | 652 | ||
653 | 653 | ||
654 | int |
654 | int |
655 | setvarcmd(argc, argv) |
655 | setvarcmd(argc, argv) |
656 | int argc; |
656 | int argc; |
657 | char **argv; |
657 | char **argv; |
658 | { |
658 | { |
659 | if (argc <= 2) |
659 | if (argc <= 2) |
660 | return unsetcmd(argc, argv); |
660 | return unsetcmd(argc, argv); |
661 | else if (argc == 3) |
661 | else if (argc == 3) |
662 | setvar(argv[1], argv[2], 0); |
662 | setvar(argv[1], argv[2], 0); |
663 | else |
663 | else |
664 | error("List assignment not implemented"); |
664 | error("List assignment not implemented"); |
665 | return 0; |
665 | return 0; |
666 | } |
666 | } |
667 | 667 | ||
668 | 668 | ||
669 | /* |
669 | /* |
670 | * The unset builtin command. We unset the function before we unset the |
670 | * The unset builtin command. We unset the function before we unset the |
671 | * variable to allow a function to be unset when there is a readonly variable |
671 | * variable to allow a function to be unset when there is a readonly variable |
672 | * with the same name. |
672 | * with the same name. |
673 | */ |
673 | */ |
674 | 674 | ||
675 | int |
675 | int |
676 | unsetcmd(argc, argv) |
676 | unsetcmd(argc, argv) |
677 | int argc; |
677 | int argc; |
678 | char **argv; |
678 | char **argv; |
679 | { |
679 | { |
680 | char **ap; |
680 | char **ap; |
681 | int i; |
681 | int i; |
682 | int flg_func = 0; |
682 | int flg_func = 0; |
683 | int flg_var = 0; |
683 | int flg_var = 0; |
684 | int ret = 0; |
684 | int ret = 0; |
685 | 685 | ||
686 | while ((i = nextopt("vf")) != '\0') { |
686 | while ((i = nextopt("vf")) != '\0') { |
687 | if (i == 'f') |
687 | if (i == 'f') |
688 | flg_func = 1; |
688 | flg_func = 1; |
689 | else |
689 | else |
690 | flg_var = 1; |
690 | flg_var = 1; |
691 | } |
691 | } |
692 | if (flg_func == 0 && flg_var == 0) |
692 | if (flg_func == 0 && flg_var == 0) |
693 | flg_var = 1; |
693 | flg_var = 1; |
694 | 694 | ||
695 | for (ap = argptr; *ap ; ap++) { |
695 | for (ap = argptr; *ap ; ap++) { |
696 | if (flg_func) |
696 | if (flg_func) |
697 | ret |= unsetfunc(*ap); |
697 | ret |= unsetfunc(*ap); |
698 | if (flg_var) |
698 | if (flg_var) |
699 | ret |= unsetvar(*ap); |
699 | ret |= unsetvar(*ap); |
700 | } |
700 | } |
701 | return ret; |
701 | return ret; |
702 | } |
702 | } |
703 | 703 | ||
704 | 704 | ||
705 | /* |
705 | /* |
706 | * Unset the specified variable. |
706 | * Unset the specified variable. |
707 | */ |
707 | */ |
708 | 708 | ||
709 | int |
709 | int |
710 | unsetvar(s) |
710 | unsetvar(s) |
711 | const char *s; |
711 | const char *s; |
712 | { |
712 | { |
713 | struct var **vpp; |
713 | struct var **vpp; |
714 | struct var *vp; |
714 | struct var *vp; |
715 | 715 | ||
716 | vpp = hashvar(s); |
716 | vpp = hashvar(s); |
717 | for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { |
717 | for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { |
718 | if (varequal(vp->text, s)) { |
718 | if (varequal(vp->text, s)) { |
719 | if (vp->flags & VREADONLY) |
719 | if (vp->flags & VREADONLY) |
720 | return (1); |
720 | return (1); |
721 | INTOFF; |
721 | INTOFF; |
722 | if (*(strchr(vp->text, '=') + 1) != '\0') |
722 | if (*(strchr(vp->text, '=') + 1) != '\0') |
723 | setvar(s, nullstr, 0); |
723 | setvar(s, nullstr, 0); |
724 | vp->flags &= ~VEXPORT; |
724 | vp->flags &= ~VEXPORT; |
725 | vp->flags |= VUNSET; |
725 | vp->flags |= VUNSET; |
726 | if ((vp->flags & VSTRFIXED) == 0) { |
726 | if ((vp->flags & VSTRFIXED) == 0) { |
727 | if ((vp->flags & VTEXTFIXED) == 0) |
727 | if ((vp->flags & VTEXTFIXED) == 0) |
728 | ckfree(vp->text); |
728 | ckfree(vp->text); |
729 | *vpp = vp->next; |
729 | *vpp = vp->next; |
730 | ckfree(vp); |
730 | ckfree(vp); |
731 | } |
731 | } |
732 | INTON; |
732 | INTON; |
733 | return (0); |
733 | return (0); |
734 | } |
734 | } |
735 | } |
735 | } |
736 | 736 | ||
737 | return (1); |
737 | return (1); |
738 | } |
738 | } |
739 | 739 | ||
740 | 740 | ||
741 | 741 | ||
742 | /* |
742 | /* |
743 | * Find the appropriate entry in the hash table from the name. |
743 | * Find the appropriate entry in the hash table from the name. |
744 | */ |
744 | */ |
745 | 745 | ||
746 | STATIC struct var ** |
746 | STATIC struct var ** |
747 | hashvar(p) |
747 | hashvar(p) |
748 | const char *p; |
748 | const char *p; |
749 | { |
749 | { |
750 | unsigned int hashval; |
750 | unsigned int hashval; |
751 | 751 | ||
752 | hashval = ((unsigned char) *p) << 4; |
752 | hashval = ((unsigned char) *p) << 4; |
753 | while (*p && *p != '=') |
753 | while (*p && *p != '=') |
754 | hashval += (unsigned char) *p++; |
754 | hashval += (unsigned char) *p++; |
755 | return &vartab[hashval % VTABSIZE]; |
755 | return &vartab[hashval % VTABSIZE]; |
756 | } |
756 | } |
757 | 757 | ||
758 | 758 | ||
759 | 759 | ||
760 | /* |
760 | /* |
761 | * Returns true if the two strings specify the same varable. The first |
761 | * Returns true if the two strings specify the same varable. The first |
762 | * variable name is terminated by '='; the second may be terminated by |
762 | * variable name is terminated by '='; the second may be terminated by |
763 | * either '=' or '\0'. |
763 | * either '=' or '\0'. |
764 | */ |
764 | */ |
765 | 765 | ||
766 | STATIC int |
766 | STATIC int |
767 | varequal(p, q) |
767 | varequal(p, q) |
768 | const char *p, *q; |
768 | const char *p, *q; |
769 | { |
769 | { |
770 | while (*p == *q++) { |
770 | while (*p == *q++) { |
771 | if (*p++ == '=') |
771 | if (*p++ == '=') |
772 | return 1; |
772 | return 1; |
773 | } |
773 | } |
774 | if (*p == '=' && *(q - 1) == '\0') |
774 | if (*p == '=' && *(q - 1) == '\0') |
775 | return 1; |
775 | return 1; |
776 | return 0; |
776 | return 0; |
777 | } |
777 | } |
778 | 778 |