Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * Expansion - quoting, separation, substitution, globbing
3
 */
4
 
5
#include "sh.h"
6
#include <pwd.h>
7
#include "ksh_dir.h"
8
#include "ksh_stat.h"
9
 
10
/*
11
 * string expansion
12
 *
13
 * first pass: quoting, IFS separation, ~, ${}, $() and $(()) substitution.
14
 * second pass: alternation ({,}), filename expansion (*?[]).
15
 */
16
 
17
/* expansion generator state */
18
typedef struct Expand {
19
	/* int  type; */	/* see expand() */
20
	const char *str;	/* string */
21
	union {
22
		const char **strv;/* string[] */
23
		struct shf *shf;/* file */
24
	} u;			/* source */
25
	struct tbl *var;	/* variable in ${var..} */
26
	short	split;		/* split "$@" / call waitlast $() */
27
} Expand;
28
 
29
#define	XBASE		0	/* scanning original */
30
#define	XSUB		1	/* expanding ${} string */
31
#define	XARGSEP		2	/* ifs0 between "$*" */
32
#define	XARG		3	/* expanding $*, $@ */
33
#define	XCOM		4	/* expanding $() */
34
#define XNULLSUB	5	/* "$@" when $# is 0 (don't generate word) */
35
 
36
/* States used for field splitting */
37
#define IFS_WORD	0	/* word has chars (or quotes) */
38
#define IFS_WS		1	/* have seen IFS white-space */
39
#define IFS_NWS		2	/* have seen IFS non-white-space */
40
 
41
static	int	varsub ARGS((Expand *xp, char *sp, char *word, int *stypep, int *slenp));
42
static	int	comsub ARGS((Expand *xp, char *cp));
43
static	char   *trimsub ARGS((char *str, char *pat, int how));
44
static	void	glob ARGS((char *cp, XPtrV *wp, int markdirs));
45
static	void	globit ARGS((XString *xs, char **xpp, char *sp, XPtrV *wp,
46
			     int check));
47
static char	*maybe_expand_tilde ARGS((char *p, XString *dsp, char **dpp,
48
					  int isassign));
49
static	char   *tilde ARGS((char *acp));
50
static	char   *homedir ARGS((char *name));
51
#ifdef BRACE_EXPAND
52
static void	alt_expand ARGS((XPtrV *wp, char *start, char *exp_start,
53
				 char *end, int fdo));
54
#endif
55
 
56
/* compile and expand word */
57
char *
58
substitute(cp, f)
59
	const char *cp;
60
	int f;
61
{
62
	struct source *s, *sold;
63
 
64
	sold = source;
65
	s = pushs(SWSTR, ATEMP);
66
	s->start = s->str = cp;
67
	source = s;
68
	if (yylex(ONEWORD) != LWORD)
69
		internal_errorf(1, "substitute");
70
	source = sold;
71
	afree(s, ATEMP);
72
	return evalstr(yylval.cp, f);
73
}
74
 
75
/*
76
 * expand arg-list
77
 */
78
char **
79
eval(ap, f)
80
	register char **ap;
81
	int f;
82
{
83
	XPtrV w;
84
 
85
	if (*ap == NULL)
86
		return ap;
87
	XPinit(w, 32);
88
	XPput(w, NULL);		/* space for shell name */
89
#ifdef	SHARPBANG
90
	XPput(w, NULL);		/* and space for one arg */
91
#endif
92
	while (*ap != NULL)
93
		expand(*ap++, &w, f);
94
	XPput(w, NULL);
95
#ifdef	SHARPBANG
96
	return (char **) XPclose(w) + 2;
97
#else
98
	return (char **) XPclose(w) + 1;
99
#endif
100
}
101
 
102
/*
103
 * expand string
104
 */
105
char *
106
evalstr(cp, f)
107
	char *cp;
108
	int f;
109
{
110
	XPtrV w;
111
 
112
	XPinit(w, 1);
113
	expand(cp, &w, f);
114
	cp = (XPsize(w) == 0) ? null : (char*) *XPptrv(w);
115
	XPfree(w);
116
	return cp;
117
}
118
 
119
/*
120
 * expand string - return only one component
121
 * used from iosetup to expand redirection files
122
 */
123
char *
124
evalonestr(cp, f)
125
	register char *cp;
126
	int f;
127
{
128
	XPtrV w;
129
 
130
	XPinit(w, 1);
131
	expand(cp, &w, f);
132
	switch (XPsize(w)) {
133
	case 0:
134
		cp = null;
135
		break;
136
	case 1:
137
		cp = (char*) *XPptrv(w);
138
		break;
139
	default:
140
		cp = evalstr(cp, f&~DOGLOB);
141
		break;
142
	}
143
	XPfree(w);
144
	return cp;
145
}
146
 
147
/* for nested substitution: ${var:=$var2} */
148
typedef struct SubType {
149
	short	stype;		/* [=+-?%#] action after expanded word */
150
	short	base;		/* begin position of expanded word */
151
	short	f;		/* saved value of f (DOPAT, etc) */
152
	struct tbl *var;	/* variable for ${var..} */
153
	short	quote;		/* saved value of quote (for ${..[%#]..}) */
154
	struct SubType *prev;	/* old type */
155
	struct SubType *next;	/* poped type (to avoid re-allocating) */
156
} SubType;
157
 
158
void
159
expand(cp, wp, f)
160
	char *cp;		/* input word */
161
	register XPtrV *wp;	/* output words */
162
	int f;			/* DO* flags */
163
{
164
	register int UNINITIALIZED(c);
165
	register int type;	/* expansion type */
166
	register int quote = 0;	/* quoted */
167
	XString ds;		/* destination string */
168
	register char *dp, *sp;	/* dest., source */
169
	int fdo, word;		/* second pass flags; have word */
170
	int doblank;		/* field spliting of parameter/command subst */
171
	Expand x;		/* expansion variables */
172
	SubType st_head, *st;
173
	int UNINITIALIZED(newlines); /* For trailing newlines in COMSUB */
174
	int saw_eq, tilde_ok;
175
	int make_magic;
176
 
177
	if (cp == NULL)
178
		internal_errorf(1, "expand(NULL)");
179
	/* for alias, readonly, set, typeset commands */
180
	if ((f & DOVACHECK) && is_wdvarassign(cp)) {
181
		f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE);
182
		f |= DOASNTILDE;
183
	}
