GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/ksh/lex.c Lines: 638 895 71.3 %
Date: 2017-11-07 Branches: 543 798 68.0 %

Line Branch Exec Source
1
/*	$OpenBSD: lex.c,v 1.71 2017/07/04 11:46:15 anton Exp $	*/
2
3
/*
4
 * lexical analysis and source input
5
 */
6
7
#include <ctype.h>
8
#include <errno.h>
9
#include <libgen.h>
10
#include <stdio.h>
11
#include <string.h>
12
#include <unistd.h>
13
14
#include "sh.h"
15
16
/*
17
 * states while lexing word
18
 */
19
#define	SINVALID	-1	/* invalid state */
20
#define	SBASE	0		/* outside any lexical constructs */
21
#define	SWORD	1		/* implicit quoting for substitute() */
22
#define	SLETPAREN 2		/* inside (( )), implicit quoting */
23
#define	SSQUOTE	3		/* inside '' */
24
#define	SDQUOTE	4		/* inside "" */
25
#define	SBRACE	5		/* inside ${} */
26
#define	SCSPAREN 6		/* inside $() */
27
#define	SBQUOTE	7		/* inside `` */
28
#define	SASPAREN 8		/* inside $(( )) */
29
#define SHEREDELIM 9		/* parsing <<,<<- delimiter */
30
#define SHEREDQUOTE 10		/* parsing " in <<,<<- delimiter */
31
#define SPATTERN 11		/* parsing *(...|...) pattern (*+?@!) */
32
#define STBRACE 12		/* parsing ${..[#%]..} */
33
#define	SBRACEQ	13		/* inside "${}" */
34
35
/* Structure to keep track of the lexing state and the various pieces of info
36
 * needed for each particular state.
37
 */
38
typedef struct lex_state Lex_state;
39
struct lex_state {
40
	int ls_state;
41
	union {
42
		/* $(...) */
43
		struct scsparen_info {
44
			int nparen;	/* count open parenthesis */
45
			int csstate;	/* XXX remove */
46
#define ls_scsparen ls_info.u_scsparen
47
		} u_scsparen;
48
49
		/* $((...)) */
50
		struct sasparen_info {
51
			int nparen;	/* count open parenthesis */
52
			int start;	/* marks start of $(( in output str */
53
#define ls_sasparen ls_info.u_sasparen
54
		} u_sasparen;
55
56
		/* ((...)) */
57
		struct sletparen_info {
58
			int nparen;	/* count open parenthesis */
59
#define ls_sletparen ls_info.u_sletparen
60
		} u_sletparen;
61
62
		/* `...` */
63
		struct sbquote_info {
64
			int indquotes;	/* true if in double quotes: "`...`" */
65
#define ls_sbquote ls_info.u_sbquote
66
		} u_sbquote;
67
68
		Lex_state *base;	/* used to point to next state block */
69
	} ls_info;
70
};
71
72
typedef struct State_info State_info;
73
struct State_info {
74
	Lex_state	*base;
75
	Lex_state	*end;
76
};
77
78
79
static void	readhere(struct ioword *);
80
static int	getsc__(void);
81
static void	getsc_line(Source *);
82
static int	getsc_bn(void);
83
static char	*get_brace_var(XString *, char *);
84
static int	arraysub(char **);
85
static const char *ungetsc(int);
86
static void	gethere(void);
87
static Lex_state *push_state_(State_info *, Lex_state *);
88
static Lex_state *pop_state_(State_info *, Lex_state *);
89
static char	*special_prompt_expand(char *);
90
static int	dopprompt(const char *, int, const char **, int);
91
int		promptlen(const char *cp, const char **spp);
92
93
static int backslash_skip;
94
static int ignore_backslash_newline;
95
96
Source *source;		/* yyparse/yylex source */
97
YYSTYPE	yylval;		/* result from yylex */
98
struct ioword *heres[HERES], **herep;
99
char	ident[IDENT+1];
100
101
char  **history;	/* saved commands */
102
char  **histptr;	/* last history item */
103
int	histsize;	/* history size */
104
105
/* optimized getsc_bn() */
106
#define getsc()		(*source->str != '\0' && *source->str != '\\' \
107
			 && !backslash_skip ? *source->str++ : getsc_bn())
108
/* optimized getsc__() */
109
#define	getsc_()	((*source->str != '\0') ? *source->str++ : getsc__())
110
111
#define STATE_BSIZE	32
112
113
#define PUSH_STATE(s)	do { \
114
			    if (++statep == state_info.end) \
115
				statep = push_state_(&state_info, statep); \
116
			    state = statep->ls_state = (s); \
117
			} while (0)
118
119
#define POP_STATE()	do { \
120
			    if (--statep == state_info.base) \
121
				statep = pop_state_(&state_info, statep); \
122
			    state = statep->ls_state; \
123
			} while (0)
124
125
126
127
/*
128
 * Lexical analyzer
129
 *
130
 * tokens are not regular expressions, they are LL(1).
131
 * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
132
 * hence the state stack.
133
 */
