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