home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / Editors / mjovesrc.zoo / disp.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  30KB  |  1,493 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. #include "jove.h"
  9. #include "ctype.h"
  10. #include "termcap.h"
  11. #include "chars.h"
  12. #include "fp.h"
  13. #include "disp.h"
  14. #ifdef    IPROCS
  15. # include "iproc.h"
  16. #endif
  17.  
  18. #ifdef    MAC
  19. # include "mac.h"
  20. #else
  21. # ifdef    STDARGS
  22. #  include <stdarg.h>
  23. # else
  24. #  include <varargs.h>
  25. # endif
  26. # include <sys/stat.h>
  27. #endif
  28.  
  29. #include <signal.h>
  30.  
  31. private void
  32. #ifdef    ID_CHAR
  33.     DeTab proto((int, char *, char *, size_t, int)),
  34.     DelChar proto((int, int, int)),
  35.     InsChar proto((int, int, int, char *)),
  36. #endif
  37.     DoIDline proto((int)),
  38.     do_cl_eol proto((int)),
  39.     ModeLine proto((Window *)),
  40.     GotoDot proto((void)),
  41.     UpdLine proto((int)),
  42.     UpdWindow proto((Window *, int));
  43.  
  44. #ifdef    MSDOS
  45. extern void    dobell proto((int x));
  46. #else
  47. private void    dobell proto((int x));
  48. #endif
  49.  
  50. #ifdef    ID_CHAR
  51. private bool
  52.     IDchar proto ((char *, int, int)),
  53.     OkayDelete proto ((int, int, int)),
  54.     OkayInsert proto ((int, int));
  55. private int
  56.     NumSimilar proto ((char *, char *, int)),
  57.     IDcomp proto ((char *, char *, int));
  58. #endif
  59. private int
  60.     AddLines proto((int, int)),
  61.     DelLines proto((int, int));
  62.  
  63.  
  64.  
  65. int    DisabledRedisplay = NO;
  66.  
  67. /* Kludge windows gets called by the routines that delete lines from the
  68.    buffer.  If the w->w_line or w->w_top are deleted and this procedure
  69.    is not called, the redisplay routine will barf. */
  70.  
  71. void
  72. ChkWindows(line1, line2)
  73. Line    *line1,
  74.     *line2;
  75. {
  76.     register Window    *w = fwind;
  77.     register Line    *lp,
  78.             *lend = line2->l_next;
  79.  
  80.     do {
  81.         if (w->w_bufp == curbuf) {
  82.             for (lp = line1->l_next; lp != lend; lp = lp->l_next) {
  83.                 if (lp == w->w_top)
  84.                     w->w_flags |= W_TOPGONE;
  85.                 if (lp == w->w_line)
  86.                     w->w_flags |= W_CURGONE;
  87.             }
  88.         }
  89.         w = w->w_next;
  90.     } while (w != fwind);
  91. }
  92.  
  93. /* Deleted and killed Lines are about to be recycled: check for dangling refs */
  94.  
  95. void
  96. ChkWinLines()
  97. {
  98.     register Window    *w = fwind;
  99.  
  100.     do {
  101.         if (w->w_top == NULL || w->w_top->l_dline == NULL_DADDR)
  102.             w->w_flags |= W_TOPGONE;
  103.         if (w->w_line == NULL || w->w_line->l_dline == NULL_DADDR)
  104.             w->w_flags |= W_CURGONE;
  105.         w = w->w_next;
  106.     } while (w != fwind);
  107. }
  108.  
  109. private bool    RingBell;    /* So if we have a lot of errors ...
  110.                   ring the bell only ONCE */
  111.  
  112. void
  113. redisplay()
  114. {
  115.     register Window    *w = fwind;
  116.     int    lineno,
  117.         done_ID = NO,
  118.         i;
  119.     register struct scrimage    *des_p,
  120.                     *phys_p;
  121.  
  122.     if (DisabledRedisplay == YES)
  123.         return;
  124.     curwind->w_line = curwind->w_bufp->b_dot;
  125.     curwind->w_char = curwind->w_bufp->b_char;
  126. #ifdef    MAC
  127.     InputPending = NO;
  128. #else
  129.     if ((InputPending = charp()) != NO)    /* calls CheckEvent, which could */
  130.         return;    /* result in a call to rediplay(). We don't want that. */
  131. #endif
  132. #ifdef    BSD_SIGS
  133.     if (UpdFreq)
  134.         SigHold(SIGALRM);
  135. #endif
  136.     if (RingBell) {
  137.         dobell(1);
  138.         RingBell = NO;
  139.     }
  140.     AbortCnt = BufSize;        /* initialize this now */
  141.     if (UpdMesg)
  142.         DrawMesg(YES);
  143.  
  144.     for (lineno = 0, w = fwind; lineno < ILI; w = w->w_next) {
  145.         UpdWindow(w, lineno);
  146.         lineno += w->w_height;
  147.     }
  148.  
  149.     UpdModLine = NO;/* Now that we've called update window, we can
  150.                assume that the modeline will be updated.  But
  151.                if while redrawing the modeline the user types
  152.                a character, ModeLine() is free to set this on
  153.                again so that the modeline will be fully drawn
  154.                at the next redisplay. */
  155.  
  156.     des_p = DesiredScreen;
  157.     phys_p = PhysScreen;
  158.     for (i = 0; i < ILI; i++, des_p++, phys_p++) {
  159.         if (!done_ID && (des_p->s_id != phys_p->s_id)) {
  160.             DoIDline(i);
  161.             done_ID = YES;
  162.         }
  163.         if ((des_p->s_flags & (DIRTY | L_MOD)) ||
  164.             (des_p->s_id != phys_p->s_id) ||
  165.             (des_p->s_vln != phys_p->s_vln) ||
  166.             (des_p->s_offset != phys_p->s_offset))
  167.             UpdLine(i);
  168.         if (InputPending)
  169.             goto ret;
  170.     }
  171.  
  172.     if (Asking) {
  173.         Placur(LI - 1, min(CO - 2, calc_pos(mesgbuf, AskingWidth)));
  174.             /* Nice kludge */
  175.         flushscreen();
  176.     } else {
  177.         GotoDot();
  178.     }
  179. ret:
  180.     ;    /* yuck */
  181.  
  182. #ifdef    BSD_SIGS
  183.     if (UpdFreq)
  184.         SigRelse(SIGALRM);
  185. #endif
  186. #ifdef    MAC
  187.     if (Windchange)
  188.         docontrols();
  189. #endif    /* MAC */
  190. }
  191.  
  192. #ifndef    IBMPC
  193. private void
  194. dobell(n)
  195. int    n;
  196. {
  197.     while (--n >= 0) {
  198. #ifndef    MAC
  199.         if (VisBell && VB)
  200.             putstr(VB);
  201.         else
  202.             putpad(BL, 1);
  203. #else
  204.         SysBeep(5);
  205. #endif
  206.     }
  207.     flushscreen();
  208. }
  209. #endif    /* IBMPC */
  210.  
  211. /* find_pos() returns the position on the line, that C_CHAR represents
  212.    in LINE */
  213.  
  214. private int
  215. find_pos(line, c_char)
  216. Line    *line;
  217. int    c_char;
  218. {
  219.     return calc_pos(lcontents(line), c_char);
  220. }
  221.  
  222. int
  223. calc_pos(lp, c_char)
  224. register char    *lp;
  225. register int    c_char;
  226. {
  227.     register int    pos = 0;
  228.     register int    c;
  229.  
  230.  
  231.     while ((--c_char >= 0) && ((c = *lp++) & CHARMASK) != 0) {
  232.         if (c == '\t')
  233.             pos += (tabstop - (pos % tabstop));
  234.         else if (jiscntrl(c))
  235.             pos += 2;
  236.         else
  237.             pos += 1;
  238.     }
  239.     return pos;
  240. }
  241.  
  242. bool    UpdModLine = NO,
  243.     UpdMesg = NO;
  244.  
  245. private void
  246. DoIDline(start)
  247. int    start;
  248. {
  249.     register struct scrimage    *des_p = &DesiredScreen[start];
  250.     struct scrimage    *phys_p = &PhysScreen[start];
  251.     register int    i,
  252.             j;
  253.  
  254.     /* Some changes have been made.  Try for insert or delete lines.
  255.        If either case has happened, Addlines and/or DelLines will do
  256.        necessary scrolling, also CONVERTING PhysScreen to account for the
  257.        physical changes.  The comparison continues from where the
  258.        insertion/deletion takes place; this doesn't happen very often,
  259.        usually it happens with more than one window with the same
  260.        buffer. */
  261.  
  262.     if (!CanScroll)
  263.         return;        /* We should never have been called! */
  264.  
  265.     for (i = start; i < ILI; i++, des_p++, phys_p++)
  266.         if (des_p->s_id != phys_p->s_id)
  267.             break;
  268.  
  269.     for (; i < ILI; i++) {
  270.         for (j = i + 1; j < ILI; j++) {
  271.             des_p = &DesiredScreen[j];
  272.             phys_p = &PhysScreen[j];
  273.             if (des_p->s_id != 0 && des_p->s_id == phys_p->s_id)
  274.                 break;
  275.             if (des_p->s_id == PhysScreen[i].s_id) {
  276.                 if (des_p->s_id == 0)
  277.                     continue;
  278.                 if (AddLines(i, j - i)) {
  279.                     DoIDline(j);
  280.                     return;
  281.                 }
  282.                 break;
  283.             }
  284.             if ((des_p = &DesiredScreen[i])->s_id == phys_p->s_id) {
  285.                 if (des_p->s_id == 0)
  286.                     continue;
  287.                 if (DelLines(i, j - i)) {
  288.                     DoIDline(i);
  289.                     return;
  290.                 }
  291.                 break;
  292.             }
  293.         }
  294.     }
  295. }
  296.  
  297. /* Make DesiredScreen reflect what the screen should look like when we are done
  298.    with the redisplay.  This deals with horizontal scrolling.  Also makes
  299.    sure the current line of the Window is in the window. */
  300.  
  301. bool    ScrollAll = NO;
  302.  
  303. private void
  304. UpdWindow(w, start)
  305. register Window    *w;
  306. int    start;
  307. {
  308.     Line    *lp;
  309.     int    i,
  310.         upper,        /* top of window */
  311.         lower,        /* bottom of window */
  312.         strt_col,    /* starting print column of current line */
  313.         ntries = 0;    /* # of tries at updating window */
  314.     register struct scrimage    *des_p,
  315.                     *phys_p;
  316.     Buffer    *bp = w->w_bufp;
  317.  
  318. retry:
  319.     if (w->w_flags & W_CURGONE) {
  320.         w->w_line = bp->b_dot;
  321.         w->w_char = bp->b_char;
  322.     }
  323.     if (w->w_flags & W_TOPGONE)
  324.         CentWind(w);    /* reset topline of screen */
  325.     w->w_flags &= ~(W_CURGONE | W_TOPGONE);
  326.  
  327.     /* make sure that the current line is in the window */
  328.     upper = start;
  329.     lower = upper + w->w_height - 1;    /* don't include modeline */
  330.     for (i = upper, lp = w->w_top; i < lower && lp != NULL; lp = lp->l_next, i++)
  331.         if (lp == w->w_line)
  332.             break;
  333.     if (i == lower || lp == NULL) {
  334.         ntries += 1;
  335.         if (ntries == 1) {
  336.             CalcWind(w);
  337.             goto retry;
  338.         } else if (ntries == 2) {
  339.             w->w_top = w->w_line = w->w_bufp->b_first;
  340.             writef("\rERROR in redisplay: I got hopelessly lost!");
  341.             dobell(2);
  342.             goto retry;
  343.         } else if (ntries == 3) {
  344.             writef("\n\rOops, still lost, quitting ...\r\n");
  345.             finish(SIGHUP);
  346.         }
  347.     }
  348.  
  349.     /* first do some calculations for the current line */
  350.     {
  351.         int    diff = (w->w_flags & W_NUMLINES) ? 8 : 0,
  352.             end_col;
  353.  
  354.         strt_col = ScrollAll? w->w_LRscroll : PhysScreen[i].s_offset;
  355.         end_col = strt_col + (CO - 2) - diff;
  356.         /* Right now we are displaying from strt_col to
  357.            end_col of the buffer line.  These are PRINT
  358.            columns, not actual characters. */
  359.         w->w_dotcol = find_pos(w->w_line, w->w_char);
  360.         /* if the new dotcol is out of range, reselect
  361.            a horizontal window */
  362.         if ((PhysScreen[i].s_offset == -1) ||
  363.             (w->w_dotcol < strt_col) ||
  364.             (w->w_dotcol >= end_col)) {
  365.             if (w->w_dotcol < ((CO - 2) - diff))
  366.                 strt_col = 0;
  367.             else
  368.                 strt_col = w->w_dotcol - (CO / 2);
  369.             if (ScrollAll) {
  370.                 if (w->w_LRscroll != strt_col)
  371.                     UpdModLine = YES;
  372.                 w->w_LRscroll = strt_col;
  373.             }
  374.         }
  375.         w->w_dotline = i;
  376.         w->w_dotcol += diff;
  377.     }
  378.  
  379.     des_p = &DesiredScreen[upper];
  380.     phys_p = &PhysScreen[upper];
  381.     for (i = upper, lp = w->w_top; lp != NULL && i < lower; i++, des_p++, phys_p++, lp = lp->l_next) {
  382.         des_p->s_window = w;
  383.         des_p->s_lp = lp;
  384.         /* ??? what is -(daddr)1?  Would NULL_DADDR work as well? -- DHR */
  385.         des_p->s_id = (lp == curline && DOLsave)?
  386.             -(daddr)1 : lp->l_dline & ~DIRTY;
  387.         des_p->s_flags = isdirty(lp) ? L_MOD : 0;
  388.         if (w->w_flags & W_NUMLINES)
  389.             des_p->s_vln = w->w_topnum + (i - upper);
  390.         else
  391.             des_p->s_vln = 0;
  392.  
  393.         if (lp == w->w_line)
  394.             des_p->s_offset = strt_col;
  395.         else
  396.             des_p->s_offset = w->w_LRscroll;
  397.     }
  398.  
  399.     /* Is structure assignment faster than copy each field separately? */
  400.     if (i < lower) {
  401.         static const struct scrimage    dirty_plate = { 0, DIRTY, 0, 0, 0, 0 },
  402.                     clean_plate = { 0, 0, 0, 0, 0, 0 };
  403.  
  404.         for (; i < lower; i++, des_p++, phys_p++)
  405.             if (phys_p->s_id != 0)
  406.                 *des_p = dirty_plate;
  407.             else
  408.                 *des_p = clean_plate;
  409.     }
  410.  
  411.     des_p->s_window = w;
  412.     des_p->s_flags = 0;
  413.     /* ??? The following assignment is very questionable:
  414.      * - it stores a pointer in an integer variable
  415.      * - it counts on these values being distinct from
  416.      *   disk addresses, 0 (NULL_DADDR), and -1.
  417.      * -- DHR
  418.      */
  419.     des_p->s_id = (daddr) w->w_bufp;
  420.     if (des_p->s_id != phys_p->s_id || UpdModLine)
  421.         des_p->s_flags = MODELINE | DIRTY;
  422. #ifdef    MAC
  423.     if (UpdModLine)
  424.         Modechange = YES;
  425.     if (w == curwind && w->w_control)
  426.         SetScrollBar(w->w_control);
  427. #endif
  428. }
  429.  
  430. /* Write whatever is in mesgbuf (maybe we are Asking, or just printed
  431.    a message).  Turns off the UpdateMesg line flag. */
  432.  
  433. void
  434. DrawMesg(abortable)
  435. bool    abortable;
  436. {
  437. #ifndef    MAC        /* same reason as in redisplay() */
  438.     if (charp())
  439.         return;
  440. #endif
  441.     i_set(ILI, 0);
  442.     if (swrite(mesgbuf, NO, abortable)) {
  443.         cl_eol();
  444.         UpdMesg = NO;
  445.     }
  446.     flushscreen();
  447. }
  448.  
  449. /* Goto the current position in the current window.  Presumably redisplay()
  450.    has already been called, and curwind->{w_dotline,w_dotcol} have been set
  451.    correctly. */
  452.  
  453. private void
  454. GotoDot()
  455. {
  456.     if (!InputPending) {
  457.         Placur(curwind->w_dotline,
  458.             curwind->w_dotcol - PhysScreen[curwind->w_dotline].s_offset);
  459.         flushscreen();
  460.     }
  461. }
  462.  
  463. private int
  464. UntilEqual(start)
  465. register int    start;
  466. {
  467.     register struct scrimage    *des_p = &DesiredScreen[start],
  468.                     *phys_p = &PhysScreen[start];
  469.  
  470.     while ((start < ILI) && (des_p->s_id != phys_p->s_id)) {
  471.         des_p += 1;
  472.         phys_p += 1;
  473.         start += 1;
  474.     }
  475.  
  476.     return start;
  477. }
  478.  
  479. /* Calls the routine to do the physical changes, and changes PhysScreen to
  480.    reflect those changes. */
  481.  
  482. private int
  483. AddLines(at, num)
  484. register int    at,
  485.         num;
  486. {
  487.     register int    i;
  488.     int    bottom = UntilEqual(at + num);
  489.  
  490.     if (num == 0 || num >= ((bottom - 1) - at))
  491.         return NO;                /* we did nothing */
  492.     v_ins_line(num, at, bottom - 1);
  493.  
  494.     /* Now change PhysScreen to account for the physical change. */
  495.  
  496.     for (i = bottom - 1; i - num >= at; i--)
  497.         PhysScreen[i] = PhysScreen[i - num];
  498.     for (i = 0; i < num; i++)
  499.         PhysScreen[at + i].s_id = 0;
  500.     return YES;                    /* we did something */
  501. }
  502.  
  503. private int
  504. DelLines(at, num)
  505. register int    at,
  506.         num;
  507. {
  508.     register int    i;
  509.     int    bottom = UntilEqual(at + num);
  510.  
  511.     if (num == 0 || num >= ((bottom - 1) - at))
  512.         return NO;
  513.     v_del_line(num, at, bottom - 1);
  514.  
  515.     for (i = at; num + i < bottom; i++)
  516.         PhysScreen[i] = PhysScreen[num + i];
  517.     for (i = bottom - num; i < bottom; i++)
  518.         PhysScreen[i].s_id = 0;
  519.     return YES;
  520. }
  521.  
  522. /* Update line linenum in window w.  Only set PhysScreen to DesiredScreen
  523.    if the swrite or cl_eol works, that is nothing is interupted by
  524.    characters typed. */
  525.  
  526. private void
  527. UpdLine(linenum)
  528. register int    linenum;
  529. {
  530.     register struct scrimage    *des_p = &DesiredScreen[linenum];
  531.     register Window    *w = des_p->s_window;
  532.  
  533.     i_set(linenum, 0);
  534.     if (des_p->s_flags & MODELINE) {
  535.         ModeLine(w);
  536.     } else if (des_p->s_id) {
  537.         des_p->s_lp->l_dline &= ~DIRTY;
  538.         des_p->s_flags &= ~(DIRTY | L_MOD);
  539. #ifdef    ID_CHAR
  540.         if (UseIC) {
  541.             char    outbuf[MAXCOLS],
  542.                 *lptr;
  543.             int    fromcol = (w->w_flags & W_NUMLINES) ? 8 : 0;
  544.  
  545.             if (w->w_flags & W_NUMLINES)
  546.                 swritef(outbuf, sizeof(outbuf), "%6d  ",
  547.                     des_p->s_vln);
  548.             lptr = lcontents(des_p->s_lp);
  549.             DeTab(des_p->s_offset, lptr, outbuf + fromcol,
  550.                 (sizeof outbuf) - 1 - fromcol,
  551.                 des_p->s_window->w_flags & W_VISSPACE);
  552.             if (IDchar(outbuf, linenum, 0))
  553.                 PhysScreen[linenum] = *des_p;
  554.             else if (i_set(linenum, 0), swrite(outbuf, NO, YES))
  555.                 do_cl_eol(linenum);
  556.             else
  557.                 PhysScreen[linenum].s_id = -1;
  558.         } else {
  559. #endif    /* ID_CHAR */
  560.             if (w->w_flags & W_NUMLINES)
  561.                 (void) swrite(sprint("%6d  ", des_p->s_vln), NO, YES);
  562.             if (BufSwrite(linenum))
  563.                 do_cl_eol(linenum);
  564.             else
  565.                 PhysScreen[linenum].s_id = -1;
  566. #ifdef    ID_CHAR
  567.         }
  568. #endif
  569.     } else if (PhysScreen[linenum].s_id) {    /* not the same ... make sure */
  570.         do_cl_eol(linenum);
  571.     }
  572. }
  573.  
  574. private void
  575. do_cl_eol(linenum)
  576. register int    linenum;
  577. {
  578.     cl_eol();
  579.     PhysScreen[linenum] = DesiredScreen[linenum];
  580. }
  581.  
  582. #ifdef    ID_CHAR
  583.  
  584. /* From here to the end of the file is code that tries to utilize the
  585.    insert/delete character feature on some terminals.  It is very confusing
  586.    and not so well written code, AND there is a lot of it.  You may want
  587.    to use the space for something else. */
  588.  
  589. bool    IN_INSmode = FALSE;
  590.  
  591. bool    UseIC = FALSE;
  592.  
  593. int    IMlen;
  594.  
  595. private int
  596.     DClen,
  597.     IClen,
  598.     MDClen,
  599.     MIClen,
  600.     CElen;
  601.  
  602. void
  603. disp_opt_init()
  604. {
  605.     DClen = DC ? strlen(DC) : 0;
  606.     MDClen = M_DC ? strlen(M_DC) : 9999;
  607.     IClen = IC ? strlen(IC) : 0;
  608.     MIClen = M_IC ? strlen(M_IC) : 9999;
  609.     IMlen = IM ? strlen(IM) : 0;
  610.     CElen = CE ? strlen(CE) : 0;
  611.  
  612.     UseIC = (IC || IM || M_IC);
  613. }
  614.  
  615. void
  616. INSmode(on)
  617. bool    on;
  618. {
  619.     if (on && !IN_INSmode) {
  620.         putpad(IM, 1);
  621.         IN_INSmode = YES;
  622.     } else if (!on && IN_INSmode) {
  623.         putpad(EI, 1);
  624.         IN_INSmode = NO;
  625.     }
  626. }
  627.  
  628. private void
  629. DeTab(s_offset, buf, outbuf, limit, visspace)
  630. int    s_offset;
  631. register char    *buf;
  632. char    *outbuf;
  633. size_t    limit;
  634. int    visspace;
  635. {
  636.     register char    *phys_p = outbuf,
  637.             c;
  638.     register int    pos = 0;
  639.     char        *limitp = &outbuf[limit];
  640.  
  641. #define OkayOut(ch)    { \
  642.     if ((pos++ >= s_offset) && (phys_p < limitp)) \
  643.         *phys_p++ = (ch); \
  644. }
  645.  
  646.     while ((c = *buf++) != '\0') {
  647.         if (c == '\t') {
  648.             int    nchars = (tabstop - (pos % tabstop));
  649.  
  650.             if (visspace) {
  651.                 OkayOut('>');
  652.                 nchars -= 1;
  653.             }
  654.             while (--nchars >= 0)
  655.                 OkayOut(' ');
  656.  
  657.         } else if (jiscntrl(c)) {
  658.             OkayOut('^');
  659.             OkayOut(c == 0177 ? '?' : c + '@');
  660.         } else {
  661.             if (visspace && c == ' ')
  662.                 c = '_';
  663.             OkayOut(c);
  664.         }
  665.         if (pos - s_offset >= CO) {
  666.             phys_p = &outbuf[CO - 1];
  667.             *phys_p++ = '!';
  668.             break;
  669.         }
  670.     }
  671.     *phys_p = '\0';
  672.  
  673. #undef    OkayOut
  674. }
  675.  
  676. /* ID character routines full of special cases and other fun stuff like that.
  677.    It actually works though ...
  678.  
  679.     Returns Non-Zero if you are finished (no differences left). */
  680.  
  681. private bool
  682. IDchar(new, lineno, col)
  683. register char    *new;
  684. int    lineno,
  685.     col;
  686. {
  687.     register int    i;
  688.     int    j,
  689.         oldlen,
  690.         NumSaved;
  691.     register struct screenline    *sline = &Screen[lineno];
  692.  
  693.     oldlen = sline->s_length - sline->s_line;
  694.  
  695.     for (i = col; i < oldlen && new[i] != '\0'; i++)
  696.         if (sline->s_line[i] != new[i])
  697.             break;
  698.     if (new[i] == '\0' || i == oldlen)
  699.         return new[i] == '\0' && i == oldlen;
  700.  
  701.     for (j = i + 1; j < oldlen && new[j]; j++) {
  702.         if (new[j] == sline->s_line[i]) {
  703.             NumSaved = IDcomp(new + j, sline->s_line + i,
  704.                     (int)strlen(new)) + NumSimilar(new + i,
  705.                         sline->s_line + i, j - i);
  706.             if (OkayInsert(NumSaved, j - i)) {
  707.                 InsChar(lineno, i, j - i, new);
  708.                 return IDchar(new, lineno, j);
  709.             }
  710.         }
  711.     }
  712.  
  713.     for (j = i + 1; j < oldlen && new[i]; j++) {
  714.         if (new[i] == sline->s_line[j]) {
  715.             NumSaved = IDcomp(new + i, sline->s_line + j,
  716.                     oldlen - j);
  717.             if (OkayDelete(NumSaved, j - i, new[oldlen] == '\0')) {
  718.                 DelChar(lineno, i, j - i);
  719.                 return IDchar(new, lineno, i);
  720.             }
  721.         }
  722.     }
  723.     return NO;
  724. }
  725.  
  726. private int
  727. NumSimilar(s, t, n)
  728. register char    *s,
  729.         *t;
  730. int    n;
  731. {
  732.     register int    num = 0;
  733.  
  734.     while (n--)
  735.         if (*s++ == *t++)
  736.             num += 1;
  737.     return num;
  738. }
  739.  
  740. private int
  741. IDcomp(s, t, len)
  742. register char    *s,
  743.         *t;
  744. int    len;
  745. {
  746.     register int    i;
  747.     int    num = 0,
  748.         nonspace = 0;
  749.     char    c;
  750.  
  751.     for (i = 0; i < len; i++) {
  752.         if ((c = *s++) != *t++)
  753.             break;
  754.         if (c != ' ')
  755.             nonspace++;
  756.         if (nonspace)
  757.             num += 1;
  758.     }
  759.  
  760.     return num;
  761. }
  762.  
  763. private bool
  764. OkayDelete(Saved, num, samelength)
  765. int    Saved,
  766.     num,
  767.     samelength;
  768. {
  769.     /* If the old and the new are the same length, then we don't
  770.      * have to clear to end of line.  We take that into consideration.
  771.      */
  772.     return ((Saved + (!samelength ? CElen : 0))
  773.         > min(MDClen, DClen * num));
  774. }
  775.  
  776. private bool
  777. OkayInsert(Saved, num)
  778. int    Saved,
  779.     num;
  780. {
  781.     register int    n = 0;
  782.  
  783.     if (IC)        /* Per character prefixes */
  784.         n = min(num * IClen, MIClen);
  785.  
  786.     if (IM && !IN_INSmode) {
  787.         /* Good terminal.  Fewer characters in this case */
  788.         n += IMlen;
  789.     }
  790.  
  791.     n += num;    /* The characters themselves */
  792.  
  793.     return Saved > n;
  794. }
  795.  
  796. private void
  797. DelChar(lineno, col, num)
  798. int    lineno,
  799.     col,
  800.     num;
  801. {
  802.     register char    *from,
  803.             *to;
  804.     register int    i;
  805.     struct screenline *sp = (&Screen[lineno]);
  806.  
  807.     Placur(lineno, col);
  808.     if (M_DC && num > 1) {
  809.         putargpad(M_DC, num, num);
  810.     } else {
  811.         for (i = num; --i >= 0; )
  812.             putpad(DC, 1);
  813.     }
  814.  
  815.     to = sp->s_line + col;
  816.     from = to + num;
  817.  
  818.     byte_copy(from, to, (size_t) (sp->s_length - from + 1));
  819.     clrline(sp->s_length - num, sp->s_length);
  820.     sp->s_length -= num;
  821. }
  822.  
  823. private void
  824. InsChar(lineno, col, num, new)
  825. int    lineno,
  826.     col,
  827.     num;
  828. char    *new;
  829. {
  830.     register char    *sp1,
  831.             *sp2,    /* To push over the array. */
  832.             *sp3;    /* Last character to push over. */
  833.     int    i;
  834.  
  835.     i_set(lineno, 0);
  836.     sp2 = Curline->s_length + num;
  837.  
  838.     if (sp2 >= cursend) {
  839.         i_set(lineno, CO - num - 1);
  840.         cl_eol();
  841.         sp2 = cursend - 1;
  842.     }
  843.     Curline->s_length = sp2;
  844.     sp1 = sp2 - num;
  845.     sp3 = Curline->s_line + col;
  846.  
  847.     while (sp1 >= sp3)
  848.         *sp2-- = *sp1--;
  849.  
  850.     new += col;
  851.     byte_copy(new, sp3, (size_t) num);
  852.     /* The internal screen is correct, and now we have to do
  853.        the physical stuff. */
  854.  
  855.     Placur(lineno, col);
  856.     if (IM) {
  857.         if (!IN_INSmode)
  858.             INSmode(ON);
  859.     } else if (M_IC && num > 1) {
  860.         putargpad(M_IC, num, num);
  861.     } else if (IC) {
  862.         for (i = 0; i < num; i++)
  863.             putpad(IC, 1);
  864.     }
  865.     for (i = 0; i < num; i++) {
  866.         jputchar(new[i]);
  867.         if (IN_INSmode)
  868.             putpad(IP, 1);
  869.     }
  870.     CapCol += num;
  871. }
  872.  
  873. #endif    /* ID_CHAR */
  874.  
  875. #ifdef    UNIX        /* obviously ... no mail today if not Unix*/
  876.  
  877. /* chkmail() returns nonzero if there is new mail since the
  878.    last time we checked. */
  879.  
  880. char    Mailbox[FILESIZE];    /* initialized in main */
  881. int    MailInt = 60;        /* check no more often than 60 seconds */
  882. #ifdef    BIFF
  883. bool    BiffChk = NO;        /* whether to turn off biff while in JOVE */
  884. #endif
  885.  
  886. int
  887. chkmail(force)
  888. int    force;
  889. {
  890.     time_t    now;
  891.     static int    state = NO;    /* assume unknown */
  892.     static time_t    last_chk = 0,
  893.             mbox_time = 0;
  894.     struct stat    stbuf;
  895.  
  896.     if (MailInt == 0)
  897.         return NO;
  898.     time(&now);
  899.     if ((force == NO) && (now < last_chk + MailInt))
  900.         return state;
  901.     last_chk = now;
  902.     if (stat(Mailbox, &stbuf) < 0) {
  903.         state = NO;        /* no mail */
  904.         return NO;
  905.     }
  906.     if (((stbuf.st_atime > stbuf.st_mtime) &&
  907.          (stbuf.st_atime > mbox_time)) ||
  908.         (stbuf.st_size == 0)) {
  909.         mbox_time = stbuf.st_atime;
  910.         state = NO;
  911.     } else if (stbuf.st_mtime > mbox_time) {
  912.         if (mbox_time > 0)
  913.             dobell(2);        /* announce the change */
  914.         mbox_time = stbuf.st_mtime;
  915.         state = YES;
  916.     }
  917.     return state;
  918. }
  919.  
  920. #endif    /* UNIX */
  921.  
  922. /* Print the mode line. */
  923.  
  924. private char    *mode_p,
  925.         *mend_p;
  926. bool    BriteMode = ON;        /* modeline should standout */
  927.  
  928. private void
  929. mode_app(str)
  930. register const char    *str;
  931. {
  932.     do ; while ((mode_p < mend_p) && (*mode_p++ = *str++)!='\0');
  933.     mode_p -= 1;    /* back over the null */
  934. }
  935.  
  936. char    ModeFmt[120] = "%3c %w %[%sJOVE (%M)   Buffer: %b  \"%f\" %]%s%m*- %((%t)%s%)%e";
  937.  
  938. private void
  939. ModeLine(w)
  940. register Window    *w;
  941. {
  942.     int    n,
  943.         glue = 0;
  944.     bool    ign_some = NO;
  945.     char    line[MAXCOLS],
  946.         *fmt = ModeFmt,
  947.         fillc,
  948.         c;
  949.     register Buffer    *thisbuf = w->w_bufp;
  950.     register Buffer *bp;
  951.  
  952.     mode_p = line;
  953.     mend_p = &line[(sizeof line) - 1];
  954.  
  955. #ifdef    IBMPC
  956.     /* very subtle - don't mess up attributes too much */
  957.     fillc = '-';
  958. #else    /* !IBMPC */
  959. #  ifdef    MAC
  960.     fillc = '_';    /* looks better on a Mac */
  961. #  else    /* !MAC */
  962.     if (SO == NULL)
  963.         BriteMode = OFF;
  964.     fillc = BriteMode ? ' ' : '-';
  965. #  endif    /* !MAC */
  966. #endif    /* !IBMPC */
  967.  
  968.     while ((c = *fmt++)!='\0' && mode_p<mend_p) {
  969.         if (c != '%') {
  970.             if (c == '\\')
  971.                 if ((c = *fmt++) == '\0')
  972.                     break;
  973.             if (!ign_some)
  974.                 *mode_p++ = c;
  975.             continue;
  976.         }
  977.         if ((c = *fmt++) == '\0')    /* char after the '%' */
  978.             break;
  979.         if (ign_some && c != ')')
  980.             continue;
  981.         n = 1;
  982.         if (c >= '0' && c <= '9') {
  983.             n = 0;
  984.             while (c >= '0' && c <= '9') {
  985.                 n = n * 10 + (c - '0');
  986.                 c = *fmt++;
  987.             }
  988.             if (c == '\0')
  989.                 break;
  990.         }
  991.         switch (c) {
  992.         case '(':
  993.             if (w->w_next != fwind)    /* Not bottom window. */
  994.                 ign_some = YES;
  995.             break;
  996.  
  997.         case ')':
  998.             ign_some = NO;
  999.             break;
  1000.  
  1001.         case '[':
  1002.         case ']':
  1003.             for (n=RecDepth; n>0 && mode_p<mend_p; n--)
  1004.                 *mode_p++ = c;
  1005.             break;
  1006.  
  1007. #ifdef    UNIX
  1008.         case 'C':    /* check mail here */
  1009.             if (chkmail(NO) == YES)
  1010.                 mode_app("[New mail]");
  1011.             break;
  1012.  
  1013. #endif    /* UNIX */
  1014.  
  1015.         case 'M':
  1016.             {
  1017.             static const char    *const mmodes[] = {
  1018.                 "Fundamental ",
  1019.                 "Text ",
  1020.                 "C ",
  1021. #ifdef    LISP
  1022.                 "Lisp ",
  1023. #endif
  1024.                 NULL
  1025.             };
  1026.  
  1027.             mode_app(mmodes[thisbuf->b_major]);
  1028.  
  1029.             if (BufMinorMode(thisbuf, Fill))
  1030.                 mode_app("Fill ");
  1031.             if (BufMinorMode(thisbuf, Abbrev))
  1032.                 mode_app("Abbrev ");
  1033.             if (BufMinorMode(thisbuf, OverWrite))
  1034.                 mode_app("OvrWt ");
  1035.             if (BufMinorMode(thisbuf, Indent))
  1036.                 mode_app("Indent ");
  1037.             if (BufMinorMode(thisbuf, ReadOnly))
  1038.                 mode_app("RO ");
  1039.             if (InMacDefine)
  1040.                 mode_app("Def ");
  1041.             mode_p -= 1;    /* Back over the extra space. */
  1042.             break;
  1043.             }
  1044.  
  1045.         case 'c':
  1046.             while (--n>=0 && mode_p<mend_p)
  1047.                 *mode_p++ = fillc;
  1048.             break;
  1049.  
  1050.         case 'd':    /* print working directory */
  1051.             mode_app(pr_name(pwd(), YES));
  1052.             break;
  1053.  
  1054.         case 'e':    /* stretchable glue */
  1055.             *mode_p++ = '\0';    /* glue marker */
  1056.             glue++;
  1057.             break;
  1058.  
  1059.         case 'b':
  1060.             mode_app(thisbuf->b_name);
  1061.             break;
  1062.  
  1063.         case 'f':
  1064.         case 'F':
  1065.             if (thisbuf->b_fname == NULL)
  1066.                 mode_app("[No file]");
  1067.             else {
  1068.                 if (c == 'f')
  1069.                     mode_app(pr_name(thisbuf->b_fname, YES));
  1070.                 else
  1071.                     mode_app(basename(thisbuf->b_fname));
  1072.             }
  1073.             break;
  1074.  
  1075. #ifdef    LOAD_AV
  1076.         case 'l':
  1077.             {
  1078.             int    la = get_la();
  1079.             char    minibuf[10];
  1080.  
  1081.             swritef(minibuf, sizeof(minibuf), "%d.%02d",
  1082.                    la/100, la%100);
  1083.             mode_app(minibuf);
  1084.             break;
  1085.             }
  1086. #endif
  1087.  
  1088.         case 'm':
  1089.             {
  1090.             char    yea = (*fmt == '\0') ? '*' : *fmt++;
  1091.             char    nay = (*fmt == '\0') ? ' ' : *fmt++;
  1092.  
  1093.             *mode_p++ = IsModified(w->w_bufp) ? yea : nay;
  1094.             break;
  1095.             }
  1096.  
  1097.         case 'n':
  1098.             {
  1099.             char    tmp[16];
  1100.  
  1101.             for (bp = world, n = 1; bp != NULL; bp = bp->b_next, n++)
  1102.                 if (bp == thisbuf)
  1103.                     break;
  1104.  
  1105.             swritef(tmp, sizeof(tmp), "%d", n);
  1106.             mode_app(tmp);
  1107.             break;
  1108.             }
  1109.  
  1110. #ifdef    IPROCS
  1111.         case 'p':
  1112.             if (thisbuf->b_type == B_PROCESS) {
  1113.                 char    tmp[40];
  1114.                 Process    *p = thisbuf->b_process;
  1115.  
  1116.                 swritef(tmp, sizeof(tmp), "(%s%s)",
  1117.                     ((p == NULL || p->p_dbx_mode == NO)
  1118.                      ? "" : "DBX "),
  1119.                     ((p == NULL) ? "No process" :
  1120.                      pstate(p)));
  1121.                 mode_app(tmp);
  1122.             }
  1123.             break;
  1124. #endif
  1125.  
  1126.         case 's':
  1127.             if (mode_p[-1] != ' ')
  1128.                 *mode_p++ = ' ';
  1129.             break;
  1130.  
  1131.         case 't':
  1132.             {
  1133.             char    timestr[12];
  1134.  
  1135.             mode_app(get_time((time_t *)NULL, timestr, 11, 16));
  1136.             break;
  1137.             }
  1138.  
  1139.         case 'w':
  1140.             if (w->w_LRscroll > 0)
  1141.                 mode_app(">");
  1142.             break;
  1143.  
  1144.         default:
  1145.             mode_app("?");
  1146.             break;
  1147.         }
  1148.     }
  1149.  
  1150.     /* Glue (Knuth's term) is a field that expands to fill
  1151.      * any leftover space.  Multiple glue fields compete
  1152.      * on an equal basis.  This is a generalization of a
  1153.      * mechanism to allow centring and right-justification.
  1154.      * The original meaning of %e (fill the rest of the
  1155.      * line) has also been generalized.  %e can now
  1156.      * meaningfully be used 0 or more times.
  1157.      */
  1158.  
  1159.     if  (glue) {
  1160.         /* 2 space pad plus padding for magic cookies */
  1161.         register char    *to = &line[CO - 2 - (2 * SG)],
  1162.                 *from = mode_p;
  1163.  
  1164.         if (to < from)
  1165.             to = from;
  1166.         mode_p = to;
  1167.         while (from != line) {
  1168.             if ((*--to = *--from) == '\0') {
  1169.                 register int    portion = (to-from) / glue;
  1170.  
  1171.                 glue--;
  1172.                 *to = fillc;
  1173.                 while (--portion >= 0)
  1174.                     *--to = fillc;
  1175.             }
  1176.         }
  1177.     }
  1178.  
  1179.     *mode_p = '\0';
  1180.  
  1181.     /* Highlight mode line. */
  1182.     if (BriteMode) {
  1183. #ifdef    ID_CHAR
  1184.         if (IN_INSmode)
  1185.             INSmode(OFF);
  1186. #endif
  1187.         SO_on();
  1188.     }
  1189.     if (swrite(line, BriteMode, YES))
  1190.         do_cl_eol(i_line);
  1191.     else
  1192.         UpdModLine = YES;
  1193.     if (BriteMode)
  1194.         SO_off();
  1195. }
  1196.  
  1197. private void
  1198. v_clear(line1, line2)
  1199. register int    line1;
  1200. int    line2;
  1201. {
  1202.     register struct scrimage    *phys_p, *des_p;
  1203.  
  1204.     phys_p = &PhysScreen[line1];
  1205.     des_p = &DesiredScreen[line1];
  1206.  
  1207.     while (line1 <= line2) {
  1208.         i_set(line1, 0);
  1209.         cl_eol();
  1210.         phys_p->s_id = des_p->s_id = 0;
  1211.         phys_p += 1;
  1212.         des_p += 1;
  1213.         line1 += 1;
  1214.     }
  1215. }
  1216.  
  1217. /* This tries to place the current line of the current window in the
  1218.    center of the window, OR to place it at the arg'th line of the window.
  1219.    This also causes the horizontal position of the line to be centered,
  1220.    if the line needs scrolling, or moved all the way back to the left,
  1221.    if that's possible. */
  1222. void
  1223. RedrawDisplay()
  1224. {
  1225.     int    line;
  1226.     Line    *newtop = prev_line((curwind->w_line = curline), is_an_arg() ?
  1227.                 arg_value() : HALF(curwind));
  1228.  
  1229.     if ((line = in_window(curwind, curwind->w_line)) != -1)
  1230.         PhysScreen[line].s_offset = -1;
  1231.     if (newtop == curwind->w_top)
  1232.         v_clear(FLine(curwind), FLine(curwind) + SIZE(curwind));
  1233.     else
  1234.         SetTop(curwind, newtop);
  1235. }
  1236.  
  1237. void
  1238. ClAndRedraw()
  1239. {
  1240.     cl_scr(YES);
  1241. }
  1242.  
  1243. void
  1244. NextPage()
  1245. {
  1246.     Line    *newline;
  1247.  
  1248.     if (Asking)
  1249.         return;
  1250.     if (arg_value() < 0) {
  1251.         negate_arg_value();
  1252.         PrevPage();
  1253.         return;
  1254.     }
  1255.     if (arg_type() == YES)
  1256.         UpScroll();
  1257.     else {
  1258.         if (in_window(curwind, curwind->w_bufp->b_last) != -1) {
  1259.             rbell();
  1260.             return;
  1261.         }
  1262.         newline = next_line(curwind->w_top, max(1, SIZE(curwind) - 1));
  1263.         SetTop(curwind, curwind->w_line = newline);
  1264.         if (curwind->w_bufp == curbuf)
  1265.             SetLine(newline);
  1266.     }
  1267. }
  1268.  
  1269. #ifdef    MSDOS
  1270.  
  1271. void
  1272. PageScrollUp()
  1273. {
  1274.     int i, n;
  1275.  
  1276.     n = max(1, SIZE(curwind) - 1);
  1277.     for (i=0; i<n; i++) {
  1278.         UpScroll();
  1279.         redisplay();
  1280.     }
  1281. }
  1282.  
  1283. void
  1284. PageScrollDown()
  1285. {
  1286.     int i, n;
  1287.  
  1288.     n = max(1, SIZE(curwind) - 1);
  1289.     for (i=0; i<n; i++) {
  1290.         DownScroll();
  1291.         redisplay();
  1292.     }
  1293. }
  1294. #endif    /* MSDOS */
  1295.  
  1296. void
  1297. PrevPage()
  1298. {
  1299.     Line    *newline;
  1300.  
  1301.     if (Asking)
  1302.         return;
  1303.     if (arg_value() < 0) {
  1304.         negate_arg_value();
  1305.         NextPage();
  1306.         return;
  1307.     }
  1308.     if (arg_type() == YES)
  1309.         DownScroll();
  1310.     else {
  1311.         newline = prev_line(curwind->w_top, max(1, SIZE(curwind) - 1));
  1312.         SetTop(curwind, curwind->w_line = newline);
  1313.         if (curwind->w_bufp == curbuf)
  1314.             SetLine(newline);
  1315.     }
  1316. }
  1317.  
  1318. void
  1319. UpScroll()
  1320. {
  1321.     SetTop(curwind, next_line(curwind->w_top, arg_value()));
  1322.     if ((curwind->w_bufp == curbuf) &&
  1323.         (in_window(curwind, curline) == -1))
  1324.         SetLine(curwind->w_top);
  1325. }
  1326.  
  1327. void
  1328. DownScroll()
  1329. {
  1330.     SetTop(curwind, prev_line(curwind->w_top, arg_value()));
  1331.     if ((curwind->w_bufp == curbuf) &&
  1332.         (in_window(curwind, curline) == -1))
  1333.         SetLine(curwind->w_top);
  1334. }
  1335.  
  1336. bool    VisBell = NO;
  1337.  
  1338. void
  1339. rbell()
  1340. {
  1341.     RingBell = YES;
  1342. }
  1343.  
  1344. /* Message prints the null terminated string onto the bottom line of the
  1345.    terminal. */
  1346.  
  1347. void
  1348. message(str)
  1349. char    *str;
  1350. {
  1351.     if (InJoverc)
  1352.         return;
  1353.     UpdMesg = YES;
  1354.     errormsg = NO;
  1355.     if (str != mesgbuf)
  1356.         null_ncpy(mesgbuf, str, (sizeof mesgbuf) - 1);
  1357. }
  1358.  
  1359. /* End of Window */
  1360.  
  1361. void
  1362. Eow()
  1363. {
  1364.     if (Asking)
  1365.         return;
  1366.     SetLine(next_line(curwind->w_top, SIZE(curwind) - 1 -
  1367.             min(SIZE(curwind) - 1, arg_value() - 1)));
  1368.     if (!is_an_arg())
  1369.         Eol();
  1370. }
  1371.  
  1372. /* Beginning of Window */
  1373.  
  1374. void
  1375. Bow()
  1376. {
  1377.     if (Asking)
  1378.         return;
  1379.     SetLine(next_line(curwind->w_top, min(SIZE(curwind) - 1, arg_value() - 1)));
  1380. }
  1381.  
  1382. private int    LineNo,
  1383.         last_col;
  1384. private bool
  1385.         DoAutoNL;
  1386. private Window    *old_wind;    /* save the window we were in BEFORE
  1387.                    before we were called, if UseBuffers
  1388.                    is nonzero */
  1389.  
  1390. bool    UseBuffers = FALSE,
  1391.     TOabort = FALSE;
  1392.  
  1393. /* This initializes the typeout.  If send-typeout-to-buffers is set
  1394.    the buffer NAME is created (emptied if it already exists) and output
  1395.    goes to the buffer.  Otherwise output is drawn on the screen and
  1396.    erased by TOstop() */
  1397.  
  1398. void
  1399. TOstart(name, auto_newline)
  1400. char    *name;
  1401. bool    auto_newline;
  1402. {
  1403.     if (UseBuffers) {
  1404.         old_wind = curwind;
  1405.         pop_wind(name, YES, B_SCRATCH);
  1406.     } else
  1407.         DisabledRedisplay = YES;
  1408.     TOabort = FALSE;
  1409.     LineNo = last_col = 0;
  1410.     DoAutoNL = auto_newline;
  1411. }
  1412.  
  1413. #ifdef    STDARGS
  1414.     void
  1415. Typeout(char *fmt, ...)
  1416. #else
  1417.     /*VARARGS1*/ void
  1418. Typeout(fmt, va_alist)
  1419.     char    *fmt;
  1420.     va_dcl
  1421. #endif
  1422. {
  1423.     if (TOabort)
  1424.         return;
  1425.  
  1426.     if (!UseBuffers && (LineNo == ILI - 1)) {
  1427.         register int    c;
  1428.  
  1429.         LineNo = 0;
  1430.         last_col = 0;
  1431.         f_mess("--more--");
  1432.         if ((c = jgetchar()) != ' ') {
  1433.             TOabort = TRUE;
  1434.             if (c != AbortChar && c != RUBOUT)
  1435.                 Ungetc(c);
  1436.             f_mess(NullStr);
  1437.             return;
  1438.         }
  1439.         f_mess(NullStr);
  1440.     }
  1441.  
  1442.     if (fmt) {
  1443.         char    string[132];
  1444.         va_list    ap;
  1445.  
  1446.         va_init(ap, fmt);
  1447.         format(string, sizeof string, fmt, ap);
  1448.         va_end(ap);
  1449.         if (UseBuffers) {
  1450.             ins_str(string, NO);
  1451.         } else {
  1452.             i_set(LineNo, last_col);
  1453.             (void) swrite(string, NO, YES);
  1454.             last_col = i_col;
  1455.         }
  1456.     }
  1457.     if (!UseBuffers) {
  1458.         PhysScreen[LineNo].s_id = -1;
  1459.         if (fmt == NULL || DoAutoNL) {
  1460.             cl_eol();
  1461.             flushscreen();
  1462.             LineNo += 1;
  1463.             last_col = 0;
  1464.         }
  1465.     } else if (fmt == NULL || DoAutoNL)
  1466.         ins_str("\n", NO);
  1467. }
  1468.  
  1469. void
  1470. TOstop()
  1471. {
  1472.     int    c;
  1473.  
  1474.     if (UseBuffers) {
  1475.         ToFirst();
  1476.         SetWind(old_wind);
  1477.     } else {
  1478.         if (TOabort) {
  1479.             DisabledRedisplay = NO;
  1480.         } else {
  1481.             if (last_col != 0)
  1482.                 Typeout((char *)NULL);
  1483.             Typeout("----------");
  1484.             cl_eol();
  1485.             flushscreen();
  1486.             c = jgetchar();
  1487.             if (c != ' ')
  1488.                 Ungetc(c);
  1489.             DisabledRedisplay = NO;
  1490.         }
  1491.     }
  1492. }
  1493.