134
135
int
136
yylex(int cf)
137
{
138
170685044
	Lex_state states[STATE_BSIZE], *statep;
139
85342522
	State_info state_info;
140
	int c, state;
141
85342522
	XString ws;		/* expandable output word */
142
	char *wp;		/* output word pointer */
143
	char *sp, *dp;
144
85342522
	int c2;
145
146
147
  Again:
148
86975781
	states[0].ls_state = SINVALID;
149
86975781
	states[0].ls_info.base = NULL;
150
86975781
	statep = &states[1];
151
86975781
	state_info.base = states;
152
86975781
	state_info.end = &states[STATE_BSIZE];
153
154
86975781
	Xinit(ws, wp, 64, ATEMP);
155
156
86975781
	backslash_skip = 0;
157
86975781
	ignore_backslash_newline = 0;
158
159
86975781
	if (cf&ONEWORD)
160
701753
		state = SWORD;
161
86274028
	else if (cf&LETEXPR) {
162
50
		*wp++ = OQUOTE;	 /* enclose arguments in (double) quotes */
163
		state = SLETPAREN;
164
50
		statep->ls_sletparen.nparen = 0;
165
50
	} else {		/* normal lexing */
166
86273978
		state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
167

682377313
		while ((c = getsc()) == ' ' || c == '\t')
168
			;
169
86271116
		if (c == '#') {
170
2276800
			ignore_backslash_newline++;
171

412452008
			while ((c = getsc()) != '\0' && c != '\n')
172
				;
173
2276800
			ignore_backslash_newline--;
174
2276800
		}
175
86271116
		ungetsc(c);
176
	}
177
86972919
	if (source->flags & SF_ALIAS) {	/* trailing ' ' in alias definition */
178
546
		source->flags &= ~SF_ALIAS;
179
		/* In POSIX mode, a trailing space only counts if we are
180
		 * parsing a simple command
181
		 */
182

546
		if (!Flag(FPOSIX) || (cf & CMDWORD))
183
546
			cf |= ALIAS;
184
	}
185
186
	/* Initial state: one of SBASE SHEREDELIM SWORD SASPAREN */
187
86972919
	statep->ls_state = state;
188
189
	/* collect non-special or quoted characters to form word */
190


2622347664
	while (!((c = getsc()) == 0 ||
191
812458312
	    ((state == SBASE || state == SHEREDELIM) && ctype(c, C_LEX1)))) {
192
424487368
		Xcheck(ws, wp);
193



583163182
		switch (state) {
194
		case SBASE:
195

231104350
			if (Flag(FCSHHISTORY) && (source->flags & SF_TTY) &&
196
			    c == '!') {
197
				char **replace = NULL;
198
				int get, i;
199
				char match[200] = { 0 }, *str = match;
200
				size_t mlen;
201
202
				c2 = getsc();
203
				if (c2 == '\0' || c2 == ' ' || c2 == '\t')
204
					;
205
				else if (c2 == '!')
206
					replace = hist_get_newest(0);
207
				else if (isdigit(c2) || c2 == '-' ||
208
				    isalpha(c2)) {
209
					get = !isalpha(c2);
210
211
					*str++ = c2;
212
					do {
213
						if ((c2 = getsc()) == '\0')
214
							break;
215
						if (c2 == '\t' || c2 == ' ' ||
216
						    c2 == '\n') {
217
							ungetsc(c2);
218
							break;
219
						}
220
						*str++ = c2;
221
					} while (str < &match[sizeof(match)-1]);
222
					*str = '\0';
223
224
					if (get) {
225
						int h = findhistrel(match);
226
						if (h >= 0)
227
							replace = &history[h];
228
					} else {
229
						int h = findhist(-1, 0, match, true);
230
						if (h >= 0)
231
							replace = &history[h];
232
					}
233
				}
234
235
				/*
236
				 * XXX ksh history buffer saves un-expanded
237
				 * commands. Until the history buffer code is
238
				 * changed to contain expanded commands, we
239
				 * ignore the bad commands (spinning sucks)
240
				 */
241
				if (replace && **replace == '!')
242
					ungetsc(c2);
243
				else if (replace) {
244
					Source *s;
245
246
					/* do not strdup replacement via alloc */
247
					s = pushs(SREREAD, source->areap);
248
					s->start = s->str = *replace;
249
					s->next = source;
250
					s->u.freeme = NULL;
251
					source = s;
252
					continue;
253
				} else if (*match != '\0') {
254
					/* restore what followed the '!' */
255
					mlen = strlen(match);
256
					for (i = mlen-1; i >= 0; i--)
257
						ungetsc(match[i]);
258
				} else
259
					ungetsc(c2);
260
			}
261

231330955
			if (c == '[' && (cf & (VARASN|ARRAYVAR))) {
262
167375
				*wp = EOS; /* temporary */
263
167375
				if (is_wdvarname(Xstring(ws, wp), false)) {
264
823
					char *p, *tmp;
265
266
823
					if (arraysub(&tmp)) {
267
823
						*wp++ = CHAR;
268
823
						*wp++ = c;
269
13588
						for (p = tmp; *p; ) {
270
5971
							Xcheck(ws, wp);
271
5971
							*wp++ = CHAR;
272
5971
							*wp++ = *p++;
273
						}
274
823
						afree(tmp, ATEMP);
275
823
						break;
276
					} else {
277
						Source *s;
278
279
						s = pushs(SREREAD,
280
							  source->areap);
281
						s->start = s->str
282
							= s->u.freeme = tmp;
283
						s->next = source;
284
						source = s;
285
					}
286
823
				}
287
166552
				*wp++ = CHAR;
288
166552
				*wp++ = c;
289
166552
				break;
290
			}
291
			/* FALLTHROUGH */
292
		  Sbase1:	/* includes *(...|...) pattern (*+?@!) */
293
470592476
			if (c == '*' || c == '@' || c == '+' || c == '?' ||
294
235296238
			    c == '!') {
295

10783917
				c2 = getsc();
296
2696775
				if (c2 == '(' /*)*/ ) {
297
8714
					*wp++ = OPAT;
298
8714
					*wp++ = c;
299
17428
					PUSH_STATE(SPATTERN);
300
8714
					break;
301
				}
302
2688061
				ungetsc(c2);
303
2688061
			}
304
			/* FALLTHROUGH */
305
		  Sbase2:	/* doesn't include *(...|...) pattern (*+?@!) */
306

237793424
			switch (c) {
307
			case '\\':
308

2498493
				c = getsc();
309
624642
				if (c) /* trailing \ is lost */
310
624567
					*wp++ = QCHAR, *wp++ = c;
311
				break;
312
			case '\'':
313
1512931
				if ((cf & HEREDOC) || state == SBRACEQ) {
314
4258
					*wp++ = CHAR, *wp++ = c;
315
4258
					break;
316
				}
317
1508673
				*wp++ = OQUOTE;
318
1508673
				ignore_backslash_newline++;
319
3017346
				PUSH_STATE(SSQUOTE);
320
1508673
				break;
321
			case '"':
322
8449707
				*wp++ = OQUOTE;
323
16899414
				PUSH_STATE(SDQUOTE);
324
8449707
				break;
325
			default:
326
				goto Subst;
327
			}
328
			break;
329
330
		  Subst:
331

335261021
			switch (c) {
332
			case '\\':
333

14598312
				c = getsc();
334

3649578
				switch (c) {
335
				case '\\':
336
				case '$': case '`':
337
347927
					*wp++ = QCHAR, *wp++ = c;
338
347927
					break;
339
				case '"':
340
374041
					if ((cf & HEREDOC) == 0) {
341
374041
						*wp++ = QCHAR, *wp++ = c;
342
374041
						break;
343
					}
344
					/* FALLTHROUGH */
345
				default:
346
2927610
					if (cf & UNESCAPE) {
347
						*wp++ = QCHAR, *wp++ = c;
348
						break;
349
					}
350
2927610
					Xcheck(ws, wp);
351
2927610
					if (c) { /* trailing \ is lost */
352
2927610
						*wp++ = CHAR, *wp++ = '\\';
353
2927610
						*wp++ = CHAR, *wp++ = c;
354
2927610
					}
355
					break;
356
				}
357
				break;
358
			case '$':
359

60637556
				c = getsc();
360
15159389
				if (c == '(') /*)*/ {
361

182604
					c = getsc();
362
45651
					if (c == '(') /*)*/ {
363
28712
						PUSH_STATE(SASPAREN);
364
14356
						statep->ls_sasparen.nparen = 2;
365
14356
						statep->ls_sasparen.start =
366
14356
						    Xsavepos(ws, wp);
367
14356
						*wp++ = EXPRSUB;
368
14356
					} else {
369
31295
						ungetsc(c);
370
62590
						PUSH_STATE(SCSPAREN);
371
31295
						statep->ls_scsparen.nparen = 1;
372
31295
						statep->ls_scsparen.csstate = 0;
373
31295
						*wp++ = COMSUB;
374
					}
375
15113738
				} else if (c == '{') /*}*/ {
376
2538935
					*wp++ = OSUBST;
377
2538935
					*wp++ = '{'; /*}*/
378
2538935
					wp = get_brace_var(&ws, wp);
379

10155740
					c = getsc();
380
					/* allow :# and :% (ksh88 compat) */
381
2538935
					if (c == ':') {
382
178775
						*wp++ = CHAR, *wp++ = c;
383

715100
						c = getsc();
384
178775
					}
385
					/* If this is a trim operation,
386
					 * treat (,|,) specially in STBRACE.
387
					 */
388
5077870
					if (c == '#' || c == '%') {
389
2538935
						ungetsc(c);
390
15870
						PUSH_STATE(STBRACE);
391
7935
					} else {
392
						ungetsc(c);
393
5062000
						if (state == SDQUOTE ||
394
2531000
						    state == SBRACEQ)
395
2567774
							PUSH_STATE(SBRACEQ);
396
						else
397
2494226
							PUSH_STATE(SBRACE);
398
					}
399
12574803
				} else if (ctype(c, C_ALPHA)) {
400
10942395
					*wp++ = OSUBST;
401
10942395
					*wp++ = 'X';
402
10942395
					do {
403
73890142
						Xcheck(ws, wp);
404
73685645
						*wp++ = c;
405

294405857
						c = getsc();
406

85005146
					} while (ctype(c, C_ALPHA) || digit(c));
407
10942395
					*wp++ = '\0';
408
10942395
					*wp++ = CSUBST;
409
10942395
					*wp++ = 'X';
410
10942395
					ungetsc(c);
411

13978943
				} else if (ctype(c, C_VAR1) || digit(c)) {
412
1622082
					Xcheck(ws, wp);
413
1622082
					*wp++ = OSUBST;
414
1622082
					*wp++ = 'X';
415
1622082
					*wp++ = c;
416
1622082
					*wp++ = '\0';
417
1622082
					*wp++ = CSUBST;
418
1622082
					*wp++ = 'X';
419
1622082
				} else {
420
10326
					*wp++ = CHAR, *wp++ = '$';
421
10326
					ungetsc(c);
422
				}
423
				break;
424
			case '`':
425
647240
				PUSH_STATE(SBQUOTE);
426
323620
				*wp++ = COMSUB;
427
				/* Need to know if we are inside double quotes
428
				 * since sh/at&t-ksh translate the \" to " in
429
				 * "`..\"..`".
430
				 */
431
323620
				statep->ls_sbquote.indquotes = 0;
432
				Lex_state *s = statep;
433
323620
				Lex_state *base = state_info.base;
434
323620
				while (1) {
435
1864156
					for (; s != base; s--) {
436
647490
						if (s->ls_state == SDQUOTE) {
437
39032
							statep->ls_sbquote.indquotes = 1;
438
39032
							break;
439
						}
440
					}
441
323620
					if (s != base)
442
						break;
443
284588
					if (!(s = s->ls_info.base))
444
						break;
445
					base = s-- - STATE_BSIZE;
446
				}
447
				break;
448
			default:
449
316128434
				*wp++ = CHAR, *wp++ = c;
450
316128434
			}
451
			break;
452
453
		case SSQUOTE:
454
48392783
			if (c == '\'') {
455
3017794
				POP_STATE();
456
1508897
				if (state == SBRACEQ) {
457
					*wp++ = CHAR, *wp++ = c;
458
					break;
459
				}
460
1508897
				*wp++ = CQUOTE;
461
1508897
				ignore_backslash_newline--;
462
1508897
			} else
463
46883886
				*wp++ = QCHAR, *wp++ = c;
464
			break;
465
466
		case SDQUOTE:
467
82107280
			if (c == '"') {
468
16899414
				POP_STATE();
469
8449707
				*wp++ = CQUOTE;
470
			} else
471
				goto Subst;
472
8449707
			break;
473
474
		case SCSPAREN: /* $( .. ) */
475
			/* todo: deal with $(...) quoting properly
476
			 * kludge to partly fake quoting inside $(..): doesn't
477
			 * really work because nested $(..) or ${..} inside
478
			 * double quotes aren't dealt with.
479
			 */
480

1032681
			switch (statep->ls_scsparen.csstate) {
481
			case 0: /* normal */
482

788856
				switch (c) {
483
				case '(':
484
					statep->ls_scsparen.nparen++;
485
					break;
486
				case ')':
487
31295
					statep->ls_scsparen.nparen--;
488
31295
					break;
489
				case '\\':
490
8204
					statep->ls_scsparen.csstate = 1;
491
8204
					break;
492
				case '"':
493
23874
					statep->ls_scsparen.csstate = 2;
494
23874
					break;
495
				case '\'':
496
1942
					statep->ls_scsparen.csstate = 4;
497
1942
					ignore_backslash_newline++;
498
1942
					break;
499
				}
500
				break;
501
502
			case 1: /* backslash in normal mode */
503
			case 3: /* backslash in double quotes */
504
8658
				--statep->ls_scsparen.csstate;
505
8658
				break;
506
507
			case 2: /* double quotes */
508
127858
				if (c == '"')
509
23874
					statep->ls_scsparen.csstate = 0;
510
103984
				else if (c == '\\')
511
454
					statep->ls_scsparen.csstate = 3;
512
				break;
513
514
			case 4: /* single quotes */
515
18054
				if (c == '\'') {
516
1942
					statep->ls_scsparen.csstate = 0;
517
1942
					ignore_backslash_newline--;
518
1942
				}
519
				break;
520
			}
521
878111
			if (statep->ls_scsparen.nparen == 0) {
522
62590
				POP_STATE();
523
31295
				*wp++ = 0; /* end of COMSUB */
524
31295
			} else
525
846816
				*wp++ = c;
526
			break;
527
528
		case SASPAREN: /* $(( .. )) */
529
			/* todo: deal with $((...); (...)) properly */
530
			/* XXX should nest using existing state machine
531
			 * (embed "..", $(...), etc.) */
532
138562
			if (c == '(')
533
100
				statep->ls_sasparen.nparen++;
534
138462
			else if (c == ')') {
535
14456
				statep->ls_sasparen.nparen--;
536
14456
				if (statep->ls_sasparen.nparen == 1) {
537
					/*(*/
538

57424
					if ((c2 = getsc()) == ')') {
539
28712
						POP_STATE();
540
14356
						*wp++ = 0; /* end of EXPRSUB */
541
14356
						break;
542
					} else {
543
						char *s;
544
545
						ungetsc(c2);
546
						/* mismatched parenthesis -
547
						 * assume we were really
548
						 * parsing a $(..) expression
549
						 */
550
						s = Xrestpos(ws, wp,
551
						    statep->ls_sasparen.start);
552
						memmove(s + 1, s, wp - s);
553
						*s++ = COMSUB;
554
						*s = '('; /*)*/
555
						wp++;
556
						statep->ls_scsparen.nparen = 1;
557
						statep->ls_scsparen.csstate = 0;
558
						state = statep->ls_state =
559
						    SCSPAREN;
560
					}
561
				}
562
			}
563
124206
			*wp++ = c;
564
124206
			break;
565
566
		case SBRACEQ:
567
			/*{*/
568
3789587
			if (c == '}') {
569
2567774
				POP_STATE();
570
1283887
				*wp++ = CSUBST;
571
1283887
				*wp++ = /*{*/ '}';
572
			} else
573
				goto Sbase2;
574
1283887
			break;
575
576
		case SBRACE:
577
			/*{*/
578
5455190
			if (c == '}') {
579
2494226
				POP_STATE();
580
1247113
				*wp++ = CSUBST;
581
1247113
				*wp++ = /*{*/ '}';
582
			} else
583
				goto Sbase1;
584
1247113
			break;
585
586
		case STBRACE:
587
			/* Same as SBRACE, except (,|,) treated specially */
588
			/*{*/
589
32219
			if (c == '}') {
590
15870
				POP_STATE();
591
7935
				*wp++ = CSUBST;
592
7935
				*wp++ = /*{*/ '}';
593
32219
			} else if (c == '|') {
594
100
				*wp++ = SPAT;
595
24284
			} else if (c == '(') {
596
25
				*wp++ = OPAT;
597
25
				*wp++ = ' ';	/* simile for @ */
598
50
				PUSH_STATE(SPATTERN);
599
			} else
600
				goto Sbase1;
601
			break;
602
603
		case SBQUOTE:
604
14345336
			if (c == '`') {
605
323620
				*wp++ = 0;
606
647240
				POP_STATE();
607
14345336
			} else if (c == '\\') {
608


1172674
				switch (c = getsc()) {
609
				case '\\':
610
				case '$': case '`':
611
34390
					*wp++ = c;
612
34390
					break;
613
				case '"':
614
6390
					if (statep->ls_sbquote.indquotes) {
615
6052
						*wp++ = c;
616
6052
						break;
617
					}
618
					/* FALLTHROUGH */
619
				default:
620
252642
					if (c) { /* trailing \ is lost */
621
252642
						*wp++ = '\\';
622
252642
						*wp++ = c;
623
252642
					}
624
					break;
625
				}
626
			} else
627
13728632
				*wp++ = c;
628
			break;
629
630
		case SWORD:	/* ONEWORD */
631
			goto Subst;
632
633
		case SLETPAREN:	/* LETEXPR: (( ... )) */
634
			/*(*/
635
250
			if (c == ')') {
636
50
				if (statep->ls_sletparen.nparen > 0)
637
				    --statep->ls_sletparen.nparen;
638
				/*(*/
639

200
				else if ((c2 = getsc()) == ')') {
640
					c = 0;
641
50
					*wp++ = CQUOTE;
642
50
					goto Done;
643
				} else
644
					ungetsc(c2);
645
200
			} else if (c == '(')
646
				/* parenthesis inside quotes and backslashes
647
				 * are lost, but at&t ksh doesn't count them
648
				 * either
649
				 */
650
				++statep->ls_sletparen.nparen;
651
			goto Sbase2;
652
653
		case SHEREDELIM:	/* <<,<<- delimiter */
654
			/* XXX chuck this state (and the next) - use
655
			 * the existing states ($ and \`..` should be
656
			 * stripped of their specialness after the
657
			 * fact).
658
			 */
659
			/* here delimiters need a special case since
660
			 * $ and `..` are not to be treated specially
661
			 */
662
1353817
			if (c == '\\') {
663

103268
				c = getsc();
664
25817
				if (c) { /* trailing \ is lost */
665
25817
					*wp++ = QCHAR;
666
25817
					*wp++ = c;
667
25817
				}
668
1328000
			} else if (c == '\'') {
669
448
				PUSH_STATE(SSQUOTE);
670
224
				*wp++ = OQUOTE;
671
224
				ignore_backslash_newline++;
672
1328000
			} else if (c == '"') {
673
100
				state = statep->ls_state = SHEREDQUOTE;
674
100
				*wp++ = OQUOTE;
675
100
			} else {
676
1327676
				*wp++ = CHAR;
677
1327676
				*wp++ = c;
678
			}
679
			break;
680
681
		case SHEREDQUOTE:	/* " in <<,<<- delimiter */
682
400
			if (c == '"') {
683
100
				*wp++ = CQUOTE;
684
100
				state = statep->ls_state = SHEREDELIM;
685
100
			} else {
686
300
				if (c == '\\') {
687


100
					switch (c = getsc()) {
688
					case '\\': case '"':
689
					case '$': case '`':
690
						break;
691
					default:
692
						if (c) { /* trailing \ lost */
693
							*wp++ = CHAR;
694
							*wp++ = '\\';
695
						}
696
						break;
697
					}
698
				}
699
300
				*wp++ = CHAR;
700
300
				*wp++ = c;
701
			}
702
			break;
703
704
		case SPATTERN:	/* in *(...|...) pattern (*+?@!) */
705
148702
			if ( /*(*/ c == ')') {
706
8839
				*wp++ = CPAT;
707
17678
				POP_STATE();
708
148702
			} else if (c == '|') {
709
12736
				*wp++ = SPAT;
710
139863
			} else if (c == '(') {
711
100
				*wp++ = OPAT;
712
100
				*wp++ = ' ';	/* simile for @ */
713
200
				PUSH_STATE(SPATTERN);
714
			} else
715
				goto Sbase1;
716
			break;
717
		}
718
	}
719
Done:
720
87118807
	Xcheck(ws, wp);
721
86972919
	if (statep != &states[1])
722
		/* XXX figure out what is missing */
723
		yyerror("no closing quote\n");
724
725
	/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
726
86972919
	if (state == SHEREDELIM)
727
233676
		state = SBASE;
728
729
86972919
	dp = Xstring(ws, wp);
730

87609906
	if ((c == '<' || c == '>') && state == SBASE &&
731
2847787
	    ((c2 = Xlength(ws, wp)) == 0 ||
732

1911026
	    (c2 == 2 && dp[0] == CHAR && digit(dp[1])))) {
733
2847704
		struct ioword *iop = alloc(sizeof(*iop), ATEMP);
734
735
2847704
		if (c2 == 2)
736
636969
			iop->unit = dp[1] - '0';
737
		else
738
2210735
			iop->unit = c == '>'; /* 0 for <, 1 for > */
739
740

11390816
		c2 = getsc();
741
		/* <<, >>, <> are ok, >< is not */
742

5262054
		if (c == c2 || (c == '<' && c2 == '>')) {
743
1300062
			iop->flag = c == c2 ?
744
433354
			    (c == '>' ? IOCAT : IOHERE) : IORDWR;
745
433354
			if (iop->flag == IOHERE) {
746

934704
				if ((c2 = getsc()) == '-')
747
450
					iop->flag |= IOSKIP;
748
				else
749
233226
					ungetsc(c2);
750
			}
751
2414350
		} else if (c2 == '&')
752
1781367
			iop->flag = IODUP | (c == '<' ? IORDUP : 0);
753
		else {
754
632983
			iop->flag = c == '>' ? IOWRITE : IOREAD;
755
632983
			if (c == '>' && c2 == '|')
756
				iop->flag |= IOCLOB;
757
			else
758
632983
				ungetsc(c2);
759
		}
760
761
2847704
		iop->name = NULL;
762
2847704
		iop->delim = NULL;
763
2847704
		iop->heredoc = NULL;
764
2847704
		Xfree(ws, wp);	/* free word */
765
2847704
		yylval.iop = iop;
766
		return REDIR;
767
	}
768
769
84125215
	if (wp == dp && state == SBASE) {
770
31095429
		Xfree(ws, wp);	/* free word */
771
		/* no word, process LEX1 character */
772

31095429
		switch (c) {
773
		default:
774
4191224
			return c;
775
776
		case '|':
777
		case '&':
778
		case ';':
779

35267374
			if ((c2 = getsc()) == c)
780
3209096
				c = (c == ';') ? BREAK :
781
1277966
				    (c == '|') ? LOGOR :
782
531832
				    (c == '&') ? LOGAND :
783
				    YYERRCODE;
784
7212398
			else if (c == '|' && c2 == '&')
785
				c = COPROC;
786
			else
787
7212398
				ungetsc(c2);
788
8816946
			return c;
789
790
		case '\n':
791
16275837
			gethere();
792
16275837
			if (cf & CONTIN)
793
				goto Again;
794
14657626
			return c;
795
796
		case '(':  /*)*/
797
474712
			if (!Flag(FSH)) {
798

84504
				if ((c2 = getsc()) == '(') /*)*/
799
					/* XXX need to handle ((...); (...)) */
800
50
					c = MDPAREN;
801
				else
802
21076
					ungetsc(c2);
803
			}
804
474712
			return c;
805
		  /*(*/
806
		case ')':
807
1336685
			return c;
808
		}
809
	}
810
811
53029786
	*wp++ = EOS;		/* terminate word */
812
53029786
	yylval.cp = Xclose(ws, wp);
813
53029786
	if (state == SWORD || state == SLETPAREN)	/* ONEWORD? */
814
701803
		return LWORD;
815
52327983
	ungetsc(c);		/* unget terminator */
816
817
	/* copy word to unprefixed string ident */
818

792750231
	for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
819
211922382
		*dp++ = *sp++;
820
	/* Make sure the ident array stays '\0' padded */
821
52327983
	memset(dp, 0, (ident+IDENT) - dp + 1);
822
52327983
	if (c != EOS)
823
15908105
		*ident = '\0';	/* word is not unquoted */
824
825

88747861
	if (*ident != '\0' && (cf&(KEYWORD|ALIAS))) {
826
		struct tbl *p;
827
20440365
		int h = hash(ident);
828
829
		/* { */
830

40700413
		if ((cf & KEYWORD) && (p = ktsearch(&keywords, ident, h)) &&
831

6427711
		    (!(cf & ESACONLY) || p->val.i == ESAC || p->val.i == '}')) {
832
6162065
			afree(yylval.cp, ATEMP);
833
6162065
			return p->val.i;
834
		}
835

27852159
		if ((cf & ALIAS) && (p = ktsearch(&aliases, ident, h)) &&
836
15344
		    (p->flag & ISSET)) {
837
			Source *s;
838
839
31188
			for (s = source; s->type == SALIAS; s = s->next)
840
546
				if (s->u.tblp == p)
841
296
					return LWORD;
842
			/* push alias expansion */
843
15048
			s = pushs(SALIAS, source->areap);
844
15048
			s->start = s->str = p->val.s;
845
15048
			s->u.tblp = p;
846
15048
			s->next = source;
847
15048
			source = s;
848
15048
			afree(yylval.cp, ATEMP);
849
15048
			goto Again;
850
		}
851
14262956
	}
852
853
46150574
	return LWORD;
854
85339635
}
855
856
static void
857
gethere(void)
858
{
859
	struct ioword **p;
860
861
49294913
	for (p = heres; p < herep; p++)
862
233676
		readhere(*p);
863
16275837
	herep = heres;
864
16275837
}
865
866
/*
867
 * read "<<word" text into temp file
868
 */
