GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/csh/lex.c Lines: 0 812 0.0 %
Date: 2017-11-07 Branches: 0 761 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: lex.c,v 1.25 2017/08/30 07:54:54 anton Exp $	*/
2
/*	$NetBSD: lex.c,v 1.9 1995/09/27 00:38:46 jtc Exp $	*/
3
4
/*-
5
 * Copyright (c) 1980, 1991, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/types.h>
34
#include <termios.h>
35
#include <errno.h>
36
#include <fcntl.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <unistd.h>
40
#include <stdarg.h>
41
42
#include "csh.h"
43
#include "extern.h"
44
45
/*
46
 * These lexical routines read input and form lists of words.
47
 * There is some involved processing here, because of the complications
48
 * of input buffering, and especially because of history substitution.
49
 */
50
51
static Char	*word(void);
52
static int	 getC1(int);
53
static void	 getdol(void);
54
static void	 getexcl(int);
55
static struct Hist
56
		*findev(Char *, bool);
57
static void	 setexclp(Char *);
58
static int	 bgetc(void);
59
static void	 bfree(void);
60
static struct wordent
61
		*gethent(int);
62
static int	 matchs(Char *, Char *);
63
static int	 getsel(int *, int *, int);
64
static struct wordent
65
		*getsub(struct wordent *);
66
static Char	*subword(Char *, int, bool *);
67
static struct wordent
68
		*dosub(int, struct wordent *, bool);
69
70
/*
71
 * Peekc is a peek character for getC, peekread for readc.
72
 * There is a subtlety here in many places... history routines
73
 * will read ahead and then insert stuff into the input stream.
74
 * If they push back a character then they must push it behind
75
 * the text substituted by the history substitution.  On the other
76
 * hand in several places we need 2 peek characters.  To make this
77
 * all work, the history routines read with getC, and make use both
78
 * of ungetC and unreadc.  The key observation is that the state
79
 * of getC at the call of a history reference is such that calls
80
 * to getC from the history routines will always yield calls of
81
 * readc, unless this peeking is involved.  That is to say that during
82
 * getexcl the variables lap, exclp, and exclnxt are all zero.
83
 *
84
 * Getdol invokes history substitution, hence the extra peek, peekd,
85
 * which it can ungetD to be before history substitutions.
86
 */
87
static Char peekc = 0, peekd = 0;
88
static Char peekread = 0;
89
90
/* (Tail of) current word from ! subst */
91
static Char *exclp = NULL;
92
93
/* The rest of the ! subst words */
94
static struct wordent *exclnxt = NULL;
95
96
/* Count of remaining words in ! subst */
97
static int exclc = 0;
98
99
/* "Globp" for alias resubstitution */
100
Char *alvecp = NULL;
101
int aret = F_SEEK;
102
103
/*
104
 * Labuf implements a general buffer for lookahead during lexical operations.
105
 * Text which is to be placed in the input stream can be stuck here.
106
 * We stick parsed ahead $ constructs during initial input,
107
 * process id's from `$$', and modified variable values (from qualifiers
108
 * during expansion in sh.dol.c) here.
109
 */
110
static Char labuf[BUFSIZ];
111
112
/*
113
 * Lex returns to its caller not only a wordlist (as a "var" parameter)
114
 * but also whether a history substitution occurred.  This is used in
115
 * the main (process) routine to determine whether to echo, and also
116
 * when called by the alias routine to determine whether to keep the
117
 * argument list.
118
 */
119
static bool hadhist = 0;
120
121
/*
122
 * Avoid alias expansion recursion via \!#
123
 */
