Home | History | Annotate | Download | only in bfs
      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
    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
    194 reset()		/* for longjmp on signal */
    195 {
    196 	longjmp(env, 1);
    197 }
    198 
    199 static void
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    534 qcomd()
    535 {
    536 	if (more())
    537 		return (-1);
    538 	quit();
    539 	return (0);
    540 }
    541 
    542 static int
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    787 colcomd(struct Comd *p)
    788 {
    789 	return (defaults(p, 1, 0, 0, 0, 0, 0));
    790 }
    791 
    792 static int
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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
   1162 getstr(int prt, char buf[], char brk, char ignr, int nonl)
   1163 {