184
	if (Flag(FNOGLOB))
185
		f &= ~DOGLOB;
186
	if (Flag(FMARKDIRS))
187
		f |= DOMARKDIRS;
188
#ifdef BRACE_EXPAND
189
	if (Flag(FBRACEEXPAND) && (f & DOGLOB))
190
		f |= DOBRACE_;
191
#endif /* BRACE_EXPAND */
192
 
193
	Xinit(ds, dp, 128, ATEMP);	/* init dest. string */
194
	type = XBASE;
195
	sp = cp;
196
	fdo = 0;
197
	saw_eq = 0;
198
	tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0; /* must be 1/0 */
199
	doblank = 0;
200
	make_magic = 0;
201
	word = (f&DOBLANK) ? IFS_WS : IFS_WORD;
202
	st_head.next = (SubType *) 0;
203
	st = &st_head;
204
 
205
	while (1) {
206
		Xcheck(ds, dp);
207
 
208
		switch (type) {
209
		  case XBASE:	/* original prefixed string */
210
			c = *sp++;
211
			switch (c) {
212
			  case EOS:
213
				c = 0;
214
				break;
215
			  case CHAR:
216
				c = *sp++;
217
				break;
218
			  case QCHAR:
219
				quote |= 2; /* temporary quote */
220
				c = *sp++;
221
				break;
222
			  case OQUOTE:
223
				word = IFS_WORD;
224
				tilde_ok = 0;
225
				quote = 1;
226
				continue;
227
			  case CQUOTE:
228
				quote = 0;
229
				continue;
230
			  case COMSUB:
231
				tilde_ok = 0;
232
				if (f & DONTRUNCOMMAND) {
233
					word = IFS_WORD;
234
					*dp++ = '$'; *dp++ = '(';
235
					while (*sp != '\0') {
236
						Xcheck(ds, dp);
237
						*dp++ = *sp++;
238
					}
239
					*dp++ = ')';
240
				} else {
241
					type = comsub(&x, sp);
242
					if (type == XCOM && (f&DOBLANK))
243
						doblank++;
244
					sp = strchr(sp, 0) + 1;
245
					newlines = 0;
246
				}
247
				continue;
248
			  case EXPRSUB:
249
				word = IFS_WORD;
250
				tilde_ok = 0;
251
				if (f & DONTRUNCOMMAND) {
252
					*dp++ = '$'; *dp++ = '('; *dp++ = '(';
253
					while (*sp != '\0') {
254
						Xcheck(ds, dp);
255
						*dp++ = *sp++;
256
					}
257
					*dp++ = ')'; *dp++ = ')';
258
				} else {
259
					struct tbl v;
260
					char *p;
261
 
262
					v.flag = DEFINED|ISSET|INTEGER;
263
					v.type = 10; /* not default */
264
					v.name[0] = '\0';
265
					v_evaluate(&v, substitute(sp, 0),
266
						KSH_UNWIND_ERROR);
267
					sp = strchr(sp, 0) + 1;
268
					for (p = str_val(&v); *p; ) {
269
						Xcheck(ds, dp);
270
						*dp++ = *p++;
271
					}
272
				}
273
				continue;
274
			  case OSUBST: /* ${{#}var{:}[=+-?#%]word} */
275
			  /* format is:
276
			   *   OSUBST [{x] plain-variable-part \0
277
			   *     compiled-word-part CSUBST [}x]
278
			   * This is were all syntax checking gets done...
279
			   */
280
			  {
281
				char *varname = ++sp; /* skip the { or x (}) */
282
				int stype;
283
				int slen;
284
 
285
				sp = strchr(sp, '\0') + 1; /* skip variable */
286
				type = varsub(&x, varname, sp, &stype, &slen);
287
				if (type < 0) {
288
					char endc;
289
					char *str, *end;
290
 
291
					end = (char *) wdscan(sp, CSUBST);
292
					/* ({) the } or x is already skipped */
293
					endc = *end;
294
					*end = EOS;
295
					str = snptreef((char *) 0, 64, "%S",
296
							varname - 1);
297
					*end = endc;
298
					errorf("%s: bad substitution", str);
299
				}
300
				if (f&DOBLANK)
301
					doblank++;
302
				tilde_ok = 0;
303
				if (type == XBASE) {	/* expand? */
304
					if (!st->next) {
305
						SubType *newst;
306
 
307
						newst = (SubType *) alloc(
308
							sizeof(SubType), ATEMP);
309
						newst->next = (SubType *) 0;
310
						newst->prev = st;
311
						st->next = newst;
312
					}
313
					st = st->next;
314
					st->stype = stype;
315
					st->base = Xsavepos(ds, dp);
316
					st->f = f;
317
					st->var = x.var;
318
					st->quote = quote;
319
					/* skip qualifier(s) */
320
					if (stype)
321
						sp += slen;
322
					switch (stype & 0x7f) {
323
					  case '#':
324
					  case '%':
325
						/* ! DOBLANK,DOBRACE_,DOTILDE */
326
						f = DOPAT | (f&DONTRUNCOMMAND)
327
						    | DOTEMP_;
328
						quote = 0;
329
						/* Prepend open pattern (so |
330
						 * in a trim will work as
331
						 * expected)
332
						 */
333
						*dp++ = MAGIC;
334
						*dp++ = '@' + 0x80;
335
						break;
336
					  case '=':
337
						/* Enabling tilde expansion
338
						 * after :'s here is
339
						 * non-standard ksh, but is
340
						 * consistent with rules for
341
						 * other assignments.  Not
342
						 * sure what POSIX thinks of
343
						 * this.
344
						 * Not doing tilde expansion
345
						 * for integer variables is a
346
						 * non-POSIX thing - makes
347
						 * sense though, since ~ is
348
						 * a arithmetic operator.
349
						 */
350
						if (!(x.var->flag & INTEGER))
351
							f |= DOASNTILDE|DOTILDE;
352
						f |= DOTEMP_;
353
						/* These will be done after the
354
						 * value has been assigned.
355
						 */
356
						f &= ~(DOBLANK|DOGLOB|DOBRACE_);
357
						tilde_ok = 1;
358
						break;
359
					  case '?':
360
						f &= ~DOBLANK;
361
						f |= DOTEMP_;
362
						/* fall through */
363
					  default:
364
						/* Enable tilde expansion */
365
						tilde_ok = 1;
366
						f |= DOTILDE;
367
					}
368
				} else
369
					/* skip word */
370
					sp = (char *) wdscan(sp, CSUBST);
371
				continue;
372
			  }
373
			  case CSUBST: /* only get here if expanding word */
374
				sp++; /* ({) skip the } or x */
375
				tilde_ok = 0;	/* in case of ${unset:-} */
376
				*dp = '\0';
377
				quote = st->quote;
378
				f = st->f;
379
				if (f&DOBLANK)
380
					doblank--;
381
				switch (st->stype&0x7f) {
382
				  case '#':
383
				  case '%':
384
					/* Append end-pattern */
385
					*dp++ = MAGIC; *dp++ = ')'; *dp = '\0';
386
					dp = Xrestpos(ds, dp, st->base);
387
					/* Must use st->var since calling
388
					 * global would break things
389
					 * like x[i+=1].
390
					 */
391
					x.str = trimsub(str_val(st->var),
392
						dp, st->stype);
393
					type = XSUB;
394
					if (f&DOBLANK)
395
						doblank++;
396
					st = st->prev;
397
					continue;
398
				  case '=':
399
					/* Restore our position and substitute
400
					 * the value of st->var (may not be
401
					 * the assigned value in the presence
402
					 * of integer/right-adj/etc attributes).
403
					 */
404
					dp = Xrestpos(ds, dp, st->base);
405
					/* Must use st->var since calling
406
					 * global would cause with things
407
					 * like x[i+=1] to be evaluated twice.
408
					 */
409
					/* Note: not exported by FEXPORT
410
					 * in at&t ksh.
411
					 */
412
					/* XXX POSIX says readonly is only
413
					 * fatal for special builtins (setstr
414
					 * does readonly check).
415
					 */
416
					setstr(st->var, debunk(
417
						(char *) alloc(strlen(dp) + 1,
418
							ATEMP), dp),
419
						KSH_UNWIND_ERROR);
420
					x.str = str_val(st->var);
421
					type = XSUB;
422
					if (f&DOBLANK)
423
						doblank++;
424
					st = st->prev;
425
					continue;
426
				  case '?':
427
				    {
428
					char *s = Xrestpos(ds, dp, st->base);
429
 
430
					errorf("%s: %s", st->var->name,
431
					    dp == s ? 
432
					      "parameter null or not set"
433
					    : (debunk(s, s), s));
434
				    }
435
				}
436
				st = st->prev;
437
				type = XBASE;
438
				continue;
439
 
440
			  case OPAT: /* open pattern: *(foo|bar) */
441
				/* Next char is the type of pattern */
442
				make_magic = 1;
443
				c = *sp++ + 0x80;
444
				break;
445
 
446
			  case SPAT: /* pattern seperator (|) */
447
				make_magic = 1;
448
				c = '|';
449
				break;
450
 
451
			  case CPAT: /* close pattern */
452
				make_magic = 1;
453
				c = /*(*/ ')';
454
				break;
455
			}
456
			break;
457
 
458
		  case XNULLSUB:
459
			/* Special case for "$@" (and "${foo[@]}") - no
460
			 * word is generated if $# is 0 (unless there is
461
			 * other stuff inside the quotes).
462
			 */
463
			type = XBASE;
464
			if (f&DOBLANK) {
465
				doblank--;
466
				/* not really correct: x=; "$x$@" should
467
				 * generate a null argument and
468
				 * set A; "${@:+}" shouldn't.
469
				 */
470
				if (dp == Xstring(ds, dp))
471
					word = IFS_WS;
472
			}
473
			continue;
474
 
475
		  case XSUB:
476
			if ((c = *x.str++) == 0) {
477
				type = XBASE;
478
				if (f&DOBLANK)
479
					doblank--;
480
				continue;
481
			}
482
			break;
483
 
484
		  case XARGSEP:
485
			type = XARG;
486
			quote = 1;
487
		  case XARG:
488
			if ((c = *x.str++) == '\0') {
489
				/* force null words to be created so
490
				 * set -- '' 2 ''; foo "$@" will do
491
				 * the right thing
492
				 */
493
				if (quote && x.split)
494
					word = IFS_WORD;
495
				if ((x.str = *x.u.strv++) == NULL) {
496
					type = XBASE;
497
					if (f&DOBLANK)
498
						doblank--;
499
					continue;
500
				}
501
				c = ifs0;
502
				if (c == 0) {
503
					if (quote && !x.split)
504
						continue;
505
					c = ' ';
506
				}
507
				if (quote && x.split) {
508
					/* terminate word for "$@" */
509
					type = XARGSEP;
510
					quote = 0;
511
				}
512
			}
513
			break;
514
 
515
		  case XCOM:
516
			if (newlines) {		/* Spit out saved nl's */
517
				c = '\n';
518
				--newlines;
519
			} else {
520
				while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
521
				    if (c == '\n')
522
					    newlines++;	/* Save newlines */
523
				if (newlines && c != EOF) {
524
					shf_ungetc(c, x.u.shf);
525
					c = '\n';
526
					--newlines;
527
				}
528
			}
529
			if (c == EOF) {
530
				newlines = 0;
531
				shf_close(x.u.shf);
532
				if (x.split)
533
					subst_exstat = waitlast();
534
				type = XBASE;
535
				if (f&DOBLANK)
536
					doblank--;
537
				continue;
538
			}
539
			break;
540
		}
541
 
542
		/* check for end of word or IFS separation */
543
		if (c == 0 || (!quote && (f & DOBLANK) && doblank && !make_magic
544
			       && ctype(c, C_IFS)))
545
		{
546
			/* How words are broken up:
547
			 *		   |       value of c
548
			 *	  word	   |	ws	nws	0
549
			 *	-----------------------------------
550
			 *	IFS_WORD	w/WS	w/NWS	w
551
			 *	IFS_WS		-/WS	w/NWS	-
552
			 *	IFS_NWS		-/NWS	w/NWS	w
553
			 *   (w means generate a word)
554
			 * Note that IFS_NWS/0 generates a word (at&t ksh
555
			 * doesn't do this, but POSIX does).
556
			 */
557
			if (word == IFS_WORD
558
			    || (!ctype(c, C_IFSWS) && (c || word == IFS_NWS)))
559
			{
560
				char *p;
561
 
562
				*dp++ = '\0';
563
				p = Xclose(ds, dp);
564
#ifdef BRACE_EXPAND
565
				if (fdo & DOBRACE_)
566
					/* also does globbing */
567
					alt_expand(wp, p, p,
568
						   p + Xlength(ds, (dp - 1)),
569
						   fdo | (f & DOMARKDIRS));
570
				else
571
#endif /* BRACE_EXPAND */
572
				if (fdo & DOGLOB)
573
					glob(p, wp, f & DOMARKDIRS);
574
				else if ((f & DOPAT) || !(fdo & DOMAGIC_))
575
					XPput(*wp, p);
576
				else
577
					XPput(*wp, debunk(p, p));
578
				fdo = 0;
579
				saw_eq = 0;
580
				tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
581
				if (c != 0)
582
					Xinit(ds, dp, 128, ATEMP);
583
			}
584
			if (c == 0)
585
				return;
586
			if (word != IFS_NWS)
587
				word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS;
588
		} else {
589
			/* age tilde_ok info - ~ code tests second bit */
590
			tilde_ok <<= 1;
591
			/* mark any special second pass chars */
592
			if (!quote)
593
				switch (c) {
594
				  case '[':
595
				  case NOT:
596
				  case '-':
597
				  case ']':
598
					/* For character classes - doesn't hurt
599
					 * to have magic !,-,]'s outside of
600
					 * [...] expressions.
601
					 */
602
					if (f & (DOPAT | DOGLOB)) {
603
						fdo |= DOMAGIC_;
604
						if (c == '[')
605
							fdo |= f & DOGLOB;
606
						*dp++ = MAGIC;
607
					}
608
					break;
609
				  case '*':
610
				  case '?':
611
					if (f & (DOPAT | DOGLOB)) {
612
						fdo |= DOMAGIC_ | (f & DOGLOB);
613
						*dp++ = MAGIC;
614
					}
615
					break;
616
#ifdef BRACE_EXPAND
617
				  case OBRACE:
618
				  case ',':
619
				  case CBRACE:
620
					if ((f & DOBRACE_) && (c == OBRACE
621
						|| (fdo & DOBRACE_)))
622
					{
623
						fdo |= DOBRACE_|DOMAGIC_;
624
						*dp++ = MAGIC;
625
					}
626
					break;
627
#endif /* BRACE_EXPAND */
628
				  case '=':
629
					/* Note first unquoted = for ~ */
630
					if (!(f & DOTEMP_) && !saw_eq) {
631
						saw_eq = 1;
632
						tilde_ok = 1;
633
					}
634
					break;
635
				  case PATHSEP: /* : */
636
					/* Note unquoted : for ~ */
637
					if (!(f & DOTEMP_) && (f & DOASNTILDE))
638
						tilde_ok = 1;
639
					break;
640
				  case '~':
641
					/* tilde_ok is reset whenever
642
					 * any of ' " $( $(( ${ } are seen.
643
					 * Note that tilde_ok must be preserved
644
					 * through the sequence ${A=a=}~
645
					 */
646
					if (type == XBASE
647
					    && (f & (DOTILDE|DOASNTILDE))
648
					    && (tilde_ok & 2))
649
					{
650
						char *p, *dp_x;
651
 
652
						dp_x = dp;
653
						p = maybe_expand_tilde(sp,
654
							&ds, &dp_x,
655
							f & DOASNTILDE);
656
						if (p) {
657
							if (dp != dp_x)
658
								word = IFS_WORD;
659
							dp = dp_x;
660
							sp = p;
661
							continue;
662
						}
663
					}
664
					break;
665
				}
666
			else
667
				quote &= ~2; /* undo temporary */
668
 
669
			if (make_magic) {
670
				make_magic = 0;
671
				fdo |= DOMAGIC_ | (f & DOGLOB);
672
				*dp++ = MAGIC;
673
			} else if (ISMAGIC(c)) {
674
				fdo |= DOMAGIC_;
675
				*dp++ = MAGIC;
676
			}
677
			*dp++ = c; /* save output char */
678
			word = IFS_WORD;
679
		}
680
	}