124
int     hleft;
125
126
static Char getCtmp;
127
128
#define getC(f)		((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))
129
#define	ungetC(c)	peekc = c
130
#define	ungetD(c)	peekd = c
131
132
int
133
lex(struct wordent *hp)
134
{
135
    struct wordent *wdp;
136
    int     c;
137
138
    btell(&lineloc);
139
    hp->next = hp->prev = hp;
140
    hp->word = STRNULL;
141
    hadhist = 0;
142
    do
143
	c = readc(0);
144
    while (c == ' ' || c == '\t');
145
    if (c == HISTSUB && intty)
146
	/* ^lef^rit	from tty is short !:s^lef^rit */
147
	getexcl(c);
148
    else
149
	unreadc(c);
150
    wdp = hp;
151
    /*
152
     * The following loop is written so that the links needed by freelex will
153
     * be ready and rarin to go even if it is interrupted.
154
     */
155
    do {
156
	struct wordent *new;
157
158
	new = xmalloc((size_t) sizeof(*wdp));
159
	new->word = 0;
160
	new->prev = wdp;
161
	new->next = hp;
162
	wdp->next = new;
163
	wdp = new;
164
	wdp->word = word();
165
    } while (wdp->word[0] != '\n');
166
    hp->prev = wdp;
167
    return (hadhist);
168
}
169
170
void
171
prlex(FILE *fp, struct wordent *sp0)
172
{
173
    struct wordent *sp = sp0->next;
174
175
    for (;;) {
176
	(void) fprintf(fp, "%s", vis_str(sp->word));
177
	sp = sp->next;
178
	if (sp == sp0)
179
	    break;
180
	if (sp->word[0] != '\n')
181
	    (void) fputc(' ', fp);
182
    }
183
}
184
185
void
186
copylex(struct wordent *hp, struct wordent *fp)
187
{
188
    struct wordent *wdp;
189
190
    wdp = hp;
191
    fp = fp->next;
192
    do {
193
	struct wordent *new;
194
195
	new = xmalloc((size_t) sizeof(*wdp));
196
	new->prev = wdp;
197
	new->next = hp;
198
	wdp->next = new;
199
	wdp = new;
200
	wdp->word = Strsave(fp->word);
201
	fp = fp->next;
202
    } while (wdp->word[0] != '\n');
203
    hp->prev = wdp;
204
}
205
206
void
207
freelex(struct wordent *vp)
208
{
209
    struct wordent *fp;
210
211
    while (vp->next != vp) {
212
	fp = vp->next;
213
	vp->next = fp->next;
214
	free(fp->word);
215
	free(fp);
216
    }
217
    vp->prev = vp;
218
}
219
220
static Char *
221
word(void)
222
{
223
    Char c, c1;
224
    Char *wp;
225
    Char    wbuf[BUFSIZ];
226
    bool dolflg;
227
    int i;
228
229
    wp = wbuf;
230
    i = BUFSIZ - 4;
231
loop:
232
    while ((c = getC(DOALL)) == ' ' || c == '\t')
233
	continue;
234
    if (cmap(c, _META | _ESC))
235
	switch (c) {
236
	case '&':
237
	case '|':
238
	case '<':
239
	case '>':
240
	    *wp++ = c;
241
	    c1 = getC(DOALL);
242
	    if (c1 == c)
243
		*wp++ = c1;
244
	    else
245
		ungetC(c1);
246
	    goto ret;
247
248
	case '#':
249
	    if (intty)
250
		break;
251
	    c = 0;
252
	    do {
253
		c1 = c;
254
		c = getC(0);
255
	    } while (c != '\n');
256
	    if (c1 == '\\')
257
		goto loop;
258
	    /* fall into ... */
259
260
	case ';':
261
	case '(':
262
	case ')':
263
	case '\n':
264
	    *wp++ = c;
265
	    goto ret;
266
267
	case '\\':
268
	    c = getC(0);
269
	    if (c == '\n') {
270
		if (onelflg == 1)
271
		    onelflg = 2;
272
		goto loop;
273
	    }
274
	    if (c != HIST)
275
		*wp++ = '\\', --i;
276
	    c |= QUOTE;
277
	}
278
    c1 = 0;
279
    dolflg = DOALL;
280
    for (;;) {
281
	if (c1) {
282
	    if (c == c1) {
283
		c1 = 0;
284
		dolflg = DOALL;
285
	    }
286
	    else if (c == '\\') {
287
		c = getC(0);
288
		if (c == HIST)
289
		    c |= QUOTE;
290
		else {
291
		    if (c == '\n')
292
			/*
293
			 * if (c1 == '`') c = ' '; else
294
			 */
295
			c |= QUOTE;
296
		    ungetC(c);
297
		    c = '\\';
298
		}
299
	    }
300
	    else if (c == '\n') {
301
		seterror(ERR_UNMATCHED, c1);
302
		ungetC(c);
303
		break;
304
	    }
305
	}
306
	else if (cmap(c, _META | _QF | _QB | _ESC)) {
307
	    if (c == '\\') {
308
		c = getC(0);
309
		if (c == '\n') {
310
		    if (onelflg == 1)
311
			onelflg = 2;
312
		    break;
313
		}
314
		if (c != HIST)
315
		    *wp++ = '\\', --i;
316
		c |= QUOTE;
317
	    }
318
	    else if (cmap(c, _QF | _QB)) {	/* '"` */
319
		c1 = c;
320
		dolflg = c == '"' ? DOALL : DOEXCL;
321
	    }
322
	    else if (c != '#' || !intty) {
323
		ungetC(c);
324
		break;
325
	    }
326
	}
327
	if (--i > 0) {
328
	    *wp++ = c;
329
	    c = getC(dolflg);
330
	}
331
	else {
332
	    seterror(ERR_WTOOLONG);
333
	    wp = &wbuf[1];
334
	    break;
335
	}
336
    }
337
ret:
338
    *wp = 0;
339
    return (Strsave(wbuf));
340
}
341
342
static int
343
getC1(int flag)
344
{
345
    Char c;
346
347
    while (1) {
348
	if ((c = peekc) != '\0') {
349
	    peekc = 0;
350
	    return (c);
351
	}
352
	if (lap) {
353
	    if ((c = *lap++) == 0)
354
		lap = 0;
355
	    else {
356
		if (cmap(c, _META | _QF | _QB))
357
		    c |= QUOTE;
358
		return (c);
359
	    }
360
	}
361
	if ((c = peekd) != '\0') {
362
	    peekd = 0;
363
	    return (c);
364
	}
365
	if (exclp) {
366
	    if ((c = *exclp++) != '\0')
367
		return (c);
368
	    if (exclnxt && --exclc >= 0) {
369
		exclnxt = exclnxt->next;
370
		setexclp(exclnxt->word);
371
		return (' ');
372
	    }
373
	    exclp = 0;
374
	    exclnxt = 0;
375
	}
376
	if (exclnxt) {
377
	    exclnxt = exclnxt->next;
378
	    if (--exclc < 0)
379
		exclnxt = 0;
380
	    else
381
		setexclp(exclnxt->word);
382
	    continue;
383
	}
384
	c = readc(0);
385
	if (c == '$' && (flag & DODOL)) {
386
	    getdol();
387
	    continue;
388
	}
389
	if (c == HIST && (flag & DOEXCL)) {
390
	    getexcl(0);
391
	    continue;
392
	}
393
	break;
394
    }
395
    return (c);
396
}
397
398
static void
399
getdol(void)
400
{
401
    Char *np, *ep;
402
    Char    name[4 * MAXVARLEN + 1];
403
    int c;
404
    int     sc;
405
    bool    special = 0, toolong;
406
407
    np = name, *np++ = '$';
408
    c = sc = getC(DOEXCL);
409
    if (any("\t \n", c)) {
410
	ungetD(c);
411
	ungetC('$' | QUOTE);
412
	return;
413
    }
414
    if (c == '{')
415
	*np++ = c, c = getC(DOEXCL);
416
    if (c == '#' || c == '?')
417
	special++, *np++ = c, c = getC(DOEXCL);
418
    *np++ = c;
419
    switch (c) {
420
421
    case '<':
422
    case '$':
423
    case '!':
424
	if (special)
425
	    seterror(ERR_SPDOLLT);
426
	*np = 0;
427
	addla(name);
428
	return;
429
430
    case '\n':
431
	ungetD(c);
432
	np--;
433
	seterror(ERR_NEWLINE);
434
	*np = 0;
435
	addla(name);
436
	return;
437
438
    case '*':
439
	if (special)
440
	    seterror(ERR_SPSTAR);
441
	*np = 0;
442
	addla(name);
443
	return;
444
445
    default:
446
	toolong = 0;
447
	if (Isdigit(c)) {
448
	    /* we know that np < &name[4] */
449
	    ep = &np[MAXVARLEN];
450
	    while ((c = getC(DOEXCL)) != '\0'){
451
		if (!Isdigit(c))
452
		    break;
453
		if (np < ep)
454
		    *np++ = c;
455
		else
456
		    toolong = 1;
457
	    }
458
	}
459
	else if (letter(c)) {
460
	    /* we know that np < &name[4] */
461
	    ep = &np[MAXVARLEN];
462
	    toolong = 0;
463
	    while ((c = getC(DOEXCL)) != '\0') {
464
		/* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */
465
		if (!letter(c) && !Isdigit(c))
466
		    break;
467
		if (np < ep)
468
		    *np++ = c;
469
		else
470
		    toolong = 1;
471
	    }
472
	}
473
	else {
474
	    *np = 0;
475
	    seterror(ERR_VARILL);
476
	    addla(name);
477
	    return;
478
	}
479
	if (toolong) {
480
	    seterror(ERR_VARTOOLONG);
481
	    *np = 0;
482
	    addla(name);
483
	    return;
484
	}
485
	break;
486
    }
487
    if (c == '[') {
488
	*np++ = c;
489
	/*
490
	 * Name up to here is a max of MAXVARLEN + 8.
491
	 */
492
	ep = &np[2 * MAXVARLEN + 8];
493
	do {
494
	    /*
495
	     * Michael Greim: Allow $ expansion to take place in selector
496
	     * expressions. (limits the number of characters returned)
497
	     */
498
	    c = getC(DOEXCL | DODOL);
499
	    if (c == '\n') {
500
		ungetD(c);
501
		np--;
502
		seterror(ERR_NLINDEX);
503
		*np = 0;
504
		addla(name);
505
		return;
506
	    }
507
	    if (np < ep)
508
		*np++ = c;
509
	} while (c != ']');
510
	*np = '\0';
511
	if (np >= ep) {
512
	    seterror(ERR_SELOVFL);
513
	    addla(name);
514
	    return;
515
	}
516
	c = getC(DOEXCL);
517
    }
518
    /*
519
     * Name up to here is a max of 2 * MAXVARLEN + 8.
520
     */
521
    if (c == ':') {
522
	/*
523
	 * if the :g modifier is followed by a newline, then error right away!
524
	 * -strike
525
	 */
526
527
	int     gmodflag = 0, amodflag = 0;
528
529
	do {
530
	    *np++ = c, c = getC(DOEXCL);
531
	    if (c == 'g' || c == 'a') {
532
		if (c == 'g')
533
		    gmodflag++;
534
		else
535
		    amodflag++;
536
		*np++ = c; c = getC(DOEXCL);
537
	    }
538
	    if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) {
539
		if (c == 'g')
540
		    gmodflag++;
541
		else
542
		    amodflag++;
543
		*np++ = c; c = getC(DOEXCL);
544
	    }
545
	    *np++ = c;
546
	    /* scan s// [eichin:19910926.0512EST] */
547
	    if (c == 's') {
548
		int delimcnt = 2;
549
		int delim = getC(0);
550
		*np++ = delim;
551
552
		if (!delim || letter(delim)
553
		    || Isdigit(delim) || any(" \t\n", delim)) {
554
		    seterror(ERR_BADSUBST);
555
		    break;
556
		}
557
		while ((c = getC(0)) != (-1)) {
558
		    *np++ = c;
559
		    if(c == delim) delimcnt--;
560
		    if(!delimcnt) break;
561
		}
562
		if(delimcnt) {
563
		    seterror(ERR_BADSUBST);
564
		    break;
565
		}
566
		c = 's';
567
	    }
568
	    if (!any("htrqxes", c)) {
569
		if ((amodflag || gmodflag) && c == '\n')
570
		    stderror(ERR_VARSYN);	/* strike */
571
		seterror(ERR_VARMOD, c);
572
		*np = 0;
573
		addla(name);
574
		return;
575
	    }
576
	}
577
	while ((c = getC(DOEXCL)) == ':');
578
	ungetD(c);
579
    }
