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 {