681
}
682
 
683
/*
684
 * Prepare to generate the string returned by ${} substitution.
685
 */
686
static int
687
varsub(xp, sp, word, stypep, slenp)
688
	Expand *xp;
689
	char *sp;
690
	char *word;
691
	int *stypep;	/* becomes qualifier type */
692
	int *slenp;	/* " " len (=, :=, etc.) valid iff *stypep != 0 */
693
{
694
	int c;
695
	int state;	/* next state: XBASE, XARG, XSUB, XNULLSUB */
696
	int stype;	/* substitution type */
697
	int slen;
698
	char *p;
699
	struct tbl *vp;
700
 
701
	if (sp[0] == '\0')	/* Bad variable name */
702
		return -1;
703
 
704
	xp->var = (struct tbl *) 0;
705
 
706
	/* ${#var}, string length or array size */
707
	if (sp[0] == '#' && (c = sp[1]) != '\0') {
708
		int zero_ok = 0;
709
 
710
		/* Can't have any modifiers for ${#...} */
711
		if (*word != CSUBST)
712
			return -1;
713
		sp++;
714
		/* Check for size of array */
715
		if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') {
716
			int n = 0;
717
			int max = 0;
718
			vp = global(arrayname(sp));
719
			if (vp->flag & (ISSET|ARRAY))
720
				zero_ok = 1;
721
			for (; vp; vp = vp->u.array)
722
				if (vp->flag & ISSET) {
723
					max = vp->index + 1;
724
					n++;
725
				}
726
			c = n; /* ksh88/ksh93 go for number, not max index */
727
		} else if (c == '*' || c == '@')
728
			c = e->loc->argc;
729
		else {
730
			p = str_val(global(sp));
731
			zero_ok = p != null;
732
			c = strlen(p);
733
		}
734
		if (Flag(FNOUNSET) && c == 0 && !zero_ok)
735
			errorf("%s: parameter not set", sp);
736
		*stypep = 0; /* unqualified variable/string substitution */
737
		xp->str = str_save(ulton((unsigned long)c, 10), ATEMP);
738
		return XSUB;
739
	}
