GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/ksh/var.c Lines: 483 604 80.0 %
Date: 2017-11-13 Branches: 340 489 69.5 %

Line Branch Exec Source
1
/*	$OpenBSD: var.c,v 1.59 2017/08/30 17:08:45 jca Exp $	*/
2
3
#include <sys/stat.h>
4
5
#include <ctype.h>
6
#include <errno.h>
7
#include <limits.h>
8
#include <stdlib.h>
9
#include <string.h>
10
#include <time.h>
11
#include <unistd.h>
12
13
#include "sh.h"
14
15
/*
16
 * Variables
17
 *
18
 * WARNING: unreadable code, needs a rewrite
19
 *
20
 * if (flag&INTEGER), val.i contains integer value, and type contains base.
21
 * otherwise, (val.s + type) contains string value.
22
 * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
23
 */
24
static	struct tbl vtemp;
25
static	struct table specials;
26
static char	*formatstr(struct tbl *, const char *);
27
static void	export(struct tbl *, const char *);
28
static int	special(const char *);
29
static void	unspecial(const char *);
30
static void	getspec(struct tbl *);
31
static void	setspec(struct tbl *);
32
static void	unsetspec(struct tbl *);
33
static struct tbl *arraysearch(struct tbl *, int);
34
35
/*
36
 * create a new block for function calls and simple commands
37
 * assume caller has allocated and set up genv->loc
38
 */
39
void
40
newblock(void)
41
{
42
	struct block *l;
43
	static char *const empty[] = {null};
44
45
5284842
	l = alloc(sizeof(struct block), ATEMP);
46
2642421
	l->flags = 0;
47
2642421
	ainit(&l->area); /* todo: could use genv->area (l->area => l->areap) */
48
2642421
	if (!genv->loc) {
49
104763
		l->argc = 0;
50
		l->argv = (char **) empty;
51
104763
	} else {
52
2537658
		l->argc = genv->loc->argc;
53
2537658
		l->argv = genv->loc->argv;
54
	}
55
2642421
	l->exit = l->error = NULL;
56
2642421
	ktinit(&l->vars, &l->area, 0);
57
2642421
	ktinit(&l->funs, &l->area, 0);
58
2642421
	l->next = genv->loc;
59
2642421
	genv->loc = l;
60
2642421
}
61
62
/*
63
 * pop a block handling special variables
64
 */
65
void
66
popblock(void)
67
{
68
5042982
	struct block *l = genv->loc;
69
2521491
	struct tbl *vp, **vpp = l->vars.tbls, *vq;
70
	int i;
71
72
2521491
	genv->loc = l->next;	/* pop block */
73
5143526
	for (i = l->vars.size; --i >= 0; )
74

59612
		if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) {
75
4156
			if ((vq = global(vp->name))->flag & ISSET)
76
4144
				setspec(vq);
77
			else
78
12
				unsetspec(vq);
79
		}
80
2521491
	if (l->flags & BF_DOGETOPTS)
81
2440
		user_opt = l->getopts_state;
82
2521491
	afreeall(&l->area);
83
2521491
	afree(l, ATEMP);
84
2521491
}
85
86
/* called by main() to initialize variable data structures */
87
void
88
initvar(void)
89
{
90
	static const struct {
91
		const char *name;
92
		int v;
93
	} names[] = {
94
		{ "COLUMNS",		V_COLUMNS },
95
		{ "IFS",		V_IFS },
96
		{ "OPTIND",		V_OPTIND },
97
		{ "PATH",		V_PATH },
98
		{ "POSIXLY_CORRECT",	V_POSIXLY_CORRECT },
99
		{ "TMPDIR",		V_TMPDIR },
100
#ifdef HISTORY
101
		{ "HISTCONTROL",	V_HISTCONTROL },
102
		{ "HISTFILE",		V_HISTFILE },
103
		{ "HISTSIZE",		V_HISTSIZE },
104
#endif /* HISTORY */
105
#ifdef EDIT
106
		{ "EDITOR",		V_EDITOR },
107
		{ "VISUAL",		V_VISUAL },
108
#endif /* EDIT */
109
		{ "MAIL",		V_MAIL },
110
		{ "MAILCHECK",		V_MAILCHECK },
111
		{ "MAILPATH",		V_MAILPATH },
112
		{ "RANDOM",		V_RANDOM },
113
		{ "SECONDS",		V_SECONDS },
114
		{ "TMOUT",		V_TMOUT },
115
		{ "LINENO",		V_LINENO },
116
		{ NULL,	0 }
117
	};
118
	int i;
119
	struct tbl *tp;
120
121
209526
	ktinit(&specials, APERM, 32); /* must be 2^n (currently 17 specials) */
122
3980994
	for (i = 0; names[i].name; i++) {
123
1885734
		tp = ktenter(&specials, names[i].name, hash(names[i].name));
124
1885734
		tp->flag = DEFINED|ISSET;
125
1885734
		tp->type = names[i].v;
126
	}
127
104763
}
128
129
/* Used to calculate an array index for global()/local().  Sets *arrayp to
130
 * non-zero if this is an array, sets *valp to the array index, returns
131
 * the basename of the array.
132
 */
