home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / vi / v_ex.c < prev    next >
C/C++ Source or Header  |  1997-06-26  |  15KB  |  698 lines

  1. /*-
  2.  * Copyright (c) 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  * Copyright (c) 1992, 1993, 1994, 1995, 1996
  5.  *    Keith Bostic.  All rights reserved.
  6.  *
  7.  * See the LICENSE file for redistribution information.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #ifndef lint
  13. static const char sccsid[] = "@(#)v_ex.c    10.42 (Berkeley) 6/28/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18. #include <sys/time.h>
  19.  
  20. #include <bitstring.h>
  21. #include <limits.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <unistd.h>
  26. #include <signal.h>        /* for SIGTSTP check */
  27.  
  28. #include "../common/common.h"
  29. #include "vi.h"
  30.  
  31. static int v_ecl __P((SCR *));
  32. static int v_ecl_init __P((SCR *));
  33. static int v_ecl_log __P((SCR *, TEXT *));
  34. static int v_ex_done __P((SCR *, VICMD *));
  35. static int v_exec_ex __P((SCR *, VICMD *, EXCMD *));
  36.  
  37. /*
  38.  * v_again -- &
  39.  *    Repeat the previous substitution.
  40.  *
  41.  * PUBLIC: int v_again __P((SCR *, VICMD *));
  42.  */
  43. int
  44. v_again(sp, vp)
  45.     SCR *sp;
  46.     VICMD *vp;
  47. {
  48.     ARGS *ap[2], a;
  49.     EXCMD cmd;
  50.  
  51.     ex_cinit(&cmd, C_SUBAGAIN, 2, vp->m_start.lno, vp->m_start.lno, 1, ap);
  52.     ex_cadd(&cmd, &a, "", 1);
  53.  
  54.     return (v_exec_ex(sp, vp, &cmd));
  55. }
  56.  
  57. /*
  58.  * v_exmode -- Q
  59.  *    Switch the editor into EX mode.
  60.  *
  61.  * PUBLIC: int v_exmode __P((SCR *, VICMD *));
  62.  */
  63. int
  64. v_exmode(sp, vp)
  65.     SCR *sp;
  66.     VICMD *vp;
  67. {
  68.     GS *gp;
  69.  
  70.     gp = sp->gp;
  71.  
  72.     /* Try and switch screens -- the screen may not permit it. */
  73.     if (gp->scr_screen(sp, SC_EX)) {
  74.         msgq(sp, M_ERR,
  75.             "207|The Q command requires the ex terminal interface");
  76.         return (1);
  77.     }
  78.     (void)gp->scr_attr(sp, SA_ALTERNATE, 0);
  79.  
  80.     /* Save the current cursor position. */
  81.     sp->frp->lno = sp->lno;
  82.     sp->frp->cno = sp->cno;
  83.     F_SET(sp->frp, FR_CURSORSET);
  84.  
  85.     /* Switch to ex mode. */
  86.     F_CLR(sp, SC_VI | SC_SCR_VI);
  87.     F_SET(sp, SC_EX);
  88.  
  89.     /* Move out of the vi screen. */
  90.     (void)ex_puts(sp, "\n");
  91.  
  92.     return (0);
  93. }
  94.  
  95. /*
  96.  * v_join -- [count]J
  97.  *    Join lines together.
  98.  *
  99.  * PUBLIC: int v_join __P((SCR *, VICMD *));
  100.  */
  101. int
  102. v_join(sp, vp)
  103.     SCR *sp;
  104.     VICMD *vp;
  105. {
  106.     EXCMD cmd;
  107.     int lno;
  108.  
  109.     /*
  110.      * YASC.
  111.      * The general rule is that '#J' joins # lines, counting the current
  112.      * line.  However, 'J' and '1J' are the same as '2J', i.e. join the
  113.      * current and next lines.  This doesn't map well into the ex command
  114.      * (which takes two line numbers), so we handle it here.  Note that
  115.      * we never test for EOF -- historically going past the end of file
  116.      * worked just fine.
  117.      */
  118.     lno = vp->m_start.lno + 1;
  119.     if (F_ISSET(vp, VC_C1SET) && vp->count > 2)
  120.         lno = vp->m_start.lno + (vp->count - 1);
  121.  
  122.     ex_cinit(&cmd, C_JOIN, 2, vp->m_start.lno, lno, 0, NULL);
  123.     return (v_exec_ex(sp, vp, &cmd));
  124. }
  125.  
  126. /*
  127.  * v_shiftl -- [count]<motion
  128.  *    Shift lines left.
  129.  *
  130.  * PUBLIC: int v_shiftl __P((SCR *, VICMD *));
  131.  */
  132. int
  133. v_shiftl(sp, vp)
  134.     SCR *sp;
  135.     VICMD *vp;
  136. {
  137.     ARGS *ap[2], a;
  138.     EXCMD cmd;
  139.  
  140.     ex_cinit(&cmd, C_SHIFTL, 2, vp->m_start.lno, vp->m_stop.lno, 0, ap);
  141.     ex_cadd(&cmd, &a, "<", 1);
  142.     return (v_exec_ex(sp, vp, &cmd));
  143. }
  144.  
  145. /*
  146.  * v_shiftr -- [count]>motion
  147.  *    Shift lines right.
  148.  *
  149.  * PUBLIC: int v_shiftr __P((SCR *, VICMD *));
  150.  */
  151. int
  152. v_shiftr(sp, vp)
  153.     SCR *sp;
  154.     VICMD *vp;
  155. {
  156.     ARGS *ap[2], a;
  157.     EXCMD cmd;
  158.  
  159.     ex_cinit(&cmd, C_SHIFTR, 2, vp->m_start.lno, vp->m_stop.lno, 0, ap);
  160.     ex_cadd(&cmd, &a, ">", 1);
  161.     return (v_exec_ex(sp, vp, &cmd));
  162. }
  163.  
  164. /*
  165.  * v_suspend -- ^Z
  166.  *    Suspend vi.
  167.  *
  168.  * PUBLIC: int v_suspend __P((SCR *, VICMD *));
  169.  */
  170. int
  171. v_suspend(sp, vp)
  172.     SCR *sp;
  173.     VICMD *vp;
  174. {
  175.     ARGS *ap[2], a;
  176.     EXCMD cmd;
  177.  
  178.     ex_cinit(&cmd, C_STOP, 0, OOBLNO, OOBLNO, 0, ap);
  179.     ex_cadd(&cmd, &a, "suspend", sizeof("suspend") - 1);
  180.     return (v_exec_ex(sp, vp, &cmd));
  181. }
  182.  
  183. /*
  184.  * v_switch -- ^^
  185.  *    Switch to the previous file.
  186.  *
  187.  * PUBLIC: int v_switch __P((SCR *, VICMD *));
  188.  */
  189. int
  190. v_switch(sp, vp)
  191.     SCR *sp;
  192.     VICMD *vp;
  193. {
  194.     ARGS *ap[2], a;
  195.     EXCMD cmd;
  196.     char *name;
  197.  
  198.     /*
  199.      * Try the alternate file name, then the previous file
  200.      * name.  Use the real name, not the user's current name.
  201.      */
  202.     if ((name = sp->alt_name) == NULL) {
  203.         msgq(sp, M_ERR, "180|No previous file to edit");
  204.         return (1);
  205.     }
  206.  
  207.     /* If autowrite is set, write out the file. */
  208.     if (file_m1(sp, 0, FS_ALL))
  209.         return (1);
  210.  
  211.     ex_cinit(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, ap);
  212.     ex_cadd(&cmd, &a, name, strlen(name));
  213.     return (v_exec_ex(sp, vp, &cmd));
  214. }
  215.  
  216. /*
  217.  * v_tagpush -- ^[
  218.  *    Do a tag search on the cursor keyword.
  219.  *
  220.  * PUBLIC: int v_tagpush __P((SCR *, VICMD *));
  221.  */
  222. int
  223. v_tagpush(sp, vp)
  224.     SCR *sp;
  225.     VICMD *vp;
  226. {
  227.     ARGS *ap[2], a;
  228.     EXCMD cmd;
  229.  
  230.     ex_cinit(&cmd, C_TAG, 0, OOBLNO, 0, 0, ap);
  231.     ex_cadd(&cmd, &a, VIP(sp)->keyw, strlen(VIP(sp)->keyw));
  232.     return (v_exec_ex(sp, vp, &cmd));
  233. }
  234.  
  235. /*
  236.  * v_tagpop -- ^T
  237.  *    Pop the tags stack.
  238.  *
  239.  * PUBLIC: int v_tagpop __P((SCR *, VICMD *));
  240.  */
  241. int
  242. v_tagpop(sp, vp)
  243.     SCR *sp;
  244.     VICMD *vp;
  245. {
  246.     EXCMD cmd;
  247.  
  248.     ex_cinit(&cmd, C_TAGPOP, 0, OOBLNO, 0, 0, NULL);
  249.     return (v_exec_ex(sp, vp, &cmd));
  250. }
  251.  
  252. /*
  253.  * v_filter -- [count]!motion command(s)
  254.  *    Run range through shell commands, replacing text.
  255.  *
  256.  * PUBLIC: int v_filter __P((SCR *, VICMD *));
  257.  */
  258. int
  259. v_filter(sp, vp)
  260.     SCR *sp;
  261.     VICMD *vp;
  262. {
  263.     EXCMD cmd;
  264.     TEXT *tp;
  265.  
  266.     /*
  267.      * !!!
  268.      * Historical vi permitted "!!" in an empty file, and it's handled
  269.      * as a special case in the ex_bang routine.  Don't modify this setup
  270.      * without understanding that one.  In particular, note that we're
  271.      * manipulating the ex argument structures behind ex's back.
  272.      *
  273.      * !!!
  274.      * Historical vi did not permit the '!' command to be associated with
  275.      * a non-line oriented motion command, in general, although it did
  276.      * with search commands.  So, !f; and !w would fail, but !/;<CR>
  277.      * would succeed, even if they all moved to the same location in the
  278.      * current line.  I don't see any reason to disallow '!' using any of
  279.      * the possible motion commands.
  280.      *
  281.      * !!!
  282.      * Historical vi ran the last bang command if N or n was used as the
  283.      * search motion.
  284.      */
  285.     if (F_ISSET(vp, VC_ISDOT) ||
  286.         ISCMD(vp->rkp, 'N') || ISCMD(vp->rkp, 'n')) {
  287.         ex_cinit(&cmd, C_BANG,
  288.             2, vp->m_start.lno, vp->m_stop.lno, 0, NULL);
  289.         EXP(sp)->argsoff = 0;            /* XXX */
  290.  
  291.         if (argv_exp1(sp, &cmd, "!", 1, 1))
  292.             return (1);
  293.         cmd.argc = EXP(sp)->argsoff;        /* XXX */
  294.         cmd.argv = EXP(sp)->args;        /* XXX */
  295.         return (v_exec_ex(sp, vp, &cmd));
  296.     }
  297.  
  298.     /* Get the command from the user. */
  299.     if (v_tcmd(sp, vp,
  300.         '!', TXT_BS | TXT_CR | TXT_ESCAPE | TXT_FILEC | TXT_PROMPT))
  301.         return (1);
  302.  
  303.     /*
  304.      * Check to see if the user changed their mind.
  305.      *
  306.      * !!!
  307.      * Entering <escape> on an empty line was historically an error,
  308.      * this implementation doesn't bother.
  309.      */
  310.     tp = sp->tiq.cqh_first;
  311.     if (tp->term != TERM_OK) {
  312.         vp->m_final.lno = sp->lno;
  313.         vp->m_final.cno = sp->cno;
  314.         return (0);
  315.     }
  316.  
  317.     /* Home the cursor. */
  318.     vs_home(sp);
  319.  
  320.     ex_cinit(&cmd, C_BANG, 2, vp->m_start.lno, vp->m_stop.lno, 0, NULL);
  321.     EXP(sp)->argsoff = 0;            /* XXX */
  322.  
  323.     if (argv_exp1(sp, &cmd, tp->lb + 1, tp->len - 1, 1))
  324.         return (1);
  325.     cmd.argc = EXP(sp)->argsoff;        /* XXX */
  326.     cmd.argv = EXP(sp)->args;        /* XXX */
  327.     return (v_exec_ex(sp, vp, &cmd));
  328. }
  329.  
  330. /*
  331.  * v_event_exec --
  332.  *    Execute some command(s) based on an event.
  333.  *
  334.  * PUBLIC: int v_event_exec __P((SCR *, VICMD *));
  335.  */
  336. int
  337. v_event_exec(sp, vp)
  338.     SCR *sp;
  339.     VICMD *vp;
  340. {
  341.     EXCMD cmd;
  342.  
  343.     switch (vp->ev.e_event) {
  344.     case E_QUIT:
  345.         ex_cinit(&cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0, NULL);
  346.         break;
  347.     case E_WRITE:
  348.         ex_cinit(&cmd, C_WRITE, 0, OOBLNO, OOBLNO, 0, NULL);
  349.         break;
  350.     default:
  351.         abort();
  352.     }
  353.     return (v_exec_ex(sp, vp, &cmd));
  354. }
  355.  
  356. /*
  357.  * v_exec_ex --
  358.  *    Execute an ex command.
  359.  */
  360. static int
  361. v_exec_ex(sp, vp, exp)
  362.     SCR *sp;
  363.     VICMD *vp;
  364.     EXCMD *exp;
  365. {
  366.     int rval;
  367.  
  368.     rval = exp->cmd->fn(sp, exp);
  369.     return (v_ex_done(sp, vp) || rval);
  370. }
  371.  
  372. /*
  373.  * v_ex -- :
  374.  *    Execute a colon command line.
  375.  *
  376.  * PUBLIC: int v_ex __P((SCR *, VICMD *));
  377.  */
  378. int
  379. v_ex(sp, vp)
  380.     SCR *sp;
  381.     VICMD *vp;
  382. {
  383.     GS *gp;
  384.     TEXT *tp;
  385.     int do_cedit, do_resolution, ifcontinue;
  386.  
  387.     gp = sp->gp;
  388.  
  389.     /*
  390.      * !!!
  391.      * If we put out more than a single line of messages, or ex trashes
  392.      * the screen, the user may continue entering ex commands.  We find
  393.      * this out when we do the screen/message resolution.  We can't enter
  394.      * completely into ex mode however, because the user can elect to
  395.      * return into vi mode by entering any key, i.e. we have to be in raw
  396.      * mode.
  397.      */
  398.     for (do_cedit = do_resolution = 0;;) {
  399.         /*
  400.          * !!!
  401.          * There may already be an ex command waiting to run.  If
  402.          * so, we continue with it.
  403.          */
  404.         if (!EXCMD_RUNNING(gp)) {
  405.             /* Get a command. */
  406.             if (v_tcmd(sp, vp, ':',
  407.                 TXT_BS | TXT_CEDIT | TXT_FILEC | TXT_PROMPT))
  408.                 return (1);
  409.             tp = sp->tiq.cqh_first;
  410.  
  411.             /*
  412.              * If the user entered a single <esc>, they want to
  413.              * edit their colon command history.  If they already
  414.              * entered some text, move it into the edit history.
  415.              */
  416.             if (tp->term == TERM_CEDIT) {
  417.                 if (tp->len > 1 && v_ecl_log(sp, tp))
  418.                     return (1);
  419.                 do_cedit = 1;
  420.                 break;
  421.             }
  422.  
  423.             /* If the user didn't enter anything, return. */
  424.             if (tp->term == TERM_BS)
  425.                 break;
  426.  
  427.             /* Log the command. */
  428.             if (O_STR(sp, O_CEDIT) != NULL && v_ecl_log(sp, tp))
  429.                 return (1);
  430.  
  431.             /* Push a command on the command stack. */
  432.             if (ex_run_str(sp, NULL, tp->lb, tp->len, 0, 1))
  433.                 return (1);
  434.         }
  435.  
  436.         /* Home the cursor. */
  437.         vs_home(sp);
  438.  
  439.         /*
  440.          * !!!
  441.          * If the editor wrote the screen behind curses back, put out
  442.          * a <newline> so that we don't overwrite the user's command
  443.          * with its output or the next want-to-continue? message.  This
  444.          * doesn't belong here, but I can't find another place to put
  445.          * it.  See, we resolved the output from the last ex command,
  446.          * and the user entered another one.  This is the only place
  447.          * where we have control before the ex command writes output.
  448.          * We could get control in vs_msg(), but we have no way to know
  449.          * if command didn't put out any output when we try and resolve
  450.          * this command.  This fixes a bug where combinations of ex
  451.          * commands, e.g. ":set<CR>:!date<CR>:set" didn't look right.
  452.          */
  453.         if (F_ISSET(sp, SC_SCR_EXWROTE))
  454.             (void)putchar('\n');
  455.  
  456.         /* Call the ex parser. */
  457.         (void)ex_cmd(sp);
  458.  
  459.         /* Flush ex messages. */
  460.         (void)ex_fflush(sp);
  461.  
  462.         /* Resolve any messages. */
  463.         if (vs_ex_resolve(sp, &ifcontinue))
  464.             return (1);
  465.  
  466.         /*
  467.          * Continue or return.  If continuing, make sure that we
  468.          * eventually do resolution.
  469.          */
  470.         if (!ifcontinue)
  471.             break;
  472.         do_resolution = 1;
  473.  
  474.         /* If we're continuing, it's a new command. */
  475.         ++sp->ccnt;
  476.     }
  477.  
  478.     /*
  479.      * If the user previously continued an ex command, we have to do
  480.      * resolution to clean up the screen.  Don't wait, we already did
  481.      * that.
  482.      */
  483.     if (do_resolution) {
  484.         F_SET(sp, SC_EX_WAIT_NO);
  485.         if (vs_ex_resolve(sp, &ifcontinue))
  486.             return (1);
  487.     }
  488.  
  489.     /* Cleanup from the ex command. */
  490.     if (v_ex_done(sp, vp))
  491.         return (1);
  492.  
  493.     /* The user may want to edit their colon command history. */
  494.     if (do_cedit)
  495.         return (v_ecl(sp));
  496.  
  497.     return (0);
  498. }
  499.  
  500. /*
  501.  * v_ex_done --
  502.  *    Cleanup from an ex command.
  503.  */
  504. static int
  505. v_ex_done(sp, vp)
  506.     SCR *sp;
  507.     VICMD *vp;
  508. {
  509.     size_t len;
  510.  
  511.     /*
  512.      * The only cursor modifications are real, however, the underlying
  513.      * line may have changed; don't trust anything.  This code has been
  514.      * a remarkably fertile place for bugs.  Do a reality check on a
  515.      * cursor value, and make sure it's okay.  If necessary, change it.
  516.      * Ex keeps track of the line number, but it cares less about the
  517.      * column and it may have disappeared.
  518.      *
  519.      * Don't trust ANYTHING.
  520.      *
  521.      * XXX
  522.      * Ex will soon have to start handling the column correctly; see
  523.      * the POSIX 1003.2 standard.
  524.      */
  525.     if (db_eget(sp, sp->lno, NULL, &len, NULL)) {
  526.         sp->lno = 1;
  527.         sp->cno = 0;
  528.     } else if (sp->cno >= len)
  529.         sp->cno = len ? len - 1 : 0;
  530.  
  531.     vp->m_final.lno = sp->lno;
  532.     vp->m_final.cno = sp->cno;
  533.  
  534.     /*
  535.      * Don't re-adjust the cursor after executing an ex command,
  536.      * and ex movements are permanent.
  537.      */
  538.     F_CLR(vp, VM_RCM_MASK);
  539.     F_SET(vp, VM_RCM_SET);
  540.  
  541.     return (0);
  542. }
  543.  
  544. /*
  545.  * v_ecl --
  546.  *    Start an edit window on the colon command-line commands.
  547.  */
  548. static int
  549. v_ecl(sp)
  550.     SCR *sp;
  551. {
  552.     GS *gp;
  553.     SCR *new;
  554.  
  555.     /* Initialize the screen, if necessary. */
  556.     gp = sp->gp;
  557.     if (gp->ccl_sp == NULL && v_ecl_init(sp))
  558.         return (1);
  559.  
  560.     /* Get a new screen. */
  561.     if (screen_init(gp, sp, &new))
  562.         return (1);
  563.     if (vs_split(sp, new, 1)) {
  564.         (void)screen_end(new);
  565.         return (1);
  566.     }
  567.  
  568.     /* Attach to the screen. */
  569.     new->ep = gp->ccl_sp->ep;
  570.     ++new->ep->refcnt;
  571.  
  572.     new->frp = gp->ccl_sp->frp;
  573.     new->frp->flags = sp->frp->flags;
  574.  
  575.     /* Move the cursor to the end. */
  576.     (void)db_last(new, &new->lno);
  577.     if (new->lno == 0)
  578.         new->lno = 1;
  579.  
  580.     /* Remember the originating window. */
  581.     sp->ccl_parent = sp;
  582.  
  583.     /* It's a special window. */
  584.     F_SET(new, SC_COMEDIT);
  585.  
  586.     /* Set up the switch. */
  587.     sp->nextdisp = new;
  588.     F_SET(sp, SC_SSWITCH);
  589.     return (0);
  590. }
  591.  
  592. /*
  593.  * v_ecl_exec --
  594.  *    Execute a command from a colon command-line window.
  595.  *
  596.  * PUBLIC: int v_ecl_exec __P((SCR *));
  597.  */
  598. int
  599. v_ecl_exec(sp)
  600.     SCR *sp;
  601. {
  602.     size_t len;
  603.     char *p;
  604.  
  605.     if (db_get(sp, sp->lno, 0, &p, &len) && sp->lno == 1) {
  606.         v_emsg(sp, NULL, VIM_EMPTY);
  607.         return (1);
  608.     }
  609.     if (len == 0) {
  610.         msgq(sp, M_BERR, "307|No ex command to execute");
  611.         return (1);
  612.     }
  613.     
  614.     /* Push the command on the command stack. */
  615.     if (ex_run_str(sp, NULL, p, len, 0, 0))
  616.         return (1);
  617.  
  618.     /* Set up the switch. */
  619.     sp->nextdisp = sp->ccl_parent;
  620.     F_SET(sp, SC_EXIT);
  621.     return (0);
  622. }
  623.  
  624. /*
  625.  * v_ecl_log --
  626.  *    Log a command into the colon command-line log file.
  627.  */
  628. static int
  629. v_ecl_log(sp, tp)
  630.     SCR *sp;
  631.     TEXT *tp;
  632. {
  633.     EXF *save_ep;
  634.     recno_t lno;
  635.     int rval;
  636.  
  637.     /* Initialize the screen, if necessary. */
  638.     if (sp->gp->ccl_sp == NULL && v_ecl_init(sp))
  639.         return (1);
  640.  
  641.     /*
  642.      * Don't log colon command window commands into the colon command
  643.      * window...
  644.      */
  645.     if (sp->ep == sp->gp->ccl_sp->ep)
  646.         return (0);
  647.  
  648.     /*
  649.      * XXX
  650.      * Swap the current EXF with the colon command file EXF.  This
  651.      * isn't pretty, but too many routines "know" that sp->ep points
  652.      * to the current EXF.
  653.      */
  654.     save_ep = sp->ep;
  655.     sp->ep = sp->gp->ccl_sp->ep;
  656.     if (db_last(sp, &lno)) {
  657.         sp->ep = save_ep;
  658.         return (1);
  659.     }
  660.     rval = db_append(sp, 0, lno, tp->lb, tp->len);
  661.     sp->ep = save_ep;
  662.     return (rval);
  663. }
  664.  
  665. /*
  666.  * v_ecl_init --
  667.  *    Initialize the colon command-line log file.
  668.  */
  669. static int
  670. v_ecl_init(sp)
  671.     SCR *sp;
  672. {
  673.     FREF *frp;
  674.     GS *gp;
  675.  
  676.     gp = sp->gp;
  677.  
  678.     /* Get a temporary file. */
  679.     if ((frp = file_add(sp, NULL)) == NULL)
  680.         return (1);
  681.  
  682.     /*
  683.      * XXX
  684.      * Create a screen -- the file initialization code wants one.
  685.      */
  686.     if (screen_init(gp, sp, &gp->ccl_sp))
  687.         return (1);
  688.     if (file_init(gp->ccl_sp, frp, NULL, 0)) {
  689.         (void)screen_end(gp->ccl_sp);
  690.         return (1);
  691.     }
  692.  
  693.     /* The underlying file isn't recoverable. */
  694.     F_CLR(gp->ccl_sp->ep, F_RCV_ON);
  695.  
  696.     return (0);
  697. }
  698.