580
    else
581
	ungetD(c);
582
    if (sc == '{') {
583
	c = getC(DOEXCL);
584
	if (c != '}') {
585
	    ungetD(c);
586
	    seterror(ERR_MISSING, '}');
587
	    *np = 0;
588
	    addla(name);
589
	    return;
590
	}
591
	*np++ = c;
592
    }
593
    *np = 0;
594
    addla(name);
595
    return;
596
}
597
598
void
599
addla(Char *cp)
600
{
601
    Char    buf[BUFSIZ];
602
603
    if (Strlen(cp) + (lap ? Strlen(lap) : 0) >=
604
	(sizeof(labuf) - 4) / sizeof(Char)) {
605
	seterror(ERR_EXPOVFL);
606
	return;
607
    }
608
    if (lap)
609
	(void) Strlcpy(buf, lap, sizeof buf/sizeof(Char));
610
    (void) Strlcpy(labuf, cp, sizeof labuf/sizeof(Char));
611
    if (lap)
612
	(void) Strlcat(labuf, buf, sizeof labuf/sizeof(Char));
613
    lap = labuf;
614
}
615
616
static Char lhsb[32];
617
static Char slhs[32];
618
static Char rhsb[64];
619
static int quesarg;
620
621
static void
622
getexcl(int sc)
623
{
624
    struct wordent *hp, *ip;
625
    int     left, right, dol;
626
    int c;
627
628
    if (sc == 0) {
629
	sc = getC(0);
630
	if (sc != '{') {
631
	    ungetC(sc);
632
	    sc = 0;
633
	}
634
    }
635
    quesarg = -1;
636
    lastev = eventno;
637
    hp = gethent(sc);
638
    if (hp == 0)
639
	return;
640
    hadhist = 1;
641
    dol = 0;
642
    if (hp == alhistp)
643
	for (ip = hp->next->next; ip != alhistt; ip = ip->next)
644
	    dol++;
645
    else
646
	for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
647
	    dol++;
648
    left = 0, right = dol;
649
    if (sc == HISTSUB) {
650
	ungetC('s'), unreadc(HISTSUB), c = ':';
651
	goto subst;
652
    }
653
    c = getC(0);
654
    if (!any(":^$*-%", c))
655
	goto subst;
656
    left = right = -1;
657
    if (c == ':') {
658
	c = getC(0);
659
	unreadc(c);
660
	if (letter(c) || c == '&') {
661
	    c = ':';
662
	    left = 0, right = dol;
663
	    goto subst;
664
	}
665
    }
666
    else
667
	ungetC(c);
668
    if (!getsel(&left, &right, dol))
669
	return;
670
    c = getC(0);
671
    if (c == '*')
672
	ungetC(c), c = '-';
673
    if (c == '-') {
674
	if (!getsel(&left, &right, dol))
675
	    return;
676
	c = getC(0);
677
    }
678
subst:
679
    exclc = right - left + 1;
680
    while (--left >= 0)
681
	hp = hp->next;
682
    if (sc == HISTSUB || c == ':') {
683
	do {
684
	    hp = getsub(hp);
685
	    c = getC(0);
686
	} while (c == ':');
687
    }
688
    unreadc(c);
689
    if (sc == '{') {
690
	c = getC(0);
691
	if (c != '}')
692
	    seterror(ERR_BADBANG);
693
    }
694
    exclnxt = hp;
695
}
696
697
static struct wordent *
698
getsub(struct wordent *en)
699
{
700
    Char *cp;
701
    int     delim;
702
    int c;
703
    int     sc;
704
    bool global;
705
    Char    orhsb[sizeof(rhsb) / sizeof(Char)];
706
707
    do {
708
	exclnxt = 0;
709
	global = 0;
710
	sc = c = getC(0);
711
	if (c == 'g' || c == 'a') {
712
	    global |= (c == 'g') ? 1 : 2;
713
	    sc = c = getC(0);
714
	}
715
	if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) {
716
	    global |= (c == 'g') ? 1 : 2;
717
	    sc = c = getC(0);
718
	}
719
720
	switch (c) {
721
	case 'p':
722
	    justpr++;
723
	    return (en);
724
725
	case 'x':
726
	case 'q':
727
	    global |= 1;
728
729
	    /* fall into ... */
730
731
	case 'h':
732
	case 'r':
733
	case 't':
734
	case 'e':
735
	    break;
736
737
	case '&':
738
	    if (slhs[0] == 0) {
739
		seterror(ERR_NOSUBST);
740
		return (en);
741
	    }
742
	    (void) Strlcpy(lhsb, slhs, sizeof(lhsb)/sizeof(Char));
743
	    break;
744
745
	case 's':
746
	    delim = getC(0);
747
	    if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) {
748
		unreadc(delim);
749
		lhsb[0] = 0;
750
		seterror(ERR_BADSUBST);
751
		return (en);
752
	    }
753
	    cp = lhsb;
754
	    for (;;) {
755
		c = getC(0);
756
		if (c == '\n') {
757
		    unreadc(c);
758
		    break;
759
		}
760
		if (c == delim)
761
		    break;
762
		if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) {
763
		    lhsb[0] = 0;
764
		    seterror(ERR_BADSUBST);
765
		    return (en);
766
		}
767
		if (c == '\\') {
768
		    c = getC(0);
769
		    if (c != delim && c != '\\')
770
			*cp++ = '\\';
771
		}
772
		*cp++ = c;
773
	    }
