2 #include "ksh_limval.h"
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
35 static char *const empty
[] = {null
};
37 l
= (struct block
*) alloc(sizeof(struct block
), ATEMP
);
39 ainit(&l
->area
); /* todo: could use e->area (l->area => l->areap) */
42 l
->argv
= (char **) empty
;
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);
55 * pop a block handling special variables
60 struct block
*l
= e
->loc
;
61 struct tbl
*vp
, **vpp
= l
->vars
.tbls
, *vq
;
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
)
72 if (l
->flags
& BF_DOGETOPTS
)
73 user_opt
= l
->getopts_state
;
78 /* called by main() to initialize variable data structures */
86 { "COLUMNS", V_COLUMNS
},
88 { "OPTIND", V_OPTIND
},
90 { "POSIXLY_CORRECT", V_POSIXLY_CORRECT
},
91 { "TMPDIR", V_TMPDIR
},
93 { "HISTFILE", V_HISTFILE
},
94 { "HISTSIZE", V_HISTSIZE
},
96 { "RANDOM", V_RANDOM
},
97 { "SECONDS", V_SECONDS
},
99 { "LINENO", V_LINENO
},
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.
118 array_index_calc(const char *n
, bool *arrayp
, int *valp
)
124 p
= skip_varname(n
, false);
125 if (p
!= n
&& *p
== '[' && (len
= array_ref_len(p
))) {
129 /* Calculate the value of the subscript */
131 tmp
= str_nsave(p
+1, len
-2, ATEMP
);
132 sub
= substitute(tmp
, 0);
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
);
145 * Search for variable, if not found create globally.
148 global(const char *n
)
150 struct block
*l
= e
->loc
;
157 /* Check to see if this is an array */
158 n
= array_index_calc(n
, &array
, &val
);
163 errorf("bad substitution");
170 for (c
= 0; digit(*n
); n
++)
173 /* setstr can't fail here */
174 setstr(vp
, l
->argv
[c
], KSH_RETURN_ERROR
);
181 vp
->flag
|= ISSET
|INTEGER
;
187 /* If no job, expand to nothing */
188 if ((vp
->val
.i
= j_async()) == 0)
189 vp
->flag
&= ~(ISSET
|INTEGER
);
198 vp
->flag
&= ~INTEGER
;
199 vp
->val
.s
= getoptions();
202 vp
->flag
&= ~(ISSET
|INTEGER
);
206 for (l
= e
->loc
; ; l
= l
->next
) {
207 vp
= ktsearch(&l
->vars
, n
, h
);
210 return arraysearch(vp
, val
);
217 vp
= ktenter(&l
->vars
, n
, h
);
219 vp
= arraysearch(vp
, val
);
227 * Search for local variable, if not found create locally.
230 local(const char *n
, bool copy
)
232 struct block
*l
= e
->loc
;
238 /* Check to see if this is an array */
239 n
= array_index_calc(n
, &array
, &val
);
243 vp
->flag
= DEFINED
|RDONLY
;
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
)))
256 vp
->flag
|= vq
->flag
& (EXPORTV
|INTEGER
|RDONLY
258 |LCASEV
|UCASEV_AL
|INT_U
|INT_L
);
259 if (vq
->flag
& INTEGER
)
261 vp
->u2
.field
= vq
->u2
.field
;
265 vp
= arraysearch(vp
, val
);
272 /* get variable string value */
274 str_val(struct tbl
*vp
)
278 if ((vp
->flag
&SPECIAL
))
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";
294 s
= strbuf
+ sizeof(strbuf
);
295 if (vp
->flag
& INT_U
)
296 n
= (unsigned long) vp
->val
.i
;
298 n
= (vp
->val
.i
< 0) ? -vp
->val
.i
: vp
->val
.i
;
299 base
= (vp
->type
== 0) ? 10 : vp
->type
;
303 *--s
= digits
[n
% base
];
308 *--s
= digits
[base
% 10];
310 *--s
= digits
[base
/ 10];
312 if (!(vp
->flag
& INT_U
) && vp
->val
.i
< 0)
314 if (vp
->flag
& (RJUST
|LJUST
)) /* case already dealt with */
315 s
= formatstr(vp
, s
);
317 s
= str_save(s
, ATEMP
);
322 /* get variable integer value, with error checking */
324 intval(struct tbl
*vp
)
329 base
= getint(vp
, &num
, false);
331 /* XXX check calls - is error here ok by POSIX? */
332 errorf("%s: bad number", str_val(vp
));
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;
343 if ((vq
->flag
& RDONLY
) && !no_ro_check
) {
344 warningf(true, "%s: is read only", vq
->name
);
349 if (!(vq
->flag
&INTEGER
)) { /* string dest */
350 if ((vq
->flag
&ALLOC
)) {
353 && s
<= vq
->val
.s
+ strlen(vq
->val
.s
))
354 internal_errorf(true,
355 "setstr: %s=%s: assigning to self",
357 afree((void*)vq
->val
.s
, vq
->areap
);
359 vq
->flag
&= ~(ISSET
|ALLOC
);
361 if (s
&& (vq
->flag
& (UCASEV_AL
|LCASEV
|LJUST
|RJUST
)))
362 fs
= s
= formatstr(vq
, s
);
363 if ((vq
->flag
&EXPORTV
))
366 vq
->val
.s
= str_save(s
, vq
->areap
);
367 if (vq
->val
.s
) /* <sjg> don't lie */
370 } else /* integer dest */
371 if (!v_evaluate(vq
, s
, error_ok
, true))
374 if ((vq
->flag
&SPECIAL
))
377 afree((char *)fs
, ATEMP
);
381 /* set variable to integer */
383 setint(struct tbl
*vq
, long int n
)
385 if (!(vq
->flag
&INTEGER
)) {
386 struct tbl
*vp
= &vtemp
;
387 vp
->flag
= (ISSET
|INTEGER
);
391 /* setstr can't fail here */
392 setstr(vq
, str_val(vp
), KSH_RETURN_ERROR
);
396 if ((vq
->flag
&SPECIAL
))
401 getint(struct tbl
*vp
, long int *nump
, bool arith
)
409 if (vp
->flag
&SPECIAL
)
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
))
414 if (vp
->flag
&INTEGER
) {
418 s
= vp
->val
.s
+ vp
->type
;
419 if (s
== NULL
) /* redundant given initial test */
424 if (arith
&& *s
== '0' && *(s
+1)) {
426 if (*s
== 'x' || *s
== 'X') {
429 } else if (vp
->flag
& ZEROFIL
) {
436 for (c
= *s
++; c
; c
= *s
++) {
439 } else if (c
== '#') {
441 if (have_base
|| base
< 2 || base
> 36)
445 } else if (letnum(c
)) {
449 c
-= 'a' - 10; /* todo: assumes ascii */
451 c
-= 'A' - 10; /* todo: assumes ascii */
453 c
= -1; /* _: force error */
454 if (c
< 0 || c
>= base
)
456 num
= num
* base
+ c
;
466 /* convert variable vq to integer variable, setting its value from vp
467 * (vq and vp may be the same)
470 setint_v(struct tbl
*vq
, struct tbl
*vp
, bool arith
)
475 if ((base
= getint(vp
, &num
, arith
)) == -1)
477 if (!(vq
->flag
& INTEGER
) && (vq
->flag
& ALLOC
)) {
479 afree(vq
->val
.s
, vq
->areap
);
482 if (vq
->type
== 0) /* default base */
484 vq
->flag
|= ISSET
|INTEGER
;
485 if (vq
->flag
&SPECIAL
)
491 formatstr(struct tbl
*vp
, const char *s
)
498 if (vp
->flag
& (RJUST
|LJUST
)) {
499 if (!vp
->u2
.field
) /* default field width */
505 p
= (char *) alloc(nlen
+ 1, ATEMP
);
506 if (vp
->flag
& (RJUST
|LJUST
)) {
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]))
515 if (slen
> vp
->u2
.field
) {
516 s
+= 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
);
524 /* strip leading spaces/zeros */
527 if (vp
->flag
& ZEROFIL
)
530 shf_snprintf(p
, nlen
+ 1, "%-*.*s",
531 vp
->u2
.field
, vp
->u2
.field
, s
);
534 memcpy(p
, s
, olen
+ 1);
536 if (vp
->flag
& UCASEV_AL
) {
540 } else if (vp
->flag
& LCASEV
) {
550 * make vp->val.s be "name=value" for quick exporting.
553 export(struct tbl
*vp
, const char *val
)
556 char *op
= (vp
->flag
&ALLOC
) ? vp
->val
.s
: NULL
;
557 int namelen
= strlen(vp
->name
);
558 int vallen
= strlen(val
) + 1;
561 xp
= (char*)alloc(namelen
+ 1 + vallen
, vp
->areap
);
562 memcpy(vp
->val
.s
= xp
, vp
->name
, namelen
);
565 vp
->type
= xp
- vp
->val
.s
; /* offset to value */
566 memcpy(xp
, val
, vallen
);
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.
577 typeset(const char *var
, Tflag set
, Tflag clr
, int field
, int base
)
580 struct tbl
*vpbase
, *t
;
584 /* check for valid variable name, search for value */
585 val
= skip_varname(var
, false);
591 len
= array_ref_len(val
);
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
602 for (i
= 1; i
< len
- 1; i
++)
609 tvar
= str_nsave(var
, val
++ - var
, ATEMP
);
611 /* Importing from original environment: must have an = */
618 vp
= (set
&LOCAL
) ? local(tvar
, (set
& LOCAL_COPY
) ? true : false)
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
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
);
635 /* most calls are with set/clr == 0 */
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
) {
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
)));
651 if (t
->flag
& INTEGER
) {
653 free_me
= (char *) 0;
655 s
= t
->val
.s
+ t
->type
;
656 free_me
= (t
->flag
& ALLOC
) ? t
->val
.s
661 if (!(t
->flag
& INTEGER
) && (set
& INTEGER
)) {
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
))
671 if (set
& (LJUST
|RJUST
|ZEROFIL
))
674 if (!setstr(t
, s
, KSH_RETURN_ERROR
)) {
675 /* Somewhat arbitrary action here:
676 * zap contents of varibale, but keep
680 if (t
->flag
& INTEGER
)
684 afree((void*) t
->val
.s
,
686 t
->flag
&= ~(ISSET
|ALLOC
);
691 afree((void *) free_me
, t
->areap
);
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 */
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
);
718 /* Unset a variable. array_ref is set if there was an array reference in
719 * the name lookup (eg, x[2]).
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
) {
729 /* Free up entire array */
730 for (a
= vp
->u
.array
; a
; ) {
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).
750 skip_varname(const char *s
, int aok
)
754 if (s
&& letter(*s
)) {
755 while (*++s
&& letnum(*s
))
757 if (aok
&& *s
== '[' && (alen
= array_ref_len(s
)))
763 /* Return a pointer to the first character past any legal variable name. */
765 skip_wdvarname(const char *s
, int aok
) /* skip array de-reference? */
767 if (s
[0] == CHAR
&& letter(s
[1])) {
770 }while (s
[0] == CHAR
&& letnum(s
[1]));
771 if (aok
&& s
[0] == CHAR
&& s
[1] == '[') {
772 /* skip possible array de-reference */
784 else if (c
== ']' && --depth
== 0) {
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.
818 struct block
*l
= e
->loc
;
820 struct tbl
*vp
, **vpp
;
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
)) {
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
);
838 vp2
->flag
&= ~EXPORTV
;
841 if ((vp
->flag
&INTEGER
)) {
842 /* integer to string */
845 vp
->flag
&= ~(INTEGER
|RDONLY
);
846 /* setstr can't fail here */
847 setstr(vp
, val
, KSH_RETURN_ERROR
);
849 XPput(env
, vp
->val
.s
);
852 ap
= (char **) XPclose(env
);
857 * Someone has set the srand() value, therefore from now on
858 * we return values from rand() instead of arc4random()
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.
874 * handle special variables with side effects - PATH, SECONDS.
877 /* Test if name is a special parameter */
879 special(const char *name
)
883 tp
= ktsearch(&specials
, name
, hash(name
));
884 return tp
&& (tp
->flag
& ISSET
) ? tp
->type
: V_NONE
;
887 /* Make a variable non-special */
889 unspecial(const char *name
)
893 tp
= ktsearch(&specials
, name
, hash(name
));
898 static time_t seconds
; /* time SECONDS last set */
899 static int user_lineno
; /* what user set $LINENO to */
902 getspec(struct tbl
*vp
)
904 switch (special(vp
->name
)) {
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
));
916 vp
->flag
&= ~SPECIAL
;
917 setint(vp
, (long) (rand() & 0x7fff));
922 vp
->flag
&= ~SPECIAL
;
923 setint(vp
, (long) histsize
);
928 vp
->flag
&= ~SPECIAL
;
929 setint(vp
, (long) user_opt
.uoptind
);
933 vp
->flag
&= ~SPECIAL
;
934 setint(vp
, (long) current_lineno
+ user_lineno
);
941 setspec(struct tbl
*vp
)
945 switch (special(vp
->name
)) {
949 path
= str_save(str_val(vp
), APERM
);
950 flushcom(1); /* clear tracked aliases */
953 setctypes(s
= str_val(vp
), C_IFS
);
957 vp
->flag
&= ~SPECIAL
;
958 getopts_reset((int) intval(vp
));
961 case V_POSIXLY_CORRECT
:
962 change_flag(FPOSIX
, OF_SPECIAL
, 1);
966 afree(tmpdir
, APERM
);
969 /* Use tmpdir iff it is an absolute path, is writable and
970 * searchable and is a directory...
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
);
982 vp
->flag
&= ~SPECIAL
;
983 sethistsize((int) intval(vp
));
987 sethistfile(str_val(vp
));
991 vp
->flag
&= ~SPECIAL
;
992 srand((unsigned int)intval(vp
));
996 vp
->flag
&= ~SPECIAL
;
997 seconds
= time((time_t*) 0) - intval(vp
);
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;
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
;
1015 unsetspec(struct tbl
*vp
)
1017 switch (special(vp
->name
)) {
1021 path
= str_save(def_path
, APERM
);
1022 flushcom(1); /* clear tracked aliases */
1025 setctypes(" \t\n", C_IFS
);
1029 /* should not become unspecial */
1031 afree(tmpdir
, APERM
);
1032 tmpdir
= (char *) 0;
1038 case V_TMOUT
: /* at&t ksh leaves previous value in place */
1039 unspecial(vp
->name
);
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,
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.
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
;
1067 /* The table entry is always [0] */
1073 while (curr
&& curr
->index
< val
) {
1075 curr
= curr
->u
.array
;
1077 if (curr
&& curr
->index
== val
) {
1078 if (curr
->flag
&ISSET
)
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
;
1090 if (curr
!= new) { /* not reusing old array entry */
1091 prev
->u
.array
= new;
1092 new->u
.array
= curr
;
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
1102 array_ref_len(const char *cp
)
1108 while ((c
= *s
++) && (c
!= ']' || --depth
))
1117 * Make a copy of the base of an array name
1120 arrayname(const char *str
)
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.
1134 set_array(const char *var
, int reset
, char **vals
)
1136 struct tbl
*vp
, *vq
;
1139 /* to get local array, use "typeset foo; set -A foo" */
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 */
1147 /* trash existing values and attributes */
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
);