869
870
static void
871
readhere(struct ioword *iop)
872
{
873
	int c;
874
467352
	char *volatile eof;
875
	char *eofp;
876
	int skiptabs;
877
233676
	XString xs;
878
	char *xp;
879
	int xpos;
880
881
233676
	eof = evalstr(iop->delim, 0);
882
883
233676
	if (!(iop->flag & IOEVAL))
884
26141
		ignore_backslash_newline++;
885
886
233676
	Xinit(xs, xp, 256, ATEMP);
887
888
3046657
	for (;;) {
889
3046657
		eofp = eof;
890
3046657
		skiptabs = iop->flag & IOSKIP;
891
3046657
		xpos = Xsavepos(xs, xp);
892

18969156
		while ((c = getsc()) != 0) {
893
4403066
			if (skiptabs) {
894
3075
				if (c == '\t')
895
					continue;
896
				skiptabs = 0;
897
1250
			}
898
4401241
			if (c != *eofp)
899
				break;
900
1357389
			Xcheck(xs, xp);
901
1354643
			Xput(xs, xp, c);
902
1354643
			eofp++;
903
		}
904
		/* Allow EOF here so commands with out trailing newlines
905
		 * will work (eg, ksh -c '...', $(...), etc).
906
		 */
907

3280308
		if (*eofp == '\0' && (c == 0 || c == '\n')) {
908
233651
			xp = Xrestpos(xs, xp, xpos);
909
			break;
910
		}
911
2813006
		ungetsc(c);
912

359143540
		while ((c = getsc()) != '\n') {
913
69015737
			if (c == 0)
914
				yyerror("here document `%s' unclosed\n", eof);
915
69125832
			Xcheck(xs, xp);
916
69015712
			Xput(xs, xp, c);
917
		}
918
2814168
		Xcheck(xs, xp);
919
2812981
		Xput(xs, xp, c);
920
	}
921
233651
	Xput(xs, xp, '\0');
922
233651
	iop->heredoc = Xclose(xs, xp);
923
924
233651
	if (!(iop->flag & IOEVAL))
925
26141
		ignore_backslash_newline--;
926
233651
}
927
928
void
929
yyerror(const char *fmt, ...)
930
{
931
102
	va_list va;
932
933
	/* pop aliases and re-reads */
934

204
	while (source->type == SALIAS || source->type == SREREAD)
935
		source = source->next;
936
	source->str = null;	/* zap pending input */
937
938
	error_prefix(true);
939
	va_start(va, fmt);
940
	shf_vfprintf(shl_out, fmt, va);
941
	va_end(va);
942
	errorf(NULL);
943
}
944
945
/*
946
 * input for yylex with alias expansion
947
 */