740
 
741
	/* Check for qualifiers in word part */
742
	stype = 0;
743
	c = word[slen = 0] == CHAR ? word[1] : 0;
744
	if (c == ':') {
745
		slen += 2;
746
		stype = 0x80;
747
		c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
748
	}
749
	if (ctype(c, C_SUBOP1)) {
750
		slen += 2;
751
		stype |= c;
752
	} else if (ctype(c, C_SUBOP2)) { /* Note: ksh88 allows :%, :%%, etc */
753
		slen += 2;
754
		stype = c;
755
		if (word[slen + 0] == CHAR && c == word[slen + 1]) {
756
			stype |= 0x80;
757
			slen += 2;
758
		}
759
	} else if (stype)	/* : is not ok */
760
		return -1;
761
	if (!stype && *word != CSUBST)
762
		return -1;
763
	*stypep = stype;
764
	*slenp = slen;
765
 
766
	c = sp[0];
767
	if (c == '*' || c == '@') {
768
		switch (stype & 0x7f) {
769
		  case '=':	/* can't assign to a vector */
770
		  case '%':	/* can't trim a vector (yet) */
771
		  case '#':
772
			return -1;
773
		}
774
		if (e->loc->argc == 0) {
775
			xp->str = null;
776
			state = c == '@' ? XNULLSUB : XSUB;
777
		} else {
778
			xp->u.strv = (const char **) e->loc->argv + 1;
779
			xp->str = *xp->u.strv++;
780
			xp->split = c == '@'; /* $@ */
781
			state = XARG;
782
		}
783
	} else {
784
		if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') {
785
			XPtrV wv;
786
 
787
			switch (stype & 0x7f) {
788
			  case '=':	/* can't assign to a vector */
789
			  case '%':	/* can't trim a vector (yet) */
790
			  case '#':
791
				return -1;
792
			}
793
			XPinit(wv, 32);
794
			vp = global(arrayname(sp));
795
			for (; vp; vp = vp->u.array) {
796
				if (!(vp->flag&ISSET))
797
					continue;
798
				XPput(wv, str_val(vp));
799
			}
800
			if (XPsize(wv) == 0) {
801
				xp->str = null;
802
				state = p[1] == '@' ? XNULLSUB : XSUB;
803
				XPfree(wv);
804
			} else {
805
				XPput(wv, 0);
806
				xp->u.strv = (const char **) XPptrv(wv);
807
				xp->str = *xp->u.strv++;
808
				xp->split = p[1] == '@'; /* ${foo[@]} */
809
				state = XARG;
810
			}
811
		} else {
812
			/* Can't assign things like $! or $1 */
813
			if ((stype & 0x7f) == '='
814
			    && (ctype(*sp, C_VAR1) || digit(*sp)))
815
				return -1;
816
			xp->var = global(sp);
817
			xp->str = str_val(xp->var);
818
			state = XSUB;
819
		}
