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

  1. /*
  2.  *
  3.  *      Virtual Screen Kernel Interface
  4.  *              (vsinterf.c)
  5.  *
  6.  *      by Gaige B. Paulsen
  7.  *
  8.  *    This file contains the control and interface calls for the NCSA
  9.  *  Virtual Screen Kernal.
  10.  *
  11.  *      VSinit(maxwidth)                    - Initialize the VSK
  12.  *      VSnewscreen(maxlines,scrnsave)    - Initialize a new screen.
  13.  *      VSdetach(w)                        - Detach screen w
  14.  *      VSredraw(w,x1,y1,x2,y2)            - redraw region for window w
  15.  *      VSwrite(w,ptr,len)                - write text @ptr, length len
  16.  *      VSclear(w)                        - clear w's real screen
  17.  *      VSkbsend(w,k,echo)                - send keycode k's rep. out window w (w/echo if req.)
  18.  *      VSclearall(w)                        - clear w's real and saved screen
  19.  *      VSreset(w)                        - reset w's emulator (as per TERM)
  20.  *      VSgetline(w,y)                    - get a ptr to w's line y
  21.  *      VSsetrgn(w,x1,y1,x2,y2)            - set local display region
  22.  *      VSscrolback(w,n)                    - scrolls window w back n lines
  23.  *      VSscrolforward(w,n)                - scrolls window w forward n lines
  24.  *      VSscrolleft(w,n)                     - scrolls window w left  n columns
  25.  *      VSscrolright(w,n)                     - scrolls window w right n columns
  26.  *      VSscrolcontrol(w,scrlon,offtop)    - sets scroll vars for w
  27.  *      VSgetrgn(w,&x1,&y1,&x2,&y2)        - returns set region
  28.  *      VSsnapshot(w)                          - takes a snapshot of w
  29.  *      VSgetlines(w)                        - Returns current # of lines
  30.  *      VSsetlines(w, lines)                - Sets the current # of lines to lines
  31.  *    
  32.  *        Version Date    Notes
  33.  *        ------- ------  ---------------------------------------------------
  34.  *        0.01    861102  Initial coding -GBP
  35.  *        0.10    861113  Added some actual program to this file -GBP
  36.  *        0.15    861114  Initiated Kludge Operation-GBP
  37.  *        0.50    8611VSPBOTTOM  Parameters added to VSnewscreen -GBP
  38.  *        0.90    870203    Added the kbsend routine -GBP
  39.  *        2.1        871130    NCSA Telnet 2.1 -GBP
  40.  *        2.2     880715    NCSA Telnet 2.2 -GBP
  41.  *
  42.  */
  43.  
  44. #ifdef MPW
  45. #pragma segment VS
  46. #endif
  47.  
  48. #define VSMASTER
  49.  
  50.  
  51. #include "rsinterf.proto.h"
  52. #include "rsmac.proto.h"
  53. #include "vsem.proto.h"
  54. #include "vsdata.h"
  55. #include "vskeys.h"
  56. #include "vsinit.h"
  57. #include "vsintern.proto.h"
  58. #include "Wind.h"
  59. #include "DlogUtils.proto.h"
  60. #include "maclook.proto.h"
  61. #include "errors.proto.h"
  62. #define DEBUGMAC
  63.  
  64. #include "vsinterf.proto.h"
  65.  
  66. extern TelInfoRec *TelInfo;
  67. extern WindRec    *screens;
  68. extern long        TempItemsDirID;
  69. extern short    TempItemsVRefNum;
  70.  
  71. short
  72.   /* Internal variables for use in managing windows */
  73.     VSmax = 0, /* max nr screens allowed */
  74.     VSinuse = 0; /* nr screens actually in existence */
  75. VSscrndata *VSscreens;
  76.  
  77. short VSinit
  78.   (
  79.     short max /* max nr screens to allow */
  80.   )
  81.   /* initializes virtual screen and window handling. */
  82.   {
  83.     short i;
  84.  
  85.     RSinitall(max);
  86.     VSmax = max;
  87.     VSIwn = 0;
  88.     if ((VSscreens = (VSscrndata *) myNewPtr(max * sizeof(VSscrndata))) == 0L)
  89.         return(-2);
  90.     for (i = 0; i < max; i++)
  91.       {
  92.         VSscreens[i].loc = 0L;
  93.         VSscreens[i].stat = 0;
  94.       } /* for */
  95.     return(0);
  96.   } /* VSinit */
  97.  
  98.  
  99. short VSiscapturing(short w) {                                /* BYU 2.4.18 */
  100.     return(VSscreens[w].captureRN);                    /* BYU 2.4.18 */
  101. }                                                        /* BYU 2.4.18 */
  102.  
  103. Boolean VSopencapture(short scrn_num, short w)
  104. {
  105.     UNUSED_ARG(scrn_num)
  106.     static short    captNumber = 1;
  107.     short            VRefNum;
  108.     long            DirID;
  109.     Str255            filename, tempString;
  110.     Str32            numstring;
  111.     Point            where = {100,100};
  112.     SFReply            sfr;
  113.     long            junk = 0;
  114.     OSErr            err;
  115.     
  116.     NumToString(captNumber++, numstring);
  117.     GetIndString(filename, MISC_STRINGS, CAPTFILENAME);
  118.     filename[++(filename[0])] = ' ';
  119.     pstrcat(filename, numstring);
  120.     
  121.     GetIndString(tempString,MISC_STRINGS,SAVE_CAPTURED_TEXT_STRING);
  122.     SFPutFile(where,tempString, filename, NULL, &sfr);
  123.     if (sfr.good) {
  124.         (void) GetWDInfo(sfr.vRefNum, &VRefNum, &DirID, &junk);
  125.  
  126.         err = HCreate(VRefNum, DirID, sfr.fName, 
  127.                     gApplicationPrefs->CaptureFileCreator, 'TEXT');
  128.         if (err == dupFNErr) {
  129.             HDelete(VRefNum, DirID, sfr.fName);
  130.             err = HCreate(VRefNum, DirID, sfr.fName,
  131.                             gApplicationPrefs->CaptureFileCreator, 'TEXT');
  132.             }
  133.             
  134.         if (err != noErr)
  135.             OperationFailedAlert(CANT_CREATE_FILE, 500, err);
  136.         else {        
  137.             err = HOpen(VRefNum, DirID, sfr.fName, fsRdWrPerm,
  138.                 &VSscreens[w].captureRN);
  139.             if (err != noErr) OperationFailedAlert(CANT_OPEN_FILE, 501, err);
  140.             else {
  141.                 SetEOF(VSscreens[w].captureRN, (long) 0);
  142.                 return(TRUE);
  143.                 }
  144.             }
  145.         }
  146.         
  147.     return(FALSE);
  148. }
  149.  
  150. void VSclosecapture(short w) {                                    /* BYU 2.4.18 */
  151.     FSClose(VSscreens[w].captureRN);                    /* BYU 2.4.18 */
  152.     VSscreens[w].captureRN = 0;                            /* BYU 2.4.18 */
  153. }                                                        /* BYU 2.4.18 */
  154.  
  155. void VScapture(unsigned char *ptr, short len) {        /* BYU 2.4.18 */
  156.     long ln = len;                                /* BYU 2.4.18 */
  157.     if (VSscreens[VSIwn].captureRN) {            /* BYU 2.4.18 */
  158.         unsigned char captbuf[512];                /* BYU 2.4.18 */
  159.         unsigned char *ptr2,*ptr3;                /* BYU 2.4.18 */
  160.         ptr2 = ptr;                                /* BYU 2.4.18 */
  161.         ptr3 = &captbuf[0];                        /* BYU 2.4.18 */
  162.         for (len = 0; len < ln; len++) {        /* BYU 2.4.18 */
  163.             if (*ptr2 >= 32 ||                     /* BYU 2.4.18 */
  164.                 *ptr2 == 13 ||                    /* BYU 2.4.18 */
  165.                 *ptr2 ==  9)                    /* BYU 2.4.18 */
  166.                 *(ptr3++) = *(ptr2++);            /* BYU 2.4.18 */
  167.             else {                                /* BYU 2.4.18 */
  168.                 ptr2++;                            /* BYU 2.4.18 */
  169.                 ln--;                            /* BYU 2.4.18 */
  170.             }                                    /* BYU 2.4.18 */
  171.         }                                        /* BYU 2.4.18 */
  172.         if (ln > 0) {                                                    /* BYU 2.4.18 */
  173.             if (FSWrite(VSscreens[VSIwn].captureRN, &ln, captbuf)) {    /* BYU 2.4.18 */
  174.                 FSClose(VSscreens[VSIwn].captureRN);                    /* BYU 2.4.18 */
  175.                 VSscreens[VSIwn].captureRN = 0;                            /* BYU 2.4.18 */
  176.             }                                            /* BYU 2.4.18 */
  177.         }                                            /* BYU 2.4.18 */
  178.     }                                                /* BYU 2.4.18 */
  179. }                                                    /* BYU 2.4.18 */
  180.  
  181. short    VSisprinting(short w)
  182. {
  183.     return((VSscreens[w].loc)->prredirect);
  184. }
  185.  
  186. void    ClosePrintingFile(short w)
  187. {
  188.     OSErr sts;
  189.     char tmp[80];
  190.  
  191.     putln("Attempting to remove print file");
  192.     
  193.     if ((sts=FSClose ((VSscreens[w].loc)->refNum)) != noErr) {
  194.         SysBeep(1);
  195.         sprintf(tmp,"FSClose: ERROR %d",sts); putln(tmp);
  196.         }
  197.     if ((sts=HDelete(TempItemsVRefNum, TempItemsDirID, (StringPtr)VSIw->fname)) != noErr) {
  198.         SysBeep(1);
  199.         sprintf(tmp,"HDelete: ERROR %d",sts); putln(tmp);
  200.         }
  201. }
  202.  
  203. short VSvalids
  204.   (
  205.     short w
  206.   )
  207.   /* validates a virtual screen number and sets it as the
  208.     current screen for subsequent operations if success.
  209.     Returns 0 iff success. */
  210.   {
  211.     if (VSinuse == 0)
  212.         return(-5); /* -5=no ports in use */
  213.     if (VSIwn == w)
  214.         return(0);    /* Currently set to that window */
  215.     if ((w > VSmax) || (w < 0))
  216.         return(-6); /* blown out the top of the stuff */
  217.     VSIwn = w;
  218.     if (VSscreens[w].stat != 1)
  219.         return(-3);/* not currently active */
  220.     VSIw = VSscreens[w].loc;
  221.     if (VSIw == 0L)
  222.         return(-3); /* no space allocated */
  223.     return(0);
  224.   } /* VSvalids */
  225.  
  226. VSscrn *VSwhereis(short i) /* screen number */
  227.   /* returns a pointer to the structure for the specified screen. */
  228.   {
  229.     VSvalids(i);
  230.     return(VSIw);
  231.   } /* VSwhereis */
  232.  
  233. void VSIclrbuf
  234.   (
  235.     void
  236.   )
  237.   /* clears out the text and attribute buffers for the current screen.
  238.     All text characters are set to blanks, and all attribute bytes
  239.     are set to zero. Doesn't update the display. */
  240.   {
  241.     register short j, i;
  242.     register char *tx;
  243.     register unsigned short *ta;
  244.     for (i = 0; i <= VSIw->lines; i++)
  245.       {
  246.         ta = &VSIw->attrst[i]->text[0];
  247.         tx = &VSIw->linest[i]->text[0];
  248.         for (j = 0; j <= VSIw->allwidth; j++)
  249.           {
  250.             *ta++ = 0;
  251.             *tx++ = ' ';
  252.           } /* for */
  253.       } /* for */
  254.   } /* VSIclrbuf */
  255.  
  256. short VSnewscreen
  257.   (
  258.     short maxlines, /* max lines to save in scrollback buffer */
  259.     short screensave, /* whether to have a scrollback buffer */
  260.     short numLines, //numLines initially on screen  (CCP 2.7)
  261.     short maxwid, /* number of columns on screen */
  262.     short forcesave    /* NCSA 2.5: force lines to be saved */
  263.   )
  264.   /* creates a new virtual screen, and returns its number. */
  265.   {
  266.  
  267.     if (maxlines < VSDEFLINES)
  268.         maxlines = VSDEFLINES;
  269.  
  270.     if (VSinuse >= VSmax)
  271.       /* too many screens in existence */
  272.         return(-1);
  273.     VSIwn = 0;
  274.     while ((VSIwn < VSmax) && (VSscreens[VSIwn].stat == 1))
  275.         VSIwn++;
  276.     if (VSIwn >= VSmax)
  277.       /* shouldn't occur? */
  278.         return(-1);
  279.     numLines -= 1;  //correct for internal use
  280.     
  281. /*
  282. *  Fill initial scrollback buffer and screen storage space.
  283. *
  284. *  Memory allocation rules:
  285. *  line->mem == 0 if not a memory allocation, line->mem == 1 if it is the first
  286. *     VSline in a block (indeterminate size, may be size == 1)
  287. *  
  288. *  attributes array is ALWAYS allocated as one block.  Internally represented and
  289. *  manipulated as a linked list of lines, but only one of the lines will have 
  290. *  line->mem == 1.  This list is always supposed to be circular (it is never
  291. *  extended, as attributes are never scrolled back).
  292. *
  293. *  scrollback and screen line buffer space is allocated in large blocks.  Each
  294. *  block will have line->mem == 1 if the pointer to that VSline is "free"able.
  295. *  This list will either be circular (which means it has reached its full size),
  296. *  or it will have a NULL next field at the end.  During scrolling, the end may
  297. *  be augmented until VSIw->numlines > VSIw->maxlines or we run out of memory.
  298. *  Typically allocate memory 100 lines at a time in two blocks, one is the VSline
  299. *  list, the other is the mem for the character storage.
  300. *
  301. */
  302.  
  303. /* All memory allocation for this function is done at once, to help damage control in 
  304. low memory situations */
  305.  
  306.     if ((VSscreens[VSIwn].loc = VSIw = (VSscrn *) myNewPtr(sizeof(VSscrn))) == 0L)
  307.         return(-2);
  308.  
  309.     VSIw->lines = numLines;
  310.     //VSIw->lines = 23; CCP 2.7 set this from the start
  311.  
  312.     VSIw->linest = VSInewlinearray(VSIw->lines + 1);
  313.     if (VSIw->linest == NULL)
  314.      {
  315.         DisposePtr((Ptr)VSIw);
  316.         VSscreens[VSIwn].loc = VSIw = NULL;
  317.         return (-2);
  318.     }    
  319.     
  320.     VSIw->attrst = VSInewattrlinearray(VSIw->lines + 1);
  321.     if (VSIw->attrst == NULL)
  322.      {
  323.         DisposePtr((Ptr)VSIw->linest);
  324.         DisposePtr((Ptr)VSIw);
  325.         VSscreens[VSIwn].loc = VSIw = NULL;
  326.         return (-2);
  327.     }    
  328.  
  329.     VSIw->tabs = (char *) myNewPtr(132);        /* NCSA: SB - allow 132 column mode */
  330.     if (VSIw->tabs == NULL)  /* CCP: Hey?  Why not check if we got it?! */
  331.     {
  332.         DisposePtr((Ptr)VSIw->attrst);
  333.         DisposePtr((Ptr)VSIw->linest);
  334.         DisposePtr((Ptr)VSIw);
  335.         VSscreens[VSIwn].loc = VSIw = NULL;
  336.         return (-2);
  337.     }
  338.  
  339.     VSIw->allwidth = 131;                /* NCSA: SB - always allocate max lines */
  340.  
  341.     if (screensave)
  342.         VSIw->buftop = VSInewlines(VSIw->lines + 1 + VSDEFLINES,1); /* screen lines plus some initial preallocated scrollback space */
  343.     else
  344.         VSIw->buftop = VSInewlines(VSIw->lines + 1,1); /* screen lines, no scrollback */
  345.     if (VSIw->buftop == NULL)
  346.     {
  347.         DisposePtr((Ptr)VSIw->tabs);
  348.         DisposePtr((Ptr)VSIw->attrst);
  349.         DisposePtr((Ptr)VSIw->linest);
  350.         DisposePtr((Ptr)VSIw);
  351.         VSscreens[VSIwn].loc = VSIw = NULL;
  352.         return(-2);
  353.     }
  354.     VSIw->linest[0] = VSIw->buftop;
  355.     VSIw->attrst[0] = (VSattrlinePtr)VSInewlines(VSIw->lines + 1,2);        /* new space for attributes (these are never scrolled back) */
  356.     if (VSIw->attrst[0] == NULL)
  357.     {
  358.         VSIfreelinelist(VSIw->buftop);
  359.         DisposePtr((Ptr)VSIw->tabs);
  360.         DisposePtr((Ptr)VSIw->attrst);
  361.         DisposePtr((Ptr)VSIw->linest);
  362.         DisposePtr((Ptr)VSIw);
  363.         VSscreens[VSIwn].loc = VSIw = NULL;
  364.         return(-2);
  365.     }
  366.  
  367.     VSIw->vistop = VSIw->scrntop = VSIw->buftop;    /* initial view = screen */
  368.  
  369.     VSIlistndx(VSIw->scrntop, VSIw->attrst[0]);    /* Set up screen arrays */
  370.     
  371.     VSIw->attrst[0]->prev = VSIw->attrst[VSIw->lines]; /* make attribute list circular, since it is never extended */
  372.     VSIw->attrst[VSIw->lines]->next = VSIw->attrst[0];
  373.     
  374.     if (!screensave)
  375.     {   /* make text line list circular to indicate no extensions */
  376.         VSIw->linest[0]->prev = VSIw->linest[VSIw->lines];
  377.         VSIw->linest[VSIw->lines]->next = VSIw->linest[0];
  378.     } /* if */
  379.     
  380.     VSIw->maxlines = maxlines;
  381.     VSIw->numlines = 0;
  382.     VSscreens[VSIwn].captureRN = 0;        /* BYU 2.4.18 - capture file's RefNum */
  383.     VSIw->id = 'VSCR';
  384.     VSIw->maxwidth = maxwid - 1;
  385.     VSIw->savelines = screensave;
  386.     VSIw->forcesave = forcesave;        /* NCSA 2.5 */
  387.     VSIw->attrib = 0;
  388.     VSIw->Pattrib = -1; /* initially no saved attribute */
  389.     VSIw->x = 0;
  390.     VSIw->y = 0;
  391.     VSIw->charset = 0;
  392.     VSIw->G0 = 0;
  393.     VSIw->G1 = 1;
  394.     VSIw->DECAWM = 0;
  395.     VSIw->DECCKM = 0;
  396.     VSIw->DECPAM = 0;
  397.     VSIw->DECORG = 0;
  398.     VSIw->IRM = 0;
  399.     VSIw->escflg = 0;
  400.     VSIw->top = 0;
  401.     VSIw->bottom = numLines;
  402.     VSIw->parmptr = 0;
  403.     VSIw->Rtop = 0;
  404.     VSIw->Rleft = 0;
  405.     VSIw->Rright = maxwid - 1;
  406.     VSIw->Rbottom = numLines;
  407.     VSIw->ESscroll = 1;
  408.     VSIw->prredirect = 0;                        /* LU */
  409.     VSIw->prbuf = 0;                            /* LU */
  410.     VSIw->refNum = -1;                            /* LU */
  411.     VSIw->possibleForce = 0;
  412.     VSIclrbuf();
  413.     VSItabinit();
  414.     VSscreens[VSIwn].stat = 1;
  415.     VSinuse++;
  416.  
  417.     return(VSIwn);
  418. } /* VSnewscreen */
  419.  
  420. short VSdestroy(short w) /* screen number */
  421.   /* gets rid of a virtual screen. */
  422.   {
  423.     if (VSvalids(w) != 0)
  424.         return(-3);
  425.     VSIfreelines();
  426.     VSIfreelinelist((VSlinePtr)VSIw->attrst[0]);
  427.     if(VSIw->attrst)
  428.         DisposPtr((Ptr) VSIw->attrst);
  429.     if(VSIw->linest)
  430.         DisposPtr((Ptr) VSIw->linest);
  431.     if(VSIw->tabs)
  432.         DisposPtr(VSIw->tabs);
  433.     if(VSIw)
  434.         DisposPtr((Ptr) VSIw);
  435.     VSscreens[w].stat = 0;
  436.     VSIwn = -1;
  437.     VSinuse--;            /* SCA '87 */
  438.     return(0);
  439.   } /* VSdestroy */
  440.  
  441.  
  442. void VSredrawLine(short w) //redraws current line
  443. {
  444.     if (VSvalids(w) != 0)
  445.         return;
  446.     VSredraw(w, 0, VSIw->y,VSIw->maxwidth, VSIw->y); 
  447.     VSIcuroff(w);
  448. }
  449.  
  450.  
  451. short VSredraw
  452.   (
  453.     short w,         // window to redraw */
  454.     short x1,         
  455.     short y1,
  456.     short x2,
  457.     short y2
  458.   )
  459.   /* redisplays the specified portion of a virtual screen. */
  460.   {
  461.     VSlinePtr ypt;
  462.     VSattrlinePtr ypa;
  463.     short y;
  464.     short tx1, tx2, ty1, ty2, tn, offset;
  465.  
  466.     if (VSvalids(w) != 0)
  467.         return(-3);
  468.  
  469.     x1 += VSIw->Rleft;    // Make local coords global again
  470.     x2 += VSIw->Rleft;
  471.     y1 += VSIw->Rtop;
  472.     y2 += VSIw->Rtop;
  473.  
  474.     if (x1 < 0) x1 = 0;
  475.     else if (x1 > VSIw->maxwidth) x1 = VSIw->maxwidth;
  476.     if (x2 < 0) x2 = 0;
  477.     else if (x2 > VSIw->maxwidth) x2 = VSIw->maxwidth;
  478.     if (y1 < -VSIw->numlines) y1 = -VSIw->numlines;
  479.     else if (y1 > VSIw->lines) y1 = VSIw->lines;
  480.     if (y2 < -VSIw->numlines) y2 = -VSIw->numlines;    /* limit to amount of scrollback */
  481.     else if (y2 > VSIw->lines) y2 = VSIw->lines;
  482.  
  483.     tx1 = x1;        // Set up to clip redraw area to visible area
  484.     tx2 = x2;
  485.     ty1 = y1;
  486.     ty2 = y2;
  487.     tn = -1;        // so we include more than 1 line
  488.     
  489.     if (VSIclip(&tx1, &ty1, &tx2, &ty2, &tn, &offset)!=0) return 0;        // test clip region
  490.     
  491.     VSIcuroff(w);                         // temporarily hide cursor
  492.     RSerase(w, tx1, ty1, tx2, ty2);        // Erase the offending area
  493.  
  494.     // draw visible part of scrollback buffer
  495.     if (y1 < 0) {
  496.     
  497.         tx1 = x1;        // Set up to clip redraw area to visible area of scrollback buffer
  498.         tx2 = x2;
  499.         ty1 = y1;
  500.         ty2 = (y2>=0) ? -1 : y2;
  501.         tn = -1;
  502.         
  503.         if (!VSIclip(&tx1, &ty1, &tx2, &ty2, &tn, &offset)) {
  504.             ypt = VSIw->vistop;
  505.             for(y=VSIw->Rtop; y<y1; y++)
  506.                 ypt = ypt->next;        // Get pointer to top line we need
  507.     
  508.             for (y=ty1; y<=ty2; y++) {
  509.                 RSdraw(w, tx1, y, 0, tn, ypt->text + VSIw->Rleft +tx1);
  510.                 ypt = ypt->next;
  511.             }
  512.         }
  513.         y1 = 0;            // continue with on-screen buffer, if any
  514.     }
  515.  
  516.     // draw visible part of on-screen buffer, taking account of attributes
  517.     if (y2 >= 0) {
  518.     
  519.         tx1 = x1;        // Set up to clip redraw area to visible area of on-screen buffer
  520.         tx2 = x2;
  521.         ty1 = y1;
  522.         ty2 = y2;
  523.         tn = -1;
  524.  
  525.         if (!VSIclip(&tx1, &ty1, &tx2, &ty2, &tn, &offset)) {
  526.         
  527.             ypt = VSIw->linest[VSIw->Rtop+ty1];
  528.             ypa = VSIw->attrst[VSIw->Rtop+ty1];
  529.             
  530.             for (y=ty1; y<=ty2; y++) {
  531.                 char *pt;
  532.                 unsigned short *pa;
  533.                 unsigned short lasta;
  534.                 short x, lastx;
  535.             
  536.                 pt = ypt->text + VSIw->Rleft;
  537.                 pa = ypa->text + VSIw->Rleft;
  538.                 
  539.                 lastx = tx1;
  540.                 lasta = pa[tx1];
  541.                 for(x=tx1+1; x<=tx2; x++) {
  542.                     if (pa[x]!=lasta) {
  543.                         RSdraw(w, lastx, y, lasta, x-lastx, pt + lastx);
  544.                         lastx = x;
  545.                         lasta = pa[x];
  546.                     }
  547.                 }
  548.                 if (lastx<=tx2)
  549.                     RSdraw(w, lastx, y, lasta, tx2-lastx+1, pt + lastx);
  550.                 
  551.                 ypt = ypt->next;
  552.                 ypa = ypa->next;
  553.             }
  554.         }
  555.     }
  556.  
  557.     VSIcurson(w, VSIw->x, VSIw->y, 0); /* restore cursor at original position */
  558.  
  559.     tx1 = ty1 = 0;
  560.     tn = 132;
  561.     return(0);
  562.   } /* VSredraw */
  563.  
  564. short VSwrite
  565.   (
  566.     short w, /* screen to draw into */
  567.     char *ptr, /* pointer to text string */
  568.     short len  /* length of text string */
  569.   )
  570.   /* sends a stream of characters to the specified window. */
  571.   {
  572. //      _profile = 1;
  573.     if (len == 0)
  574.         return 0;
  575.     if (VSvalids(w) != 0)
  576.         return(-3);
  577.     VSIcuroff(w); /* hide cursor momentarily */
  578.     VSem((unsigned char *) ptr, len);    /* BYU LSC - interpret the character stream */
  579.     VSIcurson(w, VSIw->x, VSIw->y, 1); /* restore cursor, force it to be visible. */
  580. //    _profile = 0;
  581.     return(0);
  582.   } /* VSwrite */
  583.  
  584. short VSIgetNextTabDistance(void)
  585. {
  586.     short current;
  587.     
  588.     if (VSIw->x >= VSIw->maxwidth)
  589.         return(0);
  590.     current = VSIw->x + 1;
  591.     while ((VSIw->tabs[current] != 'x')&&(current < VSIw->maxwidth))
  592.         current++;
  593.     return (current - VSIw->x);
  594. }
  595.  
  596.  
  597.                                                             // MAT--We need to define how big the Queue is
  598.                                                             // MAT--for sending the cursor characters.
  599.                                                             // MAT--Since MacTCP doesn't like 30+ individual
  600. #define MATSbufSize    254                                        // MAT--SendChar requests.
  601. void VSpossendEM                                            // MAT--we can change this to support EMACS
  602.   (                                                            // MAT--style movement commands.
  603.     short w, /* affected screen */                                                // MAT--
  604.     short x, /* column to move to */                                                // MAT--
  605.     short y, /* line to move to */                                                // MAT--
  606.     short echo /* local echo flag */                                                // MAT--
  607.   )                                                                                // MAT--
  608.   /* sends a stream of VT100 cursor-movement sequences to move the                // MAT--
  609.     cursor on the specified screen to the specified position. */                // MAT--
  610. {                                                                                // MAT--
  611.     UNUSED_ARG(echo)
  612.     static char                                                                    // MAT--
  613.             tt[MATSbufSize] = "";                                                // MAT--
  614.         char curschar;                                                            // MAT--
  615.         short localCount;                                                            // MAT--
  616.                                                                                 // MAT--
  617.                                                                                 // MAT--
  618.     if (x < 0 || y < 0 || x > VSIw->maxwidth || y > VSIw->lines)                // MAT--
  619.         return;                                                                    // MAT--
  620.   /* convert x and y to relative distance to move */                            // MAT--
  621.     x -= VSIw->x;                                                                // MAT--
  622.     y -= VSIw->y;                                                                // MAT--
  623.                                                                                 // MAT--
  624.     curschar = '\002'; /* EMACS cursor left */                                    // MAT--
  625.     localCount=0;
  626.     while (x < 0 && localCount < MATSbufSize)                                    // MAT--
  627.       {                                                                            // MAT--
  628.         tt[localCount] = curschar;                                                // MAT--
  629.         x++; localCount++;                                                        // MAT--
  630.       } /* while */                                                                // MAT--
  631.     if(localCount)    RSsendstring(w, tt, localCount);                            // MAT--
  632.  
  633.     curschar = '\016'; /* EMACS cursor down */                                    // MAT--
  634.     localCount=0;
  635.     while (y > 0 && localCount < MATSbufSize)                                    // MAT-- why we check to see if localCount is < MATSbufSize
  636.       {                                                                            // MAT-- I dont know. But If they had a window > 254 columns
  637.         tt[localCount] = curschar;                                                // MAT-- maybe it's a good idea.
  638.         y--; localCount++;                                                        // MAT-- but it never hurts to be safe.
  639.       } /* while */                                                                // MAT--
  640.     if(localCount)    RSsendstring(w, tt, localCount);                            // MAT--
  641.  
  642.     curschar = '\020'; /* EMACS cursor up */                                    // MAT--
  643.     localCount=0;
  644.     while (y < 0 && localCount < MATSbufSize)                                    // MAT--
  645.       {                                                                            // MAT--
  646.         tt[localCount] = curschar;                                                // MAT--
  647.         y++; localCount++;                                                        // MAT--
  648.       } /* while */                                                                // MAT--
  649.     if(localCount)    RSsendstring(w, tt, localCount);                            // MAT--
  650.  
  651.     curschar = '\006'; /* EMACS cursor right */                                    // MAT--
  652.     localCount=0;
  653.     while (x > 0 && localCount < MATSbufSize)                                    // MAT--
  654.       {                                                                            // MAT--
  655.         tt[localCount] = curschar;                                                // MAT--
  656.         x--; localCount++;                                                        // MAT--
  657.       } /* while */                                                                // MAT--
  658.     if(localCount)    RSsendstring(w, tt, localCount);                            // MAT--
  659.                                                                                 // MAT--
  660.     if (0)    //(note: supposed to look for "echo" here)                            // MAT--
  661.       {                                                                            // MAT--
  662.         VSIcuroff(w);                                                            // MAT--
  663.         VSIw->x = x;                                                            // MAT--
  664.         VSIw->y = y;                                                            // MAT--
  665.         VSIcurson(w, VSIw->x, VSIw->y, 1); /* Force Move */                        // MAT--
  666.       } /* if */                                                                // MAT--
  667.   } /* VSpossendEM */                    // changed comment                        // MAT--
  668.      
  669. void VSpossend
  670.   (
  671.     short w, /* affected screen */
  672.     short x, /* column to move to */
  673.     short y, /* line to move to */
  674.     short echo /* local echo flag */
  675.   )
  676.   /* sends a stream of VT100 cursor-movement sequences to move the
  677.     cursor on the specified screen to the specified position. */
  678. {
  679.     static char
  680.         VSkbax[] = "\033O ",        /* prefix for auxiliary code */
  681.         VSkban[] = "\033[ ";        /* prefix for arrows normal */
  682.     char *vskptr;
  683.  
  684.     if (VSvalids(w) != 0)
  685.         return;
  686.     
  687.     
  688. /* NCSA: SB - This would bomb before.  You need to get the screens # from the 
  689.                 translation routine before you access the record! */      
  690.     if (screens[findbyVS(w)].arrowmap) {    /* NCSA: SB - get the CORRECT screens # */
  691.         VSpossendEM(w,x,y,echo);            // MAT--  call our cursor movement routine
  692.         return;                             // MAT--  then exit
  693.     }
  694.  
  695.     if (VSIw->DECPAM && VSIw->DECCKM)
  696.         vskptr = VSkbax;
  697.     else
  698.         vskptr = VSkban;
  699.     if (x < 0 || y < 0 || x > VSIw->maxwidth || y > VSIw->lines)
  700.         return;
  701.   /* convert x and y to relative distance to move */
  702.     x -= VSIw->x;
  703.     y -= VSIw->y;
  704.  
  705.     vskptr[2] = 'D'; /* cursor left */
  706.     while (x < 0)
  707.       {
  708.         x++;
  709.         RSsendstring(w, vskptr, 3);
  710.       } /* while */
  711.  
  712.     vskptr[2] = 'B'; /* cursor down */
  713.     while (y > 0)
  714.       {
  715.         y--;
  716.         RSsendstring(w, vskptr, 3);
  717.       } /* while */
  718.     vskptr[2] = 'A'; /* cursor up */
  719.     while (y < 0)
  720.       {
  721.         y++;
  722.         RSsendstring(w, vskptr, 3);
  723.       } /* while */
  724.     vskptr[2] = 'C'; /* cursor right */
  725.     while (x > 0)
  726.       {
  727.         x--;
  728.         RSsendstring(w, vskptr, 3);
  729.       } /* while */
  730.  
  731.     if (echo)
  732.       {
  733.         VSIcuroff(w);
  734.         VSIw->x = x;
  735.         VSIw->y = y;
  736.         VSIcurson(w, VSIw->x, VSIw->y, 1); /* Force Move */
  737.       } /* if */
  738.   } /* VSpossend */
  739.  
  740. char VSkbsend
  741.   (
  742.     short w, /* active window */
  743.     unsigned char k, /* special key code if > 128, else ascii code */
  744.     short echo /* local echo flag */
  745.   )
  746.   /* sends the appropriate sequence for the specified key, taking due
  747.     account of terminal mode settings. */
  748.   {
  749.     static char
  750.         VSkbkn[] = "\033O ",        /* prefix for keypad normal */
  751.         VSkbax[] = "\033O ",        /* prefix for auxiliary code*/
  752.         VSkban[] = "\033[ ",        /* prefix for arrows normal */
  753.         VSkbfn[] = "\033O ",        /* prefix for function keys */        /* BYU 2.4.12 */
  754.         VSk220[] = "\033[  ~";        /* prefix for vt220 keys */            /* BYU 2.4.12 */
  755.     char *vskptr;
  756.     short vskplen;
  757.  
  758.  
  759.     if (VSvalids(w) != 0)
  760.         return(-3);
  761.  
  762.     if ( screens[findbyVS(w)].arrowmap && (k <= VSLT) && (k >= VSUP) )    // MAT--
  763.                                         // MAT-- important...we need to check this first before
  764.         {                                // MAT-- the next if(…) statement gets its hands on the string.
  765.             switch (k) {                // MAT--  do the mapping from arrowkeys -> EMACS ctrl keys.
  766.                 case VSLT:                // MAT-- 
  767.                     k = 0x02;            // MAT-- ^B            Question: Is there a way to find out if the option
  768.                     break;                // MAT--                       key was held down with this character?
  769.                 case VSRT:                // MAT--             I didn't want to declare myEvent an extern
  770.                     k = 0x06;            // MAT-- ^F            (I didn't know if that was a no-no)
  771.                     break;                // MAT--             If I can.....let me know, I want to make
  772.                 case VSUP:                // MAT--             option-arrowkey's do useful things too
  773.                     k = 0x10;            // MAT-- ^P
  774.                     break;                // MAT--             checking the keymap would be a kludge here.
  775.                 case VSDN:                // MAT-- 
  776.                     k = 0x0e;            // MAT-- ^N
  777.                     break;                // MAT-- 
  778.             }    /* switch k */            // MAT--
  779.             RSsendstring(w,(char *)&k,1);        // MAT-- send the character
  780.             return(0);                    // MAT--
  781.         }                                // MAT--
  782.  
  783.  
  784.     if (k < VSF10)                            /* BYU 2.4.12 */
  785.       /* 7-bit ascii code -- send as is */
  786.         RSsendstring(w,(char *) &k, 1);        /* BYU LSC */
  787.     
  788.     /* Keypad (Not Application Mode): 0-9 , - . Enter */    
  789.     if ((k > VSLT) && (k < VSF1) && (!VSIw->DECPAM)) {
  790.         RSsendstring(w, &VSIkpxlate[0][k - VSUP], 1);
  791.         if (echo)
  792.             VSwrite(w, &VSIkpxlate[0][k - VSUP], 1);
  793.         if (k == VSKE)
  794.             RSsendstring(w, "\012", 1);
  795.         return(0);
  796.       } /* if */
  797.     
  798.       
  799.     if (VSIw->DECPAM && VSIw->DECCKM) {
  800.       /* aux kp mode */
  801.           vskptr = VSkbax;
  802.         vskplen = 3;
  803.         vskptr[2] = VSIkpxlate[1][k - VSUP];    /* BYU 2.4.12 */
  804.       }
  805.     else if (k < VSUP) {                        /* BYU 2.4.12 */
  806.         vskptr = VSk220;                        /* BYU 2.4.12 */
  807.         vskplen = VSIkplen[k - VSF10];            /* BYU 2.4.12 */
  808.         vskptr[2] = VSIkpxlate2[k - VSF10];        /* BYU 2.4.12 */
  809.         vskptr[3] = VSIkpxlate3[k - VSF10];        /* BYU 2.4.12 */
  810.     } else {                                    /* BYU 2.4.12 */
  811.         vskplen = 3;                            /* BYU 2.4.12 */
  812.         if (k < VSK0) {                            /* BYU 2.4.13 - arrow keys */
  813.             vskptr = VSkban;                    /* BYU 2.4.12 */
  814.             if (VSIw->DECCKM)                    /* BYU 2.4.13 */
  815.                 vskptr[1] = 79;                    /* BYU 2.4.13 */
  816.             else                                /* BYU 2.4.13 */
  817.                 vskptr[1] = 91;                    /* BYU 2.4.13 */
  818.         }                                        /* BYU 2.4.13 */
  819.         else if (k < VSF1)                         /* BYU 2.4.12 */
  820.             vskptr = VSkbkn;                    /* BYU 2.4.12 */
  821.         else                                     /* BYU 2.4.12 */
  822.             vskptr = VSkbfn;                    /* BYU 2.4.12 */
  823.                                                 /* BYU 2.4.12 */
  824.         vskptr[2] = VSIkpxlate[1][k - VSUP];    /* BYU 2.4.12 */
  825.     }                                            /* BYU 2.4.12 */
  826.  
  827.     RSsendstring(w, vskptr, vskplen);
  828.     if (echo)
  829.         VSwrite(w, vskptr, vskplen);
  830.     return(0);
  831.   } /* VSkbsend */
  832.  
  833. short VSreset
  834.   (
  835.     short w
  836.   )
  837.   /* resets virtual terminal settings to default state, clears screen
  838.     and homes cursor. */
  839.   {
  840.     if (VSvalids(w) != 0)
  841.         return(-3);
  842.     VSIcuroff(w);            /* NCSA: SB -- get rid of extraneous cursor BS */
  843.     VSIreset(); /* causes cursor to disappear */
  844.     VSIcurson(w, VSIw->x, VSIw->y, 1); /* redisplay cursor at home position */
  845.     return(0);
  846.   } /* VSreset */
  847.  
  848. void VSscrolright
  849.   (
  850.     short w,
  851.     short n /* number of columns to scroll */
  852.   )
  853.   /* moves the view of the virtual screen within its window the
  854.     specified number of columns to the right. */
  855.   {
  856.     short sn, lmmax;
  857.  
  858.     if (VSvalids(w) != 0)
  859.         return;
  860.  
  861.   /* limit scroll amount against number of invisible columns */
  862.     lmmax = VSIw->maxwidth - (VSIw->Rright - VSIw->Rleft);
  863.     if (VSIw->Rleft + n > lmmax)
  864.         n = lmmax - VSIw->Rleft; /* can't scroll any further right than this */
  865.     if (n == 0)
  866.         return;                                    /* Do nothing if appropriate */
  867.  
  868.     VSIcuroff(w); /* temporarily hide cursor */
  869.     VSIw->Rleft += n; /* update visible region */
  870.     VSIw->Rright += n;
  871.     sn = VSIw->Rbottom - VSIw->Rtop;
  872.     RSmargininfo(w, lmmax, VSIw->Rleft);    /* update horizontal scroll bar */
  873.     RSdelcols(w, n); /* scroll the window contents */
  874.     VSIcurson(w, VSIw->x, VSIw->y, 0); /* restore cursor at original position */
  875.   /* redraw newly-revealed portion of screen */
  876.     VSredraw(w, (VSIw->Rright - VSIw->Rleft) - n, 0, (VSIw->Rright - VSIw->Rleft), sn);
  877.   } /* VSscrolright */
  878.  
  879. void VSscrolleft
  880.   (
  881.     short w,
  882.     short n /* number of columns to scroll */
  883.   )
  884.   /* moves the view of the virtual screen within its window the
  885.     specified number of columns to the left. */
  886.   {
  887.     short sn, lmmax;
  888.  
  889.     if (VSvalids(w) != 0)
  890.         return;
  891.  
  892.     lmmax = VSIw->maxwidth - (VSIw->Rright - VSIw->Rleft); /* number of invisible columns */
  893.  
  894.     if (n > VSIw->Rleft)
  895.         n = VSIw->Rleft; /* can't scroll any further left than this */
  896.     if (n == 0)
  897.         return;                                    /* Do nothing if appropriate */
  898.  
  899.     VSIcuroff(w); /* temporarily hide cursor */
  900.     VSIw->Rleft -= n; /* update visible region */
  901.     VSIw->Rright -= n;
  902.     sn = VSIw->Rbottom - VSIw->Rtop;
  903.     RSmargininfo(w, lmmax, VSIw->Rleft); /* update horizontal scroll bar */
  904.     RSinscols(w, n); /* scroll the window contents */
  905.     VSIcurson(w, VSIw->x, VSIw->y, 0); /* restore cursor at original position */
  906.     VSredraw(w, 0, 0, n, sn); /* redraw newly-revealed portion of screen */
  907.   } /* VSscrolleft */
  908.  
  909. short VSscroltop( short w /* which window */)                    /* JMB 2.6 */
  910. {                                                            /* JMB 2.6 */
  911.     if (VSvalids(w) != 0)                                    /* JMB 2.6 */
  912.         return(-3);                                            /* JMB 2.6 */
  913.                                                             /* JMB 2.6 */
  914.     return(VSscrolback(w, VSIw->Rtop + VSIw->numlines)); /* can't scroll back any further than this */
  915. }                                                            /* JMB 2.6 */
  916.  
  917. short VSscrolback
  918.   (
  919.     short w, /* which window */
  920.     short in /* number of lines to scroll */
  921.   )
  922.   /* moves the view of the virtual screen within its window the
  923.     specified number of lines upwards. */
  924.   {
  925.     short sn, n;
  926.  
  927.     n = in;
  928.  
  929.     if (VSvalids(w) != 0)
  930.         return(-3);
  931.  
  932.     if (VSIw->numlines < (n - VSIw->Rtop))
  933.         n = VSIw->Rtop + VSIw->numlines; /* can't scroll back any further than this */
  934.     if (n <= 0)
  935.         return(0);            /* Dont be scrollin' no lines.... */
  936.  
  937.     VSIcuroff(w); /* temporarily hide cursor */
  938.  
  939.     VSIw->Rtop = VSIw->Rtop - n; /* adjust the visible region */
  940.     VSIw->Rbottom = VSIw->Rbottom - n;
  941.  
  942.   /* find the line list element for the new topmost visible line */
  943.     sn = n;
  944.     while (sn-- > 0)
  945.       {
  946. #ifdef DEBUGMAC
  947.         if (VSIw->vistop->prev == 0L)
  948.             DebugStr("\pVSscrolback -- something wrong with linked list structure");
  949. #endif DEBUGMAC
  950.         VSIw->vistop = VSIw->vistop->prev;
  951.       } /* while */
  952.  
  953.     sn = VSIw->Rbottom - VSIw->Rtop;
  954.   /* update vertical scroll bar */
  955.     RSbufinfo(w, VSIw->numlines, VSIw->Rtop, VSIw->Rbottom);
  956.  
  957.     if (n <= VSIw->lines)
  958.       {
  959.         RSinslines(w, 0, sn, n, 0);    /* scroll, preserving current selection */
  960.         VSIcurson(w, VSIw->x, VSIw->y, 0); /* restore cursor at original position */
  961.         VSredraw(w, 0, 0, VSIw->maxwidth, n - 1); /* redraw newly-revealed portion */
  962.       }
  963.     else
  964.       /* currently-visible contents scrolled completely off the screen--
  965.         just redraw everything */
  966.         VSredraw(w, 0, 0, VSIw->maxwidth, sn);
  967.  
  968.     return(0);
  969.   } /* VSscrolback */
  970.  
  971. short VSscrolforward
  972.   (
  973.     short w, /* which window */
  974.     short n /* number of lines to scroll */
  975.   )
  976.   /* moves the view of the virtual screen within its window the
  977.     specified number of lines downwards. */
  978.   {
  979.     short sn;
  980.  
  981.     if (VSvalids(w) != 0)
  982.         return(-3);
  983.  
  984.     if (n > VSIw->lines - VSIw->Rbottom)
  985.         n = VSIw->lines - VSIw->Rbottom; /* can't scroll any further forward than this */
  986.     if (n <= 0)
  987.         return(0);            /* Dont be scrollin' no lines.... */
  988.  
  989.     VSIcuroff(w); /* temporarily hide cursor */
  990.  
  991.     VSIw->Rtop = n + VSIw->Rtop; /* adjust the visible region */
  992.     VSIw->Rbottom = n + VSIw->Rbottom;
  993.  
  994.   /* find the line list element for the new topmost visible line */
  995.     sn = n;
  996.     while (sn-- > 0)
  997.       {
  998. #ifdef DEBUGMAC
  999.         if (VSIw->vistop->next == nil)
  1000.             DebugStr("\pVSscrolforward -- something wrong with linked list structure");
  1001. #endif DEBUGMAC
  1002.         VSIw->vistop = VSIw->vistop->next;
  1003.       } /* while */
  1004.  
  1005.     sn = VSIw->Rbottom - VSIw->Rtop;
  1006.   /* update vertical scroll bar */
  1007.     RSbufinfo(w, VSIw->numlines, VSIw->Rtop, VSIw->Rbottom);
  1008.  
  1009.     if (n <= VSIw->lines)
  1010.       {
  1011.         RSdellines(w, 0, sn, n, 0);    /* scroll, preserving current selection */
  1012.         VSIcurson(w, VSIw->x, VSIw->y, 0); /* restore cursor at original position */
  1013.         VSredraw(w, 0, (sn + 1) - n, VSIw->maxwidth, sn); /* redraw newly-revealed portion */
  1014.       } /* if */
  1015.     else
  1016.       /* currently-visible contents scrolled completely off the screen--
  1017.         just redraw everything */
  1018.         VSredraw(w, 0, 0, VSIw->maxwidth, sn);
  1019.  
  1020.     return(0);
  1021.   } /* VSscrolforward */
  1022.  
  1023. short VSsetrgn
  1024.   (
  1025.     short w,
  1026.     short x1, /* leftmost column */
  1027.     short y1, /* uppermost line */
  1028.     short x2, /* rightmost column */
  1029.     short y2 /* bottommost line */
  1030.   )
  1031.   /* sets the visible region for the specified virtual screen
  1032.     in its window, scrolling its contents as appropriate. Assumes
  1033.     that either the vertical bounds or the height of the region has
  1034.     changed, but not both, and similarly that the horizontal bounds
  1035.     or the width has changed, but not both. */
  1036.   {
  1037.     short n;
  1038.  
  1039.     if (VSvalids(w) != 0)
  1040.         return(-3);
  1041.  
  1042.     VSIw->Rbottom = VSIw->Rtop + (y2 - y1); /* make change in height of visible region first */
  1043.  
  1044.     if (x2 > VSIw->maxwidth)
  1045.       {
  1046.       /* trying to make columns visible which aren't there--
  1047.         adjust the left and right boundaries to avoid this */
  1048.         n = x2 - VSIw->maxwidth; /* how far to adjust to the left */
  1049.         if (n > x1)
  1050.             n = x1; /* but I'd rather have unused columns on the right than on the left */
  1051.         x1 -= n;                            /* Adjust left    */
  1052.         x2 -= n;                            /* Adjust right */
  1053.       } /* if */
  1054.  
  1055.     if (VSIw->Rleft != x1)
  1056.       {
  1057.       /* left margin changed -- scroll horizontally */
  1058.       /* (assume width of region hasn't also changed) */
  1059.         n = x1 - VSIw->Rleft;
  1060.         if (n > 0)
  1061.             VSscrolright(w, n);
  1062.         else
  1063.             VSscrolleft(w, -n);
  1064.       }
  1065.     else
  1066.       /* just update horizontal scroll bar limits for new width of visible region */
  1067.         RSmargininfo(w, VSIw->maxwidth - (x2 - x1), x1);
  1068.  
  1069.     VSIw->Rleft = x1;
  1070.     VSIw->Rright = x2;
  1071.  
  1072.     if (VSIw->Rbottom > VSIw->lines)
  1073.       /* don't scroll off the bottom of the screen */
  1074.         n = VSIw->Rbottom - VSIw->lines;
  1075.     else
  1076.       /* scroll to new topmost line as specified */
  1077.         n = VSIw->Rtop - y1;
  1078.  
  1079.     if (n != 0)
  1080.       /* scroll vertically (assume height of region hasn't also changed) */
  1081.         if (n > 0)
  1082.             VSscrolback(w, n);
  1083.         else
  1084.             VSscrolforward(w, -n);
  1085.     else
  1086.       /* update vertical scroll bar limits for new height of visible region */
  1087.         RSbufinfo(w, VSIw->numlines, VSIw->Rtop, VSIw->Rbottom);
  1088.     return(0);
  1089.   } /* VSsetrgn */
  1090.  
  1091. short VSscrolcontrol
  1092.   (
  1093.     short w,
  1094.     short scrolon, /* whether to save lines off top */
  1095.     short offtop /* whether to save lines on clearing entire screen */
  1096.   )
  1097.   /* changes scrollback flag settings for a virtual screen. */
  1098.   {
  1099.     if (VSvalids(w) != 0)
  1100.         return(-3);
  1101.  
  1102.     if (scrolon > -1)
  1103.         VSIw->savelines = scrolon;
  1104.     if (offtop > -1)
  1105.         VSIw->ESscroll = offtop;
  1106.  
  1107.     return(0);
  1108.   } /* VSscrolcontrol */
  1109.  
  1110. short VSgetrgn
  1111.   (
  1112.     short w,
  1113.     short *x1,
  1114.     short *y1,
  1115.     short *x2,
  1116.     short *y2
  1117.   )
  1118.   /* returns the current visible region for a virtual screen. */
  1119.   {
  1120.     if (VSvalids(w) != 0)
  1121.         return(-3);
  1122.  
  1123.     *x1 = VSIw->Rleft;
  1124.     *y1 = VSIw->Rtop;
  1125.     *x2 = VSIw->Rright;
  1126.     *y2 = VSIw->Rbottom;
  1127.    
  1128.     return(0);
  1129.   } /* VSgetrgn */
  1130.  
  1131.  
  1132. short VSmaxwidth
  1133.   (
  1134.     short w
  1135.   )
  1136.   /* returns one less than the number of columns on a virtual screen. */
  1137.   {
  1138.     if (VSvalids(w) != 0)
  1139.         return(-3);
  1140.     return(VSIw->maxwidth);
  1141.   } /* VSmaxwidth */
  1142.  
  1143. VSlinePtr VSIGetLineStart(short w, short y1)
  1144.   /* returns a pointer to the specified text line (number may be
  1145.     negative for a line in the scrollback buffer). */
  1146.   {
  1147.     VSlinePtr ptr;
  1148.     short n;
  1149.  
  1150.     if (VSvalids(w) != 0)
  1151.         return((VSlinePtr) -3);
  1152.  
  1153.     if (y1 >= 0)
  1154.         return(VSIw->linest[y1]);
  1155.  
  1156.     n = y1 - VSIw->Rtop;                /* Number of lines from VISTOP to scroll forward */
  1157.     ptr = VSIw->vistop;
  1158.     while (n > 0)
  1159.       {
  1160.         n--;
  1161.         ptr = ptr->next;
  1162.       } /* while */
  1163.     while (n < 0)
  1164.       {
  1165.         n++;
  1166.         ptr = ptr->prev;
  1167.       } /* while */
  1168.     return(ptr);
  1169.   } /* VSIGetLineStart */
  1170.  
  1171. char *VSIstrcopy(char *src, short len, char *dest, short table)
  1172.   /* copies characters from *src (length len) to *dest, dropping
  1173.     trailing blanks. If table is nonzero, then this number (or more) of
  1174.     consecutive embedded blanks will be replaced with a tab. Returns a pointer
  1175.     to the position one past the last character copied to the *dest buffer. */
  1176.   {
  1177.     char *p, *tempp;
  1178.     short tblck;
  1179.  
  1180.     p = src + len - 1;
  1181.   /* skip trailing blanks */
  1182.     while ((*p == ' ') && (p >= src))
  1183.         p--;
  1184.     if (p < src)
  1185.         return(dest);
  1186.     if (!table)
  1187.       /* straight character copy */
  1188.         while (src <= p)
  1189.             *dest++ = *src++;
  1190.     else
  1191.       /* tab-replacement copy */
  1192.         while (src <= p)
  1193.           {
  1194.             while ((src <= p) && (*src != ' '))
  1195.                 *dest++ = *src++;
  1196.             if (src < p)
  1197.               {
  1198.                 tempp = dest; /* remember start of run of spaces */
  1199.                 tblck = 0; /* length of run */
  1200.                 while ((src <= p) && (*src == ' '))
  1201.                   {
  1202.                     *dest++ = *src++;
  1203.                     tblck++;
  1204.                   } /* while */
  1205.                 if (tblck >= table)
  1206.                   {
  1207.                     *tempp++ = '\011'; /* replace first space with a tab */
  1208.                     dest = tempp; /* drop remaining spaces */
  1209.                   } /* if */
  1210.               } /* if */
  1211.           } /* while */
  1212.     return(dest);
  1213.   } /* VSIstrcopy */
  1214.  
  1215. long VSgettext(short w, short x1, short y1, short x2, short y2, char *charp, long max, char *EOLS, short table)
  1216.   /* copies a portion of text from the specified virtual screen into
  1217.     the *charp buffer. table, if nonzero, is the minimum length of
  1218.     runs of spaces to be replaced with single tabs. Returns the
  1219.     length of the copied text. max is supposed to be the maximum
  1220.     length to copy, but this is currently ignored!
  1221.     EOLS is the end-of-line sequence to insert at line boundaries.
  1222.     This is currently assumed to be exactly one character long. */
  1223.   {
  1224.     UNUSED_ARG(max) /* !! */
  1225.     short EOLlen;
  1226.     short lx,ly,                    /* Upper bounds of selection */
  1227.         ux,uy;                    /* Lower bounds of selection */
  1228.     short maxwid;
  1229.     char *origcp;
  1230.     VSlinePtr t;
  1231.  
  1232.     if (VSvalids(w) != 0)
  1233.         return(-3);
  1234.     EOLlen = strlen(EOLS);
  1235.     maxwid = VSIw->maxwidth;
  1236.     origcp = charp;
  1237.  
  1238.     if (y1 < -VSIw->numlines)
  1239.       {
  1240.         y1 = -VSIw->numlines;
  1241.         x1 = -1;
  1242.       } /* if */
  1243.     if (y1 == y2)
  1244.       {
  1245.       /* copying no more than a single line */
  1246.         t = VSIGetLineStart(w, y1);
  1247.         if (x1 < x2)    /* Order the lower and upper bounds */
  1248.           {
  1249.             ux = x1;
  1250.             uy = y1;
  1251.             lx = x2;
  1252.             ly = y2;
  1253.           }
  1254.         else
  1255.           {
  1256.             ux = x2;
  1257.             uy = y2;
  1258.             lx = x1;
  1259.             ly = y1;
  1260.           } /* if */
  1261.  
  1262.         if ((long)(lx-ux) < max)
  1263.             charp=VSIstrcopy(&t->text[ux+1], lx-ux, charp, table);
  1264.         else
  1265.             charp=VSIstrcopy(&t->text[ux+1], (short)(max - (long)(charp-origcp)), charp, table);
  1266.         if (lx == maxwid)
  1267.             *charp++ = *EOLS; /* assumes it's only one character! */
  1268.       }
  1269.     else
  1270.       {
  1271.       /* copying more than one line */
  1272.         if (y1 < y2)    /* Order the lower and upper bounds */
  1273.           {
  1274.             ux = x1;
  1275.             uy = y1;
  1276.             lx = x2;
  1277.             ly = y2;
  1278.           }
  1279.         else
  1280.           {
  1281.             ux = x2;
  1282.             uy = y2;
  1283.             lx = x1;
  1284.             ly = y1;
  1285.           } /* if */
  1286.         t = VSIGetLineStart(w, uy);
  1287.         if (((long) (maxwid-ux) < max))
  1288.             charp=VSIstrcopy(&t->text[ux+1],maxwid-ux,charp,table);
  1289.         else
  1290.             charp=VSIstrcopy(&t->text[ux+1],(short) (max-(long)(charp-origcp)),charp,table);
  1291.         *charp++ = *EOLS; /* assumes it's only one character! */
  1292.         uy++;
  1293.         t = t->next;
  1294.         while (uy < ly && uy < VSIw->lines)
  1295.           {
  1296.             if ((long)(maxwid+1) < max)
  1297.                 charp=VSIstrcopy(t->text,maxwid+1,charp, table);
  1298.             else
  1299.                  charp=VSIstrcopy(t->text,(short)(max - (long) (charp-origcp)),charp, table);
  1300.             *charp++=*EOLS;
  1301.             t=t->next; 
  1302.             uy++;
  1303.           } /* while */
  1304.         if (ly > VSIw->lines)
  1305.             lx = maxwid;
  1306.  
  1307.         if ((long) (lx+1) < max)
  1308.             charp=VSIstrcopy(t->text,lx+1,charp,table);
  1309.         else
  1310.             charp=VSIstrcopy(t->text,(short)(max - (long)(charp-origcp)),charp,table);
  1311.  
  1312.         if (lx >= maxwid)
  1313.             *charp++ = *EOLS; /* assumes it's only one character! */
  1314.       } /* if */
  1315.     return(charp - origcp);
  1316.   } /* VSgettext */
  1317.  
  1318. short VSgetlines
  1319.   (
  1320.     short w
  1321.   )
  1322.   /* returns the number of lines in a virtual screen. */
  1323.   {
  1324.     if (VSvalids(w) != 0)
  1325.         return(-2);
  1326.     return(VSIw->lines + 1);
  1327.   } /* VSgetlines */
  1328.  
  1329. short VSsetlines
  1330.   (
  1331.     short w, /* window number */
  1332.     short lines /* new number of lines */
  1333.   )
  1334.   /* sets the number of lines in a virtual screen, reallocating text
  1335.     and attribute arrays accordingly. Returns the new number of lines
  1336.     on success, or an error otherwise */
  1337.   {
  1338.     VSlineArray linest;                /* For storage of old ones */
  1339.     VSattrlineArray attrst;
  1340.     VSlinePtr line;                            /* pointer to a line */
  1341.     short i, j, oldlines;
  1342.     char *temp;
  1343.     unsigned short *tempa;
  1344.     
  1345.     if (VSvalids(w) != 0)
  1346.         return(-3000);
  1347.     
  1348.     lines -= 1;                                /* Correct for internal use */
  1349.     oldlines = VSIw->lines;
  1350.     if (lines == oldlines)                     /* no change */
  1351.          return(0);
  1352.     
  1353.     VSIw->x = 0;
  1354.     VSIw->y = 0;
  1355.     VSIcurson(w, VSIw->x, VSIw->y, 1);     /* keeps cursor from pointing outside of window */
  1356.  
  1357.     VSIw->vistop = VSIw->scrntop;            /* Force view to the top of the screen */
  1358.     
  1359.     attrst = VSIw->attrst; /* save old screen arrays */
  1360.     linest = VSIw->linest;
  1361.  
  1362.     VSIw->linest = VSInewlinearray(lines + 1); /* allocate new screen buffers */
  1363.     if (!VSIw->linest)
  1364.     {
  1365.         VSIw->linest = linest;        /* mem problems */
  1366.         return (-2000);
  1367.     }
  1368.     
  1369.     VSIw->attrst = VSInewattrlinearray(lines + 1);
  1370.     if (!VSIw->attrst)
  1371.     {                                /* mem problems */
  1372.         DisposPtr((Ptr) VSIw->linest);
  1373.         VSIw->linest = linest;
  1374.         VSIw->attrst = attrst;
  1375.         return (-2000);
  1376.     }
  1377.     
  1378.     VSIw->lines = lines; /* set new number of screen lines */
  1379.     
  1380.  
  1381.     VSIw->linest[0] = VSInewlines(lines + 1,1); /* allocate new text and attribute lines */
  1382.     VSIw->attrst[0] = (VSattrlinePtr)VSInewlines(lines + 1,2);
  1383.     if (VSIw->linest[0] && VSIw->attrst[0])
  1384.     {    /* mem is there */
  1385.         
  1386.         /* dispose of old attribute lines */
  1387.         VSIfreelinelist((VSlinePtr)attrst[0]);
  1388.         DisposPtr((Ptr) attrst);
  1389.  
  1390.         VSIlistndx(VSIw->linest[0],VSIw->attrst[0]); /* build the new screen arrays */
  1391.         if (VSIw->savelines)
  1392.         { /* save previous screen contents in scrollback buffer */
  1393.             line = linest[oldlines]->next;                /* save continuation */
  1394.             linest[oldlines]->next = VSIw->linest[0];
  1395.             VSIw->linest[lines]->next = line;            /* restore continuation */
  1396.             VSIw->linest[0]->prev = linest[oldlines];    /* backpointer */
  1397.             if (line)                                    /* if there was a follower */
  1398.                 line->prev = VSIw->linest[lines];        /* new prev for it */
  1399.             VSIw->numlines += oldlines;                    /* we made more scrollback */
  1400.         }
  1401.         else
  1402.         {  /* get rid of previous screen contents */
  1403.             VSIfreelinelist(linest[0]);
  1404.             DisposPtr((Ptr) linest);
  1405.         }
  1406.     }
  1407.     else
  1408.     {    /* need more mem - emergency */
  1409.         if (VSIw->linest[0])                    /*if 1/2 of push for memory died, kill the other */
  1410.             VSIfreelinelist(VSIw->linest[0]);
  1411.         if (VSIw->attrst[0])
  1412.             VSIfreelinelist((VSlinePtr)VSIw->attrst[0]);
  1413.         /* Here we should ask if we want to lose the screen buffer!!  CCP */
  1414.         VSIfreelines();                              /* release scrollback buffer */
  1415.         VSIfreelinelist(linest[0]);                  /* release current visible lines */
  1416.         DisposPtr((Ptr) linest);                  
  1417.         VSIfreelinelist((VSlinePtr)attrst[0]);                  /* release current visible attrib */
  1418.         DisposPtr((Ptr) attrst);
  1419.         VSIw->linest[0] = VSInewlines(lines + 1,1); /* allocate new screen arrays */
  1420.         VSIw->attrst[0] = (VSattrlinePtr)VSInewlines(lines + 1,2);
  1421.         if (!VSIw->linest[0] || !VSIw->attrst[0])
  1422.         {  /* still not enough memory;  Try to allocate just enough to go back to original size */
  1423.             
  1424.             if (VSIw->linest[0])                    /* this gets rid of useless */
  1425.                 VSIfreelinelist(VSIw->linest[0]);    /* memory, since we are giving up */
  1426.             if (VSIw->attrst[0])                                    
  1427.                 VSIfreelinelist((VSlinePtr)VSIw->attrst[0]);
  1428.  
  1429.             VSIw->linest[0] = VSInewlines(oldlines + 1,1); /* try original size */
  1430.             VSIw->attrst[0] = (VSattrlinePtr)VSInewlines(oldlines + 1,2);
  1431.             
  1432.             if (!VSIw->linest[0] || !VSIw->attrst[0])
  1433.             /* damage control: */
  1434.             {                                          /* Nope. Give up, and signal that */
  1435.                 if (VSIw->linest[0])                  /* caller should kill this screen */
  1436.                     VSIfreelinelist(VSIw->linest[0]);    
  1437.                 if (VSIw->attrst[0])                
  1438.                     VSIfreelinelist((VSlinePtr)VSIw->attrst[0]);
  1439.                 /* dont destroy everything, as this will screw up VSdestroy later */            
  1440.                 return(-4000);
  1441.             }
  1442.             else
  1443.             {
  1444.                 lines = oldlines;
  1445.                 VSIw->lines = lines;
  1446.             }
  1447.         }
  1448.         VSIw->buftop = VSIw->linest[0];
  1449.         VSIw->numlines = 0; /* nothing in scrollback */
  1450.       } /* if */
  1451.  
  1452.     VSIw->scrntop = VSIw->linest[0];            /* new top of screen */
  1453.     VSIw->vistop = VSIw->scrntop;                /* Force a scroll to the top of the screen */
  1454.     VSIlistndx(VSIw->scrntop, VSIw->attrst[0]); /* rebuild screen arrays */    
  1455.     VSIw->attrst[0]->prev = VSIw->attrst[lines];    /* Make attribute list circular */
  1456.     VSIw->attrst[lines]->next = VSIw->attrst[0];
  1457.     if (!VSIw->savelines)
  1458.       {
  1459.       /* make text line list circular to indicate no extensions */
  1460.         VSIw->linest[lines]->next = VSIw->linest[0];
  1461.         VSIw->linest[0]->prev = VSIw->linest[lines];
  1462.       } /* if */
  1463.  
  1464.   /* initialize the new screen lines to blank text and no attributes */
  1465.     for (i = 0; i <= lines; i++)
  1466.       {
  1467.         tempa = VSIw->attrst[i]->text;
  1468.         temp = VSIw->linest[i]->text;
  1469.         for (j = 0; j <= VSIw->allwidth; j++)
  1470.           {
  1471.             *temp++ = ' ';
  1472.             *tempa++ = 0;
  1473.           } /* for */
  1474.       } /* for */
  1475.   
  1476.   /* reset scrolling region */
  1477.     VSIw->top = 0;
  1478.     VSIw->bottom = lines;
  1479.   
  1480.   /* reset visible region */
  1481.     VSIw->Rtop = 0;
  1482.     VSIw->Rbottom = lines;
  1483.  
  1484.     
  1485.     VSredraw(w, 0, 0, VSIw->maxwidth, lines); /* draw new blank screen */
  1486.     RSbufinfo(w, VSIw->numlines, VSIw->Rtop, VSIw->Rbottom); /* adjust vertical scroll bar */
  1487.  
  1488.     return(VSIw->lines);
  1489.  
  1490. } /* VSsetlines */
  1491.  
  1492.  
  1493. /*--------------------------------------------------------------------------*/
  1494. /* NCSA: SB - VSsetcols                                                     */
  1495. /*     This allows external procedures to set the column width.  Used by         */
  1496. /*    routines in main, to allow ARBITRARY column widths                        */
  1497. /*--------------------------------------------------------------------------*/
  1498. short VSsetcols(short w, short myWidth)                                    /* NCSA: SB */
  1499. {                                                                    /* NCSA: SB */
  1500.     if (VSvalids(w) != 0)                                            /* NCSA: SB */
  1501.         return(-1);                                                    /* NCSA: SB */
  1502.     VSIw->maxwidth = myWidth;                                        /* NCSA: SB */
  1503.     return 0;
  1504. }                                                                     /* NCSA: SB */
  1505.  
  1506.  
  1507. /*--------------------------------------------------------------------------*/
  1508. /* NCSA: SB - VSgetcols                                                     */
  1509. /*     This returns the column width.  Used by SetScreenDimensions, when        */
  1510. /*    the procedure needs to know the initial column width                    */
  1511. /*--------------------------------------------------------------------------*/
  1512. short VSgetcols(short w)                                                /* NCSA: SB */
  1513. {                                                                    /* NCSA: SB */
  1514.     if (VSvalids(w) != 0)                                            /* NCSA: SB */
  1515.         return(-1);                                                    /* NCSA: SB */
  1516.     return VSIw->maxwidth;                                            /* NCSA: SB */
  1517. }                                                                     /* NCSA: SB */
  1518.