133
static const char *
134
array_index_calc(const char *n, bool *arrayp, int *valp)
135
{
136
	const char *p;
137
	int len;
138
139
25793606
	*arrayp = false;
140
12896803
	p = skip_varname(n, false);
141

24111885
	if (p != n && *p == '[' && (len = array_ref_len(p))) {
142
		char *sub, *tmp;
143
408
		long rval;
144
145
		/* Calculate the value of the subscript */
146
408
		*arrayp = true;
147
408
		tmp = str_nsave(p+1, len-2, ATEMP);
148
408
		sub = substitute(tmp, 0);
149
408
		afree(tmp, ATEMP);
150
408
		n = str_nsave(n, p - n, ATEMP);
151
408
		evaluate(sub, &rval, KSH_UNWIND_ERROR, true);
152
408
		if (rval < 0 || rval > INT_MAX)
153
			errorf("%s: subscript %ld out of range", n, rval);
154
408
		*valp = rval;
155
408
		afree(sub, ATEMP);
156
408
	}
157
12896803
	return n;
158
}
159
160
/*
161
 * Search for variable, if not found create globally.
162
 */
163
struct tbl *
164
global(const char *n)
165
{
166
23673414
	struct block *l = genv->loc;
167
	struct tbl *vp;
168
	long	 num;
169
	int c;
170
	unsigned int h;
171
11836707
	bool	 array;
172
11836707
	int	 val;
173
174
	/* Check to see if this is an array */
175
11836707
	n = array_index_calc(n, &array, &val);
176
11836707
	h = hash(n);
177
11836707
	c = (unsigned char)n[0];
178
11836707
	if (!letter(c)) {
179
1682129
		if (array)
180
			errorf("bad substitution");
181
		vp = &vtemp;
182
1682129
		vp->flag = DEFINED;
183
1682129
		vp->type = 0;
184
1682129
		vp->areap = ATEMP;
185
1682129
		*vp->name = c;
186
1682129
		if (digit(c)) {
187
1488147
			errno = 0;
188
1488147
			num = strtol(n, NULL, 10);
189

2976294
			if (errno == 0 && num <= l->argc)
190
				/* setstr can't fail here */
191
1402034
				setstr(vp, l->argv[num], KSH_RETURN_ERROR);
192
1488147
			vp->flag |= RDONLY;
193
1488147
			return vp;
194
		}
195
193982
		vp->flag |= RDONLY;
196
193982
		if (n[1] != '\0')
197
			return vp;
198
193982
		vp->flag |= ISSET|INTEGER;
199

193982
		switch (c) {
200
		case '$':
201
7
			vp->val.i = kshpid;
202
7
			break;
203
		case '!':
204
			/* If no job, expand to nothing */
205
397
			if ((vp->val.i = j_async()) == 0)
206
				vp->flag &= ~(ISSET|INTEGER);
207
			break;
208
		case '?':
209
47131
			vp->val.i = exstat;
210
47131
			break;
211
		case '#':
212
146295
			vp->val.i = l->argc;
213
146295
			break;
214
		case '-':
215
14
			vp->flag &= ~INTEGER;
216
14
			vp->val.s = getoptions();
217
14
			break;
218
		default:
219
138
			vp->flag &= ~(ISSET|INTEGER);
220
138
		}
221
193982
		return vp;
222
	}
223
19393642
	for (l = genv->loc; ; l = l->next) {
224
19393642
		vp = ktsearch(&l->vars, n, h);
225
19393642
		if (vp != NULL) {
226
6505399
			if (array)
227
302
				return arraysearch(vp, val);
228
			else
229
6505097
				return vp;
230
		}
231
12888243
		if (l->next == NULL)
232
			break;
233
	}
234
3649179
	vp = ktenter(&l->vars, n, h);
235
3649179
	if (array)
236
76
		vp = arraysearch(vp, val);
237
3649179
	vp->flag |= DEFINED;
238
3649179
	if (special(n))
239
633828
		vp->flag |= SPECIAL;
240
3649179
	return vp;
241
11836707
}
242
243
/*
244
 * Search for local variable, if not found create locally.
245
 */
