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