|
|
1.1 root 1: static char *RCSid = "$Header: var.c,v 3.1 88/11/03 09:18:22 egisin Exp $";
2:
3: #include <stddef.h>
4: #include <stdlib.h>
5: #include <string.h>
6: #include <errno.h>
7: #include <setjmp.h>
8: #include <time.h>
9: #include <sys/types.h>
10: #include "sh.h"
11: #include "table.h"
12: #include "expand.h"
13:
14: /*
15: * Variables
16: *
17: * WARNING: unreadable code, needs a rewrite
18: *
19: * if (flag&INTEGER), val.i contains integer value, and type contains base.
20: * otherwise, (val.s + type) contains string value.
21: * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
22: */
23: char null [] = "";
24: static struct tbl vtemp;
25: static void getspec(), setspec();
26: static void export ARGS((struct tbl *, char *val));
27: static int special ARGS ((char *name));
28:
29: /*
30: * create a new block for function calls and simple commands
31: * assume caller has allocated and set up e.loc
32: */
33: void
34: newblock()
35: {
36: register struct block *l = e.loc;
37: static char *empty[] = {""};
38:
39: ainit(&l->area);
40: l->argc = 0;
41: l->argv = empty;
42: l->exit = l->error = NULL;
43: tinit(&l->vars, &l->area);
44: tinit(&l->funs, &l->area);
45: }
46:
47: /*
48: * pop a block handling special variables
49: */
50: void
51: popblock()
52: {
53: register struct block *l = e.loc;
54: register struct tbl *vp, **vpp = l->vars.tbls;
55: register int i;
56:
57: e.loc = l->next; /* pop block */
58: for (i = l->vars.size; --i >= 0; )
59: if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL))
60: setspec(global(vp->name));
61: afreeall(&l->area);
62: }
63:
64: /*
65: * Search for variable, if not found create globally.
66: */
67: struct tbl *
68: global(n)
69: register char *n;
70: {
71: register struct block *l = e.loc;
72: register struct tbl *vp;
73: register int c;
74: unsigned h = hash(n);
75:
76: c = n[0];
77: if (digit(c)) {
78: vp = &vtemp;
79: lastarea = ATEMP;
80: vp->flag = (DEFINED|RDONLY);
81: vp->type = 0;
82: *vp->name = c; /* should strncpy */
83: for (c = 0; digit(*n) && c < 1000; n++)
84: c = c*10 + *n-'0';
85: if (c <= l->argc)
86: setstr(vp, l->argv[c]);
87: return vp;
88: } else
89: if (!letter(c)) {
90: vp = &vtemp;
91: lastarea = ATEMP;
92: vp->flag = (DEFINED|RDONLY);
93: vp->type = 0;
94: *vp->name = c;
95: if (n[1] != '\0')
96: return vp;
97: vp->flag |= ISSET|INTEGER;
98: switch (c) {
99: case '$':
100: vp->val.i = getpid();
101: break;
102: case '!':
103: vp->val.i = async;
104: break;
105: case '?':
106: vp->val.i = exstat;
107: break;
108: case '#':
109: vp->val.i = l->argc;
110: break;
111: case '-':
112: vp->flag &= ~ INTEGER;
113: vp->val.s = getoptions();
114: break;
115: default:
116: vp->flag &= ~(ISSET|INTEGER);
117: }
118: return vp;
119: }
120: for (l = e.loc; l != NULL; l = l->next) {
121: vp = tsearch(&l->vars, n, h);
122: lastarea = &l->area;
123: if (vp != NULL)
124: return vp;
125: if (l->next == NULL)
126: break;
127: }
128: vp = tenter(&l->vars, n, h);
129: vp->flag |= DEFINED;
130: if (special(n))
131: vp->flag |= SPECIAL;
132: return vp;
133: }
134:
135: /*
136: * Search for local variable, if not found create locally.
137: */
138: struct tbl *
139: local(n)
140: register char *n;
141: {
142: register struct block *l = e.loc;
143: register struct tbl *vp;
144: unsigned h = hash(n);
145:
146: if (!letter(*n)) {
147: vp = &vtemp;
148: lastarea = ATEMP;
149: vp->flag = (DEFINED|RDONLY);
150: vp->type = 0;
151: return vp;
152: }
153: vp = tenter(&l->vars, n, h);
154: lastarea = &l->area;
155: vp->flag |= DEFINED;
156: if (special(n))
157: vp->flag |= SPECIAL;
158: return vp;
159: }
160:
161: /* get variable string value */
162: char *
163: strval(vp)
164: register struct tbl *vp;
165: {
166: register char *s;
167: static char strbuf[40];
168:
169: if ((vp->flag&SPECIAL))
170: getspec(vp);
171: if (!(vp->flag&ISSET))
172: return null; /* special to dollar() */
173: if (!(vp->flag&INTEGER)) /* string source */
174: s = vp->val.s + vp->type;
175: else { /* integer source */
176: register unsigned long n;
177: register int base;
178:
179: s = strbuf + sizeof(strbuf);
180: n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
181: base = (vp->type == 0) ? 10 : vp->type;
182:
183: *--s = '\0';
184: do {
185: *--s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%base];
186: n /= base;
187: } while (n != 0);
188: /* todo: should we output base# ? */
189: if (vp->val.i < 0)
190: *--s = '-';
191: }
192: return s;
193: }
194:
195: /* get variable integer value */
196: long
197: intval(vp)
198: register struct tbl *vp;
199: {
200: register struct tbl *vq;
201:
202: if ((vp->flag&SPECIAL))
203: getspec(vp);
204: if ((vp->flag&INTEGER))
205: return vp->val.i;
206: vq = &vtemp;
207: vq->flag = (INTEGER);
208: vq->type = 0;
209: strint(vq, vp);
210: return vq->val.i;
211: }
212:
213: /* set variable to string value */
214: void
215: setstr(vq, s)
216: register struct tbl *vq;
217: char *s;
218: {
219: if (!(vq->flag&INTEGER)) { /* string dest */
220: if ((vq->flag&ALLOC))
221: afree((Void*)vq->val.s, lastarea);
222: vq->flag &= ~ (ISSET|ALLOC);
223: vq->type = 0;
224: if ((vq->flag&EXPORT))
225: export(vq, s);
226: else
227: vq->val.s = strsave(s, lastarea);
228: vq->flag |= ALLOC;
229: } else { /* integer dest */
230: register struct tbl *vp = &vtemp;
231: vp->flag = (DEFINED|ISSET);
232: vp->type = 0;
233: vp->val.s = s;
234: strint(vq, vp);
235: }
236: vq->flag |= ISSET;
237: if ((vq->flag&SPECIAL))
238: setspec(vq);
239: }
240:
241: /* convert variable to integer variable */
242: struct tbl *
243: strint(vq, vp)
244: register struct tbl *vq, *vp;
245: {
246: register char *s = vp->val.s + vp->type;
247: register int c;
248: int base, neg = 0;
249:
250: vq->flag |= INTEGER;
251: if ((vp->flag&INTEGER)) {
252: vq->val.i = vp->val.i;
253: return vq;
254: }
255: vq->val.i = 0;
256: base = 10;
257: for (c = *s++; c ; c = *s++)
258: if (c == '-') {
259: neg++;
260: } else if (c == '#') {
261: base = vq->type = vq->val.i;
262: vq->val.i = 0;
263: } else if (letnum(c)) {
264: if ('0' <= c && c <= '9')
265: c -= '0';
266: else if ('a' <= c && c <= 'z') /* fuck EBCDIC */
267: c -= 'a'-10;
268: else if ('A' <= c && c <= 'Z')
269: c -= 'A'-10;
270: vq->val.i = (vq->val.i*base) + c;
271: } else
272: break;
273: if (neg)
274: vq->val.i = -vq->val.i;
275: if (vq->type < 2 || vq->type > 36)
276: vq->type = 0; /* default base (10) */
277: return vq;
278: }
279:
280: /* set variable to integer */
281: void
282: setint(vq, n)
283: register struct tbl *vq;
284: long n;
285: {
286: if (!(vq->flag&INTEGER)) {
287: register struct tbl *vp = &vtemp;
288: vp->flag = (ISSET|INTEGER);
289: vp->type = 0;
290: vp->val.i = n;
291: setstr(vq, strval(vp)); /* ? */
292: } else
293: vq->val.i = n;
294: vq->flag |= ISSET;
295: if ((vq->flag&SPECIAL))
296: setspec(vq);
297: }
298:
299: /* set variable from enviroment */
300: import(thing)
301: char *thing;
302: {
303: register struct tbl *vp;
304: register char *val;
305:
306: val = strchr(thing, '=');
307: if (val == NULL)
308: return 0;
309: *val = '\0';
310: vp = local(thing);
311: *val++ = '=';
312: vp->flag |= DEFINED|ISSET|EXPORT;
313: vp->val.s = thing;
314: vp->type = val - thing;
315: if ((vp->flag&SPECIAL))
316: setspec(vp);
317: return 1;
318: }
319:
320: /*
321: * make vp->val.s be "name=value" for quick exporting.
322: */
323: static void
324: export(vp, val)
325: register struct tbl *vp;
326: char *val;
327: {
328: register char *cp, *xp;
329: char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
330:
331: xp = (char*)alloc(strlen(vp->name) + strlen(val) + 2, lastarea);
332: vp->flag |= ALLOC;
333: vp->val.s = xp;
334: for (cp = vp->name; (*xp = *cp++) != '\0'; xp++)
335: ;
336: *xp++ = '=';
337: vp->type = xp - vp->val.s; /* offset to value */
338: for (cp = val; (*xp++ = *cp++) != '\0'; )
339: ;
340: if (op != NULL)
341: afree((Void*)op, lastarea);
342: }
343:
344: /*
345: * lookup variable (according to (set&LOCAL)),
346: * set its attributes (INTEGER, RDONLY, EXPORT, TRACE),
347: * and optionally set its value if an assignment.
348: */
349: struct tbl *
350: typeset(var, set, clr)
351: register char *var;
352: int clr, set;
353: {
354: register struct tbl *vp;
355: register char *val;
356:
357: /* check for valid variable name, search for value */
358: val = var;
359: if (!letter(*val))
360: return NULL;
361: for (val++; *val != '\0'; val++)
362: if (*val == '=')
363: break;
364: else if (letnum(*val))
365: ;
366: else
367: return NULL;
368: if (*val == '=')
369: *val = '\0';
370: else
371: val = NULL;
372: vp = (set&LOCAL) ? local(var) : global(var);
373: set &= ~ LOCAL;
374: if (val != NULL)
375: *val++ = '=';
376:
377: if (!(vp->flag&ISSET))
378: vp->flag = vp->flag & ~clr | set;
379: else
380: if (!(vp->flag&INTEGER) && (set&INTEGER)) {
381: /* string to integer */
382: vtemp.flag = (ISSET);
383: vtemp.type = 0;
384: vtemp.val.s = vp->val.s + vp->type;
385: if ((vp->flag&ALLOC))
386: afree((Void*)vp->val.s, lastarea); /* dangerous, used later */
387: vp->flag &= ~ ALLOC;
388: vp->flag |= INTEGER;
389: vp->type = 0;
390: strint(vp, &vtemp);
391: } else
392: if ((clr&INTEGER) && (vp->flag&INTEGER)) {
393: /* integer to string */
394: vtemp.val.s = strval(vp);
395: vp->flag &= ~ INTEGER;
396: setstr(vp, vtemp.val.s);
397: }
398:
399: vp->flag = vp->flag & ~clr | set;
400:
401: if (val != NULL) {
402: if ((vp->flag&RDONLY))
403: errorf("cannot set readonly %s\n", var);
404: if ((vp->flag&INTEGER))
405: /* setstr should be able to handle this */
406: (void)evaluate(var);
407: else
408: setstr(vp, val);
409: }
410:
411: if ((vp->flag&EXPORT) && !(vp->flag&INTEGER) && vp->type == 0)
412: export(vp, (vp->flag&ISSET) ? vp->val.s : null);
413:
414: return vp;
415: }
416:
417: void
418: unset(vp)
419: register struct tbl *vp;
420: {
421: if ((vp->flag&ALLOC))
422: afree((Void*)vp->val.s, lastarea);
423: vp->flag &= ~ (ALLOC|ISSET);
424: }
425:
426: int
427: isassign(s)
428: register char *s;
429: {
430: if (!letter(*s))
431: return (0);
432: for (s++; *s != '='; s++)
433: if (*s == 0 || !letnum(*s))
434: return (0);
435: return (1);
436: }
437:
438: /*
439: * Make the exported environment from the exported names in the dictionary.
440: */
441: char **
442: makenv()
443: {
444: struct block *l = e.loc;
445: XPtrV env;
446: register struct tbl *vp, **vpp;
447: register int i;
448:
449: XPinit(env, 64);
450: for (l = e.loc; l != NULL; l = l->next)
451: for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
452: if ((vp = *vpp++) != NULL
453: && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
454: register struct block *l2;
455: register struct tbl *vp2;
456: unsigned h = hash(vp->name);
457:
458: lastarea = &l->area;
459:
460: /* unexport any redefined instances */
461: for (l2 = l->next; l2 != NULL; l2 = l2->next) {
462: vp2 = tsearch(&l2->vars, vp->name, h);
463: if (vp2 != NULL)
464: vp2->flag &= ~ EXPORT;
465: }
466: if ((vp->flag&INTEGER)) {
467: /* integer to string */
468: char *val;
469: val = strval(vp);
470: vp->flag &= ~ INTEGER;
471: setstr(vp, val);
472: }
473: XPput(env, vp->val.s);
474: }
475: XPput(env, NULL);
476: return (char **) XPclose(env);
477: }
478:
479: /*
480: * handle special variables with side effects - PATH, SECONDS.
481: */
482:
483: static int
484: special(name)
485: register char * name;
486: {
487: if (strcmp("PATH", name) == 0)
488: return V_PATH;
489: if (strcmp("IFS", name) == 0)
490: return V_IFS;
491: if (strcmp("SECONDS", name) == 0)
492: return V_SECONDS;
493: if (strcmp("OPTIND", name) == 0)
494: return V_OPTIND;
495: return V_NONE;
496: }
497:
498: extern time_t time();
499: static time_t seconds; /* time SECONDS last set */
500:
501: static void
502: getspec(vp)
503: register struct tbl *vp;
504: {
505: switch (special(vp->name)) {
506: case V_SECONDS:
507: vp->flag &= ~ SPECIAL;
508: setint(vp, time((time_t *)0) - seconds);
509: vp->flag |= SPECIAL;
510: break;
511: }
512: }
513:
514: static void
515: setspec(vp)
516: register struct tbl *vp;
517: {
518: switch (special(vp->name)) {
519: case V_PATH:
520: path = strval(vp);
521: flushcom(1); /* clear tracked aliases */
522: break;
523: case V_IFS:
524: setctypes(strval(vp), C_IFS);
525: break;
526: case V_SECONDS:
527: seconds = time((time_t *)0);
528: break;
529: case V_OPTIND:
530: if (intval(vp) == 1)
531: resetopts();
532: break;
533: }
534: }
535:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.