1 /* $OpenBSD: var.c,v 1.70 2018/06/18 21:46:05 millert Exp $ */
24 * WARNING: unreadable code, needs a rewrite
26 * if (flag&INTEGER), val.i contains integer value, and type contains base.
27 * otherwise, (val.s + type) contains string value.
28 * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
30 static struct tbl vtemp
;
31 static struct table specials
;
32 static char *formatstr(struct tbl
*, const char *);
33 static void export(struct tbl
*, const char *);
34 static int special(const char *);
35 static void unspecial(const char *);
36 static void getspec(struct tbl
*);
37 static void setspec(struct tbl
*);
38 static void unsetspec(struct tbl
*);
39 static struct tbl
*arraysearch(struct tbl
*, int);
42 * create a new block for function calls and simple commands
43 * assume caller has allocated and set up genv->loc
49 static char *const empty
[] = {null
};
51 l
= alloc(sizeof(struct block
), ATEMP
);
53 ainit(&l
->area
); /* todo: could use genv->area (l->area => l->areap) */
56 l
->argv
= (char **) empty
;
58 l
->argc
= genv
->loc
->argc
;
59 l
->argv
= genv
->loc
->argv
;
61 l
->exit
= l
->error
= NULL
;
62 ktinit(&l
->vars
, &l
->area
, 0);
63 ktinit(&l
->funs
, &l
->area
, 0);
69 * pop a block handling special variables
74 struct block
*l
= genv
->loc
;
75 struct tbl
*vp
, **vpp
= l
->vars
.tbls
, *vq
;
78 genv
->loc
= l
->next
; /* pop block */
79 for (i
= l
->vars
.size
; --i
>= 0; )
80 if ((vp
= *vpp
++) != NULL
&& (vp
->flag
&SPECIAL
)) {
81 if ((vq
= global(vp
->name
))->flag
& ISSET
)
86 if (l
->flags
& BF_DOGETOPTS
)
87 user_opt
= l
->getopts_state
;
92 /* called by main() to initialize variable data structures */
100 { "COLUMNS", V_COLUMNS
},
102 { "OPTIND", V_OPTIND
},
104 { "POSIXLY_CORRECT", V_POSIXLY_CORRECT
},
105 { "TMPDIR", V_TMPDIR
},
106 { "HISTCONTROL", V_HISTCONTROL
},
107 { "HISTFILE", V_HISTFILE
},
108 { "HISTSIZE", V_HISTSIZE
},
109 { "EDITOR", V_EDITOR
},
110 { "VISUAL", V_VISUAL
},
112 { "MAILCHECK", V_MAILCHECK
},
113 { "MAILPATH", V_MAILPATH
},
114 { "RANDOM", V_RANDOM
},
115 { "SECONDS", V_SECONDS
},
116 { "TMOUT", V_TMOUT
},
117 { "LINENO", V_LINENO
},
124 ktinit(&specials
, APERM
, 32); /* must be 2^n (currently 19 specials) */
125 for (i
= 0; names
[i
].name
; i
++) {
126 tp
= ktenter(&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.
137 array_index_calc(const char *n
, bool *arrayp
, int *valp
)
143 p
= skip_varname(n
, false);
144 if (p
!= n
&& *p
== '[' && (len
= array_ref_len(p
))) {
148 /* Calculate the value of the subscript */
150 tmp
= str_nsave(p
+1, len
-2, ATEMP
);
151 sub
= substitute(tmp
, 0);
153 n
= str_nsave(n
, p
- n
, ATEMP
);
154 evaluate(sub
, &rval
, KSH_UNWIND_ERROR
, true);
155 if (rval
< 0 || rval
> INT_MAX
)
156 errorf("%s: subscript %" PRIi64
" out of range",
165 * Search for variable, if not found create globally.
168 global(const char *n
)
170 struct block
*l
= genv
->loc
;
178 /* Check to see if this is an array */
179 n
= array_index_calc(n
, &array
, &val
);
181 c
= (unsigned char)n
[0];
184 errorf("bad substitution");
192 num
= strtol(n
, NULL
, 10);
193 if (errno
== 0 && num
<= l
->argc
)
194 /* setstr can't fail here */
195 setstr(vp
, l
->argv
[num
], KSH_RETURN_ERROR
);
202 vp
->flag
|= ISSET
|INTEGER
;
208 /* If no job, expand to nothing */
209 if ((vp
->val
.i
= j_async()) == 0)
210 vp
->flag
&= ~(ISSET
|INTEGER
);
219 vp
->flag
&= ~INTEGER
;
220 vp
->val
.s
= getoptions();
223 vp
->flag
&= ~(ISSET
|INTEGER
);
227 for (l
= genv
->loc
; ; l
= l
->next
) {
228 vp
= ktsearch(&l
->vars
, n
, h
);
231 return arraysearch(vp
, val
);
238 vp
= ktenter(&l
->vars
, n
, h
);
240 vp
= arraysearch(vp
, val
);
248 * Search for local variable, if not found create locally.
251 local(const char *n
, bool copy
)
253 struct block
*l
= genv
->loc
;
259 /* Check to see if this is an array */
260 n
= array_index_calc(n
, &array
, &val
);
264 vp
->flag
= DEFINED
|RDONLY
;
269 vp
= ktenter(&l
->vars
, n
, h
);
270 if (copy
&& !(vp
->flag
& DEFINED
)) {
271 struct block
*ll
= l
;
272 struct tbl
*vq
= NULL
;
274 while ((ll
= ll
->next
) && !(vq
= ktsearch(&ll
->vars
, n
, h
)))
277 vp
->flag
|= vq
->flag
&
278 (EXPORT
| INTEGER
| RDONLY
| LJUST
| RJUST
|
279 ZEROFIL
| LCASEV
| UCASEV_AL
| INT_U
| INT_L
);
280 if (vq
->flag
& INTEGER
)
282 vp
->u2
.field
= vq
->u2
.field
;
286 vp
= arraysearch(vp
, val
);
293 /* get variable string value */
295 str_val(struct tbl
*vp
)
299 if ((vp
->flag
&SPECIAL
))
301 if (!(vp
->flag
&ISSET
))
302 s
= null
; /* special to dollar() */
303 else if (!(vp
->flag
&INTEGER
)) /* string source */
304 s
= vp
->val
.s
+ vp
->type
;
305 else { /* integer source */
306 /* worst case number length is when base=2, so use
307 * minus base # number BITS(int64_t) NUL */
308 char strbuf
[1 + 2 + 1 + BITS(int64_t) + 1];
309 const char *digits
= (vp
->flag
& UCASEV_AL
) ?
310 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" :
311 "0123456789abcdefghijklmnopqrstuvwxyz";
315 s
= strbuf
+ sizeof(strbuf
);
316 if (vp
->flag
& INT_U
)
317 n
= (uint64_t) vp
->val
.i
;
319 n
= (vp
->val
.i
< 0) ? -vp
->val
.i
: vp
->val
.i
;
320 base
= (vp
->type
== 0) ? 10 : vp
->type
;
321 if (base
< 2 || base
> strlen(digits
))
326 *--s
= digits
[n
% base
];
331 *--s
= digits
[base
% 10];
333 *--s
= digits
[base
/ 10];
335 if (!(vp
->flag
& INT_U
) && vp
->val
.i
< 0)
337 if (vp
->flag
& (RJUST
|LJUST
)) /* case already dealt with */
338 s
= formatstr(vp
, s
);
340 s
= str_save(s
, ATEMP
);
345 /* get variable integer value, with error checking */
347 intval(struct tbl
*vp
)
352 base
= getint(vp
, &num
, false);
354 /* XXX check calls - is error here ok by POSIX? */
355 errorf("%s: bad number", str_val(vp
));
359 /* set variable to string value */
361 setstr(struct tbl
*vq
, const char *s
, int error_ok
)
363 const char *fs
= NULL
;
364 int no_ro_check
= error_ok
& KSH_IGNORE_RDONLY
;
365 error_ok
&= ~KSH_IGNORE_RDONLY
;
366 if ((vq
->flag
& RDONLY
) && !no_ro_check
) {
367 warningf(true, "%s: is read only", vq
->name
);
372 if (!(vq
->flag
&INTEGER
)) { /* string dest */
373 if ((vq
->flag
&ALLOC
)) {
375 if (s
>= vq
->val
.s
&&
376 s
<= vq
->val
.s
+ strlen(vq
->val
.s
))
377 internal_errorf("%s: %s=%s: assigning to self",
378 __func__
, vq
->name
, s
);
379 afree(vq
->val
.s
, vq
->areap
);
381 vq
->flag
&= ~(ISSET
|ALLOC
);
383 if (s
&& (vq
->flag
& (UCASEV_AL
|LCASEV
|LJUST
|RJUST
)))
384 fs
= s
= formatstr(vq
, s
);
385 if ((vq
->flag
&EXPORT
))
388 vq
->val
.s
= str_save(s
, vq
->areap
);
391 } else { /* integer dest */
392 if (!v_evaluate(vq
, s
, error_ok
, true))
396 if ((vq
->flag
&SPECIAL
))
398 afree((void *)fs
, ATEMP
);
402 /* set variable to integer */
404 setint(struct tbl
*vq
, int64_t n
)
406 if (!(vq
->flag
&INTEGER
)) {
407 struct tbl
*vp
= &vtemp
;
408 vp
->flag
= (ISSET
|INTEGER
);
412 /* setstr can't fail here */
413 setstr(vq
, str_val(vp
), KSH_RETURN_ERROR
);
417 if ((vq
->flag
&SPECIAL
))
422 getint(struct tbl
*vp
, int64_t *nump
, bool arith
)
430 if (vp
->flag
&SPECIAL
)
432 /* XXX is it possible for ISSET to be set and val.s to be 0? */
433 if (!(vp
->flag
&ISSET
) || (!(vp
->flag
&INTEGER
) && vp
->val
.s
== NULL
))
435 if (vp
->flag
&INTEGER
) {
439 s
= vp
->val
.s
+ vp
->type
;
440 if (s
== NULL
) /* redundant given initial test */
445 if (arith
&& *s
== '0' && *(s
+1)) {
447 if (*s
== 'x' || *s
== 'X') {
450 } else if (vp
->flag
& ZEROFIL
) {
457 for (c
= (unsigned char)*s
++; c
; c
= (unsigned char)*s
++) {
460 } else if (c
== '#') {
462 if (have_base
|| base
< 2 || base
> 36)
466 } else if (letnum(c
)) {
470 c
-= 'a' - 10; /* todo: assumes ascii */
472 c
-= 'A' - 10; /* todo: assumes ascii */
474 c
= -1; /* _: force error */
475 if (c
< 0 || c
>= base
)
477 num
= num
* base
+ c
;
487 /* convert variable vq to integer variable, setting its value from vp
488 * (vq and vp may be the same)
491 setint_v(struct tbl
*vq
, struct tbl
*vp
, bool arith
)
496 if ((base
= getint(vp
, &num
, arith
)) == -1)
498 if (!(vq
->flag
& INTEGER
) && (vq
->flag
& ALLOC
)) {
500 afree(vq
->val
.s
, vq
->areap
);
503 if (vq
->type
== 0) /* default base */
505 vq
->flag
|= ISSET
|INTEGER
;
506 if (vq
->flag
&SPECIAL
)
512 formatstr(struct tbl
*vp
, const char *s
)
519 if (vp
->flag
& (RJUST
|LJUST
)) {
520 if (!vp
->u2
.field
) /* default field width */
526 p
= alloc(nlen
+ 1, ATEMP
);
527 if (vp
->flag
& (RJUST
|LJUST
)) {
530 if (vp
->flag
& RJUST
) {
531 const char *r
= s
+ olen
;
532 /* strip trailing spaces (at&t ksh uses r[-1] == ' ') */
533 while (r
> s
&& isspace((unsigned char)r
[-1]))
536 if (slen
> vp
->u2
.field
) {
537 s
+= slen
- vp
->u2
.field
;
540 shf_snprintf(p
, nlen
+ 1,
541 ((vp
->flag
& ZEROFIL
) && digit(*s
)) ?
542 "%0*s%.*s" : "%*s%.*s",
543 vp
->u2
.field
- slen
, null
, slen
, s
);
545 /* strip leading spaces/zeros */
546 while (isspace((unsigned char)*s
))
548 if (vp
->flag
& ZEROFIL
)
551 shf_snprintf(p
, nlen
+ 1, "%-*.*s",
552 vp
->u2
.field
, vp
->u2
.field
, s
);
555 memcpy(p
, s
, olen
+ 1);
557 if (vp
->flag
& UCASEV_AL
) {
559 if (islower((unsigned char)*q
))
560 *q
= toupper((unsigned char)*q
);
561 } else if (vp
->flag
& LCASEV
) {
563 if (isupper((unsigned char)*q
))
564 *q
= tolower((unsigned char)*q
);
571 * make vp->val.s be "name=value" for quick exporting.
574 export(struct tbl
*vp
, const char *val
)
577 char *op
= (vp
->flag
&ALLOC
) ? vp
->val
.s
: NULL
;
578 int namelen
= strlen(vp
->name
);
579 int vallen
= strlen(val
) + 1;
582 xp
= alloc(namelen
+ 1 + vallen
, vp
->areap
);
583 memcpy(vp
->val
.s
= xp
, vp
->name
, namelen
);
586 vp
->type
= xp
- vp
->val
.s
; /* offset to value */
587 memcpy(xp
, val
, vallen
);
588 afree(op
, vp
->areap
);
592 * lookup variable (according to (set&LOCAL)),
593 * set its attributes (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL,
594 * LCASEV, UCASEV_AL), and optionally set its value if an assignment.
597 typeset(const char *var
, int set
, int clr
, int field
, int base
)
600 struct tbl
*vpbase
, *t
;
604 /* check for valid variable name, search for value */
605 val
= skip_varname(var
, false);
611 len
= array_ref_len(val
);
614 /* IMPORT is only used when the shell starts up and is
615 * setting up its environment. Allow only simple array
616 * references at this time since parameter/command substitution
617 * is preformed on the [expression], which would be a major
622 for (i
= 1; i
< len
- 1; i
++)
629 tvar
= str_nsave(var
, val
++ - var
, ATEMP
);
631 /* Importing from original environment: must have an = */
638 /* Prevent typeset from creating a local PATH/ENV/SHELL */
639 if (Flag(FRESTRICTED
) && (strcmp(tvar
, "PATH") == 0 ||
640 strcmp(tvar
, "ENV") == 0 || strcmp(tvar
, "SHELL") == 0))
641 errorf("%s: restricted", tvar
);
643 vp
= (set
&LOCAL
) ? local(tvar
, (set
& LOCAL_COPY
) ? true : false) :
645 set
&= ~(LOCAL
|LOCAL_COPY
);
647 vpbase
= (vp
->flag
& ARRAY
) ? global(arrayname(var
)) : vp
;
649 /* only allow export flag to be set. at&t ksh allows any attribute to
650 * be changed, which means it can be truncated or modified
653 if ((vpbase
->flag
&RDONLY
) &&
654 (val
|| clr
|| (set
& ~EXPORT
)))
655 /* XXX check calls - is error here ok by POSIX? */
656 errorf("%s: is read only", tvar
);
660 /* most calls are with set/clr == 0 */
663 /* XXX if x[0] isn't set, there will be problems: need to have
664 * one copy of attributes for arrays...
666 for (t
= vpbase
; t
; t
= t
->u
.array
) {
668 int error_ok
= KSH_RETURN_ERROR
;
670 char *free_me
= NULL
;
672 fake_assign
= (t
->flag
& ISSET
) && (!val
|| t
!= vp
) &&
673 ((set
& (UCASEV_AL
|LCASEV
|LJUST
|RJUST
|ZEROFIL
)) ||
674 ((t
->flag
& INTEGER
) && (clr
& INTEGER
)) ||
675 (!(t
->flag
& INTEGER
) && (set
& INTEGER
)));
677 if (t
->flag
& INTEGER
) {
681 s
= t
->val
.s
+ t
->type
;
682 free_me
= (t
->flag
& ALLOC
) ? t
->val
.s
:
687 if (!(t
->flag
& INTEGER
) && (set
& INTEGER
)) {
691 if (!(t
->flag
& RDONLY
) && (set
& RDONLY
)) {
692 /* allow var to be initialized read-only */
693 error_ok
|= KSH_IGNORE_RDONLY
;
695 t
->flag
= (t
->flag
| set
) & ~clr
;
696 /* Don't change base if assignment is to be done,
697 * in case assignment fails.
699 if ((set
& INTEGER
) && base
> 0 && (!val
|| t
!= vp
))
701 if (set
& (LJUST
|RJUST
|ZEROFIL
))
704 if (!setstr(t
, s
, error_ok
)) {
705 /* Somewhat arbitrary action here:
706 * zap contents of variable, but keep
710 if (t
->flag
& INTEGER
)
714 afree(t
->val
.s
, t
->areap
);
715 t
->flag
&= ~(ISSET
|ALLOC
);
719 afree(free_me
, t
->areap
);
727 if (vp
->flag
&INTEGER
) {
728 /* do not zero base before assignment */
729 setstr(vp
, val
, KSH_UNWIND_ERROR
| KSH_IGNORE_RDONLY
);
730 /* Done after assignment to override default */
734 /* setstr can't fail (readonly check already done) */
735 setstr(vp
, val
, KSH_RETURN_ERROR
| KSH_IGNORE_RDONLY
);
738 /* only x[0] is ever exported, so use vpbase */
739 if ((vpbase
->flag
&EXPORT
) && !(vpbase
->flag
&INTEGER
) &&
741 export(vpbase
, (vpbase
->flag
&ISSET
) ? vpbase
->val
.s
: null
);
746 /* Unset a variable. array_ref is set if there was an array reference in
747 * the name lookup (eg, x[2]).
750 unset(struct tbl
*vp
, int array_ref
)
752 if (vp
->flag
& ALLOC
)
753 afree(vp
->val
.s
, vp
->areap
);
754 if ((vp
->flag
& ARRAY
) && !array_ref
) {
757 /* Free up entire array */
758 for (a
= vp
->u
.array
; a
; ) {
761 if (tmp
->flag
& ALLOC
)
762 afree(tmp
->val
.s
, tmp
->areap
);
763 afree(tmp
, tmp
->areap
);
767 /* If foo[0] is being unset, the remainder of the array is kept... */
768 vp
->flag
&= SPECIAL
| (array_ref
? ARRAY
|DEFINED
: 0);
769 if (vp
->flag
& SPECIAL
)
770 unsetspec(vp
); /* responsible for `unspecial'ing var */
773 /* return a pointer to the first char past a legal variable name (returns the
774 * argument if there is no legal name, returns * a pointer to the terminating
775 * null if whole string is legal).
778 skip_varname(const char *s
, int aok
)
782 if (s
&& letter(*s
)) {
783 while (*++s
&& letnum(*s
))
785 if (aok
&& *s
== '[' && (alen
= array_ref_len(s
)))
791 /* Return a pointer to the first character past any legal variable name. */
793 skip_wdvarname(const char *s
,
794 int aok
) /* skip array de-reference? */
796 if (s
[0] == CHAR
&& letter(s
[1])) {
799 } while (s
[0] == CHAR
&& letnum(s
[1]));
800 if (aok
&& s
[0] == CHAR
&& s
[1] == '[') {
801 /* skip possible array de-reference */
813 else if (c
== ']' && --depth
== 0) {
823 /* Check if coded string s is a variable name */
825 is_wdvarname(const char *s
, int aok
)
827 char *p
= skip_wdvarname(s
, aok
);
829 return p
!= s
&& p
[0] == EOS
;
832 /* Check if coded string s is a variable assignment */
834 is_wdvarassign(const char *s
)
836 char *p
= skip_wdvarname(s
, true);
838 return p
!= s
&& p
[0] == CHAR
&& p
[1] == '=';
842 * Make the exported environment from the exported names in the dictionary.
849 struct tbl
*vp
, **vpp
;
853 for (l
= genv
->loc
; l
!= NULL
; l
= l
->next
)
854 for (vpp
= l
->vars
.tbls
, i
= l
->vars
.size
; --i
>= 0; )
855 if ((vp
= *vpp
++) != NULL
&&
856 (vp
->flag
&(ISSET
|EXPORT
)) == (ISSET
|EXPORT
)) {
859 unsigned int h
= hash(vp
->name
);
861 /* unexport any redefined instances */
862 for (l2
= l
->next
; l2
!= NULL
; l2
= l2
->next
) {
863 vp2
= ktsearch(&l2
->vars
, vp
->name
, h
);
865 vp2
->flag
&= ~EXPORT
;
867 if ((vp
->flag
&INTEGER
)) {
868 /* integer to string */
871 vp
->flag
&= ~(INTEGER
|RDONLY
);
872 /* setstr can't fail here */
873 setstr(vp
, val
, KSH_RETURN_ERROR
);
875 XPput(env
, vp
->val
.s
);
878 return (char **) XPclose(env
);
882 * Called after a fork in parent to bump the random number generator.
883 * Done to ensure children will not get the same random number sequence
884 * if the parent doesn't use $RANDOM.
893 * handle special variables with side effects - PATH, SECONDS.
896 /* Test if name is a special parameter */
898 special(const char *name
)
902 tp
= ktsearch(&specials
, name
, hash(name
));
903 return tp
&& (tp
->flag
& ISSET
) ? tp
->type
: V_NONE
;
906 /* Make a variable non-special */
908 unspecial(const char *name
)
912 tp
= ktsearch(&specials
, name
, hash(name
));
917 static struct timespec seconds
; /* time SECONDS last set */
918 static int user_lineno
; /* what user set $LINENO to */
921 getspec(struct tbl
*vp
)
923 switch (special(vp
->name
)) {
925 vp
->flag
&= ~SPECIAL
;
926 /* On start up the value of SECONDS is used before seconds
927 * has been set - don't do anything in this case
928 * (see initcoms[] in main.c).
930 if (vp
->flag
& ISSET
) {
931 struct timespec difference
, now
;
933 clock_gettime(CLOCK_MONOTONIC
, &now
);
934 timespecsub(&now
, &seconds
, &difference
);
935 setint(vp
, (int64_t)difference
.tv_sec
);
940 vp
->flag
&= ~SPECIAL
;
941 setint(vp
, (int64_t) (rand() & 0x7fff));
945 vp
->flag
&= ~SPECIAL
;
946 setint(vp
, (int64_t) histsize
);
950 vp
->flag
&= ~SPECIAL
;
951 setint(vp
, (int64_t) user_opt
.uoptind
);
955 vp
->flag
&= ~SPECIAL
;
956 setint(vp
, (int64_t) current_lineno
+ user_lineno
);
963 setspec(struct tbl
*vp
)
967 switch (special(vp
->name
)) {
969 afree(search_path
, APERM
);
970 search_path
= str_save(str_val(vp
), APERM
);
971 flushcom(1); /* clear tracked aliases */
974 setctypes(s
= str_val(vp
), C_IFS
);
978 vp
->flag
&= ~SPECIAL
;
979 getopts_reset((int) intval(vp
));
982 case V_POSIXLY_CORRECT
:
983 change_flag(FPOSIX
, OF_SPECIAL
, 1);
986 afree(tmpdir
, APERM
);
988 /* Use tmpdir iff it is an absolute path, is writable and
989 * searchable and is a directory...
995 if (s
[0] == '/' && access(s
, W_OK
|X_OK
) == 0 &&
996 stat(s
, &statb
) == 0 && S_ISDIR(statb
.st_mode
))
997 tmpdir
= str_save(s
, APERM
);
1001 sethistcontrol(str_val(vp
));
1004 vp
->flag
&= ~SPECIAL
;
1005 sethistsize((int) intval(vp
));
1006 vp
->flag
|= SPECIAL
;
1009 sethistfile(str_val(vp
));
1012 set_editmode(str_val(vp
));
1015 if (!(global("VISUAL")->flag
& ISSET
))
1016 set_editmode(str_val(vp
));
1022 if (getint(vp
, &l
, false) == -1) {
1026 if (l
<= MIN_COLS
|| l
> INT_MAX
)
1039 vp
->flag
&= ~SPECIAL
;
1041 vp
->flag
|= SPECIAL
;
1044 vp
->flag
&= ~SPECIAL
;
1045 srand_deterministic((unsigned int)intval(vp
));
1046 vp
->flag
|= SPECIAL
;
1049 vp
->flag
&= ~SPECIAL
;
1050 clock_gettime(CLOCK_MONOTONIC
, &seconds
);
1051 seconds
.tv_sec
-= intval(vp
);
1052 vp
->flag
|= SPECIAL
;
1055 /* at&t ksh seems to do this (only listen if integer) */
1056 if (vp
->flag
& INTEGER
)
1057 ksh_tmout
= vp
->val
.i
>= 0 ? vp
->val
.i
: 0;
1060 vp
->flag
&= ~SPECIAL
;
1061 /* The -1 is because line numbering starts at 1. */
1062 user_lineno
= (unsigned int) intval(vp
) - current_lineno
- 1;
1063 vp
->flag
|= SPECIAL
;
1070 vp
->flag
&= ~SPECIAL
;
1071 if (setupterm(str_val(vp
), shl_out
->fd
, &ret
) == ERR
)
1072 del_curterm(cur_term
);
1073 vp
->flag
|= SPECIAL
;
1081 unsetspec(struct tbl
*vp
)
1083 switch (special(vp
->name
)) {
1085 afree(search_path
, APERM
);
1086 search_path
= str_save(def_path
, APERM
);
1087 flushcom(1); /* clear tracked aliases */
1090 setctypes(" \t\n", C_IFS
);
1094 /* should not become unspecial */
1095 afree(tmpdir
, APERM
);
1105 sethistcontrol(NULL
);
1108 case V_MAILCHECK
: /* at&t ksh leaves previous value in place */
1111 case V_TMOUT
: /* at&t ksh leaves previous value in place */
1112 unspecial(vp
->name
);
1115 /* at&t ksh man page says OPTIND, OPTARG and _ lose special meaning,
1116 * but OPTARG does not (still set by getopts) and _ is also still
1117 * set in various places.
1118 * Don't know what at&t does for:
1119 * MAIL, MAILPATH, HISTSIZE, HISTFILE,
1120 * Unsetting these in at&t ksh does not loose the `specialness':
1121 * no effect: IFS, COLUMNS, PATH, TMPDIR,
1123 * pdkshisms: no effect:
1124 * POSIXLY_CORRECT (use set +o posix instead)
1130 * Search for (and possibly create) a table entry starting with
1131 * vp, indexed by val.
1134 arraysearch(struct tbl
*vp
, int val
)
1136 struct tbl
*prev
, *curr
, *new;
1137 size_t namelen
= strlen(vp
->name
) + 1;
1139 vp
->flag
|= ARRAY
|DEFINED
;
1141 /* The table entry is always [0] */
1146 while (curr
&& curr
->index
< val
) {
1148 curr
= curr
->u
.array
;
1150 if (curr
&& curr
->index
== val
) {
1151 if (curr
->flag
&ISSET
)
1156 new = alloc(sizeof(struct tbl
) + namelen
,
1158 strlcpy(new->name
, vp
->name
, namelen
);
1159 new->flag
= vp
->flag
& ~(ALLOC
|DEFINED
|ISSET
|SPECIAL
);
1160 new->type
= vp
->type
;
1161 new->areap
= vp
->areap
;
1162 new->u2
.field
= vp
->u2
.field
;
1164 if (curr
!= new) { /* not reusing old array entry */
1165 prev
->u
.array
= new;
1166 new->u
.array
= curr
;
1171 /* Return the length of an array reference (eg, [1+2]) - cp is assumed
1172 * to point to the open bracket. Returns 0 if there is no matching closing
1176 array_ref_len(const char *cp
)
1182 while ((c
= *s
++) && (c
!= ']' || --depth
))
1191 * Make a copy of the base of an array name
1194 arrayname(const char *str
)
1198 if ((p
= strchr(str
, '[')) == 0)
1199 /* Shouldn't happen, but why worry? */
1200 return (char *) str
;
1202 return str_nsave(str
, p
- str
, ATEMP
);
1205 /* Set (or overwrite, if !reset) the array variable var to the values in vals.
1208 set_array(const char *var
, int reset
, char **vals
)
1210 struct tbl
*vp
, *vq
;
1213 /* to get local array, use "typeset foo; set -A foo" */
1216 /* Note: at&t ksh allows set -A but not set +A of a read-only var */
1217 if ((vp
->flag
&RDONLY
))
1218 errorf("%s: is read only", var
);
1219 /* This code is quite non-optimal */
1221 /* trash existing values and attributes */
1223 /* todo: would be nice for assignment to completely succeed or
1224 * completely fail. Only really effects integer arrays:
1225 * evaluation of some of vals[] may fail...
1227 for (i
= 0; vals
[i
]; i
++) {
1228 vq
= arraysearch(vp
, i
);
1229 /* would be nice to deal with errors here... (see above) */
1230 setstr(vq
, vals
[i
], KSH_RETURN_ERROR
);