246
struct tbl *
247
local(const char *n, bool copy)
248
{
249
1060096
	struct block *l = genv->loc;
250
	struct tbl *vp;
251
	unsigned int h;
252
1060096
	bool	 array;
253
1060096
	int	 val;
254
255
	/* Check to see if this is an array */
256
1060096
	n = array_index_calc(n, &array, &val);
257
1060096
	h = hash(n);
258
1060096
	if (!letter(*n)) {
259
		vp = &vtemp;
260
		vp->flag = DEFINED|RDONLY;
261
		vp->type = 0;
262
		vp->areap = ATEMP;
263
		return vp;
264
	}
265
1060096
	vp = ktenter(&l->vars, n, h);
266

1068563
	if (copy && !(vp->flag & DEFINED)) {
267
		struct block *ll = l;
268
		struct tbl *vq = NULL;
269
270

58431
		while ((ll = ll->next) && !(vq = ktsearch(&ll->vars, n, h)))
271
			;
272
8467
		if (vq) {
273
4174
			vp->flag |= vq->flag &
274
			    (EXPORT | INTEGER | RDONLY | LJUST | RJUST |
275
			    ZEROFIL | LCASEV | UCASEV_AL | INT_U | INT_L);
276
4174
			if (vq->flag & INTEGER)
277
				vp->type = vq->type;
278
4174
			vp->u2.field = vq->u2.field;
279
4174
		}
280
8467
	}
281
1060096
	if (array)
282
30
		vp = arraysearch(vp, val);
283
1060096
	vp->flag |= DEFINED;
284
1060096
	if (special(n))
285
633394
		vp->flag |= SPECIAL;
286
1060096
	return vp;
287
1060096
}
288
289
/* get variable string value */
290
char *
291
str_val(struct tbl *vp)
292
{
293
	char *s;
294
295
13264282
	if ((vp->flag&SPECIAL))
296
748141
		getspec(vp);
297
6632141
	if (!(vp->flag&ISSET))
298
749984
		s = null;		/* special to dollar() */
299
5882157
	else if (!(vp->flag&INTEGER))	/* string source */
300
5450908
		s = vp->val.s + vp->type;
301
	else {				/* integer source */
302
		/* worst case number length is when base=2, so use BITS(long) */
303
		/* minus base #     number    null */
304
431249
		char strbuf[1 + 2 + 1 + BITS(long) + 1];
305
431249
		const char *digits = (vp->flag & UCASEV_AL) ?
306
		    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" :
307
		    "0123456789abcdefghijklmnopqrstuvwxyz";
308
		unsigned long n;
309
		int base;
310
311
431249
		s = strbuf + sizeof(strbuf);
312
431249
		if (vp->flag & INT_U)
313
			n = (unsigned long) vp->val.i;
314
		else
315
431249
			n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
316
993194
		base = (vp->type == 0) ? 10 : vp->type;
317

862498
		if (base < 2 || base > strlen(digits))
318
			base = 10;
319
320
431249
		*--s = '\0';
321
431249
		do {
322
920963
			*--s = digits[n % base];
323
920963
			n /= base;
324
920963
		} while (n != 0);
325
431249
		if (base != 10) {
326
78
			*--s = '#';
327
78
			*--s = digits[base % 10];
328
78
			if (base >= 10)
329
				*--s = digits[base / 10];
330
		}
331

862498
		if (!(vp->flag & INT_U) && vp->val.i < 0)
332
6
			*--s = '-';
333
431249
		if (vp->flag & (RJUST|LJUST)) /* case already dealt with */
334
			s = formatstr(vp, s);
335
		else
336
431249
			s = str_save(s, ATEMP);
337
431249
	}
338
6632141
	return s;
339
}
340
341
/* get variable integer value, with error checking */
342
long
343
intval(struct tbl *vp)
344
{
345
1261264
	long num;
346
	int base;
347
348
630632
	base = getint(vp, &num, false);
349
630632
	if (base == -1)
350
		/* XXX check calls - is error here ok by POSIX? */
351
		errorf("%s: bad number", str_val(vp));
352
1261264
	return num;
353
630632
}
354
355
/* set variable to string value */
356
int
357
setstr(struct tbl *vq, const char *s, int error_ok)
358
{
359
	const char *fs = NULL;
360
16625276
	int no_ro_check = error_ok & KSH_IGNORE_RDONLY;
361
8312638
	error_ok &= ~KSH_IGNORE_RDONLY;
362
8312638
	if ((vq->flag & RDONLY) && !no_ro_check) {
363
		warningf(true, "%s: is read only", vq->name);
364
		if (!error_ok)
365
			errorf(NULL);
366
		return 0;
367
	}
368
8312638
	if (!(vq->flag&INTEGER)) { /* string dest */
369
7787535
		if ((vq->flag&ALLOC)) {
370
			/* debugging */
371

4648523
			if (s >= vq->val.s &&
372
1579275
			    s <= vq->val.s + strlen(vq->val.s))
373
				internal_errorf(true,
374
				    "setstr: %s=%s: assigning to self",
375
				    vq->name, s);
376
3069248
			afree(vq->val.s, vq->areap);
377
3069248
		}
378
7787535
		vq->flag &= ~(ISSET|ALLOC);
379
7787535
		vq->type = 0;
380

15575070
		if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST)))
381
2904
			fs = s = formatstr(vq, s);
382
7787535
		if ((vq->flag&EXPORT))
383
2660628
			export(vq, s);
384
		else {
385
5126907
			vq->val.s = str_save(s, vq->areap);
386
5126907
			vq->flag |= ALLOC;
387
		}
388
	} else {		/* integer dest */
389
525073
		if (!v_evaluate(vq, s, error_ok, true))
390
			return 0;
391
	}
392
8312608
	vq->flag |= ISSET;
393
8312608
	if ((vq->flag&SPECIAL))
394
849961
		setspec(vq);
395
8312608
	afree((void *)fs, ATEMP);
396
8312608
	return 1;
397
8312608
}
398
399
/* set variable to integer */
400
void
401
setint(struct tbl *vq, long int n)
402
{
403
217890
	if (!(vq->flag&INTEGER)) {
404
		struct tbl *vp = &vtemp;
405
106723
		vp->flag = (ISSET|INTEGER);
406
106723
		vp->type = 0;
407
106723
		vp->areap = ATEMP;
408
106723
		vp->val.i = n;
409
		/* setstr can't fail here */
410
106723
		setstr(vq, str_val(vp), KSH_RETURN_ERROR);
411
106723
	} else
412
2222
		vq->val.i = n;
413
108945
	vq->flag |= ISSET;
414
108945
	if ((vq->flag&SPECIAL))
415
917
		setspec(vq);
416
108945
}
417
418
int
419
getint(struct tbl *vp, long int *nump, bool arith)
420
{
421
	char *s;
422
	int c;
423
	int base, neg;
424
	int have_base = 0;
425
	long num;
426
427
3013668
	if (vp->flag&SPECIAL)
428
3870
		getspec(vp);
429
	/* XXX is it possible for ISSET to be set and val.s to be 0? */
430

7283409
	if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
431
		return -1;
432
3013668
	if (vp->flag&INTEGER) {
433
1757595
		*nump = vp->val.i;
434
1757595
		return vp->type;
435
	}
436
1256073
	s = vp->val.s + vp->type;
437
1256073
	if (s == NULL)	/* redundant given initial test */
438
		s = null;
439
	base = 10;
440
	num = 0;
441
	neg = 0;
442

2250795
	if (arith && *s == '0' && *(s+1)) {
443
6
		s++;
444

12
		if (*s == 'x' || *s == 'X') {
445
			s++;
446
			base = 16;
447
6
		} else if (vp->flag & ZEROFIL) {
448
			while (*s == '0')
449
				s++;
450
		} else
451
			base = 8;
452
		have_base++;
453
6
	}
454
6755090
	for (c = (unsigned char)*s++; c ; c = (unsigned char)*s++) {
455
2121490
		if (c == '-') {
456
			neg++;
457
2121490
		} else if (c == '#') {
458
72
			base = (int) num;
459
72
			if (have_base || base < 2 || base > 36)
460
12
				return -1;
461
			num = 0;
462
			have_base = 1;
463

4242896
		} else if (letnum(c)) {
464
2121418
			if (isdigit(c))
465
2121418
				c -= '0';
466
			else if (islower(c))
467
				c -= 'a' - 10; /* todo: assumes ascii */
468
			else if (isupper(c))
469
				c -= 'A' - 10; /* todo: assumes ascii */
470
			else
471
				c = -1; /* _: force error */
472

4242836
			if (c < 0 || c >= base)
473
6
				return -1;
474
2121412
			num = num * base + c;
475
		} else
476
			return -1;
477
	}
478
1256055
	if (neg)
479
		num = -num;
480
1256055
	*nump = num;
481
1256055
	return base;
482
3013668
}
483
484
/* convert variable vq to integer variable, setting its value from vp
485
 * (vq and vp may be the same)
486
 */