774
	    if (cp != lhsb)
775
		*cp++ = 0;
776
	    else if (lhsb[0] == 0) {
777
		seterror(ERR_LHS);
778
		return (en);
779
	    }
780
	    cp = rhsb;
781
	    (void) Strlcpy(orhsb, cp, sizeof(orhsb)/sizeof(Char));
782
	    for (;;) {
783
		c = getC(0);
784
		if (c == '\n') {
785
		    unreadc(c);
786
		    break;
787
		}
788
		if (c == delim)
789
		    break;
790
		if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) {
791
		    seterror(ERR_RHSLONG);
792
		    return (en);
793
		}
794
		if (c == '\\') {
795
		    c = getC(0);
796
		    if (c != delim /* && c != '~' */ )
797
			*cp++ = '\\';
798
		}
799
		*cp++ = c;
800
	    }
801
	    *cp++ = 0;
802
	    break;
803
804
	default:
805
	    if (c == '\n')
806
		unreadc(c);
807
	    seterror(ERR_BADBANGMOD, c);
808
	    return (en);
809
	}
810
	(void) Strlcpy(slhs, lhsb, sizeof(slhs)/sizeof(Char));
811
	if (exclc)
812
	    en = dosub(sc, en, global);
813
    }
814
    while ((c = getC(0)) == ':');
