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 {
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 }