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