487
struct tbl *
488
setint_v(struct tbl *vq, struct tbl *vp, bool arith)
489
{
490
	int base;
491
2381202
	long num;
492
493
2381202
	if ((base = getint(vp, &num, arith)) == -1)
494
18
		return NULL;
495

3507237
	if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) {
496
		vq->flag &= ~ALLOC;
497
		afree(vq->val.s, vq->areap);
498
	}
499
2381184
	vq->val.i = num;
500
2381184
	if (vq->type == 0) /* default base */
501
2250896
		vq->type = base;
502
2381184
	vq->flag |= ISSET|INTEGER;
503
2381184
	if (vq->flag&SPECIAL)
504
420064
		setspec(vq);
505
2381184
	return vq;
506
2381202
}
507
508
static char *
509
formatstr(struct tbl *vp, const char *s)
510
{
511
	int olen, nlen;
512
	char *p, *q;
513
514
5808
	olen = strlen(s);
515
516
2904
	if (vp->flag & (RJUST|LJUST)) {
517
		if (!vp->u2.field)	/* default field width */
518
			vp->u2.field = olen;
519
		nlen = vp->u2.field;
520
	} else
521
		nlen = olen;
522
523
2904
	p = alloc(nlen + 1, ATEMP);
524
2904
	if (vp->flag & (RJUST|LJUST)) {
525
		int slen;
526
527
		if (vp->flag & RJUST) {
528
			const char *q = s + olen;
529
			/* strip trailing spaces (at&t ksh uses q[-1] == ' ') */
530
			while (q > s && isspace((unsigned char)q[-1]))
531
				--q;
532
			slen = q - s;
533
			if (slen > vp->u2.field) {
534
				s += slen - vp->u2.field;
535
				slen = vp->u2.field;
536
			}
537
			shf_snprintf(p, nlen + 1,
538
				((vp->flag & ZEROFIL) && digit(*s)) ?
539
					  "%0*s%.*s" : "%*s%.*s",
540
				vp->u2.field - slen, null, slen, s);
541
		} else {
542
			/* strip leading spaces/zeros */
543
			while (isspace((unsigned char)*s))
544
				s++;
545
			if (vp->flag & ZEROFIL)
546
				while (*s == '0')
547
					s++;
548
			shf_snprintf(p, nlen + 1, "%-*.*s",
549
				vp->u2.field, vp->u2.field, s);
550
		}
551
	} else
552
2904
		memcpy(p, s, olen + 1);
553
554
2904
	if (vp->flag & UCASEV_AL) {
555
		for (q = p; *q; q++)
556
			if (islower((unsigned char)*q))
557
				*q = toupper((unsigned char)*q);
558
2904
	} else if (vp->flag & LCASEV) {
559
73080
		for (q = p; *q; q++)
560
33636
			if (isupper((unsigned char)*q))
561
				*q = tolower((unsigned char)*q);
562
	}
563
564
2904
	return p;
565
}
566
567
/*
568
 * make vp->val.s be "name=value" for quick exporting.
569
 */
570
static void
571
export(struct tbl *vp, const char *val)
572
{
573
	char *xp;
574
8017107
	char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
575
2669562
	int namelen = strlen(vp->name);
576
2669562
	int vallen = strlen(val) + 1;
577
578
2669562
	vp->flag |= ALLOC;
579
2669562
	xp = alloc(namelen + 1 + vallen, vp->areap);
580
2669562
	memcpy(vp->val.s = xp, vp->name, namelen);
581
2669562
	xp += namelen;
582
2669562
	*xp++ = '=';
583
2669562
	vp->type = xp - vp->val.s; /* offset to value */
584
2669562
	memcpy(xp, val, vallen);
585
2669562
	afree(op, vp->areap);
586
2669562
}
587
588
/*
589
 * lookup variable (according to (set&LOCAL)),
590
 * set its attributes (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL,
591
 * LCASEV, UCASEV_AL), and optionally set its value if an assignment.
592
 */
