home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Telnet 2.7b5 / source / Screens / vsintern.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-18  |  35.5 KB  |  1,391 lines  |  [TEXT/CWIE]

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