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 }