593
struct tbl *
594
typeset(const char *var, int set, int clr, int field, int base)
595
{
596
	struct tbl *vp;
597
	struct tbl *vpbase, *t;
598
	char *tvar;
599
	const char *val;
600
601
	/* check for valid variable name, search for value */
602
12734454
	val = skip_varname(var, false);
603
6367227
	if (val == var)
604
		return NULL;
605
6367227
	if (*val == '[') {
606
		int len;
607
608
284
		len = array_ref_len(val);
609
284
		if (len == 0)
610
			return NULL;
611
		/* IMPORT is only used when the shell starts up and is
612
		 * setting up its environment.  Allow only simple array
613
		 * references at this time since parameter/command substitution
614
		 * is preformed on the [expression], which would be a major
615
		 * security hole.
616
		 */
617
284
		if (set & IMPORT) {
618
			int i;
619
			for (i = 1; i < len - 1; i++)
620
				if (!digit(val[i]))
621
					return NULL;
622
		}
623
284
		val += len;
624
284
	}
625
6367227
	if (*val == '=')
626
5722551
		tvar = str_nsave(var, val++ - var, ATEMP);
627
	else {
628
		/* Importing from original environment: must have an = */
629
644676
		if (set & IMPORT)
630
			return NULL;
631
		tvar = (char *) var;
632
		val = NULL;
633
	}
634
635
	/* Prevent typeset from creating a local PATH/ENV/SHELL */
636

6369987
	if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 ||
637
2760
	    strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0))
638
		errorf("%s: restricted", tvar);
639
640
19101681
	vp = (set&LOCAL) ? local(tvar, (set & LOCAL_COPY) ? true : false) :
641
5307137
	    global(tvar);
642
6367227
	set &= ~(LOCAL|LOCAL_COPY);
643
644
19101681
	vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp;
645
646
	/* only allow export flag to be set.  at&t ksh allows any attribute to
647
	 * be changed, which means it can be truncated or modified
648
	 * (-L/-R/-Z/-i).
649
	 */
650

6367227
	if ((vpbase->flag&RDONLY) &&
651
6
	    (val || clr || (set & ~EXPORT)))
652
		/* XXX check calls - is error here ok by POSIX? */
653
		errorf("%s: is read only", tvar);
654
6367221
	if (val)
655
5722545
		afree(tvar, ATEMP);
656
657
	/* most calls are with set/clr == 0 */
658
6367221
	if (set | clr) {
659
		int ok = 1;
660
		/* XXX if x[0] isn't set, there will be problems: need to have
661
		 * one copy of attributes for arrays...
662
		 */
663
14370748
		for (t = vpbase; t; t = t->u.array) {
664
			int fake_assign;
665
			int error_ok = KSH_RETURN_ERROR;
666
			char *s = NULL;
667
			char *free_me = NULL;
668
669

8048646
			fake_assign = (t->flag & ISSET) && (!val || t != vp) &&
670
536206
			    ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL)) ||
671

536218
			    ((t->flag & INTEGER) && (clr & INTEGER)) ||
672
1072400
			    (!(t->flag & INTEGER) && (set & INTEGER)));
673
3592702
			if (fake_assign) {
674
104775
				if (t->flag & INTEGER) {
675
					s = str_val(t);
676
					free_me = NULL;
677
				} else {
678
104775
					s = t->val.s + t->type;
679
314325
					free_me = (t->flag & ALLOC) ? t->val.s :
680
					    NULL;
681
				}
682
104775
				t->flag &= ~ALLOC;
683
104775
			}
684

7185362
			if (!(t->flag & INTEGER) && (set & INTEGER)) {
685
628848
				t->type = 0;
686
628848
				t->flag &= ~ALLOC;
687
628848
			}
688

7185404
			if (!(t->flag & RDONLY) && (set & RDONLY)) {
689
				/* allow var to be initialized read-only */
690
				error_ok |= KSH_IGNORE_RDONLY;
691
211572
			}
692
3592702
			t->flag = (t->flag | set) & ~clr;
693
			/* Don't change base if assignment is to be done,
694
			 * in case assignment fails.
695
			 */
696

3592816
			if ((set & INTEGER) && base > 0 && (!val || t != vp))
697
18
				t->type = base;
698
3592702
			if (set & (LJUST|RJUST|ZEROFIL))
699
				t->u2.field = field;
700
3592702
			if (fake_assign) {
701
104775
				if (!setstr(t, s, error_ok)) {
702
					/* Somewhat arbitrary action here:
703
					 * zap contents of variable, but keep
704
					 * the flag settings.
705
					 */
706
					ok = 0;
707
					if (t->flag & INTEGER)
708
						t->flag &= ~ISSET;
709
					else {
710
						if (t->flag & ALLOC)
711
							afree(t->val.s, t->areap);
712
						t->flag &= ~(ISSET|ALLOC);
713
						t->type = 0;
714
					}
715
				}
716
104775
				afree(free_me, t->areap);
717
104775
			}
718
		}
719
3592672
		if (!ok)
720
		    errorf(NULL);
721
3592672
	}
722
723
6367221
	if (val != NULL) {
724
5722545
		if (vp->flag&INTEGER) {
725
			/* do not zero base before assignment */
726
420280
			setstr(vp, val, KSH_UNWIND_ERROR | KSH_IGNORE_RDONLY);
727
			/* Done after assignment to override default */
728
420280
			if (base > 0)
729
42
				vp->type = base;
730
		} else
731
			/* setstr can't fail (readonly check already done) */
732
5302235
			setstr(vp, val, KSH_RETURN_ERROR | KSH_IGNORE_RDONLY);
733
	}
734
735
	/* only x[0] is ever exported, so use vpbase */
736

12089685
	if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER) &&
737
2861244
	    vpbase->type == 0)
738
26289
		export(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null);
739
740
6367191
	return vp;
741
6367191
}
742
743
/* Unset a variable.  array_ref is set if there was an array reference in
744
 * the name lookup (eg, x[2]).
745
 */
