xref: /onnv-gate/usr/src/cmd/bfs/bfs.c (revision 239:22a33675e457)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <setjmp.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <regexpr.h>
36 #include <limits.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <sys/stat.h>
40 #include <locale.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <wait.h>
44 #include <fcntl.h>
45 int setjmp();
46 static jmp_buf env;
47 
48 extern int scrwidth(wchar_t);
49 
50 #define	BRKTYP	char
51 #define	BRKSIZ	8192
52 #define	BRKTWO	4
53 #define	BFSAND
54 #define	BFSLIM	511
55 #define	BFSTRU	511
56 #define	BFSBUF	512
57 
58 struct Comd {
59 	int Cnumadr;
60 	int Cadr[2];
61 	char Csep;
62 	char Cop;
63 };
64 
65 static int Dot, Dollar;
66 static int markarray[26], *mark;
67 static int fstack[15] = {1, -1};
68 static int infildes = 0;
69 static int outfildes = 1;
70 static char internal[512], *intptr;
71 static char comdlist[100];
72 static char *endds;
73 static char charbuf = '\n';
74 static int peeked;
75 static char currex[100];
76 static int trunc = BFSTRU;
77 static int crunch = -1;
78 static int segblk[512], segoff[512], txtfd, prevblk, prevoff;
79 static int oldfd = 0;
80 static int flag4 = 0;
81 static int flag3 = 0;
82 static int flag2 = 0;
83 static int flag1 = 0;
84 static int flag = 0;
85 static int lprev = 1;
86 static int status[1];
87 static BRKTYP *lincnt;
88 static char *perbuf;
89 static char *rebuf;
90 static char *glbuf;
91 static char tty, *bigfile;
92 static char fle[80];
93 static char prompt = 1;
94 static char verbose = 1;	/* 1=print # of bytes read in; 0=silent. */
95 static char varray[10][100];	/* Holds xv cmd parameters. */
96 static double outcnt;
97 static char strtmp[32];
98 
99 static void reset();
100 static void begin(struct Comd *p);
101 static int  bigopen(char file[]);
102 static void sizeprt(int blk, int off);
103 static void bigread(int l, char rec[]);
104 static int gcomd(struct Comd *p, int k);
105 static int fcomd(struct Comd *p);
106 static void ecomd();
107 static int kcomd(struct Comd *p);
108 static int xncomd(struct Comd *p);
109 static int pcomd(struct Comd *p);
110 static int qcomd();
111 static int xcomds(struct Comd *p);
112 static int xbcomd(struct Comd *p);
113 static int xccomd(struct Comd *p);
114 static int xfcomd(struct Comd *p);
115 static int xocomd(struct Comd *p);
116 static int xtcomd(struct Comd *p);
117 static int xvcomd();
118 static int wcomd(struct Comd *p);
119 static int nlcomd(struct Comd *p);
120 static int eqcomd(struct Comd *p);
121 static int colcomd(struct Comd *p);
122 static int excomd();
123 static int xcomdlist(struct Comd *p);
124 static int defaults(struct Comd *p, int prt, int max,
125 		    int def1, int def2, int setdot, int errsok);
126 static int getcomd(struct Comd *p, int prt);
127 static int getadrs(struct Comd *p, int prt);
128 static int getadr(struct Comd *p, int prt);
129 static int getnumb(struct Comd *p, int prt);
130 static int rdnumb(int prt);
131 static int getrel(struct Comd *p, int prt);
132 static int getmark(struct Comd *p, int prt);
133 static int getrex(struct Comd *p, int prt, char c);
134 static int hunt(int prt, char rex[], int start, int down, int wrap, int errsok);
135 static int jump(int prt, char label[]);
136 static int getstr(int prt, char buf[], char brk, char ignr, int nonl);
137 static int regerr(int c);
138 static int err(int prt, char msg[]);
139 static char mygetc();
140 static int readc(int f, char *c);
141 static int percent(char line[256]);
142 static int newfile(int prt, char f[]);
143 static void push(int s[], int d);
144 static int pop(int s[]);
145 static int peekc();
146 static void eat();
147 static int more();
148 static void quit();
149 static void out(char *ln);
150 static char *untab(char l[]);
151 static int patoi(char *b);
152 static int equal(char *a, char *b);
153 
154 int
main(int argc,char * argv[])155 main(int argc, char *argv[])
156 {
157 	struct Comd comdstruct, *p;
158 	(void) setlocale(LC_ALL, "");
159 	if (argc < 2 || argc > 3) {
160 		(void) err(1, "arg count");
161 		quit();
162 	}
163 	mark = markarray-'a';
164 	if (argc == 3) {
165 		verbose = 0;
166 	}
167 	setbuf(stdout, 0);
168 	if (bigopen(bigfile = argv[argc-1]))
169 		quit();
170 	tty = isatty(0);
171 	p = &comdstruct;
172 	/* Look for 0 or more non-'%' char followed by a '%' */
173 	perbuf = compile("[^%]*%", (char *)0, (char *)0);
174 	if (regerrno)
175 		(void) regerr(regerrno);
176 	(void) setjmp(env);
177 #if defined(__STDC__)
178 	(void) signal(SIGINT, (void (*)(int))reset);
179 #else
180 	(void) signal(SIGINT, reset);
181 #endif
182 	(void) err(0, "");
183 	(void) printf("\n");
184 	flag = 0;
185 	prompt = 0;
186 	/*CONSTCOND*/	for (;;)
187 		begin(p);
188 
189 	/* NOTREACHED */
190 	return (0);
191 }
192 
193 static void
reset()194 reset()		/* for longjmp on signal */
195 {
196 	longjmp(env, 1);
197 }
198 
199 static void
begin(struct Comd * p)200 begin(struct Comd *p)
201 {
202 	char line[256];
203 	strtagn:
204 	if (flag == 0)
205 		eat();
206 	if (infildes != 100) {
207 		if (infildes == 0 && prompt)
208 			(void) printf("*");
209 		flag3 = 1;
210 		if (getstr(1, line, 0, 0, 0))
211 			exit(1);
212 		flag3 = 0;
213 		if (percent(line) < 0)
214 			goto strtagn;
215 		(void) newfile(1, "");
216 	}
217 	if (!(getcomd(p, 1) < 0)) {
218 		switch (p->Cop) {
219 		case 'e':
220 			if (!flag)
221 				ecomd();
222 			else
223 				(void) err(0, "");
224 			break;
225 
226 		case 'f':
227 			(void) fcomd(p);
228 			break;
229 
230 		case 'g':
231 			if (flag == 0)
232 				(void) gcomd(p, 1);
233 			else
234 				(void) err(0, "");
235 			break;
236 
237 		case 'k':
238 			(void)  kcomd(p);
239 			break;
240 
241 		case 'p':
242 			(void) pcomd(p);
243 			break;
244 
245 		case 'q':
246 			(void) qcomd();
247 			break;
248 
249 		case 'v':
250 			if (flag == 0)
251 				(void) gcomd(p, 0);
252 			else
253 				(void) err(0, "");
254 			break;
255 
256 		case 'x':
257 			if (!flag)
258 				(void) xcomds(p);
259 			else
260 				(void) err(0, "");
261 			break;
262 
263 		case 'w':
264 			(void) wcomd(p);
265 			break;
266 
267 		case '\n':
268 			(void)  nlcomd(p);
269 			break;
270 
271 		case '=':
272 			(void) eqcomd(p);
273 			break;
274 
275 		case ':':
276 			(void) colcomd(p);
277 			break;
278 
279 		case '!':
280 			(void) excomd();
281 			break;
282 
283 		case 'P':
284 			prompt = !prompt;
285 			break;
286 
287 		default:
288 			if (flag)
289 				(void) err(0, "");
290 			else
291 				(void) err(1, "bad command");
292 			break;
293 		}
294 	}
295 }
296 
297 static int
bigopen(char file[])298 bigopen(char file[])
299 {
300 	int l, off, cnt;
301 	int blk, newline, n, s;
302 	char block[512];
303 	size_t totsiz;
304 	BRKTYP *tptr;
305 	if ((txtfd = open(file, 0)) < 0)
306 		return (err(1, "can't open"));
307 	blk = -1;
308 	newline = 1;
309 	l = cnt = s = 0;
310 	off = 512;
311 	totsiz = 0;
312 	if ((lincnt = (BRKTYP *)malloc(BRKSIZ)) == (BRKTYP *)NULL)
313 		return (err(1, "too many lines"));
314 	endds = (BRKTYP *)lincnt;
315 	totsiz += BRKSIZ;
316 	while ((n = read(txtfd, block, 512)) > 0) {
317 		blk++;
318 		for (off = 0; off < n; off++) {
319 			if (newline) {
320 				newline = 0;
321 				if (l > 0 && !(l&07777)) {
322 					totsiz += BRKSIZ;
323 					tptr = (BRKTYP *)
324 					    realloc(lincnt, totsiz);
325 					if (tptr == NULL)
326 						return
327 						    (err(1, "too many lines"));
328 					else
329 						lincnt = tptr;
330 				}
331 				lincnt[l] = (char)cnt;
332 				cnt = 0;
333 				if (!(l++ & 077)) {
334 					segblk[s] = blk;
335 					segoff[s++] = off;
336 				}
337 				if (l < 0 || l > 32767)
338 					return (err(1, "too many lines"));
339 			}
340 			if (block[off] == '\n') newline = 1;
341 			cnt++;
342 		}
343 	}
344 	if (!(l&07777)) {
345 		totsiz += BRKTWO;
346 		tptr = (BRKTYP *)realloc(lincnt, totsiz);
347 		if (tptr == NULL)
348 			return (err(1, "too many lines"));
349 		else
350 			lincnt = tptr;
351 	}
352 	lincnt[Dot = Dollar = l] = (char)cnt;
353 	sizeprt(blk, off);
354 	return (0);
355 }
356 
357 static void
sizeprt(int blk,int off)358 sizeprt(int blk, int off)
359 {
360 	if (verbose)
361 		(void) printf("%.0f", 512.*blk+off);
362 }
363 
364 static int saveblk = -1;
365 
366 static void
bigread(int l,char rec[])367 bigread(int l, char rec[])
368 {
369 	int i;
370 	char *r, *b;
371 	int off;
372 	static char savetxt[512];
373 
374 	if ((i = l-lprev) == 1) prevoff += lincnt[lprev]BFSAND;
375 	else if (i >= 0 && i <= 32)
376 		for (i = lprev; i < l; i++) prevoff += lincnt[i]BFSAND;
377 	else if (i < 0 && i >= -32)
378 		for (i = lprev-1; i >= l; i--) prevoff -= lincnt[i]BFSAND;
379 	else {
380 		prevblk = segblk[i = (l-1)>>6];
381 		prevoff = segoff[i];
382 		for (i = (i<<6)+1; i < l; i++) prevoff += lincnt[i]BFSAND;
383 	}
384 
385 	prevblk += prevoff>>9;
386 	prevoff &= 0777;
387 	lprev = l;
388 	if (prevblk != saveblk) {
389 		(void) lseek(txtfd, ((long)(saveblk = prevblk))<<9, 0);
390 		(void) read(txtfd, savetxt, 512);
391 	}
392 	r = rec;
393 	off = prevoff;
394 	/*CONSTCOND*/while (1) {
395 		for (b = savetxt+off; b < savetxt+512; b++) {
396 			if ((*r++ = *b) == '\n') {
397 				*(r-1) = '\0';
398 				return;
399 			}
400 			if (((unsigned)r - (unsigned)rec) > BFSLIM) {
401 
402 				(void) write(2,
403 				    "Line too long--output truncated\n", 32);
404 				return;
405 			}
406 		}
407 		(void) read(txtfd, savetxt, 512);
408 		off = 0;
409 		saveblk++;
410 	}
411 }
412 
413 static void
ecomd()414 ecomd()
415 {
416 	int i = 0;
417 	while (peekc() == ' ')
418 		(void) mygetc();
419 	while ((fle[i++] = mygetc()) != '\n');
420 	fle[--i] = '\0';
421 	/* Without this, ~20 "e" cmds gave "can't open" msg. */
422 	(void) close(txtfd);
423 	free(endds);
424 	/* Reset parameters. */
425 	lprev = 1;
426 	prevblk = 0;
427 	prevoff = 0;
428 	saveblk = -1;
429 	if (bigopen(bigfile  = fle))
430 		quit();
431 	(void) printf("\n");
432 }
433 
434 static int
fcomd(struct Comd * p)435 fcomd(struct Comd *p)
436 {
437 	if (more() || defaults(p, 1, 0, 0, 0, 0, 0))
438 		return (-1);
439 	(void) printf("%s\n", bigfile);
440 	return (0);
441 }
442 
443 static int
gcomd(struct Comd * p,int k)444 gcomd(struct Comd *p, int k)
445 {
446 	char d;
447 	int i, end;
448 	char line[BFSBUF];
449 	if (defaults(p, 1, 2, 1, Dollar, 0, 0))
450 		return (-1);
451 	if ((d = mygetc()) == '\n')
452 		return (err(1, "syntax"));
453 	if (peekc() == d)
454 		(void) mygetc();
455 	else
456 		if (getstr(1, currex, d, 0, 1))
457 			return (-1);
458 	glbuf = compile(currex, (char *)0, (char *)0);
459 	if (regerrno) {
460 		(void) regerr(regerrno);
461 		return (-1);
462 	} else {
463 		if (glbuf)
464 			free(glbuf);
465 	}
466 
467 	if (getstr(1, comdlist, 0, 0, 0))
468 		return (-1);
469 	i = p->Cadr[0];
470 	end = p->Cadr[1];
471 	while (i <= end) {
472 		bigread(i, line);
473 		if (!(step(line, glbuf))) {
474 			if (!k) {
475 				Dot = i;
476 				if (xcomdlist(p))
477 					return (err(1, "bad comd list"));
478 			}
479 			i++;
480 		} else {
481 			if (k) {
482 				Dot = i;
483 				if (xcomdlist(p))
484 					return (err(1, "bad comd list"));
485 			}
486 			i++;
487 		}
488 	}
489 	return (0);
490 }
491 
492 static int
kcomd(struct Comd * p)493 kcomd(struct Comd *p)
494 {
495 	char c;
496 	if ((c = peekc()) < 'a' || c > 'z')
497 		return (err(1, "bad mark"));
498 	(void) mygetc();
499 	if (more() || defaults(p, 1, 1, Dot, 0, 1, 0))
500 		return (-1);
501 	mark[c] = Dot = p->Cadr[0];
502 	return (0);
503 }
504 
505 static int
xncomd(struct Comd * p)506 xncomd(struct Comd *p)
507 {
508 	char c;
509 	if (more() || defaults(p, 1, 0, 0, 0, 0, 0))
510 		return (-1);
511 
512 	for (c = 'a'; c <= 'z'; c++)
513 		if (mark[c])
514 			(void) printf("%c\n", c);
515 
516 	return (0);
517 }
518 
519 static int
pcomd(struct Comd * p)520 pcomd(struct Comd *p)
521 {
522 	int i;
523 	char line[BFSBUF];
524 	if (more() || defaults(p, 1, 2, Dot, Dot, 1, 0))
525 		return (-1);
526 	for (i = p->Cadr[0]; i <= p->Cadr[1] && i > 0; i++) {
527 		bigread(i, line);
528 		out(line);
529 	}
530 	return (0);
531 }
532 
533 static int
qcomd()534 qcomd()
535 {
536 	if (more())
537 		return (-1);
538 	quit();
539 	return (0);
540 }
541 
542 static int
xcomds(struct Comd * p)543 xcomds(struct Comd *p)
544 {
545 	switch (mygetc()) {
546 	case 'b':	return (xbcomd(p));
547 	case 'c':	return (xccomd(p));
548 	case 'f':	return (xfcomd(p));
549 	case 'n':	return (xncomd(p));
550 	case 'o':	return (xocomd(p));
551 	case 't':	return (xtcomd(p));
552 	case 'v':	return (xvcomd());
553 	default:	return (err(1, "bad command"));
554 	}
555 }
556 
557 static int
xbcomd(struct Comd * p)558 xbcomd(struct Comd *p)
559 {
560 	int fail,  n;
561 	char d;
562 	char str[50];
563 
564 	fail = 0;
565 	if (defaults(p, 0, 2, Dot, Dot, 0, 1))
566 		fail = 1;
567 	else {
568 		if ((d = mygetc()) == '\n')
569 			return (err(1, "syntax"));
570 		if (d == 'z') {
571 			if (status[0] != 0)
572 				return (0);
573 			(void) mygetc();
574 			if (getstr(1, str, 0, 0, 0))
575 				return (-1);
576 			return (jump(1, str));
577 		}
578 		if (d == 'n') {
579 			if (status[0] == 0)
580 				return (0);
581 			(void) mygetc();
582 			if (getstr(1, str, 0, 0, 0))
583 				return (-1);
584 			return (jump(1, str));
585 		}
586 		if (getstr(1, str, d, ' ', 0))
587 			return (-1);
588 		if ((n = hunt(0, str, p->Cadr[0]-1, 1, 0, 1)) < 0)
589 			fail = 1;
590 		if (getstr(1, str, 0, 0, 0))
591 			return (-1);
592 		if (more())
593 			return (err(1, "syntax"));
594 	}
595 	if (!fail) {
596 		Dot = n;
597 		return (jump(1, str));
598 	}
599 	return (0);
600 }
601 
602 static int
xccomd(struct Comd * p)603 xccomd(struct Comd *p)
604 {
605 	char arg[100];
606 	if (getstr(1, arg, 0, ' ', 0) || defaults(p, 1, 0, 0, 0, 0, 0))
607 		return (-1);
608 	if (equal(arg, ""))
609 		crunch = -crunch;
610 	else if (equal(arg, "0"))
611 		crunch = -1;
612 	else if (equal(arg, "1"))
613 		crunch = 1;
614 	else
615 		return (err(1, "syntax"));
616 
617 	return (0);
618 }
619 
620 static int
xfcomd(struct Comd * p)621 xfcomd(struct Comd *p)
622 {
623 	char fl[100];
624 	char *f;
625 	if (defaults(p, 1, 0, 0, 0, 0, 0))
626 		return (-1);
627 
628 	while (peekc() == ' ')
629 		(void) mygetc();
630 	for (f = fl; (*f = mygetc()) != '\n'; f++);
631 	if (f == fl)
632 		return (err(1, "no file"));
633 	*f = '\0';
634 
635 	return (newfile(1, fl));
636 }
637 
638 static int
xocomd(struct Comd * p)639 xocomd(struct Comd *p)
640 {
641 	int fd;
642 	char arg[100];
643 
644 	if (getstr(1, arg, 0, ' ', 0) || defaults(p, 1, 0, 0, 0, 0, 0))
645 		return (-1);
646 
647 	if (!arg[0]) {
648 		if (outfildes == 1)
649 			return (err(1, "no diversion"));
650 		(void) close(outfildes);
651 		outfildes = 1;
652 	} else {
653 		if (outfildes != 1)
654 			return (err(1, "already diverted"));
655 		if ((fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC,
656 		    (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH))) < 0)
657 			return (err(1, "can't create"));
658 		outfildes = fd;
659 	}
660 	return (0);
661 }
662 
663 static int
xtcomd(struct Comd * p)664 xtcomd(struct Comd *p)
665 {
666 	int t;
667 
668 	while (peekc() == ' ')
669 		(void) mygetc();
670 	if ((t = rdnumb(1)) < 0 || more() || defaults(p, 1, 0, 0, 0, 0, 0))
671 		return (-1);
672 
673 	trunc = t;
674 	return (0);
675 }
676 
677 static int
xvcomd()678 xvcomd()
679 {
680 	char c;
681 	int i;
682 	int temp0, temp1, temp2;
683 	int fildes[2];
684 
685 	if ((c = peekc()) < '0' || c > '9')
686 		return (err(1, "digit required"));
687 	(void) mygetc();
688 	c -= '0';
689 	while (peekc() == ' ')
690 		(void) mygetc();
691 	if (peekc() == '\\')
692 		(void) mygetc();
693 	else if (peekc()  ==  '!') {
694 		if (pipe(fildes) < 0) {
695 			(void) printf("Try again");
696 			return (-1);
697 		}
698 		temp0 = dup(0);
699 		temp1 = dup(1);
700 		temp2 = infildes;
701 		(void) close(0);
702 		(void) dup(fildes[0]);
703 		(void) close(1);
704 		(void) dup(fildes[1]);
705 		(void) close(fildes[0]);
706 		(void) close(fildes[1]);
707 		(void) mygetc();
708 		flag4 = 1;
709 		(void) excomd();
710 		(void) close(1);
711 		infildes = 0;
712 	}
713 	for (i = 0; (varray[c][i] = mygetc()) != '\n'; i++);
714 	varray[c][i] = '\0';
715 	if (flag4) {
716 		infildes = temp2;
717 		(void) close(0);
718 		(void) dup(temp0);
719 		(void) close(temp0);
720 		(void) dup(temp1);
721 		(void) close(temp1);
722 		flag4 = 0;
723 		charbuf = ' ';
724 	}
725 	return (0);
726 }
727 
728 static int
wcomd(struct Comd * p)729 wcomd(struct Comd *p)
730 {
731 	int i, fd, savefd;
732 	int savecrunch, savetrunc;
733 	char arg[100], line[BFSBUF];
734 
735 	if (getstr(1, arg, 0, ' ', 0) || defaults(p, 1, 2, 1, Dollar, 1, 0))
736 		return (-1);
737 	if (!arg[0])
738 		return (err(1, "no file name"));
739 	if (equal(arg, bigfile))
740 		return (err(1, "no change indicated"));
741 	if ((fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC,
742 	    (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)))  < 0)
743 		return (err(1, "can't create"));
744 
745 	savefd = outfildes;
746 	savetrunc = trunc;
747 	savecrunch = crunch;
748 	outfildes = fd;
749 	trunc = BFSTRU;
750 	crunch = -1;
751 
752 	outcnt = 0;
753 	for (i = p->Cadr[0]; i <= p->Cadr[1] && i > 0; i++) {
754 		bigread(i, line);
755 		out(line);
756 	}
757 	if (verbose)
758 		(void) printf("%.0f\n", outcnt);
759 	(void) close(fd);
760 
761 	outfildes = savefd;
762 	trunc = savetrunc;
763 	crunch = savecrunch;
764 	return (0);
765 }
766 
767 static int
nlcomd(struct Comd * p)768 nlcomd(struct Comd *p)
769 {
770 	if (defaults(p, 1, 2, Dot+1, Dot+1, 1, 0)) {
771 		(void) mygetc();
772 		return (-1);
773 	}
774 	return (pcomd(p));
775 }
776 
777 static int
eqcomd(struct Comd * p)778 eqcomd(struct Comd *p)
779 {
780 	if (more() || defaults(p, 1, 1, Dollar, 0, 0, 0))
781 		return (-1);
782 	(void) printf("%d\n", p->Cadr[0]);
783 	return (0);
784 }
785 
786 static int
colcomd(struct Comd * p)787 colcomd(struct Comd *p)
788 {
789 	return (defaults(p, 1, 0, 0, 0, 0, 0));
790 }
791 
792 static int
xcomdlist(struct Comd * p)793 xcomdlist(struct Comd *p)
794 {
795 	flag = 1;
796 	flag2 = 1;
797 	(void) newfile(1, "");
798 	while (flag2)
799 		begin(p);
800 	if (flag == 0)
801 		return (1);
802 	flag = 0;
803 	return (0);
804 }
805 
806 static int
excomd()807 excomd()
808 {
809 	pid_t i;
810 	int j;
811 	if (infildes != 100)
812 		charbuf = '\n';
813 	while ((i = fork()) < (pid_t)0)
814 		(void) sleep(10);
815 	if (i == (pid_t)0) {
816 		/* Guarantees child can be intr. */
817 		(void) signal(SIGINT, SIG_DFL);
818 		if (infildes == 100 || flag4) {
819 			(void) execl("/usr/bin/sh", "sh", "-c", intptr, 0);
820 			exit(0);
821 		}
822 		if (infildes != 0) {
823 			(void) close(0);
824 			(void) dup(infildes);
825 		}
826 		for (j = 3; j < 15; j++) (void) close(j);
827 		(void) execl("/usr/bin/sh", "sh", "-t", 0);
828 		exit(0);
829 	}
830 	(void) signal(SIGINT, SIG_IGN);
831 	while (wait(status) != i);
832 	status[0] = status[0] >> 8;
833 
834 #if defined(__STDC__)
835 	(void) signal(SIGINT, (void (*)(int))reset);
836 #else
837 	(void) signal(SIGINT, reset);	/* Restore signal to previous status */
838 #endif
839 
840 	if (((infildes == 0) || ((infildes  == 100) &&
841 	    (fstack[fstack[0]] == 0)))&& verbose && (!flag4))
842 		(void) printf("!\n");
843 	return (0);
844 }
845 
846 static int
defaults(struct Comd * p,int prt,int max,int def1,int def2,int setdot,int errsok)847 defaults(struct Comd *p, int prt, int max,
848     int def1, int def2, int setdot, int errsok)
849 {
850 	if (!def1)
851 		def1 = Dot;
852 	if (!def2)
853 		def2 = def1;
854 	if (p->Cnumadr >= max)
855 		return (errsok?-1:err(prt, "adr count"));
856 	if (p->Cnumadr < 0) {
857 		p->Cadr[++p->Cnumadr] = def1;
858 		p->Cadr[++p->Cnumadr] = def2;
859 	} else if (p->Cnumadr < 1)
860 		p->Cadr[++p->Cnumadr] = p->Cadr[0];
861 	if (p->Cadr[0] < 1 || p->Cadr[0] > Dollar ||
862 	    p->Cadr[1] < 1 || p->Cadr[1] > Dollar)
863 		return (errsok?-1:err(prt, "range"));
864 	if (p->Cadr[0] > p->Cadr[1])
865 		return (errsok?-1:err(prt, "adr1 > adr2"));
866 	if (setdot)
867 		Dot = p->Cadr[1];
868 	return (0);
869 }
870 
871 static int
getcomd(struct Comd * p,int prt)872 getcomd(struct Comd *p, int prt)
873 {
874 	int r;
875 	int c;
876 
877 	p->Cnumadr = -1;
878 	p->Csep = ' ';
879 	switch (c = peekc()) {
880 	case ',':
881 	case ';':	p->Cop = mygetc();
882 		return (0);
883 	}
884 
885 	if ((r = getadrs(p, prt)) < 0)
886 		return (r);
887 
888 	if ((c = peekc()) < 0)
889 		return (err(prt, "syntax"));
890 	if (c == '\n')
891 		p->Cop = '\n';
892 	else
893 		p->Cop = mygetc();
894 
895 	return (0);
896 }
897 
898 static int
getadrs(struct Comd * p,int prt)899 getadrs(struct Comd *p, int prt)
900 {
901 	int r;
902 	char c;
903 
904 	if ((r = getadr(p, prt)) < 0)
905 		return (r);
906 
907 	switch (c = peekc()) {
908 		case ';':
909 			Dot = p->Cadr[0];
910 			(void) mygetc();
911 			p->Csep = c;
912 			return (getadr(p, prt));
913 		case ',':
914 			(void) mygetc();
915 			p->Csep = c;
916 			return (getadr(p, prt));
917 		}
918 
919 	return (0);
920 }
921 
922 static int
getadr(struct Comd * p,int prt)923 getadr(struct Comd *p, int prt)
924 {
925 	int r;
926 	char c;
927 
928 	r = 0;
929 	while (peekc() == ' ')
930 		(void) mygetc();	/* Ignore leading spaces */
931 	switch (c = peekc()) {
932 		case '\n':
933 		case ',':
934 		case ';':	return (0);
935 		case '\'':	(void) mygetc();
936 			r = getmark(p, prt);
937 			break;
938 
939 		case '0':
940 		case '1':
941 		case '2':
942 		case '3':
943 		case '4':
944 		case '5':
945 		case '6':
946 		case '7':
947 		case '8':
948 		case '9':	r = getnumb(p, prt);
949 			break;
950 		case '.':	(void) mygetc();
951 			p->Cadr[++p->Cnumadr] = Dot;
952 			break;
953 		case '+':
954 		case '-':	p->Cadr[++p->Cnumadr] = Dot;
955 			break;
956 		case '$':	(void) mygetc();
957 			p->Cadr[++p->Cnumadr] = Dollar;
958 			break;
959 		case '^':	(void) mygetc();
960 			p->Cadr[++p->Cnumadr] = Dot - 1;
961 			break;
962 		case '/':
963 		case '?':
964 		case '>':
965 		case '<':	(void) mygetc();
966 			r = getrex(p, prt, c);
967 			break;
968 		default:	return (0);
969 		}
970 
971 	if (r == 0)
972 		r = getrel(p, prt);
973 	return (r);
974 }
975 
976 static int
getnumb(struct Comd * p,int prt)977 getnumb(struct Comd *p, int prt)
978 {
979 	int i;
980 
981 	if ((i = rdnumb(prt)) < 0)
982 		return (-1);
983 	p->Cadr[++p->Cnumadr] = i;
984 	return (0);
985 }
986 
987 static int
rdnumb(int prt)988 rdnumb(int prt)
989 {
990 	char num[20],  *n;
991 	int i;
992 
993 	n = num;
994 	while ((*n = peekc()) >= '0' && *n <= '9') {
995 		n++;
996 		(void) mygetc();
997 	}
998 
999 	*n = '\0';
1000 	if ((i = patoi(num)) >= 0)
1001 		return (i);
1002 	return (err(prt, "bad num"));
1003 }
1004 
1005 static int
getrel(struct Comd * p,int prt)1006 getrel(struct Comd *p, int prt)
1007 {
1008 	int op, n;
1009 	char c;
1010 	int j;
1011 
1012 	n = 0;
1013 	op = 1;
1014 	while ((c = peekc()) == '+' || c == '-') {
1015 		if (c == '+')
1016 			n++;
1017 		else
1018 			n--;
1019 		(void) mygetc();
1020 	}
1021 	j = n;
1022 	if (n < 0)
1023 		op = -1;
1024 	if (c == '\n')
1025 		p->Cadr[p->Cnumadr] += n;
1026 	else {
1027 		if ((n = rdnumb(0)) > 0 && p->Cnumadr >= 0) {
1028 			p->Cadr[p->Cnumadr] += op*n;
1029 			(void) getrel(p, prt);
1030 		} else {
1031 			p->Cadr[p->Cnumadr] += j;
1032 		}
1033 	}
1034 	return (0);
1035 }
1036 
1037 static int
getmark(struct Comd * p,int prt)1038 getmark(struct Comd *p, int prt)
1039 {
1040 	char c;
1041 
1042 	if ((c = peekc()) < 'a' || c > 'z')
1043 		return (err(prt, "bad mark"));
1044 	(void) mygetc();
1045 
1046 	if (!mark[c])
1047 		return (err(prt, "undefined mark"));
1048 	p->Cadr[++p->Cnumadr] = mark[c];
1049 	return (0);
1050 }
1051 
1052 static int
getrex(struct Comd * p,int prt,char c)1053 getrex(struct Comd *p, int prt, char c)
1054 {
1055 	int down, wrap, start;
1056 
1057 	if (peekc() == c)
1058 		(void) mygetc();
1059 	else if (getstr(prt, currex, c, 0, 1))
1060 		return (-1);
1061 
1062 	switch (c) {
1063 	case '/':	down = 1; wrap = 1; break;
1064 	case '?':	down = 0; wrap = 1; break;
1065 	case '>':	down = 1; wrap = 0; break;
1066 	case '<':	down = 0; wrap = 0; break;
1067 	}
1068 
1069 	if (p->Csep == ';')
1070 		start = p->Cadr[0];
1071 	else
1072 		start = Dot;
1073 
1074 	if ((p->Cadr[++p->Cnumadr] = hunt(prt, currex, start, down, wrap, 0))
1075 	    < 0)
1076 		return (-1);
1077 	return (0);
1078 }
1079 
1080 static int
hunt(int prt,char rex[],int start,int down,int wrap,int errsok)1081 hunt(int prt, char rex[], int start, int down, int wrap, int errsok)
1082 {
1083 	int i, end1, incr;
1084 	int start1, start2;
1085 	char line[BFSBUF];
1086 
1087 	if (down) {
1088 		start1 = start + 1;
1089 		end1 = Dollar;
1090 		start2 = 1;
1091 		incr = 1;
1092 	} else {
1093 		start1 = start  - 1;
1094 		end1 = 1;
1095 		start2 = Dollar;
1096 		incr = -1;
1097 	}
1098 
1099 	rebuf = compile(rex, (char *)0, (char *)0);
1100 	if (regerrno)
1101 		(void) regerr(regerrno);
1102 	else
1103 		if (rebuf)
1104 			free(rebuf);
1105 
1106 	for (i = start1; i != end1+incr; i += incr) {
1107 		bigread(i, line);
1108 		if (step(line, rebuf)) {
1109 			return (i);
1110 		}
1111 	}
1112 
1113 	if (!wrap)
1114 		return (errsok?-1:err(prt, "not found"));
1115 
1116 	for (i = start2; i != start1; i += incr) {
1117 		bigread(i, line);
1118 		if (step(line, rebuf)) {
1119 			return (i);
1120 		}
1121 	}
1122 
1123 	return (errsok?-1:err(prt, "not found"));
1124 }
1125 
1126 static int
jump(int prt,char label[])1127 jump(int prt, char label[])
1128 {
1129 	char *l;
1130 	char line[256];
1131 
1132 	if (infildes == 0 && tty)
1133 		return (err(prt, "jump on tty"));
1134 	if (infildes == 100)
1135 		intptr = internal;
1136 	else
1137 		(void) lseek(infildes, 0L, 0);
1138 
1139 	(void) snprintf(strtmp,
1140 	    sizeof (strtmp) * sizeof (char), "^: *%s$", label);
1141 	rebuf = compile(strtmp, (char *)0, (char *)0);
1142 	if (regerrno) {
1143 		(void) regerr(regerrno);
1144 		return (-1);
1145 	}
1146 
1147 	for (l = line; readc(infildes, l); l++) {
1148 		if (*l == '\n') {
1149 			*l = '\0';
1150 			if (step(line, rebuf)) {
1151 				charbuf = '\n';
1152 				return (peeked = 0);
1153 			}
1154 			l = line - 1;
1155 		}
1156 	}
1157 
1158 	return (err(prt, "label not found"));
1159 }
1160 
1161 static int
getstr(int prt,char buf[],char brk,char ignr,int nonl)1162 getstr(int prt, char buf[], char brk, char ignr, int nonl)
1163 {
1164 	char *b, c, prevc;
1165 
1166 	prevc = 0;
1167 	for (b = buf; c = peekc(); prevc = c) {
1168 		if (c == '\n') {
1169 			if (prevc == '\\' && (!flag3)) *(b-1) = mygetc();
1170 			else if (prevc == '\\' && flag3) {
1171 				*b++ = mygetc();
1172 			} else if (nonl)
1173 				break;
1174 			else
1175 				return (*b = '\0');
1176 		} else {
1177 			(void) mygetc();
1178 			if (c == brk) {
1179 				if (prevc == '\\') *(b-1) = c;
1180 				else return (*b = '\0');
1181 			} else if (b != buf || c != ignr) *b++ = c;
1182 		}
1183 	}
1184 	return (err(prt, "syntax"));
1185 }
1186 
1187 static int
regerr(int c)1188 regerr(int c)
1189 {
1190 	if (prompt) {
1191 		switch (c) {
1192 		case 11: (void) printf("Range endpoint too large.\n");
1193 			break;
1194 		case 16: (void) printf("Bad number.\n");
1195 			break;
1196 		case 25: (void) printf("``\\digit'' out of range.\n");
1197 			break;
1198 		case 41: (void) printf("No remembered search string.\n");
1199 			break;
1200 		case 42: (void) printf("() imbalance.\n");
1201 			break;
1202 		case 43: (void) printf("Too many (.\n");
1203 			break;
1204 		case 44: (void) printf("More than 2 numbers given in { }.\n");
1205 			break;
1206 		case 45: (void) printf("} expected after \\.\n");
1207 			break;
1208 		case 46: (void) printf("First number exceeds second in { }.\n");
1209 			break;
1210 		case 49: (void) printf("[] imbalance.\n");
1211 			break;
1212 		case 50: (void) printf("Regular expression overflow.\n");
1213 			break;
1214 		case 67: (void) printf("Illegal byte sequence.\n");
1215 			break;
1216 		default: (void) printf("RE error.\n");
1217 			break;
1218 		}
1219 	} else {
1220 		(void) printf("?\n");
1221 	}
1222 	return (-1);
1223 }
1224 
1225 static int
err(int prt,char msg[])1226 err(int prt, char msg[])
1227 {
1228 	if (prt) (prompt? (void) printf("%s\n", msg): (void) printf("?\n"));
1229 	if (infildes != 0) {
1230 		infildes = pop(fstack);
1231 		charbuf = '\n';
1232 		peeked = 0;
1233 		flag3 = 0;
1234 		flag2 = 0;
1235 		flag = 0;
1236 	}
1237 	return (-1);
1238 }
1239 
1240 static char
mygetc()1241 mygetc()
1242 {
1243 	if (!peeked) {
1244 		while ((!(infildes == oldfd && flag)) && (!flag1) &&
1245 		    (!readc(infildes, &charbuf))) {
1246 			if (infildes == 100 && (!flag)) flag1 = 1;
1247 			if ((infildes = pop(fstack)) == -1) quit();
1248 			if ((!flag1) && infildes == 0 && flag3 && prompt)
1249 				(void) printf("*");
1250 		}
1251 		if (infildes == oldfd && flag) flag2 = 0;
1252 		flag1 = 0;
1253 	} else peeked = 0;
1254 	return (charbuf);
1255 }
1256 
1257 static int
readc(int f,char * c)1258 readc(int f, char *c)
1259 {
1260 	if (f == 100) {
1261 		if (!(*c = *intptr++)) {
1262 			intptr--;
1263 			charbuf = '\n';
1264 			return (0);
1265 		}
1266 	} else if (read(f, c, 1) != 1) {
1267 		(void) close(f);
1268 		charbuf = '\n';
1269 		return (0);
1270 	}
1271 	return (1);
1272 }
1273 
1274 static int
percent(char line[256])1275 percent(char line[256])
1276 {
1277 	char *lp, *var;
1278 	char *front, *per, c[2], *olp, p[2], fr[256];
1279 	int i, j;
1280 
1281 	per = p;
1282 	var = c;
1283 	front = fr;
1284 	j = 0;
1285 	while (!j) {
1286 		j = 1;
1287 		olp = line;
1288 		intptr = internal;
1289 		while (step(olp, perbuf)) {
1290 			while (loc1 < loc2) *front++ = *loc1++;
1291 			*(--front) = '\0';
1292 			front = fr;
1293 			*per++ = '%';
1294 			*per = '\0';
1295 			per = p;
1296 			*var = *loc2;
1297 			if ((i = 1 + strlen(front)) >= 2 && fr[i-2] == '\\') {
1298 				(void) strcat(front, "");
1299 				--intptr;
1300 				(void) strcat(per, "");
1301 			} else {
1302 				if (!(*var >= '0' && *var <= '9'))
1303 					return (err(1, "usage: %digit"));
1304 				(void) strcat(front, "");
1305 				(void) strcat(varray[*var-'0'], "");
1306 				j  = 0;
1307 				loc2++;	/* Compensate for removing --lp above */
1308 			}
1309 			olp = loc2;
1310 		}
1311 		(void) strcat(olp, "");
1312 		*intptr = '\0';
1313 		if (!j) {
1314 			intptr = internal;
1315 			lp = line;
1316 			(void)
1317 			    strncpy(intptr, lp, sizeof (intptr)*sizeof (char));
1318 		}
1319 	}
1320 	return (0);
1321 }
1322 
1323 static int
newfile(int prt,char f[])1324 newfile(int prt, char f[])
1325 {
1326 	int fd;
1327 
1328 	if (!*f) {
1329 		if (flag != 0) {
1330 			oldfd = infildes;
1331 			intptr = comdlist;
1332 		} else intptr = internal;
1333 		fd = 100;
1334 	} else if ((fd = open(f, 0)) < 0) {
1335 		(void) snprintf(strtmp, sizeof (strtmp) * sizeof (char),
1336 		    "cannot open %s", f);
1337 		return (err(prt, strtmp));
1338 	}
1339 
1340 	push(fstack, infildes);
1341 	if (flag4) oldfd = fd;
1342 	infildes = fd;
1343 	return (peeked = 0);
1344 }
1345 
1346 static void
push(int s[],int d)1347 push(int s[], int d)
1348 {
1349 	s[++s[0]] = d;
1350 }
1351 
1352 static int
pop(int s[])1353 pop(int s[])
1354 {
1355 	return (s[s[0]--]);
1356 }
1357 
1358 static int
peekc()1359 peekc()
1360 {
1361 	int c;
1362 
1363 	c = mygetc();
1364 	peeked = 1;
1365 
1366 	return (c);
1367 }
1368 
1369 static void
eat()1370 eat()
1371 {
1372 	if (charbuf != '\n')
1373 		while (mygetc() != '\n');
1374 	peeked = 0;
1375 }
1376 
1377 static int
more()1378 more()
1379 {
1380 	if (mygetc() != '\n')
1381 		return (err(1, "syntax"));
1382 	return (0);
1383 }
1384 
1385 static void
quit()1386 quit()
1387 {
1388 	exit(0);
1389 }
1390 
1391 static void
out(char * ln)1392 out(char *ln)
1393 {
1394 	char *rp, *wp, prev;
1395 	int w, width;
1396 	char *oldrp;
1397 	wchar_t cl;
1398 	int p;
1399 	ptrdiff_t lim;
1400 	if (crunch > 0) {
1401 
1402 		ln = untab(ln);
1403 		rp = wp = ln - 1;
1404 		prev = ' ';
1405 
1406 		while (*++rp) {
1407 			if (prev != ' ' || *rp != ' ')
1408 				*++wp = *rp;
1409 			prev = *rp;
1410 		}
1411 		*++wp = '\n';
1412 		lim = (ptrdiff_t)wp - (ptrdiff_t)ln;
1413 		*++wp = '\0';
1414 
1415 		if (*ln == '\n')
1416 			return;
1417 	} else
1418 		ln[lim = strlen(ln)] = '\n';
1419 
1420 	if (MB_CUR_MAX <= 1) {
1421 		if (lim > trunc)
1422 			ln[lim = trunc] = '\n';
1423 	} else {
1424 		if ((trunc < (BFSBUF -1)) || (lim > trunc)) {
1425 			w = 0;
1426 			oldrp = rp = ln;
1427 			/*CONSTCOND*/while (1) {
1428 				if ((p = mbtowc(&cl, rp, MB_LEN_MAX)) == 0) {
1429 					break;
1430 				}
1431 				if (p == -1) {
1432 					width = p = 1;
1433 				} else {
1434 					width = scrwidth(cl);
1435 					if (width == 0)
1436 						width = 1;
1437 				}
1438 				if ((w += width) > trunc)
1439 					break;
1440 				rp += p;
1441 			}
1442 			*rp = '\n';
1443 			lim = (ptrdiff_t)rp - (ptrdiff_t)oldrp;
1444 		}
1445 	}
1446 
1447 	outcnt += write(outfildes, ln, lim+1);
1448 }
1449 
1450 static char *
untab(char l[])1451 untab(char l[])
1452 {
1453 	static char line[BFSBUF];
1454 	char *q, *s;
1455 
1456 	s = l;
1457 	q = line;
1458 	do {
1459 		if (*s == '\t')
1460 			do
1461 				*q++ = ' ';
1462 			while (((ptrdiff_t)q-(ptrdiff_t)line)%8);
1463 		else *q++ = *s;
1464 	} while (*s++);
1465 	return (line);
1466 }
1467 
1468 /*
1469  *	Function to convert ascii string to integer.  Converts
1470  *	positive numbers only.  Returns -1 if non-numeric
1471  *	character encountered.
1472  */
1473 
1474 static int
patoi(char * b)1475 patoi(char *b)
1476 {
1477 	int i;
1478 	char *a;
1479 
1480 	a = b;
1481 	i = 0;
1482 	while (*a >= '0' && *a <= '9') i = 10 * i + *a++ - '0';
1483 
1484 	if (*a)
1485 		return (-1);
1486 	return (i);
1487 }
1488 
1489 /*
1490  *	Compares 2 strings.  Returns 1 if equal, 0 if not.
1491  */
1492 
1493 static int
equal(char * a,char * b)1494 equal(char *a, char *b)
1495 {
1496 	char *x, *y;
1497 
1498 	x = a;
1499 	y = b;
1500 	while (*x == *y++)
1501 		if (*x++ == 0)
1502 			return (1);
1503 	return (0);
1504 }
1505