home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / display.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  43KB  |  2,143 lines

  1. /*
  2.  * The functions in this file handle redisplay. There are two halves, the
  3.  * ones that update the virtual display screen, and the ones that make the
  4.  * physical display screen the same as the virtual display screen. These
  5.  * functions use hints that are left in the windows by the commands.
  6.  *
  7.  *
  8.  * $Log: display.c,v $
  9.  * Revision 1.54  1992/12/04  09:12:25  foxharp
  10.  * deleted unused assigns
  11.  *
  12.  * Revision 1.53  1992/08/20  23:40:48  foxharp
  13.  * typo fixes -- thanks, eric
  14.  *
  15.  * Revision 1.52  1992/08/05  21:55:16  foxharp
  16.  * handle files with DOS drive designators properly on mode line
  17.  *
  18.  * Revision 1.51  1992/07/24  07:49:38  foxharp
  19.  * shorten_name changes
  20.  *
  21.  * Revision 1.50  1992/07/22  19:25:57  foxharp
  22.  * handle non-printables correctly -- how did I get involved in this, anyway!
  23.  *
  24.  * Revision 1.49  1992/07/22  09:18:16  foxharp
  25.  * got it.  sheesh.
  26.  *
  27.  * Revision 1.48  1992/07/22  00:50:43  foxharp
  28.  * interim -- still dumping core in vtset
  29.  *
  30.  * Revision 1.47  1992/07/21  09:08:30  foxharp
  31.  * now pass lp to vtset()
  32.  *
  33.  * Revision 1.46  1992/07/21  08:57:53  foxharp
  34.  * pushed list mode choice into vtset()
  35.  *
  36.  * Revision 1.45  1992/07/20  22:44:44  foxharp
  37.  * performance improvements -- fewer vtputc's
  38.  *
  39.  * Revision 1.44  1992/07/18  13:13:56  foxharp
  40.  * put all path-shortening in one place (shorten_path()), and took out
  41.  * some old code now unnecessary
  42.  *
  43.  * Revision 1.43  1992/07/13  20:03:54  foxharp
  44.  * the "terse" variable is now a boolean mode
  45.  *
  46.  * Revision 1.42  1992/07/13  19:37:00  foxharp
  47.  * trim leading `pwd` from filenames in modeline, now that filenames are
  48.  * usually absolute
  49.  *
  50.  * Revision 1.41  1992/07/01  16:59:46  foxharp
  51.  * scwrite() arg changes, and some fore/background color cleanup
  52.  *
  53.  * Revision 1.40  1992/06/26  22:21:05  foxharp
  54.  * small almost cosmetic changes to mlsav'ing
  55.  *
  56.  * Revision 1.39  1992/05/29  08:36:06  foxharp
  57.  * moved the SVR3_PTEM ifdef so it works with POSIX too
  58.  *
  59.  * Revision 1.38  1992/05/19  08:55:44  foxharp
  60.  * more prototype and shadowed decl fixups
  61.  *
  62.  * Revision 1.37  1992/05/16  12:00:31  pgf
  63.  * prototypes/ansi/void-int stuff/microsoftC
  64.  *
  65.  * Revision 1.36  1992/04/27  19:50:43  pgf
  66.  * fixed ifdefs on termio inclusion
  67.  *
  68.  * Revision 1.35  1992/04/14  08:50:01  pgf
  69.  * fix SIGWINCH handling for X11 case
  70.  *
  71.  * Revision 1.34  1992/03/25  19:13:17  pgf
  72.  * BSD portability changes
  73.  *
  74.  * Revision 1.33  1992/03/19  23:31:54  pgf
  75.  * mlputc now converts tabs to single spaces, since we don't really
  76.  * know how wide they should be anyway
  77.  *
  78.  * Revision 1.32  1992/03/19  23:13:04  pgf
  79.  * SIGT for signals
  80.  *
  81.  * Revision 1.31  1992/03/07  10:21:29  pgf
  82.  * suppress prompts (mlprompt()) if execing buff or file
  83.  *
  84.  * Revision 1.30  1992/03/05  09:17:21  pgf
  85.  * added support for new "terse" variable, to control unnecessary messages
  86.  *
  87.  * Revision 1.29  1992/03/01  18:38:40  pgf
  88.  * compilation error #if COLOR
  89.  *
  90.  * Revision 1.28  1992/02/17  08:57:36  pgf
  91.  * added "showmode" support
  92.  *
  93.  * Revision 1.27  1992/01/22  20:26:00  pgf
  94.  * fixed ifdef conflict: SVR3_PTEM
  95.  *
  96.  * Revision 1.26  1992/01/05  00:05:24  pgf
  97.  * split mlwrite into mlwrite/mlprompt/mlforce to make errors visible more
  98.  * often.  also normalized message appearance somewhat.
  99.  *
  100.  * Revision 1.25  1991/11/13  20:09:27  pgf
  101.  * X11 changes, from dave lemke
  102.  *
  103.  * Revision 1.24  1991/11/08  13:14:40  pgf
  104.  * more lint
  105.  *
  106.  * Revision 1.23  1991/11/07  03:58:31  pgf
  107.  * lint cleanup
  108.  *
  109.  * Revision 1.22  1991/11/03  17:35:06  pgf
  110.  * don't access unset vt column 80 if screen isn't that wide
  111.  *
  112.  * Revision 1.21  1991/11/01  14:38:00  pgf
  113.  * saber cleanup
  114.  *
  115.  * Revision 1.20  1991/10/28  14:22:46  pgf
  116.  * no more TABVAL macro, curtabstopval renamed curtabval
  117.  *
  118.  * Revision 1.19  1991/10/26  00:14:56  pgf
  119.  * put termio.h back in, and switch to SVR3 around ptem.h
  120.  *
  121.  * Revision 1.18  1991/10/23  12:05:37  pgf
  122.  * we don't need termio.h
  123.  *
  124.  * Revision 1.17  1991/10/08  01:28:43  pgf
  125.  * dbgwrite now uses raw'est i/o
  126.  *
  127.  * Revision 1.16  1991/09/26  13:16:19  pgf
  128.  * LIST mode and w_sideways are now both window values
  129.  *
  130.  * Revision 1.15  1991/09/11  02:30:22  pgf
  131.  * use get_recorded_char, now that we have it
  132.  *
  133.  * Revision 1.14  1991/08/16  11:10:46  pgf
  134.  * added insert mode indicator to modeline: I for insert, O for overwrite, and
  135.  * R for replace-char
  136.  *
  137.  * Revision 1.13  1991/08/07  12:35:07  pgf
  138.  * added RCS log messages
  139.  *
  140.  * revision 1.12
  141.  * date: 1991/08/06 15:12:29;
  142.  * global/local values, and printf/list changes
  143.  * 
  144.  * revision 1.11
  145.  * date: 1991/06/28 10:53:18;
  146.  * make update quit early if !curbp
  147.  * 
  148.  * revision 1.10
  149.  * date: 1991/06/25 19:52:13;
  150.  * massive data structure restructure
  151.  * 
  152.  * revision 1.9
  153.  * date: 1991/06/16 17:34:57;
  154.  * switched to modulo tab calculations
  155.  * 
  156.  * revision 1.8
  157.  * date: 1991/05/31 10:35:55;
  158.  * added new "dbgwrite()" routine, for debugging
  159.  * 
  160.  * revision 1.7
  161.  * date: 1991/04/22 09:04:14;
  162.  * more ODT support
  163.  * 
  164.  * revision 1.6
  165.  * date: 1991/03/19 12:15:08;
  166.  * fix flag checking
  167.  * 
  168.  * revision 1.5
  169.  * date: 1991/02/21 10:04:01;
  170.  * horizontal scrolling is most of the way there.  only thing
  171.  * left to do is to extend lines where the cursor is beyond the
  172.  * left edge of a scrolled screen
  173.  * 
  174.  * revision 1.4
  175.  * date: 1990/10/05 14:19:31;
  176.  * fixed typo in ODT ifdef.
  177.  * propagated mode line changes to all windows holding a given buffer
  178.  * 
  179.  * revision 1.3
  180.  * date: 1990/10/01 11:04:42;
  181.  * atatus return in newscreensize
  182.  * 
  183.  * revision 1.2
  184.  * date: 1990/09/25 11:38:06;
  185.  * took out old ifdef BEFORE code
  186.  * 
  187.  * revision 1.1
  188.  * date: 1990/09/21 10:24:58;
  189.  * initial vile RCS revision
  190.  */
  191.  
  192.  
  193. #include    "estruct.h"
  194. #include        "edef.h"
  195. #if UNIX
  196. # include <signal.h>
  197. # if POSIX
  198. #  include <termios.h>
  199. # else
  200. #  if USG
  201. #   include <termio.h>
  202. #  else
  203. #   if BERK
  204. #    include "ioctl.h"
  205. #   endif
  206. #  endif
  207. # endif
  208. # if SVR3_PTEM
  209. #  include <sys/types.h>
  210. #  include <sys/stream.h>
  211. #  include <sys/ptem.h>
  212. # endif
  213. #endif
  214.  
  215.  
  216. VIDEO   **vscreen;                      /* Virtual screen. */
  217. #if    ! MEMMAP
  218. VIDEO   **pscreen;                      /* Physical screen. */
  219. #endif
  220.  
  221.  
  222. int displaying = FALSE;
  223. /* for window size changes */
  224. int chg_width, chg_height;
  225.  
  226. /*
  227.  * Initialize the data structures used by the display code. The edge vectors
  228.  * used to access the screens are set up. The operating system's terminal I/O
  229.  * channel is set up. All the other things get initialized at compile time.
  230.  * The original window has "WFCHG" set, so that it will get completely
  231.  * redrawn on the first call to "update".
  232.  */
  233. void
  234. vtinit()
  235. {
  236.     register int i;
  237.     register VIDEO *vp;
  238.  
  239.     TTopen();        /* open the screen */
  240.     TTkopen();        /* open the keyboard */
  241.     TTrev(FALSE);
  242.     vscreen = (VIDEO **) malloc(term.t_mrow*sizeof(VIDEO *));
  243.  
  244.     if (vscreen == NULL)
  245.         exit(1);
  246.  
  247.  
  248. #if    ! MEMMAP
  249.     pscreen = (VIDEO **) malloc(term.t_mrow*sizeof(VIDEO *));
  250.  
  251.     if (pscreen == NULL)
  252.         exit(1);
  253. #endif
  254.  
  255.     for (i = 0; i < term.t_mrow; ++i) {
  256.         /* struct VIDEO already has 4 of the bytes */
  257.         vp = (VIDEO *) malloc(sizeof(struct VIDEO) + term.t_mcol - 4);
  258.  
  259.         if (vp == NULL)
  260.             exit(1);
  261.  
  262.  
  263.     /* unnecessary */
  264.     /* (void)memset(vp, ' ', sizeof(struct VIDEO) + term.t_mcol - 4); */
  265.     vp->v_flag = 0;
  266. #if    COLOR
  267.     vp->v_rfcolor = gfcolor;
  268.     vp->v_rbcolor = gbcolor;
  269. #endif
  270.         vscreen[i] = vp;
  271. #if    ! MEMMAP
  272.         /* struct VIDEO already has 4 of the bytes */
  273.         vp = (VIDEO *) malloc(sizeof(struct VIDEO) + term.t_mcol - 4);
  274.  
  275.         if (vp == NULL)
  276.             exit(1);
  277.  
  278.     /* unnecessary */
  279.     /* (void)memset(vp, 0, sizeof(struct VIDEO) + term.t_mcol - 4); */
  280.  
  281.     vp->v_flag = 0;
  282.         pscreen[i] = vp;
  283. #endif
  284.         }
  285. }
  286.  
  287. /*
  288.  * Clean up the virtual terminal system, in anticipation for a return to the
  289.  * operating system. Move down to the last line and advance, to make room
  290.  * for the system prompt. Shut down the channel to the
  291.  * terminal.
  292.  */
  293. void
  294. vttidy(f)
  295. int f;
  296. {
  297.     ttclean(f);    /* does it all now */
  298. }
  299.  
  300. /*
  301.  * Set the virtual cursor to the specified row and column on the virtual
  302.  * screen. There is no checking for nonsense values.
  303.  */
  304. void
  305. vtmove(row, col)
  306. int row,col;
  307. {
  308.     vtrow = row;
  309.     vtcol = col;
  310. }
  311.  
  312. /* Write a character to the virtual screen. The virtual row and
  313.    column are updated. If we are not yet on left edge, don't print
  314.    it yet. If the line is too long put a ">" in the last column.
  315.    This routine only puts printing characters into the virtual
  316.    terminal buffers. Only column overflow is checked.
  317. */
  318.  
  319. void
  320. vtputc(c)
  321. int c;
  322. {
  323.     register VIDEO *vp;    /* ptr to line being updated */
  324.  
  325.     vp = vscreen[vtrow];
  326.  
  327.     if (isprint(c) && vtcol >= 0 && vtcol < term.t_ncol) {
  328.         vp->v_text[vtcol] = c;
  329.         ++vtcol;
  330.         return;
  331.     }
  332.     if (c == '\t') {
  333.         do {
  334.             vtputc(' ');
  335.         } while (((vtcol + taboff)%curtabval) != 0);
  336.     } else if (c == '\n') {
  337.         return;
  338.     } else if (vtcol >= term.t_ncol) {
  339.         ++vtcol;
  340.         vp->v_text[term.t_ncol - 1] = '>';
  341.     } else if (isprint(c)) {
  342.         ++vtcol;
  343.     } else {
  344.         vtputc('^');
  345.         vtputc(toalpha(c));
  346.     }
  347. }
  348.  
  349. /* as above, but tabs and newlines are made visible */
  350. void
  351. vtlistc(c)
  352. int c;
  353. {
  354.     register VIDEO *vp;    /* ptr to line being updated */
  355.  
  356.     vp = vscreen[vtrow];
  357.  
  358.     if (vtcol >= term.t_ncol) {
  359.         ++vtcol;
  360.         vp->v_text[term.t_ncol - 1] = '>';
  361.     } else if (isprint(c)) {
  362.         if (vtcol >= 0)
  363.             vp->v_text[vtcol] = c;
  364.         ++vtcol;
  365.     } else {
  366.         vtputc('^');
  367.         vtputc(toalpha(c));
  368.     }
  369. }
  370.  
  371. int
  372. vtgetc(col)
  373. int col;
  374. {
  375.     return vscreen[vtrow]->v_text[col];
  376. }
  377.  
  378. void
  379. vtputsn(s,n)
  380. char *s;
  381. int n;
  382. {
  383.     int c;
  384.     while (n-- && (c = *s++) != 0)
  385.         vtputc(c);
  386. }
  387.  
  388.  
  389. void
  390. vtset(lp,wp)
  391. LINE *lp;
  392. WINDOW *wp;
  393. {
  394.     register char *from;
  395.     register int n;
  396.  
  397.     from = lp->l_text;
  398.     n = llength(lp);
  399.  
  400.     if (w_val(wp,WMDLIST)) {
  401.         while (vtcol <= term.t_ncol && n)
  402.             vtlistc(*from++), n--;
  403.         if (!n)
  404.             vtlistc('\n');
  405.     } else {
  406.         while (vtcol <= term.t_ncol && n)
  407.             vtputc(*from++), n--;
  408.     }
  409. }
  410.  
  411. /* VARARGS1 */
  412. void
  413. #ifdef __STDC__
  414. vtprintf( char *fmt, ...)
  415. #else
  416. vtprintf(va_alist)
  417. va_dcl
  418. #endif
  419. {
  420.  
  421.     va_list ap;
  422. #ifdef __STDC__
  423.     va_start(ap,fmt);
  424. #else
  425.     va_start(ap);
  426. #endif
  427.  
  428.     dfoutfn = vtputc;
  429.  
  430. #ifdef __STDC__
  431.     dofmt(fmt,&ap);
  432. #else
  433.     dofmt(&ap);
  434. #endif
  435.     va_end(ap);
  436.  
  437.  
  438. /*
  439.  * Erase from the end of the software cursor to the end of the line on which
  440.  * the software cursor is located.
  441.  */
  442. void
  443. vteeol()
  444. {
  445.     if (vtcol < term.t_ncol) {
  446.         (void)memset(&vscreen[vtrow]->v_text[vtcol],
  447.             ' ', term.t_ncol-vtcol);
  448.         vtcol = term.t_ncol;
  449.     }
  450. }
  451.  
  452. /* upscreen:    user routine to force a screen update
  453.         always finishes complete update        */
  454. /* ARGSUSED */
  455. int
  456. upscreen(f, n)
  457. int f,n;
  458. {
  459.     update(TRUE);
  460.     return(TRUE);
  461. }
  462.  
  463. int scrflags;
  464. /*
  465.  * Make sure that the display is right. This is a three part process. First,
  466.  * scan through all of the windows looking for dirty ones. Check the framing,
  467.  * and refresh the screen. Second, make sure that "currow" and "curcol" are
  468.  * correct for the current window. Third, make the virtual and physical
  469.  * screens the same.
  470.  */
  471. int
  472. update(force)
  473. int force;    /* force update past type ahead? */
  474. {
  475.     register WINDOW *wp;
  476.     register int screencol;
  477.  
  478.     if (!curbp) /* not initialized */
  479.         return FALSE;
  480. #if    TYPEAH
  481.     if (force == FALSE && typahead())
  482.         return SORTOFTRUE;
  483. #endif
  484. #if    VISMAC == 0
  485.     if (force == FALSE && (get_recorded_char(FALSE) != -1))
  486.         return SORTOFTRUE;
  487. #endif
  488.  
  489.     displaying = TRUE;
  490.  
  491.     /* first, propagate mode line changes to all instances of
  492.         a buffer displayed in more than one window */
  493.     wp = wheadp;
  494.     while (wp != NULL) {
  495.         if (wp->w_flag & WFMODE) {
  496.             if (wp->w_bufp->b_nwnd > 1) {
  497.                 /* make sure all previous windows have this */
  498.                 register WINDOW *owp;
  499.                 owp = wheadp;
  500.                 while (owp != NULL) {
  501.                     if (owp->w_bufp == wp->w_bufp)
  502.                         owp->w_flag |= WFMODE;
  503.                     owp = owp->w_wndp;
  504.                 }
  505.             }
  506.         }
  507.         wp = wp->w_wndp;
  508.     }
  509.  
  510.     /* update any windows that need refreshing */
  511.     wp = wheadp;
  512.     while (wp != NULL) {
  513.         if (wp->w_flag) {
  514.             curtabval = tabstop_val(wp->w_bufp);
  515.             /* if the window has changed, service it */
  516.             reframe(wp);    /* check the framing */
  517.             if (wp->w_flag & (WFKILLS|WFINS)) {
  518.                 scrflags |= (wp->w_flag & (WFINS|WFKILLS));
  519.                 wp->w_flag &= ~(WFKILLS|WFINS);
  520.             }
  521.             if ((wp->w_flag & ~(/* WFMOVE| */WFMODE)) == WFEDIT)
  522.                 updone(wp);    /* update EDITed line */
  523.             else if (wp->w_flag & ~(WFMOVE))
  524.                 updall(wp);    /* update all lines */
  525.             if (scrflags || (wp->w_flag & WFMODE))
  526.                 modeline(wp);    /* update modeline */
  527.             wp->w_flag = 0;
  528.             wp->w_force = 0;
  529.         }
  530.         /* on to the next window */
  531.         wp = wp->w_wndp;
  532.     }
  533.     curtabval = tabstop_val(curbp);
  534.  
  535.     /* recalc the current hardware cursor location */
  536.     screencol = updpos();
  537.  
  538. #if    MEMMAP
  539.     /* update the cursor and flush the buffers */
  540.     /* movecursor(currow, screencol); */
  541. #endif
  542.  
  543.     /* check for lines to de-extend */
  544.     upddex();
  545.  
  546.     /* if screen is garbage, re-plot it */
  547.     if (sgarbf)
  548.         updgar();
  549.  
  550.     /* update the virtual screen to the physical screen */
  551.     updupd(force);
  552.  
  553.     /* update the cursor and flush the buffers */
  554.     movecursor(currow, screencol);
  555.     
  556.     TTflush();
  557.     displaying = FALSE;
  558.     while (chg_width || chg_height)
  559.         newscreensize(chg_height,chg_width);
  560.     return(TRUE);
  561. }
  562.  
  563. /*    reframe:    check to see if the cursor is on in the window
  564.             and re-frame it if needed or wanted        */
  565. void
  566. reframe(wp)
  567. WINDOW *wp;
  568. {
  569.     register LINE *lp;
  570.     register int i = 0;
  571.  
  572.     /* if not a requested reframe, check for a needed one */
  573.     if ((wp->w_flag & WFFORCE) == 0) {
  574. #if SCROLLCODE && ! MEMMAP
  575.         /* loop from one line above the window to one line after */
  576.         lp = lback(wp->w_line.l);
  577.         for (i = -1; i <= wp->w_ntrows; i++)
  578. #else
  579.         /* loop through the window */
  580.         lp = wp->w_line.l;
  581.         for (i = 0; i < wp->w_ntrows; i++)
  582. #endif
  583.         {
  584.  
  585.             /* if the line is in the window, no reframe */
  586.             if (lp == wp->w_dot.l) {
  587. #if SCROLLCODE && ! MEMMAP
  588.                 /* if not _quite_ in, we'll reframe gently */
  589.                 if ( i < 0 || i == wp->w_ntrows) {
  590.                     /* if the terminal can't help, then
  591.                         we're simply outside */
  592.                     if (term.t_scroll == NULL)
  593.                         i = wp->w_force;
  594.                     break;
  595.                 }
  596. #endif
  597.                 return;
  598.             }
  599.  
  600.             /* if we are at the end of the file, reframe */
  601.             if (i >= 0 && lp == wp->w_bufp->b_line.l)
  602.                 break;
  603.  
  604.             /* on to the next line */
  605.             lp = lforw(lp);
  606.         }
  607.     }
  608.  
  609. #if SCROLLCODE && ! MEMMAP
  610.     if (i == -1) {    /* we're just above the window */
  611.         i = 1;    /* put dot at first line */
  612.         scrflags |= WFINS;
  613.     } else if (i == wp->w_ntrows) { /* we're just below the window */
  614.         i = -1;    /* put dot at last line */
  615.         scrflags |= WFKILLS;
  616.     } else /* put dot where requested */
  617. #endif
  618.         i = wp->w_force;  /* (is 0, unless reposition() was called) */
  619.  
  620.     wp->w_flag |= WFMODE;
  621.     
  622.     /* w_force specifies which line of the window dot should end up on */
  623.     /*     positive --> lines from the top                */
  624.     /*     negative --> lines from the bottom            */
  625.     /*     zero --> middle of window                */
  626.     
  627.     /* enforce some maximums */
  628.     if (i > 0) {
  629.         if (--i >= wp->w_ntrows)
  630.             i = wp->w_ntrows - 1;
  631.     } else if (i < 0) {    /* negative update???? */
  632.         i += wp->w_ntrows;
  633.         if (i < 0)
  634.             i = 0;
  635.     } else
  636.         i = wp->w_ntrows / 2;
  637.  
  638.     /* backup to new line at top of window */
  639.     lp = wp->w_dot.l;
  640.     while (i != 0 && lback(lp) != wp->w_bufp->b_line.l) {
  641.         --i;
  642.         lp = lback(lp);
  643.     }
  644.  
  645.     if (lp == wp->w_bufp->b_line.l)
  646.         lp = lback(lp);
  647.         
  648.     /* and reset the current line-at-top-of-window */
  649.     wp->w_line.l = lp;
  650.     wp->w_flag |= WFHARD;
  651.     wp->w_flag &= ~WFFORCE;
  652. }
  653.  
  654. /*    updone:    update the current line    to the virtual screen        */
  655.  
  656. void
  657. updone(wp)
  658. WINDOW *wp;    /* window to update current line in */
  659. {
  660.     register LINE *lp;    /* line to update */
  661.     register int sline;    /* physical screen line to update */
  662.  
  663.     /* search down the line we want */
  664.     lp = wp->w_line.l;
  665.     sline = wp->w_toprow;
  666.     while (lp != wp->w_dot.l) {
  667.         ++sline;
  668.         lp = lforw(lp);
  669.     }
  670.  
  671.     l_to_vline(wp,lp,sline);
  672.     vteeol();
  673. }
  674.  
  675. /*    updall:    update all the lines in a window on the virtual screen */
  676.  
  677. void
  678. updall(wp)
  679. WINDOW *wp;    /* window to update lines in */
  680. {
  681.     register LINE *lp;    /* line to update */
  682.     register int sline;    /* physical screen line to update */
  683.  
  684.     /* search down the lines, updating them */
  685.     lp = wp->w_line.l;
  686.     sline = wp->w_toprow;
  687.     while (sline < wp->w_toprow + wp->w_ntrows) {
  688.         l_to_vline(wp,lp,sline);
  689.         vteeol();
  690.         if (lp != wp->w_bufp->b_line.l)
  691.             lp = lforw(lp);
  692.         ++sline;
  693.     }
  694.  
  695. }
  696.  
  697. /* line to virtual screen line */
  698. void
  699. l_to_vline(wp,lp,sline)
  700. WINDOW *wp;    /* window to update lines in */
  701. LINE *lp;
  702. int sline;
  703. {
  704.  
  705.     /* and update the virtual line */
  706.     vscreen[sline]->v_flag |= VFCHG;
  707.     vscreen[sline]->v_flag &= ~VFREQ;
  708.     if (w_val(wp,WVAL_SIDEWAYS))
  709.         taboff = w_val(wp,WVAL_SIDEWAYS);
  710.     if (lp != wp->w_bufp->b_line.l) {
  711.         vtmove(sline, -w_val(wp,WVAL_SIDEWAYS));
  712.         vtset(lp, wp);
  713.         if (w_val(wp,WVAL_SIDEWAYS)) {
  714.             vscreen[sline]->v_text[0] = '<';
  715.             if (vtcol < 1) vtcol = 1;
  716.         }
  717.     } else {
  718.         vtmove(sline, 0);
  719.         vtputc('~');
  720.     }
  721.     taboff = 0;
  722. #if    COLOR
  723.     vscreen[sline]->v_rfcolor = w_val(wp,WVAL_FCOLOR);
  724.     vscreen[sline]->v_rbcolor = w_val(wp,WVAL_BCOLOR);
  725. #endif
  726. }
  727.  
  728. /*    updpos:    update the position of the hardware cursor and handle extended
  729.         lines. This is the only update for simple moves.
  730.         returns the screen column for the cursor    */
  731. int
  732. updpos()
  733. {
  734.     register LINE *lp;
  735.     register int c;
  736.     register int i;
  737.  
  738.     /* find the current row */
  739.     lp = curwp->w_line.l;
  740.     currow = curwp->w_toprow;
  741.     while (lp != DOT.l) {
  742.         ++currow;
  743.         lp = lforw(lp);
  744.         if (lp == curwp->w_line.l) {
  745.             mlforce("BUG:  lost dot updpos().  setting at top");
  746.             curwp->w_line.l = DOT.l  = lforw(curbp->b_line.l);
  747.             currow = curwp->w_toprow;
  748.         }
  749.     }
  750.  
  751.     /* find the current column */
  752.     curcol = -w_val(curwp,WVAL_SIDEWAYS);
  753.     i = 0;
  754.     while (i < DOT.o) {
  755.         c = lgetc(lp, i++);
  756.         if (c == '\t' && !w_val(curwp,WMDLIST)) {
  757.             do {
  758.                 curcol++;
  759.             } while (((curcol +
  760.                 w_val(curwp,WVAL_SIDEWAYS))%curtabval) != 0);
  761.         } else {
  762.             if (!isprint(c))
  763.                 ++curcol;
  764.             ++curcol;
  765.         }
  766.  
  767.     }
  768.  
  769.     /* if extended, flag so and update the virtual line image */
  770.     if (curcol >=  term.t_ncol - 1) {
  771.         return updext_past();
  772.     } else if (w_val(curwp,WVAL_SIDEWAYS) && curcol < 1) {
  773.         return updext_before();
  774.     } else {
  775.         return curcol;
  776.     }
  777. }
  778.  
  779. /*    upddex:    de-extend any line that deserves it        */
  780.  
  781. void
  782. upddex()
  783. {
  784.     register WINDOW *wp;
  785.     register LINE *lp;
  786.     register int i;
  787.  
  788.     wp = wheadp;
  789.  
  790.     while (wp != NULL) {
  791.         lp = wp->w_line.l;
  792.         i = wp->w_toprow;
  793.  
  794.         curtabval = tabstop_val(wp->w_bufp);
  795.  
  796.         while (i < wp->w_toprow + wp->w_ntrows) {
  797.             if (vscreen[i]->v_flag & VFEXT) {
  798.                 if ((wp != curwp) || (lp != wp->w_dot.l) ||
  799.                    (curcol < term.t_ncol - 1)) {
  800.                     l_to_vline(wp,lp,i);
  801.                     vteeol();
  802.                     /* this line no longer is extended */
  803.                     vscreen[i]->v_flag &= ~VFEXT;
  804.                 }
  805.             }
  806.             lp = lforw(lp);
  807.             ++i;
  808.         }
  809.         /* and onward to the next window */
  810.         wp = wp->w_wndp;
  811.     }
  812.     curtabval = tabstop_val(curbp);
  813. }
  814.  
  815. /*    updgar:    if the screen is garbage, clear the physical screen and
  816.         the virtual screen and force a full update        */
  817.  
  818. extern char mlsave[];
  819.  
  820. void
  821. updgar()
  822. {
  823.     register char *txt;
  824.     register int i,j;
  825.  
  826.     for (i = 0; i < term.t_nrow; ++i) {
  827.         vscreen[i]->v_flag |= VFCHG;
  828. #if    REVSTA
  829.         vscreen[i]->v_flag &= ~VFREV;
  830. #endif
  831. #if    COLOR
  832.         vscreen[i]->v_fcolor = gfcolor;
  833.         vscreen[i]->v_bcolor = gbcolor;
  834. #endif
  835. #if    ! MEMMAP
  836.         txt = pscreen[i]->v_text;
  837.         for (j = 0; j < term.t_ncol; ++j)
  838.             txt[j] = ' ';
  839. #endif
  840.     }
  841.  
  842.     movecursor(0, 0);         /* Erase the screen. */
  843.     (*term.t_eeop)();
  844.     sgarbf = FALSE;             /* Erase-page clears */
  845.     mpresf = FALSE;             /* the message area. */
  846.     if (mlsave[0]) {
  847.         mlforce(mlsave);
  848.     }
  849. #if    COLOR
  850.     else
  851.         mlerase();        /* needs to be cleared if colored */
  852. #endif
  853. }
  854.  
  855. /*    updupd:    update the physical screen from the virtual screen    */
  856.  
  857. void
  858. updupd(force)
  859. int force;    /* forced update flag */
  860. {
  861.     register VIDEO *vp1;
  862.     register int i;
  863. #if SCROLLCODE && ! MEMMAP
  864.     if (scrflags & WFKILLS)
  865.         scrolls(FALSE);
  866.     if (scrflags & WFINS)
  867.         scrolls(TRUE);
  868.     scrflags = 0;
  869. #endif
  870.  
  871.     for (i = 0; i < term.t_nrow; ++i) {
  872.         vp1 = vscreen[i];
  873.  
  874.         /* for each line that needs to be updated*/
  875.         if ((vp1->v_flag & VFCHG) != 0) {
  876. #if    TYPEAH
  877.             if (force == FALSE && typahead())
  878.                 return;
  879. #endif
  880. #if    MEMMAP
  881.             updateline(i, vp1, vp1);
  882. #else
  883.             updateline(i, vp1, pscreen[i]);
  884. #endif
  885.         }
  886.     }
  887. }
  888.  
  889. #if SCROLLCODE && ! MEMMAP
  890. /* optimize out scrolls (line breaks, and newlines) */
  891. /* arg. chooses between looking for inserts or deletes */
  892. int    
  893. scrolls(inserts)    /* returns true if it does something */
  894. int inserts;
  895. {
  896.     struct    VIDEO *vpv ;    /* virtual screen image */
  897.     struct    VIDEO *vpp ;    /* physical screen image */
  898.     int    i, j, k ;
  899.     int    rows, cols ;
  900.     int    first, match, count, ptarget = 0, vtarget = 0, end ;
  901.     int    longmatch, longcount;
  902.     int    from, to;
  903.  
  904.     if (!term.t_scroll) /* no way to scroll */
  905.         return FALSE;
  906.  
  907.     rows = term.t_nrow ;
  908.     cols = term.t_ncol ;
  909.  
  910.     first = -1 ;
  911.     for (i = 0; i < rows; i++) {    /* find first wrong line */
  912.         if (!texttest(i,i)) {
  913.             first = i;
  914.             break;
  915.         }
  916.     }
  917.  
  918.     if (first < 0)
  919.         return FALSE;        /* no text changes */
  920.  
  921.     vpv = vscreen[first] ;
  922.     vpp = pscreen[first] ;
  923.  
  924.     if (inserts) {
  925.         /* determine types of potential scrolls */
  926.         end = endofline(vpv->v_text,cols) ;
  927.         if ( end == 0 )
  928.             ptarget = first ;        /* newlines */
  929.         else if ( strncmp(vpp->v_text, vpv->v_text, end) == 0 )
  930.             ptarget = first + 1 ;    /* broken line newlines */
  931.         else 
  932.             ptarget = first ;
  933.         from = ptarget;
  934.     } else {
  935.         from = vtarget = first + 1 ;
  936.     }
  937.  
  938.     /* find the matching shifted area */
  939.     longmatch = -1;
  940.     longcount = 0;
  941.     for (i = from+1; i < rows; i++) {
  942.         if (inserts ? texttest(i,from) : texttest(from,i) ) {
  943.             match = i ;
  944.             count = 1 ;
  945.             for (j=match+1, k=from+1; j<rows && k<rows; j++, k++) {
  946.                 if (inserts ? texttest(j,k) : texttest(k,j))
  947.                     count++ ;
  948.                 else
  949.                     break ;
  950.             }
  951.             if (longcount < count) {
  952.                 longcount = count;
  953.                 longmatch = match;
  954.             }
  955.         }
  956.     }
  957.     match = longmatch;
  958.     count = longcount;
  959.  
  960.     if (!inserts) {
  961.         /* full kill case? */
  962.         if (match > 0 && texttest(first, match-1)) {
  963.             vtarget-- ;
  964.             match-- ;
  965.             count++ ;
  966.         }
  967.     }
  968.  
  969.     /* do the scroll */
  970.     if (match>0 && count>2) {         /* got a scroll */
  971.         /* move the count lines starting at ptarget to match */
  972.         /* mlwrite("scrolls: move the %d lines starting at %d to %d",
  973.                         count,ptarget,match);
  974.         */
  975.         if (inserts) {
  976.             from = ptarget;
  977.             to = match;
  978.         } else {
  979.             from = match;
  980.             to = vtarget;
  981.         }
  982.         scrscroll(from, to, count) ;
  983.         for (i = 0; i < count; i++) {
  984.             vpp = pscreen[to+i] ;
  985.             vpv = vscreen[to+i];
  986.             strncpy(vpp->v_text, vpv->v_text, cols) ;
  987.         }
  988.         if (inserts) {
  989.             from = ptarget;
  990.             to = match;
  991.         } else {
  992.             from = vtarget+count;
  993.             to = match+count;
  994.         }
  995.         for (i = from; i < to; i++) {
  996.             char *txt;
  997.             txt = pscreen[i]->v_text;
  998.             for (j = 0; j < term.t_ncol; ++j)
  999.                 txt[j] = ' ';
  1000.             vscreen[i]->v_flag |= VFCHG;
  1001.         }
  1002.         return(TRUE) ;
  1003.     }
  1004.     return(FALSE) ;
  1005. }
  1006.  
  1007. /* move the "count" lines starting at "from" to "to" */
  1008. void
  1009. scrscroll(from, to, count)
  1010. int from, to, count;
  1011. {
  1012.     ttrow = ttcol = -1;
  1013.     (*term.t_scroll)(from,to,count);
  1014. }
  1015.  
  1016. int
  1017. texttest(vrow,prow)        /* return TRUE on text match */
  1018. int    vrow, prow ;        /* virtual, physical rows */
  1019. {
  1020.     struct    VIDEO *vpv = vscreen[vrow] ;    /* virtual screen image */
  1021.     struct    VIDEO *vpp = pscreen[prow]  ;    /* physical screen image */
  1022.  
  1023.     return (!memcmp(vpv->v_text, vpp->v_text, term.t_ncol)) ;
  1024. }
  1025.  
  1026. /* return the index of the first blank of trailing whitespace */
  1027. int    
  1028. endofline(s,n) 
  1029. char     *s;
  1030. int    n;
  1031. {
  1032.     int    i;
  1033.     for (i = n - 1; i >= 0; i--)
  1034.         if (s[i] != ' ') return(i+1) ;
  1035.     return(0) ;
  1036. }
  1037.  
  1038. #endif /* SCROLLCODE */
  1039.  
  1040.  
  1041. /*    updext_past: update the extended line which the cursor is currently
  1042.         on at a column greater than the terminal width. The line
  1043.         will be scrolled right or left to let the user see where
  1044.         the cursor is        */
  1045. int
  1046. updext_past()
  1047. {
  1048.     register int lbound, rcursor;
  1049.  
  1050.     /* calculate what column the real cursor will end up in */
  1051.     /* why is term.t_ncol in here? */
  1052.     rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
  1053.     lbound = curcol - rcursor;
  1054.     taboff = lbound + w_val(curwp,WVAL_SIDEWAYS);
  1055.  
  1056.     /* scan through the line outputing characters to the virtual screen */
  1057.     /* once we reach the left edge                    */
  1058.  
  1059.     /* start scanning offscreen */
  1060.     vtmove(currow, -lbound-w_val(curwp,WVAL_SIDEWAYS));
  1061.     vtset(DOT.l, curwp);
  1062.  
  1063.     /* truncate the virtual line, restore tab offset */
  1064.     vteeol();
  1065.     taboff = 0;
  1066.  
  1067.     /* and put a '<' in column 1 */
  1068.     vscreen[currow]->v_text[0] = '<';
  1069.     vscreen[currow]->v_flag |= (VFEXT | VFCHG);
  1070.     return rcursor;
  1071. }
  1072.  
  1073. /*    updext_before: update the extended line which the cursor is currently
  1074.         on at a column less than the terminal width. The line
  1075.         will be scrolled right or left to let the user see where
  1076.         the cursor is        */
  1077. int
  1078. updext_before()
  1079. {
  1080.     register int lbound, rcursor;
  1081.  
  1082.     /* calculate what column the real cursor will end up in */
  1083.     rcursor = (curcol % (term.t_ncol-term.t_margin));
  1084.     lbound = curcol - rcursor + 1;
  1085.     taboff = lbound;
  1086.  
  1087.     /* scan through the line outputing characters to the virtual screen */
  1088.     /* once we reach the left edge                    */
  1089.     vtmove(currow, -lbound);    /* start scanning offscreen */
  1090.     vtset(DOT.l, curwp);
  1091.  
  1092.     /* truncate the virtual line, restore tab offset */
  1093.     vteeol();
  1094.     taboff = 0;
  1095.  
  1096.     /* and put a '<' in column 1 */
  1097.     vscreen[currow]->v_text[0] = '<';
  1098.     vscreen[currow]->v_flag |= (VFEXT | VFCHG);
  1099.     return rcursor;
  1100. }
  1101.  
  1102.  
  1103.  
  1104. /*
  1105.  * Update a single line. This does not know how to use insert or delete
  1106.  * character sequences; we are using VT52 functionality. Update the physical
  1107.  * row and column variables. It does try an exploit erase to end of line. The
  1108.  * RAINBOW version of this routine uses fast video.
  1109.  */
  1110. #if    MEMMAP
  1111. /*    UPDATELINE specific code for the IBM-PC and other compatibles */
  1112.  
  1113. void
  1114. updateline(row, vp1, vpdummy)
  1115.  
  1116. int row;        /* row of screen to update */
  1117. struct VIDEO *vp1;    /* virtual screen image */
  1118. struct VIDEO *vpdummy;    /* virtual screen image */
  1119.  
  1120. {
  1121. #if    COLOR
  1122.     scwrite(row, 0, term.t_ncol-1,
  1123.         vp1->v_text, vp1->v_rfcolor, vp1->v_rbcolor);
  1124.     vp1->v_fcolor = vp1->v_rfcolor;
  1125.     vp1->v_bcolor = vp1->v_rbcolor;
  1126. #else
  1127.     if (vp1->v_flag & VFREQ)
  1128.         scwrite(row, 0, term.t_ncol-1, vp1->v_text, 0, 7);
  1129.     else
  1130.         scwrite(row, 0, term.t_ncol-1, vp1->v_text, 7, 0);
  1131. #endif
  1132.     vp1->v_flag &= ~(VFCHG | VFCOL);    /* flag this line as changed */
  1133.  
  1134. }
  1135.  
  1136. #else
  1137.  
  1138. void
  1139. updateline(row, vp1, vp2)
  1140.  
  1141. int row;        /* row of screen to update */
  1142. struct VIDEO *vp1;    /* virtual screen image */
  1143. struct VIDEO *vp2;    /* physical screen image */
  1144.  
  1145. {
  1146. #if RAINBOW
  1147. /*    UPDATELINE specific code for the DEC rainbow 100 micro    */
  1148.  
  1149.     register char *cp1;
  1150.     register char *cp2;
  1151.     register int nch;
  1152.  
  1153.     /* since we don't know how to make the rainbow do this, turn it off */
  1154.     flags &= (~VFREV & ~VFREQ);
  1155.  
  1156.     cp1 = &vp1->v_text[0];                    /* Use fast video. */
  1157.     cp2 = &vp2->v_text[0];
  1158.     putline(row+1, 1, cp1);
  1159.     nch = term.t_ncol;
  1160.  
  1161.     do
  1162.         {
  1163.         *cp2 = *cp1;
  1164.         ++cp2;
  1165.         ++cp1;
  1166.         }
  1167.     while (--nch);
  1168.     *flags &= ~VFCHG;
  1169. #else
  1170. /*    UPDATELINE code for all other versions        */
  1171.  
  1172.     register char *cp1;
  1173.     register char *cp2;
  1174.     register char *cp3;
  1175.     register char *cp4;
  1176.     register char *cp5;
  1177.     register int nbflag;    /* non-blanks to the right flag? */
  1178.     int rev;        /* reverse video flag */
  1179.     int req;        /* reverse video request flag */
  1180.  
  1181.  
  1182.     /* set up pointers to virtual and physical lines */
  1183.     cp1 = &vp1->v_text[0];
  1184.     cp2 = &vp2->v_text[0];
  1185.  
  1186. #if    COLOR
  1187.     TTforg(vp1->v_rfcolor);
  1188.     TTbacg(vp1->v_rbcolor);
  1189. #endif
  1190.  
  1191. #if    REVSTA | COLOR
  1192.     /* if we need to change the reverse video status of the
  1193.        current line, we need to re-write the entire line     */
  1194.     rev = (vp1->v_flag & VFREV) == VFREV;
  1195.     req = (vp1->v_flag & VFREQ) == VFREQ;
  1196.     if ((rev != req)
  1197. #if    COLOR
  1198.         || (vp1->v_fcolor != vp1->v_rfcolor) || (vp1->v_bcolor != vp1->v_rbcolor)
  1199. #endif
  1200. #if    HP150
  1201.     /* the HP150 has some reverse video problems */
  1202.         || req || rev
  1203. #endif
  1204.             ) {
  1205.         movecursor(row, 0);    /* Go to start of line. */
  1206.         /* set rev video if needed */
  1207.         if (rev != req)
  1208.             (*term.t_rev)(req);
  1209.  
  1210.         /* scan through the line and dump it to the screen and
  1211.            the virtual screen array                */
  1212.         cp3 = &vp1->v_text[term.t_ncol];
  1213. #if X11
  1214.         x_putline(row, cp1, cp3 - cp1);
  1215. #endif
  1216.         while (cp1 < cp3) {
  1217. #if !X11
  1218.             TTputc(*cp1);
  1219. #endif
  1220.             ++ttcol;
  1221.             *cp2++ = *cp1++;
  1222.         }
  1223.         /* turn rev video off */
  1224.         if (rev != req)
  1225.             (*term.t_rev)(FALSE);
  1226.  
  1227.         /* update the needed flags */
  1228.         vp1->v_flag &= ~VFCHG;
  1229.         if (req)
  1230.             vp1->v_flag |= VFREV;
  1231.         else
  1232.             vp1->v_flag &= ~VFREV;
  1233. #if    COLOR
  1234.         vp1->v_fcolor = vp1->v_rfcolor;
  1235.         vp1->v_bcolor = vp1->v_rbcolor;
  1236. #endif
  1237.         return;
  1238.     }
  1239. #endif
  1240.  
  1241.     /* advance past any common chars at the left */
  1242.     while (cp1 != &vp1->v_text[term.t_ncol] && *cp1 == *cp2) {
  1243.         ++cp1;
  1244.         ++cp2;
  1245.     }
  1246.  
  1247. /* This can still happen, even though we only call this routine on changed
  1248.  * lines. A hard update is always done when a line splits, a massive
  1249.  * change is done, or a buffer is displayed twice. This optimizes out most
  1250.  * of the excess updating. A lot of computes are used, but these tend to
  1251.  * be hard operations that do a lot of update, so I don't really care.
  1252.  */
  1253.     /* if both lines are the same, no update needs to be done */
  1254.     if (cp1 == &vp1->v_text[term.t_ncol]) {
  1255.          vp1->v_flag &= ~VFCHG;        /* flag this line is changed */
  1256.         return;
  1257.     }
  1258.  
  1259.     /* find out if there is a match on the right */
  1260.     nbflag = FALSE;
  1261.     cp3 = &vp1->v_text[term.t_ncol];
  1262.     cp4 = &vp2->v_text[term.t_ncol];
  1263.  
  1264.     while (cp3[-1] == cp4[-1]) {
  1265.         --cp3;
  1266.         --cp4;
  1267.         if (cp3[0] != ' ')        /* Note if any nonblank */
  1268.             nbflag = TRUE;        /* in right match. */
  1269.     }
  1270.  
  1271.     cp5 = cp3;
  1272.  
  1273.     /* Erase to EOL ? */
  1274.     if (nbflag == FALSE && eolexist == TRUE && (req != TRUE)) {
  1275.         while (cp5!=cp1 && cp5[-1]==' ')
  1276.             --cp5;
  1277.  
  1278.         if (cp3-cp5 <= 3)        /* Use only if erase is */
  1279.             cp5 = cp3;        /* fewer characters. */
  1280.     }
  1281.  
  1282.     movecursor(row, cp1 - &vp1->v_text[0]);    /* Go to start of line. */
  1283. #if    REVSTA
  1284.     TTrev(rev);
  1285. #endif
  1286.  
  1287. #if X11
  1288.     x_putline(row, cp1, cp5 - cp1 + 1);
  1289. #endif
  1290.     while (cp1 != cp5) {        /* Ordinary. */
  1291. #if !X11
  1292.         TTputc(*cp1);
  1293. #endif
  1294.         ++ttcol;
  1295.         *cp2++ = *cp1++;
  1296.     }
  1297.  
  1298.     if (cp5 != cp3) {        /* Erase. */
  1299.         TTeeol();
  1300.         while (cp1 != cp3)
  1301.             *cp2++ = *cp1++;
  1302.     }
  1303. #if    REVSTA
  1304.     TTrev(FALSE);
  1305. #endif
  1306.     vp1->v_flag &= ~VFCHG;        /* flag this line as updated */
  1307.     return;
  1308. #endif
  1309. }
  1310. #endif
  1311.  
  1312.  
  1313. /*
  1314.  * Redisplay the mode line for the window pointed to by the "wp". This is the
  1315.  * only routine that has any idea of how the modeline is formatted. You can
  1316.  * change the modeline format by hacking at this routine. Called by "update"
  1317.  * any time there is a dirty window.
  1318.  */
  1319. void
  1320. modeline(wp)
  1321. WINDOW *wp;
  1322. {
  1323.     register int n;
  1324.     register BUFFER *bp;
  1325.     register lchar;        /* character to draw line in buffer with */
  1326.  
  1327.     n = wp->w_toprow+wp->w_ntrows;          /* Location. */
  1328.     vscreen[n]->v_flag |= VFCHG | VFREQ | VFCOL;/* Redraw next time. */
  1329.  
  1330.  
  1331. #if    COLOR
  1332.     vscreen[n]->v_rfcolor = gbcolor;        /* black on */
  1333.     vscreen[n]->v_rbcolor = gfcolor;        /* white.....*/
  1334. #endif
  1335.     vtmove(n, 0);                           /* Seek to right line. */
  1336.     if (wp == curwp) {                /* mark the current buffer */
  1337.         lchar = '=';
  1338.     } else {
  1339. #if    REVSTA
  1340.         if (revexist)
  1341.             lchar = ' ';
  1342.         else
  1343. #endif
  1344.             lchar = '-';
  1345.     }
  1346.     bp = wp->w_bufp;
  1347.  
  1348.     vtputc(lchar);
  1349.     if (b_val(bp, MDSHOWMODE)) {
  1350.         register int ic;
  1351.         ic = lchar;
  1352.         if (wp == curwp) {
  1353.             if (insertmode == INSERT)
  1354.                 ic = 'I';
  1355.             else if (insertmode == REPLACECHAR)
  1356.                 ic = 'R';
  1357.             else if (insertmode == OVERWRITE)
  1358.                 ic = 'O';
  1359.         }
  1360.         vtputc(ic);
  1361.     }
  1362.     vtprintf("%c %s",lchar,bp->b_bname);
  1363.     if (b_val(bp,MDVIEW))
  1364.         vtputsn(" [view only]", 20);
  1365.     if (b_val(bp,MDDOS))
  1366.         vtputsn(" [dos-style]", 20);
  1367.     if (bp->b_flag&BFCHG)
  1368.         vtputsn(" [modified]", 20);
  1369.     if (bp->b_fname && bp->b_fname[0]) {
  1370.         char *p;
  1371.         p = shorten_path(bp->b_fname);
  1372.         if (p && strcmp(p,bp->b_bname) != 0) {
  1373.             if (!isspace(p[0])) {
  1374.                 vtprintf(" is ");
  1375. #if MSDOS
  1376.                 if (isupper(p[0]) && p[1] == ':') {
  1377.                     vtprintf("%c:",p[0]);
  1378.                     p += 2;
  1379.                 }
  1380. #endif
  1381.                 if (p[0] != slash &&
  1382.                     p[0] != '.' &&
  1383.                     p[0] != '!')
  1384.                     vtprintf(".%c",slash);
  1385.             }
  1386.             vtprintf("%s",p);
  1387.         }
  1388.     }
  1389.     vtputc(' ');
  1390.  
  1391.  
  1392.     /* Pad to full width, then go back and overwrite right-end info */
  1393.     n = term.t_ncol;
  1394.     while (vtcol < n)
  1395.         vtputc(lchar);
  1396.         
  1397.     { /* determine if top line, bottom line, or both are visible */
  1398.         LINE *lp = wp->w_line.l;
  1399.         int rows = wp->w_ntrows;
  1400.         char *msg = NULL;
  1401.         
  1402.         vtcol = n - 7;  /* strlen(" top ") plus a couple */
  1403.         while (rows--) {
  1404.             lp = lforw(lp);
  1405.             if (lp == wp->w_bufp->b_line.l) {
  1406.                 msg = " bot ";
  1407.                 break;
  1408.             }
  1409.         }
  1410.         if (lback(wp->w_line.l) == wp->w_bufp->b_line.l) {
  1411.             if (msg) {
  1412.                 if (wp->w_line.l == wp->w_bufp->b_line.l)
  1413.                     msg = " emp ";
  1414.                 else 
  1415.                     msg = " all ";
  1416.             } else {
  1417.                 msg = " top ";
  1418.             }
  1419.         }
  1420.         if (!msg)
  1421.             msg = " mid ";
  1422.         vtputsn(msg,20);
  1423.         vtputc(lchar);
  1424.         vtputc(lchar);
  1425.  
  1426.     }
  1427. #ifdef show_tabstop_on_modeline
  1428.     { /* put in the tabstop value */
  1429.         int t = tabstop_val(wp->w_bufp);
  1430.         vtcol = n - 11;
  1431.         while (t) {
  1432.             vtputc((t%10)+'0');
  1433.             t /= 10;
  1434.             vtcol -= 2;
  1435.         }
  1436.     }
  1437. #endif
  1438.  
  1439.     /* mark column 80 */
  1440.     if (n > 80 && vtgetc(80) == lchar) {
  1441.         vtcol = 80;
  1442.         vtputc('|');
  1443.     }
  1444. }
  1445.  
  1446. void
  1447. upmode()    /* update all the mode lines */
  1448. {
  1449.     register WINDOW *wp;
  1450.  
  1451.     wp = wheadp;
  1452.     while (wp != NULL) {
  1453.         wp->w_flag |= WFMODE;
  1454.         wp = wp->w_wndp;
  1455.     }
  1456. }
  1457.  
  1458. /*
  1459.  * Send a command to the terminal to move the hardware cursor to row "row"
  1460.  * and column "col". The row and column arguments are origin 0. Optimize out
  1461.  * random calls. Update "ttrow" and "ttcol".
  1462.  */
  1463. void
  1464. movecursor(row, col)
  1465. int row,col;
  1466. {
  1467.     if (row!=ttrow || col!=ttcol)
  1468.         {
  1469.             ttrow = row;
  1470.             ttcol = col;
  1471.             TTmove(row, col);
  1472.         }
  1473. }
  1474.  
  1475.  
  1476.  
  1477.  
  1478. /*
  1479.  * Erase the message line. This is a special routine because the message line
  1480.  * is not considered to be part of the virtual screen. It always works
  1481.  * immediately; the terminal buffer is flushed via a call to the flusher.
  1482.  */
  1483. void
  1484. mlerase()
  1485. {
  1486.     int i;
  1487.  
  1488.     if (mpresf == FALSE)
  1489.         return;
  1490.     movecursor(term.t_nrow, 0);
  1491.     if (discmd == FALSE)
  1492.         return;
  1493.  
  1494. #if    COLOR
  1495.      TTforg(gfcolor);
  1496.      TTbacg(gbcolor);
  1497. #endif
  1498.     if (eolexist == TRUE)
  1499.         TTeeol();
  1500.     else {
  1501.         for (i = 0; i < term.t_ncol - 1; i++)
  1502.             TTputc(' ');
  1503.         movecursor(term.t_nrow, 1);    /* force the move! */
  1504.         movecursor(term.t_nrow, 0);
  1505.     }
  1506.     TTflush();
  1507.     mpresf = FALSE;
  1508. }
  1509.  
  1510.  
  1511.  
  1512. #ifndef __STDC__
  1513.  
  1514. #ifndef va_dcl     /* then try these out */
  1515.  
  1516. typedef char *va_list;
  1517. #define va_dcl int va_alist;
  1518. #define va_start(list) list = (char *) &va_alist
  1519. #define va_end(list)
  1520. #define va_arg(list, mode) ((mode *)(list += sizeof(mode)))[-1]
  1521.  
  1522. #endif
  1523.  
  1524. #endif /* __STDC__ */
  1525.  
  1526. char *mlsavep;
  1527. char mlsave[NSTRING];
  1528.  
  1529. void
  1530. mlsavec(c)
  1531. int c;
  1532. {
  1533.     if (mlsavep - mlsave < NSTRING-1) {
  1534.         *mlsavep++ = c;
  1535.         *mlsavep = '\0';
  1536.     }
  1537.  
  1538. }
  1539.  
  1540. /*
  1541.  * Write a message into the message line only if appropriate.
  1542.  */
  1543. /* VARARGS1 */
  1544. void
  1545. #ifdef __STDC__
  1546. mlwrite( char *fmt, ...)
  1547. #else
  1548. mlwrite(va_alist)
  1549. va_dcl
  1550. #endif
  1551. {
  1552.     va_list ap;
  1553.     /* if we are not currently echoing on the command line, abort this */
  1554.     if (global_b_val(MDTERSE) || dotcmdmode == PLAY || discmd == FALSE) {
  1555.         movecursor(term.t_nrow, 0);
  1556.         return;
  1557.     }
  1558. #ifdef __STDC__
  1559.     va_start(ap,fmt);
  1560.     mlmsg(fmt,&ap);
  1561. #else
  1562.     va_start(ap);
  1563.     mlmsg(&ap);
  1564. #endif
  1565.     va_end(ap);
  1566. }
  1567.  
  1568. /*    Put a string out to the message line regardless of the
  1569.     current $discmd setting. This is needed when $debug is TRUE
  1570.     and for the write-message and clear-message-line commands
  1571.     Also used for most errors, to be sure they're seen.
  1572. */
  1573. /* VARARGS1 */
  1574. void
  1575. #ifdef __STDC__
  1576. mlforce(char *fmt, ...)
  1577. #else
  1578. mlforce(va_alist)
  1579. va_dcl
  1580. #endif
  1581. {
  1582.     va_list ap;
  1583. #ifdef __STDC__
  1584.     va_start(ap,fmt);
  1585.     mlmsg(fmt,&ap);
  1586. #else
  1587.     va_start(ap);
  1588.     mlmsg(&ap);
  1589. #endif
  1590.     va_end(ap);
  1591. }
  1592.  
  1593. /* VARARGS1 */
  1594. void
  1595. #ifdef __STDC__
  1596. mlprompt( char *fmt, ...)
  1597. #else
  1598. mlprompt(va_alist)
  1599. va_dcl
  1600. #endif
  1601. {
  1602.     va_list ap;
  1603.     int osgarbf = sgarbf;
  1604.     if (discmd == FALSE) {
  1605.         movecursor(term.t_nrow, 0);
  1606.         return;
  1607.     }
  1608.     sgarbf = FALSE;
  1609. #ifdef __STDC__
  1610.     va_start(ap,fmt);
  1611.     mlmsg(fmt,&ap);
  1612. #else
  1613.     va_start(ap);
  1614.     mlmsg(&ap);
  1615. #endif
  1616.     va_end(ap);
  1617.     sgarbf = osgarbf;
  1618. }
  1619.  
  1620. /* VARARGS */
  1621. void
  1622. #ifdef __STDC__
  1623. dbgwrite( char *fmt, ...)
  1624. #else
  1625. dbgwrite(va_alist)
  1626. va_dcl
  1627. #endif
  1628. {
  1629.     va_list ap;    /* ptr to current data field */
  1630. #ifdef __STDC__
  1631.     va_start(ap,fmt);
  1632.     mlmsg(fmt,&ap);
  1633. #else
  1634.     va_start(ap);
  1635.     mlmsg(&ap);
  1636. #endif
  1637.     va_end(ap);
  1638.     TTgetc();
  1639. }
  1640.  
  1641. /*
  1642.  * Do the real message-line work.  Keep track of the physical cursor
  1643.  * position. A small class of printf like format items is handled.
  1644.  * Set the "message line" flag TRUE.
  1645.  */
  1646. void
  1647. #ifdef __STDC__
  1648. mlmsg( char *fmt, va_list *app)
  1649. #else
  1650. mlmsg(app)
  1651. va_list *app;    /* ptr to current data field */
  1652. #endif
  1653. {
  1654.  
  1655.     if (sgarbf) {
  1656.         /* then we'll lose the message on the next update(), so save it now */
  1657.         mlsavep = mlsave;
  1658.         dfoutfn = mlsavec;
  1659. #ifdef __STDC__
  1660.         dofmt(fmt,app);
  1661. #else
  1662.         dofmt(app);
  1663. #endif
  1664.         return;
  1665.     }
  1666.  
  1667. #if    COLOR
  1668.     /* set up the proper colors for the command line */
  1669.     TTforg(gfcolor);
  1670.     TTbacg(gbcolor);
  1671. #endif
  1672.  
  1673.     /* if we cannot erase to end-of-line, do it manually */
  1674.     if (eolexist == FALSE) {
  1675.         mlerase();
  1676.         TTflush();
  1677.     }
  1678.  
  1679.  
  1680.     movecursor(term.t_nrow, 0);
  1681.  
  1682.     dfoutfn = mlputc;
  1683. #ifdef __STDC__
  1684.     dofmt(fmt,app);
  1685. #else
  1686.     dofmt(app);
  1687. #endif
  1688.  
  1689.     /* if we can, erase to the end of screen */
  1690.     if (eolexist == TRUE)
  1691.         TTeeol();
  1692.     TTflush();
  1693.     mpresf = TRUE;
  1694.     mlsave[0] = '\0';
  1695.  
  1696. /*
  1697.  * Write out a character. Update the physical cursor position. This assumes that
  1698.  * the character has width "1"; if this is not the case
  1699.  * things will get screwed up a little.
  1700.  */
  1701. void
  1702. mlputc(c)
  1703. int c;
  1704. {
  1705.     if (c == '\r') ttcol = 0;
  1706.     if (c == '\t') c = ' ';
  1707.     if (ttcol < term.t_ncol-1) {
  1708.             TTputc(c);
  1709.             ++ttcol;
  1710.     }
  1711. }
  1712.  
  1713. /* 
  1714.  * Generic string formatter.  Takes printf-like args, and calls
  1715.  * the global function (*dfoutfn)(c) for each c
  1716.  */
  1717. void
  1718. #ifdef __STDC__
  1719. dofmt( char *fmt, va_list *app)
  1720. #else
  1721. dofmt(app)
  1722. va_list *app;
  1723. #endif
  1724. {
  1725. #ifndef __STDC__
  1726.     register char *fmt;
  1727. #endif
  1728.     register int c;        /* current char in format string */
  1729.     register int wid;
  1730.     register int n;
  1731.     register int nchars = 0;
  1732.     int islong;
  1733. #ifndef __STDC__
  1734.     fmt = va_arg(*app, char *);
  1735. #endif
  1736.     while ((c = *fmt++) != 0 ) {
  1737.         if (c != '%') {
  1738.             (*dfoutfn)(c);
  1739.             nchars++;
  1740.             continue;
  1741.         }
  1742.         c = *fmt++;
  1743.         wid = 0;
  1744.         islong = FALSE;
  1745.         if (c == '*') {
  1746.             wid = va_arg(*app,int);
  1747.             c = *fmt++;
  1748.         } else while (isdigit(c)) {
  1749.             wid = (wid * 10) + c - '0';
  1750.             c = *fmt++;
  1751.         }
  1752.         if (c == 'l') {
  1753.             islong = TRUE;
  1754.             c = *fmt++;
  1755.         }
  1756.         switch (c) {
  1757.             case '\0':
  1758.                 n = 0;
  1759.                 break;
  1760.             case 'c':
  1761.                 (*dfoutfn)(va_arg(*app,int));
  1762.                 n = 1;
  1763.                 break;
  1764.  
  1765.             case 'd':
  1766.                 if (!islong) {
  1767.                     n = dfputi(va_arg(*app,int), 10);
  1768.                     break;
  1769.                 }
  1770.                 /* fall through */
  1771.             case 'D':
  1772.                 n = dfputli(va_arg(*app,long), 10);
  1773.                 break;
  1774.  
  1775.             case 'o':
  1776.                 n = dfputi(va_arg(*app,int), 8);
  1777.                 break;
  1778.  
  1779.             case 'x':
  1780.                 if (!islong) {
  1781.                     n = dfputi(va_arg(*app,int), 16);
  1782.                     break;
  1783.                 }
  1784.                 /* fall through */
  1785.             case 'X':
  1786.                 n = dfputli(va_arg(*app,long), 16);
  1787.                 break;
  1788.  
  1789.             case 's':
  1790.                 n = dfputs(va_arg(*app,char *));
  1791.                 break;
  1792.  
  1793.             case 'S': /* use wid as max width */
  1794.                 n = dfputsn(va_arg(*app,char *),wid);
  1795.                 break;
  1796.  
  1797.             case 'f':
  1798.                 n = dfputf(va_arg(*app,int));
  1799.                 break;
  1800.  
  1801.             case 'P': /* output padding -- pads total output to
  1802.                     "wid" chars, using c as the pad char */
  1803.                 wid -= nchars;
  1804.                 /* fall through */
  1805.  
  1806.             case 'p': /* field padding -- puts out "wid"
  1807.                     copies of c */
  1808.                 n = 0;
  1809.                 c = va_arg(*app,int);
  1810.                 while (n < wid) {
  1811.                     (*dfoutfn)(c);
  1812.                     n++;
  1813.                 }
  1814.                 break;
  1815.  
  1816.  
  1817.             default:
  1818.                 (*dfoutfn)(c);
  1819.                 n = 1;
  1820.         }
  1821.         wid -= n;
  1822.         nchars += n;
  1823.         while (wid-- > 0) {
  1824.             (*dfoutfn)(' ');
  1825.             nchars++;
  1826.         }
  1827.     }
  1828.  
  1829. }
  1830.  
  1831. /*
  1832.  * Do format a string.
  1833.  */
  1834. int
  1835. dfputs(s)
  1836. char *s;
  1837. {
  1838.     register int c;
  1839.     register int l = 0;
  1840.  
  1841.     while ((c = *s++) != 0) {
  1842.             (*dfoutfn)(c);
  1843.         l++;
  1844.     }
  1845.     return l;
  1846. }
  1847.  
  1848. /* as above, but takes a count for s's length */
  1849. int
  1850. dfputsn(s,n)
  1851. char *s;
  1852. int n;
  1853. {
  1854.     register int c;
  1855.     register int l = 0;
  1856.     while ((c = *s++) != 0 && n-- != 0) {
  1857.             (*dfoutfn)(c);
  1858.         l++;
  1859.     }
  1860.     return l;
  1861. }
  1862.  
  1863. /*
  1864.  * Do format an integer, in the specified radix.
  1865.  */
  1866. int
  1867. dfputi(i, r)
  1868. int i,r;
  1869. {
  1870.     register int q;
  1871.     static char hexdigits[] = "0123456789ABCDEF";
  1872.  
  1873.     if (i < 0) {
  1874.         (*dfoutfn)('-');
  1875.         i = -i;
  1876.     return dfputi(i, r) + 1;
  1877.     }
  1878.  
  1879.     q = i/r;
  1880.  
  1881.     if (q != 0)
  1882.         q = dfputi(q, r);
  1883.  
  1884.     (*dfoutfn)(hexdigits[i%r]);
  1885.     return q + 1; /* number of digits printed */
  1886. }
  1887.  
  1888. /*
  1889.  * do the same except as a long integer.
  1890.  */
  1891. int
  1892. dfputli(l, r)
  1893. long l;
  1894. int r;
  1895. {
  1896.     register long q;
  1897.  
  1898.     if (l < 0) {
  1899.         l = -l;
  1900.         (*dfoutfn)('-');
  1901.     }
  1902.  
  1903.     q = l/r;
  1904.  
  1905.     if (q != 0)
  1906.         q = dfputli(q, r);
  1907.  
  1908.     (*dfoutfn)((int)(l%r)+'0');
  1909.     return q + 1;
  1910. }
  1911.  
  1912. /*
  1913.  *    Do format a scaled integer with two decimal places
  1914.  */
  1915. int
  1916. dfputf(s)
  1917. int s;    /* scaled integer to output */
  1918. {
  1919.     register int i;    /* integer portion of number */
  1920.     register int f;    /* fractional portion of number */
  1921.  
  1922.     /* break it up */
  1923.     i = s / 100;
  1924.     f = s % 100;
  1925.  
  1926.     /* send out the integer portion */
  1927.     i = dfputi(i, 10);
  1928.     (*dfoutfn)('.');
  1929.     (*dfoutfn)((f / 10) + '0');
  1930.     (*dfoutfn)((f % 10) + '0');
  1931.     return i + 3;
  1932. }    
  1933.  
  1934. /* 
  1935.  * Local sprintf -- similar to standard libc, but
  1936.  *  returns pointer to null character at end of buffer, so it can
  1937.  *  be called repeatedly, as in:
  1938.  *    cp = lsprintf(cp, fmt, args...);
  1939.  *
  1940.  */
  1941.  
  1942. char *lsp;
  1943.  
  1944. void
  1945. lspputc(c)
  1946. int c;
  1947. {
  1948.     *lsp++ = c;
  1949. }
  1950.  
  1951. /* VARARGS1 */
  1952. char *
  1953. #ifdef __STDC__
  1954. lsprintf( char *buf, char *fmt, ...)
  1955. #else
  1956. lsprintf(va_alist)
  1957. va_dcl
  1958. #endif
  1959. {
  1960.  
  1961.     va_list ap;
  1962. #ifdef __STDC__
  1963.     va_start(ap,fmt);
  1964. #else
  1965.     char *buf;
  1966.     va_start(ap);
  1967.     buf = va_arg(ap, char *);
  1968. #endif
  1969.  
  1970.     lsp = buf;
  1971.     dfoutfn = lspputc;
  1972.  
  1973. #ifdef __STDC__
  1974.     dofmt(fmt,&ap);
  1975. #else
  1976.     dofmt(&ap);
  1977. #endif
  1978.     va_end(ap);
  1979.  
  1980.     *lsp = '\0';
  1981.     return lsp;
  1982.  
  1983. static char *lsbuf;
  1984.  
  1985. void
  1986. lssetbuf(buf)
  1987. char *buf;
  1988. {
  1989.     lsbuf = buf;
  1990. }
  1991.  
  1992. /* VARARGS1 */
  1993. char *
  1994. #ifdef __STDC__
  1995. _lsprintf( char *fmt, ...)
  1996. #else
  1997. _lsprintf(va_alist)
  1998. va_dcl
  1999. #endif
  2000. {
  2001.  
  2002.     va_list ap;
  2003. #ifdef __STDC__
  2004.     va_start(ap,fmt);
  2005. #else
  2006.     va_start(ap);
  2007. #endif
  2008.  
  2009.     lsp = lsbuf;
  2010.     dfoutfn = lspputc;
  2011.  
  2012. #ifdef __STDC__
  2013.     dofmt(fmt,&ap);
  2014. #else
  2015.     dofmt(&ap);
  2016. #endif
  2017.     va_end(ap);
  2018.  
  2019.     *lsp = '\0';
  2020.     return lsp;
  2021.  
  2022. /*
  2023.  * Buffer printf -- like regular printf, but puts characters
  2024.  *    into the BUFFER.
  2025.  *
  2026.  */
  2027.  
  2028. void
  2029. bputc(c)
  2030. int c;
  2031. {
  2032.     if (c == '\n')
  2033.         lnewline();
  2034.     else
  2035.         linsert(1,c);
  2036. }
  2037.  
  2038. /* printf into curbp, at DOT */
  2039. /* VARARGS */
  2040. void
  2041. #ifdef __STDC__
  2042. bprintf( char *fmt, ...)
  2043. #else
  2044. bprintf(va_alist)
  2045. va_dcl
  2046. #endif
  2047. {
  2048.     va_list ap;
  2049.  
  2050.     dfoutfn = bputc;
  2051.  
  2052. #ifdef __STDC__
  2053.     va_start(ap,fmt);
  2054.     dofmt(fmt,&ap);
  2055. #else
  2056.     va_start(ap);
  2057.     dofmt(&ap);
  2058. #endif
  2059.     va_end(ap);
  2060.  
  2061.  
  2062. #if RAINBOW
  2063.  
  2064. putline(row, col, buf)
  2065. int row, col;
  2066. char buf[];
  2067. {
  2068.     int n;
  2069.  
  2070.     n = strlen(buf);
  2071.     if (col + n - 1 > term.t_ncol)
  2072.         n = term.t_ncol - col + 1;
  2073.     Put_Data(row, col, n, buf);
  2074. }
  2075. #endif
  2076.  
  2077. /* Get terminal size from system.
  2078.    Store number of lines into *heightp and width into *widthp.
  2079.    If zero or a negative number is stored, the value is not valid.  */
  2080.  
  2081. void
  2082. getscreensize (widthp, heightp)
  2083. int *widthp, *heightp;
  2084. {
  2085. #ifdef TIOCGWINSZ
  2086.     struct winsize size;
  2087.     *widthp = 0;
  2088.     *heightp = 0;
  2089.     if (ioctl (0, TIOCGWINSZ, &size) < 0)
  2090.         return;
  2091.     *widthp = size.ws_col;
  2092.     *heightp = size.ws_row;
  2093. #else
  2094.     *widthp = 0;
  2095.     *heightp = 0;
  2096. #endif
  2097. }
  2098.  
  2099. #if defined( SIGWINCH) && ! X11
  2100. SIGT
  2101. sizesignal (signo)
  2102. int signo;
  2103. {
  2104.     int w, h;
  2105.     extern int errno;
  2106.     int old_errno = errno;
  2107.  
  2108.     getscreensize (&w, &h);
  2109.  
  2110.     if ((h && h-1 != term.t_nrow) || (w && w != term.t_ncol))
  2111.         newscreensize(h, w);
  2112.  
  2113.     signal (SIGWINCH, sizesignal);
  2114.     errno = old_errno;
  2115.     SIGRET;
  2116. }
  2117. #endif
  2118.  
  2119. void
  2120. newscreensize (h, w)
  2121. int h, w;
  2122. {
  2123.     /* do the change later */
  2124.     if (displaying) {
  2125.         chg_width = w;
  2126.         chg_height = h;
  2127.         return;
  2128.     }
  2129.     chg_width = chg_height = 0;
  2130.     if (h - 1 < term.t_mrow)
  2131.         newlength(TRUE,h);
  2132.     if (w < term.t_mcol)
  2133.         newwidth(TRUE,w);
  2134.  
  2135.     update(TRUE);
  2136. }
  2137.  
  2138.