reenabled swaptest. quake should now load data and start on big endian architectures...
[AROS-Contrib.git] / gnu / abc-shell / var.c
blob3e04ea6413f6f5ed0a04eb2e17b323a19239461b
1 #include "ksh_time.h"
2 #include "ksh_limval.h"
3 #include <sys/stat.h>
4 #include <ctype.h>
5 #include "sh.h"
7 /*
8 * Variables
10 * WARNING: unreadable code, needs a rewrite
12 * if (flag&INTEGER), val.i contains integer value, and type contains base.
13 * otherwise, (val.s + type) contains string value.
14 * if (flag&EXPORTV), val.s contains "name=value" for E-Z exporting.
16 static struct tbl vtemp;
17 static struct table specials;
18 static char *formatstr(struct tbl *, const char *);
19 static void export(struct tbl *, const char *);
20 static int special(const char *);
21 static void unspecial(const char *);
22 static void getspec(struct tbl *);
23 static void setspec(struct tbl *);
24 static void unsetspec(struct tbl *);
25 static struct tbl *arraysearch(struct tbl *, int);
28 * create a new block for function calls and simple commands
29 * assume caller has allocated and set up e->loc
31 void
32 newblock(void)
34 struct block *l;
35 static char *const empty[] = {null};
37 l = (struct block *) alloc(sizeof(struct block), ATEMP);
38 l->flags = 0;
39 ainit(&l->area); /* todo: could use e->area (l->area => l->areap) */
40 if (!e->loc) {
41 l->argc = 0;
42 l->argv = (char **) empty;
43 } else {
44 l->argc = e->loc->argc;
45 l->argv = e->loc->argv;
47 l->exit = l->error = NULL;
48 ktinit(&l->vars, &l->area, 0);
49 ktinit(&l->funs, &l->area, 0);
50 l->next = e->loc;
51 e->loc = l;
55 * pop a block handling special variables
57 void
58 popblock(void)
60 struct block *l = e->loc;
61 struct tbl *vp, **vpp = l->vars.tbls, *vq;
62 int i;
64 e->loc = l->next; /* pop block */
65 for (i = l->vars.size; --i >= 0; )
66 if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) {
67 if ((vq = global(vp->name))->flag & ISSET)
68 setspec(vq);
69 else
70 unsetspec(vq);
72 if (l->flags & BF_DOGETOPTS)
73 user_opt = l->getopts_state;
74 afreeall(&l->area);
75 afree(l, ATEMP);
78 /* called by main() to initialize variable data structures */
79 void
80 initvar(void)
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 { "RANDOM", V_RANDOM },
97 { "SECONDS", V_SECONDS },
98 { "TMOUT", V_TMOUT },
99 { "LINENO", V_LINENO },
100 { (char *) 0, 0 }
102 int i;
103 struct tbl *tp;
105 ktinit(&specials, APERM, 32); /* must be 2^n (currently 17 specials) */
106 for (i = 0; names[i].name; i++) {
107 tp = ktenter(&specials, names[i].name, hash(names[i].name));
108 tp->flag = DEFINED|ISSET;
109 tp->type = names[i].v;
113 /* Used to calculate an array index for global()/local(). Sets *arrayp to
114 * non-zero if this is an array, sets *valp to the array index, returns
115 * the basename of the array.
117 const char *
118 array_index_calc(const char *n, bool *arrayp, int *valp)
120 const char *p;
121 int len;
123 *arrayp = false;
124 p = skip_varname(n, false);
125 if (p != n && *p == '[' && (len = array_ref_len(p))) {
126 char *sub, *tmp;
127 long rval;
129 /* Calculate the value of the subscript */
130 *arrayp = true;
131 tmp = str_nsave(p+1, len-2, ATEMP);
132 sub = substitute(tmp, 0);
133 afree(tmp, ATEMP);
134 n = str_nsave(n, p - n, ATEMP);
135 evaluate(sub, &rval, KSH_UNWIND_ERROR, true);
136 if (rval < 0 || rval > ARRAYMAX)
137 errorf("%s: subscript %ld out of range", n, rval);
138 *valp = rval;
139 afree(sub, ATEMP);
141 return n;
145 * Search for variable, if not found create globally.
147 struct tbl *
148 global(const char *n)
150 struct block *l = e->loc;
151 struct tbl *vp;
152 int c;
153 unsigned int h;
154 bool array;
155 int val;
157 /* Check to see if this is an array */
158 n = array_index_calc(n, &array, &val);
159 h = hash(n);
160 c = n[0];
161 if (!letter(c)) {
162 if (array)
163 errorf("bad substitution");
164 vp = &vtemp;
165 vp->flag = DEFINED;
166 vp->type = 0;
167 vp->areap = ATEMP;
168 *vp->name = c;
169 if (digit(c)) {
170 for (c = 0; digit(*n); n++)
171 c = c*10 + *n-'0';
172 if (c <= l->argc)
173 /* setstr can't fail here */
174 setstr(vp, l->argv[c], KSH_RETURN_ERROR);
175 vp->flag |= RDONLY;
176 return vp;
178 vp->flag |= RDONLY;
179 if (n[1] != '\0')
180 return vp;
181 vp->flag |= ISSET|INTEGER;
182 switch (c) {
183 case '$':
184 vp->val.i = kshpid;
185 break;
186 case '!':
187 /* If no job, expand to nothing */
188 if ((vp->val.i = j_async()) == 0)
189 vp->flag &= ~(ISSET|INTEGER);
190 break;
191 case '?':
192 vp->val.i = exstat;
193 break;
194 case '#':
195 vp->val.i = l->argc;
196 break;
197 case '-':
198 vp->flag &= ~INTEGER;
199 vp->val.s = getoptions();
200 break;
201 default:
202 vp->flag &= ~(ISSET|INTEGER);
204 return vp;
206 for (l = e->loc; ; l = l->next) {
207 vp = ktsearch(&l->vars, n, h);
208 if (vp != NULL) {
209 if (array)
210 return arraysearch(vp, val);
211 else
212 return vp;
214 if (l->next == NULL)
215 break;
217 vp = ktenter(&l->vars, n, h);
218 if (array)
219 vp = arraysearch(vp, val);
220 vp->flag |= DEFINED;
221 if (special(n))
222 vp->flag |= SPECIAL;
223 return vp;
227 * Search for local variable, if not found create locally.
229 struct tbl *
230 local(const char *n, bool copy)
232 struct block *l = e->loc;
233 struct tbl *vp;
234 unsigned int h;
235 bool array;
236 int val;
238 /* Check to see if this is an array */
239 n = array_index_calc(n, &array, &val);
240 h = hash(n);
241 if (!letter(*n)) {
242 vp = &vtemp;
243 vp->flag = DEFINED|RDONLY;
244 vp->type = 0;
245 vp->areap = ATEMP;
246 return vp;
248 vp = ktenter(&l->vars, n, h);
249 if (copy && !(vp->flag & DEFINED)) {
250 struct block *ll = l;
251 struct tbl *vq = (struct tbl *) 0;
253 while ((ll = ll->next) && !(vq = ktsearch(&ll->vars, n, h)))
255 if (vq) {
256 vp->flag |= vq->flag & (EXPORTV|INTEGER|RDONLY
257 |LJUST|RJUST|ZEROFIL
258 |LCASEV|UCASEV_AL|INT_U|INT_L);
259 if (vq->flag & INTEGER)
260 vp->type = vq->type;
261 vp->u2.field = vq->u2.field;
264 if (array)
265 vp = arraysearch(vp, val);
266 vp->flag |= DEFINED;
267 if (special(n))
268 vp->flag |= SPECIAL;
269 return vp;
272 /* get variable string value */
273 char *
274 str_val(struct tbl *vp)
276 char *s;
278 if ((vp->flag&SPECIAL))
279 getspec(vp);
280 if (!(vp->flag&ISSET))
281 s = null; /* special to dollar() */
282 else if (!(vp->flag&INTEGER)) /* string source */
283 s = vp->val.s + vp->type;
284 else { /* integer source */
285 /* worst case number length is when base=2, so use BITS(long) */
286 /* minus base # number null */
287 char strbuf[1 + 2 + 1 + BITS(long) + 1];
288 const char *digits = (vp->flag & UCASEV_AL) ?
289 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
290 : "0123456789abcdefghijklmnopqrstuvwxyz";
291 unsigned long n;
292 int base;
294 s = strbuf + sizeof(strbuf);
295 if (vp->flag & INT_U)
296 n = (unsigned long) vp->val.i;
297 else
298 n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
299 base = (vp->type == 0) ? 10 : vp->type;
301 *--s = '\0';
302 do {
303 *--s = digits[n % base];
304 n /= base;
305 } while (n != 0);
306 if (base != 10) {
307 *--s = '#';
308 *--s = digits[base % 10];
309 if (base >= 10)
310 *--s = digits[base / 10];
312 if (!(vp->flag & INT_U) && vp->val.i < 0)
313 *--s = '-';
314 if (vp->flag & (RJUST|LJUST)) /* case already dealt with */
315 s = formatstr(vp, s);
316 else
317 s = str_save(s, ATEMP);
319 return s;
322 /* get variable integer value, with error checking */
323 long
324 intval(struct tbl *vp)
326 long num;
327 int base;
329 base = getint(vp, &num, false);
330 if (base == -1)
331 /* XXX check calls - is error here ok by POSIX? */
332 errorf("%s: bad number", str_val(vp));
333 return num;
336 /* set variable to string value */
338 setstr(struct tbl *vq, const char *s, int error_ok)
340 const char *fs = NULL;
341 int no_ro_check = error_ok & 0x4;
342 error_ok &= ~0x4;
343 if ((vq->flag & RDONLY) && !no_ro_check) {
344 warningf(true, "%s: is read only", vq->name);
345 if (!error_ok)
346 errorf(null);
347 return 0;
349 if (!(vq->flag&INTEGER)) { /* string dest */
350 if ((vq->flag&ALLOC)) {
351 /* debugging */
352 if (s >= vq->val.s
353 && s <= vq->val.s + strlen(vq->val.s))
354 internal_errorf(true,
355 "setstr: %s=%s: assigning to self",
356 vq->name, s);
357 afree((void*)vq->val.s, vq->areap);
359 vq->flag &= ~(ISSET|ALLOC);
360 vq->type = 0;
361 if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST)))
362 fs = s = formatstr(vq, s);
363 if ((vq->flag&EXPORTV))
364 export(vq, s);
365 else {
366 vq->val.s = str_save(s, vq->areap);
367 if (vq->val.s) /* <sjg> don't lie */
368 vq->flag |= ALLOC;
370 } else /* integer dest */
371 if (!v_evaluate(vq, s, error_ok, true))
372 return 0;
373 vq->flag |= ISSET;
374 if ((vq->flag&SPECIAL))
375 setspec(vq);
376 if (fs)
377 afree((char *)fs, ATEMP);
378 return 1;
381 /* set variable to integer */
382 void
383 setint(struct tbl *vq, long int n)
385 if (!(vq->flag&INTEGER)) {
386 struct tbl *vp = &vtemp;
387 vp->flag = (ISSET|INTEGER);
388 vp->type = 0;
389 vp->areap = ATEMP;
390 vp->val.i = n;
391 /* setstr can't fail here */
392 setstr(vq, str_val(vp), KSH_RETURN_ERROR);
393 } else
394 vq->val.i = n;
395 vq->flag |= ISSET;
396 if ((vq->flag&SPECIAL))
397 setspec(vq);
401 getint(struct tbl *vp, long int *nump, bool arith)
403 char *s;
404 int c;
405 int base, neg;
406 int have_base = 0;
407 long num;
409 if (vp->flag&SPECIAL)
410 getspec(vp);
411 /* XXX is it possible for ISSET to be set and val.s to be 0? */
412 if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
413 return -1;
414 if (vp->flag&INTEGER) {
415 *nump = vp->val.i;
416 return vp->type;
418 s = vp->val.s + vp->type;
419 if (s == NULL) /* redundant given initial test */
420 s = null;
421 base = 10;
422 num = 0;
423 neg = 0;
424 if (arith && *s == '0' && *(s+1)) {
425 s++;
426 if (*s == 'x' || *s == 'X') {
427 s++;
428 base = 16;
429 } else if (vp->flag & ZEROFIL) {
430 while (*s == '0')
431 s++;
432 } else
433 base = 8;
434 have_base++;
436 for (c = *s++; c ; c = *s++) {
437 if (c == '-') {
438 neg++;
439 } else if (c == '#') {
440 base = (int) num;
441 if (have_base || base < 2 || base > 36)
442 return -1;
443 num = 0;
444 have_base = 1;
445 } else if (letnum(c)) {
446 if (isdigit(c))
447 c -= '0';
448 else if (islower(c))
449 c -= 'a' - 10; /* todo: assumes ascii */
450 else if (isupper(c))
451 c -= 'A' - 10; /* todo: assumes ascii */
452 else
453 c = -1; /* _: force error */
454 if (c < 0 || c >= base)
455 return -1;
456 num = num * base + c;
457 } else
458 return -1;
460 if (neg)
461 num = -num;
462 *nump = num;
463 return base;
466 /* convert variable vq to integer variable, setting its value from vp
467 * (vq and vp may be the same)
469 struct tbl *
470 setint_v(struct tbl *vq, struct tbl *vp, bool arith)
472 int base;
473 long num;
475 if ((base = getint(vp, &num, arith)) == -1)
476 return NULL;
477 if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) {
478 vq->flag &= ~ALLOC;
479 afree(vq->val.s, vq->areap);
481 vq->val.i = num;
482 if (vq->type == 0) /* default base */
483 vq->type = base;
484 vq->flag |= ISSET|INTEGER;
485 if (vq->flag&SPECIAL)
486 setspec(vq);
487 return vq;
490 static char *
491 formatstr(struct tbl *vp, const char *s)
493 int olen, nlen;
494 char *p, *q;
496 olen = strlen(s);
498 if (vp->flag & (RJUST|LJUST)) {
499 if (!vp->u2.field) /* default field width */
500 vp->u2.field = olen;
501 nlen = vp->u2.field;
502 } else
503 nlen = olen;
505 p = (char *) alloc(nlen + 1, ATEMP);
506 if (vp->flag & (RJUST|LJUST)) {
507 int slen;
509 if (vp->flag & RJUST) {
510 const char *q = s + olen;
511 /* strip trailing spaces (at&t ksh uses q[-1] == ' ') */
512 while (q > s && isspace(q[-1]))
513 --q;
514 slen = q - s;
515 if (slen > vp->u2.field) {
516 s += slen - vp->u2.field;
517 slen = vp->u2.field;
519 shf_snprintf(p, nlen + 1,
520 ((vp->flag & ZEROFIL) && digit(*s)) ?
521 "%0*s%.*s" : "%*s%.*s",
522 vp->u2.field - slen, null, slen, s);
523 } else {
524 /* strip leading spaces/zeros */
525 while (isspace(*s))
526 s++;
527 if (vp->flag & ZEROFIL)
528 while (*s == '0')
529 s++;
530 shf_snprintf(p, nlen + 1, "%-*.*s",
531 vp->u2.field, vp->u2.field, s);
533 } else
534 memcpy(p, s, olen + 1);
536 if (vp->flag & UCASEV_AL) {
537 for (q = p; *q; q++)
538 if (islower(*q))
539 *q = toupper(*q);
540 } else if (vp->flag & LCASEV) {
541 for (q = p; *q; q++)
542 if (isupper(*q))
543 *q = tolower(*q);
546 return p;
550 * make vp->val.s be "name=value" for quick exporting.
552 static void
553 export(struct tbl *vp, const char *val)
555 char *xp;
556 char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
557 int namelen = strlen(vp->name);
558 int vallen = strlen(val) + 1;
560 vp->flag |= ALLOC;
561 xp = (char*)alloc(namelen + 1 + vallen, vp->areap);
562 memcpy(vp->val.s = xp, vp->name, namelen);
563 xp += namelen;
564 *xp++ = '=';
565 vp->type = xp - vp->val.s; /* offset to value */
566 memcpy(xp, val, vallen);
567 if (op != NULL)
568 afree((void*)op, vp->areap);
572 * lookup variable (according to (set&LOCAL)),
573 * set its attributes (INTEGER, RDONLY, EXPORTV, TRACE, LJUST, RJUST, ZEROFIL,
574 * LCASEV, UCASEV_AL), and optionally set its value if an assignment.
576 struct tbl *
577 typeset(const char *var, Tflag set, Tflag clr, int field, int base)
579 struct tbl *vp;
580 struct tbl *vpbase, *t;
581 char *tvar;
582 const char *val;
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;
591 len = array_ref_len(val);
592 if (len == 0)
593 return NULL;
594 /* IMPORTV 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.
600 if (set & IMPORTV) {
601 int i;
602 for (i = 1; i < len - 1; i++)
603 if (!digit(val[i]))
604 return NULL;
606 val += len;
608 if (*val == '=')
609 tvar = str_nsave(var, val++ - var, ATEMP);
610 else {
611 /* Importing from original environment: must have an = */
612 if (set & IMPORTV)
613 return NULL;
614 tvar = (char *) var;
615 val = NULL;
618 vp = (set&LOCAL) ? local(tvar, (set & LOCAL_COPY) ? true : false)
619 : global(tvar);
620 set &= ~(LOCAL|LOCAL_COPY);
622 vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp;
624 /* only allow export flag to be set. at&t ksh allows any attribute to
625 * be changed, which means it can be truncated or modified
626 * (-L/-R/-Z/-i).
628 if ((vpbase->flag&RDONLY)
629 && (val || clr || (set & ~EXPORTV)))
630 /* XXX check calls - is error here ok by POSIX? */
631 errorf("%s: is read only", tvar);
632 if (val)
633 afree(tvar, ATEMP);
635 /* most calls are with set/clr == 0 */
636 if (set | clr) {
637 int ok = 1;
638 /* XXX if x[0] isn't set, there will be problems: need to have
639 * one copy of attributes for arrays...
641 for (t = vpbase; t; t = t->u.array) {
642 int fake_assign;
643 char *s = NULL;
644 char *free_me = NULL;
646 fake_assign = (t->flag & ISSET) && (!val || t != vp)
647 && ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL))
648 || ((t->flag & INTEGER) && (clr & INTEGER))
649 || (!(t->flag & INTEGER) && (set & INTEGER)));
650 if (fake_assign) {
651 if (t->flag & INTEGER) {
652 s = str_val(t);
653 free_me = (char *) 0;
654 } else {
655 s = t->val.s + t->type;
656 free_me = (t->flag & ALLOC) ? t->val.s
657 : (char *) 0;
659 t->flag &= ~ALLOC;
661 if (!(t->flag & INTEGER) && (set & INTEGER)) {
662 t->type = 0;
663 t->flag &= ~ALLOC;
665 t->flag = (t->flag | set) & ~clr;
666 /* Don't change base if assignment is to be done,
667 * in case assignment fails.
669 if ((set & INTEGER) && base > 0 && (!val || t != vp))
670 t->type = base;
671 if (set & (LJUST|RJUST|ZEROFIL))
672 t->u2.field = field;
673 if (fake_assign) {
674 if (!setstr(t, s, KSH_RETURN_ERROR)) {
675 /* Somewhat arbitrary action here:
676 * zap contents of varibale, but keep
677 * the flag settings.
679 ok = 0;
680 if (t->flag & INTEGER)
681 t->flag &= ~ISSET;
682 else {
683 if (t->flag & ALLOC)
684 afree((void*) t->val.s,
685 t->areap);
686 t->flag &= ~(ISSET|ALLOC);
687 t->type = 0;
690 if (free_me)
691 afree((void *) free_me, t->areap);
694 if (!ok)
695 errorf(null);
698 if (val != NULL) {
699 if (vp->flag&INTEGER) {
700 /* do not zero base before assignment */
701 setstr(vp, val, KSH_UNWIND_ERROR | 0x4);
702 /* Done after assignment to override default */
703 if (base > 0)
704 vp->type = base;
705 } else
706 /* setstr can't fail (readonly check already done) */
707 setstr(vp, val, KSH_RETURN_ERROR | 0x4);
710 /* only x[0] is ever exported, so use vpbase */
711 if ((vpbase->flag&EXPORTV) && !(vpbase->flag&INTEGER)
712 && vpbase->type == 0)
713 export(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null);
715 return vp;
718 /* Unset a variable. array_ref is set if there was an array reference in
719 * the name lookup (eg, x[2]).
721 void
722 unset(struct tbl *vp, int array_ref)
724 if (vp->flag & ALLOC)
725 afree((void*)vp->val.s, vp->areap);
726 if ((vp->flag & ARRAY) && !array_ref) {
727 struct tbl *a, *tmp;
729 /* Free up entire array */
730 for (a = vp->u.array; a; ) {
731 tmp = a;
732 a = a->u.array;
733 if (tmp->flag & ALLOC)
734 afree((void *) tmp->val.s, tmp->areap);
735 afree(tmp, tmp->areap);
737 vp->u.array = (struct tbl *) 0;
739 /* If foo[0] is being unset, the remainder of the array is kept... */
740 vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0);
741 if (vp->flag & SPECIAL)
742 unsetspec(vp); /* responsible for `unspecial'ing var */
745 /* return a pointer to the first char past a legal variable name (returns the
746 * argument if there is no legal name, returns * a pointer to the terminating
747 * null if whole string is legal).
749 char *
750 skip_varname(const char *s, int aok)
752 int alen;
754 if (s && letter(*s)) {
755 while (*++s && letnum(*s))
757 if (aok && *s == '[' && (alen = array_ref_len(s)))
758 s += alen;
760 return (char *) s;
763 /* Return a pointer to the first character past any legal variable name. */
764 char *
765 skip_wdvarname(const char *s, int aok) /* skip array de-reference? */
767 if (s[0] == CHAR && letter(s[1])) {
769 s += 2;
770 }while (s[0] == CHAR && letnum(s[1]));
771 if (aok && s[0] == CHAR && s[1] == '[') {
772 /* skip possible array de-reference */
773 const char *p = s;
774 char c;
775 int depth = 0;
777 while (1) {
778 if (p[0] != CHAR)
779 break;
780 c = p[1];
781 p += 2;
782 if (c == '[')
783 depth++;
784 else if (c == ']' && --depth == 0) {
785 s = p;
786 break;
791 return (char *) s;
794 /* Check if coded string s is a variable name */
796 is_wdvarname(const char *s, int aok)
798 char *p = skip_wdvarname(s, aok);
800 return p != s && p[0] == EOS;
803 /* Check if coded string s is a variable assignment */
805 is_wdvarassign(const char *s)
807 char *p = skip_wdvarname(s, true);
809 return p != s && p[0] == CHAR && p[1] == '=';
813 * Make the exported environment from the exported names in the dictionary.
815 char **
816 makenv(void)
818 struct block *l = e->loc;
819 XPtrV env;
820 struct tbl *vp, **vpp;
821 int i;
822 char **ap;
824 XPinit(env, 64);
825 for (l = e->loc; l != NULL; l = l->next)
826 for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
827 if ((vp = *vpp++) != NULL
828 && (vp->flag&(ISSET|EXPORTV))==(ISSET|EXPORTV)) {
829 struct block *l2;
830 struct tbl *vp2;
831 unsigned int h = hash(vp->name);
833 /* unexport any redefined instances */
834 for (l2 = l->next; l2 != NULL; l2 = l2->next) {
835 vp2 = ktsearch(&l2->vars, vp->name, h);
836 if (vp2 != NULL)
838 vp2->flag &= ~EXPORTV;
841 if ((vp->flag&INTEGER)) {
842 /* integer to string */
843 char *val;
844 val = str_val(vp);
845 vp->flag &= ~(INTEGER|RDONLY);
846 /* setstr can't fail here */
847 setstr(vp, val, KSH_RETURN_ERROR);
849 XPput(env, vp->val.s);
851 XPput(env, NULL);
852 ap = (char **) XPclose(env);
853 return (char **) ap;
857 * Someone has set the srand() value, therefore from now on
858 * we return values from rand() instead of arc4random()
860 int use_rand = 0;
863 * Called after a fork in parent to bump the random number generator.
864 * Done to ensure children will not get the same random number sequence
865 * if the parent doesn't use $RANDOM.
867 void
868 change_random(void)
870 rand();
874 * handle special variables with side effects - PATH, SECONDS.
877 /* Test if name is a special parameter */
878 static int
879 special(const char *name)
881 struct tbl *tp;
883 tp = ktsearch(&specials, name, hash(name));
884 return tp && (tp->flag & ISSET) ? tp->type : V_NONE;
887 /* Make a variable non-special */
888 static void
889 unspecial(const char *name)
891 struct tbl *tp;
893 tp = ktsearch(&specials, name, hash(name));
894 if (tp)
895 ktdelete(tp);
898 static time_t seconds; /* time SECONDS last set */
899 static int user_lineno; /* what user set $LINENO to */
901 static void
902 getspec(struct tbl *vp)
904 switch (special(vp->name)) {
905 case V_SECONDS:
906 vp->flag &= ~SPECIAL;
907 /* On start up the value of SECONDS is used before seconds
908 * has been set - don't do anything in this case
909 * (see initcoms[] in main.c).
911 if (vp->flag & ISSET)
912 setint(vp, (long) (time((time_t *)0) - seconds));
913 vp->flag |= SPECIAL;
914 break;
915 case V_RANDOM:
916 vp->flag &= ~SPECIAL;
917 setint(vp, (long) (rand() & 0x7fff));
918 vp->flag |= SPECIAL;
919 break;
920 #ifdef HISTORY
921 case V_HISTSIZE:
922 vp->flag &= ~SPECIAL;
923 setint(vp, (long) histsize);
924 vp->flag |= SPECIAL;
925 break;
926 #endif /* HISTORY */
927 case V_OPTIND:
928 vp->flag &= ~SPECIAL;
929 setint(vp, (long) user_opt.uoptind);
930 vp->flag |= SPECIAL;
931 break;
932 case V_LINENO:
933 vp->flag &= ~SPECIAL;
934 setint(vp, (long) current_lineno + user_lineno);
935 vp->flag |= SPECIAL;
936 break;
940 static void
941 setspec(struct tbl *vp)
943 char *s;
945 switch (special(vp->name)) {
946 case V_PATH:
947 if (path)
948 afree(path, APERM);
949 path = str_save(str_val(vp), APERM);
950 flushcom(1); /* clear tracked aliases */
951 break;
952 case V_IFS:
953 setctypes(s = str_val(vp), C_IFS);
954 ifs0 = *s;
955 break;
956 case V_OPTIND:
957 vp->flag &= ~SPECIAL;
958 getopts_reset((int) intval(vp));
959 vp->flag |= SPECIAL;
960 break;
961 case V_POSIXLY_CORRECT:
962 change_flag(FPOSIX, OF_SPECIAL, 1);
963 break;
964 case V_TMPDIR:
965 if (tmpdir) {
966 afree(tmpdir, APERM);
967 tmpdir = (char *) 0;
969 /* Use tmpdir iff it is an absolute path, is writable and
970 * searchable and is a directory...
973 struct stat statb;
974 s = str_val(vp);
975 if (ISABSPATH(s) && eaccess(s, W_OK|X_OK) == 0
976 && stat(s, &statb) == 0 && S_ISDIR(statb.st_mode))
977 tmpdir = str_save(s, APERM);
979 break;
980 #ifdef HISTORY
981 case V_HISTSIZE:
982 vp->flag &= ~SPECIAL;
983 sethistsize((int) intval(vp));
984 vp->flag |= SPECIAL;
985 break;
986 case V_HISTFILE:
987 sethistfile(str_val(vp));
988 break;
989 #endif /* HISTORY */
990 case V_RANDOM:
991 vp->flag &= ~SPECIAL;
992 srand((unsigned int)intval(vp));
993 vp->flag |= SPECIAL;
994 break;
995 case V_SECONDS:
996 vp->flag &= ~SPECIAL;
997 seconds = time((time_t*) 0) - intval(vp);
998 vp->flag |= SPECIAL;
999 break;
1000 case V_TMOUT:
1001 /* at&t ksh seems to do this (only listen if integer) */
1002 if (vp->flag & INTEGER)
1003 ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0;
1004 break;
1005 case V_LINENO:
1006 vp->flag &= ~SPECIAL;
1007 /* The -1 is because line numbering starts at 1. */
1008 user_lineno = (unsigned int) intval(vp) - current_lineno - 1;
1009 vp->flag |= SPECIAL;
1010 break;
1014 static void
1015 unsetspec(struct tbl *vp)
1017 switch (special(vp->name)) {
1018 case V_PATH:
1019 if (path)
1020 afree(path, APERM);
1021 path = str_save(def_path, APERM);
1022 flushcom(1); /* clear tracked aliases */
1023 break;
1024 case V_IFS:
1025 setctypes(" \t\n", C_IFS);
1026 ifs0 = ' ';
1027 break;
1028 case V_TMPDIR:
1029 /* should not become unspecial */
1030 if (tmpdir) {
1031 afree(tmpdir, APERM);
1032 tmpdir = (char *) 0;
1034 break;
1035 case V_LINENO:
1036 case V_RANDOM:
1037 case V_SECONDS:
1038 case V_TMOUT: /* at&t ksh leaves previous value in place */
1039 unspecial(vp->name);
1040 break;
1042 /* at&t ksh man page says OPTIND, OPTARG and _ lose special meaning,
1043 * but OPTARG does not (still set by getopts) and _ is also still
1044 * set in various places.
1045 * Unsetting these in at&t ksh does not loose the `specialness':
1046 * no effect: IFS, COLUMNS, PATH, TMPDIR,
1047 * VISUAL, EDITOR,
1048 * pdkshisms: no effect:
1049 * POSIXLY_CORRECT (use set +o posix instead)
1055 * Search for (and possibly create) a table entry starting with
1056 * vp, indexed by val.
1058 static struct tbl *
1059 arraysearch(struct tbl *vp, int val)
1061 struct tbl *prev, *curr, *new;
1062 size_t namelen = strlen(vp->name) + 1;
1064 vp->flag |= ARRAY|DEFINED;
1066 vp->index = 0;
1067 /* The table entry is always [0] */
1068 if (val == 0)
1069 return vp;
1071 prev = vp;
1072 curr = vp->u.array;
1073 while (curr && curr->index < val) {
1074 prev = curr;
1075 curr = curr->u.array;
1077 if (curr && curr->index == val) {
1078 if (curr->flag&ISSET)
1079 return curr;
1080 else
1081 new = curr;
1082 } else
1083 new = (struct tbl *)alloc(sizeof(struct tbl) + namelen, vp->areap);
1084 strlcpy(new->name, vp->name, namelen);
1085 new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL);
1086 new->type = vp->type;
1087 new->areap = vp->areap;
1088 new->u2.field = vp->u2.field;
1089 new->index = val;
1090 if (curr != new) { /* not reusing old array entry */
1091 prev->u.array = new;
1092 new->u.array = curr;
1094 return new;
1097 /* Return the length of an array reference (eg, [1+2]) - cp is assumed
1098 * to point to the open bracket. Returns 0 if there is no matching closing
1099 * bracket.
1102 array_ref_len(const char *cp)
1104 const char *s = cp;
1105 int c;
1106 int depth = 0;
1108 while ((c = *s++) && (c != ']' || --depth))
1109 if (c == '[')
1110 depth++;
1111 if (!c)
1112 return 0;
1113 return s - cp;
1117 * Make a copy of the base of an array name
1119 char *
1120 arrayname(const char *str)
1122 const char *p;
1124 if ((p = strchr(str, '[')) == 0)
1125 /* Shouldn't happen, but why worry? */
1126 return (char *) str;
1128 return str_nsave(str, p - str, ATEMP);
1131 /* Set (or overwrite, if !reset) the array variable var to the values in vals.
1133 void
1134 set_array(const char *var, int reset, char **vals)
1136 struct tbl *vp, *vq;
1137 int i;
1139 /* to get local array, use "typeset foo; set -A foo" */
1140 vp = global(var);
1142 /* Note: at&t ksh allows set -A but not set +A of a read-only var */
1143 if ((vp->flag&RDONLY))
1144 errorf("%s: is read only", var);
1145 /* This code is quite non-optimal */
1146 if (reset > 0)
1147 /* trash existing values and attributes */
1148 unset(vp, 0);
1149 /* todo: would be nice for assignment to completely succeed or
1150 * completely fail. Only really effects integer arrays:
1151 * evaluation of some of vals[] may fail...
1153 for (i = 0; vals[i]; i++) {
1154 vq = arraysearch(vp, i);
1155 /* would be nice to deal with errors here... (see above) */
1156 setstr(vq, vals[i], KSH_RETURN_ERROR);