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