815
    unreadc(c);
816
    return (en);
817
}
818
819
static struct wordent *
820
dosub(int sc, struct wordent *en, bool global)
821
{
822
    struct wordent lexi;
823
    bool    didsub = 0, didone = 0;
824
    struct wordent *hp = &lexi;
825
    struct wordent *wdp;
826
    int i = exclc;
827
828
    wdp = hp;
829
    while (--i >= 0) {
830
	struct wordent *new = xcalloc(1, sizeof *wdp);
831
832
	new->word = 0;
833
	new->prev = wdp;
834
	new->next = hp;
835
	wdp->next = new;
836
	wdp = new;
837
	en = en->next;
838
	if (en->word) {
839
	    Char *tword, *otword;
840
841
	    if ((global & 1) || didsub == 0) {
842
		tword = subword(en->word, sc, &didone);
843
		if (didone)
844
		    didsub = 1;
845
		if (global & 2) {
846
		    while (didone && tword != STRNULL) {
847
			otword = tword;
848
			tword = subword(otword, sc, &didone);
849
			if (Strcmp(tword, otword) == 0) {
850
			    free(otword);
851
			    break;
852
			}
853
			else
854
			    free(otword);
855
		    }
856
		}
857
	    }
858
	    else
859
		tword = Strsave(en->word);
860
	    wdp->word = tword;
861
	}
862
    }
863
    if (didsub == 0)
864
	seterror(ERR_MODFAIL);
865
    hp->prev = wdp;
866
    return (&enthist(-1000, &lexi, 0)->Hlex);
867
}
868
869
static Char *
870
subword(Char *cp, int type, bool *adid)
871
{
872
    Char    wbuf[BUFSIZ];
873
    Char *wp, *mp, *np;
874
    int i;
875
876
    *adid = 0;
877
    switch (type) {
878
879
    case 'r':
880
    case 'e':
881
    case 'h':
882
    case 't':
883
    case 'q':
884
    case 'x':
885
	wp = domod(cp, type);
886
	if (wp == 0)
887
	    return (Strsave(cp));
888
	*adid = 1;
889
	return (wp);
890
891
    default:
892
	wp = wbuf;
893
	i = BUFSIZ - 4;
894
	for (mp = cp; *mp; mp++)
895
	    if (matchs(mp, lhsb)) {
896
		for (np = cp; np < mp;)
897
		    *wp++ = *np++, --i;
898
		for (np = rhsb; *np; np++)
899
		    switch (*np) {
900
901
		    case '\\':
902
			if (np[1] == '&')
903
			    np++;
904
			/* fall into ... */
905
906
		    default:
907
			if (--i < 0) {
908
			    seterror(ERR_SUBOVFL);
909
			    return (STRNULL);
910
			}
911
			*wp++ = *np;
912
			continue;
913
914
		    case '&':
915
			i -= Strlen(lhsb);
916
			if (i < 0) {
917
			    seterror(ERR_SUBOVFL);
918
			    return (STRNULL);
919
			}
920
			*wp = 0;
921
			(void)Strlcat(wp, lhsb,
922
			    sizeof(wbuf)/sizeof(Char) - (wp - wbuf));
923
			wp = Strend(wp);
924
			continue;
925
		    }
926
		mp += Strlen(lhsb);
927
		i -= Strlen(mp);
928
		if (i < 0) {
929
		    seterror(ERR_SUBOVFL);
930
		    return (STRNULL);
931
		}
932
		*wp = 0;
933
		(void)Strlcat(wp, mp,
934
		    sizeof(wbuf)/sizeof(Char) - (wp - wbuf));
935
		*adid = 1;
936
		return (Strsave(wbuf));
937
	    }
938
	return (Strsave(cp));
939
    }
940
}
941
942
Char   *
943
domod(Char *cp, int type)
944
{
945
    Char *wp, *xp;
946
    int c;
947
948
    switch (type) {
949
950
    case 'x':
951
    case 'q':
952
	wp = Strsave(cp);
953
	for (xp = wp; (c = *xp) != '\0'; xp++)
954
	    if ((c != ' ' && c != '\t') || type == 'q')
955
		*xp |= QUOTE;
956
	return (wp);
957
958
    case 'h':
959
    case 't':
960
	if (!any(short2str(cp), '/'))
961
	    return (type == 't' ? Strsave(cp) : 0);
962
	wp = Strend(cp);
963
	while (*--wp != '/')
964
	    continue;
965
	if (type == 'h')
966
	    xp = Strsave(cp), xp[wp - cp] = 0;
967
	else
968
	    xp = Strsave(wp + 1);
969
	return (xp);
970
971
    case 'e':
972
    case 'r':
973
	wp = Strend(cp);
974
	for (wp--; wp >= cp && *wp != '/'; wp--)
975
	    if (*wp == '.') {
976
		if (type == 'e')
977
		    xp = Strsave(wp + 1);
978
		else
979
		    xp = Strsave(cp), xp[wp - cp] = 0;
980
		return (xp);
981
	    }
982
	return (Strsave(type == 'e' ? STRNULL : cp));
983
    default:
984
	break;
985
    }
986
    return (0);
987
}
988
989
static int
990
matchs(Char *str, Char *pat)
991
{
992
    while (*str && *pat && *str == *pat)
993
	str++, pat++;
994
    return (*pat == 0);
995
}
996
997
static int
998
getsel(int *al, int *ar, int dol)
999
{
1000
    int c = getC(0);
1001
    int i;
1002
    bool    first = *al < 0;
1003
1004
    switch (c) {
1005
1006
    case '%':
1007
	if (quesarg == -1) {
1008
	    seterror(ERR_BADBANGARG);
1009
	    return (0);
1010
	}
1011
	if (*al < 0)
1012
	    *al = quesarg;
1013
	*ar = quesarg;
1014
	break;
1015
1016
    case '-':
1017
	if (*al < 0) {
1018
	    *al = 0;
1019
	    *ar = dol - 1;
1020
	    unreadc(c);
1021
	}
1022
	return (1);
1023
1024
    case '^':
1025
	if (*al < 0)
1026
	    *al = 1;
1027
	*ar = 1;
1028
	break;
1029
1030
    case '$':
1031
	if (*al < 0)
1032
	    *al = dol;
1033
	*ar = dol;
1034
	break;
1035
1036
    case '*':
1037
	if (*al < 0)
1038
	    *al = 1;
1039
	*ar = dol;
1040
	if (*ar < *al) {
1041
	    *ar = 0;
1042
	    *al = 1;
1043
	    return (1);
1044
	}
1045
	break;
1046
1047
    default:
1048
	if (Isdigit(c)) {
1049
	    i = 0;
1050
	    while (Isdigit(c)) {
1051
		i = i * 10 + c - '0';
1052
		c = getC(0);
1053
	    }
1054
	    if (i < 0)
1055
		i = dol + 1;
1056
	    if (*al < 0)
1057
		*al = i;
1058
	    *ar = i;
1059
	}
1060
	else if (*al < 0)
1061
	    *al = 0, *ar = dol;
1062
	else
1063
	    *ar = dol - 1;
1064
	unreadc(c);
1065
	break;
1066
    }
1067
    if (first) {
1068
	c = getC(0);
1069
	unreadc(c);
1070
	if (any("-$*", c))
1071
	    return (1);
1072
    }
1073
    if (*al > *ar || *ar > dol) {
1074
	seterror(ERR_BADBANGARG);
1075
	return (0);
1076
    }
1077
    return (1);
1078
1079
}
1080
1081
static struct wordent *
1082
gethent(int sc)
1083
{
1084
    struct Hist *hp;
1085
    Char *np;
1086
    int c;
1087
    int     event;
1088
    bool    back = 0;
1089
1090
    c = sc == HISTSUB ? HIST : getC(0);
1091
    if (c == HIST) {
1092
	if (alhistp)
1093
	    return (alhistp);
1094
	event = eventno;
1095
    }
1096
    else
1097
	switch (c) {
1098
1099
	case ':':
1100
	case '^':
1101
	case '$':
1102
	case '*':
1103
	case '%':
1104
	    ungetC(c);
1105
	    if (lastev == eventno && alhistp)
1106
		return (alhistp);
1107
	    event = lastev;
1108
	    break;
1109
1110
	case '#':		/* !# is command being typed in (mrh) */
1111
	    if (--hleft == 0) {
1112
		seterror(ERR_HISTLOOP);
1113
		return (0);
1114
	    }
1115
	    else
1116
		return (&paraml);
1117
	    /* NOTREACHED */
1118
1119
	case '-':
1120
	    back = 1;
1121
	    c = getC(0);
1122
	    /* FALLSTHROUGH */
1123
1124
	default:
1125
	    if (any("(=~", c)) {
1126
		unreadc(c);
1127
		ungetC(HIST);
1128
		return (0);
1129
	    }
1130
	    np = lhsb;
1131
	    event = 0;
1132
	    while (!cmap(c, _ESC | _META | _QF | _QB) && !any("${}:", c)) {
1133
		if (event != -1 && Isdigit(c))
1134
		    event = event * 10 + c - '0';
1135
		else
1136
		    event = -1;
1137
		if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
1138
		    *np++ = c;
1139
		c = getC(0);
1140
	    }
1141
	    unreadc(c);
1142
	    if (np == lhsb) {
1143
		ungetC(HIST);
1144
		return (0);
1145
	    }
1146
	    *np++ = 0;
1147
	    if (event != -1) {
1148
		/*
1149
		 * History had only digits
1150
		 */
1151
		if (back)
1152
		    event = eventno + (alhistp == 0) - (event ? event : 0);
1153
		break;
1154
	    }
1155
	    hp = findev(lhsb, 0);
1156
	    if (hp)
1157
		lastev = hp->Hnum;
1158
	    return (&hp->Hlex);
1159
1160
	case '?':
1161
	    np = lhsb;
1162
	    for (;;) {
1163
		c = getC(0);
1164
		if (c == '\n') {
1165
		    unreadc(c);
1166
		    break;
1167
		}
1168
		if (c == '?')
1169
		    break;
1170
		if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
1171
		    *np++ = c;
1172
	    }
1173
	    if (np == lhsb) {
1174
		if (lhsb[0] == 0) {
1175
		    seterror(ERR_NOSEARCH);
1176
		    return (0);
1177
		}
1178
	    }
1179
	    else
1180
		*np++ = 0;
1181
	    hp = findev(lhsb, 1);
1182
	    if (hp)
1183
		lastev = hp->Hnum;
1184
	    return (&hp->Hlex);
1185
	}
1186
1187
    for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
1188
	if (hp->Hnum == event) {
1189
	    hp->Href = eventno;
1190
	    lastev = hp->Hnum;
1191
	    return (&hp->Hlex);
1192
	}
1193
    np = putn(event);
1194
    seterror(ERR_NOEVENT, vis_str(np));
1195
    return (0);
1196
}
1197
1198
static struct Hist *
1199
findev(Char *cp, bool anyarg)
1200
{
1201
    struct Hist *hp;
1202
1203
    for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
1204
	Char   *dp;
1205
	Char *p, *q;
1206
	struct wordent *lp = hp->Hlex.next;
1207
	int     argno = 0;
1208
1209
	/*
1210
	 * The entries added by alias substitution don't have a newline but do
1211
	 * have a negative event number. Savehist() trims off these entries,
1212
	 * but it happens before alias expansion, too early to delete those
1213
	 * from the previous command.
1214
	 */
1215
	if (hp->Hnum < 0)
1216
	    continue;
1217
	if (lp->word[0] == '\n')
1218
	    continue;
1219
	if (!anyarg) {
1220
	    p = cp;
1221
	    q = lp->word;
1222
	    do
1223
		if (!*p)
1224
		    return (hp);
1225
	    while (*p++ == *q++);
1226
	    continue;
1227
	}
1228
	do {
1229
	    for (dp = lp->word; *dp; dp++) {
1230
		p = cp;
1231
		q = dp;
1232
		do
1233
		    if (!*p) {
1234
			quesarg = argno;
1235
			return (hp);
1236
		    }
1237
		while (*p++ == *q++);
1238
	    }
1239
	    lp = lp->next;
1240
	    argno++;
1241
	} while (lp->word[0] != '\n');
1242
    }