746
void
747
unset(struct tbl *vp, int array_ref)
748
{
749
7712
	if (vp->flag & ALLOC)
750
183
		afree(vp->val.s, vp->areap);
751
3856
	if ((vp->flag & ARRAY) && !array_ref) {
752
		struct tbl *a, *tmp;
753
754
		/* Free up entire array */
755
480
		for (a = vp->u.array; a; ) {
756
			tmp = a;
757
220
			a = a->u.array;
758
220
			if (tmp->flag & ALLOC)
759
220
				afree(tmp->val.s, tmp->areap);
760
220
			afree(tmp, tmp->areap);
761
		}
762
20
		vp->u.array = NULL;
763
20
	}
764
	/* If foo[0] is being unset, the remainder of the array is kept... */
765
3856
	vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0);
766
3856
	if (vp->flag & SPECIAL)
767
15
		unsetspec(vp);	/* responsible for `unspecial'ing var */
768
3856
}
769
770
/* return a pointer to the first char past a legal variable name (returns the
771
 * argument if there is no legal name, returns * a pointer to the terminating
772
 * null if whole string is legal).
773
 */
774
char *
775
skip_varname(const char *s, int aok)
776
{
777
	int alen;
778
779

57793194
	if (s && letter(*s)) {
780

299597979
		while (*++s && letnum(*s))
781
			;
782

17582479
		if (aok && *s == '[' && (alen = array_ref_len(s)))
783
			s += alen;
784
	}
785
19264398
	return (char *) s;
786
}
787
788
/* Return a pointer to the first character past any legal variable name.  */
789
char *
790
skip_wdvarname(const char *s,
791
    int aok)				/* skip array de-reference? */
792
{
793

15855583
	if (s[0] == CHAR && letter(s[1])) {
794
4899796
		do {
795
24623714
			s += 2;
796

45524765
		} while (s[0] == CHAR && letnum(s[1]));
797

10383422
		if (aok && s[0] == CHAR && s[1] == '[') {
798
			/* skip possible array de-reference */
799
			const char *p = s;
800
			char c;
801
			int depth = 0;
802
803
4707
			while (1) {
804
4707
				if (p[0] != CHAR)
805
					break;
806
4707
				c = p[1];
807
4707
				p += 2;
808
4707
				if (c == '[')
809
824
					depth++;
810

4707
				else if (c == ']' && --depth == 0) {
811
					s = p;
812
509
					break;
813
				}
814
			}
815
509
		}
816
	}
817
5370217
	return (char *) s;
818
}
819
820
/* Check if coded string s is a variable name */
821
int
822
is_wdvarname(const char *s, int aok)
823
{
824
100616
	char *p = skip_wdvarname(s, aok);
825
826
106968
	return p != s && p[0] == EOS;
827
}
828
829
/* Check if coded string s is a variable assignment */
830
int
831
is_wdvarassign(const char *s)
832
{
833
10639818
	char *p = skip_wdvarname(s, true);
834
835

16117596
	return p != s && p[0] == CHAR && p[1] == '=';
836
}
837
838
/*
839
 * Make the exported environment from the exported names in the dictionary.
840
 */
