changelog for 0.9.1
[posh.git] / var.c
blob84c28d08aee95cec63b9a37dcec787900ae59e72
1 #include "sh.h"
2 #include "ksh_time.h"
3 #include "ksh_limval.h"
4 #include "ksh_stat.h"
5 #include <ctype.h>
6 #include <search.h>
8 extern int uoptind;
11 * Variables
13 * WARNING: unreadable code, needs a rewrite
15 * if (flag&INTEGER), val.i contains integer value, and type contains base.
16 * otherwise, (val.s + type) contains string value.
17 * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
19 static struct tbl vtemp;
20 static struct block *ltemp; /* ugly */
21 static XPtrV *envtemp; /* also ugly */
23 void * specials_root;
24 static void export ARGS((struct tbl *vp, const char *val));
25 static int special ARGS((const char *name));
26 static void unspecial ARGS((const char *name));
27 static void getspec ARGS((struct tbl *vp));
28 static void setspec ARGS((struct tbl *vp));
29 static void unsetspec ARGS((struct tbl *vp));
30 static struct tbl *arraysearch ARGS((struct tbl *, int));
33 * create a new block for function calls and simple commands
34 * assume caller has allocated and set up e->loc
36 void
37 newblock(void)
39 struct block *l;
40 static char *const empty[] = {null};
42 l = (struct block *) alloc(sizeof(struct block), ATEMP);
43 l->flags = 0;
44 ainit(&l->area); /* todo: could use e->area (l->area => l->areap) */
45 if (!e->loc) {
46 l->argc = 0;
47 l->argv = (char **) empty;
48 } else {
49 l->argc = e->loc->argc;
50 l->argv = e->loc->argv;
52 l->exit = l->error = NULL;
53 transitional_tinit(&l->vars, &l->area);
54 transitional_tinit(&l->funs, &l->area);
55 l->next = e->loc;
56 e->loc = l;
59 void popblock_walk(const void *nodep, const VISIT which, const int UNUSED(depth)) {
60 struct tbl *datap, *vq;
62 switch(which) {
63 case preorder:
64 case endorder:
65 break;
66 case postorder:
67 case leaf:
68 datap = *(struct tbl **)nodep;
69 if (datap->flag & SPECIAL) {
70 if ((vq = global(datap->name))->flag & ISSET)
71 setspec(vq);
72 else
73 unsetspec(vq);
75 break;
81 * pop a block handling special variables
83 void
84 popblock(void)
86 struct block *l = e->loc;
88 e->loc = l->next; /* pop block */
89 twalk(l->vars.root, popblock_walk);
90 if (l->flags & BF_DOGETOPTS)
91 user_opt = l->getopts_state;
92 afreeall(&l->area);
93 afree(l, ATEMP);
96 /* called by main() to initialize variable data structures */
97 void
98 initvar(void)
100 static const struct {
101 const char *name;
102 int v;
103 } names[] = {
104 { "COLUMNS", V_COLUMNS },
105 { "IFS", V_IFS },
106 { "OPTIND", V_OPTIND },
107 { "PATH", V_PATH },
108 { "TMPDIR", V_TMPDIR },
109 #ifdef HISTORY
110 { "HISTFILE", V_HISTFILE },
111 { "HISTSIZE", V_HISTSIZE },
112 #endif /* HISTORY */
113 #ifdef EDIT
114 { "EDITOR", V_EDITOR },
115 { "VISUAL", V_VISUAL },
116 #endif /* EDIT */
117 #ifdef KSH
118 { "MAIL", V_MAIL },
119 { "MAILCHECK", V_MAILCHECK },
120 { "MAILPATH", V_MAILPATH },
121 { "RANDOM", V_RANDOM },
122 { "SECONDS", V_SECONDS },
123 { "TMOUT", V_TMOUT },
124 #endif /* KSH */
125 { "LINENO", V_LINENO },
126 { (char *) 0, 0 }
128 int i;
129 struct tbl *tp;
131 specials_root = NULL;
132 for (i = 0; names[i].name; i++) {
133 tp = transitional_tenter((void **)&specials_root, names[i].name, APERM);
134 tp->flag = DEFINED|ISSET;
135 tp->type = names[i].v;
139 /* Used to calculate an array index for global()/local(). Sets *arrayp to
140 * non-zero if this is an array, sets *valp to the array index, returns
141 * the basename of the array.
143 const char *
144 array_index_calc(n, arrayp, valp)
145 const char *n;
146 bool_t *arrayp;
147 int *valp;
149 const char *p;
150 int len;
152 *arrayp = FALSE;
153 p = skip_varname(n, FALSE);
154 if (p != n && *p == '[' && (len = array_ref_len(p))) {
155 char *sub, *tmp;
156 long rval;
158 /* Calculate the value of the subscript */
159 *arrayp = TRUE;
160 tmp = str_nsave(p+1, len-2, ATEMP);
161 sub = substitute(tmp, 0);
162 afree(tmp, ATEMP);
163 n = str_nsave(n, p - n, ATEMP);
164 evaluate(sub, &rval, KSH_UNWIND_ERROR);
165 if (rval < 0 || rval > ARRAYMAX)
166 errorf("%s: subscript out of range", n);
167 *valp = rval;
168 afree(sub, ATEMP);
170 return (n);
174 * Search for variable, if not found create globally.
176 struct tbl *
177 global(const char *n)
179 struct block *l = e->loc;
180 struct tbl *vp;
181 int c;
182 bool_t array;
183 int val;
185 /* Check to see if this is an array */
186 n = array_index_calc(n, &array, &val);
187 c = n[0];
188 if (!isalpha(c) && c!='_') {
189 if (array)
190 errorf("bad substitution");
191 vp = &vtemp;
192 vp->flag = DEFINED;
193 vp->type = 0;
194 vp->areap = ATEMP;
195 *vp->name = c;
196 if (isdigit(c)) {
197 for (c = 0; isdigit(*n); n++)
198 c = c*10 + *n-'0';
199 if (c <= l->argc)
200 /* setstr can't fail here */
201 setstr(vp, l->argv[c], KSH_RETURN_ERROR);
202 vp->flag |= RDONLY;
203 return vp;
205 vp->flag |= RDONLY;
206 if (n[1] != '\0')
207 return vp;
208 vp->flag |= ISSET|INTEGER;
209 switch (c) {
210 case '$':
211 vp->val.i = kshpid;
212 break;
213 case '!':
214 /* If no job, expand to nothing */
215 if ((vp->val.i = j_async()) == 0)
216 vp->flag &= ~(ISSET|INTEGER);
217 break;
218 case '?':
219 vp->val.i = exstat;
220 break;
221 case '#':
222 vp->val.i = l->argc;
223 break;
224 case '-':
225 vp->flag &= ~INTEGER;
226 vp->val.s = getoptions();
227 break;
228 default:
229 vp->flag &= ~(ISSET|INTEGER);
231 return (vp);
233 for (l = e->loc; ; l = l->next) {
234 vp = transitional_tsearch(&l->vars.root, n);
235 if (vp != NULL) {
236 if (array)
237 return (arraysearch(vp, val));
238 else
239 return (vp);
241 if (l->next == NULL)
242 break;
244 vp = transitional_tenter(&l->vars.root, n, APERM);
245 if (array)
246 vp = arraysearch(vp, val);
247 vp->flag |= DEFINED;
248 if (special(n))
249 vp->flag |= SPECIAL;
250 return (vp);
254 * Search for local variable, if not found create locally.
256 struct tbl *
257 local(const char *n, bool_t copy)
259 struct block *l = e->loc;
260 struct tbl *vp;
261 bool_t array;
262 int val;
264 /* Check to see if this is an array */
265 n = array_index_calc(n, &array, &val);
266 if (!isalpha(*n) && *n!='_') {
267 vp = &vtemp;
268 vp->flag = DEFINED|RDONLY;
269 vp->type = 0;
270 vp->areap = ATEMP;
271 return (vp);
273 vp = transitional_tenter(&l->vars.root, n, &l->area);
274 if (copy && !(vp->flag & DEFINED)) {
275 struct block *ll = l;
276 struct tbl *vq = (struct tbl *) 0;
278 while ((ll = ll->next) && !(vq = transitional_tsearch(&ll->vars.root, n)))
280 if (vq) {
281 vp->flag |= vq->flag & (EXPORT|INTEGER|RDONLY);
282 if (vq->flag & INTEGER)
283 vp->type = vq->type;
284 vp->u2.field = vq->u2.field;
287 if (array)
288 vp = arraysearch(vp, val);
289 vp->flag |= DEFINED;
290 if (special(n))
291 vp->flag |= SPECIAL;
292 return (vp);
295 /* get variable string value */
296 char *
297 str_val(struct tbl *vp)
299 char *s;
301 if ((vp->flag&SPECIAL))
302 getspec(vp);
303 if (!(vp->flag&ISSET))
304 s = null; /* special to dollar() */
305 else if (!(vp->flag&INTEGER)) /* string source */
306 s = vp->val.s + vp->type;
307 else { /* integer source */
308 /* worst case number length is when base=2, so use BITS(long) */
309 /* minus base # number null */
310 static char strbuf[1 + 2 + 1 + BITS(long) + 1];
311 const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
312 register unsigned long n;
313 register int base;
315 s = strbuf + sizeof(strbuf);
316 n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
317 base = (vp->type == 0) ? 10 : vp->type;
319 *--s = '\0';
320 do {
321 *--s = digits[n % base];
322 n /= base;
323 } while (n != 0);
324 if (base != 10) {
325 *--s = '#';
326 *--s = digits[base % 10];
327 if (base >= 10)
328 *--s = digits[base / 10];
330 if (vp->val.i < 0)
331 *--s = '-';
333 return s;
336 /* get variable integer value, with error checking */
337 long
338 intval(vp)
339 register struct tbl *vp;
341 long num;
342 int base;
344 base = getint(vp, &num);
345 if (base == -1)
346 /* XXX check calls - is error here ok by POSIX? */
347 errorf("%s: bad number", str_val(vp));
348 return (num);
351 /* set variable to string value */
353 setstr(struct tbl *vq, const char *s, int error_ok)
355 int no_ro_check = error_ok & 0x4;
356 error_ok &= ~0x4;
357 if ((vq->flag & RDONLY) && !no_ro_check) {
358 warningf(TRUE, "%s: is read only", vq->name);
359 if (!error_ok)
360 errorf(null);
361 return (0);
363 if (!(vq->flag&INTEGER)) { /* string dest */
364 if ((vq->flag&ALLOC)) {
365 /* debugging */
366 if (s >= vq->val.s
367 && s <= vq->val.s + strlen(vq->val.s))
368 internal_errorf(TRUE,
369 "setstr: %s=%s: assigning to self",
370 vq->name, s);
371 afree((void*)vq->val.s, vq->areap);
373 vq->flag &= ~(ISSET|ALLOC);
374 vq->type = 0;
375 if ((vq->flag&EXPORT))
376 export(vq, s);
377 else {
378 vq->val.s = str_save(s, vq->areap);
379 if (vq->val.s) /* <sjg> don't lie */
380 vq->flag |= ALLOC;
382 } else /* integer dest */
383 if (!v_evaluate(vq, s, error_ok))
384 return 0;
385 vq->flag |= ISSET;
386 if ((vq->flag&SPECIAL))
387 setspec(vq);
388 return (1);
391 /* set variable to integer */
392 void
393 setint(struct tbl *vq, long n)
395 if (!(vq->flag&INTEGER)) {
396 struct tbl *vp = &vtemp;
397 vp->flag = (ISSET|INTEGER);
398 vp->type = 0;
399 vp->areap = ATEMP;
400 vp->val.i = n;
401 /* setstr can't fail here */
402 setstr(vq, str_val(vp), KSH_RETURN_ERROR);
403 } else
404 vq->val.i = n;
405 vq->flag |= ISSET;
406 if ((vq->flag&SPECIAL))
407 setspec(vq);
411 getint(struct tbl *vp, long *nump)
413 char *s;
414 int c, base, neg;
415 int have_base = 0;
416 long num;
418 if (vp->flag&SPECIAL)
419 getspec(vp);
420 /* XXX is it possible for ISSET to be set and val.s to be 0? */
421 if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
422 return (-1);
423 if (vp->flag&INTEGER) {
424 *nump = vp->val.i;
425 return (vp->type);
427 s = vp->val.s + vp->type;
428 if (s == NULL) /* redundent given initial test */
429 s = null;
430 base = 10;
431 num = 0;
432 neg = 0;
434 if ((c = *s) == '0') {
435 /* 0 means octal, 0x means hex */
436 if((c = *++s) == 'x') {
437 base = 16;
438 s++;
439 } else {
440 base = 8;
444 for (c = *s++; c ; c = *s++) {
445 if (c == '-') {
446 neg++;
447 } else if (c == '#') {
448 base = (int) num;
449 if (have_base || base < 2 || base > 36)
450 return -1;
451 num = 0;
452 have_base = 1;
453 } else if (isalnum(c) || c=='_') {
454 if (isdigit(c))
455 c -= '0';
456 else if (islower(c))
457 c -= 'a' - 10; /* todo: assumes ascii */
458 else if (isupper(c))
459 c -= 'A' - 10; /* todo: assumes ascii */
460 else
461 c = -1; /* _: force error */
462 if (c < 0 || c >= base)
463 return -1;
464 num = num * base + c;
465 } else
466 return -1;
468 if (neg)
469 num = -num;
470 *nump = num;
471 return base;
474 /* convert variable vq to integer variable, setting its value from vp
475 * (vq and vp may be the same)
477 struct tbl *
478 setint_v(vq, vp)
479 register struct tbl *vq, *vp;
481 int base;
482 long num;
484 if ((base = getint(vp, &num)) == -1)
485 return NULL;
486 if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) {
487 vq->flag &= ~ALLOC;
488 afree(vq->val.s, vq->areap);
490 vq->val.i = num;
491 if (vq->type == 0) /* default base */
492 vq->type = base;
493 vq->flag |= ISSET|INTEGER;
494 if (vq->flag&SPECIAL)
495 setspec(vq);
496 return vq;
499 #ifdef SILLY_FEATURES
500 static char *
501 formatstr(vp, s)
502 struct tbl *vp;
503 const char *s;
505 int olen, nlen;
506 char *p;
508 olen = strlen(s);
510 nlen = olen;
512 p = (char *) alloc(nlen + 1, ATEMP);
513 memcpy(p, s, olen + 1);
515 return p;
517 #endif /* SILLY_FEATURES */
520 * make vp->val.s be "name=value" for quick exporting.
522 static void
523 export(struct tbl *vp, const char *val)
525 char *xp;
526 char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
527 int namelen = strlen(vp->name);
528 int vallen = strlen(val) + 1;
530 vp->flag |= ALLOC;
531 xp = (char*)alloc(namelen + 1 + vallen, vp->areap);
532 memcpy(vp->val.s = xp, vp->name, namelen);
533 xp += namelen;
534 *xp++ = '=';
535 vp->type = xp - vp->val.s; /* offset to value */
536 memcpy(xp, val, vallen);
537 if (op != NULL)
538 afree((void*)op, vp->areap);
542 * lookup variable (according to (set&LOCAL)),
543 * set its attributes (INTEGER, RDONLY, EXPORT, TRACE),
544 * and optionally set its value if an assignment.
546 struct tbl *
547 typeset(const char *var, Tflag set, Tflag clr, int UNUSED(field), int base)
549 struct tbl *vp;
550 struct tbl *vpbase, *t;
551 char *tvar;
552 const char *val;
554 /* check for valid variable name, search for value */
555 val = skip_varname(var, FALSE);
556 if (val == var)
557 return (NULL);
558 if (*val == '[') {
559 int len;
561 len = array_ref_len(val);
562 if (len == 0)
563 return (NULL);
564 /* IMPORT is only used when the shell starts up and is
565 * setting up its environment. Allow only simple array
566 * references at this time since parameter/command substitution
567 * is preformed on the [expression], which would be a major
568 * security hole.
570 if (set & IMPORT) {
571 int i;
572 for (i = 1; i < len - 1; i++)
573 if (!isdigit(val[i]))
574 return NULL;
576 val += len;
578 if (*val == '=')
579 tvar = str_nsave(var, val++ - var, ATEMP);
580 else {
581 /* Importing from original envirnment: must have an = */
582 if (set & IMPORT)
583 return NULL;
584 tvar = (char *) var;
585 val = NULL;
588 vp = (set&LOCAL) ? local(tvar, (set & LOCAL_COPY) ? TRUE : FALSE)
589 : global(tvar);
590 set &= ~(LOCAL|LOCAL_COPY);
592 vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp;
594 /* only allow export flag to be set. at&t ksh allows any attribute to
595 * be changed, which means it can be truncated or modified
596 * (-L/-R/-Z/-i).
598 if ((vpbase->flag&RDONLY)
599 && (val || clr || (set & ~EXPORT)))
600 /* XXX check calls - is error here ok by POSIX? */
601 errorf("%s: is read only", tvar);
602 if (val)
603 afree(tvar, ATEMP);
605 /* most calls are with set/clr == 0 */
606 if (set | clr) {
607 int ok = 1;
608 /* XXX if x[0] isn't set, there will be problems: need to have
609 * one copy of attributes for arrays...
611 for (t = vpbase; t; t = t->u.array) {
612 int fake_assign;
613 char UNINITIALIZED(*s);
614 char UNINITIALIZED(*free_me);
616 fake_assign = (t->flag & ISSET) && (!val || t != vp)
617 && (((t->flag & INTEGER)
618 && (clr & INTEGER))
619 || (!(t->flag & INTEGER) && (set & INTEGER)));
620 if (fake_assign) {
621 if (t->flag & INTEGER) {
622 s = str_val(t);
623 free_me = (char *) 0;
624 } else {
625 s = t->val.s + t->type;
626 free_me = (t->flag & ALLOC) ? t->val.s
627 : (char *) 0;
629 t->flag &= ~ALLOC;
631 if (!(t->flag & INTEGER) && (set & INTEGER)) {
632 t->type = 0;
633 t->flag &= ~ALLOC;
635 t->flag = (t->flag | set) & ~clr;
636 /* Don't change base if assignment is to be done,
637 * in case assignment fails.
639 if ((set & INTEGER) && base > 0 && (!val || t != vp))
640 t->type = base;
641 if (fake_assign) {
642 if (!setstr(t, s, KSH_RETURN_ERROR)) {
643 /* Somewhat arbitrary action here:
644 * zap contents of varibale, but keep
645 * the flag settings.
647 ok = 0;
648 if (t->flag & INTEGER)
649 t->flag &= ~ISSET;
650 else {
651 if (t->flag & ALLOC)
652 afree((void*) t->val.s,
653 t->areap);
654 t->flag &= ~(ISSET|ALLOC);
655 t->type = 0;
658 if (free_me)
659 afree((void *) free_me, t->areap);
662 if (!ok)
663 errorf(null);
666 if (val != NULL) {
667 if (vp->flag&INTEGER) {
668 /* do not zero base before assignment */
669 setstr(vp, val, KSH_UNWIND_ERROR | 0x4);
670 /* Done after assignment to override default */
671 if (base > 0)
672 vp->type = base;
673 } else
674 /* setstr can't fail (readonly check already done) */
675 setstr(vp, val, KSH_RETURN_ERROR | 0x4);
678 /* only x[0] is ever exported, so use vpbase */
679 if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER)
680 && vpbase->type == 0)
681 export(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null);
683 return (vp);
686 /* Unset a variable. array_ref is set if there was an array reference in
687 * the name lookup (eg, x[2]).
689 void
690 unset(struct tbl *vp, int array_ref)
692 if (vp->flag & ALLOC)
693 afree((void*)vp->val.s, vp->areap);
694 if ((vp->flag & ARRAY) && !array_ref) {
695 struct tbl *a, *tmp;
697 /* Free up entire array */
698 for (a = vp->u.array; a; ) {
699 tmp = a;
700 a = a->u.array;
701 if (tmp->flag & ALLOC)
702 afree((void *) tmp->val.s, tmp->areap);
703 afree(tmp, tmp->areap);
705 vp->u.array = (struct tbl *) 0;
707 /* If foo[0] is being unset, the remainder of the array is kept... */
708 vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0);
709 if (vp->flag & SPECIAL)
710 unsetspec(vp); /* responsible for `unspecial'ing var */
713 /* return a pointer to the first char past a legal variable name (returns the
714 * argument if there is no legal name, returns * a pointer to the terminating
715 * null if whole string is legal).
717 char *
718 skip_varname(const char *s, int aok)
720 int alen;
722 if (s && (isalpha(*s) || *s=='_' )) {
723 while (*++s && (isalnum(*s) || *s=='_'))
725 if (aok && *s == '[' && (alen = array_ref_len(s)))
726 s += alen;
728 return (char *) s;
731 /* Return a pointer to the first character past any legal variable name. */
732 char *
733 skip_wdvarname(const char *s, int aok)
735 if (s[0] == CHAR && (isalpha(s[1]) || s[1]=='_')) {
737 s += 2;
738 while (s[0] == CHAR && (isalnum(s[1]) || s[1]=='_'));
739 if (aok && s[0] == CHAR && s[1] == '[') {
740 /* skip possible array de-reference */
741 const char *p = s;
742 char c;
743 int depth = 0;
745 while (1) {
746 if (p[0] != CHAR)
747 break;
748 c = p[1];
749 p += 2;
750 if (c == '[')
751 depth++;
752 else if (c == ']' && --depth == 0) {
753 s = p;
754 break;
759 return (char *) s;
762 /* Check if coded string s is a variable name */
764 is_wdvarname(const char *s, int aok)
766 char *p = skip_wdvarname(s, aok);
768 return p != s && p[0] == EOS;
771 /* Check if coded string s is a variable assignment */
773 is_wdvarassign(const char *s)
775 char *p = skip_wdvarname(s, TRUE);
777 return p != s && p[0] == CHAR && p[1] == '=';
780 void makeenv_walk(const void *nodep, const VISIT which, const int UNUSED(depth)) {
781 struct tbl *datap, *vp2;
782 struct block *l2;
784 switch(which) {
785 case preorder:
786 case endorder:
787 break;
788 case postorder:
789 case leaf:
790 datap = *(struct tbl **)nodep;
791 if ((datap->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
792 /* unexport any redefined instances */
793 for (l2 = ltemp->next; l2 != NULL; l2 = l2->next) {
794 vp2 = transitional_tsearch(&l2->vars.root, datap->name);
795 if (vp2 != NULL)
796 vp2->flag &= ~EXPORT;
798 if ((datap->flag&INTEGER)) {
799 /* integer to string */
800 char *val;
801 val = str_val(datap);
802 datap->flag &= ~(INTEGER|RDONLY);
803 /* setstr can't fail here */
804 setstr(datap, val, KSH_RETURN_ERROR);
806 XPput(*envtemp, datap->val.s);
808 break;
813 * Make the exported environment from the exported names in the dictionary.
815 char **
816 makenv()
818 struct block *l = e->loc;
819 XPtrV env;
821 XPinit(env, 64);
822 for (l = e->loc; l != NULL; l = l->next) {
823 ltemp = l;
824 envtemp = &env;
825 twalk(l->vars.root, makeenv_walk);
827 XPput(env, NULL);
828 return (char **) XPclose(env);
832 * Called after a fork in parent to bump the random number generator.
833 * Done to ensure children will not get the same random number sequence
834 * if the parent doesn't use $RANDOM.
836 void
837 change_random()
839 rand();
843 * handle special variables with side effects - PATH, SECONDS.
846 /* Test if name is a special parameter */
847 static int
848 special(const char *name)
850 struct tbl *tp;
852 tp = transitional_tsearch((void **)&specials_root, name);
853 return tp && (tp->flag & ISSET) ? tp->type : V_NONE;
856 /* Make a variable non-special */
857 static void
858 unspecial(const char *name)
860 struct tbl *tp;
862 tp = transitional_tsearch((void **)&specials_root, name);
863 if (tp)
864 transitional_tdelete((void **)&specials_root, tp);
867 #ifdef KSH
868 static time_t seconds; /* time SECONDS last set */
869 #endif /* KSH */
870 static int user_lineno; /* what user set $LINENO to */
872 static void
873 getspec(vp)
874 register struct tbl *vp;
876 switch (special(vp->name)) {
877 #ifdef KSH
878 case V_SECONDS:
879 vp->flag &= ~SPECIAL;
880 /* On start up the value of SECONDS is used before seconds
881 * has been set - don't do anything in this case
882 * (see initcoms[] in main.c).
884 if (vp->flag & ISSET)
885 setint(vp, (long) (time((time_t *)0) - seconds));
886 vp->flag |= SPECIAL;
887 break;
888 case V_RANDOM:
889 vp->flag &= ~SPECIAL;
890 setint(vp, (long) (rand() & 0x7fff));
891 vp->flag |= SPECIAL;
892 break;
893 #endif /* KSH */
894 #ifdef HISTORY
895 case V_HISTSIZE:
896 vp->flag &= ~SPECIAL;
897 setint(vp, (long) histsize);
898 vp->flag |= SPECIAL;
899 break;
900 #endif /* HISTORY */
901 case V_OPTIND:
902 vp->flag &= ~SPECIAL;
903 setint(vp, (long) uoptind);
904 vp->flag |= SPECIAL;
905 break;
906 case V_LINENO:
907 vp->flag &= ~SPECIAL;
908 setint(vp, (long) current_lineno + user_lineno);
909 vp->flag |= SPECIAL;
910 break;
914 static void
915 setspec(struct tbl *vp)
917 char *s;
919 switch (special(vp->name)) {
920 case V_PATH:
921 if (path)
922 afree(path, APERM);
923 path = str_save(str_val(vp), APERM);
924 break;
925 case V_IFS:
926 setctypes(s = str_val(vp), C_IFS);
927 ifs0 = *s;
928 break;
929 case V_OPTIND:
930 vp->flag &= ~SPECIAL;
931 optind = uoptind = ((int) intval(vp));
932 vp->flag |= SPECIAL;
933 break;
934 case V_TMPDIR:
935 if (tmpdir) {
936 afree(tmpdir, APERM);
937 tmpdir = (char *) 0;
939 /* Use tmpdir iff it is an absolute path, is writable and
940 * searchable and is a directory...
943 struct stat statb;
944 s = str_val(vp);
945 if (ISABSPATH(s) && eaccess(s, W_OK|X_OK) == 0
946 && stat(s, &statb) == 0 && S_ISDIR(statb.st_mode))
947 tmpdir = str_save(s, APERM);
949 break;
950 #ifdef HISTORY
951 case V_HISTSIZE:
952 vp->flag &= ~SPECIAL;
953 sethistsize((int) intval(vp));
954 vp->flag |= SPECIAL;
955 break;
956 case V_HISTFILE:
957 sethistfile(str_val(vp));
958 break;
959 #endif /* HISTORY */
960 #ifdef EDIT
961 case V_VISUAL:
962 set_editmode(str_val(vp));
963 break;
964 case V_EDITOR:
965 if (!(global("VISUAL")->flag & ISSET))
966 set_editmode(str_val(vp));
967 break;
968 case V_COLUMNS:
969 if ((x_cols = intval(vp)) <= MIN_COLS)
970 x_cols = MIN_COLS;
971 break;
972 #endif /* EDIT */
973 #ifdef KSH
974 case V_MAIL:
975 mbset(str_val(vp));
976 break;
977 case V_MAILPATH:
978 mpset(str_val(vp));
979 break;
980 case V_MAILCHECK:
981 vp->flag &= ~SPECIAL;
982 mcset(intval(vp));
983 vp->flag |= SPECIAL;
984 break;
985 case V_RANDOM:
986 vp->flag &= ~SPECIAL;
987 srand((unsigned int)intval(vp));
988 vp->flag |= SPECIAL;
989 break;
990 case V_SECONDS:
991 vp->flag &= ~SPECIAL;
992 seconds = time((time_t*) 0) - intval(vp);
993 vp->flag |= SPECIAL;
994 break;
995 case V_TMOUT:
996 /* at&t ksh seems to do this (only listen if integer) */
997 if (vp->flag & INTEGER)
998 ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0;
999 break;
1000 #endif /* KSH */
1001 case V_LINENO:
1002 vp->flag &= ~SPECIAL;
1003 /* The -1 is because line numbering starts at 1. */
1004 user_lineno = (unsigned int) intval(vp) - current_lineno - 1;
1005 vp->flag |= SPECIAL;
1006 break;
1010 static void
1011 unsetspec(struct tbl *vp)
1013 switch (special(vp->name)) {
1014 case V_PATH:
1015 if (path)
1016 afree(path, APERM);
1017 path = str_save(def_path, APERM);
1018 break;
1019 case V_IFS:
1020 setctypes(" \t\n", C_IFS);
1021 ifs0 = ' ';
1022 break;
1023 case V_TMPDIR:
1024 /* should not become unspecial */
1025 if (tmpdir) {
1026 afree(tmpdir, APERM);
1027 tmpdir = (char *) 0;
1029 break;
1030 #ifdef KSH
1031 case V_MAIL:
1032 mbset((char *) 0);
1033 break;
1034 case V_MAILPATH:
1035 mpset((char *) 0);
1036 break;
1037 #endif /* KSH */
1039 case V_LINENO:
1040 #ifdef KSH
1041 case V_MAILCHECK: /* at&t ksh leaves previous value in place */
1042 case V_RANDOM:
1043 case V_SECONDS:
1044 case V_TMOUT: /* at&t ksh leaves previous value in place */
1045 #endif /* KSH */
1046 unspecial(vp->name);
1047 break;
1049 /* at&t ksh man page says OPTIND, OPTARG and _ lose special meaning,
1050 * but OPTARG does not (still set by getopts) and _ is also still
1051 * set in various places.
1052 * Don't know what at&t does for:
1053 * MAIL, MAILPATH, HISTSIZE, HISTFILE,
1054 * Unsetting these in at&t ksh does not loose the `specialness':
1055 * no effect: IFS, COLUMNS, PATH, TMPDIR,
1056 * VISUAL, EDITOR,
1062 * Search for (and possibly create) a table entry starting with
1063 * vp, indexed by val.
1065 static struct tbl *
1066 arraysearch(struct tbl *vp, int val)
1068 struct tbl *prev, *curr, *new;
1070 vp->flag |= ARRAY|DEFINED;
1072 /* The table entry is always [0] */
1073 if (val == 0) {
1074 vp->index = 0;
1075 return vp;
1077 prev = vp;
1078 curr = vp->u.array;
1079 while (curr && curr->index < val) {
1080 prev = curr;
1081 curr = curr->u.array;
1083 if (curr && curr->index == val) {
1084 if (curr->flag&ISSET)
1085 return curr;
1086 else
1087 new = curr;
1088 } else
1089 new = (struct tbl *)alloc(sizeof(struct tbl)+strlen(vp->name)+1, vp->areap);
1090 strcpy(new->name, vp->name);
1091 new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL);
1092 new->type = vp->type;
1093 new->areap = vp->areap;
1094 new->u2.field = vp->u2.field;
1095 new->index = val;
1096 if (curr != new) { /* not reusing old array entry */
1097 prev->u.array = new;
1098 new->u.array = curr;
1100 return (new);
1103 /* Return the length of an array reference (eg, [1+2]) - cp is assumed
1104 * to point to the open bracket. Returns 0 if there is no matching closing
1105 * bracket.
1108 array_ref_len(const char *cp)
1110 const char *s = cp;
1111 int c;
1112 int depth = 0;
1114 while ((c = *s++) && (c != ']' || --depth))
1115 if (c == '[')
1116 depth++;
1117 if (!c)
1118 return (0);
1119 return (s - cp);
1123 * Make a copy of the base of an array name
1125 char *
1126 arrayname(const char *str)
1128 const char *p;
1130 if ((p = strchr(str, '[')) == 0)
1131 /* Shouldn't happen, but why worry? */
1132 return (char *) str;
1134 return str_nsave(str, p - str, ATEMP);