|
|
1.1 ! root 1: /* ! 2: * An editor. ! 3: * Commands. ! 4: */ ! 5: #include <stdio.h> ! 6: #include <ctype.h> ! 7: #include "ed.h" ! 8: ! 9: /* ! 10: * Edit a file. The filename is stored in `file'. ! 11: */ ! 12: edit() ! 13: { ! 14: register int ret, i; ! 15: ! 16: if (doladd > 0) ! 17: delete(1, doladd); ! 18: tmpseek = CLSIZE; ! 19: rcurbno = -1; ! 20: wcurbno = -1; ! 21: if ((fp=xfopen(file, "r")) == NULL) { ! 22: derror("Cannot open file"); ! 23: return (0); ! 24: } ! 25: #if RSX ! 26: if ((i=fp->v_efbk+1-tmp->v_hibk) > 0) { ! 27: if (grow(i) == 0) { ! 28: terror("Temp file error"); ! 29: return (0); ! 30: } ! 31: } ! 32: #endif ! 33: ret = 1; ! 34: if (append(0, readfil) == 0) ! 35: ret = 0; ! 36: else if (ferror(fp)) { ! 37: derror("Read error"); ! 38: ret = 0; ! 39: } ! 40: fclose(fp); ! 41: for (i=0; i<MKSIZE; i++) ! 42: marklin[i] = 0; ! 43: saved = 1; ! 44: if (cflag != 0) { ! 45: printl(stdout, !oflag ? cct : lct); ! 46: printc(stdout, '\n'); ! 47: } ! 48: return (ret); ! 49: } ! 50: ! 51: /* ! 52: * Make sure that the previous command is terminated either ! 53: * immediately by a newline or has a 'p' or a 'l' which is ! 54: * then terminated by a newline. The variable `vcom' is set ! 55: * to the verify command. A zero is returned if there were ! 56: * bad characters before the newline, otherwise a one. ! 57: */ ! 58: verify(flag) ! 59: { ! 60: register int c; ! 61: ! 62: vcom = ' '; ! 63: if (flag==0 && mflag!=0) ! 64: return (1); ! 65: if ((c=getx()) == '\n') { ! 66: ungetx(c); ! 67: return (1); ! 68: } ! 69: if (c=='l' || c=='p') { ! 70: if (getx() == '\n') { ! 71: ungetx('\n'); ! 72: vcom = c; ! 73: return (1); ! 74: } ! 75: } ! 76: derror("Bad command"); ! 77: return (0); ! 78: } ! 79: ! 80: /* ! 81: * Get a filename of the form required for the r command. ! 82: * which is returned in `name'. If no name is specified, ! 83: * the one stored in `file' is copied. If a file name is ! 84: * specified and none exists in `file', it is copied to ! 85: * `file'. If an illegal name is given, an error is derrord. ! 86: */ ! 87: getfile(name) ! 88: char name[FNSIZE+1]; ! 89: { ! 90: register int c; ! 91: register char *p1, *p2; ! 92: ! 93: switch (c=getx()) { ! 94: case '\n': ! 95: p1 = name; ! 96: p2 = file; ! 97: while (*p1++ = *p2++) ! 98: ; ! 99: break; ! 100: case ' ': ! 101: case '\t': ! 102: p1 = name; ! 103: p2 = &name[FNSIZE]; ! 104: while ((c=getx()) == ' ' || c == '\t') ! 105: ; ! 106: *p1++ = c; ! 107: while ((c=getx()) != EOF && c != '\n') { ! 108: if (p1 >= p2) { ! 109: derror("File name too long"); ! 110: name[0] = '\0'; ! 111: return (0); ! 112: } ! 113: *p1++ = c; ! 114: } ! 115: *p1 = '\0'; ! 116: if (c == EOF) { ! 117: derror("EOF in file name"); ! 118: name[0] = '\0'; ! 119: return (0); ! 120: } ! 121: if (file[0] == '\0') { ! 122: p1 = file; ! 123: p2 = name; ! 124: while (*p1++ = *p2++) ! 125: ; ! 126: } ! 127: break; ! 128: default: ! 129: while (getx() != '\n') ! 130: ; ! 131: derror("Bad command"); ! 132: return (0); ! 133: } ! 134: if (name[0] == '\0') { ! 135: derror("Null file name"); ! 136: return (0); ! 137: } ! 138: return (1); ! 139: } ! 140: ! 141: /* ! 142: * Read the rest of the input line into `tempbuf'. ! 143: */ ! 144: rest() ! 145: { ! 146: register int c; ! 147: register char *cp; ! 148: ! 149: cp = tempbuf; ! 150: while ((c=getx())!=EOF && c!='\n') { ! 151: if (cp >= &tempbuf[TBSIZE-1]) { ! 152: derror("Line too long"); ! 153: return (0); ! 154: } ! 155: *cp++ = c; ! 156: } ! 157: *cp = '\0'; ! 158: return (1); ! 159: } ! 160: ! 161: /* ! 162: * Append text after the given address. A line of text is gotten ! 163: * by calling the given function until it returns NULL. ! 164: */ ! 165: append(a, f) ! 166: int (*f)(); ! 167: { ! 168: int seek; ! 169: register int n; ! 170: ! 171: cct = 0; ! 172: lct = 0; ! 173: if (a<0 || a>doladd) { ! 174: derror("Address out of range"); ! 175: return (0); ! 176: } ! 177: dotadd = a; ! 178: while ((n=(*f)()) != 0) { ! 179: if (intflag) ! 180: return (1); ! 181: seek = linead(); ! 182: if (putline(linebuf, n) == 0) ! 183: return (0); ! 184: saved = 0; ! 185: cct += n; ! 186: lct++; ! 187: if (expand(dotadd) == 0) ! 188: return (0); ! 189: line[++dotadd] = seek; ! 190: } ! 191: return (1); ! 192: } ! 193: ! 194: /* ! 195: * Expand the line table and leave a hole at the given address. ! 196: */ ! 197: expand(a) ! 198: { ! 199: register LINE *lp1; ! 200: register LINE *lp2; ! 201: register int n; ! 202: ! 203: if (doladd+3 >= lnsize) { ! 204: lp1 = (LINE *)realloc(line, (n=lnsize*2)*sizeof(LINE)); ! 205: if (lp1 == NULL) { ! 206: derror("Line table overflow"); ! 207: return (0); ! 208: } ! 209: line = lp1; ! 210: lnsize = n; ! 211: } ! 212: lp1 = &line[doladd+2]; ! 213: lp2 = &line[doladd+1]; ! 214: n = doladd++ - a; ! 215: while (n--) ! 216: *--lp1 = *--lp2; ! 217: return (1); ! 218: } ! 219: ! 220: /* ! 221: * Get a line of text from the terminal. The number of characters ! 222: * including the null terminator at the end of the string is returned. ! 223: * If end of file or a line containing only a single dot is found, ! 224: * 0 is returned. ! 225: */ ! 226: readtty() ! 227: { ! 228: register int c; ! 229: register char *lp; ! 230: ! 231: appflag++; ! 232: lp = linebuf; ! 233: while ((c=getx())!=EOF && c!='\n') { ! 234: if (lp < &linebuf[LBSIZE-1]) ! 235: *lp++ = c; ! 236: } ! 237: --appflag; ! 238: if (c==EOF && lp==linebuf) { ! 239: lastchr = '\n'; ! 240: if (gcp == NULL) ! 241: clearerr(stdin); ! 242: return (0); ! 243: } ! 244: if (linebuf[0]=='.' && lp==linebuf+1) ! 245: return (0); ! 246: *lp++ = '\0'; ! 247: return (lp-linebuf); ! 248: } ! 249: ! 250: /* ! 251: * Get a line of text from the file open on file pointer `fp'. ! 252: * Return the number of characters in the line including the ! 253: * null terminator at the end. On end of file, 0 is returned. ! 254: */ ! 255: readfil() ! 256: { ! 257: register int c, n; ! 258: register char *lp; ! 259: ! 260: if ((c=getc(fp)) == EOF) ! 261: return (0); ! 262: lp = linebuf; ! 263: n = LBSIZE-1; ! 264: while (c!=EOF && c!='\n') { ! 265: *lp++ = c; ! 266: if (--n == 0) ! 267: break; ! 268: c = getc(fp); ! 269: } ! 270: *lp++ = '\0'; ! 271: return (lp-linebuf); ! 272: } ! 273: ! 274: /* ! 275: * Delete the given line range. ! 276: */ ! 277: delete(a1, a2) ! 278: { ! 279: register LINE *p1, *p2; ! 280: register int n; ! 281: ! 282: if (a1>a2 || a1<1 || a2>doladd) { ! 283: derror("Address out of range"); ! 284: return (0); ! 285: } ! 286: p1 = &line[a1]; ! 287: p2 = &line[a2+1]; ! 288: n = doladd - a2; ! 289: while (n--) ! 290: *p1++ = *p2++; ! 291: doladd -= (a2+1) - a1; ! 292: if ((dotadd=a1) > doladd) ! 293: --dotadd; ! 294: saved = doladd==0; ! 295: return (1); ! 296: } ! 297: ! 298: /* ! 299: * Concatenate the lines in the given range to form ! 300: * a single line. ! 301: */ ! 302: join(a1, a2) ! 303: { ! 304: long seek; ! 305: int bn, a; ! 306: register int n; ! 307: register char *lp, *tp; ! 308: ! 309: if (a1>a2 || a1<1 || a2>doladd) { ! 310: derror("Address out of range"); ! 311: return (0); ! 312: } ! 313: bn = 0; ! 314: lp = linebuf; ! 315: for (a=a1; a<=a2; a++) { ! 316: if ((n=getline(a, tempbuf)) == 0) ! 317: return (0); ! 318: if ((bn+=--n) >= LBSIZE-1) { ! 319: derror("Temporary buffer overflow"); ! 320: return (0); ! 321: } ! 322: tp = tempbuf; ! 323: while (n--) ! 324: *lp++ = *tp++; ! 325: } ! 326: *lp++ = '\0'; ! 327: seek = linead(); ! 328: if (putline(linebuf, ++bn) == 0) ! 329: return (0); ! 330: line[a1] = seek; ! 331: a = doladd - a2; ! 332: for (n=0; n<a; n++) ! 333: line[a1+1+n] = line[a2+1+n]; ! 334: dotadd = a1; ! 335: doladd -= a2 - a1; ! 336: return (1); ! 337: } ! 338: ! 339: /* ! 340: * List the given line range. All non-printing characters are ! 341: * escaped. ! 342: */ ! 343: list(a1, a2) ! 344: { ! 345: int a; ! 346: register int n; ! 347: register char *p; ! 348: ! 349: if (a1>a2 || a1<1 || a2>doladd) { ! 350: derror("Address out of range"); ! 351: return (0); ! 352: } ! 353: for (a=a1; a<=a2; a++) { ! 354: if (intflag) ! 355: return (1); ! 356: if (getline(a, linebuf) == 0) ! 357: break; ! 358: n = 0; ! 359: for (p=linebuf; *p; p++) { ! 360: if (n++ >= 72) { ! 361: n = 0; ! 362: prints(stdout, "\\\n"); ! 363: } ! 364: switch (*p) { ! 365: case '\b': ! 366: prints(stdout, "-\b<"); ! 367: continue; ! 368: case '\t': ! 369: prints(stdout, "-\b>"); ! 370: continue; ! 371: case '\\': ! 372: prints(stdout, "\\\\"); ! 373: continue; ! 374: default: ! 375: if (isascii(*p) && !iscntrl(*p)) { ! 376: printc(stdout, *p); ! 377: continue; ! 378: } ! 379: printc(stdout, '\\'); ! 380: printo(stdout, *p); ! 381: n += 3; ! 382: } ! 383: } ! 384: prints(stdout, "\\n"); ! 385: printc(stdout, '\n'); ! 386: dotadd = a; ! 387: } ! 388: return (1); ! 389: } ! 390: ! 391: /* ! 392: * Take the text that is between lines `a1' and `a2' and ! 393: * place it after line `a3'. ! 394: */ ! 395: move(a1, a2, a3) ! 396: int a1, a2, a3; ! 397: { ! 398: LINE l; ! 399: register int a, n, x; ! 400: ! 401: if (a1>a2 || a1<1 || a2>doladd || a3<0 || a3>doladd) { ! 402: derror("Address out of range"); ! 403: return (0); ! 404: } ! 405: if (a3>=a1-1 && a3<=a2) { ! 406: dotadd = a2; ! 407: return (1); ! 408: } ! 409: if (a3 < a1) { ! 410: for (a=a1, x=a3+1; a<=a2; a++, x++) { ! 411: l = line[a]; ! 412: for (n=a; n>x; --n) ! 413: line[n] = line[n-1]; ! 414: line[x] = l; ! 415: } ! 416: dotadd = a3 + a2+1 - a1; ! 417: } else { ! 418: for (a=a2, x=a3; a>=a1; --a, --x) { ! 419: l = line[a]; ! 420: for (n=a; n<x; n++) ! 421: line[n] = line[n+1]; ! 422: line[x] = l; ! 423: } ! 424: dotadd = a3; ! 425: } ! 426: saved = 0; ! 427: return (1); ! 428: } ! 429: ! 430: /* ! 431: * Given a string describing a set of options, set them. ! 432: */ ! 433: setoptf(sp) ! 434: register char *sp; ! 435: { ! 436: register int t; ! 437: ! 438: t = 1; ! 439: while (*sp != '\0') { ! 440: switch (*sp++) { ! 441: case '+': ! 442: t = 1; ! 443: continue; ! 444: case '-': ! 445: t = 0; ! 446: continue; ! 447: case 'c': ! 448: cflag = t; ! 449: continue; ! 450: case 'm': ! 451: mflag = t; ! 452: continue; ! 453: case 'o': ! 454: oflag = t; ! 455: continue; ! 456: case 'p': ! 457: pflag = t; ! 458: continue; ! 459: case 's': ! 460: sflag = t; ! 461: continue; ! 462: case 'v': ! 463: vflag = t; ! 464: continue; ! 465: default: ! 466: derror("Bad option"); ! 467: return; ! 468: } ! 469: } ! 470: } ! 471: ! 472: /* ! 473: * Display options. ! 474: */ ! 475: disoptf() ! 476: { ! 477: if (cflag) ! 478: printc(stdout, 'c'); ! 479: if (mflag) ! 480: printc(stdout, 'm'); ! 481: if (oflag) ! 482: printc(stdout, 'o'); ! 483: if (pflag) ! 484: printc(stdout, 'p'); ! 485: if (sflag) ! 486: printc(stdout, 's'); ! 487: if (vflag) ! 488: printc(stdout, 'v'); ! 489: if (keyp != NULL) ! 490: printc(stdout, 'x'); ! 491: printc(stdout, '\n'); ! 492: } ! 493: ! 494: /* ! 495: * Print the given line range. ! 496: */ ! 497: print(a1, a2) ! 498: { ! 499: register int a; ! 500: register char *p; ! 501: ! 502: if (a1>a2 || a1<1 || a2>doladd) { ! 503: derror("Address out of range"); ! 504: return (0); ! 505: } ! 506: for (a=a1; a<=a2; a++) { ! 507: if (intflag) ! 508: return (1); ! 509: if (getline(a, linebuf) == 0) ! 510: break; ! 511: p = linebuf; ! 512: while (*p) ! 513: printc(stdout, *p++); ! 514: printc(stdout, '\n'); ! 515: dotadd = a; ! 516: } ! 517: return (1); ! 518: } ! 519: ! 520: /* ! 521: * Make a copy of the text between lines `a1' and `a2' ! 522: * and place them after `a3'. ! 523: */ ! 524: copy(a1, a2, a3) ! 525: { ! 526: register int i, j, n; ! 527: ! 528: if (a1>a2 || a1<1 || a2>doladd || a3<0 || a3>doladd) { ! 529: derror("Address out of range"); ! 530: return (0); ! 531: } ! 532: n = (a2+1) - a1; ! 533: if (doladd+n+2 > lnsize) { ! 534: derror("Line table overflow"); ! 535: return (0); ! 536: } ! 537: for (i=doladd; i>a3; --i) ! 538: line[i+n] = line[i]; ! 539: for (i=0; i<n; i++) { ! 540: if ((j=i+a1) > a3) ! 541: j += n; ! 542: if ((j=getline(j, linebuf)) == 0) ! 543: goto err; ! 544: line[a3+1+i] = linead(); ! 545: if (putline(linebuf, j) == 0) ! 546: goto err; ! 547: } ! 548: dotadd = a3+n; ! 549: doladd += n; ! 550: saved = 0; ! 551: return (1); ! 552: ! 553: err: ! 554: for (i=a3+1; i<=doladd; i++) ! 555: line[i] = line[i+n]; ! 556: return (0); ! 557: } ! 558: ! 559: /* ! 560: * Write the given line range onto the file whose name is ! 561: * stored in `file'. `perm' is the permission string we ! 562: * want the file opened with. ! 563: */ ! 564: wfile(a1, a2, name, perm, sflag) ! 565: char *name, *perm; ! 566: { ! 567: register int a; ! 568: register char *cp; ! 569: ! 570: if (doladd!=0 || addspec!=0) { ! 571: if (a1>a2 || a1<1 || a2>doladd) { ! 572: derror("Address out of range"); ! 573: return (0); ! 574: } ! 575: } ! 576: if ((fp=xfopen(name, perm)) == NULL) { ! 577: derror("Cannot open file"); ! 578: return (0); ! 579: } ! 580: cct = 0; ! 581: lct = 0; ! 582: for (a=a1; a<=a2; a++) { ! 583: if (getline(a, linebuf) == 0) ! 584: break; ! 585: cp = linebuf; ! 586: while (*cp) { ! 587: printc(fp, *cp++); ! 588: cct++; ! 589: } ! 590: printc(fp, '\n'); ! 591: if (ferror(fp)) ! 592: break; ! 593: cct++; ! 594: lct++; ! 595: } ! 596: if (sflag==0 && cflag!=0) { ! 597: printl(stdout, !oflag ? cct : lct); ! 598: printc(stdout, '\n'); ! 599: } ! 600: if ((a=ferror(fp)) == 0) ! 601: saved = 1; ! 602: else { ! 603: if (sflag == 0) ! 604: derror("Write error"); ! 605: } ! 606: fclose(fp); ! 607: #if COHERENT ! 608: sync(); ! 609: #endif ! 610: return (!a); ! 611: } ! 612: ! 613: /* ! 614: * Open a file. If we are in encryption mode, the open unit is really a ! 615: * file descriptor piped to the crypt command. ! 616: */ ! 617: FILE * ! 618: xfopen(fn, mode) ! 619: char *fn; ! 620: char *mode; ! 621: { ! 622: #if COHERENT ! 623: register FILE *fp; ! 624: register int f; ! 625: register int u; ! 626: register int a; ! 627: register int b; ! 628: int pv[2]; ! 629: ! 630: if (keyp == NULL) ! 631: fp = fopen(fn, mode); ! 632: else { ! 633: switch (mode[0]) { ! 634: case 'a': ! 635: return (NULL); ! 636: case 'r': ! 637: a = 0; ! 638: b = 1; ! 639: break; ! 640: case 'w': ! 641: a = 1; ! 642: b = 0; ! 643: break; ! 644: } ! 645: if (pipe(pv) < 0) ! 646: return (NULL); ! 647: if ((f=fork()) < 0) { ! 648: close(pv[0]); ! 649: close(pv[1]); ! 650: return (NULL); ! 651: } ! 652: if (f == 0) { ! 653: if ((u=(a==0)?open(fn, 0):creat(fn, 0644)) < 0) ! 654: exit(1); ! 655: dup2(u, a); ! 656: dup2(pv[b], b); ! 657: close(u); ! 658: close(pv[0]); ! 659: close(pv[1]); ! 660: execl("/bin/crypt", "crypt", keyp, NULL); ! 661: exit(1); ! 662: } ! 663: close(pv[b]); ! 664: fp = fdopen(pv[a], mode); ! 665: } ! 666: return (fp); ! 667: #else ! 668: return(fopen(fn, mode)); ! 669: #endif ! 670: } ! 671: ! 672: /* ! 673: * Read a key from the standard input. ! 674: */ ! 675: setkey() ! 676: { ! 677: #if COHERENT ! 678: register int n; ! 679: ! 680: keyp = getpass("key? "); ! 681: if ((n=strlen(keyp)) > CKSIZE) { ! 682: derror("Key too long"); ! 683: keyp = NULL; ! 684: return (0); ! 685: } ! 686: if (n == 0) ! 687: keyp = NULL; ! 688: return (1); ! 689: #else ! 690: derror("Cannot set key"); ! 691: return (0); ! 692: #endif ! 693: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.