820
	}
821
 
822
	c = stype&0x7f;
823
	/* test the compiler's code generator */
824
	if (ctype(c, C_SUBOP2) ||
825
	    (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */
826
	     c == '=' || c == '-' || c == '?' : c == '+'))
827
		state = XBASE;	/* expand word instead of variable value */
828
	if (Flag(FNOUNSET) && xp->str == null
829
	    && (ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
830
		errorf("%s: parameter not set", sp);
831
	return state;
832
}
833
 
834
/*
835
 * Run the command in $(...) and read its output.
836
 */
837
static int
838
comsub(xp, cp)
839
	register Expand *xp;
840
	char *cp;
841
{
842
	Source *s, *sold;
843
	register struct op *t;
844
	struct shf *shf;
845
 
846
	s = pushs(SSTRING, ATEMP);
847
	s->start = s->str = cp;
848
	sold = source;
849
	t = compile(s);
850
	source = sold;
851
 
852
	if (t == NULL)
853
		return XBASE;
854
 
855
	if (t != NULL && t->type == TCOM && /* $(<file) */
856
	    *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
857
		register struct ioword *io = *t->ioact;
858
		char *name;
859
 
860
		if ((io->flag&IOTYPE) != IOREAD)
861
			errorf("funny $() command: %s",
862
				snptreef((char *) 0, 32, "%R", io));
863
		shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
864
			SHF_MAPHI|SHF_CLEXEC);
865
		if (shf == NULL)
866
			errorf("%s: cannot open $() input", name);
867
		xp->split = 0;	/* no waitlast() */
868
	} else {
869
		int ofd1, pv[2];
870
		openpipe(pv);
871
		shf = shf_fdopen(pv[0], SHF_RD, (struct shf *) 0);
872
		ofd1 = savefd(1, 0);	/* fd 1 may be closed... */
873
		ksh_dup2(pv[1], 1, FALSE);
874
		close(pv[1]);
875
		execute(t, XFORK|XXCOM|XPIPEO);
876
		restfd(1, ofd1);
877
		startlast();
878
		xp->split = 1;	/* waitlast() */
879
	}
880
 
881
	xp->u.shf = shf;
882
	return XCOM;
883
}
884
 
