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