948
949
Source *
950
pushs(int type, Area *areap)
951
{
952
	Source *s;
953
954
9631294
	s = alloc(sizeof(Source), areap);
955
4815647
	s->type = type;
956
4815647
	s->str = null;
957
4815647
	s->start = NULL;
958
4815647
	s->line = 0;
959
4815647
	s->cmd_offset = 0;
960
4815647
	s->errline = 0;
961
4815647
	s->file = NULL;
962
4815647
	s->flags = 0;
963
4815647
	s->next = NULL;
964
4815647
	s->areap = areap;
965
4815647
	if (type == SFILE || type == SSTDIN) {
966
		char *dummy;
967
49295
		Xinit(s->xs, dummy, 256, s->areap);
968
49295
	} else
969
4766352
		memset(&s->xs, 0, sizeof(s->xs));
970
4815647
	return s;
971
}
972
973
static int
974
getsc__(void)
975
{
976
69563842
	Source *s = source;
977
	int c;
978
979
91989547
	while ((c = *s->str++) == 0) {
980
57176855
		s->str = NULL;		/* return 0 for EOF by default */
981


57176855
		switch (s->type) {
982
		case SEOF:
983
8468681
			s->str = null;
984
8468681
			return 0;
985
986
		case SSTDIN:
987
		case SFILE:
988
20076082
			getsc_line(s);
989
20076082
			break;
990
991
		case SWSTR:
992
			break;
993
994
		case SSTRING:
995
			break;
996
997
		case SWORDS:
998
1168257
			s->start = s->str = *s->u.strv++;
999
1168257
			s->type = SWORDSEP;
1000
1168257
			break;
1001
1002
		case SWORDSEP:
1003
1167784
			if (*s->u.strv == NULL) {
1004
893266
				s->start = s->str = "\n";
1005
				s->type = SEOF;
1006
893266
			} else {
1007
274518
				s->start = s->str = " ";
1008
				s->type = SWORDS;
1009
			}
1010
1167784
			break;
1011
1012
		case SALIAS:
1013
29175
			if (s->flags & SF_ALIASEND) {
1014
				/* pass on an unused SF_ALIAS flag */
1015
14127
				source = s->next;
1016
14127
				source->flags |= s->flags & SF_ALIAS;
1017
14127
				s = source;
1018

44223
			} else if (*s->u.tblp->val.s &&
1019
15048
			    isspace((unsigned char)strchr(s->u.tblp->val.s, 0)[-1])) {
1020
546
				source = s = s->next;	/* pop source stack */
1021
				/* Note that this alias ended with a space,
1022
				 * enabling alias expansion on the following
1023
				 * word.
1024
				 */
1025
546
				s->flags |= SF_ALIAS;
1026
546
			} else {
1027
				/* At this point, we need to keep the current
1028
				 * alias in the source list so recursive
1029
				 * aliases can be detected and we also need
1030
				 * to return the next character.  Do this
1031
				 * by temporarily popping the alias to get
1032
				 * the next character and then put it back
1033
				 * in the source list with the SF_ALIASEND
1034
				 * flag set.
1035
				 */
1036
14502
				source = s->next;	/* pop source stack */
1037
14502
				source->flags |= s->flags & SF_ALIAS;
1038
14502
				c = getsc__();
1039
14502
				if (c) {
1040
14452
					s->flags |= SF_ALIASEND;
1041
14452
					s->ugbuf[0] = c; s->ugbuf[1] = '\0';
1042
14452
					s->start = s->str = s->ugbuf;
1043
14452
					s->next = source;
1044
14452
					source = s;
1045
				} else {
1046
50
					s = source;
1047
					/* avoid reading eof twice */
1048
50
					s->str = NULL;
1049
50
					break;
1050
				}
1051
			}
1052
			continue;
1053
1054
		case SREREAD:
1055
			if (s->start != s->ugbuf) /* yuck */
1056
				afree(s->u.freeme, ATEMP);
1057
			source = s = s->next;
1058
			continue;
1059
		}
1060
26266876
		if (s->str == NULL) {
1061
3870296
			s->type = SEOF;
1062
3870296
			s->start = s->str = null;
1063
3870296
			return '\0';
1064
		}
1065
22396580
		if (s->flags & SF_ECHO) {
1066
25
			shf_puts(s->str, shl_out);
1067
25
			shf_flush(shl_out);
1068
25
		}
1069
	}
1070
22440082
	return c;
1071
34779059
}
1072
1073
static void
1074
getsc_line(Source *s)
1075
{
1076
40152164
	char *xp = Xstring(s->xs, xp);
1077
40162024
	int interactive = Flag(FTALKING) && s->type == SSTDIN;
1078
40159752
	int have_tty = interactive && (s->flags & SF_TTY);
1079
1080
	/* Done here to ensure nothing odd happens when a timeout occurs */
1081
20125375
	XcheckN(s->xs, xp, LINE);
1082
20076082
	*xp = '\0';
1083
20076082
	s->start = s->str = xp;
1084
1085
20076082
	if (have_tty && ksh_tmout) {
1086
		ksh_tmout_state = TMOUT_READING;
1087
		alarm(ksh_tmout);
1088
	}
1089
#ifdef EDIT
1090

20076082
	if (have_tty && (0
1091
# ifdef VI
1092
3588
	    || Flag(FVI)
1093
# endif /* VI */
1094
# ifdef EMACS
1095

5401
	    || Flag(FEMACS) || Flag(FGMACS)
1096
# endif /* EMACS */
1097
	    )) {
1098
		int nread;
1099
1100
3588
		nread = x_read(xp, LINE);
1101
3588
		if (nread < 0)	/* read error */
1102
			nread = 0;
1103
3588
		xp[nread] = '\0';
1104
		xp += nread;
1105
3588
	}
1106
	else
1107
#endif /* EDIT */
1108
	{
1109
20072494
		if (interactive) {
1110
4000
			pprompt(prompt, 0);
1111
4000
		} else
1112
20068494
			s->line++;
1113
1114
		while (1) {
1115
20072594
			char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);
1116
1117

20085034
			if (!p && shf_error(s->u.shf) &&
1118
			    s->u.shf->errno_ == EINTR) {
1119
				shf_clearerr(s->u.shf);
1120
				if (trap)
1121
					runtraps(0);
1122
				continue;
1123
			}
1124

40132748
			if (!p || (xp = p, xp[-1] == '\n'))
1125
20072494
				break;
1126
			/* double buffer size */
1127
100
			xp++; /* move past null so doubling works... */
1128
125
			XcheckN(s->xs, xp, Xlength(s->xs, xp));
1129
100
			xp--; /* ...and move back again */
1130
100
		}
1131
		/* flush any unwanted input so other programs/builtins
1132
		 * can read it.  Not very optimal, but less error prone
1133
		 * than flushing else where, dealing with redirections,
1134
		 * etc..
1135
		 * todo: reduce size of shf buffer (~128?) if SSTDIN
1136
		 */
1137
20072494
		if (s->type == SSTDIN)
1138
67842
			shf_flush(s->u.shf);
1139
	}
