home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Commun⁄Network / Telnet 2.5.src.ThinkC / source / junkk < prev    next >
Encoding:
Text File  |  1991-06-27  |  30.7 KB  |  1,304 lines  |  [TEXT/MPS ]

  1. #ifdef lint
  2. static char *SCCSid = "%W%    (NCSA)    %G%";
  3. #endif
  4.  
  5. /*
  6.  *
  7.  *      Virtual Screen Kernel Internal Routines
  8.  *                      (vsintern.c)
  9.  *  National Center for Supercomputing Applications
  10.  *
  11.  *      by Gaige B. Paulsen
  12.  *
  13.  *    This file contains the private internal calls for the NCSA
  14.  *  Virtual Screen Kernel.
  15.  *
  16.  *        Version Date    Notes
  17.  *        ------- ------  ---------------------------------------------------
  18.  *        0.01    861102  Initial coding -GBP
  19.  *        0.50    861113  First compiled edition -GBP
  20.  *        0.70    861114  Internal operation confirmed -GBP
  21.  *        2.1        871130    NCSA Telnet 2.1 -GBP
  22.  *        2.2     880715    NCSA Telnet 2.2 -GBP
  23.  */
  24.  
  25. #include <String.h>
  26. #include <Quickdraw.h>
  27. #include <Controls.h>
  28. #include <Memory.h>
  29. #include "vsdata.h"
  30. #include "vskeys.h"
  31. #include "vsinterf.h"
  32. #include "rsmac.h"
  33.  
  34. #define ScrollbackQuantum 100
  35.  
  36. #define VSIclrattrib 0
  37.  
  38. int VSIclip
  39.   (
  40.      int *x1, /* starting column */
  41.      int *y1, /* line on which to draw (assumed to lie within visible region) */
  42.      int *x2, /* ending column (inclusive) (output if *n >= 0) */
  43.      int *y2, /* ending line (inclusive) (output if *n >= 0) */
  44.      int *n, /* length of text to draw (input and output) */
  45.      int *offset /* length of initial part of text to skip (output) */
  46.   )
  47.   /* clips a text string to the visible region, given the starting
  48.     line and column in screen coordinates at which it is to be drawn.
  49.     If the length of the string is given, will also compute the ending
  50.     line and column. On return, these coordinates will be normalized
  51.     to the current visible region. Returns a nonzero function result
  52.     iff the string is completely invisible. */
  53.   {
  54.     if (*n >= 0)
  55.       {
  56.       /* compute ending line and column (inclusive) */
  57.         *x2 = *x1 + *n - 1;
  58.         *y2 = *y1;
  59.       }
  60.   /* else take these as given */
  61.  
  62.     if ((*x1 > VSIw->Rright) || (*y2 < VSIw->Rtop))
  63.         return (-1); /* nothing to draw */
  64.  
  65.     if (*x2 > VSIw->Rright)
  66.         *x2 = VSIw->Rright;
  67.     if (*y2 > VSIw->Rbottom)
  68.         *y2 = VSIw->Rbottom;
  69.   /* normalize x1, x2, y1, y2 to be relative to current visible region */
  70.     *x1 -= VSIw->Rleft;
  71.     *x2 -= VSIw->Rleft;
  72.     *y1 -= VSIw->Rtop;
  73.     *y2 -= VSIw->Rtop;
  74.   /* clip part of text string lying outside region, if any */
  75.     *offset = - *x1;
  76.     if (*offset < 0)
  77.         *offset = 0; /* text string starts within region--nothing to clip */
  78.   /* don't draw anything outside region */
  79.     if (*x1 < 0)
  80.         *x1 = 0;
  81.     if (*y1 < 0)
  82.         *y1 = 0;
  83.  
  84.     *n = *x2 - *x1 + 1; /* length of string to draw (assuming it's all on one line) */
  85.     if ((*n <= 0) || (*y2 - *y1 < 0))
  86.         return (-1); /* nothing to draw */
  87.     return (0);
  88.   } /* VSIclip */
  89.  
  90. VSIcdellines(w, top, bottom, n, scrolled)
  91.     int
  92.         w, /* affected window */
  93.         top, /* where to start deleting from */
  94.         bottom, /* bottom line of region to scroll */
  95.         n, /* number of lines to delete */
  96.         scrolled;
  97.           /*
  98.             -ve => cancel current selection, if any;
  99.             +ve => selection has moved up one line;
  100.             0 => don't touch selection
  101.           */
  102.   /* updates the display to indicate deletion of the specified
  103.     number of lines from the top of the specified region.
  104.     Returns 0 iff any part of the change is visible. */
  105.   {
  106.     int
  107.         x1 = 0,
  108.         x2 = VSIw->maxwidth,
  109.         tn = -1,
  110.         offset;
  111.  
  112.     if (VSIclip(&x1, &top, &x2, &bottom, &tn, &offset))
  113.         return(-1); /* affected region is invisible */
  114.     tn = bottom - top;
  115.     if (tn < n)
  116.         n = tn; /* don't bother scrolling more lines than scrolling region holds */
  117.     RSdellines(w, top, bottom, n, scrolled);
  118.     return(0);                /* I delete the whole thing! */
  119.   } /* VSIcdellines */
  120.  
  121. VSIcinslines(w, top, bottom, n,scrolled)
  122.     int
  123.         w, /* affected window */
  124.         top, /* where to insert blank lines */
  125.         bottom, /* bottom of area to scroll */
  126.         n, /* number of lines to insert */
  127.         scrolled; /* -ve <=> cancel current selection, if any */
  128.   /* updates the display to indicate insertion of the specified
  129.     number of blank lines at the top of the specified region.
  130.     Returns 0 iff any part of the change is visible. */
  131.   {
  132.     int
  133.         x1 = 0,
  134.         x2 = VSIw->maxwidth,
  135.         tn = -1,
  136.         offset;
  137.  
  138.     if (VSIclip(&x1, &top, &x2, &bottom, &tn, &offset))
  139.         return -1; /* affected region is invisible */
  140.     tn = bottom - top;
  141.     if (tn < n)
  142.         n = tn; /* don't bother scrolling more lines than scrolling region holds */
  143.     RSinslines(w, top, bottom, n, scrolled);
  144.     return 0;
  145.   } /* VSIcinslines */
  146.  
  147. void VSIcurson
  148.   (
  149.     int w,
  150.     int x,
  151.     int y,
  152.     int ForceMove
  153.   )
  154.   /* displays the text cursor at the specified position. If
  155.     ForceMove is true, I am to do any appropriate scrolling of
  156.     the display to ensure the cursor is within the visible region.
  157.     Assumes cursor isn't currently being shown. */
  158.   {
  159.     int
  160.         x2,
  161.         y2,
  162.         n = 1,
  163.         offset;
  164.  
  165.     if (!VSIclip(&x, &y, &x2, &y2, &n, &offset))
  166.       /* cursor already lies within visible region */
  167.         RScurson(w, x, y); /* just make it visible */
  168.     else if (ForceMove)
  169.       {
  170.       /* scroll to make cursor visible */
  171.         x2 = VSIw->Rbottom - VSIw->Rtop;
  172.         if (x2 >= VSIw->lines)
  173.           /* visible region is big enough to show entire screen--
  174.             make sure I don't scroll off the bottom of the screen.
  175.             This call will also do any appropriate scrolling and
  176.             redisplaying of the cursor. */
  177.             VSsetrgn(VSIwn, VSIw->Rleft, VSIw->lines - x2,
  178.                 VSIw->Rright, VSIw->lines);
  179.         else
  180.           {
  181.           /* x & y have been normalized relative to left & top
  182.             of current visible region. Just call the appropriate scroll
  183.             routine, which will also redisplay the cursor. */
  184.             if (y > 0)
  185.                 VSscrolforward(VSIwn, y);
  186.             else
  187.                 VSscrolback(VSIwn, -y);
  188.           } /* if */
  189.       } /* if */
  190.   } /* VSIcurson */
  191.  
  192. void VSIcuroff
  193.   (
  194.     int w
  195.   )
  196.   /* hides the cursor for the specified screen. Assumes it
  197.     is currently being shown (or that it's on an invisible
  198.     part of the screen). */
  199.   {
  200.     int
  201.         x = VSIw->x,
  202.         y = VSIw->y,
  203.         x2,
  204.         y2,
  205.         n = 1,
  206.         offset;
  207.  
  208.     if (!VSIclip(&x, &y, &x2, &y2, &n, &offset))
  209.       /* cursor is on visible part of screen */
  210.         RScursoff(w);
  211.   } /* VSIcuroff */
  212.  
  213. VSlineArray VSInewlinearray
  214.   (
  215.     int nrlines
  216.   )
  217.   /* allocates an array to hold the specified number of pointers
  218.     to line elements. */
  219.   {
  220.     return
  221.         (VSlineArray) NewPtr(sizeof(VSlinePtr) * nrlines);
  222.   } /* VSInewlinearray */
  223.  
  224. VSlinePtr VSInewlines
  225.   (
  226.     int nlines
  227.   )
  228.   /* allocates a doubly-linked list of the specified number of
  229.     line elements, and returns a pointer to the head of the list,
  230.     or nil if ran out of memory. The maximum number of characters
  231.     each line can hold is controlled by VSIw->allwidth. */
  232.   {
  233.     VSlinePtr t2;
  234.     char *t;
  235.     register int i;
  236.     
  237.     if (!RSokmem(30000))                /* don't use up end of mem for scrollback */
  238.         return((VSlinePtr) 0L);
  239.   /* allocate one block for the line list elements, and another
  240.     block for the line contents. These blocks will be divided up
  241.     and appropriate flags set so I will be able to call DisposPtr
  242.     the right number of times, with the right arguments. */
  243.     if ((t = NewPtr(nlines * (VSIw->allwidth + 1))) != 0L)
  244.       {
  245.         if ((t2 = (VSlinePtr) NewPtr(nlines * sizeof(VSline))) != 0L)
  246.             t2->text = t;
  247.         else
  248.           {
  249.           /* clean up gracefully before giving up */
  250.             DisposPtr(t);
  251.             return(0L);
  252.           } /* if */
  253.       }
  254.     else
  255.       /* sorree no memoree */
  256.         return((VSlinePtr) 0L);
  257.  
  258. /*
  259. *  indicate to the free routine that the first record is the one to free.
  260. */
  261.     t2->mem = 1;                        /* call DisposPtr on this one */
  262.     t2->next = t2 + 1;                    /* point to next one */
  263. /*
  264. *  Take our allocation for multiple lines and fill in the structures to 
  265. *  point to the right text fields and connect the doubly-linked chain.
  266. *
  267. */
  268.     for (i = 1; i < nlines; i++)
  269.       {
  270.         t += (VSIw->allwidth + 1);        /* inc to next text space for a line */
  271.         t2[i].mem = 0;                    /* don't DisposPtr any of these */
  272.         t2[i].text = t;
  273.         t2[i].prev = t2 + i - 1;        /* point back one */
  274.         t2[i].next = t2 + i + 1;        /* point forward one */
  275.       } /* for */
  276.     
  277.     t2[0].prev = 0L;                    /* first one has no prev yet */
  278.     t2[nlines - 1].next = 0L;            /* last one has no next yet */
  279.  
  280.     return(t2);
  281.   } /* VSInewlines */
  282.  
  283. void VSIlistndx
  284.   (
  285.     register VSlinePtr ts,
  286.     register VSlinePtr as
  287.   )
  288.   /* sets up the screen arrays for the current screen to point
  289.     at the given lists of attribute and text lines. */
  290.   {
  291.     register int i;
  292.     for (i = 0; i <= VSIw->lines; i++)
  293.       {
  294.         VSIw->attrst[i] = as;
  295.         VSIw->linest[i] = ts;
  296.         ts = ts->next;
  297.         as = as->next;
  298.       } /* for */
  299.   } /* VSIlistndx */
  300.  
  301. void VSIscroff
  302.   (
  303.     void
  304.   )
  305.   /* called to save current screen contents in scrollback buffer,
  306.     if it is ordained that I should do so. This is called by VSIes
  307.     (below) just before the entire screen is cleared. */
  308.   {
  309.     VSlinePtr tmp;
  310.     register int i, j;
  311.  
  312.     if
  313.       (
  314.             (!VSIw->savelines) /* not saving lines */
  315.         ||
  316.             (VSIw->top != 0) || (VSIw->bottom != VSIw->lines)
  317.               /* scrolling region isn't exactly the entire screen */
  318.       )
  319.         return; /* do nothing */
  320.  
  321.     tmp = VSIw->linest[VSIw->lines]; /* need VSIw->lines + 1 more lines */
  322.     for (i = 0; i <= VSIw->lines; i++)
  323.       {
  324.       /* count off the lines in the part of the scrollback buffer
  325.         below the screen (if any), to see if there's enough to hold
  326.         a screenful. If the scrollback list isn't circular, then
  327.         this part contains lines that have been allocated, but not
  328.         yet used. If the list is circular (meaning it has reached
  329.         its full size), then this is the part that is next in line
  330.         for reuse. */
  331.         if (!tmp->next) 
  332.           { /* not enough */
  333.             j = VSIw->maxlines - VSIw->numlines - i; /* potential unallocated scrollback */
  334.             if (j > ScrollbackQuantum)
  335.                 j = ScrollbackQuantum; /* but don't bother allocating more than this */
  336.             if (j <= 0)
  337.               {
  338.               /* already reached user-specified scrollback limit-- */
  339.               /* make the list circular to indicate no more extension. */
  340.                 tmp->next = VSIw->buftop;
  341.                 VSIw->buftop->prev = tmp;        /* connect it up */
  342.               }
  343.             else
  344.               {
  345.               /* extend the scrollback buffer to make room for
  346.                 another screenful */
  347.                 if (j < VSIw->lines - i + 1)
  348.                     j = VSIw->lines - i + 1; /* need at least this many */
  349.                 if ((tmp->next = VSInewlines(j)) != 0L) 
  350.                     tmp->next->prev = tmp;        /* got some space--link it up */
  351.                 else
  352.                   {
  353.                   /* out of memory--no more extensions */
  354.                     tmp->next = VSIw->buftop;
  355.                     VSIw->buftop->prev = tmp;    
  356.                   } /* if */                
  357.               } /* if */
  358.             break;                                /* only allocate once is enough */
  359.           } /* if */
  360.         tmp = tmp->next; /* keep counting */
  361.       } /* for */
  362.         
  363. /*
  364. *  at this point, we know we have enough memory for the whole scroll.
  365. *  It might be wraparound (reuse of some line elements), might not.
  366. */
  367.         
  368.     for (i = 0; i <= VSIw->lines; i++)
  369.       {
  370.       /* push another screen line into the scrollback area */
  371.         if (VSIw->linest[VSIw->lines]->next == VSIw->buftop)
  372.             VSIw->buftop = VSIw->buftop->next;    /* reusing old space */
  373.         else
  374.             VSIw->numlines++;                /* using some new space */
  375.         VSIw->scrntop = VSIw->scrntop->next; /* move another line into the scrollback buffer */
  376.         VSIlistndx(VSIw->scrntop, VSIw->attrst[1]); /* and update screen arrays */
  377.       /* note that it's up to the caller to clear out the new screen text
  378.         and attribute lines */
  379.       } /* for */
  380.  
  381.     VSIw->vistop = VSIw->scrntop;
  382.     RSbufinfo(VSIwn, VSIw->numlines, VSIw->Rtop, VSIw->Rbottom); /* update vertical scroll bar */
  383.   } /* VSIscroff */
  384.  
  385. void VSIelo
  386.   (
  387.     int s /* line to erase, -ve => line containing cursor */
  388.   )
  389.   /* blanks out the specified line in the screen buffer.
  390.     Doesn't do anything to the display. */
  391.   {
  392.     char *tt, *ta;
  393.     int i;
  394.  
  395.     if (s < 0)
  396.         s = VSIw->y;
  397.  
  398.     ta = &VSIw->attrst[s]->text[0];
  399.     tt = &VSIw->linest[s]->text[0];
  400.     for (i = 0; i <= VSIw->allwidth; i++)
  401.       {
  402.         *ta++ = VSIclrattrib;
  403.         *tt++ = ' ';
  404.       } /* for */
  405.   } /* VSIelo */
  406.  
  407. void VSIes
  408.   (
  409.     void
  410.   )
  411.   /* clears the screen, first saving its contents in the
  412.     scrollback buffer if appropriate. Also updates the display. */
  413.   {
  414.     int
  415.         i;
  416.     int
  417.         x1 = 0,
  418.         y1 = 0,
  419.         x2 = VSIw->maxwidth,
  420.         y2 = VSIw->lines,
  421.         n = -1,
  422.         offset;
  423.  
  424.   /* save screen contents in scrollback buffer, if appropriate */
  425.     if (VSIw->ESscroll)
  426.         VSIscroff();
  427.   /* clear out screen buffer */
  428.     for (i = 0; i <= VSIw->lines; i++)
  429.         VSIelo(i);
  430.   /* update display to show what I've done */
  431.     if (!VSIclip(&x1, &y1, &x2, &y2, &n, &offset)) 
  432.         RSerase(VSIwn, x1, y1, x2, y2);
  433.     VSIw->vistop = VSIw->scrntop;
  434.   } /* VSIes */
  435.  
  436. void VSItabclear
  437.   (
  438.     void
  439.   )
  440.   /* clears all current tab settings. */
  441.   {
  442.     int
  443.         x = 0;
  444.  
  445.     while (x <= VSIw->allwidth)
  446.       {
  447.         VSIw->tabs[x] = ' ';
  448.         x++;
  449.       } /* while */
  450.   } /* VSItabclear */
  451.  
  452. void VSItabinit
  453.   (
  454.     void
  455.   )
  456.   /* sets tab settings to default (every 8 columns). */
  457.   {
  458.     int
  459.         x = 0;
  460.  
  461.     VSItabclear();
  462.     while (x <= VSIw->allwidth)
  463.       {
  464.         VSIw->tabs[x] = 'x';
  465.         x += 8;
  466.       }
  467.     VSIw->tabs[VSIw->allwidth] = 'x';
  468.   } /* VSItabinit */
  469.  
  470. void VSIreset
  471.   (
  472.     void
  473.   )
  474.   /* restores terminal mode settings to defaults and clears screen. */
  475.   {
  476.     VSIw->top = 0;
  477.     VSIw->bottom = VSIw->lines;
  478.     VSIw->parmptr = 0;
  479.     VSIw->escflg = 0;
  480.     VSIw->DECAWM = 0;
  481.     VSIw->DECCKM = 0;
  482.     VSIw->DECPAM = 0;
  483.     VSIw->DECORG = 0;
  484.     VSIw->IRM = 0;
  485.     VSIw->attrib = 0;
  486.     VSIw->Pattrib = -1;
  487.     VSIw->x = 0;
  488.     VSIw->y = 0;
  489.     VSIw->charset = 0;
  490.     VSIes();
  491.     VSItabinit();
  492.   } /* VSIreset */
  493.  
  494. VSIlistmove(TD, BD, TI, BI)
  495.     register VSlinePtr TD, BD, TI, BI;
  496.   /* moves the lines from TD to BD inclusive from their
  497.     present position to between TI and BI. Either of the
  498.     latter may be nil. */
  499.   {
  500.   /* unlink the lines from TD to BD */
  501.     if (TD->prev != 0L)
  502.         TD->prev->next = BD->next;    /* Maintain circularity */
  503.     if (BD->next != 0L)
  504.         BD->next->prev = TD->prev;
  505.   /* relink them between TI and BI */
  506.     TD->prev = TI;                                /* Place the node in its new home */
  507.     BD->next = BI;
  508.     if (TI != 0L)
  509.         TI->next = TD;                    /* Ditto prev->prev */
  510.     if (BI != 0L)
  511.         BI->prev = BD;
  512.   } /* VSIlistmove */
  513.  
  514. void VSIdellines(n,s)
  515. int    n,s;
  516. {
  517.     int i,j, attop;
  518.     char *ta,*tt;
  519.     VSline *as,*ts,*TD,*BD,*TI,*BI,*itt,*ita;
  520.  
  521.     attop= (VSIw->vistop == VSIw->scrntop);
  522.     if (s<0) s=VSIw->y;
  523.  
  524.     if ( s+n-1 > VSIw->bottom) n = VSIw->bottom -s +1;
  525.  
  526.     ts=VSIw->linest[0]->prev;
  527.     TD=VSIw->linest[s];
  528.     BD=VSIw->linest[s+n-1];
  529.     TI=VSIw->linest[VSIw->bottom];
  530.     BI=TI->next;
  531.  
  532.     itt=TD;
  533.     if ((TI!=BD))
  534.         VSIlistmove(TD,BD,TI,BI);
  535.  
  536.     if (s==0 || n>VSPBOTTOM) as= VSIw->attrst[n];
  537.     else as= VSIw->attrst[0];
  538.  
  539.     TD=VSIw->attrst[s];
  540.     BD=VSIw->attrst[s+n-1];
  541.     TI=VSIw->attrst[VSIw->bottom];
  542.     BI=TI->next;
  543.  
  544.     if (TD!=BI && TI!=BD)
  545.         VSIlistmove(TD,BD,TI,BI);
  546.  
  547.     ita=TD;
  548.     for(i=0; i<n; i++) {
  549.         ta=ita->text;
  550.         tt=itt->text;
  551.         for(j=0; j<=VSIw->allwidth; j++) {
  552.             *tt++=' ';
  553.             *ta++=VSIclrattrib;
  554.             }
  555.         ita=ita->next;
  556.         itt=itt->next;
  557.         }
  558.     VSIw->scrntop = ts->next;
  559.     if (attop) VSIw->vistop = VSIw->scrntop;
  560.  
  561.     VSIlistndx(ts->next,as);
  562.  
  563.     VSIcdellines(VSIwn,s, VSIw->bottom,n, -1);        /* Destroy selection area if this is called */
  564.   } /* VSIdellines */
  565.  
  566. void VSIinslines
  567.   (
  568.     int n, /* how many to insert */
  569.     int s /* where to insert them, -ve => line containing cursor */
  570.   )
  571.   /* inserts the specified number of blank lines, scrolling the
  572.     remaining ones down, and dropping off any that fall off the
  573.     end of the scrolling region. */
  574.   {
  575.     int i, j;
  576.     char *ta, *tt;
  577.     VSlinePtr as, ts, TD, BD, TI, BI, itt, ita;
  578.  
  579.     if (s < 0)
  580.         s = VSIw->y;
  581.     if (s + n - 1 > VSIw->bottom)
  582.       /* don't bother inserting more than scrolling region can hold */
  583.         n = VSIw->bottom - s + 1;
  584.  
  585.   /* find new tops of screen arrays */
  586.     if (s == 0 && n <= VSIw->lines)
  587.       {
  588.       /* element for first blank line being inserted */
  589.         ts = VSIw->linest[VSIw->bottom - n + 1];
  590.         as = VSIw->attrst[VSIw->bottom - n + 1];
  591.       }
  592.     else
  593.       {
  594.       /* top line unaffected, or entire screen is being wiped */
  595.         ts = VSIw->linest[0];
  596.         as = VSIw->attrst[0];
  597.       } /* if */
  598.  
  599.     BI = VSIw->linest[s]; /* insert blank lines before this one */
  600.     TI = BI->prev; /* insert them after this one */
  601.     TD = VSIw->linest[VSIw->bottom - n + 1]; /* topmost line to delete */
  602.     BD = VSIw->linest[VSIw->bottom]; /* bottommost line to delete */
  603.     itt = TD; /* start of text lines to be blanked out */
  604.   /* the space occupied by the deleted lines will be reused for
  605.     the new blank lines */
  606.     if (TD != BI && TI != BD)
  607.       /* new and deleted lines not contiguous -- move the space
  608.         to its new position */
  609.         VSIlistmove(TD, BD, TI, BI);
  610.  
  611.     BI = VSIw->attrst[s]; /* insert new lines before this one */
  612.     TI = BI->prev; /* insert them after this one */
  613.     TD = VSIw->attrst[VSIw->bottom - n + 1]; /* topmost line to delete */
  614.     BD = VSIw->attrst[VSIw->bottom]; /* bottommost line to delete */
  615.   /* do the same rearrangement on the attribute lines */
  616.     if (TD != BI && TI != BD)
  617.       /* new and deleted lines not contiguous -- move the space
  618.         to its new position */
  619.         VSIlistmove(TD, BD, TI, BI);
  620.  
  621.   /* blank out the newly-inserted lines */
  622.     ita = TD; /* start of attribute lines to be blanked out */
  623.     for (i = 0; i < n; i++)
  624.       {
  625.         tt = itt->text;
  626.         ta = ita->text;
  627.         for (j = 0; j <= VSIw->allwidth; j++)
  628.           {
  629.             *tt++ = ' ';
  630.             *ta++ = VSIclrattrib;
  631.           }
  632.         itt = itt->next;
  633.         ita = ita->next;
  634.       } /* for */
  635.  
  636.     VSIw->scrntop = ts;
  637.     VSIlistndx(ts, as); /* re-sync screen arrays */
  638.     if (VSIw->Rtop >= 0)
  639.       /* make sure vistop still points to same line position
  640.         on screen that it did before */
  641.         VSIw->vistop = VSIw->linest[VSIw->Rtop];
  642.   /* update display to match reality */
  643.     VSIcinslines(VSIwn, s, VSIw->bottom, n, -1);  /* Destroy selection area if this is called tooo */
  644.   } /* VSIinslines */
  645.  
  646. void VSIscroll()
  647.   {
  648.     register char *temp,*tempa;
  649.     VSline *tmp;
  650.     register int i;
  651.     int tx1,tx2,ty1,ty2, tn,offset;
  652.  
  653.     tx1=ty1=0; tn=132;
  654.     if (!VSIclip( &tx1, &ty1,&tx2,&ty2, &tn, &offset) )
  655.         RSdrawsep( VSIwn, ty1, 1);                    /* Draw Separator */
  656.  
  657.     if ( (!VSIw->savelines) || (VSIw->top !=0) || (VSIw->bottom != VSPBOTTOM))
  658.         VSIdellines(1,VSIw->top);
  659.     else {
  660.         
  661.         if ( VSIw->linest[VSPBOTTOM]->next == 0L) {            /* need wrap or storage */
  662.         
  663.             i = VSIw->maxlines - VSIw->numlines;    /* number of lines needed */
  664.             if (i > 100) i = 100;
  665.     
  666.             if (( i > 0 ) && (tmp = VSInewlines(i)) !=0L ) {
  667.                     VSIw->linest[VSPBOTTOM]->next = tmp;        /* ADD some lines */
  668.                     tmp->prev= VSIw->linest[VSIw->bottom];
  669.                     VSIw->numlines++;                /* count one */
  670.                     RSbufinfo(VSIwn, VSIw->numlines,VSIw->Rtop, VSIw->Rbottom);
  671.                 }
  672.             else {
  673.                 VSIw->linest[VSIw->bottom]->next =VSIw->buftop;        /* Make it circular */
  674.                 VSIw->buftop->prev= VSIw->linest[VSIw->bottom];
  675.                 VSIw->buftop=VSIw->buftop->next;    /* step one forward */
  676.                 }
  677.             }    
  678.         else {
  679.             if ( VSIw->linest[VSIw->bottom]->next == VSIw->buftop)
  680.                 VSIw->buftop=VSIw->buftop->next;    /* if we are in old terr. loop*/
  681.             else
  682.                 VSIw->numlines++;                    /* count it */
  683.             }
  684.  
  685.         VSIw->scrntop=VSIw->scrntop->next;
  686.         VSIlistndx( VSIw->scrntop, VSIw->attrst[1]);
  687.  
  688.         if (VSIcdellines(VSIwn,VSIw->Rtop, VSIw->Rbottom,1,1) ) {        /* Dont destroy select */
  689.                 /* If we did not show on screen then we mush do dis */
  690.             if (VSIw->Rtop > -VSIw->numlines) {    /* If we are not at the top..... */
  691.                 VSIw->Rtop--; VSIw->Rbottom--;    /* Then we should move down  */
  692.                 }
  693.             else {                                /* But if we're at the top.... */
  694.                                                 /* The region remains the same .. */
  695.                 VSIw->vistop=VSIw->vistop->next;/* and move the vistop as */
  696.                 RSdellines( VSIwn, 0,VSIw->Rbottom-VSIw->Rtop,1,1);/* we also delete the top line */
  697.                 }                                /* well.... (but don't destroy selection)  */
  698.             }
  699.         else {
  700.                 VSIw->vistop=VSIw->vistop->next;
  701.             }
  702.  
  703.         tempa=VSIw->attrst[VSPBOTTOM]->text;
  704.         temp =VSIw->linest[VSPBOTTOM]->text;
  705.         for(i=0;i<=VSIw->allwidth; i++) {
  706.             *temp++=' ';
  707.             *tempa++=0;
  708.             }
  709.     }
  710.     tx1=ty1=0; tn=132;
  711.     if (!VSIclip( &tx1, &ty1,&tx2,&ty2, &tn, &offset) )
  712.         RSdrawsep( VSIwn, ty1, 1);                    /* Draw Separator */
  713.   } /* VSIscroll */
  714.  
  715. void VSIindex
  716.   (
  717.     void
  718.   )
  719.   /* moves cursor down one line, unless it's at the bottom of
  720.     the scrolling region, in which case scrolls up one. */
  721.   {
  722.     if (VSIw->y == VSIw->bottom)
  723.         VSIscroll();
  724.     else
  725.         VSIw->y++;
  726.   } /* VSIindex */
  727.  
  728. VSIwrapnow(xp, yp)
  729.     int *xp, *yp;
  730.   /* checks current cursor position for VSIw to see if
  731.     it's within bounds, wrapping to next line if not.
  732.     Returns correct cursor position in either case in *xp
  733.     and *yp. */
  734.   {
  735.     if (VSIw->x > VSIw->maxwidth) 
  736.       {
  737.         VSIw->x = 0;
  738.         VSIindex();
  739.       } /* if */
  740.     *xp = VSIw->x;
  741.     *yp = VSIw->y;
  742.   } /* VSIwrapnow */
  743.  
  744. void VSIeeol
  745.   (
  746.     void
  747.   )
  748.   /* erases characters to the end of the current line. */
  749.   {
  750.     char
  751.         *tt,
  752.         *ta;
  753.     int
  754.         x1 = VSIw->x,
  755.         y1 = VSIw->y,
  756.         x2 = VSIw->maxwidth,
  757.         y2 = VSIw->y,
  758.         n = -1,
  759.         offset;
  760.     int
  761.         i;
  762.  
  763.     VSIwrapnow(&x1, &y1);
  764.     y2 = y1;
  765.   /* clear out screen line */
  766.     ta = &VSIw->attrst[y1]->text[x1];
  767.     tt = &VSIw->linest[y1]->text[x1];
  768.     for (i = VSIw->allwidth - x1 + 1; i > 0; i--)
  769.       {
  770.         *ta++ = VSIclrattrib;
  771.         *tt++ = ' ';
  772.       }
  773.   /* update display */
  774.     if (!VSIclip(&x1, &y1, &x2, &y2, &n, &offset)) 
  775.         RSerase(VSIwn, x1, y1, x2, y2);
  776.   } /* VSIeeol */
  777.  
  778. void VSIdelchars
  779.   (
  780.     int x /* how many characters to delete */
  781.   )
  782.   /* deletes characters at the current cursor position onwards,
  783.     moving the remainder of the line to the left. */
  784.   {
  785.     int
  786.         i;
  787.     int
  788.         x1 = VSIw->x,
  789.         y1 = VSIw->y,
  790.         x2 = VSIw->maxwidth,
  791.         y2 = VSIw->y,
  792.         n = -1,
  793.         offset;
  794.     char
  795.         *tempa,
  796.         *temp;
  797.  
  798.     VSIwrapnow(&x1, &y1);
  799.     y2 = y1;
  800.  
  801.     if (x > VSIw->maxwidth)
  802.         x = VSIw->maxwidth;
  803.     tempa = VSIw->attrst[y1]->text;
  804.     temp = VSIw->linest[y1]->text;
  805.     for (i = x1; i <= VSIw->maxwidth - x; i++)
  806.       {
  807.       /* move remainder of line to the left */
  808.         temp[i] = temp[x + i];
  809.         tempa[i] = tempa[x + i];
  810.       }
  811.     for (i = VSIw->maxwidth - x + 1; i <= VSIw->allwidth; i++)
  812.       {
  813.       /* insert blank characters after end of line */
  814.         temp[i] = ' ';
  815.         tempa[i] = VSIclrattrib;
  816.       }
  817.   /* update display */
  818.     if (!VSIclip(&x1, &y1, &x2, &y2, &n, &offset))
  819.       {
  820.         if (VSIw->VSIDC)
  821.             RSdelchars(VSIwn, x1, y1, x);
  822.         else
  823.           /* redraw from cursor position to end of line.
  824.             Trouble is, this isn't going to preserve the
  825.             right attributes. */
  826.             RSdraw
  827.               (
  828.                 VSIwn, x1, y1, VSIw->attrib, n,
  829.                 &VSIw->linest[y1]->text[x1]
  830.               );
  831.       } /* if */
  832.   } /* VSIdelchars */
  833.  
  834. void VSIfreelinelist
  835.   (
  836.     VSlinePtr listhead
  837.   )
  838.   /* frees up the list of line elements pointed to by listhead. */
  839.   {
  840.     register VSlinePtr
  841.         ThisElt, NextElt, ToFree;
  842.  
  843.     ThisElt = listhead;
  844.     ToFree = nil;
  845.     while (true)
  846.       {
  847.         if (ThisElt == nil)
  848.             break;
  849.         NextElt = ThisElt->next;
  850.         if (ThisElt->mem)
  851.           {
  852.             ThisElt->next = ToFree;
  853.             ToFree = ThisElt;
  854.           } /* if */
  855.         ThisElt = NextElt;
  856.         if (ThisElt == listhead)
  857.             break;
  858.       } /* while */
  859.     while (ToFree)
  860.       {
  861.         NextElt = ToFree->next;
  862.         DisposPtr(ToFree->text);
  863.         DisposPtr((Ptr) ToFree);
  864.         ToFree = NextElt;
  865.       } /* while */
  866.   } /* VSIfreelinelist */
  867.  
  868. void VSIfreelines
  869.   (
  870.     void
  871.   )
  872.   /* frees up all the memory allocated for screen and scrollback
  873.     text lines for the current screen. */
  874.   {
  875.     VSIfreelinelist(VSIw->buftop);
  876.   } /* VSIfreelines */
  877.  
  878. void VSIrindex
  879.   (
  880.     void
  881.   )
  882.   /* moves cursor up one line, unless it's at the top of
  883.     the scrolling region, in which case scrolls down one. */
  884.   {
  885.     if (VSIw->y == VSIw->top)
  886.         VSIinslines(1, VSIw->top);
  887.     else
  888.         VSIw->y--;
  889.   } /* VSIrindex */
  890.  
  891. void VSIebol
  892.   (
  893.     void
  894.   )
  895.   /* erases characters from beginning of line to cursor. */
  896.   {
  897.     char
  898.         *tt,
  899.         *ta;
  900.     int
  901.         x1 = 0,
  902.         y1 = VSIw->y,
  903.         x2 = VSIw->x,
  904.         y2 = VSIw->y,
  905.         n = -1,
  906.         offset;
  907.     int
  908.         i;
  909.  
  910.     VSIwrapnow(&x2, &y1);
  911.     y2 = y1;
  912.   /* clear from beginning of line to cursor */
  913.     ta = &VSIw->attrst[y1]->text[0];
  914.     tt = &VSIw->linest[y1]->text[0];
  915.     for (i = 0; i <= x2; i++)
  916.       {
  917.         *ta++ = VSIclrattrib;
  918.         *tt++ = ' ';
  919.       }
  920.   /* update display */
  921.     if (!VSIclip(&x1, &y1, &x2, &y2, &n, &offset)) 
  922.         RSerase(VSIwn, x1, y1, x2, y2);
  923.   } /* VSIebol */
  924.  
  925. void VSIel
  926.   (
  927.     int s /* line to clear, -ve => line containing cursor */
  928.   )
  929.   /* erases the specified line. */
  930.   {
  931.     char
  932.         *tt,
  933.         *ta;
  934.     int
  935.         x1 = 0,
  936.         y1 = s,
  937.         x2 = VSIw->maxwidth,
  938.         y2 = s,
  939.         n = -1,
  940.         offset;
  941.     int
  942.         i;
  943.  
  944.     if (s < 0)
  945.       {
  946.         VSIwrapnow(&x1, &y1);
  947.         s = y2 = y1;
  948.         x1 = 0;
  949.       } /* if */
  950.   /* clear out line */
  951.     ta = &VSIw->attrst[s]->text[0];
  952.     tt = &VSIw->linest[s]->text[0];
  953.     for(i = 0; i <= VSIw->allwidth; i++)
  954.       {
  955.         *ta++ = VSIclrattrib;
  956.         *tt++ = ' ';
  957.       }
  958.   /* update display */
  959.     if (!VSIclip(&x1, &y1, &x2, &y2, &n, &offset)) 
  960.         RSerase(VSIwn, x1, y1, x2, y2);
  961.   } /* VSIel */
  962.  
  963. void VSIeeos
  964.   (
  965.     void
  966.   )
  967.   /* erases characters from cursor to end of screen. */
  968.   {
  969.     int
  970.         i;
  971.     int
  972.         x1 = 0,
  973.         y1 = VSIw->y + 1,
  974.         x2 = VSIw->maxwidth,
  975.         y2 = VSIw->lines,
  976.         n = -1,
  977.         offset;
  978.  
  979.     VSIwrapnow(&x1, &y1);
  980.     y1++;
  981.     x1 = 0;
  982.  
  983.     i = y1;
  984.   /* erase complete lines from screen */
  985.     if (!VSIclip(&x1, &y1, &x2, &y2, &n, &offset)) 
  986.         RSerase(VSIwn, x1, y1, x2, y2);
  987.   /* blank out current line from cursor to end */
  988.     VSIeeol(); /* this also erases the partial line on-screen */
  989.   /* blank out remaining lines to end of screen */
  990.     while (i <= VSIw->lines)
  991.       {
  992.         VSIelo(i);
  993.         i++;
  994.       } /* while */
  995.     if (VSIw->y < VSIw->lines && (VSIw->x <= VSIw->maxwidth))
  996.       /* erase the partial line (what--again??) */
  997.         if (!VSIclip(&x1, &y1, &x2, &y2, &n, &offset)) 
  998.             RSerase(VSIwn, x1, y1, x2, y2);
  999.   } /* VSIeeos */
  1000.  
  1001. void VSIebos
  1002.   (
  1003.     void
  1004.   )
  1005.   /* erases characters from beginning of screen to cursor. */
  1006.   {
  1007.     int
  1008.         i;
  1009.     int
  1010.         x1,
  1011.         y1,
  1012.         x2 = VSIw->maxwidth,
  1013.         y2,
  1014.         n = -1,
  1015.         offset;
  1016.  
  1017.     VSIwrapnow(&x1, &y1);
  1018.     y2 = y1 - 1;
  1019.     x1 = 0;
  1020.     y1 = 0;
  1021.   /* blank out current line from beginning to cursor */
  1022.     VSIebol(); /* this also erases the partial line on-screen */
  1023.     i = 0;
  1024.   /* blank out remaining lines from beginning of screen to previous line */
  1025.     while (i < (y2 + 1))
  1026.       {
  1027.         VSIelo(i);
  1028.         i++;
  1029.       } /* while */
  1030.     if (y2 >= 0)
  1031.       /* erase the partial line (what--again??) */
  1032.         if (!VSIclip(&x1, &y1, &x2, &y2, &n, &offset)) 
  1033.             RSerase(VSIwn, x1, y1, x2, y2);
  1034.   } /* VSIebos */
  1035.  
  1036. void VSIrange
  1037.   (
  1038.     void
  1039.   )
  1040.   /* constrains cursor position to valid range (somewhere on the screen). */
  1041.   {
  1042.     int
  1043.         wrap = 0;
  1044.     if (VSIw->DECAWM)
  1045.         wrap = 1;
  1046.     if (VSIw->x < 0)
  1047.         VSIw->x = 0;
  1048.     if (VSIw->x > (VSIw->maxwidth + wrap))
  1049.         VSIw->x = VSIw->maxwidth + wrap;
  1050.     if (VSIw->y < 0)
  1051.         VSIw->y = 0;
  1052.     if (VSIw->y > VSIw->lines)
  1053.         VSIw->y = VSIw->lines;
  1054.   } /* VSIrange */
  1055.  
  1056. void VTsendpos
  1057.   (
  1058.     void
  1059.   )
  1060.   /* sends an escape sequence representing the current cursor position. */
  1061.   {
  1062.     char
  1063.         tempbuf[19];
  1064.     int
  1065.         x = VSIw->x,
  1066.         y = VSIw->y;
  1067.  
  1068.     if (x > VSIw->maxwidth)
  1069.       {
  1070.       /* autowrap pending */
  1071.         x = 0;
  1072.         y++;
  1073.       }
  1074.     if (y > VSIw->lines)
  1075.       /* scroll pending (because of the autowrap) */
  1076.         y = VSIw->lines;
  1077.  
  1078.     sprintf(tempbuf, "\033[%d;%dR", y + 1, x + 1);
  1079.     RSsendstring(VSIwn, tempbuf, strlen(tempbuf));
  1080.   } /* VTsendpos */
  1081.  
  1082. void VTsendstat
  1083.   (
  1084.     void
  1085.   )
  1086.   /* sends the terminal status string. */
  1087.   {
  1088.     RSsendstring(VSIwn, "\033[0n", 4);
  1089.   } /* VTsendstat */
  1090.  
  1091. void VTsendident
  1092.   (
  1093.     void
  1094.   )
  1095.   /* sends an appropriate terminal identification sequence. */
  1096.   {
  1097. #ifdef VT100RESP
  1098.     if (VSIw->allwidth > 80)
  1099.         RSsendstring(VSIwn, "\033[?4;6c", 7);
  1100.     else
  1101.         RSsendstring(VSIwn, "\033[?1;6c", 7);
  1102. #endif VT100RESP
  1103.     RSsendstring(VSIwn, "\033[?6c", 5);
  1104.   } /* VTsendident */
  1105.  
  1106. void VTalign
  1107.   (
  1108.     void
  1109.   )
  1110.   /* fills screen with uppercase "E"s, for checking screen alignment. */
  1111.   /* Yeah, right. */
  1112.   {
  1113.     char *tt;
  1114.     int i, j;
  1115.  
  1116.     VSIes();        /* erase the screen */
  1117.     for (j = 0; j < VSIw->lines; j++)
  1118.       {
  1119.         tt = &VSIw->linest[j]->text[0];
  1120.         for (i = 0; i <= VSIw->maxwidth; i++)
  1121.             *tt++ = 'E';
  1122.       } /* for */
  1123.   /* update the display */
  1124.     VSredraw(VSIwn, 0, 0,
  1125.         (VSIw->Rright - VSIw->Rleft), (VSIw->Rbottom - VSIw->Rtop));
  1126.   } /* VTalign */
  1127.  
  1128. void VSIapclear
  1129.   (
  1130.     void
  1131.   )
  1132.   /* initializes all the parameters for the current control
  1133.     sequence, and the current param index, to zero. */
  1134.   {
  1135.     int
  1136.         parmptr = maxparms;
  1137.     while (--parmptr >= 0)
  1138.         VSIw->parms[parmptr] = -1;
  1139.     VSIw->parmptr = 0;
  1140.   } /* VSIapclear */
  1141.  
  1142. void VSIsetoption
  1143.   (
  1144.     int toggle /* 1 => set, 0 => reset */
  1145.   )
  1146.   /* sets/resets various options, as specified by the parms in
  1147.     the current control sequence. Note that this implementation
  1148.     will not set/reset more than one option at a time! */
  1149.   {
  1150.     int
  1151.         WindWidth = VSIw->Rright - VSIw->Rleft;
  1152.  
  1153.     switch (VSIw->parms[0])
  1154.       {
  1155.         case -2: /* DEC-private control sequence */
  1156.             switch (VSIw->parms[1])
  1157.               {
  1158.                 case 1: /* cursor-key mode */
  1159.                     VSIw->DECCKM = toggle;
  1160.                     break;
  1161.                 case 3: /* 80/132 columns */
  1162.                     VSIw->x = VSIw->y = 0; /* home cursor */
  1163.                     VSIes(); /* and clear screen */
  1164.                     if (toggle)        /* 132 column mode */
  1165.                         VSIw->maxwidth = VSIw->allwidth;
  1166.                     else
  1167.                         VSIw->maxwidth = 79;
  1168.                   /* update scroll bars */
  1169.                     RSmargininfo(VSIwn, VSIw->maxwidth - WindWidth, VSIw->Rleft);
  1170.                     break;
  1171.                 case 6: /* origin mode */
  1172.                     VSIw->DECORG = toggle;
  1173.                     break;
  1174.                 case 7: /* autowrap mode */
  1175.                     VSIw->DECAWM = toggle;
  1176.                     break;
  1177.                 default:
  1178.                     break;
  1179.               } /* switch */
  1180.             break;
  1181.         case  4: /* insert/replace character writing mode */
  1182.             VSIw->IRM = toggle;
  1183.             break;
  1184.         default:
  1185.             break;
  1186.       } /* switch */
  1187.   } /* VSIsetoption */
  1188.  
  1189. int VSItab
  1190.   (
  1191.     void
  1192.   )
  1193.   /* advances VSIw->x to the next tab position. */
  1194.   {
  1195.     if (VSIw->x >= VSIw->maxwidth)
  1196.       {
  1197.       /* already at right margin */
  1198.         VSIw->x = VSIw->maxwidth;
  1199.         return(0);
  1200.       } /* if */
  1201.     VSIw->x++; /* advance at least one position */
  1202.     while ((VSIw->tabs[VSIw->x] != 'x') && (VSIw->x < VSIw->maxwidth))
  1203.         VSIw->x++;
  1204.     return(0);
  1205.   } /* VSItab */
  1206.  
  1207. void VSIinschar
  1208.   (
  1209.     int x /* number of blanks to insert */
  1210.   )
  1211.   /* inserts the specified number of blank characters at the
  1212.     current cursor position, moving the rest of the line along,
  1213.     losing any characters that fall off the right margin.
  1214.     Does not update the display. */
  1215.   {
  1216.     int i, j;
  1217.     char *tempa, *temp;
  1218.  
  1219.     VSIwrapnow(&i, &j);
  1220.  
  1221.     tempa = VSIw->attrst[VSIw->y]->text;
  1222.     temp = VSIw->linest[VSIw->y]->text;
  1223.     for (i = VSIw->maxwidth - x; i >= VSIw->x; i--)
  1224.       {
  1225.       /* move along remaining characters on line */
  1226.         temp[x + i] =temp[i];
  1227.         tempa[x + i] = tempa[i];
  1228.       } /* for */
  1229.     for (i = VSIw->x; i < VSIw->x + x; i++)
  1230.       {
  1231.       /* insert appropriate number of blanks */
  1232.         temp[i] = ' ';
  1233.         tempa[i] = VSIclrattrib;
  1234.       } /* for */
  1235.   } /* VSIinschar */
  1236.  
  1237. void VSIinsstring
  1238.   (
  1239.     int len,
  1240.     char *start
  1241.   )
  1242.   /* updates the screen to show insertion of a string of characters
  1243.     at the current cursor position. The text has already been
  1244.     inserted into the screen buffer. Also, the cursor position has
  1245.     already been updated, so the part needing redrawing begins at column
  1246.     (VSIw->x - len). */
  1247.   {
  1248.     if (VSIw->VSIDC)
  1249.         RSinsstring(VSIwn, VSIw->x - len, VSIw->y,
  1250.             VSIw->attrib, len, start);
  1251.     else
  1252.       /* redraw from beginning of text insertion to end of line.
  1253.         Trouble is, this isn't going to preserve the right attributes. */
  1254.         RSdraw(VSIwn, VSIw->x - len, VSIw->y, VSIw->attrib,
  1255.             VSIw->maxwidth - VSIw->x + len + 1, start);
  1256.   } /* VSIinsstring */
  1257.  
  1258. void VSIsave
  1259.   (
  1260.     void
  1261.   )
  1262.   /* saves the current cursor position and attribute settings. */
  1263.   {
  1264.     VSIw->Px = VSIw->x;
  1265.     VSIw->Py = VSIw->y;
  1266.     VSIw->Pattrib = VSIw->attrib;
  1267.   } /* VSIsave */
  1268.  
  1269. void VSIrestore
  1270.   (
  1271.     void
  1272.   )
  1273.   /* restores the last-saved cursor position and attribute settings. */
  1274.   {
  1275.     if (VSIw->Pattrib < 0)
  1276.       /* no previous save */
  1277.         return;
  1278.         
  1279.     VSIw->x = VSIw->Px;
  1280.     VSIw->y = VSIw->Py;
  1281.     VSIrange();
  1282.     VSIw->attrib = VSinattr(VSIw->Pattrib); /* hmm, this will clear the graphics character set selection */
  1283.   } /* VSIrestore */
  1284.  
  1285. void VSIdraw
  1286.   (
  1287.     int VSIwn, /* window number */
  1288.     int x, /* starting column */
  1289.     int y, /* line on which to draw */
  1290.     int a, /* text attributes */
  1291.     int len, /* length of text to draw */
  1292.     char *c /* pointer to text */
  1293.   )
  1294.   /* displays a piece of text (assumed to fit on a single line) on a
  1295.     screen, using the specified attributes, and clipping to the
  1296.     current visible region. Highlights any part of the text lying
  1297.     within the current selection. */
  1298.   {
  1299.     int x2, y2, offset;
  1300.  
  1301.     if (!VSIclip(&x, &y, &x2, &y2, &len, &offset))
  1302.         RSdraw(VSIwn, x, y, a, len, c + offset);
  1303.   } /* VSIdraw */
  1304.