home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / ncsat.cpt / Telnet2.5 final / vs / vsinterf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-16  |  37.9 KB  |  1,415 lines

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