home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / program / d / elvis / Source / c / redraw < prev    next >
Encoding:
Text File  |  1989-12-31  |  17.4 KB  |  904 lines

  1. /* redraw.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    16820 SW Tallac Way
  6.  *    Beaverton, OR 97006
  7.  *    kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
  8.  */
  9.  
  10.  
  11. /* This file contains functions that draw text on the screen.  The major entry
  12.  * points are:
  13.  *    redrawrange()    - called from modify.c to give hints about what parts
  14.  *              of the screen need to be redrawn.
  15.  *    redraw()    - redraws the screen (or part of it) and positions
  16.  *              the cursor where it belongs.
  17.  *    idx2col()    - converts a markidx() value to a logical column number.
  18.  */
  19.  
  20. #include "vi.h"
  21.  
  22. /* This variable contains the line number that smartdrawtext() knows best */
  23. static long smartlno;
  24.  
  25. /* This function remebers where changes were made, so that the screen can be
  26.  * redraw in a more efficient manner.
  27.  */
  28. redrawrange(after, pre, post)
  29.     long    after;    /* lower bound of redrawafter */
  30.     long    pre;    /* upper bound of redrawpre */
  31.     long    post;    /* upper bound of redrawpost */
  32. {
  33.     long    l;
  34.  
  35.     if (after < redrawafter)
  36.         redrawafter = after;
  37.  
  38.     l = redrawpre - redrawpost + pre - post;
  39.     if (post > redrawpost)
  40.         redrawpost = post;
  41.     redrawpre = redrawpost + l;
  42. }
  43.  
  44.  
  45. /* This function is used in visual mode for drawing the screen (or just parts
  46.  * of the screen, if that's all thats needed).  It also takes care of
  47.  * scrolling.
  48.  */
  49. redraw(curs, inputting)
  50.     MARK    curs;        /* where to leave the screen's cursor */
  51.     int    inputting;    /* boolean: being called from input() ? */
  52. {
  53.     char        *text;        /* a line of text to display */
  54.     static long    chgs;        /* previous changes level */
  55.     long        l;
  56.     int        i;
  57.  
  58.     /* if curs == MARK_UNSET, then we should reset internal vars */
  59.     if (curs == MARK_UNSET)
  60.     {
  61.         if (topline < 1 || topline > nlines)
  62.         {
  63.             topline = 1L;
  64.         }
  65.         else
  66.         {
  67.             move(LINES - 1, 0);
  68.             clrtoeol();
  69.         }
  70.         leftcol = 0;
  71.         mustredraw = TRUE;
  72.         redrawafter = INFINITY;
  73.         redrawpre = 0L;
  74.         redrawpost = 0L;
  75.         chgs = 0;
  76.         smartlno = 0L;
  77.         return;
  78.     }
  79.  
  80.     /* figure out which column the cursor will be in */
  81.     l = markline(curs);
  82.     text = fetchline(l);
  83.     mark2phys(curs, text, inputting);
  84.  
  85.     /* adjust topline, if necessary, to get the cursor on the screen */
  86.     if (l >= topline && l <= botline)
  87.     {
  88.         /* it is on the screen already */
  89.  
  90.         /* if the file was changed but !mustredraw, then redraw line */
  91.         if (chgs != changes && !mustredraw)
  92.         {
  93.             smartdrawtext(text, l);
  94.         }
  95.     }
  96.     else if (l < topline && l > topline - LINES)
  97.     {
  98.         /* near top - scroll down */
  99.         if (!mustredraw && (SR || AL))
  100.         {
  101.             move(0,0);
  102.             while (l < topline)
  103.             {
  104.                 topline--;
  105.                 if (SR)
  106.                 {
  107.                     tputs(SR, 1, faddch);
  108.                 }
  109.                 else
  110.                 {
  111.                     insertln();
  112.                 }
  113.                 text = fetchline(topline);
  114.                 drawtext(text);
  115.                 tputs(UP, 1, faddch);
  116.             }
  117.  
  118.             /* blank out the last line */
  119.             move(LINES - 1, 0);
  120.             clrtoeol();
  121.         }
  122.         else
  123.         {
  124.             topline = l;
  125.             redrawafter = INFINITY;
  126.             redrawpre = 0L;
  127.             redrawpost = 0L;
  128.         }
  129.     }
  130.     else if (l > topline && l < botline + LINES)
  131.     {
  132.         /* near bottom -- scroll up */
  133.         if (!mustredraw
  134. #if 1
  135.          || redrawafter == redrawpre && redrawpre == botline && redrawpost == l
  136. #endif
  137.         )
  138.         {
  139.             move(LINES - 1,0);
  140.             clrtoeol();
  141.             while (l > botline)
  142.             {
  143.                 topline++; /* <-- also adjusts botline */
  144.                 text = fetchline(botline);
  145.                 drawtext(text);
  146.             }
  147.             mustredraw = FALSE;
  148.         }
  149.         else
  150.         {
  151.             topline = l - (LINES - 2);
  152.             redrawafter = INFINITY;
  153.             redrawpre = 0L;
  154.             redrawpost = 0L;
  155.         }
  156.     }
  157.     else
  158.     {
  159.         /* distant line - center it & force a redraw */
  160.         topline = l - (LINES / 2) - 1;
  161.         if (topline < 1)
  162.         {
  163.             topline = 1;
  164.         }
  165.         mustredraw = TRUE;
  166.         redrawafter = INFINITY;
  167.         redrawpre = 0L;
  168.         redrawpost = 0L;
  169.     }
  170.  
  171.     /* Now... do we really have to redraw? */
  172.     if (mustredraw)
  173.     {
  174.         /* If redrawfter (and friends) aren't set, assume we should
  175.          * redraw everything.
  176.          */
  177.         if (redrawafter == INFINITY)
  178.         {
  179.             redrawafter = 0L;
  180.             redrawpre = redrawpost = INFINITY;
  181.         }
  182.  
  183.         /* adjust smartlno to correspond with inserted/deleted lines */
  184.         if (smartlno >= redrawafter)
  185.         {
  186.             if (smartlno < redrawpre)
  187.             {
  188.                 smartlno = 0L;
  189.             }
  190.             else
  191.             {
  192.                 smartlno += (redrawpost - redrawpre);
  193.             }
  194.         }
  195.  
  196.         /* should we insert some lines into the screen? */
  197.         if (redrawpre < redrawpost && redrawpre <= botline)
  198.         {
  199.             /* lines were inserted into the file */
  200.  
  201.             /* decide where insertion should start */
  202.             if (redrawpre < topline)
  203.             {
  204.                 l = topline;
  205.             }
  206.             else
  207.             {
  208.                 l = redrawpre;
  209.             }
  210.  
  211.             /* insert the lines... maybe */
  212.             if (l + redrawpost - redrawpre > botline || !AL)
  213.             {
  214.                 /* Whoa!  a whole screen full - just redraw */
  215.                 redrawpre = redrawpost = INFINITY;
  216.             }
  217.             else
  218.             {
  219.                 /* really insert 'em */
  220.                 move((int)(l - topline), 0);
  221.                 for (i = redrawpost - redrawpre; i > 0; i--)
  222.                 {
  223.                     insertln();
  224.                 }
  225.  
  226.                 /* NOTE: the contents of those lines will be
  227.                  * drawn as part of the regular redraw loop.
  228.                  */
  229.  
  230.                 /* clear the last line */
  231.                 move(LINES - 1, 0);
  232.                 clrtoeol();
  233.             }
  234.         }
  235.  
  236.         /* do we want to delete some lines from the screen? */
  237.         if (redrawpre > redrawpost && redrawpost <= botline)
  238.         {
  239.             if (redrawpre > botline || !DL)
  240.             {
  241.                 redrawpost = redrawpre = INFINITY;
  242.             }
  243.             else /* we'd best delete some lines from the screen */
  244.             {
  245.                 /* clear the last line, so it doesn't look
  246.                  * ugly as it gets pulled up into the screen
  247.                  */
  248.                 move(LINES - 1, 0);
  249.                 clrtoeol();
  250.  
  251.                 /* delete the lines */
  252.                 move((int)(redrawpost - topline), 0);
  253.                  for (l = redrawpost;
  254.                      l < redrawpre && l <= botline;
  255.                      l++)
  256.                 {
  257.                     deleteln();
  258.                 }
  259.  
  260.                 /* draw the lines that are now newly visible
  261.                  * at the bottom of the screen
  262.                  */
  263.                 i = LINES - 1 + (redrawpost - redrawpre);
  264.                 move(i, 0);
  265.                 for (l = topline + i; l <= botline; l++)
  266.                 {
  267.                     /* clear this line */
  268.                     clrtoeol();
  269.  
  270.                     /* draw the line, or ~ for non-lines */
  271.                     if (l <= nlines)
  272.                     {
  273.                         text = fetchline(l);
  274.                         drawtext(text);
  275.                     }
  276.                     else
  277.                     {
  278.                         addstr("~\n");
  279.                     }
  280.                 }
  281.             }
  282.         }
  283.  
  284.         /* redraw the current line */
  285.         l = markline(curs);
  286.         pfetch(l);
  287.         smartdrawtext(ptext, l);
  288.  
  289.         /* decide where we should start redrawing from */
  290.         if (redrawafter < topline)
  291.         {
  292.             l = topline;
  293.         }
  294.         else
  295.         {
  296.             l = redrawafter;
  297.         }
  298.         move((int)(l - topline), 0);
  299.  
  300.         /* draw the other lines */
  301.         for (; l <= botline && l < redrawpost; l++)
  302.         {
  303.             /* handle the cursor's line later */
  304.             if (l == markline(cursor))
  305.             {
  306.                 qaddch('\n');
  307.                 continue;
  308.             }
  309.  
  310.             /* clear this line */
  311.             clrtoeol();
  312.  
  313.             /* draw the line, or ~ for non-lines */
  314.             if (l <= nlines)
  315.             {
  316.                 text = fetchline(l);
  317.                 drawtext(text);
  318.             }
  319.             else
  320.             {
  321.                 addstr("~\n");
  322.             }
  323.         }
  324.  
  325.         mustredraw = FALSE;
  326.     }
  327.  
  328.     /* force total (non-partial) redraw next time if not set */
  329.     redrawafter = INFINITY;
  330.     redrawpre = 0L;
  331.     redrawpost = 0L;
  332.  
  333.     /* move the cursor to where it belongs */
  334.     move((int)(markline(curs) - topline), physcol);
  335.     wqrefresh(stdscr);
  336.  
  337.     chgs = changes;
  338. }
  339.  
  340.  
  341. /* This function converts a MARK to a column number.  It doesn't automatically
  342.  * adjust for leftcol; that must be done by the calling function
  343.  */
  344. int idx2col(curs, text, inputting)
  345.     MARK        curs;    /* the line# & index# of the cursor */
  346.     register char    *text;    /* the text of the line, from fetchline */
  347.     int        inputting;    /* boolean: called from input() ? */
  348. {
  349.     static MARK    pcursor;/* previous cursor, for possible shortcut */
  350.     static MARK    pcol;    /* column number for pcol */
  351.     static long    chgs;    /* previous value of changes counter */
  352.     register int    col;    /* used to count column numbers */
  353.     register int    idx;    /* used to count down the index */
  354.     register int    i;
  355.  
  356.     /* for now, assume we have to start counting at the left edge */
  357.     col = 0;
  358.     idx = markidx(curs);
  359.  
  360.     /* if the file hasn't changed & line number is the same & it has no
  361.      * embedded character attribute strings, can we do shortcuts?
  362.      */
  363.     if (chgs == changes
  364.      && !((curs ^ pcursor) & ~(BLKSIZE - 1))
  365. #ifndef SET_NOCHARATTR
  366.      && !hasattr(markline(curs), text)
  367. #endif
  368.     )
  369.     {
  370.         /* no movement? */
  371.         if (curs == pcursor)
  372.         {
  373.             /* return the column of the char; for tabs, return its last column */
  374.             if (text[idx] == '\t' && !inputting)
  375.             {
  376.                 return pcol + *o_tabstop - (pcol % *o_tabstop) - 1;
  377.             }
  378.             else
  379.             {
  380.                 return pcol;
  381.             }
  382.         }
  383.  
  384.         /* movement to right? */
  385.         if (curs > pcursor)
  386.         {
  387.             /* start counting from previous place */
  388.             col = pcol;
  389.             idx = markidx(curs) - markidx(pcursor);
  390.             text += markidx(pcursor);
  391.         }
  392.     }
  393.  
  394.     /* count over to the char after the idx position */
  395.     while (idx > 0 && (i = *text)) /* yes, ASSIGNMENT! */
  396.     {
  397.         if (i == '\t')
  398.         {
  399.             col += *o_tabstop;
  400.             col -= col % *o_tabstop;
  401.         }
  402.         else if (i >= '\0' && i < ' ' || i == '\177')
  403.         {
  404.             col += 2;
  405.         }
  406. #ifndef SET_NOCHARATTR
  407.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  408.         {
  409.             text += 2; /* plus one more at bottom of loop */
  410.             idx -= 2;
  411.         }            
  412. #endif
  413.         else
  414.         {
  415.             col++;
  416.         }
  417.         text++;
  418.         idx--;
  419.     }
  420.  
  421.     /* save stuff to speed next call */
  422.     pcursor = curs;
  423.     pcol = col;
  424.     chgs = changes;
  425.  
  426.     /* return the column of the char; for tabs, return its last column */
  427.     if (*text == '\t' && !inputting)
  428.     {
  429.         return col + *o_tabstop - (col % *o_tabstop) - 1;
  430.     }
  431.     else
  432.     {
  433.         return col;
  434.     }
  435. }
  436.  
  437.  
  438. /* This function is similar to idx2col except that it takes care of sideways
  439.  * scrolling - for the given line, at least.
  440.  */
  441. mark2phys(m, text, inputting)
  442.     MARK    m;        /* a mark to convert */
  443.     char    *text;        /* the line that m refers to */
  444.     int    inputting;    /* boolean: caled from input() ? */
  445. {
  446.     int    i;
  447.  
  448.     i = idx2col(cursor, text, inputting);
  449.     while (i < leftcol)
  450.     {
  451.         leftcol -= *o_sidescroll;
  452.         mustredraw = TRUE;
  453.         redrawrange(1L, INFINITY, INFINITY);
  454.         qaddch('\r');
  455.         drawtext(text);
  456.     }
  457.     while (i > rightcol)
  458.     {
  459.         leftcol += *o_sidescroll;
  460.         mustredraw = TRUE;
  461.         redrawrange(1L, INFINITY, INFINITY);
  462.         qaddch('\r');
  463.         drawtext(text);
  464.     }
  465.     physcol = i - leftcol;
  466.     physrow = markline(m) - topline;
  467.  
  468.     return physcol;
  469. }
  470.  
  471. /* This function draws a single line of text on the screen.  The screen's
  472.  * cursor is assumed to be located at the leftmost column of the appropriate
  473.  * row.
  474.  */
  475. drawtext(text)
  476.     register char    *text;    /* the text to draw */
  477. {
  478.     register int    col;    /* column number */
  479.     register int    i;
  480.     register int    tabstop;    /* *o_tabstop */
  481.     register int    limitcol;    /* leftcol or leftcol + COLS */
  482.     int        abnormal;    /* boolean: charattr != A_NORMAL? */
  483.  
  484.     /* move some things into registers... */
  485.     limitcol = leftcol;
  486.     tabstop = *o_tabstop;
  487.     abnormal = FALSE;
  488.  
  489.     /* skip stuff that was scrolled off left edge */
  490.     for (col = 0;
  491.          (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
  492.          text++)
  493.     {
  494.         if (i == '\t')
  495.         {
  496.             col = col + tabstop - (col % tabstop);
  497.         }
  498.         else if (i >= 0 && i < ' ' || i == '\177')
  499.         {
  500.             col += 2;
  501.         }
  502. #ifndef SET_NOCHARATTR
  503.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  504.         {
  505.             text += 2; /* plus one more as part of "for" loop */
  506.  
  507.             /* since this attribute might carry over, we need it */
  508.             switch (*text)
  509.             {
  510.               case 'R':
  511.                 attrset(A_NORMAL);
  512.                 abnormal = FALSE;
  513.                 break;
  514.  
  515.               case 'B':
  516.                 attrset(A_BOLD);
  517.                 abnormal = TRUE;
  518.                 break;
  519.  
  520.               case 'U':
  521.                 attrset(A_UNDERLINE);
  522.                 abnormal = TRUE;
  523.                 break;
  524.  
  525.               case 'I':
  526.                 attrset(A_ALTCHARSET);
  527.                 abnormal = TRUE;
  528.                 break;
  529.             }
  530.         }
  531. #endif
  532.         else
  533.         {
  534.             col++;
  535.         }
  536.     }
  537.  
  538.     /* adjust for control char that was partially visible */
  539.     while (col > limitcol)
  540.     {
  541.         qaddch(' ');
  542.         limitcol++;
  543.     }
  544.  
  545.     /* now for the visible characters */
  546.     for (limitcol = leftcol + COLS;
  547.          (i = *text) && col < limitcol;
  548.          text++)
  549.     {
  550.         if (i == '\t')
  551.         {
  552.             i = col + tabstop - (col % tabstop);
  553.             if (i < limitcol)
  554.             {
  555.                 if (PT && !((i - leftcol) & 7))
  556.                 {
  557.                     do
  558.                     {
  559.                         qaddch('\t');
  560.                         col += 8; /* not exact! */
  561.                     } while (col < i);
  562.                     col = i; /* NOW it is exact */
  563.                 }
  564.                 else
  565.                 {
  566.                     do
  567.                     {
  568.                         qaddch(' ');
  569.                         col++;
  570.                     } while (col < i);
  571.                 }
  572.             }
  573.             else
  574.             {
  575.                 col = i;
  576.             }
  577.         }
  578.         else if (i >= 0 && i < ' ' || i == '\177')
  579.         {
  580.             col += 2;
  581.             if (col < limitcol)
  582.             {
  583.                 qaddch('^');
  584.                 qaddch(i ^ '@');
  585.             }
  586.         }
  587. #ifndef SET_NOCHARATTR
  588.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  589.         {
  590.             text += 2; /* plus one more as part of "for" loop */
  591.             switch (*text)
  592.             {
  593.               case 'R':
  594.                 attrset(A_NORMAL);
  595.                 abnormal = FALSE;
  596.                 break;
  597.  
  598.               case 'B':
  599.                 attrset(A_BOLD);
  600.                 abnormal = TRUE;
  601.                 break;
  602.  
  603.               case 'U':
  604.                 attrset(A_UNDERLINE);
  605.                 abnormal = TRUE;
  606.                 break;
  607.  
  608.               case 'I':
  609.                 attrset(A_ALTCHARSET);
  610.                 abnormal = TRUE;
  611.                 break;
  612.             }
  613.         }
  614. #endif
  615.         else
  616.         {
  617.             col++;
  618.             qaddch(i);
  619.         }
  620.     }
  621.  
  622. #ifndef SET_NOCHARATTR
  623.     /* get ready for the next line */
  624.     if (abnormal)
  625.     {
  626.         attrset(A_NORMAL);
  627.     }
  628. #endif
  629.     if (!AM || col < limitcol)
  630.     {
  631.         qaddch('\r');
  632.         qaddch('\n');
  633.     }
  634. }
  635.  
  636.  
  637. static nudgecursor(same, scan, new, lno)
  638.     int    same;    /* number of chars to be skipped over */
  639.     char    *scan;    /* where the same chars end */
  640.     char    *new;    /* where the visible part of the line starts */
  641.     long    lno;    /* line number of this line */
  642. {
  643.     if (same > 0)
  644.     {
  645.         if (same < 5)
  646.         {
  647.             /* move the cursor by overwriting */
  648.             while (same > 0)
  649.             {
  650.                 qaddch(scan[-same]);
  651.                 same--;
  652.             }
  653.         }
  654.         else
  655.         {
  656.             /* move the cursor by calling move() */
  657.             move((int)(lno - topline), (int)(scan - new));
  658.         }
  659.     }
  660. }
  661.  
  662. /* This function draws a single line of text on the screen, possibly with
  663.  * some cursor optimization.  The cursor is repositioned before drawing
  664.  * begins, so its position before doesn't really matter.
  665.  */
  666. smartdrawtext(text, lno)
  667.     register char    *text;    /* the text to draw */
  668.     long        lno;    /* line number of the text */
  669. {
  670.     static char    old[256];    /* how the line looked last time */
  671.     char        new[256];    /* how it looks now */
  672.     char        *build;        /* used to put chars into new[] */
  673.     char        *scan;        /* used for moving thru new[] or old[] */
  674.     char        *end;        /* last non-blank changed char */
  675.     char        *shift;        /* used to insert/delete chars */
  676.     int        same;        /* length of a run of unchanged chars */
  677.     int        limitcol;
  678.     int        col;
  679.     int        i;
  680.  
  681. #ifndef SET_NOCHARATTR
  682.     /* if this line has attributes, do it the dumb way instead */
  683.     if (hasattr(lno, text))
  684.     {
  685.         move((int)(lno - topline), 0);
  686.         clrtoeol();
  687.         drawtext(text);
  688.         return;
  689.     }
  690. #endif
  691.  
  692.     /* skip stuff that was scrolled off left edge */
  693.     limitcol = leftcol;
  694.     for (col = 0;
  695.          (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
  696.          text++)
  697.     {
  698.         if (i == '\t')
  699.         {
  700.             col = col + *o_tabstop - (col % *o_tabstop);
  701.         }
  702.         else if (i >= 0 && i < ' ' || i == '\177')
  703.         {
  704.             col += 2;
  705.         }
  706.         else
  707.         {
  708.             col++;
  709.         }
  710.     }
  711.  
  712.     /* adjust for control char that was partially visible */
  713.     build = new;
  714.     while (col > limitcol)
  715.     {
  716.         *build++ = ' ';
  717.         limitcol++;
  718.     }
  719.  
  720.     /* now for the visible characters */
  721.     for (limitcol = leftcol + COLS;
  722.          (i = *text) && col < limitcol;
  723.          text++)
  724.     {
  725.         if (i == '\t')
  726.         {
  727.             i = col + *o_tabstop - (col % *o_tabstop);
  728.             while (col < i && col < limitcol)
  729.             {
  730.                 *build++ = ' ';
  731.                 col++;
  732.             }
  733.         }
  734.         else if (i >= 0 && i < ' ' || i == '\177')
  735.         {
  736.             col += 2;
  737.             *build++ = '^';
  738.             if (col < limitcol)
  739.             {
  740.                 *build++ = (i ^ '@');
  741.             }
  742.         }
  743.         else
  744.         {
  745.             col++;
  746.             *build++ = i;
  747.         }
  748.     }
  749.     end = build;
  750.     while (col < limitcol)
  751.     {
  752.         *build++ = ' ';
  753.         col++;
  754.     }
  755.  
  756.     /* locate the last non-blank character */
  757.     while (end > new && end[-1] == ' ')
  758.     {
  759.         end--;
  760.     }
  761.  
  762.     /* can we optimize the displaying of this line? */
  763.     if (lno != smartlno)
  764.     {
  765.         /* nope, can't optimize - different line */
  766.         move((int)(lno - topline), 0);
  767.         for (scan = new, build = old; scan < end; )
  768.         {
  769.             qaddch(*scan);
  770.             *build++ = *scan++;
  771.         }
  772.         if (end < new + COLS)
  773.         {
  774.             clrtoeol();
  775.             while (build < old + COLS)
  776.             {
  777.                 *build++ = ' ';
  778.             }
  779.         }
  780.         smartlno = lno;
  781.         return;
  782.     }
  783.  
  784.     /* skip any initial unchanged characters */
  785.     for (scan = new, build = old; scan < end && *scan == *build; scan++, build++)
  786.     {
  787.     }
  788.     move((int)(lno - topline), (int)(scan - new));
  789.  
  790.     /* The in-between characters must be changed */
  791.     same = 0;
  792.     while (scan < end)
  793.     {
  794.         /* is this character a match? */
  795.         if (scan[0] == build[0])
  796.         {
  797.             same++;
  798.         }
  799.         else /* do we want to insert? */
  800.         if (scan < end - 1 && scan[1] == build[0] && (*IC || IM))
  801.         {
  802.             nudgecursor(same, scan, new, lno);
  803.             same = 0;
  804.  
  805.             insch(*scan);
  806.             for (shift = old + COLS; --shift > build; )
  807.             {
  808.                 shift[0] = shift[-1];
  809.             }
  810.             *build = *scan;
  811.         }
  812.         else /* do we want to delete? */
  813.         if (build < old + COLS - 1 && scan[0] == build[1] && DC)
  814.         {
  815.             nudgecursor(same, scan, new, lno);
  816.             same = 0;
  817.  
  818.             delch();
  819.             same++;
  820.             for (shift = build; shift < old + COLS - 1; shift++)
  821.             {
  822.                 shift[0] = shift[1];
  823.             }
  824.             *shift = ' ';
  825.         }
  826.         else /* we must overwrite */
  827.         {
  828.             nudgecursor(same, scan, new, lno);
  829.             same = 0;
  830.  
  831.             addch(*scan);
  832.             *build = *scan;
  833.         }
  834.  
  835.         build++;
  836.         scan++;
  837.     }
  838.  
  839.     /* maybe clear to EOL */
  840.     while (build < old + COLS && *build == ' ')
  841.     {
  842.         build++;
  843.     }
  844.     if (build < old + COLS)
  845.     {
  846.         nudgecursor(same, scan, new, lno);
  847.         same = 0;
  848.  
  849.         clrtoeol();
  850.         while (build < old + COLS)
  851.         {
  852.             *build++ = ' ';
  853.         }
  854.     }
  855. }
  856.  
  857.  
  858. #ifndef SET_NOCHARATTR
  859. /* see if a given line uses character attribute strings */
  860. int hasattr(lno, text)
  861.     long        lno;    /* the line# of the cursor */
  862.     register char    *text;    /* the text of the line, from fetchline */
  863. {
  864.     static long    plno;    /* previous line number */
  865.     static long    chgs;    /* previous value of changes counter */
  866.     static int    panswer;/* previous answer */
  867.     char        *scan;
  868.  
  869.     /* if charattr is off, then the answer is "no, it doesn't" */
  870.     if (!*o_charattr)
  871.     {
  872.         chgs = 0; /* <- forces us to check if charattr is later set */
  873.         return FALSE;
  874.     }
  875.  
  876.     /* if we already know the answer, return it... */
  877.     if (lno == plno && chgs == changes)
  878.     {
  879.         return panswer;
  880.     }
  881.  
  882.     /* get the line & look for "\fX" */
  883.     pfetch(lno);
  884.     if (plen < 3)
  885.     {
  886.         panswer = FALSE;
  887.     }
  888.     else
  889.     {
  890.         for (scan = ptext; scan[2] && !(scan[0] == '\\' && scan[1] == 'f'); scan++)
  891.         {
  892.         }
  893.         panswer = (scan[2] != '\0');
  894.     }
  895.  
  896.     /* save the results */
  897.     plno = lno;
  898.     chgs = changes;
  899.  
  900.     /* return the results */
  901.     return panswer;
  902. }
  903. #endif
  904.