885
/*
886
 * perform #pattern and %pattern substitution in ${}
887
 */
888
 
889
static char *
890
trimsub(str, pat, how)
891
	register char *str;
892
	char *pat;
893
	int how;
894
{
895
	register char *end = strchr(str, 0);
896
	register char *p, c;
897
 
898
	switch (how&0xff) {	/* UCHAR_MAX maybe? */
899
	  case '#':		/* shortest at begining */
900
		for (p = str; p <= end; p++) {
901
			c = *p; *p = '\0';
902
			if (gmatch(str, pat, FALSE)) {
903
				*p = c;
904
				return p;
905
			}
906
			*p = c;
907
		}
908
		break;
909
	  case '#'|0x80:	/* longest match at begining */
910
		for (p = end; p >= str; p--) {
911
			c = *p; *p = '\0';
912
			if (gmatch(str, pat, FALSE)) {
913
				*p = c;
914
				return p;
915
			}
916
			*p = c;
917
		}
918
		break;
919
	  case '%':		/* shortest match at end */
920
		for (p = end; p >= str; p--) {
921
			if (gmatch(p, pat, FALSE))
922
				return str_nsave(str, p - str, ATEMP);
923
		}
924
		break;
925
	  case '%'|0x80:	/* longest match at end */
926
		for (p = str; p <= end; p++) {
927
			if (gmatch(p, pat, FALSE))
928
				return str_nsave(str, p - str, ATEMP);
929
		}
930
		break;
931
	}
932
 
933
	return str;		/* no match, return string */
934
}
935
 
936
/*
937
 * glob
938
 * Name derived from V6's /etc/glob, the program that expanded filenames.
939
 */
940
 
941
/* XXX cp not const 'cause slashes are temporarily replaced with nulls... */
942
static void
943
glob(cp, wp, markdirs)
944
	char *cp;
945
	register XPtrV *wp;
946
	int markdirs;
947
{
948
	int oldsize = XPsize(*wp);
949
 
950
	if (glob_str(cp, wp, markdirs) == 0)
951
		XPput(*wp, debunk(cp, cp));
952
	else
953
		qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize),
954
			xstrcmp);
955
}
956
 
957
#define GF_NONE		0
958
#define GF_EXCHECK	BIT(0)		/* do existance check on file */
959
#define GF_GLOBBED	BIT(1)		/* some globbing has been done */
960
#define GF_MARKDIR	BIT(2)		/* add trailing / to directories */
961
 
962
/* Apply file globbing to cp and store the matching files in wp.  Returns
963
 * the number of matches found.
964
 */
965
int
966
glob_str(cp, wp, markdirs)
967
	char *cp;
968
	XPtrV *wp;
969
	int markdirs;
970
{
971
	int oldsize = XPsize(*wp);
972
	XString xs;
973
	char *xp;
974
 
975
	Xinit(xs, xp, 256, ATEMP);
976
	globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE);
977
	Xfree(xs, xp);
978
 
979
	return XPsize(*wp) - oldsize;
980
}
981
 
982
static void
983
globit(xs, xpp, sp, wp, check)
984
	XString *xs;		/* dest string */
985
	char **xpp;		/* ptr to dest end */
986
	char *sp;		/* source path */
987
	register XPtrV *wp;	/* output list */
988
	int check;		/* GF_* flags */
989
{
990
	register char *np;	/* next source component */
991
	char *xp = *xpp;
992
	char *se;
993
	char odirsep;
994
 
995
	/* This to allow long expansions to be interrupted */
996
	intrcheck();
997
 
998
	if (sp == NULL) {	/* end of source path */
999
		/* We only need to check if the file exists if a pattern
1000
		 * is followed by a non-pattern (eg, foo*x/bar; no check
1001
		 * is needed for foo* since the match must exist) or if
1002
		 * any patterns were expanded and the markdirs option is set.
1003
		 * Symlinks make things a bit tricky...
1004
		 */
1005
		if ((check & GF_EXCHECK)
1006
		    || ((check & GF_MARKDIR) && (check & GF_GLOBBED)))
1007
		{
1008
#define stat_check()	(stat_done ? stat_done : \
1009
			    (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \
1010
				? -1 : 1))
1011
			struct stat lstatb, statb;
1012
			int stat_done = 0;	 /* -1: failed, 1 ok */
1013
 
1014
			if (lstat(Xstring(*xs, xp), &lstatb) < 0)
1015
				return;
1016
			/* special case for systems which strip trailing
1017
			 * slashes from regular files (eg, /etc/passwd/).
1018
			 * SunOS 4.1.3 does this...
1019
			 */
1020
			if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp)
1021
			    && ISDIRSEP(xp[-1]) && !S_ISDIR(lstatb.st_mode)
1022
#ifdef S_ISLNK
1023
			    && (!S_ISLNK(lstatb.st_mode)
1024
				|| stat_check() < 0
1025
				|| !S_ISDIR(statb.st_mode))
1026
#endif /* S_ISLNK */
1027
				)
1028
				return;
1029
			/* Possibly tack on a trailing / if there isn't already
1030
			 * one and if the file is a directory or a symlink to a
1031
			 * directory
1032
			 */
1033
			if (((check & GF_MARKDIR) && (check & GF_GLOBBED))
1034
			    && xp > Xstring(*xs, xp) && !ISDIRSEP(xp[-1])
1035
			    && (S_ISDIR(lstatb.st_mode)
1036
#ifdef S_ISLNK
1037
				|| (S_ISLNK(lstatb.st_mode)
1038
				    && stat_check() > 0
1039
				    && S_ISDIR(statb.st_mode))
1040
#endif /* S_ISLNK */
1041
				    ))
1042
			{
1043
				*xp++ = DIRSEP;
1044
				*xp = '\0';
1045
			}
1046
		}
