home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 240_01 / ciao.c < prev    next >
Text File  |  1987-07-30  |  30KB  |  995 lines

  1. /*
  2. **   ciao.c
  3. **   sept 10, 1986, by david c. oshel, ames, iowa
  4. **
  5. **  ----->  COMPILE USING UNSIGNED CHAR
  6. **
  7. **   Console input and output for the 101% IBM PC clone.  This is the first
  8. **   module in my CIAO.LIB library.
  9. **
  10. **   These are FAST primitives to read from and write to the IBM video RAM.
  11. **   Ignores the ROM-BIOS except to set text mode and/or to read or set the 
  12. **   machine cursor (see just below).
  13. **
  14. **   The module is self-initializing.  Vid_init(n) is only required to set
  15. **   a particular mode, e.g., vid_init(3) to set 80x25 color text.  The
  16. **   requested mode is only set if the hardware supports it, and only
  17. **   monochrome mode 7 and cga modes 2 or 3 are valid.  No graphics modes.
  18. **
  19. **   Global functions which ALTER THE CONTENTS OF THE SCREEN test the 
  20. **   initialized flag.  In general, static, ROM-BIOS and cursor functions 
  21. **   do NOT test the flag.  If the flag is still zero, vid_init executes.
  22. **
  23. **   The machine cursor and the video RAM write location ("soft cursor")
  24. **   are independent, but are synchronized by default.  See setsynch fn.
  25. **
  26. **   Compiler is Microsoft C ver. 4.00, but this particular module should be 
  27. **   fairly portable to another compiler (such as Microsoft C ver. 3.00). 
  28. **
  29. */
  30.  
  31.  
  32. /*=======================================================================*
  33.      There are 16 public Video Attribute Registers:  vid[0] ... vid[15]
  34.  
  35.      The Clairol routine (CLAIROL.OBJ) recognizes four major message
  36.      levels, associated with vid[0], vid[1], vid[2], vid[3].  This is
  37.      the popout window that allows user access to the first four video
  38.      registers (only).
  39.  
  40.      Programmers have access to all 16 registers at all times, using
  41.      the CLAIROL.H header file.
  42.  
  43.      Clairol           VidReg   ^ commands that set the attribute
  44.      -------------------------------------------------------------------
  45.      Normal            vid[0]   wputs("^0"); wputs("^");
  46.      Bold              vid[1]   wputs("^1"); 
  47.      Emphasis          vid[2]   wputs("^2"); 
  48.      Attention!        vid[3]   wputs("^3"); 
  49.  
  50.                        vid[4]   wputs("^4");
  51.                        .
  52.                        .
  53.                        .
  54.                        vid[ 9]  wputs("^9");
  55.                        vid[10]  wputs("^Ω"); keystroke is ALT 234
  56.                        vid[11]  wputs("^δ");      "       ALT 235
  57.                        vid[12]  wputs("^∞");      "       ALT 236
  58.                        vid[13]  wputs("^φ");      "       ALT 237
  59.                        vid[14]  wputs("^ε");      "       ALT 238
  60.                        vid[15]  wputs("^∩");      "       ALT 239
  61.  
  62.  
  63.      The DEFAULT contents of these registers is as follows:
  64.  
  65.      Contents      *Color/Graphics Adapt.   Monochrome Adapter
  66.      -----------------------------------------------------------------
  67.      Normal         brite white on blue     normal
  68.      Bold           brite yellow on black   bright normal
  69.      Emphasis       brite blue on white     reverse
  70.      Attention      blink br. white on red  blinking reverse
  71.  
  72.      vid[ 4]       *red, 4                  underline
  73.      vid[ 5]        magenta, 5              bright underline    
  74.      vid[ 6]        dark yellow, 6          blinking normal
  75.      vid[ 7]        ordinary white, 7       blinking underline
  76.      vid[ 8]        dark grey, 8            blinking bright normal 
  77.      vid[ 9]        brite blue, 9           blinking bright underline
  78.      vid[10]        brite green, 0x0a       normal
  79.      vid[11]        brite cyan, 0x0b        normal
  80.      vid[12]        brite red, 0x0c         normal
  81.      vid[13]        brite magenta, 0x0d     normal
  82.      vid[14]        brite yellow, 0x0e      normal
  83.      vid[15]        brite white, 0x0f       normal
  84.  
  85.      *The default background is black for registers vid[4]..vid[15], and
  86.       blink is off.
  87.  
  88.  *=======================================================================*/
  89.  
  90.  
  91.  
  92. #define LINT_ARGS
  93.  
  94. #include <alloc.h>     /* _fmalloc(), _ffree()  */
  95. #include <conio.h>      /* direct console: putch(), getch(), etc */
  96.  
  97. #include "ciao.h"
  98.  
  99. /* these defines are for ciao.c alone; they are local, not for ciao.h
  100. */
  101.  
  102.  
  103. #define SCRLIM 4000                         /* 80x25 chars & attrs in screen */
  104. #define TOPX 0                              /* 80x25 screen margin defaults  */
  105. #define TOPY 0
  106. #define BTMX 79
  107. #define BTMY 24
  108. #define GOXY (2*(col+(row*80)))             /* yields absolute screen address */
  109. #define SPC ' '                             /* blank char, for clreol(), etc. */
  110.  
  111. /* monochrome monitor attributes :----------------*/
  112.  
  113. #define INV '\000'   /* invisible                 */
  114. #define UNL '\001'   /* underline                 */
  115. #define NRM '\007'   /* normal                    */
  116. #define BRU '\011'   /* bright underline          */
  117. #define BRN '\017'   /* bright normal             */
  118. #define RVR '\160'   /* reverse                   */
  119. #define BLU '\201'   /* blinking underline        */
  120. #define BLN '\207'   /* blinking normal           */
  121. #define BBU '\211'   /* blinking bright underline */
  122. #define BBN '\217'   /* blinking bright normal    */
  123. #define BLR '\360'   /* blinking reverse          */
  124.  
  125.  
  126. /*
  127. ** globals
  128. */
  129.  
  130.  
  131. int vid[16] =  /* vid_init() changes this table if cga */
  132. {
  133.     NRM, BRN, RVR, BLR, 
  134.     UNL, BRU, BLN, BLU, 
  135.     BBN, BBU, NRM, NRM,
  136.     NRM, NRM, NRM, NRM
  137. };
  138.  
  139. int vid_mode = 7;                  /* monochrome is default */
  140. int rasterh  = 12, rasterl  = 13;  /* monochrome cursor default raster lines */
  141.  
  142.  
  143. /*
  144. ** locals
  145. */
  146.  
  147. static int Initialized = 0;        /* are all the critical pointers set? */ 
  148.  
  149. static union REGS old_vid;
  150.  
  151. static int vid_seg  = 0xB000,      /* monochrome screen RAM base address */
  152.            vid_attr = 7,           /* HEAVILY USED HEREIN */
  153.            vid_page = 0,           /* "active" page is default (unused?) */ 
  154.            vid_wide = 80;          /* unused */
  155.  
  156. static char far *scribble;         /* transfer depot for RAM read/write */
  157. static char far *hidescreen;       /* pointer to invisible screen buffer */
  158.  
  159. static int activescreen = 0xB000, 
  160.            row = 0,
  161.            col = 0; 
  162.  
  163. static union REGS xy;              /* holds machine cursor address for set */
  164.  
  165. static int synchronized = 1;       /* default to hard & soft cursors alike */
  166.  
  167. static int lm = TOPX,
  168.            rm = BTMX,
  169.            tm = TOPY,
  170.            bm = BTMY;              /* default window margins */
  171.  
  172.  
  173.  
  174. /* H_pfill().  Pattern fill routine, hardwired to active screen, scribble.
  175. **
  176. ** Called by rptchar(), scrollup(), scrolldn().  Use with discretion
  177. ** because there is NO error checking!
  178. **
  179. ** Assumes scribble is already set, plus any number of other hardwired
  180. ** characteristics.  Generalizing this for any size of pattern source buffer
  181. ** and any size of destination fill buffer might be useful.
  182. **
  183. ** Movedata is very efficient.  I suspect it just sets up registers and
  184. ** then executes a single 8086 machine instruction to do the block move.  
  185. ** The result is instantaneous, at least to the proverbial naked orb.
  186. */
  187.  
  188. static void H_pfill( base, cnt ) int base, cnt;  
  189. {
  190.      static int width = 2;  /* hardwired pattern (scribble) size */
  191.  
  192.      cnt *= width;    /* translate number of pattern objects 
  193.                       ** to number of destination bytes 
  194.                       */
  195.  
  196.      /* SET PATTERN IN DEST BUFFER:  Write pattern at least once.
  197.      */
  198.      movedata( FP_SEG(scribble), FP_OFF(scribble), /* from */ 
  199.                activescreen, base,                 /* to   */
  200.                width);
  201.  
  202.      cnt -= width;                           /* one object already moved */
  203.      if (cnt > 0)                            /* shall we continue? */
  204.      {
  205.         /* ULTRAFAST PATTERN FILL:  A source byte moved to the destination
  206.         ** on iteration N extends the source pattern for iteration N+1.
  207.         */
  208.         movedata( activescreen, base,           /* srce (!)  */
  209.                   activescreen, base + width,   /* dest (!!) */
  210.                   cnt);
  211.      }
  212. }
  213.  
  214. static void setmchnloc(void); /* forward ref to static ROM-BIOS function, below */
  215.  
  216. void gotoxy( x, y ) /* 0,0 RELATIVE TO TOPLEFT CORNER OF CURRENT WINDOW! */
  217. int x, y;
  218. {
  219.  
  220.     y %= 1 + bm - tm;  /* mod number of lines in window */
  221.     x %= 1 + rm - lm;  /* mod number of columns in line */
  222.  
  223.     row = tm + y;      /* translate window-relative to fullscreen-absolute */
  224.     col = lm + x;
  225.  
  226.     if (synchronized)  /* update machine cursor? */
  227.         setmchnloc();
  228.  
  229.  
  230.  
  231.  
  232. /* Scroll functions honor the current window, and do not alter global
  233. ** col & row settings.  The window scrolls up or down one line at a time.
  234. **
  235. ** NOTICE:   The fresh, blank line which results from scrolling has the
  236. **           Normal (vid[0]) attribute.  If this "fixup" were not attempted,
  237. ** the line would have the attribute of the last character in the text which
  238. ** formerly occupied the lowest (or highest) line.  Either approach is wrong
  239. ** in some circumstances, but the Normal attribute should be correct in most
  240. ** cases.  Caller may either execute clreol() to repair the window line, or
  241. ** modify vid[0] prior to scrolling.
  242. */
  243.  
  244. void scrollup()  /* scroll current window up one line */
  245. {
  246.     register int i, b1;
  247.     auto int count, limit;
  248.  
  249.     if (!Initialized) vid_init(0);
  250.  
  251.     b1 = 2*(lm+(tm*80));           /* find top left corner of window */
  252.     limit = bm - tm;               /* and number of lines in window, less one */
  253.     count = 2*(1 + rm - lm);       /* width of line */
  254.  
  255.     for (i = 0; i < limit; i++)  /* move all contents up one line */
  256.     {
  257.         movedata( activescreen, b1 + 160,   /* source */
  258.                   activescreen, b1,         /* destination */
  259.                   count); 
  260.         b1 += 160;
  261.     }
  262.  
  263.     scribble[0] = SPC;           /* clear bottom line of window */
  264.     scribble[1] = vid[0];
  265.     H_pfill( 2*(lm+(bm*80)), 1 + rm - lm );
  266. }
  267.  
  268. void scrolldn()  /* scroll current window down one line */ 
  269. {
  270.     register int i, b1; 
  271.     auto int count, limit;
  272.  
  273.     if (!Initialized) vid_init(0);
  274.  
  275.     b1 = 2*(lm+(bm*80));           /* find bottom left corner of window */
  276.     limit = bm - tm;               /* and number of lines in window, less one */
  277.     count = 2*(1 + rm - lm);       /* width of line */
  278.  
  279.     for (i = 0; i < limit; i++)  /* move all contents down one line */
  280.     {
  281.         movedata( activescreen, b1 - 160,   /* source */
  282.                   activescreen, b1,         /* destination */
  283.                   count);
  284.         b1 -= 160;
  285.     }
  286.  
  287.     scribble[0] = SPC;           /* clear top line of window */
  288.     scribble[1] = vid[0];
  289.     H_pfill( 2*(lm+(tm*80)), 1 + rm - lm );
  290. }
  291.  
  292.  
  293.  
  294. void getwindow( tx, ty, bx, by )  /* read current window dimensions */
  295. int *tx, *ty, *bx, *by;
  296. {
  297.     *tx = lm;
  298.     *ty = tm;
  299.     *bx = rm;
  300.     *by = bm;
  301. }
  302.  
  303.  
  304. void setwindow( tx, ty, bx, by )
  305. int tx, ty, bx, by;
  306. {
  307.    if (bx > BTMX) bx = BTMX;
  308.    if (tx < TOPX) tx = TOPX;
  309.    if (by > BTMY) by = BTMY;
  310.    if (ty < TOPY) ty = TOPY;
  311.  
  312.    if (tx >= bx || ty >= by)  /* absurd values? set full screen reduced by 1 */
  313.    { 
  314.        putch(7); /* complain but continue */
  315.        lm = TOPX + 1; rm = BTMX - 1; tm = TOPY + 1; bm = BTMY - 1; 
  316.    } 
  317.    else
  318.    {
  319.        lm = tx;
  320.        rm = bx;
  321.        tm = ty;
  322.        bm = by;
  323.    }
  324. }
  325.  
  326.  
  327.  
  328.  
  329. void fullscreen()
  330. {
  331.    setwindow( TOPX, TOPY, BTMX, BTMY );
  332. }
  333.  
  334.  
  335.  
  336.  
  337. /*===========================*/
  338. /* screen character handlers */
  339. /*===========================*/
  340.  
  341. void setscreen( n ) int n;  /* set activescreen = 1 or 2, screen 1 is visible */
  342. {
  343.      if (!Initialized) vid_init(0);
  344.  
  345.      switch (n)
  346.      {
  347.          case 2:  { activescreen = FP_SEG( hidescreen ); break; }
  348.          default:
  349.          case 1:  { activescreen = vid_seg; break; }
  350.      }
  351. }
  352.  
  353.  
  354. void swapscreen( n ) int n;  /* swap hidden screen n with visible screen 1 */
  355. {                            /* for now, n can only be 2  */   
  356.      char far *save;
  357.      int tricseg, tracseg, saveseg, temp;
  358.  
  359.      if (!Initialized) vid_init(0);
  360.  
  361.      save = _fmalloc( SCRLIM );
  362.      saveseg = FP_SEG( save );
  363.  
  364.      temp = activescreen;
  365.  
  366.      if (n < 2) n = 2;       /* just now, range check on n is trivial */
  367.      if (n > 2) n = 2; 
  368.  
  369.      setscreen( n );              /* hidden screen n */
  370.         tracseg = activescreen;
  371.      setscreen( 1 );              /* visible screen 1 */ 
  372.         tricseg = activescreen;
  373.  
  374.      activescreen = temp;
  375.  
  376.      movedata( tracseg, 0, saveseg, 0, SCRLIM);  /* swap contents of screens */
  377.      movedata( tricseg, 0, tracseg, 0, SCRLIM);
  378.      movedata( saveseg, 0, tricseg, 0, SCRLIM);
  379.  
  380.      _ffree( save );
  381. }
  382.  
  383.  
  384.  
  385. void setsynch( on ) int on;  /* synchronized is ON by default */
  386. {
  387.      if ((synchronized = on? 1: 0) == 1)
  388.          setmchnloc();
  389. }
  390.  
  391.  
  392.  
  393.  
  394. void rptchar( ch, cnt ) char ch; int cnt;  /* does NOT update screen position */
  395. {
  396.      if (!Initialized) vid_init(0);
  397.  
  398.      scribble[0] = ch;
  399.      scribble[1] = vid_attr;
  400.      if (cnt >= 1) 
  401.          H_pfill( GOXY, cnt );  /* use pattern fill for speed */
  402. }
  403.  
  404.  
  405.  
  406. void readscreenchar( ch ) SCW *ch;
  407. {
  408.     if (!Initialized) vid_init(0);
  409.  
  410.     movedata( activescreen, GOXY,
  411.               FP_SEG(scribble), FP_OFF(scribble), 
  412.               2);
  413.     ch->byte = scribble[0];
  414.     ch->attr = scribble[1];
  415. }
  416.  
  417.  
  418.  
  419. /*============================*/
  420. /* screen clearing functions  */
  421. /*============================*/
  422.  
  423.  
  424.  
  425. void clreol()  /* honors current window setting */
  426. {
  427.     if (!Initialized) vid_init(0);
  428.  
  429.     rptchar(SPC, 1 + rm - col);
  430. }
  431.  
  432.  
  433. void clrwindow()   /* home cursor, clear window */
  434. {
  435.     int lin, yrel, xrel, temp;
  436.  
  437.     if (!Initialized) vid_init(0);
  438.  
  439.     temp = synchronized;
  440.     setsynch( 0 );        /* don't bother gotoxy with machine cursor updates */
  441.     lin = tm;
  442.     xrel = yrel = 0;
  443.     while (lin++ <= bm)
  444.     {
  445.         gotoxy(xrel, yrel++);
  446.         clreol();
  447.     }
  448.     gotoxy(0,0);
  449.     setsynch( temp );
  450. }
  451.  
  452.  
  453. void clreos()  /* screen only, ignores window */
  454. {
  455.     if (!Initialized) vid_init(0);
  456.     rptchar( SPC, (SCRLIM - GOXY) / 2 );
  457.  
  458. }
  459.  
  460.  
  461. void clrscrn()  /* resets full screen, homes cursor, clears screen */
  462. {
  463.     if (!Initialized) vid_init(0);
  464.  
  465.     fullscreen();
  466.     gotoxy(0,0);
  467.     rptchar(SPC,SCRLIM /2);
  468. }
  469.  
  470.  
  471. /*======================*/
  472. /* WindowBox            */
  473. /*======================*/
  474.  
  475. /* this version draws even the largest box almost instantaneously
  476. ** dco, 8/29/86
  477. */
  478.  
  479. void windowbox( tx, ty, bx, by ) int tx, ty, bx, by;
  480. {
  481.         register int i,j; 
  482.         auto int temp;
  483.  
  484.         if (!Initialized) vid_init(0);
  485.  
  486.         /* first, clear the working area to startle and amuse...
  487.         */
  488.  
  489.         setwindow( tx, ty, bx, by );
  490.         clrwindow();
  491.  
  492.         /* now, draw a crisp double-lined box (user's vid_attr ignored)
  493.         */
  494.  
  495.         temp = vid_attr;
  496.         vid_attr = (vid_mode == 2)? vid[15]: vid[10];
  497.  
  498.         tx = lm; /* use values that setwindow range checking may have found! */
  499.         ty = tm;
  500.         bx = rm;
  501.         by = bm;
  502.  
  503.         /* then, draw the border AROUND the area!
  504.         */
  505.  
  506.         fullscreen();        /* allows gotoxy to use the argument dimensions */
  507.  
  508.         if (tx > TOPX) { --tx; }
  509.         if (ty > TOPY) { --ty; }
  510.         if (bx < BTMX) { ++bx; }
  511.         if (by < BTMY) { ++by; }
  512.  
  513.         /* top line
  514.         */
  515.         gotoxy( tx, ty );
  516.         rptchar('═',bx - tx);
  517.  
  518.         /* right side
  519.         */
  520.         gotoxy( bx, ty );
  521.         rptchar('╗',1);
  522.  
  523.         j = by - ty;       /* put the for loop condition into a register int */
  524.         for ( i = 1; i < j; i++ )
  525.         {
  526.              gotoxy( bx, ty + i);
  527.              rptchar('║',1);
  528.         }
  529.  
  530.         /* bottom line 
  531.         */
  532.         gotoxy( bx, by );
  533.         rptchar('╝',1);
  534.  
  535.         gotoxy( tx, by );
  536.         rptchar('═',bx - tx);
  537.         rptchar('╚',1);
  538.  
  539.         /* left side
  540.         */
  541.         for ( i = 1; i < j; i++ )
  542.         {
  543.              gotoxy( tx, ty + i);
  544.              rptchar('║',1);
  545.         }
  546.  
  547.         gotoxy(tx,ty);
  548.         rptchar('╔',1);
  549.  
  550.         /* last, restore entry dimensions, with fixups on squashed margins
  551.         */
  552.  
  553.         /* Box is AROUND window    Window is squashed onto box's outline */
  554.         /* ---------------------   ------------------------------------- */
  555.            ++tx;                   /* else tx always was TOPX, so tx++;  */
  556.            ++ty;                   /* else ty always was TOPY, so ty++;  */
  557.            --bx;                   /* else bx always was BTMX, so bx--;  */
  558.            --by;                   /* else by always was BTMY, so by--;  */
  559.  
  560.         setwindow( tx, ty, bx, by );
  561.         gotoxy(0,0);
  562.         vid_attr = temp;  /* restore user's vid_attr */
  563. }
  564.  
  565.  
  566.  
  567.  
  568. void wink( c )  /* window character out, obeys backspace and newline */
  569. char c;
  570. {
  571.  
  572.     if (!Initialized) vid_init(0);
  573.  
  574.     /* newline? */
  575.     if (c == '\n' || c == '\r') col = 80;  /* set range err to force CR */
  576.  
  577.     /* backspace? nondestructive = 8, destructive = 127 */
  578.     else if ( c == '\b' || c == 127)  /* NOTICE:  THIS PATH RETURNS */
  579.     {
  580.         col--;               /* decrement the column */
  581.         if (col < lm)        /* beyond left margin? */
  582.         {
  583.              row--;          /* yes, decrement the line */
  584.              if (row < tm)   /* above top margin? */
  585.              {
  586.                 row = tm;    /* yes, stick at 0,0 -- does not scroll down! */
  587.                 col = lm;
  588.              }
  589.              else col = rm;  /* no, jump to rightmost column */ 
  590.         }
  591.         if (c == 127) rptchar(SPC,1); /* destroy existing char on screen    */
  592.         goto synch;
  593.     } 
  594.  
  595.     else rptchar( c, 1 );    /* uses vid_attr attribute */
  596.  
  597.     /* bump x cursor position, do newline or scroll window up if necessary */
  598.  
  599.     if ( col >= rm )      /* need to newline? */
  600.     {
  601.         col = lm;
  602.         if ( row >= bm )  /* need to scroll? */
  603.         {
  604.             row = bm;
  605.             scrollup();
  606.         }
  607.         else row++;
  608.     }
  609.     else col++;
  610.  
  611.     synch:
  612.     if (synchronized) /* update machine cursor */
  613.         setmchnloc();
  614.  
  615. } /* wink */
  616.  
  617.  
  618.  
  619.  
  620.  
  621. void wputs( p )  /* write string into window, uses wink */
  622. char *p;
  623. {
  624.      register int test;
  625.      auto int temp;
  626.  
  627.      if (!Initialized) vid_init(0);
  628.  
  629.      temp = synchronized;
  630.      setsynch(0);
  631.      while (*p) 
  632.      {
  633.          if (*p == '^')  /* escape character? switch modes */
  634.          {
  635.              p++;              /* read escape command char */
  636.              test = *p & 0xFF; /* kill sign extension */
  637.              switch ( test ) 
  638.              {
  639.                  case  '0': { vid_attr = vid[ 0]; break; }
  640.                  case  '1': { vid_attr = vid[ 1]; break; }
  641.                  case  '2': { vid_attr = vid[ 2]; break; }
  642.                  case  '3': { vid_attr = vid[ 3]; break; }
  643.  
  644.                  case  '4': { vid_attr = vid[ 4]; break; }
  645.                  case  '5': { vid_attr = vid[ 5]; break; }
  646.                  case  '6': { vid_attr = vid[ 6]; break; }
  647.                  case  '7': { vid_attr = vid[ 7]; break; }
  648.                  case  '8': { vid_attr = vid[ 8]; break; }
  649.                  case  '9': { vid_attr = vid[ 9]; break; }
  650.  
  651.                  case  'Ω': { vid_attr = vid[10]; break; } /* ea */
  652.                  case  'δ': { vid_attr = vid[11]; break; } /* eb */
  653.                  case  '∞': { vid_attr = vid[12]; break; } /* ec */
  654.                  case  'φ': { vid_attr = vid[13]; break; } /* ed */
  655.                  case  'ε': { vid_attr = vid[14]; break; } /* ee */
  656.                  case  '∩': { vid_attr = vid[15]; break; } /* ef */
  657.  
  658.                  case  '^': { 
  659.                             wink( *p );  /* verbatim ^ char */
  660.                             break; 
  661.                             }
  662.                  default:   { 
  663.                             --p; 
  664.                             vid_attr = vid[0];  /* just ^, no command arg */
  665.                             break; 
  666.                             }
  667.              }
  668.              p++;  /* next after escape command */
  669.          }
  670.          else 
  671.          {
  672.              wink( *p++ );  /* obeys newline, tab, if present */
  673.          }
  674.      }
  675.      setsynch(temp); /* update machine cursor only at last, if at all */
  676.  
  677. } /* wputs */
  678.  
  679.  
  680.  
  681. /*================================*/
  682. /*  ROM-BIOS dependent functions  */
  683. /*================================*/
  684.  
  685. static void setmchnloc(void)  /* the ROM-BIOS gotoxy function */
  686. {
  687.     xy.h.ah = 2;
  688.     xy.h.bh = 0;
  689.     xy.h.dh = row;
  690.     xy.h.dl = col;
  691.     int86( 0x10, &xy, &xy );
  692. }
  693.  
  694.  
  695. void setcursize( r1, r2 )
  696. int r1,r2;
  697. {
  698.     union REGS rx;
  699.  
  700.     rx.h.ah = 1;
  701.     rx.h.ch = r1;
  702.     rx.h.cl = r2;
  703.     int86( 0x10, &rx, &rx );
  704. }
  705.  
  706.  
  707. void defcursor()  /* set default cursor for cga or mono */
  708. {
  709.     setsynch(1);
  710.     setcursize( rasterh, rasterl );
  711. }
  712.  
  713.  
  714. /* The cursor save and restore routines recognize the synchronized flag.
  715. ** If synchronized, the machine cursor is saved or restored, and the soft
  716. ** cursor is identical to the machine cursor; if not synchronized, the
  717. ** soft cursor is saved or restored, and the machine cursor (wherever it
  718. ** happens to be) is ignored.
  719. **
  720. ** The value of the current synchronized flag is saved or returned:
  721. **
  722. **   Savecursor() returns the value of the synchronized flag, and saves it.
  723. **   Restcursor() returns the value of the synchronized flag that was active
  724. **                when the cursor was saved, but does not restore it.
  725. */
  726.  
  727. int savecursor( x )
  728. union REGS *x;
  729. {
  730.     if (synchronized)  /* hard and soft are identical, save hard */
  731.     {
  732.        x->h.ah = 3;
  733.        x->h.bh = 0;
  734.        int86( 0x10, x, x );
  735.     }
  736.     else               /* save soft */
  737.     {
  738.        x->h.dh = row;
  739.        x->h.dl = col;
  740.     }
  741.     x->h.ah = synchronized;  /* save the flag for proper kind of restore */
  742.     return( x->h.ah );
  743. }
  744.  
  745.  
  746. int restcursor( x )
  747. union REGS *x;
  748. {
  749.     if (x->h.ah != 0)        /* non-zero, synchronization was ON when saved */
  750.     {
  751.        x->h.ah = 1;          /* so restore machine size */
  752.        x->h.bh = 0;          /* ensure "active" page */
  753.        int86( 0x10, x, x );
  754.        x->h.ah = 2;          /* and machine location */
  755.        int86( 0x10, x, x );
  756.     }
  757.     row = x->h.dh;           /* in any case, set soft location to match */
  758.     col = x->h.dl;
  759.     return( x->h.ah );
  760. }
  761.  
  762.  
  763.  
  764. void hidecursor()
  765. {
  766.     setsynch(0);
  767.     setcursize( 32,32 );
  768. }
  769.  
  770.  
  771. /*
  772. **  ================================================
  773. **  Sample calls to savescreen(), restorescreen()
  774. **  Note:  These only work with text screens, 
  775. **  they do not save CRTpage/CPUpage screen info.
  776. **  They DO save the current window margins!
  777. **  ================================================
  778. **
  779. **   main() {
  780. **
  781. **   union REGS x,z;
  782. **   char far *screen1, *screen2;
  783. **
  784. **   vid_init();                            WARNING: must call vid_init()
  785. **   screen1 = savescreen( &x );
  786. **   .
  787. **   .
  788. **          screen2 = savescreen( &z );     WARNING: these MUST nest properly
  789. **          .                                        or heap allocation will
  790. **          .                                        be annihilated! 
  791. **          .
  792. **          restorescreen( screen2, &z );
  793. **   .
  794. **   .
  795. **   restorescreen( screen1, &x );
  796. **   }
  797. **
  798. */
  799.  
  800. static void sorry( n ) int n;
  801. {
  802.     char *p,*q;
  803.     q = "init";
  804.     switch (n)
  805.     {
  806.     case 2:  q = "restorescreen"; p = "no screen saved, can't restore"; break;
  807.     case 1:  q = "savescreen";
  808.     case 0:  p = "not enough k, can't continue"; break;
  809.     default: q = "nasty"; p = "looks fatal"; break;
  810.     } 
  811.     printf("\n\aCIAO: %s error: %s\n",q,p);
  812.     exit(1);
  813. }
  814.  
  815.  
  816. char far *savescreen( cursor )  /* caller must keep pointer to storage! */
  817. union REGS *cursor;
  818. {
  819.     union REGS ry;
  820.     char far *scrfptr;
  821.      
  822.     if (!Initialized) vid_init(0);
  823.  
  824.     ry.h.ah = 0x03;                   /* read cursor position...       */
  825.     ry.h.bh = 0;
  826.     int86( 0x10, &ry, cursor );       /* store result in caller's var  */
  827.  
  828.     cursor->x.cflag = 1066;           /* a famous date in history...   */
  829.     cursor->h.ah = tm;                /* save caller's window settings */
  830.     cursor->h.al = lm;                /* cannot use bx, cx or dx       */
  831.     cursor->x.di = rm;
  832.     cursor->x.si = bm;
  833.  
  834.     scrfptr = _fmalloc( SCRLIM );
  835.     if ( scrfptr == 0L )
  836.     {
  837.         sorry(1);
  838.     }
  839.     movedata( vid_seg, 0, FP_SEG( scrfptr ), FP_OFF( scrfptr ), SCRLIM );
  840.     return (scrfptr);
  841. }
  842.  
  843.  
  844.  
  845.  
  846. void restorescreen( scrfptr, cursor ) /* caller keeps pointer to storage! */
  847. char far *scrfptr;
  848. union REGS *cursor;
  849. {
  850.     union REGS rx;
  851.  
  852.     if (!Initialized || cursor->x.cflag != 1066)
  853.     {
  854.         sorry(2);
  855.     }
  856.  
  857.     movedata( FP_SEG( scrfptr ), FP_OFF( scrfptr ), vid_seg, 0, SCRLIM );
  858.     _ffree( scrfptr );
  859.  
  860.     tm = cursor->h.ah;        /* restore caller's window settings */
  861.     lm = cursor->h.al;
  862.     rm = cursor->x.di;
  863.     bm = cursor->x.si;
  864.     cursor->x.ax = cursor->x.si = cursor->x.di = cursor->x.cflag = 0;
  865.  
  866.     rx.h.ah = 1;
  867.     rx.x.bx = cursor->x.bx;
  868.     rx.x.cx = cursor->x.cx;     /* set old cursor size     */
  869.     int86( 0x10, &rx, &rx );
  870.     rx.h.ah = 2;
  871.     rx.x.bx = cursor->x.bx;
  872.     rx.x.dx = cursor->x.dx;
  873.     int86( 0x10, &rx, cursor ); /* set old cursor position */
  874. }
  875.  
  876.  
  877.  
  878.  
  879. /*
  880. ** Initialize, Deinitialize
  881. */
  882.  
  883. static void init_criticals(mode) int mode;
  884. {
  885.     int i;
  886.     union REGS rx;
  887.  
  888.     if (((scribble = (char far *) _fmalloc(2)) == 0L) ||
  889.        ((hidescreen  = (char far *) _fmalloc(SCRLIM)) == 0L)) 
  890.            sorry(0);
  891.  
  892.     rasterh  = 12;                 /* assume monochrome cursor */
  893.     rasterl  = 13;
  894.  
  895.     rx.h.ah = 15;                  /* read current video mode */
  896.     int86( 0x10, &rx, &old_vid );
  897.     vid_page = old_vid.h.bh;
  898.     vid_wide = old_vid.h.ah;
  899.     vid_mode = old_vid.h.al;   /* a 7 means we found monochrome hardware */
  900.  
  901.  
  902.     if (mode == 0) mode = vid_mode;  /* request to stay in current mode? */
  903.  
  904.     /* in any case, allow only mono mode 7, or cga modes 2 or 3 */
  905.  
  906.     if (vid_mode != 7)         /* is hardware a color/graphics adapter? */
  907.     {
  908.        vid_seg = 0xB800;       /* yes, screen RAM base address is different! */
  909.        if ( mode == 3 )        /* asking for color?  set it up! */
  910.        {
  911.           for (i = 0; i < 16; i++) 
  912.               vid[i] = i;                      /* set color defaults */
  913.           vid[0]  = 0x17 | 0x08;               /* set normal         */
  914.           vid[1]  = 0x06 | 0x08;               /*  "  bold           */
  915.           vid[2]  = 0x71 | 0x08;               /*  "  emphasis       */
  916.           vid[3]  = 0x47 | 0x08 | 0x80;        /*  "  attention      */
  917.        }
  918.        else 
  919.        {
  920.           mode = 2;                 /* only modes 2 and 3 are allowed, here */
  921.           for (i = 4; i < 16; i++)  /* all else defaults to normal */
  922.               vid[i] = vid[0];
  923.        }
  924.        rasterh = 6;               /* cga default cursor raster lines */
  925.        rasterl = 7;
  926.        if (vid_mode != mode)      /* not already in the requested mode? */
  927.        {
  928.           rx.h.ah = 0;            /* if not, set requested mode */
  929.           rx.h.al = mode;
  930.           int86( 0x10, &rx, &rx );
  931.        }
  932.        rx.h.ah = 15;              /* read current mode again */
  933.        int86( 0x10, &rx, &rx );
  934.        vid_page = rx.h.bh;        /* set globals accordingly */ 
  935.        vid_wide = rx.h.ah;
  936.        vid_mode = rx.h.al;
  937.     }
  938.     Initialized = 1;              /* we are, basically, but...  */
  939.     setscreen(1);                 /* ensure activescreen is set */
  940.     vid_attr = vid[0];            /* and ensure vid_attr is set */
  941. }
  942.  
  943.  
  944.  
  945.  
  946. /* Vid_Init() - This is a "MUST CALL", but if the various routines which
  947. **              depend on finding initialized values and pointers find the
  948. **              Initialized flag set to zero, they will take it on themselves
  949. **              to call vid_init(0).  Any argument to vid_init is valid, but
  950. **              mode 7 is set if the monochrome adapter is in the system, and
  951. **              only modes 2 or 3 are set if the cga card is found.  The 
  952. **              0 argument requests that a valid current mode not be changed;
  953. **              this prevents the firmware from clearing the screen, if it's
  954. **              not absolutely necessary.  Vid_init() will always select the
  955. **              visible screen, and synchronize the soft & machine cursors.
  956. **              Also, selects appropriate default cursor size; cga and mono
  957. **              have different cursors.
  958. */
  959.  
  960. void vid_init( mode ) int mode;
  961. {
  962.     auto union REGS x;
  963.  
  964.     init_criticals(mode);      /* sets initialized flag on exit */
  965.  
  966.     savecursor( &x );          /* We can now make sure that hard and   */
  967.     row = x.h.dh;              /* soft cursors actually are identical, */
  968.     col = x.h.dl;              /* going soft <- hard!  Otherwise, the  */
  969.     synchronized = 1;          /* first savescreen( &cursor ) doesn't! */
  970. }                              
  971.  
  972.  
  973.  
  974.  
  975. void vid_exit()
  976. {
  977.      if (Initialized)
  978.      {
  979.           if (old_vid.h.al != vid_mode)
  980.           {
  981.                old_vid.h.ah = 0;
  982.                int86( 0x10, &old_vid, &old_vid );
  983.           }
  984.           _ffree(hidescreen);
  985.           _ffree(scribble);
  986.           Initialized = 0;  /* we're NOT initialized any more! */
  987.      }
  988.      setcursize( rasterh, rasterl );
  989. }
  990.  
  991.  
  992. /* eof: ciao.c */
  993.  
  994.