1140
	/* XXX: temporary kludge to restore source after a
1141
	 * trap may have been executed.
1142
	 */
1143
20073220
	source = s;
1144
20073220
	if (have_tty && ksh_tmout) {
1145
		ksh_tmout_state = TMOUT_EXECUTING;
1146
		alarm(0);
1147
	}
1148
20073220
	s->start = s->str = Xstring(s->xs, xp);
1149
20073220
	strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
1150
	/* Note: if input is all nulls, this is not eof */
1151
20073220
	if (Xlength(s->xs, xp) == 0) { /* EOF */
1152
12381
		if (s->type == SFILE)
1153
7251
			shf_fdclose(s->u.shf);
1154
12381
		s->str = NULL;
1155
20073220
	} else if (interactive) {
1156
#ifdef HISTORY
1157
		char *p = Xstring(s->xs, xp);
1158
3960
		if (cur_prompt == PS1)
1159

8348
			while (*p && ctype(*p, C_IFS) && ctype(*p, C_IFSWS))
1160
157
				p++;
1161
3960
		if (*p) {
1162
3860
			s->line++;
1163
3860
			histsave(s->line, s->str, 1);
1164
3860
		}
1165
#endif /* HISTORY */
1166
3960
	}
1167
20073220
	if (interactive)
1168
4726
		set_prompt(PS2, NULL);