1047
#ifdef OS2 /* Done this way to avoid bug in gcc 2.7.2... */
1048
    /* Ugly kludge required for command
1049
     * completion - see how search_access()
1050
     * is implemented for OS/2...
1051
     */
1052
# define KLUDGE_VAL	4
1053
#else /* OS2 */
1054
# define KLUDGE_VAL	0
1055
#endif /* OS2 */
1056
		XPput(*wp, str_nsave(Xstring(*xs, xp), Xlength(*xs, xp)
1057
			+ KLUDGE_VAL, ATEMP));
1058
		return;
1059
	}
1060
 
1061
	if (xp > Xstring(*xs, xp))
1062
		*xp++ = DIRSEP;
1063
	while (ISDIRSEP(*sp)) {
1064
		Xcheck(*xs, xp);
1065
		*xp++ = *sp++;
1066
	}
1067
	np = ksh_strchr_dirsep(sp);
1068
	if (np != NULL) {
1069
		se = np;
1070
		odirsep = *np;	/* don't assume DIRSEP, can be multiple kinds */
1071
		*np++ = '\0';
1072
	} else {
1073
		odirsep = '\0'; /* keep gcc quiet */
1074
		se = sp + strlen(sp);
1075
	}
1076
 
1077
 
1078
	/* Check if sp needs globbing - done to avoid pattern checks for strings
1079
	 * containing MAGIC characters, open ['s without the matching close ],
1080
	 * etc. (otherwise opendir() will be called which may fail because the
1081
	 * directory isn't readable - if no globbing is needed, only execute
1082
	 * permission should be required (as per POSIX)).
1083
	 */
