1 /* $NetBSD: var.c,v 1.17 2011/10/16 17:12:11 joerg Exp $ */
6 __RCSID("$NetBSD: var.c,v 1.17 2011/10/16 17:12:11 joerg Exp $");
12 #include "ksh_limval.h"
19 * WARNING: unreadable code, needs a rewrite
21 * if (flag&INTEGER), val.i contains integer value, and type contains base.
22 * otherwise, (val.s + type) contains string value.
23 * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
25 static struct tbl vtemp
;
26 static struct table specials
;
27 static char *formatstr
ARGS((struct tbl
*vp
, const char *s
));
28 static void export
ARGS((struct tbl
*vp
, const char *val
));
29 static int special
ARGS((const char *name
));
30 static void unspecial
ARGS((const char *name
));
31 static void getspec
ARGS((struct tbl
*vp
));
32 static void setspec
ARGS((struct tbl
*vp
));
33 static void unsetspec
ARGS((struct tbl
*vp
));
34 static struct tbl
*arraysearch
ARGS((struct tbl
*, int));
37 * create a new block for function calls and simple commands
38 * assume caller has allocated and set up e->loc
43 register struct block
*l
;
44 static char *const empty
[] = {null
};
46 l
= (struct block
*) alloc(sizeof(struct block
), ATEMP
);
48 ainit(&l
->area
); /* todo: could use e->area (l->area => l->areap) */
51 l
->argv
= (char **) __UNCONST(empty
);
53 l
->argc
= e
->loc
->argc
;
54 l
->argv
= e
->loc
->argv
;
56 l
->exit
= l
->error
= NULL
;
57 tinit(&l
->vars
, &l
->area
, 0);
58 tinit(&l
->funs
, &l
->area
, 0);
64 * pop a block handling special variables
69 register struct block
*l
= e
->loc
;
70 register struct tbl
*vp
, **vpp
= l
->vars
.tbls
, *vq
;
73 e
->loc
= l
->next
; /* pop block */
74 for (i
= l
->vars
.size
; --i
>= 0; ) {
75 if ((vp
= *vpp
++) != NULL
&& (vp
->flag
&SPECIAL
)) {
76 if ((vq
= global(vp
->name
))->flag
& ISSET
)
82 if (l
->flags
& BF_DOGETOPTS
)
83 user_opt
= l
->getopts_state
;
88 /* called by main() to initialize variable data structures */
96 { "COLUMNS", V_COLUMNS
},
98 { "OPTIND", V_OPTIND
},
100 { "POSIXLY_CORRECT", V_POSIXLY_CORRECT
},
101 { "TMPDIR", V_TMPDIR
},
103 { "HISTFILE", V_HISTFILE
},
104 { "HISTSIZE", V_HISTSIZE
},
107 { "EDITOR", V_EDITOR
},
108 { "VISUAL", V_VISUAL
},
112 { "MAILCHECK", V_MAILCHECK
},
113 { "MAILPATH", V_MAILPATH
},
114 { "RANDOM", V_RANDOM
},
115 { "SECONDS", V_SECONDS
},
116 { "TMOUT", V_TMOUT
},
118 { "LINENO", V_LINENO
},
124 tinit(&specials
, APERM
, 32); /* must be 2^n (currently 17 specials) */
125 for (i
= 0; names
[i
].name
; i
++) {
126 tp
= tenter(&specials
, names
[i
].name
, hash(names
[i
].name
));
127 tp
->flag
= DEFINED
|ISSET
;
128 tp
->type
= names
[i
].v
;
132 /* Used to calculate an array index for global()/local(). Sets *arrayp to
133 * non-zero if this is an array, sets *valp to the array index, returns
134 * the basename of the array.
136 const char *array_index_calc(const char *n
, bool_t
*arrayp
, int *valp
);
139 array_index_calc(n
, arrayp
, valp
)
148 p
= skip_varname(n
, FALSE
);
149 if (p
!= n
&& *p
== '[' && (len
= array_ref_len(p
))) {
153 /* Calculate the value of the subscript */
155 tmp
= str_nsave(p
+1, len
-2, ATEMP
);
156 sub
= substitute(tmp
, 0);
158 n
= str_nsave(n
, p
- n
, ATEMP
);
159 evaluate(sub
, &rval
, KSH_UNWIND_ERROR
);
160 if (rval
< 0 || rval
> ARRAYMAX
)
161 errorf("%s: subscript out of range", n
);
169 * Search for variable, if not found create globally.
173 register const char *n
;
175 register struct block
*l
= e
->loc
;
176 register struct tbl
*vp
;
182 /* Check to see if this is an array */
183 n
= array_index_calc(n
, &array
, &val
);
188 errorf("bad substitution");
195 for (c
= 0; digit(*n
); n
++)
198 /* setstr can't fail here */
199 setstr(vp
, l
->argv
[c
], KSH_RETURN_ERROR
);
206 vp
->flag
|= ISSET
|INTEGER
;
212 /* If no job, expand to nothing */
213 if ((vp
->val
.i
= j_async()) == 0)
214 vp
->flag
&= ~(ISSET
|INTEGER
);
223 vp
->flag
&= ~INTEGER
;
224 vp
->val
.s
= getoptions();
227 vp
->flag
&= ~(ISSET
|INTEGER
);
231 for (l
= e
->loc
; ; l
= l
->next
) {
232 vp
= tsearch(&l
->vars
, n
, h
);
235 return arraysearch(vp
, val
);
242 vp
= tenter(&l
->vars
, n
, h
);
244 vp
= arraysearch(vp
, val
);
252 * Search for local variable, if not found create locally.
256 register const char *n
;
259 register struct block
*l
= e
->loc
;
260 register struct tbl
*vp
;
265 /* Check to see if this is an array */
266 n
= array_index_calc(n
, &array
, &val
);
270 vp
->flag
= DEFINED
|RDONLY
;
275 vp
= tenter(&l
->vars
, n
, h
);
276 if (copy
&& !(vp
->flag
& DEFINED
)) {
277 struct block
*ll
= l
;
278 struct tbl
*vq
= (struct tbl
*) 0;
280 while ((ll
= ll
->next
) && !(vq
= tsearch(&ll
->vars
, n
, h
)))
283 vp
->flag
|= vq
->flag
& (EXPORT
|INTEGER
|RDONLY
285 |LCASEV
|UCASEV_AL
|INT_U
|INT_L
);
286 if (vq
->flag
& INTEGER
)
288 vp
->u2
.field
= vq
->u2
.field
;
292 vp
= arraysearch(vp
, val
);
299 /* get variable string value */
302 register struct tbl
*vp
;
306 if ((vp
->flag
&SPECIAL
))
308 if (!(vp
->flag
&ISSET
))
309 s
= null
; /* special to dollar() */
310 else if (!(vp
->flag
&INTEGER
)) /* string source */
311 s
= vp
->val
.s
+ vp
->type
;
312 else { /* integer source */
313 /* worst case number length is when base=2, so use BITS(long) */
314 /* minus base # number null */
315 static char strbuf
[1 + 2 + 1 + BITS(long) + 1];
316 const char *digits
= (vp
->flag
& UCASEV_AL
) ?
317 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
318 : "0123456789abcdefghijklmnopqrstuvwxyz";
319 register unsigned long n
;
322 s
= strbuf
+ sizeof(strbuf
);
323 if (vp
->flag
& INT_U
)
324 n
= (unsigned long) vp
->val
.i
;
326 n
= (vp
->val
.i
< 0) ? -vp
->val
.i
: vp
->val
.i
;
327 base
= (vp
->type
== 0) ? 10 : vp
->type
;
331 *--s
= digits
[n
% base
];
336 *--s
= digits
[base
% 10];
338 *--s
= digits
[base
/ 10];
340 if (!(vp
->flag
& INT_U
) && vp
->val
.i
< 0)
342 if (vp
->flag
& (RJUST
|LJUST
)) { /* case already dealt with */
343 s
= formatstr(vp
, s
);
344 (void)strlcpy(strbuf
, s
, sizeof(strbuf
));
352 /* get variable integer value, with error checking */
355 register struct tbl
*vp
;
360 base
= getint(vp
, &num
);
362 /* XXX check calls - is error here ok by POSIX? */
363 errorf("%s: bad number", str_val(vp
));
367 /* set variable to string value */
369 setstr(vq
, s
, error_ok
)
370 register struct tbl
*vq
;
375 int no_ro_check
= error_ok
& 0x4;
377 if ((vq
->flag
& RDONLY
) && !no_ro_check
) {
378 warningf(TRUE
, "%s: is read only", vq
->name
);
383 if (!(vq
->flag
&INTEGER
)) { /* string dest */
384 if ((vq
->flag
&ALLOC
)) {
387 && s
<= vq
->val
.s
+ strlen(vq
->val
.s
))
388 internal_errorf(TRUE
,
389 "setstr: %s=%s: assigning to self",
391 afree((void*)vq
->val
.s
, vq
->areap
);
393 vq
->flag
&= ~(ISSET
|ALLOC
);
395 if (s
&& (vq
->flag
& (UCASEV_AL
|LCASEV
|LJUST
|RJUST
)))
396 s
= fs
= formatstr(vq
, s
);
397 if ((vq
->flag
&EXPORT
))
400 vq
->val
.s
= str_save(s
, vq
->areap
);
403 } else /* integer dest */
404 if (!v_evaluate(vq
, s
, error_ok
))
407 if ((vq
->flag
&SPECIAL
))
414 /* set variable to integer */
417 register struct tbl
*vq
;
420 if (!(vq
->flag
&INTEGER
)) {
421 register struct tbl
*vp
= &vtemp
;
422 vp
->flag
= (ISSET
|INTEGER
);
426 /* setstr can't fail here */
427 setstr(vq
, str_val(vp
), KSH_RETURN_ERROR
);
431 if ((vq
->flag
&SPECIAL
))
446 if (vp
->flag
&SPECIAL
)
448 /* XXX is it possible for ISSET to be set and val.s to be 0? */
449 if (!(vp
->flag
&ISSET
) || (!(vp
->flag
&INTEGER
) && vp
->val
.s
== NULL
))
451 if (vp
->flag
&INTEGER
) {
455 s
= vp
->val
.s
+ vp
->type
;
456 if (s
== NULL
) /* redundant given initial test */
465 if (s
[0] == '0' && s
[1] == 'x') {
470 for (c
= (unsigned char)*s
++; c
; c
= (unsigned char)*s
++) {
473 if (have_base
|| base
< 2 || base
> 36)
477 } else if (letnum(c
)) {
481 c
-= 'a' - 10; /* todo: assumes ascii */
483 c
-= 'A' - 10; /* todo: assumes ascii */
485 c
= -1; /* _: force error */
486 if (c
< 0 || c
>= base
)
488 num
= num
* base
+ c
;
498 /* convert variable vq to integer variable, setting its value from vp
499 * (vq and vp may be the same)
503 register struct tbl
*vq
, *vp
;
508 if ((base
= getint(vp
, &num
)) == -1)
510 if (!(vq
->flag
& INTEGER
) && (vq
->flag
& ALLOC
)) {
512 afree(vq
->val
.s
, vq
->areap
);
515 if (vq
->type
== 0) /* default base */
517 vq
->flag
|= ISSET
|INTEGER
;
518 if (vq
->flag
&SPECIAL
)
533 if (vp
->flag
& (RJUST
|LJUST
)) {
534 if (!vp
->u2
.field
) /* default field width */
540 p
= (char *) alloc(nlen
+ 1, ATEMP
);
541 if (vp
->flag
& (RJUST
|LJUST
)) {
544 if (vp
->flag
& RJUST
) {
545 const char *r
= s
+ olen
;
546 /* strip trailing spaces (at&t ksh uses q[-1] == ' ') */
547 while (r
> s
&& isspace((unsigned char)r
[-1]))
550 if (slen
> vp
->u2
.field
) {
551 s
+= slen
- vp
->u2
.field
;
554 shf_snprintf(p
, nlen
+ 1,
555 ((vp
->flag
& ZEROFIL
) && digit(*s
)) ?
556 "%0*s%.*s" : "%*s%.*s",
557 vp
->u2
.field
- slen
, null
, slen
, s
);
559 /* strip leading spaces/zeros */
560 while (isspace((unsigned char)*s
))
562 if (vp
->flag
& ZEROFIL
)
565 shf_snprintf(p
, nlen
+ 1, "%-*.*s",
566 vp
->u2
.field
, vp
->u2
.field
, s
);
569 memcpy(p
, s
, olen
+ 1);
571 if (vp
->flag
& UCASEV_AL
) {
573 if (islower((unsigned char)*q
))
574 *q
= toupper((unsigned char)*q
);
575 } else if (vp
->flag
& LCASEV
) {
577 if (isupper((unsigned char)*q
))
578 *q
= tolower((unsigned char)*q
);
585 * make vp->val.s be "name=value" for quick exporting.
589 register struct tbl
*vp
;
593 char *op
= (vp
->flag
&ALLOC
) ? vp
->val
.s
: NULL
;
594 int namelen
= strlen(vp
->name
);
595 int vallen
= strlen(val
) + 1;
598 xp
= (char*)alloc(namelen
+ 1 + vallen
, vp
->areap
);
599 memcpy(vp
->val
.s
= xp
, vp
->name
, namelen
);
602 vp
->type
= xp
- vp
->val
.s
; /* offset to value */
603 memcpy(xp
, val
, vallen
);
605 afree((void*)op
, vp
->areap
);
609 * lookup variable (according to (set&LOCAL)),
610 * set its attributes (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL,
611 * LCASEV, UCASEV_AL), and optionally set its value if an assignment.
614 typeset(var
, set
, clr
, field
, base
)
615 register const char *var
;
619 register struct tbl
*vp
;
620 struct tbl
*vpbase
, *t
;
624 /* check for valid variable name, search for value */
625 val
= skip_varname(var
, FALSE
);
631 len
= array_ref_len(val
);
634 /* IMPORT is only used when the shell starts up and is
635 * setting up its environment. Allow only simple array
636 * references at this time since parameter/command substitution
637 * is performed on the [expression], which would be a major
642 for (i
= 1; i
< len
- 1; i
++)
649 tvar
= str_nsave(var
, val
++ - var
, ATEMP
);
651 /* Importing from original environment: must have an = */
654 tvar
= (char *) __UNCONST(var
);
658 /* Prevent typeset from creating a local PATH/ENV/SHELL */
659 if (Flag(FRESTRICTED
) && (strcmp(tvar
, "PATH") == 0
660 || strcmp(tvar
, "ENV") == 0
661 || strcmp(tvar
, "SHELL") == 0))
662 errorf("%s: restricted", tvar
);
664 vp
= (set
&LOCAL
) ? local(tvar
, (set
& LOCAL_COPY
) ? TRUE
: FALSE
)
666 set
&= ~(LOCAL
|LOCAL_COPY
);
668 vpbase
= (vp
->flag
& ARRAY
) ? global(arrayname(var
)) : vp
;
670 /* only allow export flag to be set. at&t ksh allows any attribute to
671 * be changed, which means it can be truncated or modified
674 if ((vpbase
->flag
&RDONLY
)
675 && (val
|| clr
|| (set
& ~EXPORT
)))
676 /* XXX check calls - is error here ok by POSIX? */
677 errorf("%s: is read only", tvar
);
681 /* most calls are with set/clr == 0 */
684 /* XXX if x[0] isn't set, there will be problems: need to have
685 * one copy of attributes for arrays...
687 for (t
= vpbase
; t
; t
= t
->u
.array
) {
689 char UNINITIALIZED(*s
);
690 char UNINITIALIZED(*free_me
);
692 fake_assign
= (t
->flag
& ISSET
) && (!val
|| t
!= vp
)
693 && ((set
& (UCASEV_AL
|LCASEV
|LJUST
|RJUST
|ZEROFIL
))
694 || ((t
->flag
& INTEGER
) && (clr
& INTEGER
))
695 || (!(t
->flag
& INTEGER
) && (set
& INTEGER
)));
697 if (t
->flag
& INTEGER
) {
699 free_me
= (char *) 0;
701 s
= t
->val
.s
+ t
->type
;
702 free_me
= (t
->flag
& ALLOC
) ? t
->val
.s
707 if (!(t
->flag
& INTEGER
) && (set
& INTEGER
)) {
711 t
->flag
= (t
->flag
| set
) & ~clr
;
712 /* Don't change base if assignment is to be done,
713 * in case assignment fails.
715 if ((set
& INTEGER
) && base
> 0 && (!val
|| t
!= vp
))
717 if (set
& (LJUST
|RJUST
|ZEROFIL
))
720 if (!setstr(t
, s
, KSH_RETURN_ERROR
)) {
721 /* Somewhat arbitrary action here:
722 * zap contents of variable, but keep
726 if (t
->flag
& INTEGER
)
730 afree((void*) t
->val
.s
,
732 t
->flag
&= ~(ISSET
|ALLOC
);
737 afree((void *) free_me
, t
->areap
);
745 if (vp
->flag
&INTEGER
) {
746 /* do not zero base before assignment */
747 setstr(vp
, val
, KSH_UNWIND_ERROR
| 0x4);
748 /* Done after assignment to override default */
752 /* setstr can't fail (readonly check already done) */
753 setstr(vp
, val
, KSH_RETURN_ERROR
| 0x4);
756 /* only x[0] is ever exported, so use vpbase */
757 if ((vpbase
->flag
&EXPORT
) && !(vpbase
->flag
&INTEGER
)
758 && vpbase
->type
== 0)
759 export(vpbase
, (vpbase
->flag
&ISSET
) ? vpbase
->val
.s
: null
);
764 /* Unset a variable. array_ref is set if there was an array reference in
765 * the name lookup (eg, x[2]).
769 register struct tbl
*vp
;
772 if (vp
->flag
& ALLOC
)
773 afree((void*)vp
->val
.s
, vp
->areap
);
774 if ((vp
->flag
& ARRAY
) && !array_ref
) {
777 /* Free up entire array */
778 for (a
= vp
->u
.array
; a
; ) {
781 if (tmp
->flag
& ALLOC
)
782 afree((void *) tmp
->val
.s
, tmp
->areap
);
783 afree(tmp
, tmp
->areap
);
785 vp
->u
.array
= (struct tbl
*) 0;
787 /* If foo[0] is being unset, the remainder of the array is kept... */
788 vp
->flag
&= SPECIAL
| (array_ref
? ARRAY
|DEFINED
: 0);
789 if (vp
->flag
& SPECIAL
)
790 unsetspec(vp
); /* responsible for `unspecial'ing var */
793 /* return a pointer to the first char past a legal variable name (returns the
794 * argument if there is no legal name, returns * a pointer to the terminating
795 * null if whole string is legal).
804 if (s
&& letter(*s
)) {
805 while (*++s
&& letnum(*s
))
807 if (aok
&& *s
== '[' && (alen
= array_ref_len(s
)))
810 return (char *) __UNCONST(s
);
813 /* Return a pointer to the first character past any legal variable name. */
815 skip_wdvarname(s
, aok
)
817 int aok
; /* skip array de-reference? */
819 if (s
[0] == CHAR
&& letter(s
[1])) {
822 while (s
[0] == CHAR
&& letnum(s
[1]));
823 if (aok
&& s
[0] == CHAR
&& s
[1] == '[') {
824 /* skip possible array de-reference */
836 else if (c
== ']' && --depth
== 0) {
843 return (char *) __UNCONST(s
);
846 /* Check if coded string s is a variable name */
852 char *p
= skip_wdvarname(s
, aok
);
854 return p
!= s
&& p
[0] == EOS
;
857 /* Check if coded string s is a variable assignment */
862 char *p
= skip_wdvarname(s
, TRUE
);
864 return p
!= s
&& p
[0] == CHAR
&& p
[1] == '=';
868 * Make the exported environment from the exported names in the dictionary.
873 struct block
*l
= e
->loc
;
875 register struct tbl
*vp
, **vpp
;
879 for (l
= e
->loc
; l
!= NULL
; l
= l
->next
)
880 for (vpp
= l
->vars
.tbls
, i
= l
->vars
.size
; --i
>= 0; )
881 if ((vp
= *vpp
++) != NULL
882 && (vp
->flag
&(ISSET
|EXPORT
)) == (ISSET
|EXPORT
)) {
883 register struct block
*l2
;
884 register struct tbl
*vp2
;
885 unsigned h
= hash(vp
->name
);
887 /* unexport any redefined instances */
888 for (l2
= l
->next
; l2
!= NULL
; l2
= l2
->next
) {
889 vp2
= tsearch(&l2
->vars
, vp
->name
, h
);
891 vp2
->flag
&= ~EXPORT
;
893 if ((vp
->flag
&INTEGER
)) {
894 /* integer to string */
897 vp
->flag
&= ~(INTEGER
|RDONLY
);
898 /* setstr can't fail here */
899 setstr(vp
, val
, KSH_RETURN_ERROR
);
901 XPput(env
, vp
->val
.s
);
904 return (char **) XPclose(env
);
908 * Called after a fork in parent to bump the random number generator.
909 * Done to ensure children will not get the same random number sequence
910 * if the parent doesn't use $RANDOM.
919 * handle special variables with side effects - PATH, SECONDS.
922 /* Test if name is a special parameter */
925 register const char * name
;
927 register struct tbl
*tp
;
929 tp
= tsearch(&specials
, name
, hash(name
));
930 return tp
&& (tp
->flag
& ISSET
) ? tp
->type
: V_NONE
;
933 /* Make a variable non-special */
936 register const char * name
;
938 register struct tbl
*tp
;
940 tp
= tsearch(&specials
, name
, hash(name
));
946 static time_t seconds
; /* time SECONDS last set */
948 static int user_lineno
; /* what user set $LINENO to */
952 register struct tbl
*vp
;
954 switch (special(vp
->name
)) {
957 vp
->flag
&= ~SPECIAL
;
958 /* On start up the value of SECONDS is used before seconds
959 * has been set - don't do anything in this case
960 * (see initcoms[] in main.c).
962 if (vp
->flag
& ISSET
)
963 setint(vp
, (long) (time((time_t *)0) - seconds
));
967 vp
->flag
&= ~SPECIAL
;
968 setint(vp
, (long) (rand() & 0x7fff));
974 vp
->flag
&= ~SPECIAL
;
975 setint(vp
, (long) histsize
);
980 vp
->flag
&= ~SPECIAL
;
981 setint(vp
, (long) user_opt
.uoptind
);
985 vp
->flag
&= ~SPECIAL
;
986 setint(vp
, (long) current_lineno
+ user_lineno
);
994 register struct tbl
*vp
;
998 switch (special(vp
->name
)) {
1002 path
= str_save(str_val(vp
), APERM
);
1003 flushcom(1); /* clear tracked aliases */
1006 setctypes(s
= str_val(vp
), C_IFS
);
1010 vp
->flag
&= ~SPECIAL
;
1011 getopts_reset((int) intval(vp
));
1012 vp
->flag
|= SPECIAL
;
1014 case V_POSIXLY_CORRECT
:
1015 change_flag(FPOSIX
, OF_SPECIAL
, 1);
1019 afree(tmpdir
, APERM
);
1020 tmpdir
= (char *) 0;
1022 /* Use tmpdir iff it is an absolute path, is writable and
1023 * searchable and is a directory...
1028 if (ISABSPATH(s
) && eaccess(s
, W_OK
|X_OK
) == 0
1029 && stat(s
, &statb
) == 0 && S_ISDIR(statb
.st_mode
))
1030 tmpdir
= str_save(s
, APERM
);
1035 vp
->flag
&= ~SPECIAL
;
1036 sethistsize((int) intval(vp
));
1037 vp
->flag
|= SPECIAL
;
1040 sethistfile(str_val(vp
));
1042 #endif /* HISTORY */
1045 set_editmode(str_val(vp
));
1048 if (!(global("VISUAL")->flag
& ISSET
))
1049 set_editmode(str_val(vp
));
1052 if ((x_cols
= intval(vp
)) <= MIN_COLS
)
1064 vp
->flag
&= ~SPECIAL
;
1066 vp
->flag
|= SPECIAL
;
1069 vp
->flag
&= ~SPECIAL
;
1070 srand((unsigned int)intval(vp
));
1071 vp
->flag
|= SPECIAL
;
1074 vp
->flag
&= ~SPECIAL
;
1075 seconds
= time((time_t*) 0) - intval(vp
);
1076 vp
->flag
|= SPECIAL
;
1079 /* at&t ksh seems to do this (only listen if integer) */
1080 if (vp
->flag
& INTEGER
)
1081 ksh_tmout
= vp
->val
.i
>= 0 ? vp
->val
.i
: 0;
1085 vp
->flag
&= ~SPECIAL
;
1086 /* The -1 is because line numbering starts at 1. */
1087 user_lineno
= (unsigned int) intval(vp
) - current_lineno
- 1;
1088 vp
->flag
|= SPECIAL
;
1095 register struct tbl
*vp
;
1097 switch (special(vp
->name
)) {
1101 path
= str_save(def_path
, APERM
);
1102 flushcom(1); /* clear tracked aliases */
1105 setctypes(" \t\n", C_IFS
);
1109 /* should not become unspecial */
1111 afree(tmpdir
, APERM
);
1112 tmpdir
= (char *) 0;
1126 case V_MAILCHECK
: /* at&t ksh leaves previous value in place */
1129 case V_TMOUT
: /* at&t ksh leaves previous value in place */
1131 unspecial(vp
->name
);
1134 /* at&t ksh man page says OPTIND, OPTARG and _ lose special meaning,
1135 * but OPTARG does not (still set by getopts) and _ is also still
1136 * set in various places.
1137 * Don't know what at&t does for:
1138 * MAIL, MAILPATH, HISTSIZE, HISTFILE,
1139 * Unsetting these in at&t ksh does not loose the `specialness':
1140 * no effect: IFS, COLUMNS, PATH, TMPDIR,
1142 * pdkshisms: no effect:
1143 * POSIXLY_CORRECT (use set +o posix instead)
1149 * Search for (and possibly create) a table entry starting with
1150 * vp, indexed by val.
1153 arraysearch(vp
, val
)
1157 struct tbl
*prev
, *curr
, *new;
1158 size_t namelen
= strlen(vp
->name
) + 1;
1160 vp
->flag
|= ARRAY
|DEFINED
;
1162 /* The table entry is always [0] */
1169 while (curr
&& curr
->index
< val
) {
1171 curr
= curr
->u
.array
;
1173 if (curr
&& curr
->index
== val
) {
1174 if (curr
->flag
&ISSET
)
1179 new = (struct tbl
*)alloc(sizeof(struct tbl
) + namelen
,
1181 strlcpy(new->name
, vp
->name
, namelen
);
1182 new->flag
= vp
->flag
& ~(ALLOC
|DEFINED
|ISSET
|SPECIAL
);
1183 new->type
= vp
->type
;
1184 new->areap
= vp
->areap
;
1185 new->u2
.field
= vp
->u2
.field
;
1187 if (curr
!= new) { /* not reusing old array entry */
1188 prev
->u
.array
= new;
1189 new->u
.array
= curr
;
1194 /* Return the length of an array reference (eg, [1+2]) - cp is assumed
1195 * to point to the open bracket. Returns 0 if there is no matching closing
1206 while ((c
= *s
++) && (c
!= ']' || --depth
))
1215 * Make a copy of the base of an array name
1223 if ((p
= strchr(str
, '[')) == 0)
1224 /* Shouldn't happen, but why worry? */
1225 return (char *) __UNCONST(str
);
1227 return str_nsave(str
, p
- str
, ATEMP
);
1230 /* Set (or overwrite, if !reset) the array variable var to the values in vals.
1233 set_array(var
, reset
, vals
)
1238 struct tbl
*vp
, *vq
;
1241 /* to get local array, use "typeset foo; set -A foo" */
1244 /* Note: at&t ksh allows set -A but not set +A of a read-only var */
1245 if ((vp
->flag
&RDONLY
))
1246 errorf("%s: is read only", var
);
1247 /* This code is quite non-optimal */
1249 /* trash existing values and attributes */
1251 /* todo: would be nice for assignment to completely succeed or
1252 * completely fail. Only really effects integer arrays:
1253 * evaluation of some of vals[] may fail...
1255 for (i
= 0; vals
[i
]; i
++) {
1256 vq
= arraysearch(vp
, i
);
1257 /* would be nice to deal with errors here... (see above) */
1258 setstr(vq
, vals
[i
], KSH_RETURN_ERROR
);