1243
    seterror(ERR_NOEVENT, vis_str(cp));
1244
    return (0);
1245
}
1246
1247
1248
static void
1249
setexclp(Char *cp)
1250
{
1251
    if (cp && cp[0] == '\n')
1252
	return;
1253
    exclp = cp;
1254
}
1255
1256
void
1257
unreadc(int c)
1258
{
1259
    peekread = c;
1260
}
1261
1262
int
1263
readc(bool wanteof)
1264
{
1265
    int c;
1266
    static int sincereal;
1267
1268
    aret = F_SEEK;
1269
    if ((c = peekread) != '\0') {
1270
	peekread = 0;
1271
	return (c);
1272
    }
1273
top:
1274
    aret = F_SEEK;
1275
    if (alvecp) {
1276
	aret = A_SEEK;
1277
	if ((c = *alvecp++) != '\0')
1278
	    return (c);
1279
	if (alvec && *alvec) {
1280
		alvecp = *alvec++;
1281
		return (' ');
1282
	}
1283
	else {
1284
	    aret = F_SEEK;
1285
	    alvecp = NULL;
1286
	    return('\n');
1287
	}
1288
    }
1289
    if (alvec) {
1290
	if ((alvecp = *alvec) != '\0') {
1291
	    alvec++;
1292
	    goto top;
1293
	}
1294
	/* Infinite source! */
1295
	return ('\n');
1296
    }
1297
    if (evalp) {
1298
	aret = E_SEEK;
1299
	if ((c = *evalp++) != '\0')
1300
	    return (c);
1301
	if (evalvec && *evalvec) {
1302
	    evalp = *evalvec++;
1303
	    return (' ');
1304
	}
1305
	aret = F_SEEK;
1306
	evalp = 0;
1307
    }
1308
    if (evalvec) {
1309
	if (evalvec == (Char **) 1) {
1310
	    doneinp = 1;
1311
	    reset();
1312
	}
1313
	if ((evalp = *evalvec) != '\0') {
1314
	    evalvec++;
1315
	    goto top;
1316
	}
1317
	evalvec = (Char **) 1;
1318
	return ('\n');
1319
    }
1320
    do {
1321
	if (arginp == (Char *) 1 || onelflg == 1) {
1322
	    if (wanteof)
1323
		return (-1);
1324
	    exitstat();
1325
	}
1326
	if (arginp) {
1327
	    if ((c = *arginp++) == 0) {
1328
		arginp = (Char *) 1;
1329
		return ('\n');
1330
	    }
1331
	    return (c);
1332
	}
1333
reread:
1334
	c = bgetc();
1335
	if (c < 0) {
1336
	    struct termios tty;
1337
	    if (wanteof)
1338
		return (-1);
1339
	    /* was isatty but raw with ignoreeof yields problems */
1340
	    if (isatty(SHIN) && tcgetattr(SHIN, &tty) == 0 && (tty.c_lflag & ICANON))
1341
	    {
1342
		pid_t     ctpgrp;
1343
1344
		if (++sincereal > 25)
1345
		    goto oops;
1346
		if (tpgrp != -1 &&
1347
		    (ctpgrp = tcgetpgrp(FSHTTY)) != -1 &&
1348
		    tpgrp != ctpgrp) {
1349
		    (void) tcsetpgrp(FSHTTY, tpgrp);
1350
		    (void) kill(-ctpgrp, SIGHUP);
1351
		    (void) fprintf(csherr, "Reset tty pgrp from %d to %d\n",
1352
				   ctpgrp, tpgrp);
1353
		    goto reread;
1354
		}
1355
		if (adrof(STRignoreeof)) {
1356
		    if (loginsh)
1357
			(void) fprintf(csherr,"\nUse \"logout\" to logout.\n");
1358
		    else
1359
			(void) fprintf(csherr,"\nUse \"exit\" to leave csh.\n");
1360
		    reset();
1361
		}
1362
		if (chkstop == 0)
1363
		    panystop(1);
1364
	    }
1365
    oops:
1366
	    doneinp = 1;
1367
	    reset();
1368
	}
1369
	sincereal = 0;
1370
	if (c == '\n' && onelflg)
1371
	    onelflg--;
1372
    } while (c == 0);
1373
    return (c);
1374
}
1375
1376
static int
1377
bgetc(void)
1378
{
1379
    int buf, off, c;
1380
1381
    int numleft = 0, roomleft;
1382
    Char    ttyline[BUFSIZ];
1383
    char    tbuf[BUFSIZ + 1];
1384
1385
    if (cantell) {
1386
	if (fseekp < fbobp || fseekp > feobp) {
1387
	    fbobp = feobp = fseekp;
1388
	    (void) lseek(SHIN, fseekp, SEEK_SET);
1389
	}
1390
	if (fseekp == feobp) {
1391
	    int     i;
1392
1393
	    fbobp = feobp;
1394
	    do
1395
		c = read(SHIN, tbuf, BUFSIZ);
1396
	    while (c < 0 && errno == EINTR);
1397
	    if (c <= 0)
1398
		return (-1);
1399
	    for (i = 0; i < c; i++)
1400
		fbuf[0][i] = (unsigned char) tbuf[i];
1401
	    feobp += c;
1402
	}
1403
	c = fbuf[0][fseekp - fbobp];
1404
	fseekp++;
1405
	return (c);
1406
    }
1407
1408
again:
1409
    buf = (int) fseekp / BUFSIZ;
1410
    if (buf >= fblocks) {
1411
	Char **nfbuf = xcalloc((size_t) (fblocks + 2),
1412
			  sizeof(Char **));
1413
1414
	if (fbuf) {
1415
	    (void) blkcpy(nfbuf, fbuf);
1416
	    free(fbuf);
1417
	}
1418
	fbuf = nfbuf;
1419
	fbuf[fblocks] = xcalloc(BUFSIZ, sizeof(Char));
1420
	fblocks++;
1421
	if (!intty)
1422
	    goto again;
1423
    }
1424
    if (fseekp >= feobp) {
1425
	buf = (int) feobp / BUFSIZ;
1426
	off = (int) feobp % BUFSIZ;
1427
	roomleft = BUFSIZ - off;
1428
1429
	for (;;) {
1430
	    if (filec && intty) {
1431
		c = numleft ? numleft : tenex(ttyline, BUFSIZ);
1432
		if (c > roomleft) {
1433
		    /* start with fresh buffer */
1434
		    feobp = fseekp = fblocks * BUFSIZ;
1435
		    numleft = c;
1436
		    goto again;
1437
		}
1438
		if (c > 0)
1439
		    memcpy(fbuf[buf] + off, ttyline, c * sizeof(Char));
1440
		numleft = 0;
1441
	    }
1442
	    else {
1443
		c = read(SHIN, tbuf, roomleft);
1444
		if (c > 0) {
1445
		    int     i;
1446
		    Char   *ptr = fbuf[buf] + off;
1447
1448
		    for (i = 0; i < c; i++)
1449
			ptr[i] = (unsigned char) tbuf[i];
1450
		}
1451
	    }
1452
	    if (c >= 0)
1453
		break;
1454
	    if (errno == EWOULDBLOCK) {
1455
		int     flags;
1456
1457
		flags = fcntl(SHIN, F_GETFL);
1458
		(void) fcntl(SHIN, F_SETFL, (flags & ~O_NONBLOCK));
1459
	    }
1460
	    else if (errno != EINTR)
1461
		break;
1462
	}
1463
	if (c <= 0)
1464
	    return (-1);
1465
	feobp += c;
1466
	if (filec && !intty)
1467
	    goto again;
1468
    }
1469
    c = fbuf[buf][(int) fseekp % BUFSIZ];
1470
    fseekp++;
1471
    return (c);
1472
}
1473
1474
static void
1475
bfree(void)
1476
{
1477
    int sb, i;
1478
1479
    if (cantell)
1480
	return;
1481
    if (whyles)
1482
	return;
1483
    sb = (int) (fseekp - 1) / BUFSIZ;
1484
    if (sb > 0) {
1485
	for (i = 0; i < sb; i++)
1486
	    free(fbuf[i]);
1487
	(void) blkcpy(fbuf, &fbuf[sb]);
1488
	fseekp -= BUFSIZ * sb;
1489
	feobp -= BUFSIZ * sb;
1490
	fblocks -= sb;
1491
    }
1492
}
1493
1494
void
1495
bseek(struct Ain *l)
1496
{
1497
    switch (aret = l->type) {
1498
    case E_SEEK:
1499
	evalvec = l->a_seek;
1500
	evalp = l->c_seek;
1501
	return;
1502
    case A_SEEK:
1503
	alvec = l->a_seek;
1504
	alvecp = l->c_seek;
1505
	return;
1506
    case F_SEEK:
1507
	fseekp = l->f_seek;
1508
	return;
1509
    default:
1510
	(void) fprintf(csherr, "Bad seek type %d\n", aret);
1511
	abort();
1512
    }
1513
}
1514
1515
void
1516
btell(struct Ain *l)
1517
{
1518
    switch (l->type = aret) {
1519
    case E_SEEK:
1520
	l->a_seek = evalvec;
1521
	l->c_seek = evalp;
1522
	return;
1523
    case A_SEEK:
1524
	l->a_seek = alvec;
1525
	l->c_seek = alvecp;
1526
	return;
1527
    case F_SEEK:
1528
	l->f_seek = fseekp;
1529
	l->a_seek = NULL;
1530
	return;
1531
    default:
1532
	(void) fprintf(csherr, "Bad seek type %d\n", aret);
1533
	abort();
1534
    }
1535
}
1536
1537
void
1538
btoeof(void)
1539
{
1540
    (void) lseek(SHIN, (off_t) 0, SEEK_END);
1541
    aret = F_SEEK;
1542
    fseekp = feobp;
1543
    alvec = NULL;
1544
    alvecp = NULL;
1545
    evalvec = NULL;
1546
    evalp = NULL;
1547
    wfree();
1548
    bfree();
1549
}
1550
1551
void
1552
settell(void)
1553
{
1554
    cantell = 0;
1555
    if (arginp || onelflg || intty)
1556
	return;
1557
    if (lseek(SHIN, (off_t) 0, SEEK_CUR) < 0 || errno == ESPIPE)
1558
	return;
1559
    fbuf = xcalloc(2, sizeof(Char **));
1560
    fblocks = 1;
1561
    fbuf[0] = xcalloc(BUFSIZ, sizeof(Char));
1562
    fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, SEEK_CUR);
1563
    cantell = 1;
1564
}