1084
	if (!has_globbing(sp, se)) {
1085
		XcheckN(*xs, xp, se - sp + 1);
1086
		debunk(xp, sp);
1087
		xp += strlen(xp);
1088
		*xpp = xp;
1089
		globit(xs, xpp, np, wp, check);
1090
	} else {
1091
		DIR *dirp;
1092
		struct dirent *d;
1093
		char *name;
1094
		int len;
1095
		int prefix_len;
1096
 
1097
		/* xp = *xpp;	   copy_non_glob() may have re-alloc'd xs */
1098
		*xp = '\0';
1099
		prefix_len = Xlength(*xs, xp);
1100
		dirp = ksh_opendir(prefix_len ? Xstring(*xs, xp) : ".");
1101
		if (dirp == NULL)
1102
			goto Nodir;
1103
		while ((d = readdir(dirp)) != NULL) {
1104
			name = d->d_name;
1105
			if (name[0] == '.' &&
1106
			    (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
1107
				continue; /* always ignore . and .. */
1108
			if ((*name == '.' && *sp != '.')
1109
			    || !gmatch(name, sp, TRUE))
1110
				continue;
1111
 
1112
			len = NLENGTH(d) + 1;
1113
			XcheckN(*xs, xp, len);
1114
			memcpy(xp, name, len);
1115
			*xpp = xp + len - 1;
1116
			globit(xs, xpp, np, wp,
1117
				(check & GF_MARKDIR) | GF_GLOBBED
1118
				| (np ? GF_EXCHECK : GF_NONE));
1119
			xp = Xstring(*xs, xp) + prefix_len;
1120
		}
1121
		closedir(dirp);
1122
	  Nodir:;
1123
	}
1124
 
1125
	if (np != NULL)
1126
		*--np = odirsep;
1127
}
1128
 
1129
#if 0
1130
/* Check if p contains something that needs globbing; if it does, 0 is
1131
 * returned; if not, p is copied into xs/xp after stripping any MAGICs
1132
 */
1133
static int	copy_non_glob ARGS((XString *xs, char **xpp, char *p));
1134
static int
1135
copy_non_glob(xs, xpp, p)
1136
	XString *xs;
1137
	char **xpp;
1138
	char *p;
1139
{
1140
	char *xp;
1141
	int len = strlen(p);
1142
 
1143
	XcheckN(*xs, *xpp, len);
1144
	xp = *xpp;
1145
	for (; *p; p++) {
1146
		if (ISMAGIC(*p)) {
1147
			int c = *++p;
1148
 
1149
			if (c == '*' || c == '?')
1150
				return 0;
1151
			if (*p == '[') {
1152
				char *q = p + 1;
1153
 
1154
				if (ISMAGIC(*q) && q[1] == NOT)
1155
					q += 2;
1156
				if (ISMAGIC(*q) && q[1] == ']')
1157
					q += 2;
1158
				for (; *q; q++)
1159
					if (ISMAGIC(*q) && *++q == ']')
1160
						return 0;
1161
				/* pass a literal [ through */
1162
			}
1163
			/* must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, etc. */
1164
		}
1165
		*xp++ = *p;
1166
	}
1167
	*xp = '\0';
1168
	*xpp = xp;
1169
	return 1;
1170
}
1171
#endif /* 0 */
1172
 
1173
/* remove MAGIC from string */
1174
char *
1175
debunk(dp, sp)
1176
	char *dp;
1177
	const char *sp;
1178
{
1179
	char *d, *s;
1180
 
1181
	if ((s = strchr(sp, MAGIC))) {
1182
		memcpy(dp, sp, s - sp);
1183
		for (d = dp + (s - sp); *s; s++)
1184
			if (!ISMAGIC(*s) || !(*++s & 0x80)
1185
			    || !strchr("*+?@! ", *s & 0x7f))
1186
				*d++ = *s;
1187
			else {
1188
				/* extended pattern operators: *+?@! */
1189
				if ((*s & 0x7f) != ' ')
1190
					*d++ = *s & 0x7f;
1191
				*d++ = '(';
1192
			}
1193
		*d = '\0';
1194
	} else if (dp != sp)
1195
		strcpy(dp, sp);
1196
	return dp;
1197
}
1198
 
1199
/* Check if p is an unquoted name, possibly followed by a / or :.  If so
1200
 * puts the expanded version in *dcp,dp and returns a pointer in p just
1201
 * past the name, otherwise returns 0.
1202
 */
1203
static char *
1204
maybe_expand_tilde(p, dsp, dpp, isassign)
1205
	char *p;
1206
	XString *dsp;
1207
	char **dpp;
1208
	int isassign;
1209
{
1210
	XString ts;
1211
	char *dp = *dpp;
1212
	char *tp, *r;
1213
 
1214
	Xinit(ts, tp, 16, ATEMP);
1215
	/* : only for DOASNTILDE form */
1216
	while (p[0] == CHAR && !ISDIRSEP(p[1])
1217
	       && (!isassign || p[1] != PATHSEP))
1218
	{
1219
		Xcheck(ts, tp);
1220
		*tp++ = p[1];
1221
		p += 2;
1222
	}
1223
	*tp = '\0';
1224
	r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ? tilde(Xstring(ts, tp)) : (char *) 0;
1225
	Xfree(ts, tp);
1226
	if (r) {
1227
		while (*r) {
1228
			Xcheck(*dsp, dp);
1229
			if (ISMAGIC(*r))
1230
				*dp++ = MAGIC;
1231
			*dp++ = *r++;
1232
		}
1233
		*dpp = dp;
1234
		r = p;
1235
	}
1236
	return r;
1237
}
1238
 
1239
/*
1240
 * tilde expansion
1241
 *
1242
 * based on a version by Arnold Robbins
1243
 */
1244
 
1245
static char *
1246
tilde(cp)
1247
	char *cp;
1248
{
1249
	char *dp;
1250
 
1251
	if (cp[0] == '\0')
1252
		dp = str_val(global("HOME"));
1253
	else if (cp[0] == '+' && cp[1] == '\0')
1254
		dp = str_val(global("PWD"));
1255
	else if (cp[0] == '-' && cp[1] == '\0')
1256
		dp = str_val(global("OLDPWD"));
1257
	else
1258
		dp = homedir(cp);
1259
	/* If HOME, PWD or OLDPWD are not set, don't expand ~ */
1260
	if (dp == null)
1261
		dp = (char *) 0;
1262
	return dp;
1263
}
1264
 
1265
/*
1266
 * map userid to user's home directory.
1267
 * note that 4.3's getpw adds more than 6K to the shell,
1268
 * and the YP version probably adds much more.
1269
 * we might consider our own version of getpwnam() to keep the size down.
1270
 */
1271
 
1272
static char *
1273
homedir(name)
1274
	char *name;
1275
{
1276
	register struct tbl *ap;
1277
 
1278
	ap = tenter(&homedirs, name, hash(name));
1279
	if (!(ap->flag & ISSET)) {
1280
#ifdef OS2
1281
		/* No usernames in OS2 - punt */
1282
		return NULL;
1283
#else /* OS2 */
1284
		struct passwd *pw;
1285
 
1286
		pw = getpwnam(name);
1287
		if (pw == NULL)
1288
			return NULL;
1289
		ap->val.s = str_save(pw->pw_dir, APERM);
1290
		ap->flag |= DEFINED|ISSET|ALLOC;
1291
#endif /* OS2 */
1292
	}
1293
	return ap->val.s;
1294
}
1295
 
1296
#ifdef BRACE_EXPAND
1297
static void
1298
alt_expand(wp, start, exp_start, end, fdo)
1299
	XPtrV *wp;
1300
	char *start, *exp_start;
1301
	char *end;
1302
	int fdo;
1303
{
1304
	int UNINITIALIZED(count);
1305
	char *brace_start, *brace_end, *UNINITIALIZED(comma);
1306
	char *field_start;
1307
	char *p;
1308
 
1309
	/* search for open brace */
1310
	for (p = exp_start; (p = strchr(p, MAGIC)) && p[1] != OBRACE; p += 2)
1311
		;
1312
	brace_start = p;
1313
 
1314
	/* find matching close brace, if any */
1315
	if (p) {
1316
		comma = (char *) 0;
1317
		count = 1;
1318
		for (p += 2; *p && count; p++) {
1319
			if (ISMAGIC(*p)) {
1320
				if (*++p == OBRACE)
1321
					count++;
1322
				else if (*p == CBRACE)
1323
					--count;
1324
				else if (*p == ',' && count == 1)
1325
					comma = p;
1326
			}
1327
		}
1328
	}
1329
	/* no valid expansions... */
1330
	if (!p || count != 0) {
1331
		/* Note that given a{{b,c} we do not expand anything (this is
1332
		 * what at&t ksh does.  This may be changed to do the {b,c}
1333
		 * expansion. }
1334
		 */
1335
		if (fdo & DOGLOB)
1336
			glob(start, wp, fdo & DOMARKDIRS);
1337
		else
1338
			XPput(*wp, debunk(start, start));
1339
		return;
1340
	}
1341
	brace_end = p;
1342
	if (!comma) {
1343
		alt_expand(wp, start, brace_end, end, fdo);
1344
		return;
1345
	}
1346
 
1347
	/* expand expression */
1348
	field_start = brace_start + 2;
1349
	count = 1;
1350
	for (p = brace_start + 2; p != brace_end; p++) {
1351
		if (ISMAGIC(*p)) {
1352
			if (*++p == OBRACE)
1353
				count++;
1354
			else if ((*p == CBRACE && --count == 0)
1355
				 || (*p == ',' && count == 1))
1356
			{
1357
				char *new;
1358
				int l1, l2, l3;
1359
 
1360
				l1 = brace_start - start;
1361
				l2 = (p - 1) - field_start;
1362
				l3 = end - brace_end;
1363
				new = (char *) alloc(l1 + l2 + l3 + 1, ATEMP);
1364
				memcpy(new, start, l1);
1365
				memcpy(new + l1, field_start, l2);
1366
				memcpy(new + l1 + l2, brace_end, l3);
1367
				new[l1 + l2 + l3] = '\0';
1368
				alt_expand(wp, new, new + l1,
1369
					   new + l1 + l2 + l3, fdo);
1370
				field_start = p + 1;
1371
			}
1372
		}
1373
	}
1374
	return;
1375
}
1376
#endif /* BRACE_EXPAND */