var.c revision 1.5 1 /* $NetBSD: var.c,v 1.5 1998/11/04 18:27:21 christos Exp $ */
2
3 #include "sh.h"
4 #include "ksh_time.h"
5 #include "ksh_limval.h"
6 #include "ksh_stat.h"
7 #include <ctype.h>
8
9 /*
10 * Variables
11 *
12 * WARNING: unreadable code, needs a rewrite
13 *
14 * if (flag&INTEGER), val.i contains integer value, and type contains base.
15 * otherwise, (val.s + type) contains string value.
16 * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
17 */
18 static struct tbl vtemp;
19 static struct table specials;
20 static char *formatstr ARGS((struct tbl *vp, const char *s));
21 static void export ARGS((struct tbl *vp, const char *val));
22 static int special ARGS((const char *name));
23 static void getspec ARGS((struct tbl *vp));
24 static void setspec ARGS((struct tbl *vp));
25 static void unsetspec ARGS((struct tbl *vp));
26 static struct tbl *arraysearch ARGS((struct tbl *, int));
27 static const char *array_index_calc ARGS((const char *, bool_t *, int *));
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;
37 static char *const empty[] = {null};
38
39 l = (struct block *) alloc(sizeof(struct block), ATEMP);
40 ainit(&l->area);
41 if (!e->loc) {
42 l->argc = 0;
43 l->argv = (char **) empty;
44 } else {
45 l->argc = e->loc->argc;
46 l->argv = e->loc->argv;
47 }
48 l->exit = l->error = NULL;
49 tinit(&l->vars, &l->area, 0);
50 tinit(&l->funs, &l->area, 0);
51 l->next = e->loc;
52 e->loc = l;
53 }
54
55 /*
56 * pop a block handling special variables
57 */
58 void
59 popblock()
60 {
61 register struct block *l = e->loc;
62 register struct tbl *vp, **vpp = l->vars.tbls, *vq;
63 register int i;
64
65 e->loc = l->next; /* pop block */
66 for (i = l->vars.size; --i >= 0; ) {
67 if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) {
68 if ((vq = global(vp->name))->flag & ISSET)
69 setspec(vq);
70 else
71 unsetspec(vq);
72 }
73 }
74 afreeall(&l->area);
75 afree(l, ATEMP);
76 }
77
78 /* called by main() to initialize variable data structures */
79 void
80 initvar()
81 {
82 static const struct {
83 const char *name;
84 int v;
85 } names[] = {
86 { "COLUMNS", V_COLUMNS },
87 { "IFS", V_IFS },
88 { "OPTIND", V_OPTIND },
89 { "PATH", V_PATH },
90 { "POSIXLY_CORRECT", V_POSIXLY_CORRECT },
91 { "TMPDIR", V_TMPDIR },
92 #ifdef HISTORY
93 { "HISTFILE", V_HISTFILE },
94 { "HISTSIZE", V_HISTSIZE },
95 #endif /* HISTORY */
96 #ifdef EDIT
97 { "EDITOR", V_EDITOR },
98 { "VISUAL", V_VISUAL },
99 #endif /* EDIT */
100 #ifdef KSH
101 { "MAIL", V_MAIL },
102 { "MAILCHECK", V_MAILCHECK },
103 { "MAILPATH", V_MAILPATH },
104 { "RANDOM", V_RANDOM },
105 { "SECONDS", V_SECONDS },
106 { "TMOUT", V_TMOUT },
107 #endif /* KSH */
108 { (char *) 0, 0 }
109 };
110 int i;
111 struct tbl *tp;
112
113 tinit(&specials, APERM, 32); /* must be 2^n (currently 16 speciasl) */
114 for (i = 0; names[i].name; i++) {
115 tp = tenter(&specials, names[i].name, hash(names[i].name));
116 tp->flag = DEFINED|ISSET;
117 tp->type = names[i].v;
118 }
119 }
120
121 /* Used to calculate an array index for global()/local(). Sets *arrayp to
122 * non-zero if this is an array, sets *valp to the array index, returns
123 * the basename of the array.
124 */
125 static const char *
126 array_index_calc(n, arrayp, valp)
127 const char *n;
128 bool_t *arrayp;
129 int *valp;
130 {
131 const char *p;
132 int len;
133
134 *arrayp = FALSE;
135 p = skip_varname(n, FALSE);
136 if (p != n && *p == '[' && (len = array_ref_len(p))) {
137 char *sub, *tmp;
138 long rval;
139
140 /* Calculate the value of the subscript */
141 *arrayp = TRUE;
142 tmp = str_nsave(p+1, len-2, ATEMP);
143 sub = substitute(tmp, 0);
144 afree(tmp, ATEMP);
145 n = str_nsave(n, p - n, ATEMP);
146 evaluate(sub, &rval, FALSE);
147 if (rval < 0 || rval > ARRAYMAX)
148 errorf("%s: subscript out of range", n);
149 *valp = rval;
150 afree(sub, ATEMP);
151 }
152 return n;
153 }
154
155 /*
156 * Search for variable, if not found create globally.
157 */
158 struct tbl *
159 global(n)
160 register const char *n;
161 {
162 register struct block *l = e->loc;
163 register struct tbl *vp;
164 register int c;
165 unsigned h;
166 bool_t array;
167 int val;
168
169 /* Check to see if this is an array */
170 n = array_index_calc(n, &array, &val);
171 h = hash(n);
172 c = n[0];
173 if (!letter(c)) {
174 if (array)
175 errorf("bad substitution");
176 vp = &vtemp;
177 vp->flag = (DEFINED|RDONLY);
178 vp->type = 0;
179 vp->areap = ATEMP;
180 *vp->name = c;
181 if (digit(c)) {
182 for (c = 0; digit(*n); n++)
183 c = c*10 + *n-'0';
184 if (c <= l->argc)
185 setstr(vp, l->argv[c]);
186 return vp;
187 }
188 if (n[1] != '\0')
189 return vp;
190 vp->flag |= ISSET|INTEGER;
191 switch (c) {
192 case '$':
193 vp->val.i = kshpid;
194 break;
195 case '!':
196 /* If no job, expand to nothing */
197 if ((vp->val.i = j_async()) == 0)
198 vp->flag &= ~(ISSET|INTEGER);
199 break;
200 case '?':
201 vp->val.i = exstat;
202 break;
203 case '#':
204 vp->val.i = l->argc;
205 break;
206 case '-':
207 vp->flag &= ~INTEGER;
208 vp->val.s = getoptions();
209 break;
210 default:
211 vp->flag &= ~(ISSET|INTEGER);
212 }
213 return vp;
214 }
215 for (l = e->loc; ; l = l->next) {
216 vp = tsearch(&l->vars, n, h);
217 if (vp != NULL) {
218 if (array)
219 return arraysearch(vp, val);
220 else
221 return vp;
222 }
223 if (l->next == NULL)
224 break;
225 }
226 vp = tenter(&l->vars, n, h);
227 if (array)
228 vp = arraysearch(vp, val);
229 vp->flag |= DEFINED;
230 if (special(n))
231 vp->flag |= SPECIAL;
232 return vp;
233 }
234
235 /*
236 * Search for local variable, if not found create locally.
237 */
238 struct tbl *
239 local(n, copy)
240 register const char *n;
241 bool_t copy;
242 {
243 register struct block *l = e->loc;
244 register struct tbl *vp;
245 unsigned h;
246 bool_t array;
247 int val;
248
249 /* Check to see if this is an array */
250 n = array_index_calc(n, &array, &val);
251 h = hash(n);
252 if (!letter(*n)) {
253 vp = &vtemp;
254 vp->flag = DEFINED|RDONLY;
255 vp->type = 0;
256 vp->areap = ATEMP;
257 return vp;
258 }
259 vp = tenter(&l->vars, n, h);
260 if (copy && !(vp->flag & DEFINED)) {
261 struct block *ll = l;
262 struct tbl *vq = (struct tbl *) 0;
263
264 while ((ll = ll->next) && !(vq = tsearch(&ll->vars, n, h)))
265 ;
266 if (vq) {
267 vp->flag |= vq->flag & (EXPORT|INTEGER|RDONLY
268 |LJUST|RJUST|ZEROFIL
269 |LCASEV|UCASEV_AL|INT_U|INT_L);
270 if (vq->flag & INTEGER)
271 vp->type = vq->type;
272 vp->u2.field = vq->u2.field;
273 }
274 }
275 if (array)
276 vp = arraysearch(vp, val);
277 vp->flag |= DEFINED;
278 if (special(n))
279 vp->flag |= SPECIAL;
280 return vp;
281 }
282
283 /* get variable string value */
284 char *
285 str_val(vp)
286 register struct tbl *vp;
287 {
288 char *s;
289
290 if ((vp->flag&SPECIAL))
291 getspec(vp);
292 if (!(vp->flag&ISSET))
293 s = null; /* special to dollar() */
294 else if (!(vp->flag&INTEGER)) /* string source */
295 s = vp->val.s + vp->type;
296 else { /* integer source */
297 /* worst case number length is when base=2, so use BITS(long) */
298 /* minus base # number null */
299 static char strbuf[1 + 2 + 1 + BITS(long) + 1];
300 const char *digits = (vp->flag & UCASEV_AL) ?
301 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
302 : "0123456789abcdefghijklmnopqrstuvwxyz";
303 register unsigned long n;
304 register int base;
305
306 s = strbuf + sizeof(strbuf);
307 if (vp->flag & INT_U)
308 n = (unsigned long) vp->val.i;
309 else
310 n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
311 base = (vp->type == 0) ? 10 : vp->type;
312
313 *--s = '\0';
314 do {
315 *--s = digits[n % base];
316 n /= base;
317 } while (n != 0);
318 if (base != 10) {
319 *--s = '#';
320 *--s = digits[base % 10];
321 if (base >= 10)
322 *--s = digits[base / 10];
323 }
324 if (!(vp->flag & INT_U) && vp->val.i < 0)
325 *--s = '-';
326 if (vp->flag & (RJUST|LJUST)) /* case already dealt with */
327 s = formatstr(vp, s);
328 }
329 return s;
330 }
331
332 /* get variable integer value, with error checking */
333 long
334 intval(vp)
335 register struct tbl *vp;
336 {
337 long num;
338 int base;
339
340 base = getint(vp, &num);
341 if (base == -1)
342 /* XXX check calls - is error here ok by POSIX? */
343 errorf("%s: bad number", str_val(vp));
344 return num;
345 }
346
347 /* set variable to string value */
348 void
349 setstr(vq, s)
350 register struct tbl *vq;
351 const char *s;
352 {
353 if (!(vq->flag&INTEGER)) { /* string dest */
354 if ((vq->flag&ALLOC)) {
355 /* debugging */
356 if (s >= vq->val.s
357 && s <= vq->val.s + strlen(vq->val.s))
358 internal_errorf(TRUE,
359 "setstr: %s=%s: assigning to self",
360 vq->name, s);
361 afree((void*)vq->val.s, vq->areap);
362 }
363 vq->flag &= ~(ISSET|ALLOC);
364 vq->type = 0;
365 if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST)))
366 s = formatstr(vq, s);
367 if ((vq->flag&EXPORT))
368 export(vq, s);
369 else {
370 vq->val.s = str_save(s, vq->areap);
371 if (vq->val.s) /* <sjg> don't lie */
372 vq->flag |= ALLOC;
373 }
374 } else /* integer dest */
375 /* XXX is this correct? */
376 v_evaluate(vq, s, FALSE);
377 vq->flag |= ISSET;
378 if ((vq->flag&SPECIAL))
379 setspec(vq);
380 }
381
382 /* set variable to integer */
383 void
384 setint(vq, n)
385 register struct tbl *vq;
386 long n;
387 {
388 if (!(vq->flag&INTEGER)) {
389 register struct tbl *vp = &vtemp;
390 vp->flag = (ISSET|INTEGER);
391 vp->type = 0;
392 vp->areap = ATEMP;
393 vp->val.i = n;
394 setstr(vq, str_val(vp));
395 } else
396 vq->val.i = n;
397 vq->flag |= ISSET;
398 if ((vq->flag&SPECIAL))
399 setspec(vq);
400 }
401
402 int
403 getint(vp, nump)
404 struct tbl *vp;
405 long *nump;
406 {
407 register char *s;
408 register int c;
409 int base, neg;
410 int have_base = 0;
411 long num;
412
413 if (vp->flag&SPECIAL)
414 getspec(vp);
415 /* XXX is it possible for ISSET to be set and val.s to be 0? */
416 if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
417 return -1;
418 if (vp->flag&INTEGER) {
419 *nump = vp->val.i;
420 return vp->type;
421 }
422 s = vp->val.s + vp->type;
423 if (s == NULL) /* redundent given initial test */
424 s = null;
425 base = 10;
426 num = 0;
427 neg = 0;
428 for (c = *s++; c ; c = *s++) {
429 if (c == '-') {
430 neg++;
431 } else if (c == '#') {
432 base = (int) num;
433 if (have_base || base < 2 || base > 36)
434 return -1;
435 num = 0;
436 have_base = 1;
437 } else if (letnum(c)) {
438 if (isdigit(c))
439 c -= '0';
440 else if (islower(c))
441 c -= 'a' - 10; /* todo: assumes ascii */
442 else if (isupper(c))
443 c -= 'A' - 10; /* todo: assumes ascii */
444 else
445 c = -1; /* _: force error */
446 if (c < 0 || c >= base)
447 return -1;
448 num = num * base + c;
449 } else
450 return -1;
451 }
452 if (neg)
453 num = -num;
454 *nump = num;
455 return base;
456 }
457
458 /* convert variable vq to integer variable, setting its value from vp
459 * (vq and vp may be the same)
460 */
461 struct tbl *
462 setint_v(vq, vp)
463 register struct tbl *vq, *vp;
464 {
465 int base;
466 long num;
467
468 if ((base = getint(vp, &num)) == -1)
469 return NULL;
470 if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) {
471 vq->flag &= ~ALLOC;
472 afree(vq->val.s, vq->areap);
473 }
474 vq->val.i = num;
475 if (vq->type == 0) /* default base */
476 vq->type = base;
477 vq->flag |= ISSET|INTEGER;
478 if (vq->flag&SPECIAL)
479 setspec(vq);
480 return vq;
481 }
482
483 static char *
484 formatstr(vp, s)
485 struct tbl *vp;
486 const char *s;
487 {
488 int olen, nlen;
489 char *p, *q;
490
491 olen = strlen(s);
492
493 if (vp->flag & (RJUST|LJUST)) {
494 if (!vp->u2.field) /* default field width */
495 vp->u2.field = olen;
496 nlen = vp->u2.field;
497 } else
498 nlen = olen;
499
500 p = (char *) alloc(nlen + 1, ATEMP);
501 if (vp->flag & (RJUST|LJUST)) {
502 int slen;
503
504 if (vp->flag & RJUST) {
505 const char *q = s + olen;
506 /* strip trailing spaces (at&t ksh uses q[-1] == ' ') */
507 while (q > s && isspace((unsigned char)q[-1]))
508 --q;
509 slen = q - s;
510 if (slen > vp->u2.field) {
511 s += slen - vp->u2.field;
512 slen = vp->u2.field;
513 }
514 shf_snprintf(p, nlen + 1,
515 ((vp->flag & ZEROFIL) && digit(*s)) ?
516 "%0*s%.*s" : "%*s%.*s",
517 vp->u2.field - slen, null, slen, s);
518 } else {
519 /* strip leading spaces/zeros */
520 while (isspace((unsigned char)*s))
521 s++;
522 if (vp->flag & ZEROFIL)
523 while (*s == '0')
524 s++;
525 shf_snprintf(p, nlen + 1, "%-*.*s",
526 vp->u2.field, vp->u2.field, s);
527 }
528 } else
529 memcpy(p, s, olen + 1);
530
531 if (vp->flag & UCASEV_AL) {
532 for (q = p; *q; q++)
533 if (islower((unsigned char)*q))
534 *q = toupper(*q);
535 } else if (vp->flag & LCASEV) {
536 for (q = p; *q; q++)
537 if (isupper((unsigned char)*q))
538 *q = tolower(*q);
539 }
540
541 return p;
542 }
543
544 /*
545 * make vp->val.s be "name=value" for quick exporting.
546 */
547 static void
548 export(vp, val)
549 register struct tbl *vp;
550 const char *val;
551 {
552 register char *xp;
553 char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
554 int namelen = strlen(vp->name);
555 int vallen = strlen(val) + 1;
556
557 vp->flag |= ALLOC;
558 xp = (char*)alloc(namelen + 1 + vallen, vp->areap);
559 memcpy(vp->val.s = xp, vp->name, namelen);
560 xp += namelen;
561 *xp++ = '=';
562 vp->type = xp - vp->val.s; /* offset to value */
563 memcpy(xp, val, vallen);
564 if (op != NULL)
565 afree((void*)op, vp->areap);
566 }
567
568 /*
569 * lookup variable (according to (set&LOCAL)),
570 * set its attributes (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL,
571 * LCASEV, UCASEV_AL), and optionally set its value if an assignment.
572 */
573 struct tbl *
574 typeset(var, set, clr, field, base)
575 register const char *var;
576 Tflag clr, set;
577 int field, base;
578 {
579 register struct tbl *vp;
580 struct tbl *vpbase, *t;
581 char *tvar;
582 const char *val;
583
584 /* check for valid variable name, search for value */
585 val = skip_varname(var, FALSE);
586 if (val == var)
587 return NULL;
588 if (*val == '[') {
589 int len;
590
591 len = array_ref_len(val);
592 if (len == 0)
593 return NULL;
594 /* IMPORT is only used when the shell starts up and is
595 * setting up its environment. Allow only simple array
596 * references at this time since parameter/command substitution
597 * is preformed on the [expression], which would be a major
598 * security hole.
599 */
600 if (set & IMPORT) {
601 int i;
602 for (i = 1; i < len - 1; i++)
603 if (!digit(val[i]))
604 return NULL;
605 }
606 val += len;
607 }
608 if (*val == '=')
609 tvar = str_nsave(var, val++ - var, ATEMP);
610 else {
611 /* Importing from original envirnment: must have an = */
612 if (set & IMPORT)
613 return NULL;
614 tvar = (char *) var;
615 val = NULL;
616 }
617
618 /* Prevent typeset from creating a local PATH/ENV/SHELL */
619 if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0
620 || strcmp(tvar, "ENV") == 0
621 || strcmp(tvar, "SHELL") == 0))
622 errorf("%s: restricted", tvar);
623
624 vp = (set&LOCAL) ? local(tvar, (set & LOCAL_COPY) ? TRUE : FALSE)
625 : global(tvar);
626 set &= ~(LOCAL|LOCAL_COPY);
627
628 vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp;
629
630 /* only allow export flag to be set. at&t ksh allows any attribute to
631 * be changed, which means it can be truncated or modified
632 * (-L/-R/-Z/-i).
633 */
634 if ((vpbase->flag&RDONLY)
635 && (val || clr || (set & ~EXPORT)))
636 /* XXX check calls - is error here ok by POSIX? */
637 errorf("%s: is read only", tvar);
638 if (val)
639 afree(tvar, ATEMP);
640
641 /* most calls are with set/clr == 0 */
642 if (set | clr) {
643 /* XXX if x[0] isn't set, there will be problems: need to have
644 * one copy of attributes for arrays...
645 */
646 for (t = vpbase; t; t = t->u.array) {
647 int fake_assign;
648 char UNINITIALIZED(*s);
649 char UNINITIALIZED(*free_me);
650
651 fake_assign = (t->flag & ISSET) && (!val || t != vp)
652 && ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL))
653 || ((t->flag & INTEGER) && (clr & INTEGER))
654 || (!(t->flag & INTEGER) && (set & INTEGER)));
655 if (fake_assign) {
656 if (t->flag & INTEGER) {
657 s = str_val(t);
658 free_me = (char *) 0;
659 } else {
660 s = t->val.s + t->type;
661 free_me = (t->flag & ALLOC) ? t->val.s
662 : (char *) 0;
663 }
664 t->flag &= ~ALLOC;
665 }
666 if (!(t->flag & INTEGER) && (set & INTEGER)) {
667 t->type = 0;
668 t->flag &= ~ALLOC;
669 }
670 t->flag = (t->flag | set) & ~clr;
671 /* Don't change base if assignment is to be done,
672 * in case assignment fails.
673 */
674 if ((set & INTEGER) && base > 0 && (!val || t != vp))
675 t->type = base;
676 if (set & (LJUST|RJUST|ZEROFIL))
677 t->u2.field = field;
678 if (fake_assign) {
679 setstr(t, s);
680 if (free_me)
681 afree((void *) free_me, t->areap);
682 }
683 }
684 }
685
686 if (val != NULL) {
687 if (vp->flag&INTEGER) {
688 /* do not zero base before assignment */
689 setstr(vp, val);
690 /* Done after assignment to override default */
691 if (base > 0)
692 vp->type = base;
693 } else
694 setstr(vp, val);
695 }
696
697 /* only x[0] is ever exported, so use vpbase */
698 if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER)
699 && vpbase->type == 0)
700 export(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null);
701
702 return vp;
703 }
704
705 /* Unset a variable. array_ref is set if there was an array reference in
706 * the name lookup (eg, x[2]).
707 */
708 void
709 unset(vp, array_ref)
710 register struct tbl *vp;
711 int array_ref;
712 {
713 if (vp->flag & ALLOC)
714 afree((void*)vp->val.s, vp->areap);
715 if ((vp->flag & ARRAY) && !array_ref) {
716 struct tbl *a, *tmp;
717
718 /* Free up entire array */
719 for (a = vp->u.array; a; ) {
720 tmp = a;
721 a = a->u.array;
722 if (tmp->flag & ALLOC)
723 afree((void *) tmp->val.s, tmp->areap);
724 afree(tmp, tmp->areap);
725 }
726 vp->u.array = (struct tbl *) 0;
727 }
728 /* If foo[0] is being unset, the remainder of the array is kept... */
729 vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0);
730 if (vp->flag & SPECIAL)
731 unsetspec(vp); /* responsible for `unspecial'ing var */
732 }
733
734 /* return a pointer to the first char past a legal variable name (returns the
735 * argument if there is no legal name, returns * a pointer to the terminating
736 * null if whole string is legal).
737 */
738 char *
739 skip_varname(s, aok)
740 const char *s;
741 int aok;
742 {
743 int alen;
744
745 if (s && letter(*s)) {
746 while (*++s && letnum(*s))
747 ;
748 if (aok && *s == '[' && (alen = array_ref_len(s)))
749 s += alen;
750 }
751 return (char *) s;
752 }
753
754 /* Return a pointer to the first character past any legal variable name. */
755 char *
756 skip_wdvarname(s, aok)
757 const char *s;
758 int aok; /* skip array de-reference? */
759 {
760 if (s[0] == CHAR && letter(s[1])) {
761 do
762 s += 2;
763 while (s[0] == CHAR && letnum(s[1]));
764 if (aok && s[0] == CHAR && s[1] == '[') {
765 /* skip possible array de-reference */
766 const char *p = s;
767 char c;
768 int depth = 0;
769
770 while (1) {
771 if (p[0] != CHAR)
772 break;
773 c = p[1];
774 p += 2;
775 if (c == '[')
776 depth++;
777 else if (c == ']' && --depth == 0) {
778 s = p;
779 break;
780 }
781 }
782 }
783 }
784 return (char *) s;
785 }
786
787 /* Check if coded string s is a variable name */
788 int
789 is_wdvarname(s, aok)
790 const char *s;
791 int aok;
792 {
793 char *p = skip_wdvarname(s, aok);
794
795 return p != s && p[0] == EOS;
796 }
797
798 /* Check if coded string s is a variable assignment */
799 int
800 is_wdvarassign(s)
801 const char *s;
802 {
803 char *p = skip_wdvarname(s, TRUE);
804
805 return p != s && p[0] == CHAR && p[1] == '=';
806 }
807
808 /*
809 * Make the exported environment from the exported names in the dictionary.
810 */
811 char **
812 makenv()
813 {
814 struct block *l = e->loc;
815 XPtrV env;
816 register struct tbl *vp, **vpp;
817 register int i;
818
819 XPinit(env, 64);
820 for (l = e->loc; l != NULL; l = l->next)
821 for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
822 if ((vp = *vpp++) != NULL
823 && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
824 register struct block *l2;
825 register struct tbl *vp2;
826 unsigned h = hash(vp->name);
827
828 /* unexport any redefined instances */
829 for (l2 = l->next; l2 != NULL; l2 = l2->next) {
830 vp2 = tsearch(&l2->vars, vp->name, h);
831 if (vp2 != NULL)
832 vp2->flag &= ~EXPORT;
833 }
834 if ((vp->flag&INTEGER)) {
835 /* integer to string */
836 char *val;
837 val = str_val(vp);
838 vp->flag &= ~INTEGER;
839 setstr(vp, val);
840 }
841 XPput(env, vp->val.s);
842 }
843 XPput(env, NULL);
844 return (char **) XPclose(env);
845 }
846
847 /*
848 * handle special variables with side effects - PATH, SECONDS.
849 */
850
851 /* Test if name is a special parameter */
852 static int
853 special(name)
854 register const char * name;
855 {
856 register struct tbl *tp;
857
858 tp = tsearch(&specials, name, hash(name));
859 return tp ? tp->type : V_NONE;
860 }
861
862 #ifdef KSH
863 static time_t seconds; /* time SECONDS last set */
864 #endif /* KSH */
865
866 static void
867 getspec(vp)
868 register struct tbl *vp;
869 {
870 switch (special(vp->name)) {
871 #ifdef KSH
872 case V_SECONDS:
873 vp->flag &= ~SPECIAL;
874 setint(vp, (long) (time((time_t *)0) - seconds));
875 vp->flag |= SPECIAL;
876 break;
877 case V_RANDOM:
878 vp->flag &= ~SPECIAL;
879 setint(vp, (long) (rand() & 0x7fff));
880 vp->flag |= SPECIAL;
881 break;
882 #endif /* KSH */
883 #ifdef HISTORY
884 case V_HISTSIZE:
885 vp->flag &= ~SPECIAL;
886 setint(vp, (long) histsize);
887 vp->flag |= SPECIAL;
888 break;
889 #endif /* HISTORY */
890 }
891 }
892
893 static void
894 setspec(vp)
895 register struct tbl *vp;
896 {
897 char *s;
898
899 switch (special(vp->name)) {
900 case V_PATH:
901 path = str_val(vp);
902 flushcom(1); /* clear tracked aliases */
903 break;
904 case V_IFS:
905 setctypes(s = str_val(vp), C_IFS);
906 ifs0 = *s;
907 break;
908 case V_OPTIND:
909 getopts_reset((int) intval(vp));
910 break;
911 case V_POSIXLY_CORRECT:
912 change_flag(FPOSIX, OF_SPECIAL, 1);
913 break;
914 case V_TMPDIR:
915 if (tmpdir) {
916 afree(tmpdir, APERM);
917 tmpdir = (char *) 0;
918 }
919 /* Use tmpdir iff it is an absolute path, is writable and
920 * searchable and is a directory...
921 */
922 {
923 struct stat statb;
924 s = str_val(vp);
925 if (ISABSPATH(s) && eaccess(s, W_OK|X_OK) == 0
926 && stat(s, &statb) == 0 && S_ISDIR(statb.st_mode))
927 tmpdir = str_save(s, APERM);
928 }
929 break;
930 #ifdef HISTORY
931 case V_HISTSIZE:
932 vp->flag &= ~SPECIAL;
933 sethistsize((int) intval(vp));
934 vp->flag |= SPECIAL;
935 break;
936 case V_HISTFILE:
937 sethistfile(str_val(vp));
938 break;
939 #endif /* HISTORY */
940 #ifdef EDIT
941 case V_VISUAL:
942 set_editmode(str_val(vp));
943 break;
944 case V_EDITOR:
945 if (!(global("VISUAL")->flag & ISSET))
946 set_editmode(str_val(vp));
947 break;
948 case V_COLUMNS:
949 if ((x_cols = intval(vp)) <= MIN_COLS)
950 x_cols = MIN_COLS;
951 break;
952 #endif /* EDIT */
953 #ifdef KSH
954 case V_MAIL:
955 mbset(str_val(vp));
956 break;
957 case V_MAILPATH:
958 mpset(str_val(vp));
959 break;
960 case V_MAILCHECK:
961 /* mail_check_set(intval(vp)); */
962 break;
963 case V_RANDOM:
964 vp->flag &= ~SPECIAL;
965 srand((unsigned int)intval(vp));
966 vp->flag |= SPECIAL;
967 break;
968 case V_SECONDS:
969 vp->flag &= ~SPECIAL;
970 seconds = time((time_t*) 0) - intval(vp);
971 vp->flag |= SPECIAL;
972 break;
973 case V_TMOUT:
974 /* at&t ksh seems to do this (only listen if integer) */
975 if (vp->flag & INTEGER)
976 ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0;
977 break;
978 #endif /* KSH */
979 }
980 }
981
982 static void
983 unsetspec(vp)
984 register struct tbl *vp;
985 {
986 switch (special(vp->name)) {
987 case V_PATH:
988 path = def_path;
989 flushcom(1); /* clear tracked aliases */
990 break;
991 case V_IFS:
992 setctypes(" \t\n", C_IFS);
993 ifs0 = ' ';
994 break;
995 case V_TMPDIR:
996 /* should not become unspecial */
997 if (tmpdir) {
998 afree(tmpdir, APERM);
999 tmpdir = (char *) 0;
1000 }
1001 break;
1002 #ifdef KSH
1003 case V_MAIL:
1004 mbset((char *) 0);
1005 break;
1006 case V_MAILPATH:
1007 mpset((char *) 0);
1008 break;
1009 case V_TMOUT:
1010 /* at&t ksh doesn't do this. TMOUT becomes unspecial so
1011 * future assignments don't have effect. Could be
1012 * useful (eg, after "TMOUT=60; unset TMOUT", user
1013 * can't get rid of the timeout...). Should be handled
1014 * by generic unset code...
1015 */
1016 ksh_tmout = 0;
1017 break;
1018 #endif /* KSH */
1019 /* todo: generic action for specials (at&t says variables
1020 * lose their special meaning when unset but global() checks
1021 * the name of new vars to see if they are special)
1022 * lose meaning: _, ERRNO, LINENO, MAILCHECK,
1023 * OPTARG, OPTIND, RANDOM, SECONDS, TMOUT.
1024 * unknown: MAIL, MAILPATH, HISTSIZE, HISTFILE,
1025 * no effect: IFS, COLUMNS, PATH, TMPDIR,
1026 * VISUAL, EDITOR,
1027 * POSIXLY_CORRECT (use set +o posix instead)
1028 */
1029 }
1030 }
1031
1032 /*
1033 * Search for (and possibly create) a table entry starting with
1034 * vp, indexed by val.
1035 */
1036 static struct tbl *
1037 arraysearch(vp, val)
1038 struct tbl *vp;
1039 int val;
1040 {
1041 struct tbl *prev, *curr, *new;
1042
1043 vp->flag |= ARRAY|DEFINED;
1044
1045 /* The table entry is always [0] */
1046 if (val == 0) {
1047 vp->index = 0;
1048 return vp;
1049 }
1050 prev = vp;
1051 curr = vp->u.array;
1052 while (curr && curr->index < val) {
1053 prev = curr;
1054 curr = curr->u.array;
1055 }
1056 if (curr && curr->index == val) {
1057 if (curr->flag&ISSET)
1058 return curr;
1059 else
1060 new = curr;
1061 } else
1062 new = (struct tbl *)alloc(sizeof(struct tbl)+strlen(vp->name)+1, vp->areap);
1063 strcpy(new->name, vp->name);
1064 new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL);
1065 new->type = vp->type;
1066 new->areap = vp->areap;
1067 new->u2.field = vp->u2.field;
1068 new->index = val;
1069 if (curr != new) { /* not reusing old array entry */
1070 prev->u.array = new;
1071 new->u.array = curr;
1072 }
1073 return new;
1074 }
1075
1076 /* Return the length of an array reference (eg, [1+2]) - cp is assumed
1077 * to point to the open bracket. Returns 0 if there is no matching closing
1078 * bracket.
1079 */
1080 int
1081 array_ref_len(cp)
1082 const char *cp;
1083 {
1084 const char *s = cp;
1085 int c;
1086 int depth = 0;
1087
1088 while ((c = *s++) && (c != ']' || --depth))
1089 if (c == '[')
1090 depth++;
1091 if (!c)
1092 return 0;
1093 return s - cp;
1094 }
1095
1096 /*
1097 * Make a copy of the base of an array name
1098 */
1099 char *
1100 arrayname(str)
1101 const char *str;
1102 {
1103 const char *p;
1104
1105 if ((p = strchr(str, '[')) == 0)
1106 /* Shouldn't happen, but why worry? */
1107 return (char *) str;
1108
1109 return str_nsave(str, p - str, ATEMP);
1110 }
1111
1112 /* Set (or overwrite, if !reset) the array variable var to the values in vals.
1113 */
1114 void
1115 set_array(var, reset, vals)
1116 const char *var;
1117 int reset;
1118 char **vals;
1119 {
1120 struct tbl *vp, *vq;
1121 int i;
1122
1123 /* to get local array, use "typeset foo; set -A foo" */
1124 vp = global(var);
1125
1126 /* Note: at&t ksh allows set -A but not set +A of a read-only var */
1127 if ((vp->flag&RDONLY))
1128 errorf("%s: is read only", var);
1129 /* This code is quite non-optimal */
1130 if (reset > 0)
1131 /* trash existing values and attributes */
1132 unset(vp, 0);
1133 /* todo: would be nice for assignment to completely succeed or
1134 * completely fail. Only really effects integer arrays:
1135 * evaluation of some of vals[] may fail...
1136 */
1137 for (i = 0; vals[i]; i++) {
1138 vq = arraysearch(vp, i);
1139 setstr(vq, vals[i]);
1140 }
1141 }
1142