841
char **
842
makenv(void)
843
{
844
	struct block *l;
845
	XPtrV env;
846
	struct tbl *vp, **vpp;
847
	int i;
848
849
	XPinit(env, 64);
850
	for (l = genv->loc; l != NULL; l = l->next)
851
		for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
852
			if ((vp = *vpp++) != NULL &&
853
			    (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
854
				struct block *l2;
855
				struct tbl *vp2;
856
				unsigned int h = hash(vp->name);
857
858
				/* unexport any redefined instances */
859
				for (l2 = l->next; l2 != NULL; l2 = l2->next) {
860
					vp2 = ktsearch(&l2->vars, vp->name, h);
861
					if (vp2 != NULL)
862
						vp2->flag &= ~EXPORT;
863
				}
864
				if ((vp->flag&INTEGER)) {
865
					/* integer to string */
866
					char *val;
867
					val = str_val(vp);
868
					vp->flag &= ~(INTEGER|RDONLY);
869
					/* setstr can't fail here */
870
					setstr(vp, val, KSH_RETURN_ERROR);
871
				}
872
				XPput(env, vp->val.s);
873
			}
874
	XPput(env, NULL);
875
	return (char **) XPclose(env);
876
}
877
878
/*
879
 * Called after a fork in parent to bump the random number generator.
880
 * Done to ensure children will not get the same random number sequence
881
 * if the parent doesn't use $RANDOM.
882
 */
883
void
884
change_random(void)
885
{
886
5948724
	rand();
887
2974362
}
888
889
/*
890
 * handle special variables with side effects - PATH, SECONDS.
891
 */
892
893
/* Test if name is a special parameter */
894
static int
895
special(const char *name)
896
{
897
	struct tbl *tp;
898
899
13472798
	tp = ktsearch(&specials, name, hash(name));
900

20061310
	return tp && (tp->flag & ISSET) ? tp->type : V_NONE;
901
}
902
903
/* Make a variable non-special */
904
static void
905
unspecial(const char *name)
906
{
907
	struct tbl *tp;
908
909
24
	tp = ktsearch(&specials, name, hash(name));
910
12
	if (tp)
911
12
		ktdelete(tp);
912
12
}
913
914
static	time_t	seconds;		/* time SECONDS last set */
915
static	int	user_lineno;		/* what user set $LINENO to */
916
917
static void
918
getspec(struct tbl *vp)
919
{
920

1611085
	switch (special(vp->name)) {
921
	case V_SECONDS:
922
104799
		vp->flag &= ~SPECIAL;
923
		/* On start up the value of SECONDS is used before seconds
924
		 * has been set - don't do anything in this case
925
		 * (see initcoms[] in main.c).
926
		 */
927
104799
		if (vp->flag & ISSET)
928
36
			setint(vp, (long)(time(NULL) - seconds)); /* XXX 2038 */
929
		vp->flag |= SPECIAL;
930
104799
		break;
931
	case V_RANDOM:
932
2000
		vp->flag &= ~SPECIAL;
933
2000
		setint(vp, (long) (rand() & 0x7fff));
934
		vp->flag |= SPECIAL;
935
2000
		break;
936
#ifdef HISTORY
937
	case V_HISTSIZE:
938
		vp->flag &= ~SPECIAL;
939
		setint(vp, (long) histsize);
940
		vp->flag |= SPECIAL;
941
		break;
942
#endif /* HISTORY */
943
	case V_OPTIND:
944
186
		vp->flag &= ~SPECIAL;
945
186
		setint(vp, (long) user_opt.uoptind);
946
		vp->flag |= SPECIAL;
947
186
		break;
948
	case V_LINENO:
949
78
		vp->flag &= ~SPECIAL;
950
78
		setint(vp, (long) current_lineno + user_lineno);
951
		vp->flag |= SPECIAL;
952
78
		break;
953
	}
954
859074
}
955
956
static void
957
setspec(struct tbl *vp)
958
{
959
	char *s;
960
961




3825252
	switch (special(vp->name)) {
962
	case V_PATH:
963
209618
		afree(path, APERM);
964
209618
		path = str_save(str_val(vp), APERM);
965
209618
		flushcom(1);	/* clear tracked aliases */
966
209618
		break;
967
	case V_IFS:
968
113117
		setctypes(s = str_val(vp), C_IFS);
969
113117
		ifs0 = *s;
970
113117
		break;
971
	case V_OPTIND:
972
209538
		vp->flag &= ~SPECIAL;
973
209538
		getopts_reset((int) intval(vp));
974
209538
		vp->flag |= SPECIAL;
975
209538
		break;
976
	case V_POSIXLY_CORRECT:
977
12
		change_flag(FPOSIX, OF_SPECIAL, 1);
978
12
		break;
979
	case V_TMPDIR:
980
127
		afree(tmpdir, APERM);
981
127
		tmpdir = NULL;
982
		/* Use tmpdir iff it is an absolute path, is writable and
983
		 * searchable and is a directory...
984
		 */
985
		{
986
127
			struct stat statb;
987
988
127
			s = str_val(vp);
989

381
			if (s[0] == '/' && access(s, W_OK|X_OK) == 0 &&
990
254
			    stat(s, &statb) == 0 && S_ISDIR(statb.st_mode))
991
127
				tmpdir = str_save(s, APERM);
992
127
		}
993
127
		break;
994
#ifdef HISTORY
995
	case V_HISTCONTROL:
996
18
		sethistcontrol(str_val(vp));
997
18
		break;
998
	case V_HISTSIZE:
999
12
		vp->flag &= ~SPECIAL;
1000
12
		sethistsize((int) intval(vp));
1001
12
		vp->flag |= SPECIAL;
1002
12
		break;
1003
	case V_HISTFILE:
1004
2142
		sethistfile(str_val(vp));
1005
2142
		break;
1006
#endif /* HISTORY */
1007
#ifdef EDIT
1008
	case V_VISUAL:
1009
1998
		set_editmode(str_val(vp));
1010
1998
		break;
1011
	case V_EDITOR:
1012
1974
		if (!(global("VISUAL")->flag & ISSET))
1013
1320
			set_editmode(str_val(vp));
1014
		break;
1015
	case V_COLUMNS:
1016
		{
1017
1834
			long l;
1018
1019
1834
			if (getint(vp, &l, false) == -1) {
1020
				x_cols = MIN_COLS;
1021
				break;
1022
			}
1023
3668
			if (l <= MIN_COLS || l > INT_MAX)
1024
				x_cols = MIN_COLS;
1025
			else
1026
1834
				x_cols = l;
1027
3668
		}
1028
		break;
1029
#endif /* EDIT */
1030
	case V_MAIL:
1031
104082
		mbset(str_val(vp));
1032
104082
		break;
1033
	case V_MAILPATH:
1034
		mpset(str_val(vp));
1035
		break;
1036
	case V_MAILCHECK:
1037
209526
		vp->flag &= ~SPECIAL;
1038
209526
		mcset(intval(vp));
1039
209526
		vp->flag |= SPECIAL;
1040
209526
		break;
1041
	case V_RANDOM:
1042
2018
		vp->flag &= ~SPECIAL;
1043
2018
		srand_deterministic((unsigned int)intval(vp));
1044
2018
		vp->flag |= SPECIAL;
1045
2018
		break;
1046
	case V_SECONDS:
1047
209526
		vp->flag &= ~SPECIAL;
1048
209526
		seconds = time(NULL) - intval(vp); /* XXX 2038 */
1049
209526
		vp->flag |= SPECIAL;
1050
209526
		break;
1051
	case V_TMOUT:
1052
		/* at&t ksh seems to do this (only listen if integer) */
1053
209526
		if (vp->flag & INTEGER)
1054
628578
			ksh_tmout = vp->val.i >= 0 ? vp->val.i : 0;
1055
		break;
1056
	case V_LINENO:
1057
12
		vp->flag &= ~SPECIAL;
1058
		/* The -1 is because line numbering starts at 1. */
1059
12
		user_lineno = (unsigned int) intval(vp) - current_lineno - 1;
1060
12
		vp->flag |= SPECIAL;
1061
12
		break;
1062
	}
1063
1275086
}
1064
1065
static void
1066
unsetspec(struct tbl *vp)
1067
{
1068



78
	switch (special(vp->name)) {
1069
	case V_PATH:
1070
		afree(path, APERM);
1071
		path = str_save(def_path, APERM);
1072
		flushcom(1);	/* clear tracked aliases */
1073
		break;
1074
	case V_IFS:
1075
		setctypes(" \t\n", C_IFS);
1076
		ifs0 = ' ';
1077
		break;
1078
	case V_TMPDIR:
1079
		/* should not become unspecial */
1080
12
		afree(tmpdir, APERM);
1081
12
		tmpdir = NULL;
1082
12
		break;
1083
	case V_MAIL:
1084
		mbset(NULL);
1085
		break;
1086
	case V_MAILPATH:
1087
		mpset(NULL);
1088
		break;
1089
#ifdef HISTORY
1090
	case V_HISTCONTROL:
1091
		sethistcontrol(NULL);
1092
		break;
1093
#endif
1094
	case V_LINENO:
1095
	case V_MAILCHECK:	/* at&t ksh leaves previous value in place */
1096
	case V_RANDOM:
1097
	case V_SECONDS:
1098
	case V_TMOUT:		/* at&t ksh leaves previous value in place */
1099
12
		unspecial(vp->name);
1100
12
		break;
1101
1102
	  /* at&t ksh man page says OPTIND, OPTARG and _ lose special meaning,
1103
	   * but OPTARG does not (still set by getopts) and _ is also still
1104
	   * set in various places.
1105
	   * Don't know what at&t does for:
1106
	   *		MAIL, MAILPATH, HISTSIZE, HISTFILE,
1107
	   * Unsetting these in at&t ksh does not loose the `specialness':
1108
	   *    no effect: IFS, COLUMNS, PATH, TMPDIR,
1109
	   *		VISUAL, EDITOR,
1110
	   * pdkshisms: no effect:
1111
	   *		POSIXLY_CORRECT (use set +o posix instead)
1112
	   */
1113
	}
1114
27
}
1115
1116
/*
1117
 * Search for (and possibly create) a table entry starting with
1118
 * vp, indexed by val.
1119
 */
1120
static struct tbl *
1121
arraysearch(struct tbl *vp, int val)
1122
{
1123
	struct tbl *prev, *curr, *new;
1124
2370
	size_t namelen = strlen(vp->name) + 1;
1125
1126
1185
	vp->flag |= ARRAY|DEFINED;
1127
1185
	vp->index = 0;
1128
	/* The table entry is always [0] */
1129
1185
	if (val == 0)
1130
222
		return vp;
1131
	prev = vp;
1132
963
	curr = vp->u.array;
1133

15765
	while (curr && curr->index < val) {
1134
		prev = curr;
1135
3182
		curr = curr->u.array;
1136
	}
1137

1111
	if (curr && curr->index == val) {
1138
124
		if (curr->flag&ISSET)
1139
124
			return curr;
1140
		else
1141
			new = curr;
1142
	} else
1143
1678
		new = alloc(sizeof(struct tbl) + namelen,
1144
839
		    vp->areap);
1145
839
	strlcpy(new->name, vp->name, namelen);
1146
839
	new->flag = vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL);
1147
839
	new->type = vp->type;
1148
839
	new->areap = vp->areap;
1149
839
	new->u2.field = vp->u2.field;
1150
839
	new->index = val;
1151
839
	if (curr != new) {		/* not reusing old array entry */
1152
839
		prev->u.array = new;
1153
839
		new->u.array = curr;
1154
839
	}
1155
839
	return new;
1156
1185
}
1157
1158
/* Return the length of an array reference (eg, [1+2]) - cp is assumed
1159
 * to point to the open bracket.  Returns 0 if there is no matching closing
1160
 * bracket.
1161
 */
