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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Editor 31 */ 32 33 #include <crypt.h> 34 #include <libgen.h> 35 #include <wait.h> 36 #include <string.h> 37 #include <sys/types.h> 38 #include <locale.h> 39 #include <regexpr.h> 40 #include <regex.h> 41 #include <errno.h> 42 #include <paths.h> 43 44 static const char *msgtab[] = 45 { 46 "write or open on pipe failed", /* 0 */ 47 "warning: expecting `w'", /* 1 */ 48 "mark not lower case ascii", /* 2 */ 49 "Cannot open input file", /* 3 */ 50 "PWB spec problem", /* 4 */ 51 "nothing to undo", /* 5 */ 52 "restricted shell", /* 6 */ 53 "cannot create output file", /* 7 */ 54 "filesystem out of space!", /* 8 */ 55 "cannot open file", /* 9 */ 56 "cannot link", /* 10 */ 57 "Range endpoint too large", /* 11 */ 58 "unknown command", /* 12 */ 59 "search string not found", /* 13 */ 60 "-", /* 14 */ 61 "line out of range", /* 15 */ 62 "bad number", /* 16 */ 63 "bad range", /* 17 */ 64 "Illegal address count", /* 18 */ 65 "incomplete global expression", /* 19 */ 66 "illegal suffix", /* 20 */ 67 "illegal or missing filename", /* 21 */ 68 "no space after command", /* 22 */ 69 "fork failed - try again", /* 23 */ 70 "maximum of 64 characters in file names", /* 24 */ 71 "`\\digit' out of range", /* 25 */ 72 "interrupt", /* 26 */ 73 "line too long", /* 27 */ 74 "illegal character in input file", /* 28 */ 75 "write error", /* 29 */ 76 "out of memory for append", /* 30 */ 77 "temp file too big", /* 31 */ 78 "I/O error on temp file", /* 32 */ 79 "multiple globals not allowed", /* 33 */ 80 "global too long", /* 34 */ 81 "no match", /* 35 */ 82 "illegal or missing delimiter", /* 36 */ 83 "-", /* 37 */ 84 "replacement string too long", /* 38 */ 85 "illegal move destination", /* 39 */ 86 "-", /* 40 */ 87 "no remembered search string", /* 41 */ 88 "'\\( \\)' imbalance", /* 42 */ 89 "Too many `\\(' s", /* 43 */ 90 "more than 2 numbers given", /* 44 */ 91 "'\\}' expected", /* 45 */ 92 "first number exceeds second", /* 46 */ 93 "incomplete substitute", /* 47 */ 94 "newline unexpected", /* 48 */ 95 "'[ ]' imbalance", /* 49 */ 96 "regular expression overflow", /* 50 */ 97 "regular expression error", /* 51 */ 98 "command expected", /* 52 */ 99 "a, i, or c not allowed in G", /* 53 */ 100 "end of line expected", /* 54 */ 101 "no remembered replacement string", /* 55 */ 102 "no remembered command", /* 56 */ 103 "illegal redirection", /* 57 */ 104 "possible concurrent update", /* 58 */ 105 "-", /* 59 */ 106 "the x command has become X (upper case)", /* 60 */ 107 "Warning: 'w' may destroy input file " 108 "(due to `illegal char' read earlier)", 109 /* 61 */ 110 "Caution: 'q' may lose data in buffer;" 111 " 'w' may destroy input file", 112 /* 62 */ 113 "Encryption of string failed", /* 63 */ 114 "Encryption facility not available", /* 64 */ 115 "Cannot encrypt temporary file", /* 65 */ 116 "Enter key:", /* 66 */ 117 "Illegal byte sequence", /* 67 */ 118 "File does not exist", /* 68 */ 119 "tempnam failed", /* 69 */ 120 "Cannot open temporary file", /* 70 */ 121 0 122 }; 123 124 #include <stdlib.h> 125 #include <limits.h> 126 #include <stdio.h> 127 #include <signal.h> 128 #include <sys/types.h> 129 #include <sys/stat.h> 130 #include <sys/statvfs.h> 131 #include <unistd.h> 132 #include <termio.h> 133 #include <ctype.h> 134 #include <setjmp.h> 135 #include <fcntl.h> 136 #include <wchar.h> /* I18N */ 137 #include <wctype.h> /* I18N */ 138 #include <widec.h> /* I18N */ 139 140 #define FTYPE(A) (A.st_mode) 141 #define FMODE(A) (A.st_mode) 142 #define IDENTICAL(A, B) (A.st_dev == B.st_dev && A.st_ino == B.st_ino) 143 #define ISBLK(A) ((A.st_mode & S_IFMT) == S_IFBLK) 144 #define ISCHR(A) ((A.st_mode & S_IFMT) == S_IFCHR) 145 #define ISDIR(A) ((A.st_mode & S_IFMT) == S_IFDIR) 146 #define ISFIFO(A) ((A.st_mode & S_IFMT) == S_IFIFO) 147 #define ISREG(A) ((A.st_mode & S_IFMT) == S_IFREG) 148 149 #define PUTM() if (xcode >= 0) puts(gettext(msgtab[xcode])) 150 #define UNGETC(c) (peekc = c) 151 #define FNSIZE PATH_MAX 152 #define LBSIZE LINE_MAX 153 154 /* size of substitution replacement pattern buffer */ 155 #define RHSIZE (LINE_MAX*2) 156 157 #define KSIZE 8 158 159 #define READ 0 160 #define WRITE 1 161 162 extern char *optarg; /* Value of argument */ 163 extern int optind; /* Indicator of argument */ 164 165 struct Fspec { 166 char Ftabs[22]; 167 char Fdel; 168 unsigned char Flim; 169 char Fmov; 170 char Ffill; 171 }; 172 static struct Fspec fss; 173 174 static char *fsp; 175 static int fsprtn; 176 static char line[70]; 177 static char *linp = line; 178 static int sig; 179 static int Xqt = 0; 180 static int lastc; 181 static char savedfile[FNSIZE]; 182 static char file[FNSIZE]; 183 static char funny[FNSIZE]; 184 static int funlink = 0; 185 static char linebuf[LBSIZE]; 186 static char *tstring = linebuf; 187 188 static char *expbuf; 189 190 static char rhsbuf[RHSIZE]; 191 struct lin { 192 long cur; 193 long sav; 194 }; 195 typedef struct lin *LINE; 196 static LINE zero; 197 static LINE dot; 198 static LINE dol; 199 static LINE endcore; 200 static LINE fendcore; 201 static LINE addr1; 202 static LINE addr2; 203 static LINE savdol, savdot; 204 static int globflg; 205 static int initflg; 206 static char genbuf[LBSIZE]; 207 static long count; 208 static int numpass; /* Number of passes thru dosub(). */ 209 static int gsubf; /* Occurrence value. LBSIZE-1=all. */ 210 static int ocerr1; /* Allows lines NOT changed by dosub() to NOT be put */ 211 /* out. Retains last line changed as current line. */ 212 static int ocerr2; /* Flags if ANY line changed by substitute(). 0=nc. */ 213 static char *nextip; 214 static char *linebp; 215 static int ninbuf; 216 static int peekc; 217 static int io; 218 static void (*oldhup)(), (*oldintr)(); 219 static void (*oldquit)(), (*oldpipe)(); 220 static void quit(int) __NORETURN; 221 static int vflag = 1; 222 static int xflag; 223 static int xtflag; 224 static int kflag; 225 static int crflag; 226 /* Flag for determining if file being read is encrypted */ 227 static int hflag; 228 static int xcode = -1; 229 static char crbuf[LBSIZE]; 230 static int perm[2]; 231 static int tperm[2]; 232 static int permflag; 233 static int tpermflag; 234 static int col; 235 static char *globp; 236 static int tfile = -1; 237 static int tline; 238 static char *tfname; 239 extern char *locs; 240 static char ibuff[LBSIZE]; 241 static int iblock = -1; 242 static char obuff[LBSIZE]; 243 static int oblock = -1; 244 static int ichanged; 245 static int nleft; 246 static long savnames[26], names[26]; 247 static int anymarks; 248 static long subnewa; 249 static int fchange; 250 static int nline; 251 static int fflg, shflg; 252 static char prompt[16] = "*"; 253 static int rflg; 254 static int readflg; 255 static int eflg; 256 static int qflg = 0; 257 static int ncflg; 258 static int listn; 259 static int listf; 260 static int pflag; 261 static int flag28 = 0; /* Prevents write after a partial read */ 262 static int save28 = 0; /* Flag whether buffer empty at start of read */ 263 static long savtime; 264 static char *name = "SHELL"; 265 static char *rshell = "/usr/lib/rsh"; 266 static char *val; 267 static char *home; 268 static int nodelim; 269 270 int makekey(int *); 271 int _mbftowc(char *, wchar_t *, int (*)(), int *); 272 static int error(int code); 273 static void tlist(struct Fspec *); 274 static void tstd(struct Fspec *); 275 static void gdelete(void); 276 static void delete(void); 277 static void exfile(void); 278 static void filename(int comm); 279 static void newline(void); 280 static int gettty(void); 281 static void commands(void); 282 static void undo(void); 283 static void save(void); 284 static void strcopy(char *source, char *dest); 285 static int strequal(char **scan1, char *str); 286 static int stdtab(char *, char *); 287 static int lenchk(char *, struct Fspec *); 288 static void clear(struct Fspec *); 289 static int expnd(char *, char *, int *, struct Fspec *); 290 static void tincr(int, struct Fspec *); 291 static void targ(struct Fspec *); 292 static int numb(void); 293 static int fspec(char *, struct Fspec *, int); 294 static void red(char *); 295 static void newtime(void); 296 static void chktime(void); 297 static void getime(void); 298 static void mkfunny(void); 299 static int eopen(char *, int); 300 static void eclose(int f); 301 static void globaln(int); 302 static char *getkey(const char *); 303 static int execute(int, LINE); 304 static void error1(int); 305 static int getcopy(void); 306 static void move(int); 307 static void dosub(void); 308 static int getsub(void); 309 static int compsub(void); 310 static void substitute(int); 311 static void join(void); 312 static void global(int); 313 static void init(void); 314 static void rdelete(LINE, LINE); 315 static void append(int (*)(void), LINE); 316 static int getfile(void); 317 static void putfile(void); 318 static void onpipe(int); 319 static void onhup(int); 320 static void onintr(int); 321 static void setdot(void); 322 static void setall(void); 323 static void setnoaddr(void); 324 static void nonzero(void); 325 static void setzeroasone(void); 326 static long putline(void); 327 static LINE address(void); 328 static char *getaline(long); 329 static char *getblock(long, long); 330 static char *place(char *, char *, char *); 331 static void comple(wchar_t); 332 static void putchr(unsigned char); 333 static void putwchr(wchar_t); 334 static int getchr(void); 335 static void unixcom(void); 336 static void blkio(int, char *, ssize_t (*)()); 337 static void reverse(LINE, LINE); 338 static void putd(); 339 static wchar_t get_wchr(void); 340 341 static struct stat Fl, Tf; 342 #ifndef RESEARCH 343 static struct statvfs U; 344 static int Short = 0; 345 static mode_t oldmask; /* No umask while writing */ 346 #endif 347 static jmp_buf savej; 348 349 #ifdef NULLS 350 int nulls; /* Null count */ 351 #endif 352 static long ccount; 353 354 static int errcnt = 0; 355 356 357 static void 358 onpipe(int sig) 359 { 360 (int)error(0); 361 } 362 363 int 364 main(int argc, char **argv) 365 { 366 char *p1, *p2; 367 int c; 368 369 (void) setlocale(LC_ALL, ""); 370 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 371 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 372 #endif 373 (void) textdomain(TEXT_DOMAIN); 374 375 oldquit = signal(SIGQUIT, SIG_IGN); 376 oldhup = signal(SIGHUP, SIG_IGN); 377 oldintr = signal(SIGINT, SIG_IGN); 378 oldpipe = signal(SIGPIPE, onpipe); 379 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 380 signal(SIGTERM, quit); 381 p1 = *argv; 382 while (*p1++) 383 ; 384 while (--p1 >= *argv) 385 if (*p1 == '/') 386 break; 387 *argv = p1 + 1; 388 /* if SHELL set in environment and is /usr/lib/rsh, set rflg */ 389 if ((val = getenv(name)) != NULL) 390 if (strcmp(val, rshell) == 0) 391 rflg++; 392 if (**argv == 'r') 393 rflg++; 394 home = getenv("HOME"); 395 while (1) { 396 while ((c = getopt(argc, argv, "sp:qxC")) != EOF) { 397 switch (c) { 398 399 case 's': 400 vflag = 0; 401 break; 402 403 case 'p': 404 strncpy(prompt, optarg, sizeof (prompt)-1); 405 shflg = 1; 406 break; 407 408 case 'q': 409 signal(SIGQUIT, SIG_DFL); 410 vflag = 1; 411 break; 412 413 case 'x': 414 crflag = -1; 415 xflag = 1; 416 break; 417 418 case 'C': 419 crflag = 1; 420 xflag = 1; 421 break; 422 423 case '?': 424 (void) fprintf(stderr, gettext( 425 "Usage: ed [- | -s] [-p string] [-x] [-C] [file]\n" 426 " red [- | -s] [-p string] [-x] [-C] [file]\n")); 427 exit(2); 428 } 429 } 430 if (argv[optind] && strcmp(argv[optind], "-") == 0 && 431 strcmp(argv[optind-1], "--") != 0) { 432 vflag = 0; 433 optind++; 434 continue; 435 } 436 break; 437 } 438 argc = argc - optind; 439 argv = &argv[optind]; 440 441 if (xflag) { 442 if (permflag) 443 crypt_close(perm); 444 permflag = 1; 445 kflag = run_setkey(&perm[0], getkey(msgtab[66])); 446 if (kflag == -1) { 447 puts(gettext(msgtab[64])); 448 xflag = 0; 449 kflag = 0; 450 } 451 if (kflag == 0) 452 crflag = 0; 453 } 454 455 if (argc > 0) { 456 p1 = *argv; 457 if (strlen(p1) >= (size_t)FNSIZE) { 458 puts(gettext("file name too long")); 459 if (kflag) 460 crypt_close(perm); 461 exit(2); 462 } 463 p2 = savedfile; 464 while (*p2++ = *p1++) 465 ; 466 globp = "e"; 467 fflg++; 468 } else /* editing with no file so set savtime to 0 */ 469 savtime = 0; 470 eflg++; 471 if ((tfname = tempnam("", "ea")) == NULL) { 472 puts(gettext(msgtab[69])); 473 exit(2); 474 } 475 476 fendcore = (LINE)sbrk(0); 477 init(); 478 if (oldintr != SIG_IGN) 479 signal(SIGINT, onintr); 480 if (oldhup != SIG_IGN) 481 signal(SIGHUP, onhup); 482 setjmp(savej); 483 commands(); 484 quit(sig); 485 return (0); 486 } 487 488 static void 489 commands(void) 490 { 491 LINE a1; 492 int c; 493 char *p1, *p2; 494 int fsave, m, n; 495 496 for (;;) { 497 nodelim = 0; 498 if (pflag) { 499 pflag = 0; 500 addr1 = addr2 = dot; 501 goto print; 502 } 503 if (shflg && globp == 0) 504 write(1, gettext(prompt), strlen(gettext(prompt))); 505 addr1 = 0; 506 addr2 = 0; 507 if ((c = getchr()) == ',') { 508 addr1 = zero + 1; 509 addr2 = dol; 510 #ifdef XPG6 511 /* XPG4 - it was an error if the second address was */ 512 /* input and the first address was ommitted */ 513 /* Parse second address */ 514 if ((a1 = address()) != 0) { 515 addr2 = a1; 516 } 517 #endif 518 c = getchr(); 519 goto swch; 520 } else if (c == ';') { 521 addr1 = dot; 522 addr2 = dol; 523 #ifdef XPG6 524 /* XPG4 - it was an error if the second address was */ 525 /* input and the first address was ommitted */ 526 /* Parse second address */ 527 if ((a1 = address()) != 0) { 528 addr2 = a1; 529 } 530 #endif 531 c = getchr(); 532 goto swch; 533 } else 534 peekc = c; 535 do { 536 addr1 = addr2; 537 if ((a1 = address()) == 0) { 538 c = getchr(); 539 break; 540 } 541 addr2 = a1; 542 if ((c = getchr()) == ';') { 543 c = ','; 544 dot = a1; 545 } 546 } while (c == ','); 547 if (addr1 == 0) 548 addr1 = addr2; 549 swch: 550 switch (c) { 551 552 case 'a': 553 setdot(); 554 newline(); 555 if (!globflg) save(); 556 append(gettty, addr2); 557 continue; 558 559 case 'c': 560 #ifdef XPG6 561 setzeroasone(); 562 #endif 563 delete(); 564 append(gettty, addr1-1); 565 566 /* XPG4 - If no new lines are inserted, then the current */ 567 /* line becomes the line after the lines deleted. */ 568 569 if (((linebuf[0] != '.') || (dot == (addr1-1))) && 570 (addr2 <= dol)) 571 dot = addr1; 572 continue; 573 574 case 'd': 575 delete(); 576 continue; 577 578 case 'E': 579 fchange = 0; 580 c = 'e'; 581 /* FALLTHROUGH */ 582 case 'e': 583 fflg++; 584 setnoaddr(); 585 if (vflag && fchange) { 586 fchange = 0; 587 (void) error(1); 588 } 589 filename(c); 590 eflg++; 591 init(); 592 addr2 = zero; 593 goto caseread; 594 595 case 'f': 596 setnoaddr(); 597 filename(c); 598 if (!ncflg) /* there is a filename */ 599 getime(); 600 else 601 ncflg--; 602 puts(savedfile); 603 continue; 604 605 case 'g': 606 global(1); 607 continue; 608 case 'G': 609 globaln(1); 610 continue; 611 612 case 'h': 613 newline(); 614 setnoaddr(); 615 PUTM(); 616 continue; 617 618 case 'H': 619 newline(); 620 setnoaddr(); 621 if (!hflag) { 622 hflag = 1; 623 PUTM(); 624 } 625 else 626 hflag = 0; 627 continue; 628 629 case 'i': 630 #ifdef XPG6 631 setzeroasone(); 632 #endif 633 setdot(); 634 nonzero(); 635 newline(); 636 if (!globflg) save(); 637 append(gettty, addr2-1); 638 if (dot == addr2-1) 639 dot += 1; 640 continue; 641 642 case 'j': 643 if (addr2 == 0) { 644 addr1 = dot; 645 addr2 = dot+1; 646 } 647 setdot(); 648 newline(); 649 nonzero(); 650 if (!globflg) save(); 651 join(); 652 continue; 653 654 case 'k': 655 if ((c = getchr()) < 'a' || c > 'z') 656 (void) error(2); 657 newline(); 658 setdot(); 659 nonzero(); 660 names[c-'a'] = addr2->cur & ~01; 661 anymarks |= 01; 662 continue; 663 664 case 'm': 665 move(0); 666 continue; 667 668 case '\n': 669 if (addr2 == 0) 670 addr2 = dot+1; 671 addr1 = addr2; 672 goto print; 673 674 case 'n': 675 listn++; 676 newline(); 677 goto print; 678 679 case 'l': 680 listf++; 681 /* FALLTHROUGH */ 682 case 'p': 683 newline(); 684 print: 685 setdot(); 686 nonzero(); 687 a1 = addr1; 688 do { 689 if (listn) { 690 count = a1 - zero; 691 putd(); 692 putchr('\t'); 693 } 694 puts(getaline((a1++)->cur)); 695 } while (a1 <= addr2); 696 dot = addr2; 697 pflag = 0; 698 listn = 0; 699 listf = 0; 700 continue; 701 702 case 'Q': 703 fchange = 0; 704 /* FALLTHROUGH */ 705 case 'q': 706 setnoaddr(); 707 newline(); 708 quit(sig); 709 710 case 'r': 711 filename(c); 712 caseread: 713 readflg = 1; 714 save28 = (dol != fendcore); 715 if (crflag == 2 || crflag == -2) 716 crflag = -1; /* restore crflag for next file */ 717 errno = 0; 718 if ((io = eopen(file, O_RDONLY)) < 0) { 719 lastc = '\n'; 720 /* if first entering editor and file does not exist */ 721 /* set saved access time to 0 */ 722 if (eflg) { 723 savtime = 0; 724 eflg = 0; 725 if (c == 'e' && vflag == 0) 726 qflg = 1; 727 } 728 if (errno == ENOENT) { 729 (void) error(68); 730 } else { 731 (void) error(3); 732 } 733 } 734 /* get last mod time of file */ 735 /* eflg - entered editor with ed or e */ 736 if (eflg) { 737 eflg = 0; 738 getime(); 739 } 740 setall(); 741 ninbuf = 0; 742 n = zero != dol; 743 #ifdef NULLS 744 nulls = 0; 745 #endif 746 if (!globflg && (c == 'r')) save(); 747 append(getfile, addr2); 748 exfile(); 749 readflg = 0; 750 fchange = n; 751 continue; 752 753 case 's': 754 setdot(); 755 nonzero(); 756 if (!globflg) save(); 757 substitute(globp != 0); 758 continue; 759 760 case 't': 761 move(1); 762 continue; 763 764 case 'u': 765 setdot(); 766 newline(); 767 if (!initflg) 768 undo(); 769 else 770 (void) error(5); 771 fchange = 1; 772 continue; 773 774 case 'v': 775 global(0); 776 continue; 777 case 'V': 778 globaln(0); 779 continue; 780 781 case 'W': 782 case 'w': 783 if (flag28) { 784 flag28 = 0; 785 fchange = 0; 786 (void) error(61); 787 } 788 setall(); 789 790 /* on NULL-RE condition do not generate error */ 791 792 if ((linebuf[0] != '.') && (zero != dol) && 793 (addr1 <= zero || addr2 > dol)) 794 (void) error(15); 795 filename(c); 796 if (Xqt) { 797 io = eopen(file, O_WRONLY); 798 n = 1; /* set n so newtime will not execute */ 799 } else { 800 struct stat lFl; 801 fstat(tfile, &Tf); 802 if (stat(file, &Fl) < 0) { 803 if ((io = creat(file, S_IRUSR|S_IWUSR|S_IRGRP 804 |S_IWGRP|S_IROTH|S_IWOTH)) < 0) 805 (void) error(7); 806 fstat(io, &Fl); 807 Fl.st_mtime = 0; 808 lFl = Fl; 809 close(io); 810 } else { 811 #ifndef RESEARCH 812 oldmask = umask(0); 813 /* 814 * Must determine if file is 815 * a symbolic link 816 */ 817 lstat(file, &lFl); 818 #endif 819 } 820 #ifndef RESEARCH 821 /* 822 * Determine if there are enough free blocks on system 823 */ 824 if (!Short && statvfs(file, &U) == 0 && 825 U.f_bfree < ((Tf.st_size/U.f_frsize) + 100)) { 826 Short = 1; 827 (void) error(8); 828 } 829 Short = 0; 830 #endif 831 p1 = savedfile; /* The current filename */ 832 p2 = file; 833 m = strcmp(p1, p2); 834 if (c == 'w' && Fl.st_nlink == 1 && ISREG(lFl)) { 835 if (close(open(file, O_WRONLY)) < 0) 836 (void) error(9); 837 if (!(n = m)) 838 chktime(); 839 mkfunny(); 840 /* 841 * If funlink equals one it means that 842 * funny points to a valid file which must 843 * be unlinked when interrupted. 844 */ 845 846 funlink = 1; 847 if ((io = creat(funny, FMODE(Fl))) >= 0) { 848 chown(funny, Fl.st_uid, Fl.st_gid); 849 chmod(funny, FMODE(Fl)); 850 putfile(); 851 exfile(); 852 853 if (rename(funny, file)) 854 (void) error(10); 855 funlink = 0; 856 /* if filenames are the same */ 857 if (!n) 858 newtime(); 859 /* check if entire buffer was written */ 860 fsave = fchange; 861 if (((addr1 == zero) || 862 (addr1 == (zero + 1))) && 863 (addr2 == dol)) 864 fchange = 0; 865 else 866 fchange = 1; 867 if (fchange == 1 && m != 0) 868 fchange = fsave; 869 continue; 870 } 871 } else { 872 n = 1; /* set n so newtime will not execute */ 873 } 874 if ((io = open(file, 875 (c == 'w') ? O_WRONLY|O_CREAT|O_TRUNC 876 : O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR 877 |S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) 878 (void) error(7); 879 } 880 putfile(); 881 exfile(); 882 if (!n) 883 newtime(); 884 fsave = fchange; 885 fchange = (((addr1 == zero) || (addr1 == (zero + 1))) && 886 (addr2 == dol)) ? 0 : 1; 887 /* Leave fchange alone if partial write was to another file */ 888 if (fchange == 1 && m != 0) fchange = fsave; 889 continue; 890 891 case 'C': 892 crflag = 1; 893 /* 894 * C is same as X, but always assume input files are 895 * ciphertext 896 */ 897 goto encrypt; 898 899 case 'X': 900 crflag = -1; 901 encrypt: 902 setnoaddr(); 903 newline(); 904 xflag = 1; 905 if (permflag) 906 (void) crypt_close(perm); 907 permflag = 1; 908 if ((kflag = run_setkey(&perm[0], getkey(msgtab[66]))) == -1) { 909 xflag = 0; 910 kflag = 0; 911 crflag = 0; 912 (void) error(64); 913 } 914 if (kflag == 0) 915 crflag = 0; 916 continue; 917 918 case '=': 919 setall(); 920 newline(); 921 count = (addr2-zero)&077777; 922 putd(); 923 putchr('\n'); 924 continue; 925 926 case '!': 927 unixcom(); 928 continue; 929 930 case EOF: 931 return; 932 933 case 'P': 934 setnoaddr(); 935 newline(); 936 if (shflg) 937 shflg = 0; 938 else 939 shflg++; 940 continue; 941 } 942 if (c == 'x') 943 (void) error(60); 944 else 945 (void) error(12); 946 } 947 } 948 949 LINE 950 address(void) 951 { 952 int minus, c; 953 LINE a1; 954 int n, relerr, retval; 955 956 minus = 0; 957 a1 = 0; 958 for (;;) { 959 c = getchr(); 960 if ('0' <= c && c <= '9') { 961 n = 0; 962 do { 963 n *= 10; 964 n += c - '0'; 965 } while ((c = getchr()) >= '0' && c <= '9'); 966 peekc = c; 967 if (a1 == 0) 968 a1 = zero; 969 if (minus < 0) 970 n = -n; 971 a1 += n; 972 minus = 0; 973 continue; 974 } 975 relerr = 0; 976 if (a1 || minus) 977 relerr++; 978 switch (c) { 979 case ' ': 980 case '\t': 981 continue; 982 983 case '+': 984 minus++; 985 if (a1 == 0) 986 a1 = dot; 987 continue; 988 989 case '-': 990 case '^': 991 minus--; 992 if (a1 == 0) 993 a1 = dot; 994 continue; 995 996 case '?': 997 case '/': 998 comple(c); 999 a1 = dot; 1000 for (;;) { 1001 if (c == '/') { 1002 a1++; 1003 if (a1 > dol) 1004 a1 = zero; 1005 } else { 1006 a1--; 1007 if (a1 < zero) 1008 a1 = dol; 1009 } 1010 1011 if (execute(0, a1)) 1012 break; 1013 if (a1 == dot) 1014 (void) error(13); 1015 } 1016 break; 1017 1018 case '$': 1019 a1 = dol; 1020 break; 1021 1022 case '.': 1023 a1 = dot; 1024 break; 1025 1026 case '\'': 1027 if ((c = getchr()) < 'a' || c > 'z') 1028 (void) error(2); 1029 for (a1 = zero; a1 <= dol; a1++) 1030 if (names[c-'a'] == (a1->cur & ~01)) 1031 break; 1032 break; 1033 1034 default: 1035 peekc = c; 1036 if (a1 == 0) 1037 return (0); 1038 a1 += minus; 1039 1040 /* on NULL-RE condition do not generate error */ 1041 1042 if ((linebuf[0] != '.') && (a1 < zero || a1 > dol)) 1043 (void) error(15); 1044 return (a1); 1045 } 1046 if (relerr) 1047 (void) error(16); 1048 } 1049 } 1050 1051 static void 1052 setdot(void) 1053 { 1054 if (addr2 == 0) 1055 addr1 = addr2 = dot; 1056 if (addr1 > addr2) 1057 (void) error(17); 1058 } 1059 1060 static void 1061 setall(void) 1062 { 1063 if (addr2 == 0) { 1064 addr1 = zero+1; 1065 addr2 = dol; 1066 if (dol == zero) 1067 addr1 = zero; 1068 } 1069 setdot(); 1070 } 1071 1072 static void 1073 setnoaddr(void) 1074 { 1075 if (addr2) 1076 (void) error(18); 1077 } 1078 1079 static void 1080 nonzero(void) 1081 { 1082 /* on NULL-RE condition do not generate error */ 1083 1084 if ((linebuf[0] != '.') && (addr1 <= zero || addr2 > dol)) 1085 (void) error(15); 1086 } 1087 1088 static void 1089 setzeroasone(void) 1090 { 1091 /* for the c and i commands 0 equal to 1 address */ 1092 if (addr1 == zero) { 1093 addr1 = zero+1; 1094 } 1095 if (addr2 == zero) { 1096 addr2 = zero+1; 1097 } 1098 } 1099 1100 1101 static void 1102 newline(void) 1103 { 1104 int c; 1105 1106 if ((c = getchr()) == '\n') 1107 return; 1108 if (c == 'p' || c == 'l' || c == 'n') { 1109 pflag++; 1110 if (c == 'l') listf++; 1111 if (c == 'n') listn++; 1112 if ((c = getchr()) == '\n') 1113 return; 1114 } 1115 (void) error(20); 1116 } 1117 1118 static void 1119 filename(int comm) 1120 { 1121 char *p1, *p2; 1122 int c; 1123 int i = 0; 1124 1125 count = 0; 1126 c = getchr(); 1127 if (c == '\n' || c == EOF) { 1128 p1 = savedfile; 1129 if (*p1 == 0 && comm != 'f') 1130 (void) error(21); 1131 /* ncflg set means do not get mod time of file */ 1132 /* since no filename followed f */ 1133 if (comm == 'f') 1134 ncflg++; 1135 p2 = file; 1136 while (*p2++ = *p1++) 1137 ; 1138 red(savedfile); 1139 return; 1140 } 1141 if (c != ' ') 1142 (void) error(22); 1143 while ((c = getchr()) == ' ') 1144 ; 1145 if (c == '!') 1146 ++Xqt, c = getchr(); 1147 if (c == '\n') 1148 (void) error(21); 1149 p1 = file; 1150 do { 1151 if (++i >= FNSIZE) 1152 (void) error(24); 1153 *p1++ = c; 1154 if (c == EOF || (c == ' ' && !Xqt)) 1155 (void) error(21); 1156 } while ((c = getchr()) != '\n'); 1157 *p1++ = 0; 1158 if (Xqt) 1159 if (comm == 'f') { 1160 --Xqt; 1161 (void) error(57); 1162 } 1163 else 1164 return; 1165 if (savedfile[0] == 0 || comm == 'e' || comm == 'f') { 1166 p1 = savedfile; 1167 p2 = file; 1168 while (*p1++ = *p2++) 1169 ; 1170 } 1171 red(file); 1172 } 1173 1174 1175 static void 1176 exfile(void) 1177 { 1178 #ifdef NULLS 1179 int c; 1180 #endif 1181 1182 #ifndef RESEARCH 1183 if (oldmask) { 1184 umask(oldmask); 1185 oldmask = 0; 1186 } 1187 #endif 1188 eclose(io); 1189 io = -1; 1190 if (vflag) { 1191 putd(); 1192 putchr('\n'); 1193 #ifdef NULLS 1194 if (nulls) { 1195 c = count; 1196 count = nulls; 1197 nulls = 0; 1198 putd(); 1199 puts(gettext(" nulls replaced by '\\0'")); 1200 count = c; 1201 } 1202 #endif 1203 } 1204 } 1205 1206 static void 1207 onintr(int sig) 1208 { 1209 signal(SIGINT, onintr); 1210 putchr('\n'); 1211 lastc = '\n'; 1212 globflg = 0; 1213 if (funlink) unlink(funny); /* remove tmp file */ 1214 /* if interrupted a read, only part of file may be in buffer */ 1215 if (readflg) { 1216 sprintf(tstring, "\007read may be incomplete - beware!\007"); 1217 puts(gettext(tstring)); 1218 fchange = 0; 1219 } 1220 (void) error(26); 1221 } 1222 1223 static void 1224 onhup(int sig) 1225 { 1226 signal(SIGINT, SIG_IGN); 1227 signal(SIGHUP, SIG_IGN); 1228 /* 1229 * if there are lines in file and file was not written 1230 * since last update, save in ed.hup, or $HOME/ed.hup 1231 */ 1232 if (dol > zero && fchange == 1) { 1233 addr1 = zero+1; 1234 addr2 = dol; 1235 io = creat("ed.hup", 1236 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 1237 if (io < 0 && home) { 1238 char *fn; 1239 1240 fn = (char *)calloc(strlen(home) + 8, sizeof (char)); 1241 if (fn) { 1242 strcpy(fn, home); 1243 strcat(fn, "/ed.hup"); 1244 io = creat(fn, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP 1245 |S_IROTH|S_IWOTH); 1246 free(fn); 1247 } 1248 } 1249 if (io > 0) 1250 putfile(); 1251 } 1252 fchange = 0; 1253 ++errcnt; 1254 quit(sig); 1255 } 1256 1257 static int 1258 error(int code) 1259 { 1260 int c; 1261 1262 if (code == 28 && save28 == 0) { 1263 fchange = 0; 1264 flag28++; 1265 } 1266 readflg = 0; 1267 ++errcnt; 1268 listf = listn = 0; 1269 pflag = 0; 1270 #ifndef RESEARCH 1271 if (oldmask) { 1272 umask(oldmask); 1273 oldmask = 0; 1274 } 1275 #endif 1276 #ifdef NULLS /* Not really nulls, but close enough */ 1277 /* This is a bug because of buffering */ 1278 if (code == 28) /* illegal char. */ 1279 putd(); 1280 #endif 1281 /* Cant open file or file does not exist */ 1282 if ((code == 3) || (code == 68)) { 1283 if (qflg == 0) { 1284 putchr('?'); 1285 puts(file); 1286 } 1287 else 1288 qflg = 0; 1289 } 1290 else 1291 { 1292 putchr('?'); 1293 putchr('\n'); 1294 } 1295 count = 0; 1296 lseek(0, (long)0, 2); 1297 if (globp) 1298 lastc = '\n'; 1299 globp = 0; 1300 peekc = lastc; 1301 if (lastc) 1302 while ((c = getchr()) != '\n' && c != EOF) 1303 ; 1304 if (io) { 1305 eclose(io); 1306 io = -1; 1307 } 1308 xcode = code; 1309 if (hflag) 1310 PUTM(); 1311 if (code == 4) 1312 return (0); /* Non-fatal error. */ 1313 longjmp(savej, 1); 1314 /* NOTREACHED */ 1315 } 1316 1317 static int 1318 getchr(void) 1319 { 1320 char c; 1321 if (lastc = peekc) { 1322 peekc = 0; 1323 return (lastc); 1324 } 1325 if (globp) { 1326 if ((lastc = (unsigned char)*globp++) != 0) 1327 return (lastc); 1328 globp = 0; 1329 return (EOF); 1330 } 1331 if (read(0, &c, 1) <= 0) 1332 return (lastc = EOF); 1333 lastc = (unsigned char)c; 1334 return (lastc); 1335 } 1336 1337 static int 1338 gettty(void) 1339 { 1340 int c; 1341 char *gf; 1342 char *p; 1343 1344 p = linebuf; 1345 gf = globp; 1346 while ((c = getchr()) != '\n') { 1347 if (c == EOF) { 1348 if (gf) 1349 peekc = c; 1350 return (c); 1351 } 1352 if (c == 0) 1353 continue; 1354 *p++ = c; 1355 1356 if (p > &linebuf[LBSIZE-1]) 1357 (void) error(27); 1358 } 1359 *p++ = 0; 1360 if (linebuf[0] == '.' && linebuf[1] == 0) 1361 return (EOF); 1362 1363 /* 1364 * POSIX.2/XPG4 explicitly says no to this: 1365 * 1366 * in Solaris backslash followed by special character "." is 1367 * special character "." itself; (so terminating input mode can be 1368 * "\.\n"). 1369 * 1370 * however, POSIX2/XPG4 says, input mode is terminated by 1371 * entering line consisting of only 2 characters: ".\n" 1372 * 1373 * if (linebuf[0]=='\\' && linebuf[1]=='.' && linebuf[2]==0) { 1374 * linebuf[0] = '.'; 1375 * linebuf[1] = 0; 1376 * } 1377 */ 1378 return (0); 1379 } 1380 1381 static int 1382 getfile(void) 1383 { 1384 char c; 1385 char *lp, *fp; 1386 1387 lp = linebuf; 1388 fp = nextip; 1389 do { 1390 if (--ninbuf < 0) { 1391 if ((ninbuf = read(io, genbuf, LBSIZE)-1) < 0) 1392 if (lp > linebuf) { 1393 puts(gettext("'\\n' appended")); 1394 *genbuf = '\n'; 1395 } 1396 else 1397 return (EOF); 1398 if (crflag == -1) { 1399 if (isencrypt(genbuf, ninbuf + 1)) 1400 crflag = 2; 1401 else 1402 crflag = -2; 1403 } 1404 fp = genbuf; 1405 if (crflag > 0) 1406 if (run_crypt(count, genbuf, ninbuf+1, perm) == -1) 1407 (void) error(63); 1408 } 1409 if (lp >= &linebuf[LBSIZE]) { 1410 lastc = '\n'; 1411 (void) error(27); 1412 } 1413 if ((*lp++ = c = *fp++) == 0) { 1414 #ifdef NULLS 1415 lp[-1] = '\\'; 1416 *lp++ = '0'; 1417 nulls++; 1418 #else 1419 lp--; 1420 continue; 1421 #endif 1422 } 1423 count++; 1424 } while (c != '\n'); 1425 *--lp = 0; 1426 nextip = fp; 1427 if (fss.Ffill && fss.Flim && lenchk(linebuf, &fss) < 0) { 1428 write(1, gettext("line too long: lno = "), 1429 strlen(gettext("line too long: lno = "))); 1430 ccount = count; 1431 count = (++dot-zero)&077777; 1432 dot--; 1433 putd(); 1434 count = ccount; 1435 putchr('\n'); 1436 } 1437 return (0); 1438 } 1439 1440 static void 1441 putfile(void) 1442 { 1443 int n; 1444 LINE a1; 1445 char *fp, *lp; 1446 int nib; 1447 1448 nib = LBSIZE; 1449 fp = genbuf; 1450 a1 = addr1; 1451 do { 1452 lp = getaline(a1++->cur); 1453 if (fss.Ffill && fss.Flim && lenchk(linebuf, &fss) < 0) { 1454 write(1, gettext("line too long: lno = "), 1455 strlen(gettext("line too long: lno = "))); 1456 ccount = count; 1457 count = (a1-zero-1)&077777; 1458 putd(); 1459 count = ccount; 1460 putchr('\n'); 1461 } 1462 for (;;) { 1463 if (--nib < 0) { 1464 n = fp-genbuf; 1465 if (kflag) 1466 if (run_crypt(count-n, genbuf, n, perm) == -1) 1467 (void) error(63); 1468 if (write(io, genbuf, n) != n) 1469 (void) error(29); 1470 nib = LBSIZE - 1; 1471 fp = genbuf; 1472 } 1473 if (dol->cur == 0L)break; /* Allow write of null file */ 1474 count++; 1475 if ((*fp++ = *lp++) == 0) { 1476 fp[-1] = '\n'; 1477 break; 1478 } 1479 } 1480 } while (a1 <= addr2); 1481 n = fp-genbuf; 1482 if (kflag) 1483 if (run_crypt(count-n, genbuf, n, perm) == -1) 1484 (void) error(63); 1485 if (write(io, genbuf, n) != n) 1486 (void) error(29); 1487 } 1488 1489 static void 1490 append(int (*f)(void), LINE a) 1491 { 1492 LINE a1, a2, rdot; 1493 long tl; 1494 1495 nline = 0; 1496 dot = a; 1497 while ((*f)() == 0) { 1498 if (dol >= endcore) { 1499 if ((int)sbrk(512 * sizeof (struct lin)) == -1) { 1500 lastc = '\n'; 1501 (void) error(30); 1502 } 1503 endcore += 512; 1504 } 1505 tl = putline(); 1506 nline++; 1507 a1 = ++dol; 1508 a2 = a1+1; 1509 rdot = ++dot; 1510 while (a1 > rdot) 1511 (--a2)->cur = (--a1)->cur; 1512 rdot->cur = tl; 1513 } 1514 } 1515 1516 static void 1517 unixcom(void) 1518 { 1519 void (*savint)(); 1520 pid_t pid, rpid; 1521 int retcode; 1522 static char savcmd[LBSIZE]; /* last command */ 1523 char curcmd[LBSIZE]; /* current command */ 1524 char *psavcmd, *pcurcmd, *psavedfile; 1525 int endflg = 1, shflg = 0; 1526 wchar_t c; 1527 int len; 1528 1529 setnoaddr(); 1530 if (rflg) 1531 (void) error(6); 1532 pcurcmd = curcmd; 1533 /* read command til end */ 1534 1535 /* 1536 * a '!' found in beginning of command is replaced with the saved 1537 * command. a '%' found in command is replaced with the current 1538 * filename 1539 */ 1540 1541 c = getchr(); 1542 if (c == '!') { 1543 if (savcmd[0] == 0) 1544 (void) error(56); 1545 else { 1546 psavcmd = savcmd; 1547 while (*pcurcmd++ = *psavcmd++) 1548 ; 1549 --pcurcmd; 1550 shflg = 1; 1551 } 1552 } else 1553 UNGETC(c); /* put c back */ 1554 while (endflg == 1) { 1555 while ((c = get_wchr()) != '\n' && c != '%' && c != '\\') { 1556 if ((len = wctomb(pcurcmd, c)) <= 0) { 1557 *pcurcmd = (unsigned char)c; 1558 len = 1; 1559 } 1560 pcurcmd += len; 1561 } 1562 1563 if (c == '%') { 1564 if (savedfile[0] == 0) 1565 (void) error(21); 1566 else { 1567 psavedfile = savedfile; 1568 while (pcurcmd < curcmd + LBSIZE && 1569 (*pcurcmd++ = *psavedfile++)) 1570 ; 1571 --pcurcmd; 1572 shflg = 1; 1573 } 1574 } else if (c == '\\') { 1575 c = get_wchr(); 1576 if (c != '%') 1577 *pcurcmd++ = '\\'; 1578 if ((len = wctomb(pcurcmd, c)) <= 0) { 1579 *pcurcmd = (unsigned char)c; 1580 len = 1; 1581 } 1582 pcurcmd += len; 1583 } 1584 else 1585 /* end of command hit */ 1586 endflg = 0; 1587 } 1588 *pcurcmd++ = 0; 1589 if (shflg == 1) 1590 puts(curcmd); 1591 /* save command */ 1592 strcpy(savcmd, curcmd); 1593 1594 if ((pid = fork()) == 0) { 1595 signal(SIGHUP, oldhup); 1596 signal(SIGQUIT, oldquit); 1597 close(tfile); 1598 execlp(_PATH_BSHELL, "sh", "-c", curcmd, NULL); 1599 exit(0100); 1600 } 1601 savint = signal(SIGINT, SIG_IGN); 1602 while ((rpid = wait(&retcode)) != pid && rpid != (pid_t)-1) 1603 ; 1604 signal(SIGINT, savint); 1605 if (vflag) puts("!"); 1606 } 1607 1608 static void 1609 quit(int sig) 1610 { 1611 if (vflag && fchange) { 1612 fchange = 0; 1613 if (flag28) { 1614 flag28 = 0; 1615 (void) error(62); 1616 } 1617 1618 /* 1619 * For case where user reads in BOTH a good 1620 * file & a bad file 1621 */ 1622 (void) error(1); 1623 } 1624 unlink(tfname); 1625 if (kflag) 1626 crypt_close(perm); 1627 if (xtflag) 1628 crypt_close(tperm); 1629 exit(errcnt? 2: 0); 1630 } 1631 1632 static void 1633 delete(void) 1634 { 1635 setdot(); 1636 newline(); 1637 nonzero(); 1638 if (!globflg) 1639 save(); 1640 rdelete(addr1, addr2); 1641 } 1642 1643 static void 1644 rdelete(LINE ad1, LINE ad2) 1645 { 1646 LINE a1, a2, a3; 1647 1648 a1 = ad1; 1649 a2 = ad2+1; 1650 a3 = dol; 1651 dol -= a2 - a1; 1652 do { 1653 (a1++)->cur = (a2++)->cur; 1654 } while (a2 <= a3); 1655 a1 = ad1; 1656 if (a1 > dol) 1657 a1 = dol; 1658 dot = a1; 1659 fchange = 1; 1660 } 1661 1662 static void 1663 gdelete(void) 1664 { 1665 LINE a1, a2, a3; 1666 1667 a3 = dol; 1668 for (a1 = zero+1; (a1->cur&01) == 0; a1++) 1669 if (a1 >= a3) 1670 return; 1671 for (a2 = a1 + 1; a2 <= a3; ) { 1672 if (a2->cur & 01) { 1673 a2++; 1674 dot = a1; 1675 } else 1676 (a1++)->cur = (a2++)->cur; 1677 } 1678 dol = a1-1; 1679 if (dot > dol) 1680 dot = dol; 1681 fchange = 1; 1682 } 1683 1684 static char * 1685 getaline(long tl) 1686 { 1687 char *bp, *lp; 1688 int nl; 1689 1690 lp = linebuf; 1691 bp = getblock(tl, READ); 1692 nl = nleft; 1693 tl &= ~0377; 1694 while (*lp++ = *bp++) 1695 if (--nl == 0) { 1696 bp = getblock(tl += 0400, READ); 1697 nl = nleft; 1698 } 1699 return (linebuf); 1700 } 1701 1702 static long 1703 putline(void) 1704 { 1705 char *bp, *lp; 1706 int nl; 1707 long tl; 1708 1709 fchange = 1; 1710 lp = linebuf; 1711 tl = tline; 1712 bp = getblock(tl, WRITE); 1713 nl = nleft; 1714 tl &= ~0377; 1715 while (*bp = *lp++) { 1716 if (*bp++ == '\n') { 1717 *--bp = 0; 1718 linebp = lp; 1719 break; 1720 } 1721 if (--nl == 0) { 1722 bp = getblock(tl += 0400, WRITE); 1723 nl = nleft; 1724 } 1725 } 1726 nl = tline; 1727 tline += (((lp-linebuf)+03)>>1)&077776; 1728 return (nl); 1729 } 1730 1731 static char * 1732 getblock(long atl, long iof) 1733 { 1734 int bno, off; 1735 char *p1, *p2; 1736 int n; 1737 1738 bno = atl >> 8; 1739 off = (atl<<1)&0774; 1740 1741 /* bno is limited to 16 bits */ 1742 if (bno >= 65535) { 1743 lastc = '\n'; 1744 (void) error(31); 1745 } 1746 nleft = 512 - off; 1747 if (bno == iblock) { 1748 ichanged |= iof; 1749 return (ibuff+off); 1750 } 1751 if (bno == oblock) 1752 return (obuff+off); 1753 if (iof == READ) { 1754 if (ichanged) { 1755 if (xtflag) 1756 if (run_crypt(0L, ibuff, 512, tperm) == -1) 1757 (void) error(63); 1758 blkio(iblock, ibuff, write); 1759 } 1760 ichanged = 0; 1761 iblock = bno; 1762 blkio(bno, ibuff, read); 1763 if (xtflag) 1764 if (run_crypt(0L, ibuff, 512, tperm) == -1) 1765 (void) error(63); 1766 return (ibuff+off); 1767 } 1768 if (oblock >= 0) { 1769 if (xtflag) { 1770 p1 = obuff; 1771 p2 = crbuf; 1772 n = 512; 1773 while (n--) 1774 *p2++ = *p1++; 1775 if (run_crypt(0L, crbuf, 512, tperm) == -1) 1776 (void) error(63); 1777 blkio(oblock, crbuf, write); 1778 } else 1779 blkio(oblock, obuff, write); 1780 } 1781 oblock = bno; 1782 return (obuff+off); 1783 } 1784 1785 static void 1786 blkio(int b, char *buf, ssize_t (*iofcn)()) 1787 { 1788 lseek(tfile, (long)b<<9, 0); 1789 if ((*iofcn)(tfile, buf, 512) != 512) { 1790 if (dol != zero) 1791 (void) error(32); /* Bypass this if writing null file */ 1792 } 1793 } 1794 1795 static void 1796 init(void) 1797 { 1798 long *markp; 1799 mode_t omask; 1800 1801 if (tfile != -1) { 1802 (void) close(tfile); 1803 (void) unlink(tfname); 1804 } 1805 1806 tline = 2; 1807 for (markp = names; markp < &names[26]; ) 1808 *markp++ = 0L; 1809 subnewa = 0L; 1810 anymarks = 0; 1811 iblock = -1; 1812 oblock = -1; 1813 ichanged = 0; 1814 initflg = 1; 1815 omask = umask(0); 1816 1817 if ((tfile = open(tfname, O_CREAT|O_EXCL|O_RDWR, 1818 S_IRUSR|S_IWUSR)) < 0) { 1819 puts(gettext(msgtab[70])); 1820 exit(2); 1821 } 1822 1823 umask(omask); 1824 if (xflag) { 1825 xtflag = 1; 1826 if (tpermflag) 1827 (void) crypt_close(tperm); 1828 tpermflag = 1; 1829 if (makekey(tperm)) { 1830 xtflag = 0; 1831 puts(gettext(msgtab[65])); 1832 } 1833 } 1834 brk((char *)fendcore); 1835 dot = zero = dol = savdot = savdol = fendcore; 1836 flag28 = save28 = 0; 1837 endcore = fendcore - sizeof (struct lin); 1838 } 1839 1840 static void 1841 global(int k) 1842 { 1843 char *gp; 1844 wchar_t l; 1845 char multic[MB_LEN_MAX]; 1846 wchar_t c; 1847 LINE a1; 1848 char globuf[LBSIZE]; 1849 int n; 1850 int len; 1851 1852 if (globp) 1853 (void) error(33); 1854 setall(); 1855 nonzero(); 1856 if ((n = _mbftowc(multic, &l, getchr, &peekc)) <= 0) 1857 (void) error(67); 1858 if (l == '\n') 1859 (void) error(19); 1860 save(); 1861 comple(l); 1862 gp = globuf; 1863 while ((c = get_wchr()) != '\n') { 1864 if (c == EOF) 1865 (void) error(19); 1866 1867 /* '\\' has special meaning only if preceding a '\n' */ 1868 if (c == '\\') { 1869 c = get_wchr(); 1870 if (c != '\n') 1871 *gp++ = '\\'; 1872 } 1873 if ((gp + (unsigned int)MB_CUR_MAX) >= &globuf[LBSIZE-1]) 1874 (void) error(34); 1875 if ((len = wctomb(gp, c)) <= 0) { 1876 *gp = (unsigned char)c; 1877 len = 1; 1878 } 1879 gp += len; 1880 } 1881 if (gp == globuf) 1882 *gp++ = 'p'; 1883 *gp++ = '\n'; 1884 *gp++ = 0; 1885 for (a1 = zero; a1 <= dol; a1++) { 1886 a1->cur &= ~01; 1887 if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k) 1888 a1->cur |= 01; 1889 } 1890 /* 1891 * Special case: g/.../d (avoid n^2 algorithm) 1892 */ 1893 if (globuf[0] == 'd' && globuf[1] == '\n' && globuf[2] == '\0') { 1894 gdelete(); 1895 return; 1896 } 1897 for (a1 = zero; a1 <= dol; a1++) { 1898 if (a1->cur & 01) { 1899 a1->cur &= ~01; 1900 dot = a1; 1901 globp = globuf; 1902 globflg = 1; 1903 commands(); 1904 globflg = 0; 1905 a1 = zero; 1906 } 1907 } 1908 } 1909 1910 static void 1911 join(void) 1912 { 1913 char *gp, *lp; 1914 LINE a1; 1915 1916 if (addr1 == addr2) 1917 return; 1918 gp = genbuf; 1919 for (a1 = addr1; a1 <= addr2; a1++) { 1920 lp = getaline(a1->cur); 1921 while (*gp = *lp++) 1922 if (gp++ > &genbuf[LBSIZE-1]) 1923 (void) error(27); 1924 } 1925 lp = linebuf; 1926 gp = genbuf; 1927 while (*lp++ = *gp++) 1928 ; 1929 addr1->cur = putline(); 1930 if (addr1 < addr2) 1931 rdelete(addr1+1, addr2); 1932 dot = addr1; 1933 } 1934 1935 static void 1936 substitute(int inglob) 1937 { 1938 int nl; 1939 LINE a1; 1940 long *markp; 1941 int ingsav; /* For saving arg. */ 1942 1943 ingsav = inglob; 1944 ocerr2 = 0; 1945 gsubf = compsub(); 1946 for (a1 = addr1; a1 <= addr2; a1++) { 1947 if (execute(0, a1) == 0) 1948 continue; 1949 numpass = 0; 1950 ocerr1 = 0; 1951 inglob |= 01; 1952 dosub(); 1953 if (gsubf) { 1954 while (*loc2) { 1955 if (execute(1, (LINE)0) == 0) 1956 break; 1957 dosub(); 1958 } 1959 } 1960 if (ocerr1 == 0)continue; /* Don't put out-not changed. */ 1961 subnewa = putline(); 1962 a1->cur &= ~01; 1963 if (anymarks) { 1964 for (markp = names; markp < &names[26]; markp++) 1965 if (*markp == a1->cur) 1966 *markp = subnewa; 1967 } 1968 a1->cur = subnewa; 1969 append(getsub, a1); 1970 nl = nline; 1971 a1 += nl; 1972 addr2 += nl; 1973 } 1974 if (ingsav) 1975 return; /* Was in global-no error msg allowed. */ 1976 if (inglob == 0) 1977 (void) error(35); /* Not in global, but not found. */ 1978 if (ocerr2 == 0) 1979 (void) error(35); /* RE found, but occurrence match failed. */ 1980 } 1981 1982 static int 1983 compsub(void) 1984 { 1985 int c; 1986 wchar_t seof; 1987 char *p; 1988 char multic[MB_LEN_MAX]; 1989 int n; 1990 static char remem[RHSIZE]; 1991 static int remflg = -1; 1992 int i; 1993 1994 if ((n = _mbftowc(multic, &seof, getchr, &peekc)) <= 0) 1995 (void) error(67); 1996 if (seof == '\n' || seof == ' ') 1997 (void) error(36); 1998 comple(seof); 1999 p = rhsbuf; 2000 for (;;) { 2001 wchar_t cl; 2002 if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0) 2003 (void) error(67); 2004 if (cl == '\\') { 2005 *p++ = '\\'; 2006 if (p >= &rhsbuf[RHSIZE]) 2007 (void) error(38); 2008 if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0) 2009 (void) error(67); 2010 } else if (cl == '\n') { 2011 if (nodelim == 1) { 2012 nodelim = 0; 2013 (void) error(36); 2014 } 2015 if (!(globp && globp[0])) { 2016 UNGETC('\n'); 2017 pflag++; 2018 break; 2019 } 2020 } else if (cl == seof) 2021 break; 2022 if (p + n > &rhsbuf[RHSIZE]) 2023 (void) error(38); 2024 (void) strncpy(p, multic, n); 2025 p += n; 2026 } 2027 *p++ = 0; 2028 if (rhsbuf[0] == '%' && rhsbuf[1] == 0) 2029 /* 2030 * If there isn't a remembered string, it is an error; 2031 * otherwise the right hand side is the previous right 2032 * hand side. 2033 */ 2034 2035 if (remflg == -1) 2036 (void) error(55); 2037 else 2038 strcpy(rhsbuf, remem); 2039 else { 2040 strcpy(remem, rhsbuf); 2041 remflg = 0; 2042 } 2043 c = 0; 2044 peekc = getchr(); /* Gets char after third delimiter. */ 2045 if (peekc == 'g') { 2046 c = LBSIZE; peekc = 0; 2047 } 2048 if (peekc >= '1' && peekc <= '9') { 2049 c = peekc-'0'; 2050 peekc = 0; /* Allows getchr() to get next char. */ 2051 while (1) { 2052 i = getchr(); 2053 if (i < '0' || i > '9') 2054 break; 2055 c = c*10 + i-'0'; 2056 if (c > LBSIZE-1) 2057 (void) error(20); /* "Illegal suffix" */ 2058 } 2059 peekc = i; /* Effectively an unget. */ 2060 } 2061 newline(); 2062 return (c); 2063 2064 /* 2065 * Returns occurrence value. 0 & 1 both do first occurrence 2066 * only: c = 0 if ordinary substitute; c = 1 2067 * if use 1 in global sub(s/a/b/1). 0 in global form is illegal. 2068 */ 2069 } 2070 2071 static int 2072 getsub(void) 2073 { 2074 char *p1, *p2; 2075 2076 p1 = linebuf; 2077 if ((p2 = linebp) == 0) 2078 return (EOF); 2079 while (*p1++ = *p2++) 2080 ; 2081 linebp = 0; 2082 return (0); 2083 } 2084 2085 static void 2086 dosub(void) 2087 { 2088 char *lp, *sp, *rp; 2089 int c; 2090 2091 if (gsubf > 0 && gsubf < LBSIZE) { 2092 numpass++; 2093 if (gsubf != numpass) 2094 return; 2095 } 2096 ocerr1++; 2097 ocerr2++; 2098 lp = linebuf; 2099 sp = genbuf; 2100 rp = rhsbuf; 2101 while (lp < loc1) 2102 *sp++ = *lp++; 2103 while (c = *rp++) { 2104 if (c == '&') { 2105 sp = place(sp, loc1, loc2); 2106 continue; 2107 } else if (c == '\\') { 2108 c = *rp++; 2109 if (c >= '1' && c < nbra + '1') { 2110 sp = place(sp, braslist[c-'1'], 2111 braelist[c-'1']); 2112 continue; 2113 } 2114 } 2115 *sp++ = c; 2116 if (sp >= &genbuf[LBSIZE]) 2117 (void) error(27); 2118 } 2119 lp = loc2; 2120 loc2 = sp - genbuf + linebuf; 2121 while (*sp++ = *lp++) 2122 if (sp >= &genbuf[LBSIZE]) 2123 (void) error(27); 2124 lp = linebuf; 2125 sp = genbuf; 2126 while (*lp++ = *sp++) 2127 ; 2128 } 2129 2130 static char * 2131 place(char *sp, char *l1, char *l2) 2132 { 2133 2134 while (l1 < l2) { 2135 *sp++ = *l1++; 2136 if (sp >= &genbuf[LBSIZE]) 2137 (void) error(27); 2138 } 2139 return (sp); 2140 } 2141 2142 static void 2143 comple(wchar_t seof) 2144 { 2145 int cclass = 0; 2146 wchar_t c; 2147 int n; 2148 char *cp = genbuf; 2149 char multic[MB_LEN_MAX]; 2150 2151 while (1) { 2152 if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0) 2153 error1(67); 2154 if (n == 0 || c == '\n') { 2155 if (cclass) 2156 error1(49); 2157 else 2158 break; 2159 } 2160 if (c == seof && !cclass) 2161 break; 2162 if (cclass && c == ']') { 2163 cclass = 0; 2164 if (cp > &genbuf[LBSIZE-1]) 2165 error1(50); 2166 *cp++ = ']'; 2167 continue; 2168 } 2169 if (c == '[' && !cclass) { 2170 cclass = 1; 2171 if (cp > &genbuf[LBSIZE-1]) 2172 error1(50); 2173 *cp++ = '['; 2174 if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0) 2175 error1(67); 2176 if (n == 0 || c == '\n') 2177 error1(49); 2178 } 2179 if (c == '\\' && !cclass) { 2180 if (cp > &genbuf[LBSIZE-1]) 2181 error1(50); 2182 *cp++ = '\\'; 2183 if ((n = _mbftowc(multic, &c, getchr, &peekc)) < 0) 2184 error1(67); 2185 if (n == 0 || c == '\n') 2186 error1(36); 2187 } 2188 if (cp + n > &genbuf[LBSIZE-1]) 2189 error1(50); 2190 (void) strncpy(cp, multic, n); 2191 cp += n; 2192 } 2193 *cp = '\0'; 2194 if (n != 0 && c == '\n') 2195 UNGETC('\n'); 2196 if (n == 0 || c == '\n') 2197 nodelim = 1; 2198 2199 /* 2200 * NULL RE: do not compile a null regular expression; but process 2201 * input with last regular expression encountered 2202 */ 2203 2204 if (genbuf[0] != '\0') { 2205 if (expbuf) 2206 free(expbuf); 2207 expbuf = compile(genbuf, (char *)0, (char *)0); 2208 } 2209 if (regerrno) 2210 error1(regerrno); 2211 } 2212 2213 static void 2214 move(int cflag) 2215 { 2216 LINE adt, ad1, ad2; 2217 2218 setdot(); 2219 nonzero(); 2220 if ((adt = address()) == 0) 2221 (void) error(39); 2222 newline(); 2223 if (!globflg) save(); 2224 if (cflag) { 2225 ad1 = dol; 2226 append(getcopy, ad1++); 2227 ad2 = dol; 2228 } else { 2229 ad2 = addr2; 2230 for (ad1 = addr1; ad1 <= ad2; ) 2231 (ad1++)->cur &= ~01; 2232 ad1 = addr1; 2233 } 2234 ad2++; 2235 if (adt < ad1) { 2236 dot = adt + (ad2-ad1); 2237 if ((++adt) == ad1) 2238 return; 2239 reverse(adt, ad1); 2240 reverse(ad1, ad2); 2241 reverse(adt, ad2); 2242 } else if (adt >= ad2) { 2243 dot = adt++; 2244 reverse(ad1, ad2); 2245 reverse(ad2, adt); 2246 reverse(ad1, adt); 2247 } else 2248 (void) error(39); 2249 fchange = 1; 2250 } 2251 2252 static void 2253 reverse(LINE a1, LINE a2) 2254 { 2255 long t; 2256 2257 for (;;) { 2258 t = (--a2)->cur; 2259 if (a2 <= a1) 2260 return; 2261 a2->cur = a1->cur; 2262 (a1++)->cur = t; 2263 } 2264 } 2265 2266 static int 2267 getcopy(void) 2268 { 2269 2270 if (addr1 > addr2) 2271 return (EOF); 2272 (void) getaline((addr1++)->cur); 2273 return (0); 2274 } 2275 2276 2277 /* 2278 * Handles error code returned from comple() routine: regular expression 2279 * compile and match routines 2280 */ 2281 2282 static void 2283 error1(int code) 2284 { 2285 nbra = 0; 2286 (void) error(code); 2287 } 2288 2289 2290 static int 2291 execute(int gf, LINE addr) 2292 { 2293 char *p1; 2294 int c; 2295 2296 for (c = 0; c < nbra; c++) { 2297 braslist[c] = 0; 2298 braelist[c] = 0; 2299 } 2300 if (gf) 2301 locs = p1 = loc2; 2302 else { 2303 if (addr == zero) 2304 return (0); 2305 p1 = getaline(addr->cur); 2306 locs = 0; 2307 } 2308 return (step(p1, expbuf)); 2309 } 2310 2311 2312 static void 2313 putd() 2314 { 2315 int r; 2316 2317 r = (int)(count%10); 2318 count /= 10; 2319 if (count) 2320 putd(); 2321 putchr(r + '0'); 2322 } 2323 2324 2325 int 2326 puts(const char *sp) 2327 { 2328 int n; 2329 wchar_t c; 2330 int sz, i; 2331 if (fss.Ffill && (listf == 0)) { 2332 2333 /* deliberate attempt to remove constness of sp because */ 2334 /* it needs to be expanded */ 2335 2336 if ((i = expnd((char *)sp, funny, &sz, &fss)) == -1) { 2337 write(1, funny, fss.Flim & 0377); 2338 putchr('\n'); 2339 write(1, gettext("too long"), 2340 strlen(gettext("too long"))); 2341 } 2342 else 2343 write(1, funny, sz); 2344 putchr('\n'); 2345 if (i == -2) 2346 write(1, gettext("tab count\n"), 2347 strlen(gettext("tab count\n"))); 2348 return (0); 2349 } 2350 col = 0; 2351 while (*sp) { 2352 n = mbtowc(&c, sp, MB_LEN_MAX); 2353 if (listf) { 2354 if (n < 1) 2355 (void) error(28); 2356 else if (n == 1) 2357 putchr((unsigned char)*sp++); 2358 else { 2359 sp += n; 2360 putwchr(c); 2361 } 2362 } else { 2363 putchr((unsigned char)*sp++); 2364 } 2365 } 2366 #ifndef XPG6 2367 if (listf) 2368 putchr('$'); /* end of line is marked with a $ */ 2369 #else 2370 if (listf) { 2371 /* xpg6 - ensure that the end of line $ is not preceeded with a "\" */ 2372 /* by doing a putchr() with listf=0, thereby avoiding the $ case */ 2373 /* statement in putchr() */ 2374 listf = 0; 2375 putchr('$'); /* end of line is marked with a $ */ 2376 listf++; 2377 } 2378 #endif 2379 putchr('\n'); 2380 return (1); 2381 } 2382 2383 2384 static void 2385 putwchr(wchar_t ac) 2386 { 2387 char buf[MB_LEN_MAX], *p; 2388 char *lp; 2389 wchar_t c; 2390 short len; 2391 2392 lp = linp; 2393 c = ac; 2394 if (listf) { 2395 if (!iswprint(c)) { 2396 p = &buf[0]; 2397 if ((len = wctomb(p, c)) <= 0) { 2398 *p = (unsigned char)c; 2399 len = 1; 2400 }; 2401 while (len--) { 2402 if (col + 4 >= 72) { 2403 col = 0; 2404 *lp++ = '\\'; 2405 *lp++ = '\n'; 2406 } 2407 (void) sprintf(lp, "\\%03o", 2408 *(unsigned char *)p++); 2409 col += 4; 2410 lp += 4; 2411 } 2412 } else { 2413 if ((len = wcwidth(c)) <= 0) 2414 len = 0; 2415 if (col + len >= 72) { 2416 col = 0; 2417 *lp++ = '\\'; 2418 *lp++ = '\n'; 2419 } 2420 col += len; 2421 if ((len = wctomb(lp, c)) <= 0) { 2422 *lp = (unsigned char)c; 2423 len = 1; 2424 } 2425 lp += len; 2426 } 2427 } else { 2428 if ((len = wctomb(lp, c)) <= 0) { 2429 *lp = (unsigned char)c; 2430 len = 1; 2431 } 2432 lp += len; 2433 } 2434 if (c == '\n' || lp >= &line[64]) { 2435 linp = line; 2436 len = lp - line; 2437 write(1, line, len); 2438 return; 2439 } 2440 linp = lp; 2441 } 2442 2443 2444 static void 2445 putchr(unsigned char c) 2446 { 2447 char *lp; 2448 int len; 2449 2450 lp = linp; 2451 if (listf && c != '\n') { 2452 switch (c) { 2453 case '\\' : 2454 *lp++ = '\\'; 2455 *lp++ = '\\'; 2456 col += 2; 2457 break; 2458 case '\007' : 2459 *lp++ = '\\'; 2460 *lp++ = 'a'; 2461 col += 2; 2462 break; 2463 case '\b' : 2464 *lp++ = '\\'; 2465 *lp++ = 'b'; 2466 col += 2; 2467 break; 2468 case '\f' : 2469 *lp++ = '\\'; 2470 *lp++ = 'f'; 2471 col += 2; 2472 break; 2473 case '\r' : 2474 *lp++ = '\\'; 2475 *lp++ = 'r'; 2476 col += 2; 2477 break; 2478 case '\t' : 2479 *lp++ = '\\'; 2480 *lp++ = 't'; 2481 col += 2; 2482 break; 2483 case '\v' : 2484 *lp++ = '\\'; 2485 *lp++ = 'v'; 2486 col += 2; 2487 break; 2488 #ifdef XPG6 2489 /* if $ characters are within the line preceed with \ */ 2490 case '$' : 2491 *lp++ = '\\'; 2492 *lp++ = '$'; 2493 col += 2; 2494 break; 2495 #endif 2496 default: 2497 if (isprint(c)) { 2498 *lp++ = c; 2499 col += 1; 2500 } else { 2501 (void) sprintf(lp, "\\%03o", c); 2502 col += 4; 2503 lp += 4; 2504 } 2505 break; 2506 } 2507 2508 /* 2509 * long lines are folded w/ pt of folding indicated by writing 2510 * backslash/newline character 2511 */ 2512 2513 if (col + 1 >= 72) { 2514 col = 0; 2515 *lp++ = '\\'; 2516 *lp++ = '\n'; 2517 } 2518 } else 2519 *lp++ = c; 2520 if (c == '\n' || lp >= &line[64]) { 2521 linp = line; 2522 len = lp - line; 2523 (void) write(1, line, len); 2524 return; 2525 } 2526 linp = lp; 2527 } 2528 2529 2530 static char * 2531 getkey(const char *prompt) 2532 { 2533 struct termio b; 2534 int save; 2535 void (*sig)(); 2536 static char key[KSIZE+1]; 2537 char *p; 2538 int c; 2539 2540 sig = signal(SIGINT, SIG_IGN); 2541 ioctl(0, TCGETA, &b); 2542 save = b.c_lflag; 2543 b.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); 2544 ioctl(0, TCSETAW, &b); 2545 write(1, gettext(prompt), strlen(gettext(prompt))); 2546 p = key; 2547 while (((c = getchr()) != EOF) && (c != '\n')) { 2548 if (p < &key[KSIZE]) 2549 *p++ = c; 2550 } 2551 *p = 0; 2552 write(1, "\n", 1); 2553 b.c_lflag = save; 2554 ioctl(0, TCSETAW, &b); 2555 signal(SIGINT, sig); 2556 return (key); 2557 } 2558 2559 2560 static void 2561 globaln(int k) 2562 { 2563 char *gp; 2564 int c; 2565 int n; 2566 wchar_t cl; 2567 LINE a1; 2568 int nfirst; 2569 char globuf[LBSIZE]; 2570 char multic[MB_LEN_MAX]; 2571 int len; 2572 int pflag_save = 0; 2573 int listf_save = 0; 2574 int listn_save = 0; 2575 2576 if (globp) 2577 (void) error(33); 2578 setall(); 2579 nonzero(); 2580 if ((n = _mbftowc(multic, &cl, getchr, &peekc)) <= 0) 2581 (void) error(67); 2582 if (cl == '\n') 2583 (void) error(19); 2584 save(); 2585 comple(cl); 2586 for (a1 = zero; a1 <= dol; a1++) { 2587 a1->cur &= ~01; 2588 if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k) 2589 a1->cur |= 01; 2590 } 2591 nfirst = 0; 2592 newline(); 2593 /* 2594 * preserve the p, l, and n suffix commands of the G and V 2595 * commands during the interactive section and restore 2596 * on completion of the G and V command. 2597 */ 2598 pflag_save = pflag; 2599 listf_save = listf; 2600 listn_save = listn; 2601 pflag = 0; 2602 listf = 0; 2603 listn = 0; 2604 for (a1 = zero; a1 <= dol; a1++) { 2605 if (a1->cur & 01) { 2606 a1->cur &= ~01; 2607 dot = a1; 2608 puts(getaline(a1->cur)); 2609 if ((c = get_wchr()) == EOF) 2610 (void) error(52); 2611 if (c == 'a' || c == 'i' || c == 'c') 2612 (void) error(53); 2613 if (c == '\n') { 2614 a1 = zero; 2615 continue; 2616 } 2617 if (c != '&') { 2618 gp = globuf; 2619 if ((len = wctomb(gp, c)) <= 0) { 2620 *gp = (unsigned char)c; 2621 len = 1; 2622 } 2623 gp += len; 2624 while ((c = get_wchr()) != '\n') { 2625 2626 /* '\\' has special meaning only if preceding a '\n' */ 2627 if (c == '\\') { 2628 c = get_wchr(); 2629 if (c != '\n') 2630 *gp++ = '\\'; 2631 } 2632 if ((gp + (unsigned int)MB_CUR_MAX) >= 2633 &globuf[LBSIZE-1]) 2634 (void) error(34); 2635 2636 if ((len = wctomb(gp, c)) <= 0) { 2637 *gp = (unsigned char)c; 2638 len = 1; 2639 } 2640 gp += len; 2641 } 2642 *gp++ = '\n'; 2643 *gp++ = 0; 2644 nfirst = 1; 2645 } else if ((c = get_wchr()) != '\n') 2646 (void) error(54); 2647 globp = globuf; 2648 if (nfirst) { 2649 globflg = 1; 2650 commands(); 2651 globflg = 0; 2652 } else 2653 (void) error(56); 2654 globp = 0; 2655 a1 = zero; 2656 } 2657 } 2658 pflag = pflag_save; 2659 listf = listf_save; 2660 listn = listn_save; 2661 } 2662 2663 2664 static int 2665 eopen(char *string, int rw) 2666 { 2667 #define w_or_r(a, b) (rw ? a : b) 2668 int pf[2]; 2669 pid_t i; 2670 int io; 2671 int chcount; /* # of char read. */ 2672 2673 if (rflg) { /* restricted shell */ 2674 if (Xqt) { 2675 Xqt = 0; 2676 (void) error(6); 2677 } 2678 } 2679 if (!Xqt) { 2680 if ((io = open(string, rw)) >= 0) { 2681 if (fflg) { 2682 chcount = read(io, crbuf, LBSIZE); 2683 if (crflag == -1) { 2684 if (isencrypt(crbuf, chcount)) 2685 crflag = 2; 2686 else 2687 crflag = -2; 2688 } 2689 if (crflag > 0) 2690 if (run_crypt(0L, crbuf, chcount, perm) == -1) 2691 (void) error(63); 2692 if (fspec(crbuf, &fss, 0) < 0) { 2693 fss.Ffill = 0; 2694 fflg = 0; 2695 (void) error(4); 2696 } 2697 lseek(io, 0L, 0); 2698 } 2699 } 2700 fflg = 0; 2701 return (io); 2702 } 2703 if (pipe(pf) < 0) 2704 xerr: (void) error(0); 2705 if ((i = fork()) == 0) { 2706 signal(SIGHUP, oldhup); 2707 signal(SIGQUIT, oldquit); 2708 signal(SIGPIPE, oldpipe); 2709 signal(SIGINT, (void (*)()) 0); 2710 close(w_or_r(pf[1], pf[0])); 2711 close(w_or_r(0, 1)); 2712 dup(w_or_r(pf[0], pf[1])); 2713 close(w_or_r(pf[0], pf[1])); 2714 execlp(_PATH_BSHELL, "sh", "-c", string, (char *)0); 2715 exit(1); 2716 } 2717 if (i == (pid_t)-1) 2718 goto xerr; 2719 close(w_or_r(pf[0], pf[1])); 2720 return (w_or_r(pf[1], pf[0])); 2721 } 2722 2723 2724 static void 2725 eclose(int f) 2726 { 2727 close(f); 2728 if (Xqt) 2729 Xqt = 0, wait((int *)0); 2730 } 2731 2732 2733 static void 2734 mkfunny(void) 2735 { 2736 char *p, *p1, *p2; 2737 2738 p2 = p1 = funny; 2739 p = file; 2740 /* 2741 * Go to end of file name 2742 */ 2743 while (*p) 2744 p++; 2745 while (*--p == '/') /* delete trailing slashes */ 2746 *p = '\0'; 2747 /* 2748 * go back to beginning of file 2749 */ 2750 p = file; 2751 /* 2752 * Copy file name to funny setting p2 at 2753 * basename of file. 2754 */ 2755 while (*p1++ = *p) 2756 if (*p++ == '/') 2757 p2 = p1; 2758 /* 2759 * Set p1 to point to basename of tfname. 2760 */ 2761 p1 = strrchr(tfname, '/'); 2762 if (strlen(tfname) > (size_t)6) 2763 p1 = &tfname[strlen(tfname)-6]; 2764 p1++; 2765 *p2 = '\007'; /* add unprintable char for funny a unique name */ 2766 /* 2767 * Copy tfname to file. 2768 */ 2769 while (*++p2 = *p1++) 2770 ; 2771 } 2772 2773 2774 static void 2775 getime(void) /* get modified time of file and save */ 2776 { 2777 if (stat(file, &Fl) < 0) 2778 savtime = 0; 2779 else 2780 savtime = Fl.st_mtime; 2781 } 2782 2783 2784 static void 2785 chktime(void) /* check saved mod time against current mod time */ 2786 { 2787 if (savtime != 0 && Fl.st_mtime != 0) { 2788 if (savtime != Fl.st_mtime) 2789 (void) error(58); 2790 } 2791 } 2792 2793 2794 static void 2795 newtime(void) /* get new mod time and save */ 2796 { 2797 stat(file, &Fl); 2798 savtime = Fl.st_mtime; 2799 } 2800 2801 2802 /* 2803 * restricted - check for '/' in name and delete trailing '/' 2804 */ 2805 static void 2806 red(char *op) 2807 { 2808 char *p; 2809 2810 p = op; 2811 while (*p) 2812 if (*p++ == '/'&& rflg) { 2813 *op = 0; 2814 (void) error(6); 2815 } 2816 /* delete trailing '/' */ 2817 while (p > op) { 2818 if (*--p == '/') 2819 *p = '\0'; 2820 else break; 2821 } 2822 } 2823 2824 2825 /* 2826 * Searches thru beginning of file looking for a string of the form 2827 * <: values... :> 2828 * 2829 * where "values" are 2830 * 2831 * \b ignored 2832 * s<num> sets the Flim to <num> 2833 * t??? sets tab stop stuff 2834 * d ignored 2835 * m<num> ignored 2836 * e ignored 2837 */ 2838 2839 static int 2840 fspec(char line[], struct Fspec *f, int up) 2841 { 2842 struct termio arg; 2843 int havespec, n; 2844 int len; 2845 2846 if (!up) clear(f); 2847 2848 havespec = fsprtn = 0; 2849 for (fsp = line; *fsp && *fsp != '\n'; fsp += len) { 2850 if ((len = mblen(fsp, MB_CUR_MAX)) <= 0) 2851 len = 1; 2852 switch (*fsp) { 2853 2854 case '<': if (havespec) 2855 return (-1); 2856 if (*(fsp+1) == ':') { 2857 havespec = 1; 2858 clear(f); 2859 if (!ioctl(1, TCGETA, &arg) && 2860 ((arg.c_oflag & TAB3) == 2861 TAB3)) 2862 f->Ffill = 1; 2863 fsp++; 2864 } 2865 continue; 2866 2867 case ' ': continue; 2868 2869 case 's': if (havespec && (n = numb()) >= 0) 2870 f->Flim = n; 2871 continue; 2872 2873 case 't': if (havespec) targ(f); 2874 continue; 2875 2876 case 'd': continue; 2877 2878 case 'm': if (havespec) n = numb(); 2879 continue; 2880 2881 case 'e': continue; 2882 case ':': if (!havespec) continue; 2883 if (*(fsp+1) != '>') fsprtn = -1; 2884 return (fsprtn); 2885 2886 default: if (!havespec) continue; 2887 return (-1); 2888 } 2889 } 2890 return (1); 2891 } 2892 2893 2894 static int 2895 numb(void) 2896 { 2897 int n; 2898 2899 n = 0; 2900 while (*++fsp >= '0' && *fsp <= '9') 2901 n = 10*n + *fsp-'0'; 2902 fsp--; 2903 return (n); 2904 } 2905 2906 2907 static void 2908 targ(struct Fspec *f) 2909 { 2910 2911 if (*++fsp == '-') { 2912 if (*(fsp + 1) >= '0' && *(fsp+1) <= '9') tincr(numb(), f); 2913 else tstd(f); 2914 return; 2915 } 2916 if (*fsp >= '0' && *fsp <= '9') { 2917 tlist(f); 2918 return; 2919 } 2920 fsprtn = -1; 2921 fsp--; 2922 } 2923 2924 2925 static void 2926 tincr(int n, struct Fspec *f) 2927 { 2928 int l, i; 2929 2930 l = 1; 2931 for (i = 0; i < 20; i++) 2932 f->Ftabs[i] = l += n; 2933 f->Ftabs[i] = 0; 2934 } 2935 2936 2937 static void 2938 tstd(struct Fspec *f) 2939 { 2940 char std[3]; 2941 2942 std[0] = *++fsp; 2943 if (*(fsp+1) >= '0' && *(fsp+1) <= '9') { 2944 std[1] = *++fsp; 2945 std[2] = '\0'; 2946 } else { 2947 std[1] = '\0'; 2948 } 2949 fsprtn = stdtab(std, f->Ftabs); 2950 } 2951 2952 2953 static void 2954 tlist(struct Fspec *f) 2955 { 2956 int n, last, i; 2957 2958 fsp--; 2959 last = i = 0; 2960 2961 do { 2962 if ((n = numb()) <= last || i >= 20) { 2963 fsprtn = -1; 2964 return; 2965 } 2966 f->Ftabs[i++] = last = n; 2967 } while (*++fsp == ','); 2968 2969 f->Ftabs[i] = 0; 2970 fsp--; 2971 } 2972 2973 2974 static int 2975 expnd(char line[], char buf[], int *sz, struct Fspec *f) 2976 { 2977 char *l, *t; 2978 int b; 2979 2980 l = line - 1; 2981 b = 1; 2982 t = f->Ftabs; 2983 fsprtn = 0; 2984 2985 while (*++l && *l != '\n' && b < 511) { 2986 if (*l == '\t') { 2987 while (*t && b >= *t) 2988 t++; 2989 if (*t == 0) 2990 fsprtn = -2; 2991 do { 2992 buf[b-1] = ' '; 2993 } while (++b < *t); 2994 } else { 2995 buf[b++ - 1] = *l; 2996 } 2997 } 2998 2999 buf[b] = '\0'; 3000 *sz = b; 3001 if (*l != '\0' && *l != '\n') { 3002 buf[b-1] = '\n'; 3003 return (-1); 3004 } 3005 buf[b-1] = *l; 3006 if (f->Flim && (b-1 > (int)f->Flim)) 3007 return (-1); 3008 return (fsprtn); 3009 } 3010 3011 3012 static void 3013 clear(struct Fspec *f) 3014 { 3015 f->Ftabs[0] = f->Fdel = f->Fmov = f->Ffill = 0; 3016 f->Flim = 0; 3017 } 3018 3019 3020 static int 3021 lenchk(char line[], struct Fspec *f) 3022 { 3023 char *l, *t; 3024 int b; 3025 3026 l = line - 1; 3027 b = 1; 3028 t = f->Ftabs; 3029 3030 while (*++l && *l != '\n' && b < 511) { 3031 if (*l == '\t') { 3032 while (*t && b >= *t) 3033 t++; 3034 while (++b < *t) 3035 ; 3036 } else { 3037 b++; 3038 } 3039 } 3040 3041 if ((*l != '\0' && *l != '\n') || (f->Flim && (b-1 > (int)f->Flim))) 3042 return (-1); 3043 return (0); 3044 } 3045 #define NTABS 21 3046 3047 3048 /* 3049 * stdtabs: standard tabs table 3050 * format: option code letter(s), null, tabs, null 3051 */ 3052 3053 static char stdtabs[] = { 3054 'a', 0, 1, 10, 16, 36, 72, 0, /* IBM 370 Assembler */ 3055 'a', '2', 0, 1, 10, 16, 40, 72, 0, /* IBM Assembler alternative */ 3056 'c', 0, 1, 8, 12, 16, 20, 55, 0, /* COBOL, normal */ 3057 'c', '2', 0, 1, 6, 10, 14, 49, 0, /* COBOL, crunched */ 3058 'c', '3', 0, 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 3059 54, 58, 62, 67, 0, 3060 'f', 0, 1, 7, 11, 15, 19, 23, 0, /* FORTRAN */ 3061 'p', 0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0, 3062 /* PL/I */ 3063 's', 0, 1, 10, 55, 0, /* SNOBOL */ 3064 'u', 0, 1, 12, 20, 44, 0, /* UNIVAC ASM */ 3065 0 }; 3066 3067 3068 /* 3069 * stdtab: return tab list for any "canned" tab option. 3070 * entry: option points to null-terminated option string 3071 * tabvect points to vector to be filled in 3072 * exit: return (0) if legal, tabvect filled, ending with zero 3073 * return (-1) if unknown option 3074 */ 3075 3076 3077 static int 3078 stdtab(char *option, char *tabvect) 3079 { 3080 char *scan; 3081 3082 tabvect[0] = '\0'; 3083 scan = stdtabs; 3084 while (*scan) { 3085 if (strequal(&scan, option)) { 3086 strcopy(scan, tabvect); 3087 break; 3088 } else 3089 while (*scan++) /* skip over tab specs */ 3090 ; 3091 } 3092 3093 /* later: look up code in /etc/something */ 3094 return (tabvect[0] ? 0 : -1); 3095 } 3096 3097 3098 /* 3099 * strequal: checks strings for equality 3100 * entry: scan1 points to scan pointer, str points to string 3101 * exit: return (1) if equal, return (0) if not 3102 * *scan1 is advanced to next nonzero byte after null 3103 */ 3104 3105 3106 static int 3107 strequal(char **scan1, char *str) 3108 { 3109 char c, *scan; 3110 scan = *scan1; 3111 while ((c = *scan++) == *str && c) 3112 str++; 3113 *scan1 = scan; 3114 if (c == 0 && *str == 0) 3115 return (1); 3116 if (c) 3117 while (*scan++) 3118 ; 3119 *scan1 = scan; 3120 return (0); 3121 } 3122 3123 3124 /* strcopy: copy source to destination */ 3125 3126 3127 static void 3128 strcopy(char *source, char *dest) 3129 { 3130 while (*dest++ = *source++) 3131 ; 3132 } 3133 3134 3135 /* This is called before a buffer modifying command so that the */ 3136 /* current array of line ptrs is saved in sav and dot and dol are saved */ 3137 3138 3139 static void 3140 save(void) 3141 { 3142 LINE i; 3143 int j; 3144 3145 savdot = dot; 3146 savdol = dol; 3147 for (j = 0; j <= 25; j++) 3148 savnames[j] = names[j]; 3149 3150 for (i = zero + 1; i <= dol; i++) 3151 i->sav = i->cur; 3152 initflg = 0; 3153 } 3154 3155 3156 /* The undo command calls this to restore the previous ptr array sav */ 3157 /* and swap with cur - dot and dol are swapped also. This allows user to */ 3158 /* undo an undo */ 3159 3160 3161 static void 3162 undo(void) 3163 { 3164 int j; 3165 long tmp; 3166 LINE i, tmpdot, tmpdol; 3167 3168 tmpdot = dot; dot = savdot; savdot = tmpdot; 3169 tmpdol = dol; dol = savdol; savdol = tmpdol; 3170 /* swap arrays using the greater of dol or savdol as upper limit */ 3171 for (i = zero + 1; i <= ((dol > savdol) ? dol : savdol); i++) { 3172 tmp = i->cur; 3173 i->cur = i->sav; 3174 i->sav = tmp; 3175 } 3176 /* 3177 * If the current text lines are swapped with the 3178 * text lines in the save buffer, then swap the current 3179 * marks with those in the save area. 3180 */ 3181 3182 for (j = 0; j <= 25; j++) { 3183 tmp = names[j]; 3184 names[j] = savnames[j]; 3185 savnames[j] = tmp; 3186 } 3187 } 3188 3189 static wchar_t 3190 get_wchr(void) 3191 { 3192 wchar_t wc; 3193 char multi[MB_LEN_MAX]; 3194 3195 if (_mbftowc(multi, &wc, getchr, &peekc) <= 0) 3196 wc = getchr(); 3197 return (wc); 3198 } 3199