comparison usr/src/cmd/bfs/bfs.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
comparison
equal deleted inserted replaced
-1:000000000000 0:c9caec207d52
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 "@(#)bfs.c 1.15 05/07/26 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 {
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
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
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
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
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
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
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
1347 push(int s[], int d)
1348 {
1349 s[++s[0]] = d;
1350 }
1351
1352 static int
1353 pop(int s[])
1354 {
1355 return (s[s[0]--]);
1356 }
1357
1358 static int
1359 peekc()
1360 {
1361 int c;
1362
1363 c = mygetc();
1364 peeked = 1;
1365
1366 return (c);
1367 }
1368
1369 static void
1370 eat()
1371 {
1372 if (charbuf != '\n')
1373 while (mygetc() != '\n');
1374 peeked = 0;
1375 }
1376
1377 static int
1378 more()
1379 {
1380 if (mygetc() != '\n')
1381 return (err(1, "syntax"));
1382 return (0);
1383 }
1384
1385 static void
1386 quit()
1387 {
1388 exit(0);
1389 }
1390
1391 static void
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 *
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
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
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 }