1162
int
1163
array_ref_len(const char *cp)
1164
{
1165
	const char *s = cp;
1166
	int c;
1167
	int depth = 0;
1168
1169

20556
	while ((c = *s++) && (c != ']' || --depth))
1170
4056
		if (c == '[')
1171
872
			depth++;
1172
692
	if (!c)
1173
		return 0;
1174
692
	return s - cp;
1175
692
}
1176
1177
/*
1178
 * Make a copy of the base of an array name
1179
 */
1180
char *
1181
arrayname(const char *str)
1182
{
1183
	const char *p;
1184
1185
1688
	if ((p = strchr(str, '[')) == 0)
1186
		/* Shouldn't happen, but why worry? */
1187
		return (char *) str;
1188
1189
844
	return str_nsave(str, p - str, ATEMP);
1190
844
}
1191
1192
/* Set (or overwrite, if !reset) the array variable var to the values in vals.
1193
 */
1194
void
1195
set_array(const char *var, int reset, char **vals)
1196
{
1197
	struct tbl *vp, *vq;
1198
	int i;
1199
1200
	/* to get local array, use "typeset foo; set -A foo" */
1201
316
	vp = global(var);
1202
1203
	/* Note: at&t ksh allows set -A but not set +A of a read-only var */
1204
158
	if ((vp->flag&RDONLY))
1205
		errorf("%s: is read only", var);
1206
	/* This code is quite non-optimal */
1207
158
	if (reset > 0)
1208
		/* trash existing values and attributes */
1209
158
		unset(vp, 0);
1210
	/* todo: would be nice for assignment to completely succeed or
1211
	 * completely fail.  Only really effects integer arrays:
1212
	 * evaluation of some of vals[] may fail...
1213
	 */
1214
1870
	for (i = 0; vals[i]; i++) {
1215
777
		vq = arraysearch(vp, i);
1216
		/* would be nice to deal with errors here... (see above) */
1217
777
		setstr(vq, vals[i], KSH_RETURN_ERROR);
1218
	}
1219
158
}