1169
20073220
}
1170
1171
static char *
1172
special_prompt_expand(char *str)
1173
{
1174
	char *p = str;
1175
1176
22614
	while ((p = strstr(p, "\\$")) != NULL) {
1177
		*(p+1) = 'p';
1178
	}
1179
7538
	return str;
1180
}
1181
1182
void
1183
set_prompt(int to, Source *s)
1184
{
1185
	char *ps1;
1186
	Area *saved_atemp;
1187
1188
36792
	cur_prompt = to;
1189
1190
24528
	switch (to) {
1191
	case PS1: /* command */
1192
7538
		ps1 = str_save(str_val(global("PS1")), ATEMP);
1193
7538
		saved_atemp = ATEMP;	/* ps1 is freed by substitute() */
1194
7538
		newenv(E_ERRH);
1195
7538
		if (sigsetjmp(genv->jbuf, 0)) {
1196
			prompt = safe_prompt;
1197
			/* Don't print an error - assume it has already
1198
			 * been printed.  Reason is we may have forked
1199
			 * to run a command and the child may be
1200
			 * unwinding its stack through this code as it
1201
			 * exits.
1202
			 */
1203
		} else {
1204
			/* expand \$ before other substitutions are done */
1205
7538
			char *tmp = special_prompt_expand(ps1);
1206
7538
			prompt = str_save(substitute(tmp, 0), saved_atemp);
1207
		}
1208
7538
		quitenv(NULL);
1209
7538
		break;
1210
	case PS2: /* command continuation */
1211
4726
		prompt = str_val(global("PS2"));
1212
4726
		break;
1213
	}
1214
12264
}
1215
1216
static int
1217
dopprompt(const char *sp, int ntruncate, const char **spp, int doprint)
1218
{
1219
27566
	char strbuf[1024], tmpbuf[1024], *p, *str, nbuf[32], delimiter = '\0';
1220
	int len, c, n, totlen = 0, indelimit = 0, counting = 1, delimitthis;
1221
	const char *cp = sp;
1222
	struct tm *tm;
1223
13783
	time_t t;
1224
1225

27391
	if (*cp && cp[1] == '\r') {
1226
		delimiter = *cp;
1227
		cp += 2;
1228
	}
1229
1230
43374
	while (*cp != 0) {
1231
		delimitthis = 0;
1232

29591
		if (indelimit && *cp != delimiter)
1233
			;
1234

59182
		else if (*cp == '\n' || *cp == '\r') {
1235
			totlen = 0;
1236
			sp = cp + 1;
1237
29591
		} else if (*cp == '\t') {
1238
			if (counting)
1239
				totlen = (totlen | 7) + 1;
1240
29591
		} else if (*cp == delimiter) {
1241
			indelimit = !indelimit;
1242
			delimitthis = 1;
1243
		}
1244
1245
29591
		if (*cp == '\\') {
1246
125
			cp++;
1247
125
			if (!*cp)
1248
				break;
1249
125
			if (Flag(FSH))
1250
				snprintf(strbuf, sizeof strbuf, "\\%c", *cp);
1251








125
			else switch (*cp) {
1252
			case 'a':	/* '\' 'a' bell */
1253
				strbuf[0] = '\007';
1254
				strbuf[1] = '\0';
1255
				break;
1256
			case 'd':	/* '\' 'd' Dow Mon DD */
1257
				time(&t);
1258
				tm = localtime(&t);
1259
				strftime(strbuf, sizeof strbuf, "%a %b %d", tm);
1260
				break;
1261
			case 'D': /* '\' 'D' '{' strftime format '}' */
1262
				p = strchr(cp + 2, '}');
1263
				if (cp[1] != '{' || p == NULL) {
1264
					snprintf(strbuf, sizeof strbuf,
1265
					    "\\%c", *cp);
1266
					break;
1267
				}
1268
				strlcpy(tmpbuf, cp + 2, sizeof tmpbuf);
1269
				p = strchr(tmpbuf, '}');
1270
				if (p)
1271
					*p = '\0';
1272
				time(&t);
1273
				tm = localtime(&t);
1274
				strftime(strbuf, sizeof strbuf, tmpbuf, tm);
1275
				cp = strchr(cp + 2, '}');
1276
				break;
1277
			case 'e':	/* '\' 'e' escape */
1278
				strbuf[0] = '\033';
1279
				strbuf[1] = '\0';
1280
				break;
1281
			case 'h':	/* '\' 'h' shortened hostname */
1282
				gethostname(strbuf, sizeof strbuf);
1283
				p = strchr(strbuf, '.');
1284
				if (p)
1285
					*p = '\0';
1286
				break;
1287
			case 'H':	/* '\' 'H' full hostname */
1288
				gethostname(strbuf, sizeof strbuf);
1289
				break;
1290
			case 'j':	/* '\' 'j' number of jobs */
1291
				snprintf(strbuf, sizeof strbuf, "%d",
1292
				    j_njobs());
1293
				break;
1294
			case 'l':	/* '\' 'l' basename of tty */
1295
				p = ttyname(0);
1296
				if (p)
1297
					p = basename(p);
1298
				if (p)
1299
					strlcpy(strbuf, p, sizeof strbuf);
1300
				break;
1301
			case 'n':	/* '\' 'n' newline */
1302
				strbuf[0] = '\n';
1303
				strbuf[1] = '\0';
1304
				totlen = 0;	/* reset for prompt re-print */
1305
				sp = cp + 1;
1306
				break;
1307
			case 'p':	/* '\' '$' $ or # */
1308
				strbuf[0] = ksheuid ? '$' : '#';
1309
				strbuf[1] = '\0';
1310
				break;
1311
			case 'r':	/* '\' 'r' return */
1312
				strbuf[0] = '\r';
1313
				strbuf[1] = '\0';
1314
				totlen = 0;	/* reset for prompt re-print */
1315
				sp = cp + 1;
1316
				break;
1317
			case 's':	/* '\' 's' basename $0 */
1318
				strlcpy(strbuf, kshname, sizeof strbuf);
1319
				break;
1320
			case 't':	/* '\' 't' 24 hour HH:MM:SS */
1321
				time(&t);
1322
				tm = localtime(&t);
1323
				strftime(strbuf, sizeof strbuf, "%T", tm);
1324
				break;
1325
			case 'T':	/* '\' 'T' 12 hour HH:MM:SS */
1326
				time(&t);
1327
				tm = localtime(&t);
1328
				strftime(strbuf, sizeof strbuf, "%l:%M:%S", tm);
1329
				break;
1330
			case '@':	/* '\' '@' 12 hour am/pm format */
1331
				time(&t);
1332
				tm = localtime(&t);
1333
				strftime(strbuf, sizeof strbuf, "%r", tm);
1334
				break;
1335
			case 'A':	/* '\' 'A' 24 hour HH:MM */
1336
				time(&t);
1337
				tm = localtime(&t);
1338
				strftime(strbuf, sizeof strbuf, "%R", tm);
1339
				break;
1340
			case 'u':	/* '\' 'u' username */
1341
				strlcpy(strbuf, username, sizeof strbuf);
1342
				break;
1343
			case 'v':	/* '\' 'v' version (short) */
1344
				p = strchr(ksh_version, ' ');
1345
				if (p)
1346
					p = strchr(p + 1, ' ');
1347
				if (p) {
1348
					p++;
1349
					strlcpy(strbuf, p, sizeof strbuf);
1350
					p = strchr(strbuf, ' ');
1351
					if (p)
1352
						*p = '\0';
1353
				}
1354
				break;
1355
			case 'V':	/* '\' 'V' version (long) */
1356
				strlcpy(strbuf, ksh_version, sizeof strbuf);
1357
				break;
1358
			case 'w':	/* '\' 'w' cwd */
1359
				p = str_val(global("PWD"));
1360
				n = strlen(str_val(global("HOME")));
1361
				if (strcmp(p, "/") == 0) {
1362
					strlcpy(strbuf, p, sizeof strbuf);
1363
				} else if (strcmp(p, str_val(global("HOME"))) == 0) {
1364
					strbuf[0] = '~';
1365
					strbuf[1] = '\0';
1366
				} else if (strncmp(p, str_val(global("HOME")), n)
1367
				    == 0 && p[n] == '/') {
1368
					snprintf(strbuf, sizeof strbuf, "~/%s",
1369
					    str_val(global("PWD")) + n + 1);
1370
				} else
1371
					strlcpy(strbuf, p, sizeof strbuf);
1372
				break;
1373
			case 'W':	/* '\' 'W' basename(cwd) */
1374
				p = str_val(global("PWD"));
1375
				if (strcmp(p, str_val(global("HOME"))) == 0) {
1376
					strbuf[0] = '~';
1377
					strbuf[1] = '\0';
1378
				} else
1379
					strlcpy(strbuf, basename(p), sizeof strbuf);
1380
				break;
1381
			case '!':	/* '\' '!' history line number */
1382
				snprintf(strbuf, sizeof strbuf, "%d",
1383
				    source->line + 1);
1384
				break;
1385
			case '#':	/* '\' '#' command line number */
1386
				snprintf(strbuf, sizeof strbuf, "%d",
1387
				    source->line - source->cmd_offset + 1);
1388
				break;
1389
			case '0':	/* '\' '#' '#' ' #' octal numeric handling */
1390
			case '1':
1391
			case '2':
1392
			case '3':
1393
			case '4':
1394
			case '5':
1395
			case '6':
1396
			case '7':
1397

375
				if ((cp[1] > '7' || cp[1] < '0') ||
1398
250
				    (cp[2] > '7' || cp[2] < '0')) {
1399
					snprintf(strbuf, sizeof strbuf,
1400
					    "\\%c", *cp);
1401
					break;
1402
				}
1403
250
				n = (cp[0] - '0') * 8 * 8 + (cp[1] - '0') * 8 +
1404
125
				    (cp[2] - '0');
1405
125
				snprintf(strbuf, sizeof strbuf, "%c", n);
1406
				cp += 2;
1407
125
				break;
1408
			case '\\':	/* '\' '\' */
1409
				strbuf[0] = '\\';
1410
				strbuf[1] = '\0';
1411
				break;
1412
			case '[': /* '\' '[' .... stop counting */
1413
				strbuf[0] = '\0';
1414
				counting = 0;
1415
				break;
1416
			case ']': /* '\' ']' restart counting */
1417
				strbuf[0] = '\0';
1418
				counting = 1;
1419
				break;
1420
1421
			default:
1422
				snprintf(strbuf, sizeof strbuf, "\\%c", *cp);
1423
				break;
1424
			}
1425
125
			cp++;
1426
1427
125
			str = strbuf;
1428
125
			len = strlen(str);
1429
125
			if (ntruncate) {
1430
				if (ntruncate >= len) {
1431
					ntruncate -= len;
1432
					continue;
1433
				}
1434
				str += ntruncate;
1435
				len -= ntruncate;
1436
				ntruncate = 0;
1437
			}
1438
125
			if (doprint)
1439
125
				shf_write(str, len, shl_out);
1440
125
			if (counting && !indelimit && !delimitthis)
1441
125
				totlen += len;
1442
			continue;
1443
29466
		} else if (*cp != '!')
1444
29466
			c = *cp++;
1445
		else if (*++cp == '!')
1446
			c = *cp++;
1447
		else {
1448
			char *p;
1449
1450
			shf_snprintf(p = nbuf, sizeof(nbuf), "%d",
1451
			    source->line + 1);
1452
			len = strlen(nbuf);
1453
			if (ntruncate) {
1454
				if (ntruncate >= len) {
1455
					ntruncate -= len;
1456
					continue;
1457
				}
1458
				p += ntruncate;
1459
				len -= ntruncate;
1460
				ntruncate = 0;
1461
			}
1462
			if (doprint)
1463
				shf_write(p, len, shl_out);
1464
			if (counting && !indelimit && !delimitthis)
1465
				totlen += len;
1466
			continue;
1467
		}
1468
29466
		if (counting && ntruncate)
1469
			--ntruncate;
1470
29466
		else if (doprint) {
1471
34166
			shf_putc(c, shl_out);
1472
		}
1473
29466
		if (counting && !indelimit && !delimitthis)
1474
29466
			totlen++;
1475
	}
1476
13783
	if (doprint)
1477
9004
		shf_flush(shl_out);
1478
13783
	if (spp)
1479
3588
		*spp = sp;
1480
13783
	return (totlen);
1481
13783
}
1482
1483
void
1484
pprompt(const char *cp, int ntruncate)
1485
{
1486
18008
	dopprompt(cp, ntruncate, NULL, 1);
1487
9004
}
1488
1489
int
1490
promptlen(const char *cp, const char **spp)
1491
{
1492
9558
	return dopprompt(cp, 0, spp, 0);
1493
}
1494
1495
/* Read the variable part of a ${...} expression (ie, up to but not including
1496
 * the :[-+?=#%] or close-brace.
1497
 */
