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