|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that this notice is preserved and that due credit is given ! 7: * to the University of California at Berkeley. The name of the University ! 8: * may not be used to endorse or promote products derived from this ! 9: * software without specific prior written permission. This software ! 10: * is provided ``as is'' without express or implied warranty. ! 11: */ ! 12: ! 13: #ifdef notdef ! 14: static char sccsid[] = "@(#)collect.c 5.6 (Berkeley) 2/18/88"; ! 15: #endif /* notdef */ ! 16: ! 17: /* ! 18: * Mail -- a mail program ! 19: * ! 20: * Collect input from standard input, handling ! 21: * ~ escapes. ! 22: */ ! 23: ! 24: #include "rcv.h" ! 25: #include <sys/stat.h> ! 26: #include <sys/wait.h> ! 27: ! 28: /* ! 29: * Read a message from standard output and return a read file to it ! 30: * or NULL on error. ! 31: */ ! 32: ! 33: /* ! 34: * The following hokiness with global variables is so that on ! 35: * receipt of an interrupt signal, the partial message can be salted ! 36: * away on dead.letter. ! 37: */ ! 38: ! 39: static int (*saveint)(); /* Previous SIGINT value */ ! 40: static int (*savehup)(); /* Previous SIGHUP value */ ! 41: static int (*savecont)(); /* Previous SIGCONT value */ ! 42: static FILE *collf; /* File for saving away */ ! 43: static int hadintr; /* Have seen one SIGINT so far */ ! 44: ! 45: static jmp_buf coljmp; /* To get back to work */ ! 46: ! 47: FILE * ! 48: collect(hp) ! 49: struct header *hp; ! 50: { ! 51: FILE *fp, *fbuf; ! 52: int lc, cc, escape, eof; ! 53: int collrub(), intack(), collcont(); ! 54: register int c, t; ! 55: char linebuf[LINESIZE], *cp; ! 56: extern char tempMail[]; ! 57: int notify(); ! 58: char getsub; ! 59: int omask; ! 60: ! 61: noreset++; ! 62: fp = NULL; ! 63: collf = NULL; ! 64: ! 65: /* ! 66: * Start catching signals from here, but we're still die on interrupts ! 67: * until we're in the main loop. ! 68: */ ! 69: omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); ! 70: if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) ! 71: signal(SIGINT, value("ignore") != NOSTR ? intack : collrub); ! 72: if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) ! 73: signal(SIGHUP, collrub); ! 74: savecont = signal(SIGCONT, SIG_DFL); ! 75: if (setjmp(coljmp)) { ! 76: remove(tempMail); ! 77: goto err; ! 78: } ! 79: sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP))); ! 80: ! 81: if ((fp = fopen(tempMail, "w+")) == NULL) { ! 82: perror(tempMail); ! 83: goto err; ! 84: } ! 85: collf = fp; ! 86: remove(tempMail); ! 87: ! 88: /* ! 89: * If we are going to prompt for a subject, ! 90: * refrain from printing a newline after ! 91: * the headers (since some people mind). ! 92: */ ! 93: t = GTO|GSUBJECT|GCC|GNL; ! 94: getsub = 0; ! 95: if (intty && sflag == NOSTR && hp->h_subject == NOSTR && value("ask")) ! 96: t &= ~GNL, getsub++; ! 97: if (hp->h_seq != 0) { ! 98: puthead(hp, stdout, t); ! 99: fflush(stdout); ! 100: } ! 101: escape = ESCAPE; ! 102: if ((cp = value("escape")) != NOSTR) ! 103: escape = *cp; ! 104: eof = 0; ! 105: hadintr = 0; ! 106: ! 107: /* ! 108: * We can put the setjmp here because register variable ! 109: * needs to be saved in the loop. ! 110: */ ! 111: if (!setjmp(coljmp)) { ! 112: signal(SIGCONT, collcont); ! 113: if (getsub) ! 114: grabh(hp, GSUBJECT); ! 115: } else { ! 116: /* ! 117: * Come here for printing the after-signal message. ! 118: * Duplicate messages won't be printed because ! 119: * the write is aborted if we get a SIGTTOU. ! 120: */ ! 121: cont: ! 122: if (hadintr) { ! 123: fflush(stdout); ! 124: fprintf(stderr, ! 125: "\n(Interrupt -- one more to kill letter)\n"); ! 126: } else { ! 127: printf("(continue)\n"); ! 128: fflush(stdout); ! 129: } ! 130: } ! 131: for (;;) { ! 132: if (readline(stdin, linebuf) < 0) { ! 133: if (intty && value("ignoreeof") != NOSTR) { ! 134: if (++eof > 35) ! 135: break; ! 136: printf("Use \".\" to terminate letter\n"); ! 137: continue; ! 138: } ! 139: break; ! 140: } ! 141: eof = 0; ! 142: hadintr = 0; ! 143: if (intty && equal(".", linebuf) && ! 144: (value("dot") != NOSTR || value("ignoreeof") != NOSTR)) ! 145: break; ! 146: if (linebuf[0] != escape || rflag != NOSTR) { ! 147: if (putline(fp, linebuf) < 0) ! 148: goto err; ! 149: continue; ! 150: } ! 151: c = linebuf[1]; ! 152: switch (c) { ! 153: default: ! 154: /* ! 155: * On double escape, just send the single one. ! 156: * Otherwise, it's an error. ! 157: */ ! 158: ! 159: if (c == escape) { ! 160: if (putline(fp, &linebuf[1]) < 0) ! 161: goto err; ! 162: else ! 163: break; ! 164: } ! 165: printf("Unknown tilde escape.\n"); ! 166: break; ! 167: ! 168: case 'C': ! 169: /* ! 170: * Dump core. ! 171: */ ! 172: ! 173: core(); ! 174: break; ! 175: ! 176: case '!': ! 177: /* ! 178: * Shell escape, send the balance of the ! 179: * line to sh -c. ! 180: */ ! 181: ! 182: shell(&linebuf[2]); ! 183: break; ! 184: ! 185: case ':': ! 186: case '_': ! 187: /* ! 188: * Escape to command mode, but be nice! ! 189: */ ! 190: ! 191: execute(&linebuf[2], 1); ! 192: goto cont; ! 193: ! 194: case '.': ! 195: /* ! 196: * Simulate end of file on input. ! 197: */ ! 198: goto out; ! 199: ! 200: case 'q': ! 201: case 'Q': ! 202: /* ! 203: * Force a quit of sending mail. ! 204: * Act like an interrupt happened. ! 205: */ ! 206: ! 207: hadintr++; ! 208: collrub(SIGINT); ! 209: exit(1); ! 210: ! 211: case 'h': ! 212: /* ! 213: * Grab a bunch of headers. ! 214: */ ! 215: if (!intty || !outtty) { ! 216: printf("~h: no can do!?\n"); ! 217: break; ! 218: } ! 219: grabh(hp, GTO|GSUBJECT|GCC|GBCC); ! 220: goto cont; ! 221: ! 222: case 't': ! 223: /* ! 224: * Add to the To list. ! 225: */ ! 226: ! 227: hp->h_to = addto(hp->h_to, &linebuf[2]); ! 228: hp->h_seq++; ! 229: break; ! 230: ! 231: case 's': ! 232: /* ! 233: * Set the Subject list. ! 234: */ ! 235: ! 236: cp = &linebuf[2]; ! 237: while (isspace(*cp)) ! 238: cp++; ! 239: hp->h_subject = savestr(cp); ! 240: hp->h_seq++; ! 241: break; ! 242: ! 243: case 'c': ! 244: /* ! 245: * Add to the CC list. ! 246: */ ! 247: ! 248: hp->h_cc = addto(hp->h_cc, &linebuf[2]); ! 249: hp->h_seq++; ! 250: break; ! 251: ! 252: case 'b': ! 253: /* ! 254: * Add stuff to blind carbon copies list. ! 255: */ ! 256: hp->h_bcc = addto(hp->h_bcc, &linebuf[2]); ! 257: hp->h_seq++; ! 258: break; ! 259: ! 260: case 'd': ! 261: strcpy(linebuf + 2, deadletter); ! 262: /* fall into . . . */ ! 263: ! 264: case 'r': ! 265: /* ! 266: * Invoke a file: ! 267: * Search for the file name, ! 268: * then open it and copy the contents to fp. ! 269: */ ! 270: ! 271: cp = &linebuf[2]; ! 272: while (isspace(*cp)) ! 273: cp++; ! 274: if (*cp == '\0') { ! 275: printf("Interpolate what file?\n"); ! 276: break; ! 277: } ! 278: cp = expand(cp); ! 279: if (cp == NOSTR) ! 280: break; ! 281: if (isdir(cp)) { ! 282: printf("%s: Directory\n", cp); ! 283: break; ! 284: } ! 285: if ((fbuf = fopen(cp, "r")) == NULL) { ! 286: perror(cp); ! 287: break; ! 288: } ! 289: printf("\"%s\" ", cp); ! 290: fflush(stdout); ! 291: lc = 0; ! 292: cc = 0; ! 293: while (readline(fbuf, linebuf) >= 0) { ! 294: lc++; ! 295: if ((t = putline(fp, linebuf)) < 0) { ! 296: fclose(fbuf); ! 297: goto err; ! 298: } ! 299: cc += t; ! 300: } ! 301: fclose(fbuf); ! 302: printf("%d/%d\n", lc, cc); ! 303: break; ! 304: ! 305: case 'w': ! 306: /* ! 307: * Write the message on a file. ! 308: */ ! 309: ! 310: cp = &linebuf[2]; ! 311: while (any(*cp, " \t")) ! 312: cp++; ! 313: if (*cp == '\0') { ! 314: fprintf(stderr, "Write what file!?\n"); ! 315: break; ! 316: } ! 317: if ((cp = expand(cp)) == NOSTR) ! 318: break; ! 319: rewind(fp); ! 320: exwrite(cp, fp, 1); ! 321: break; ! 322: ! 323: case 'm': ! 324: case 'f': ! 325: /* ! 326: * Interpolate the named messages, if we ! 327: * are in receiving mail mode. Does the ! 328: * standard list processing garbage. ! 329: * If ~f is given, we don't shift over. ! 330: */ ! 331: ! 332: if (!rcvmode) { ! 333: printf("No messages to send from!?!\n"); ! 334: break; ! 335: } ! 336: cp = &linebuf[2]; ! 337: while (any(*cp, " \t")) ! 338: cp++; ! 339: if (forward(cp, fp, c) < 0) ! 340: goto err; ! 341: goto cont; ! 342: ! 343: case '?': ! 344: if ((fbuf = fopen(THELPFILE, "r")) == NULL) { ! 345: perror(THELPFILE); ! 346: break; ! 347: } ! 348: while ((t = getc(fbuf)) != EOF) ! 349: putchar(t); ! 350: fclose(fbuf); ! 351: break; ! 352: ! 353: case 'p': ! 354: /* ! 355: * Print out the current state of the ! 356: * message without altering anything. ! 357: */ ! 358: ! 359: rewind(fp); ! 360: printf("-------\nMessage contains:\n"); ! 361: puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); ! 362: while ((t = getc(fp)) != EOF) ! 363: putchar(t); ! 364: goto cont; ! 365: ! 366: case '^': ! 367: case '|': ! 368: /* ! 369: * Pipe message through command. ! 370: * Collect output as new message. ! 371: */ ! 372: ! 373: rewind(fp); ! 374: fp = mespipe(fp, &linebuf[2]); ! 375: goto cont; ! 376: ! 377: case 'v': ! 378: case 'e': ! 379: /* ! 380: * Edit the current message. ! 381: * 'e' means to use EDITOR ! 382: * 'v' means to use VISUAL ! 383: */ ! 384: ! 385: rewind(fp); ! 386: if ((fp = mesedit(fp, c)) == NULL) ! 387: goto err; ! 388: goto cont; ! 389: } ! 390: } ! 391: goto out; ! 392: err: ! 393: if (fp != NULL) { ! 394: fclose(fp); ! 395: fp = NULL; ! 396: } ! 397: out: ! 398: if (fp != NULL) ! 399: rewind(fp); ! 400: signal(SIGINT, saveint); ! 401: signal(SIGHUP, savehup); ! 402: signal(SIGCONT, savecont); ! 403: sigsetmask(omask); ! 404: noreset = 0; ! 405: return(fp); ! 406: } ! 407: ! 408: /* ! 409: * Write a file, ex-like if f set. ! 410: */ ! 411: ! 412: exwrite(name, fp, f) ! 413: char name[]; ! 414: FILE *fp; ! 415: { ! 416: register FILE *of; ! 417: register int c; ! 418: long cc; ! 419: int lc; ! 420: struct stat junk; ! 421: ! 422: if (f) { ! 423: printf("\"%s\" ", name); ! 424: fflush(stdout); ! 425: } ! 426: if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) { ! 427: if (!f) ! 428: fprintf(stderr, "%s: ", name); ! 429: fprintf(stderr, "File exists\n"); ! 430: return(-1); ! 431: } ! 432: if ((of = fopen(name, "w")) == NULL) { ! 433: perror(NOSTR); ! 434: return(-1); ! 435: } ! 436: lc = 0; ! 437: cc = 0; ! 438: while ((c = getc(fp)) != EOF) { ! 439: cc++; ! 440: if (c == '\n') ! 441: lc++; ! 442: putc(c, of); ! 443: if (ferror(of)) { ! 444: perror(name); ! 445: fclose(of); ! 446: return(-1); ! 447: } ! 448: } ! 449: fclose(of); ! 450: printf("%d/%ld\n", lc, cc); ! 451: fflush(stdout); ! 452: return(0); ! 453: } ! 454: ! 455: /* ! 456: * Edit the message being collected on fp. ! 457: * Write the message out onto some poorly-named temp file ! 458: * and point an editor at it. ! 459: * ! 460: * On return, make the edit file the new temp file. ! 461: */ ! 462: ! 463: FILE * ! 464: mesedit(fp, c) ! 465: FILE *fp; ! 466: { ! 467: int pid; ! 468: union wait s; ! 469: FILE *fbuf; ! 470: register int t; ! 471: int (*sigint)(), (*sigcont)(); ! 472: struct stat sbuf; ! 473: extern char tempEdit[]; ! 474: register char *edit; ! 475: ! 476: sigint = signal(SIGINT, SIG_IGN); ! 477: sigcont = signal(SIGCONT, SIG_DFL); ! 478: if (stat(tempEdit, &sbuf) >= 0) { ! 479: printf("%s: file exists\n", tempEdit); ! 480: goto out; ! 481: } ! 482: close(creat(tempEdit, 0600)); ! 483: if ((fbuf = fopen(tempEdit, "w")) == NULL) { ! 484: perror(tempEdit); ! 485: goto out; ! 486: } ! 487: while ((t = getc(fp)) != EOF) ! 488: putc(t, fbuf); ! 489: fflush(fbuf); ! 490: if (ferror(fbuf)) { ! 491: perror(tempEdit); ! 492: remove(tempEdit); ! 493: goto fix; ! 494: } ! 495: fclose(fbuf); ! 496: if ((edit = value(c == 'e' ? "EDITOR" : "VISUAL")) == NOSTR) ! 497: edit = c == 'e' ? EDITOR : VISUAL; ! 498: pid = vfork(); ! 499: if (pid == 0) { ! 500: if (sigint != SIG_IGN) ! 501: signal(SIGINT, SIG_DFL); ! 502: execl(edit, edit, tempEdit, 0); ! 503: perror(edit); ! 504: _exit(1); ! 505: } ! 506: if (pid == -1) { ! 507: perror("fork"); ! 508: remove(tempEdit); ! 509: goto out; ! 510: } ! 511: while (wait(&s) != pid) ! 512: ; ! 513: if (s.w_status != 0) { ! 514: printf("Fatal error in \"%s\"\n", edit); ! 515: remove(tempEdit); ! 516: goto out; ! 517: } ! 518: ! 519: /* ! 520: * Now switch to new file. ! 521: */ ! 522: ! 523: if ((fbuf = fopen(tempEdit, "a+")) == NULL) { ! 524: perror(tempEdit); ! 525: remove(tempEdit); ! 526: goto out; ! 527: } ! 528: remove(tempEdit); ! 529: collf = fbuf; ! 530: fclose(fp); ! 531: fp = fbuf; ! 532: goto out; ! 533: fix: ! 534: perror(tempEdit); ! 535: out: ! 536: signal(SIGCONT, sigcont); ! 537: signal(SIGINT, sigint); ! 538: return(fp); ! 539: } ! 540: ! 541: /* ! 542: * Pipe the message through the command. ! 543: * Old message is on stdin of command; ! 544: * New message collected from stdout. ! 545: * Sh -c must return 0 to accept the new message. ! 546: */ ! 547: ! 548: FILE * ! 549: mespipe(fp, cmd) ! 550: FILE *fp; ! 551: char cmd[]; ! 552: { ! 553: extern char tempEdit[]; ! 554: register FILE *nf; ! 555: int pid; ! 556: union wait s; ! 557: int (*saveint)(); ! 558: char *Shell; ! 559: ! 560: if ((nf = fopen(tempEdit, "w+")) == NULL) { ! 561: perror(tempEdit); ! 562: return(fp); ! 563: } ! 564: remove(tempEdit); ! 565: saveint = signal(SIGINT, SIG_IGN); ! 566: if ((Shell = value("SHELL")) == NULL) ! 567: Shell = "/bin/sh"; ! 568: if ((pid = vfork()) == -1) { ! 569: perror("fork"); ! 570: goto err; ! 571: } ! 572: if (pid == 0) { ! 573: int fd; ! 574: /* ! 575: * stdin = current message. ! 576: * stdout = new message. ! 577: */ ! 578: ! 579: close(0); ! 580: dup(fileno(fp)); ! 581: close(1); ! 582: dup(fileno(nf)); ! 583: for (fd = getdtablesize(); --fd > 2;) ! 584: close(fd); ! 585: execl(Shell, Shell, "-c", cmd, 0); ! 586: perror(Shell); ! 587: _exit(1); ! 588: } ! 589: while (wait(&s) != pid) ! 590: ; ! 591: if (s.w_status != 0 || pid == -1) { ! 592: fprintf(stderr, "\"%s\" failed!?\n", cmd); ! 593: goto err; ! 594: } ! 595: if (fsize(nf) == 0) { ! 596: fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); ! 597: goto err; ! 598: } ! 599: ! 600: /* ! 601: * Take new files. ! 602: */ ! 603: ! 604: fseek(nf, 0L, 2); ! 605: collf = nf; ! 606: fclose(fp); ! 607: signal(SIGINT, saveint); ! 608: return(nf); ! 609: ! 610: err: ! 611: fclose(nf); ! 612: signal(SIGINT, saveint); ! 613: return(fp); ! 614: } ! 615: ! 616: /* ! 617: * Interpolate the named messages into the current ! 618: * message, preceding each line with a tab. ! 619: * Return a count of the number of characters now in ! 620: * the message, or -1 if an error is encountered writing ! 621: * the message temporary. The flag argument is 'm' if we ! 622: * should shift over and 'f' if not. ! 623: */ ! 624: forward(ms, fp, f) ! 625: char ms[]; ! 626: FILE *fp; ! 627: { ! 628: register int *msgvec, *ip; ! 629: extern char tempMail[]; ! 630: ! 631: msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec); ! 632: if (msgvec == (int *) NOSTR) ! 633: return(0); ! 634: if (getmsglist(ms, msgvec, 0) < 0) ! 635: return(0); ! 636: if (*msgvec == NULL) { ! 637: *msgvec = first(0, MMNORM); ! 638: if (*msgvec == NULL) { ! 639: printf("No appropriate messages\n"); ! 640: return(0); ! 641: } ! 642: msgvec[1] = NULL; ! 643: } ! 644: printf("Interpolating:"); ! 645: for (ip = msgvec; *ip != NULL; ip++) { ! 646: touch(*ip); ! 647: printf(" %d", *ip); ! 648: if (f == 'm') { ! 649: if (transmit(&message[*ip-1], fp) < 0L) { ! 650: perror(tempMail); ! 651: return(-1); ! 652: } ! 653: } else ! 654: if (send(&message[*ip-1], fp, 0) < 0) { ! 655: perror(tempMail); ! 656: return(-1); ! 657: } ! 658: } ! 659: printf("\n"); ! 660: return(0); ! 661: } ! 662: ! 663: /* ! 664: * Send message described by the passed pointer to the ! 665: * passed output buffer. Insert a tab in front of each ! 666: * line. Return a count of the characters sent, or -1 ! 667: * on error. ! 668: */ ! 669: ! 670: long ! 671: transmit(mailp, fp) ! 672: struct message *mailp; ! 673: FILE *fp; ! 674: { ! 675: register struct message *mp; ! 676: register int ch; ! 677: long c, n; ! 678: int bol; ! 679: FILE *ibuf; ! 680: ! 681: mp = mailp; ! 682: ibuf = setinput(mp); ! 683: c = mp->m_size; ! 684: n = c; ! 685: bol = 1; ! 686: while (c-- > 0L) { ! 687: ch = getc(ibuf); ! 688: if (ch == '\n') ! 689: bol = 1; ! 690: else if (bol) { ! 691: bol = 0; ! 692: putc('\t', fp); ! 693: n++; ! 694: } ! 695: putc(ch, fp); ! 696: if (ferror(fp)) { ! 697: perror("/tmp"); ! 698: return(-1L); ! 699: } ! 700: } ! 701: return(n); ! 702: } ! 703: ! 704: /* ! 705: * Print (continue) when continued after ^Z. ! 706: */ ! 707: /*ARGSUSED*/ ! 708: collcont(s) ! 709: { ! 710: ! 711: hadintr = 0; ! 712: longjmp(coljmp, 1); ! 713: } ! 714: ! 715: /* ! 716: * On interrupt, go here to save the partial ! 717: * message on ~/dead.letter. ! 718: * Then restore signals and execute the normal ! 719: * signal routine. We only come here if signals ! 720: * were previously set anyway. ! 721: */ ! 722: ! 723: collrub(s) ! 724: { ! 725: register FILE *dbuf; ! 726: register int c; ! 727: ! 728: if (s == SIGINT && hadintr == 0) { ! 729: hadintr = 1; ! 730: longjmp(coljmp, 1); ! 731: } ! 732: rewind(collf); ! 733: if (s == SIGINT && value("nosave") != NOSTR || fsize(collf) == 0) ! 734: goto done; ! 735: if ((dbuf = fopen(deadletter, "w")) == NULL) ! 736: goto done; ! 737: chmod(deadletter, 0600); ! 738: while ((c = getc(collf)) != EOF) ! 739: putc(c, dbuf); ! 740: fclose(dbuf); ! 741: ! 742: done: ! 743: fclose(collf); ! 744: signal(SIGINT, saveint); ! 745: signal(SIGHUP, savehup); ! 746: signal(SIGCONT, savecont); ! 747: if (rcvmode) { ! 748: if (s == SIGHUP) ! 749: hangup(SIGHUP); ! 750: else ! 751: stop(s); ! 752: } else ! 753: exit(1); ! 754: } ! 755: ! 756: /* ! 757: * Acknowledge an interrupt signal from the tty by typing an @ ! 758: */ ! 759: ! 760: /*ARGSUSED*/ ! 761: intack(s) ! 762: { ! 763: ! 764: puts("@"); ! 765: fflush(stdout); ! 766: clearerr(stdin); ! 767: } ! 768: ! 769: /* ! 770: * Add a string to the end of a header entry field. ! 771: */ ! 772: ! 773: char * ! 774: addto(hf, news) ! 775: char hf[], news[]; ! 776: { ! 777: register char *cp, *cp2, *linebuf; ! 778: ! 779: if (hf == NOSTR) ! 780: hf = ""; ! 781: if (*news == '\0') ! 782: return(hf); ! 783: linebuf = salloc(strlen(hf) + strlen(news) + 2); ! 784: for (cp = hf; any(*cp, " \t"); cp++) ! 785: ; ! 786: for (cp2 = linebuf; *cp;) ! 787: *cp2++ = *cp++; ! 788: *cp2++ = ' '; ! 789: for (cp = news; any(*cp, " \t"); cp++) ! 790: ; ! 791: while (*cp != '\0') ! 792: *cp2++ = *cp++; ! 793: *cp2 = '\0'; ! 794: return(linebuf); ! 795: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.