1498
static char *
1499
get_brace_var(XString *wsp, char *wp)
1500
{
1501
	enum parse_state {
1502
			   PS_INITIAL, PS_SAW_HASH, PS_IDENT,
1503
			   PS_NUMBER, PS_VAR1, PS_END
1504
			 }
1505
		state;
1506
	char c;
1507
1508
	state = PS_INITIAL;
1509
20894225
	while (1) {
1510

94315240
		c = getsc();
1511
		/* State machine to figure out where the variable part ends. */
1512

39249370
		switch (state) {
1513
		case PS_INITIAL:
1514
2538935
			if (c == '#') {
1515
				state = PS_SAW_HASH;
1516
145
				break;
1517
			}
1518
			/* FALLTHROUGH */
1519
		case PS_SAW_HASH:
1520
2538935
			if (letter(c))
1521
2513658
				state = PS_IDENT;
1522
25277
			else if (digit(c))
1523
25225
				state = PS_NUMBER;
1524
52
			else if (ctype(c, C_VAR1))
1525
27
				state = PS_VAR1;
1526
			else
1527
				state = PS_END;
1528
			break;
1529
		case PS_IDENT:
1530

18980529
			if (!letnum(c)) {
1531
				state = PS_END;
1532
2513658
				if (c == '[') {
1533
1230
					char *tmp, *p;
1534
1535
1230
					if (!arraysub(&tmp))
1536
						yyerror("missing ]\n");
1537
1230
					*wp++ = c;
1538
11104
					for (p = tmp; *p; ) {
1539
4322
						Xcheck(*wsp, wp);
1540
4322
						*wp++ = *p++;
1541
					}
1542
1230
					afree(tmp, ATEMP);
1543

4920
					c = getsc(); /* the ] */
1544
1230
				}
1545
			}
1546
			break;
1547
		case PS_NUMBER:
1548
25225
			if (!digit(c))
1549
25225
				state = PS_END;
1550
			break;
1551
		case PS_VAR1:
1552
			state = PS_END;
1553
27
			break;
1554
		case PS_END: /* keep gcc happy */
1555
			break;
1556
		}
1557
18355290
		if (state == PS_END) {
1558
2538935
			*wp++ = '\0';	/* end of variable part */
1559
2538935
			ungetsc(c);
1560
			break;
1561
		}
1562
15824873
		Xcheck(*wsp, wp);
1563
15816355
		*wp++ = c;
1564
	}
1565
2538935
	return wp;
1566
}
1567
1568
/*
1569
 * Save an array subscript - returns true if matching bracket found, false
1570
 * if eof or newline was found.
1571
 * (Returned string double null terminated)
1572
 */
