home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume11 / mush5.7 / part06 / msgs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-09-17  |  15.9 KB  |  597 lines

  1. /* @(#)msgs.c    (c) copyright 10/18/86 (Dan Heller) */
  2.  
  3. #include "mush.h"
  4. #ifdef SYSV
  5. #include <sys/locking.h>
  6. #endif SYSV
  7.  
  8. void
  9. display_msg(n, flg)
  10. register int n;
  11. long flg;
  12. {
  13.     register FILE *pp;
  14.  
  15.     if (ison(msg[n].m_flags, DELETE)) {
  16.     print("Message %d deleted; ", n+1);
  17.     if (istool)
  18.         print_more("Select UNDELETE to read.");
  19.     else if (iscurses)
  20.         print_more("Type 'u' to undelete.");
  21.     else
  22.         print("Type 'undelete %d' to undelete\n", n+1);
  23.     return;
  24.     }
  25.     set_isread(n);
  26.     if (ison(flg, TOP)) {
  27.     turnon(flg, NO_HEADER);
  28.     print("Top of "), turnon(glob_flags, CONT_PRNT);
  29.     }
  30.  
  31.     if (!istool && isoff(flg, NO_PAGE) &&
  32.         crt < msg[n].m_lines && isoff(flg, TOP)) {
  33.     turnon(glob_flags, IGN_SIGS);
  34.     echo_on();
  35.     if (!(pp = popen(pager, "w")))
  36.         error(pager);
  37.     else {
  38.         fprintf(pp, "Message #%d (%d lines)\n", n+1, msg[n].m_lines);
  39.         (void) copy_msg(n, pp, flg);
  40.         (void) pclose(pp);
  41.     }
  42.     echo_off();
  43.     turnoff(glob_flags, IGN_SIGS);
  44.     } else {
  45.     print("Message #%d (%d lines)\n", n+1, msg[n].m_lines);
  46.     (void) copy_msg(n, stdout, flg);
  47.     }
  48. }
  49.  
  50. /*
  51.  * copy message 'n' to file "fp" according to various flag arguments
  52.  * return number of lines copied or -1 if system error on fputs.
  53.  */
  54. copy_msg(n, fp, flags)
  55. register int n;
  56. long flags;
  57. register FILE *fp;
  58. {
  59.     register int  ignoring = 0, lines = 0;
  60.     register char *indent_str;
  61.     int  on_hdr = 1, top, squeeze = FALSE;
  62.     char       line[BUFSIZ];
  63.  
  64.     still_more = 0;
  65.     if (ison(flags, TOP)) {
  66.     register char *p = do_set(set_options, "toplines");
  67.     top = (p)? atoi(p) : crt;
  68.     }
  69.     if (do_set(set_options, "alwaysignore"))
  70.     turnoff(flags, NO_IGNORE);
  71.     if (isoff(flags, NO_IGNORE) && do_set(set_options, "squeeze"))
  72.     squeeze = TRUE;
  73.  
  74. #ifdef SUNTOOL
  75.     if (istool && fp == stdout) {
  76.     register int x = (msg[n].m_lines + 2) * l_height(curfont);
  77.     if (x > 32765) { /* to overcome a bug in pixrects that sun won't fix */
  78.         print("message too big to display using this font");
  79.         return 0;
  80.     }
  81.     if (x < msg_rect.r_height) /* make it at least as big as the window */
  82.         x = msg_rect.r_height;
  83.     do_clear();
  84.     lock_cursors();
  85.     if (!(msg_pix = mem_create(msg_rect.r_width, x, 1))) {
  86.         error("mem_create");
  87.         return 0;
  88.     }
  89.     pr_rop(msg_pix, 0,0, msg_rect.r_width-1, x-1, PIX_CLR, 0,0,0);
  90.     on_hdr = 1;
  91.     }
  92. #endif SUNTOOL
  93.     if (ison(flags, INDENT) &&
  94.        (!(indent_str = do_set(set_options, "indent_str")) ||
  95.     !strcmp(indent_str, "indent_str")))
  96.     indent_str = DEF_INDENT_STR;
  97.     (void) fseek(tmpf, msg[n].m_offset, L_SET);
  98.     while (still_more < msg[n].m_size && fgets(line, BUFSIZ, tmpf)) {
  99.     still_more += strlen(line);
  100.  
  101.     /*
  102.      * If squeeze is one, all blanks lines squeeze down to one blank line.
  103.      * If squeeze is two, squeezing is in progress. Otherwise, wait for \n.
  104.      */
  105.     if (*line == '\n') {
  106.         if (on_hdr)    /* blank line -- end of header */
  107.         turnoff(flags, NO_HEADER), on_hdr = 0;
  108.         if (squeeze > 1)
  109.         continue;
  110.         else if (squeeze)
  111.         squeeze = 2;
  112.     } else if (squeeze > 1)
  113.         squeeze = 1;
  114.  
  115.     if (ison(flags, UPDATE_STATUS))
  116.         if (!strncmp(line, "Status:", 7))
  117.         continue; /* ignore this and other "Status" lines */
  118.         else if (!on_hdr) {
  119.         /* preserve NEW/UNREAD status on preserved messages */
  120.         if (isoff(msg[n].m_flags, PRESERVE)) {
  121.             (void) strcpy(line, "Status: O");
  122.             if (isoff(msg[n].m_flags, UNREAD))
  123.             (void) strcat(line, "R");
  124.             (void) strcat(line, "\n");
  125.             fputs(line, fp);
  126.             (void) strcpy(line, "\n");
  127.         }
  128.         turnoff(flags, UPDATE_STATUS);
  129.         }
  130.     if (on_hdr && isoff(flags, NO_IGNORE)) {
  131.         register char *p = any(line, " \t:");
  132.         if (!p)
  133.         ignoring = 0, on_hdr = 0;
  134.         else if (ignoring)
  135.         if (*p != ':') {
  136.             Debug("Ignoring: %s", line);
  137.             continue;
  138.         }
  139.         else
  140.             ignoring = 0;
  141.         if (p && *p == ':') {
  142.         register struct options *opts;
  143.         *p = 0;
  144.         ignoring = 0;
  145.         for (opts = ignore_hdr; opts; opts = opts->next)
  146.             if (!lcase_strcmp(opts->option, line)) {
  147.             ignoring = 1;
  148.             break;
  149.             }
  150.         *p = ':';
  151.         if (ignoring) {
  152.             Debug("Ignoring: %s", line);
  153.             continue;
  154.         }
  155.         }
  156.     }
  157.     if (!on_hdr && ison(flags, TOP) && !--top)
  158.         break;
  159.     if (isoff(flags, NO_HEADER)) {
  160.         /* note that function returns the number of lines */
  161.         lines++;
  162. #ifdef SUNTOOL
  163.         if (istool && fp == stdout) {
  164.         Addstr(line);
  165.         continue;
  166.         }
  167. #endif SUNTOOL
  168.         if (ison(flags, INDENT))
  169.         fputs(indent_str, fp);
  170.         (void) fputs(line, fp);
  171.         if (errno == ENOSPC)
  172.         return -1;
  173.     }
  174.     }
  175. #ifdef SUNTOOL
  176.     if (istool && fp == stdout) {
  177.     unlock_cursors();
  178.     txt.y = still_more = msg_rect.r_height;
  179.     scroll_win(0);  /* causes a display */
  180.     }
  181. #endif SUNTOOL
  182.     return lines;
  183. }
  184.  
  185. /* get mail from whatever the mailfile points to. open a tempfile for
  186.  * appending, then close it and reopen it for read-only.  some systems
  187.  * have flakey read/write access.
  188.  */
  189. void
  190. getmail()
  191. {
  192.     register FILE    *mail_fp;
  193.     int     lines = 0, get_status = 1;
  194.     long     ftell(), bytes;
  195.     char    line[BUFSIZ];
  196.  
  197.     if (!(mail_fp = fopen(mailfile, "r"))) {
  198.     error("Cannot open %s", mailfile);
  199.     return;
  200.     }
  201.     /*
  202.      * since this file is usually open for read-only, close it and then
  203.      * reopen it for appending.  This is done to compensate for errors
  204.      * in XENIX and to play it safe with non-essentially writable files.
  205.      * see more notes below (end of proc).
  206.      */
  207.     (void) fclose(tmpf);
  208.     {
  209.     int    omask = umask(077);
  210.     tmpf = fopen(tempfile, "a");
  211.     (void) umask(omask);
  212.     if (!tmpf) {
  213.         error("can't open %s for appending", tempfile);
  214.         (void) fclose(mail_fp);
  215.         return;
  216.     }
  217.     }
  218. #ifdef SYSV
  219.     (void) locking(fileno(mail_fp), LK_LOCK,  0);
  220. #else
  221. #ifdef BSD
  222.     if (flock(fileno(mail_fp), LOCK_SH))  /* if file is locked, flock waits */
  223.     error("WARNING: could not lock %s", mailfile);
  224. #endif BSD
  225. #endif SYSV
  226.  
  227.     (void) fseek(mail_fp, ftell(tmpf), 0);
  228.  
  229.     while (fgets(line, BUFSIZ, mail_fp) != NULL) {
  230.     if (!strncmp(line, "From ", 5)) {
  231.         if (msg_cnt == MAXMSGS-1) {
  232.         print("WARNING: exceeded %d messages.\n", MAXMSGS);
  233.         print("You should split \"%s\" into smaller files.\n",mailfile);
  234.         /* make sure that tempfile isn't removed!! */
  235.         turnon(glob_flags, IGN_SIGS);
  236.         cleanup(0); /* probably a more elegant way to exit, but... */
  237.         }
  238.         bytes = ftell(tmpf);
  239.         /* finish up message structure from previous message.
  240.          * if this is incorporating new mail, check "lines" to
  241.          * see if previous message has already been set!
  242.          */
  243.         if (msg_cnt && lines) {
  244.         msg[msg_cnt-1].m_size = bytes - msg[msg_cnt-1].m_offset;
  245.         msg[msg_cnt-1].m_lines = lines;
  246.         }
  247.         msg[msg_cnt].m_offset = bytes;
  248.         msg[msg_cnt].m_flags = lines = 0;
  249.         turnon(msg[msg_cnt].m_flags, UNREAD); /* initialize */
  250.  
  251.         fputs(line, tmpf);
  252.         if (errno == ENOSPC)
  253.         fs_error();
  254.  
  255.         /* we've read the "From " line, now read the rest of
  256.          * the message headers till we get to a blank line.
  257.          */
  258.         while (fgets(line, BUFSIZ, mail_fp) && (*line != '\n')) {
  259.         register char *p = line;
  260.         if (get_status && !(get_status = strncmp(p, "Status:", 7))) {
  261.             turnon(msg[msg_cnt].m_flags, OLD);
  262.             for (p += 8 ; *p != '\n'; p++)
  263.             switch(*p) {
  264.                 case 'R': turnoff(msg[msg_cnt].m_flags, UNREAD);
  265.             }
  266.         }
  267.         fputs(line, tmpf), lines++;
  268.         if (errno == ENOSPC)
  269.             fs_error();
  270.         }
  271.         msg_cnt++, get_status = 1;
  272.     }
  273.     fputs(line, tmpf), lines++;
  274.     if (errno == ENOSPC)
  275.         fs_error();
  276.     }
  277.     /* msg_cnt may be 0 if there is an error with the format of mailfile */
  278.     if (msg_cnt) {
  279.     msg[msg_cnt-1].m_size = ftell(tmpf) - msg[msg_cnt-1].m_offset;
  280.     msg[msg_cnt-1].m_lines = lines;
  281.     }
  282. #ifdef SYSV
  283.     locking(fileno(mail_fp), LK_UNLCK, 0);
  284. #endif /* SYSV */
  285.     fclose(mail_fp);            /* implicit unlock */
  286.     /* I've had problems with sys-v opening a file for read/write. I'd
  287.      * try fgets after a seek to an arbitrary place and get NULL. "w+"
  288.      * could be broken (XENIX), so play it safe anyway.
  289.      */
  290.     fclose(tmpf);
  291.     if (!(tmpf = fopen(tempfile, "r")))
  292.     error("can't open %s for reading", tempfile);
  293. }
  294.  
  295. fs_error()
  296. {
  297.     error("WARNING: can't write to \"%s\"", tempfile);
  298.     print("Read the manual on what to do on full file systems.\n");
  299.     cleanup(0);
  300. }
  301.  
  302. /*
  303.  * copy temp or whatever back to mailfile
  304.  * Return 0 if new mail came and user doesn't want to exit.
  305.  */
  306. copyback()
  307. {
  308.     register int    new = 0, i, j=0, k=0;
  309.     register long     flg = 0;
  310.     register FILE     *mbox = NULL_FILE, *mail_fp;
  311.     char         *mbox_file, action = 0;
  312.     int         hold = 0, delete_it = 0, dont_unlink = FALSE;
  313.  
  314. #ifdef SUNTOOL
  315.     if (istool) {
  316.     timerclear(&(mail_timer.it_interval));
  317.     timerclear(&(mail_timer.it_value));
  318.     }
  319. #endif SUNTOOL
  320.     if (ison(glob_flags, READ_ONLY)) {
  321.     print("Can't update %s: read only\n", mailfile);
  322.     return 1;
  323.     }
  324.     if (check_new_mail()) {
  325.     new = 1;
  326.     if (!istool) {
  327.         char buf[256];
  328.         if (iscurses)
  329.         putchar('\n');
  330.         print("Really quit? "), fflush(stdout);
  331.         buf[0] = 0;
  332.         if (!Getstr(buf, 256, 0) || lower(*buf) != 'y')
  333.         return 0;
  334.     }
  335.     } else if (!msg_cnt) /* prevent unnecessary overwrite */
  336.     return 0;
  337.     /* open mbox if: "autodelete" AND "hold" are NOT set. */
  338.     if (is_spool(mailfile)
  339.         && !(delete_it = !!do_set(set_options, "autodelete"))
  340.         && !(hold = !!do_set(set_options, "hold"))) {
  341.     register char *p;
  342.     int x = 1; /* tell getpath to ignore "ENOENT" if file not found */
  343.  
  344.     if (!(p = do_set(set_options, "mbox")))
  345.         p = DEF_MBOX;
  346.     mbox_file = getpath(p, &x);
  347.     if (x) {
  348.         if (x > 0)
  349.         print("%s is a directory.\n", mbox_file);
  350.         else
  351.         print("can't open %s: %s\n", p, mbox_file);
  352.         mbox = NULL_FILE;
  353.     } else {
  354.         char *mode = "a";
  355.         if (access(mbox_file, 0)) /* does it exist? */
  356.         mode = "w"; /* no, create it. */
  357.         else if (access(mbox_file, 2))   /* if yes, can we write in it? */
  358.         error("can't open %s", mbox_file); /* if no, print why not */
  359.         if (!(mbox = fopen(mbox_file, mode)))
  360.         error("can't open %s", mbox_file);
  361.     }
  362.     }
  363.     /* reopen the mailfile; make sure it's not readable */
  364.     {
  365.     int omask = umask(077);
  366.     mail_fp = fopen(mailfile, "w");
  367.     (void) umask(omask);
  368.     if (!mail_fp) {
  369.         error("can't rewrite %s", mailfile);
  370.         return 0;
  371.     }
  372.     }
  373.     turnon(glob_flags, IGN_SIGS);
  374.     print("Updating \"%s\"", mailfile), fflush(stdout);
  375. #ifdef SYSV
  376.     (void) locking(fileno(mail_fp), LK_LOCK,  0);
  377. #else
  378. #ifdef BSD
  379.     if (flock(fileno(mail_fp), LOCK_EX))
  380.     error("WARNING: could not lock %s", mailfile);
  381. #endif BSD
  382. #endif SYSV
  383.     turnon(flg, UPDATE_STATUS);
  384.     turnon(flg, NO_IGNORE);
  385.  
  386.     for (i = 0; i < msg_cnt; i++)
  387.     /* check to see if message is marked for deletion or, if read and not
  388.      * preserved, delete it if autodelete is set. Otherwise, save the
  389.      * message in the spool file if hold is set. If all fails, save in mbox.
  390.      */
  391.     if (ison(msg[i].m_flags, DELETE)
  392.         || isoff(msg[i].m_flags, UNREAD) && isoff(msg[i].m_flags, PRESERVE) 
  393.         && delete_it) {
  394.         Debug("%s %d",
  395.         (action!='d')? "\ndeleting message:" : "", i+1), action = 'd';
  396.         continue;
  397.     } else if (ison(msg[i].m_flags, UNREAD) ||
  398.          ison(msg[i].m_flags, PRESERVE) || hold || !mbox) {
  399.         j++;
  400.         Debug("%s %d",
  401.         (action!='s')? "\nsaving in spool:" : "", i+1), action = 's';
  402.         if (copy_msg(i, mail_fp, flg) == -1) {
  403.         error("WARNING: could not write back to spool");
  404.         print("ALL mail left in %s\n", tempfile);
  405.         print("Spool mailbox may be corrupted.\n");
  406.         if (new)
  407.             print("New mail may be lost. :-(\n");
  408.         dont_unlink = TRUE;
  409.         break;
  410.         }
  411.     } else if (is_spool(mailfile)) {   /* copy back to mbox if spooldir */
  412.         k++;
  413.         if (copy_msg(i, mbox, flg) == -1) {
  414.         error("WARNING: could not write to mbox");
  415.         print("Unresolved mail left in %s\n", tempfile);
  416.         dont_unlink = TRUE;
  417.         break;
  418.         }
  419.         Debug("%s %d",
  420.         (action!='m')? "\nsaving in mbox:" : "", i+1), action = 'm';
  421.     }
  422.     Debug("\n%s", mailfile);
  423. #ifdef SYSV
  424.     locking(fileno(mail_fp), LK_UNLCK, 0);
  425. #endif SYSV
  426.     fclose(mail_fp);        /* implicit unlock for BSD */
  427.     if (mbox)
  428.     fclose(mbox);
  429.     if (j) {
  430.     long times[2];
  431.     times[1] = time(×[0]) - (long)2;
  432.     if (is_spool(mailfile) && utime(mailfile, times))
  433.         error("utime");
  434.     print_more(": saved %d message%s\n", j, (j==1)? NO_STRING: "s");
  435.     } else if (!is_spool(mailfile) && !dont_unlink && !new)
  436.     if (unlink(mailfile))
  437.         turnon(glob_flags, CONT_PRNT), error(": cannot remove");
  438.     else
  439.         print_more(": removed\n");
  440.     else
  441.     print_more(": empty\n");
  442.     if (k)
  443.     print("saved %d message%s in %s\n",k,(k==1)? NO_STRING: "s",mbox_file);
  444.     if (new && !istool)
  445.     print("New mail has arrived.\n");
  446.     turnoff(glob_flags, IGN_SIGS);
  447. #ifdef SUNTOOL
  448.     if (istool) {
  449.     mail_timer.it_value.tv_sec = time_out;
  450.     setitimer(ITIMER_REAL, &mail_timer, NULL);
  451.     }
  452. #endif SUNTOOL
  453.     return 1;
  454. }
  455.  
  456. mail_size()
  457. {
  458.     struct stat buf;
  459.     if (!is_spool(mailfile)) {
  460.     char tmp[128];
  461.     if (!stat(sprintf(tmp, "%s/%s", MAILDIR, login), &buf))
  462.         spool_size = buf.st_size;
  463.     }
  464.     if (!*mailfile)
  465.     return 0;
  466.     if (stat(mailfile, &buf)) {
  467.     if (errno != ENOENT)
  468.         error("Can't stat %s", mailfile);
  469.     return 0;
  470.     }
  471.     if (is_spool(mailfile))
  472.     spool_size = buf.st_size;
  473.     if (buf.st_size > last_size) {
  474.     last_size = buf.st_size;
  475.     return 1;
  476.     }
  477.     return 0;
  478. }
  479.  
  480. void
  481. mail_status(as_prompt)
  482. {
  483.     static char buf[256];
  484.     register int cnt = 0, new = 0, unread = 0, deleted = 0;
  485.  
  486.     for ( ; cnt < msg_cnt; cnt++) {
  487.     if (ison(msg[cnt].m_flags, UNREAD))
  488.         unread++;
  489.     if (ison(msg[cnt].m_flags, DELETE))
  490.         deleted++;
  491.     if (isoff(msg[cnt].m_flags, OLD))
  492.         new++;
  493.     }
  494.     if (as_prompt) {
  495.     register char *p, *b = buf;
  496.     for (p = prompt; *p; p++)
  497.         if (*p == '\\')
  498.         switch (*++p) {
  499.             case 'n': case 'r': *b++ = '\n';
  500.             when 't': *b++ = '\t';
  501.             otherwise: *b++ = *p;
  502.         }
  503.         else if (*p == '%')
  504.         switch (*++p) {
  505.             case 'm':
  506.             b += strlen(sprintf(b,"%d",(msg_cnt)? current_msg+1:0));
  507.             when 't':
  508.             b += strlen(sprintf(b, "%d", msg_cnt));
  509.             when 'd':
  510.             b += strlen(sprintf(b, "%d", deleted));
  511.             when 'u':
  512.             b += strlen(sprintf(b, "%d", unread));
  513.             when 'n':
  514.             b += strlen(sprintf(b, "%d", new));
  515.             when 'f':
  516.             b += Strcpy(b, mailfile);
  517.             if (ison(glob_flags, READ_ONLY))
  518.                 b += Strcpy(b, " [read only]");
  519.             when 'T': case 'D': case 'Y': case 'M': case 'N':
  520.             b += Strcpy(b, Time(p, (long)0));
  521.             otherwise: *b++ = *p;
  522.         }
  523.         else if (*p == '!')
  524.         b += strlen(sprintf(b, "%d", hist_no+1));
  525.         else
  526.         *b++ = *p;
  527.     *b = 0;
  528.     print("%s", buf); /* buf MIGHT have a % in it... don't pass as fmt */
  529.     return;
  530.     }
  531.     (void) sprintf(buf,"\"%s\"%s: %d message%s, %d new, %d unread",
  532.     mailfile, ison(glob_flags, READ_ONLY)? " [read only]" : "",
  533.     msg_cnt, (msg_cnt != 1)? "s": NO_STRING, new, unread);
  534.     if (istool || iscurses)
  535.     (void) sprintf(buf+strlen(buf), ", %d deleted", deleted);
  536. #ifdef SUNTOOL
  537.     if (istool) {
  538.     static char ic_text[4];
  539.     extern struct pixrect mail_icon_image1, mail_icon_image2;
  540.     (void) sprintf(ic_text, "%3d", msg_cnt);
  541.     tool_set_attributes(tool,
  542.         WIN_LABEL, buf,
  543.         WIN_ICON_LABEL, ic_text,
  544.         WIN_ICON_IMAGE, ison(glob_flags, NEW_MAIL)?
  545.         &mail_icon_image2 : &mail_icon_image1,
  546.         0);
  547.     } else
  548. #endif SUNTOOL
  549. #ifdef CURSES
  550.     if (iscurses)
  551.         mvprintw(0, 0, "%-3d %-*s",
  552.         ((msg_cnt)? current_msg+1 : 0), COLS-5, buf), clrtoeol();
  553.     else
  554. #endif CURSES
  555.         puts(buf);
  556.     return;
  557. }
  558.  
  559. /* return -1 since function doesn't affect messages */
  560. check_flags(flags)
  561. u_long flags;
  562. {
  563.     print_more(" ");
  564.     if (ison(flags, VERBOSE))
  565.     print_more("VERBOSE ");
  566.     if (ison(flags, INCLUDE))
  567.     print_more("INCLUDE ");
  568.     if (ison(flags, INCLUDE_H))
  569.     print_more("INCLUDE_H ");
  570.     if (ison(flags, EDIT))
  571.     print_more("EDIT ");
  572.     if (ison(flags, SIGN))
  573.     print_more("SIGN ");
  574.     if (ison(flags, DO_FORTUNE))
  575.     print_more("DO_FORTUNE ");
  576.     if (ison(flags, NO_HEADER))
  577.     print_more("NO_HEADER ");
  578.     if (ison(flags, DELETE))
  579.     print_more("DELETE ");
  580.     if (ison(flags, OLD))
  581.     print_more("OLD ");
  582.     if (ison(flags, UNREAD))
  583.     print_more("UNREAD ");
  584.     if (ison(flags, UPDATE_STATUS))
  585.     print_more("UPDATE_STATUS ");
  586.     if (ison(flags, NO_PAGE))
  587.     print_more("NO_PAGE ");
  588.     if (ison(flags, INDENT))
  589.     print_more("INDENT ");
  590.     if (ison(flags, NO_IGNORE))
  591.     print_more("NO_IGNORE ");
  592.     if (ison(flags, PRESERVE))
  593.     print_more("PRESERVE ");
  594.     print_more("\n");
  595.     return -1;
  596. }
  597.