1573
static int
1574
arraysub(char **strp)
1575
{
1576
4106
	XString ws;
1577
	char	*wp;
1578
	char	c;
1579
	int	depth = 1;	/* we are just past the initial [ */
1580
1581
2053
	Xinit(ws, wp, 32, ATEMP);
1582
1583
2053
	do {
1584

41172
		c = getsc();
1585
10293
		Xcheck(ws, wp);
1586
10293
		*wp++ = c;
1587
10293
		if (c == '[')
1588
420
			depth++;
1589
9873
		else if (c == ']')
1590
2473
			depth--;
1591

26773
	} while (depth > 0 && c && c != '\n');
1592
1593
2053
	*wp++ = '\0';
1594
2053
	*strp = Xclose(ws, wp);
1595
1596
4106
	return depth == 0 ? 1 : 0;
1597
2053
}
1598
1599
/* Unget a char: handles case when we are already at the start of the buffer */
1600
static const char *
1601
ungetsc(int c)
1602
{
1603
346913404
	if (backslash_skip)
1604
552179
		backslash_skip--;
1605
	/* Don't unget eof... */
1606
173456702
	if (source->str == null && c == '\0')
1607
7445791
		return source->str;
1608
166010911
	if (source->str > source->start)
1609
166010911
		source->str--;
1610
	else {
1611
		Source *s;
1612
1613
		s = pushs(SREREAD, source->areap);
1614
		s->ugbuf[0] = c; s->ugbuf[1] = '\0';
1615
		s->start = s->str = s->ugbuf;
1616
		s->next = source;
1617
		source = s;
1618
	}
1619
166010911
	return source->str;
1620
173456702
}
1621
1622
1623
/* Called to get a char that isn't a \newline sequence. */
1624
static int
1625
getsc_bn(void)
1626
{
1627
	int c, c2;
1628
1629
98275192
	if (ignore_backslash_newline)
1630
6154368
		return getsc_();
1631
1632
47086140
	if (backslash_skip == 1) {
1633
4642788
		backslash_skip = 2;
1634
13928364
		return getsc_();
1635
	}
1636
1637
42443352
	backslash_skip = 0;
1638
1639
42443352
	while (1) {
1640
128726700
		c = getsc_();
1641
42906992
		if (c == '\\') {
1642

16984407
			if ((c2 = getsc_()) == '\n')
1643
				/* ignore the \newline; get the next char... */
1644
				continue;
1645
5194967
			ungetsc(c2);
1646
5194967
			backslash_skip = 1;
1647
5194967
		}
1648
42440490
		return c;
1649
	}
1650
49134734
}
1651
1652
static Lex_state *
1653
push_state_(State_info *si, Lex_state *old_end)
1654
{
1655
	Lex_state *new = areallocarray(NULL, STATE_BSIZE,
1656
	    sizeof(Lex_state), ATEMP);
1657
1658
	new[0].ls_info.base = old_end;
1659
	si->base = &new[0];
1660
	si->end = &new[STATE_BSIZE];
1661
	return &new[1];
1662
}
1663
1664
static Lex_state *
1665
pop_state_(State_info *si, Lex_state *old_end)
1666
{
1667
	Lex_state *old_base = si->base;
1668
1669
	si->base = old_end->ls_info.base - STATE_BSIZE;
1670
	si->end = old_end->ls_info.base;
1671
1672
	afree(old_base, ATEMP);
1673
1674
	return si->base + STATE_BSIZE - 1;
1675
}