home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / libc / pc_hw / co80 / conio.c next >
Encoding:
C/C++ Source or Header  |  1996-07-23  |  23.1 KB  |  998 lines

  1. /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
  2. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  3. #include <libc/stubs.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <stdarg.h>
  7. #include <pc.h>
  8. #include <errno.h>
  9. #include <go32.h>
  10. #include <dpmi.h>
  11. #include <libc/farptrgs.h>
  12. #include <conio.h>
  13. #include <libc/bss.h>
  14.  
  15. int _wscroll = 1;
  16.  
  17. int directvideo = 1;  /* We ignore this */
  18.  
  19. static void setcursor(unsigned int shape);
  20. static int getvideomode(void);
  21. static void bell(void);
  22. static int get_screenattrib(void);
  23. static int isEGA(void);
  24. static int _scan_getche(FILE *fp);
  25. static int _scan_ungetch(int c, FILE *fp);
  26.  
  27. #define DBGGTINFO   0
  28.  
  29. static unsigned ScreenAddress = 0xb8000UL; /* initialize just in case */
  30. static struct text_info txinfo;
  31. static int ungot_char;
  32. static int char_avail = 0;
  33.  
  34. static int adapter_type = -1;       /* 1: EGA, 2: VGA/PGA/MCGA, else 0 */
  35. static int font_seg = -1;           /* segment of DOS buffer for 8x10 font */
  36. static unsigned last_mode = 0xffff; /* video mode when before program start */
  37. static int oldattrib =  -1;         /* text attribute before program start */
  38.  
  39. static int conio_count = -1;
  40.  
  41. #define VIDADDR(r,c) (ScreenAddress + 2*(((r) * txinfo.screenwidth) + (c)))
  42.  
  43. int
  44. puttext(int c, int r, int c2, int r2, void *buf)
  45. {
  46.   short *cbuf = (short *)buf;
  47.   /* we should check for valid parameters, and maybe return 0 */
  48.   r--, r2--, c--, c2--;
  49.   for (; r <= r2; r++)
  50.   {
  51.     dosmemput(cbuf, (c2-c+1)*2, VIDADDR(r, c));
  52.     cbuf += c2-c+1;
  53.   }
  54.   return 1;
  55. }
  56.  
  57. int
  58. gettext(int c, int r, int c2, int r2, void *buf)
  59. {
  60.   short *cbuf = (short *)buf;
  61.   /* we should check for valid parameters, and maybe return 0 */
  62.   r--, r2--, c--, c2--;
  63.   for (; r <= r2; r++)
  64.   {
  65.     dosmemget(VIDADDR(r, c), (c2-c+1)*2, cbuf);
  66.     cbuf += c2-c+1;
  67.   }
  68.   return 1;
  69. }
  70.         
  71. void
  72. gotoxy(int col, int row)
  73. {
  74.   ScreenSetCursor(row + txinfo.wintop - 2, col + txinfo.winleft - 2);
  75.   txinfo.curx = col;
  76.   txinfo.cury = row;
  77. }
  78.  
  79. int
  80. wherex(void)
  81. {
  82.   int row, col;
  83.   
  84.   ScreenGetCursor(&row, &col);
  85.   
  86.   return col - txinfo.winleft + 2;
  87. }
  88.     
  89. int
  90. wherey(void)
  91. {
  92.   int row, col;
  93.   
  94.   ScreenGetCursor(&row, &col);
  95.   
  96.   return row - txinfo.wintop + 2;
  97. }
  98.  
  99. void
  100. textmode(int mode)
  101. {
  102.   __dpmi_regs regs;
  103.   int mode_to_set = mode;
  104.   if (mode == LASTMODE)
  105.     mode = mode_to_set = last_mode;
  106.  
  107.   /* Should we support 2 LAST_MODEs in a row?  Right now we do; if not,
  108.      put an ``else'' clause before next line.  */
  109.   last_mode = txinfo.currmode;
  110.   if (mode == C4350)
  111.     /* 
  112.      * just set mode 3 and load 8x8 font, idea taken 
  113.      * (and code translated from Assembler to C)
  114.      * from Csaba Biegels stdvga.asm
  115.      */
  116.     mode_to_set = 0x03;  
  117.   regs.h.ah = 0x00;        /* set mode */
  118.   regs.h.al = mode_to_set;
  119.   __dpmi_int(0x10, ®s);
  120.   if (mode == C80 || mode == BW80 || mode == C4350)
  121.   {
  122.     if (isEGA())
  123.     {
  124.       /* 
  125.        * enable cursor size emulation, see Ralf Browns
  126.        * interrupt list
  127.        */
  128.       regs.h.ah = 0x12;
  129.       regs.h.bl = 0x34;
  130.       regs.h.al = 0x00;        /* 0: enable (1: disable) */
  131.       __dpmi_int(0x10, ®s);
  132.     }
  133.   }
  134.   if (mode == C4350)
  135.   {
  136.     if (!isEGA())
  137.       return;
  138.     /* load 8x8 font */
  139.     regs.x.ax = 0x1112;         
  140.     regs.x.bx = 0;
  141.     __dpmi_int(0x10, ®s);
  142.   }
  143.   /*    _setcursortype(_NORMALCURSOR); */
  144.   /* reinitialize txinfo structure to take into account new mode */
  145.   gppconio_init();
  146. #if 0
  147.   /*
  148.    * For mode C4350 the screen is not cleared on my OAK-VGA.
  149.    * Should we clear it here? TURBOC doesn't so we don't bother either.
  150.    */
  151.   clrscr();
  152. #endif
  153. }    
  154.     
  155. void
  156. textattr(int attr)
  157. {
  158.   txinfo.attribute = ScreenAttrib = (unsigned char)attr;
  159. }
  160.  
  161. void
  162. textcolor(int color)
  163. {
  164.   /* strip blinking (highest) bit and textcolor */
  165.   ScreenAttrib &= 0x70; /* strip blinking (highest) bit and textcolor */
  166.   txinfo.attribute=(ScreenAttrib |= (color & 0x8f));
  167. }
  168.  
  169. void
  170. textbackground(int color)
  171. {
  172.   /* strip background color, keep blinking bit */
  173.   ScreenAttrib &= 0x8f; 
  174.   /* high intensity background colors (>7) are not allowed 
  175.      so we strip 0x08 bit (and higher bits) of color */
  176.   txinfo.attribute=(ScreenAttrib |= ((color & 0x07) << 4));
  177. }
  178.  
  179. void
  180. highvideo(void)
  181. {
  182.   txinfo.attribute=(ScreenAttrib |= 0x08);
  183. }
  184.  
  185. void
  186. lowvideo(void)
  187. {
  188.   txinfo.attribute=(ScreenAttrib &= 0x07);
  189. }
  190.  
  191. void
  192. normvideo(void)
  193. {
  194.   txinfo.attribute = ScreenAttrib = txinfo.normattr;
  195. }
  196.  
  197. void
  198. _setcursortype(int type)
  199. {
  200.   unsigned cursor_shape;
  201.   switch (type)
  202.   {
  203.   case _NOCURSOR:
  204.     cursor_shape = 0x2000;
  205.     break;
  206.   case _SOLIDCURSOR:
  207.     cursor_shape = 0x0007;
  208.     break;
  209.     /*      case _NORMALCURSOR: */
  210.   default:
  211.     cursor_shape = 0x0607;
  212.     break;
  213.   }
  214.   setcursor(cursor_shape);
  215. }        
  216.  
  217. static void
  218. setcursor(unsigned int cursor_shape)
  219. /* Sets the shape of the cursor */
  220. {
  221.   __dpmi_regs reg;
  222.  
  223.   reg.h.ah = 1;
  224.   reg.x.cx = cursor_shape;
  225.   __dpmi_int(0x10, ®);
  226. } /* setcursor */
  227.  
  228. static void
  229. getwincursor(int *row, int *col)
  230. {
  231.   ScreenGetCursor(row, col);
  232. }
  233.  
  234. void
  235. clreol(void)
  236. {
  237.   short   image[ 256 ];
  238.   short   val = ' ' | (ScreenAttrib << 8);
  239.   int     c, row, col, ncols;
  240.   
  241.   getwincursor(&row, &col);
  242.   ncols = txinfo.winright - col;
  243.   
  244.   for (c = 0; c < ncols; c++)
  245.     image[ c ] = val;
  246.   
  247.   puttext(col + 1, row + 1, txinfo.winright, row + 1, image);
  248. }
  249.  
  250. static void
  251. fillrow(int row, int left, int right, int fill)
  252. {
  253.   int col;
  254.   short filler[right-left+1];
  255.   
  256.   for (col = left; col <= right; col++)
  257.     filler[col-left] = fill;
  258.   dosmemput(filler, (right-left+1)*2, VIDADDR(row, left));
  259. }
  260.  
  261. void
  262. clrscr(void)
  263. {
  264.   short filler[txinfo.winright - txinfo.winleft + 1];
  265.   int row, col;
  266.   for (col=0; col < txinfo.winright - txinfo.winleft + 1; col++)
  267.     filler[col] = ' ' | (ScreenAttrib << 8);
  268.   for (row=txinfo.wintop-1; row < txinfo.winbottom; row++)
  269.     dosmemput(filler, (txinfo.winright - txinfo.winleft + 1)*2,
  270.      VIDADDR(row, txinfo.winleft - 1));
  271.   gotoxy(1, 1);
  272. }
  273.  
  274. int
  275. putch(int c)
  276. {
  277.   int     row, col;
  278.   
  279.   ScreenGetCursor(&row, &col);
  280.   
  281.   /*  first, handle the character */
  282.   if (c == '\n')
  283.   {
  284.     row++;
  285.   }
  286.   else if (c == '\r')
  287.   {
  288.     col = txinfo.winleft - 1;
  289.   }
  290.   else if (c == '\b')
  291.   {
  292.     if (col > txinfo.winleft - 1)
  293.       col--;  
  294.     else if (row > txinfo.wintop -1)
  295.     {
  296.       /* 
  297.        * Turbo-C ignores this case; we are smarter.
  298.        */
  299.       row--;
  300.       col = txinfo.winright-1;
  301.     }  
  302.   }      
  303.   else if (c == 0x07)
  304.     bell();
  305.   else {
  306.     ScreenPutChar(c, ScreenAttrib, col, row);
  307.     col++;
  308.   }
  309.   
  310.   /* now, readjust the window     */
  311.   
  312.   if (col >= txinfo.winright)
  313.   {
  314.     col = txinfo.winleft - 1;
  315.     row++;
  316.   }
  317.   
  318.   if (row >= txinfo.winbottom)
  319.   {
  320.     /* scrollwin(0, txinfo.winbottom - txinfo.wintop, 1); */
  321.     if (_wscroll)
  322.     {
  323.       ScreenSetCursor(txinfo.wintop-1,0);
  324.       delline();
  325.     }
  326.     row--;
  327.   }
  328.   
  329.   ScreenSetCursor(row, col);
  330.   txinfo.cury = row - txinfo.wintop + 2;
  331.   txinfo.curx = col - txinfo.winleft + 2;
  332.   return c;
  333. }
  334.  
  335. int
  336. getche(void)
  337. {
  338.   if (char_avail)
  339.     /*
  340.      * We don't know, wether the ungot char was already echoed
  341.      * we assume yes (for example in cscanf, probably the only
  342.      * place where ungetch is ever called.
  343.      * There is no way to check for this really, because
  344.      * ungetch could have been called with a character that
  345.      * hasn't been got by a conio function.
  346.      * We don't echo again.
  347.      */ 
  348.     return(getch());
  349.   return (putch(getch()));
  350. }
  351.  
  352. int
  353. getch(void)
  354. {
  355.   __dpmi_regs regs;
  356.   int c;
  357.   if (char_avail)
  358.   {
  359.     c = ungot_char;
  360.     char_avail = 0;
  361.   }
  362.   else
  363.   {
  364.     regs.x.ax = 0x0700;
  365.     __dpmi_int(0x21, ®s);
  366.     c = regs.h.al;
  367.   }
  368.   return(c);
  369. }
  370.  
  371. int
  372. ungetch(int c)
  373. {
  374.   if (char_avail)
  375.     return(EOF);
  376.   ungot_char = c;
  377.   char_avail = 1;
  378.   return(c);
  379. }
  380.  
  381. /* 
  382.  * kbhit from libc in libsrc/c/dos/kbhit.s doesn't check
  383.  * for ungotten chars, so we have to provide a new one
  384.  * Don't call it kbhit, rather use a new name (_conio_kbhit)
  385.  * and do a #define kbhit _conio_kbhit in gppconio.h.
  386.  * The old kbhit still can be used if gppconio.h
  387.  * is not included of after #undef kbhit
  388.  * If you don't use ungetch (directly or indirectly by cscanf)
  389.  * both kbhit and _conio_kbhit are the same.
  390.  * So this shouldn't cause any trouble with previously written
  391.  * source, because ungetch wasn't available.
  392.  * The only problem might be, if anybody just included gppconio.h
  393.  * and has not linked with libpc, (I can't think of a good reason
  394.  * for this). This will result a link error (undefined symbol _conio_kbhit).
  395.  */
  396.  
  397. #undef kbhit  /* want to be able to call kbhit from libc */
  398.  
  399. int
  400. _conio_kbhit(void)
  401. {
  402.   if (char_avail)
  403.     return(1);
  404.   else
  405.     return(kbhit());
  406. }    
  407.  
  408. /*
  409.  * The next two functions are needed by cscanf
  410.  */
  411. static int
  412. _scan_getche(FILE *fp)
  413. {
  414.   return(getche());
  415. }
  416.  
  417. static int
  418. _scan_ungetch(int c, FILE *fp)
  419. {
  420.   return(ungetch(c));
  421. }
  422.  
  423.  
  424. void
  425. insline(void)
  426. {
  427.   int row, col, left, right, nbytes, bot, fill;
  428.   ScreenGetCursor(&row, &col);
  429.   left = txinfo.winleft - 1;
  430.   right = txinfo.winright - 1;
  431.   nbytes = (right-left+1)*2;
  432.   bot = txinfo.winbottom-1;
  433.   fill = ' ' | (ScreenAttrib << 8);
  434.   while (bot > row)
  435.   {
  436.     movedata(_dos_ds, VIDADDR(bot-1, left),
  437.          _dos_ds, VIDADDR(bot, left),
  438.          nbytes);
  439.     bot--;
  440.   }
  441.   fillrow(row,left,right,fill);
  442. }
  443.  
  444.  
  445. void
  446. delline(void)
  447. {
  448.   int row, col, left, right, nbytes, bot, fill;
  449.   ScreenGetCursor(&row, &col);
  450.   left = txinfo.winleft - 1;
  451.   right = txinfo.winright - 1;
  452.   nbytes = (right-left+1)*2;
  453.   bot = txinfo.winbottom-1;
  454.   fill = ' ' | (ScreenAttrib << 8);
  455.   while(row < bot)
  456.   {
  457.     movedata(_dos_ds, VIDADDR(row+1, left),
  458.          _dos_ds, VIDADDR(row, left),
  459.          nbytes);
  460.     row++;
  461.   }
  462.   fillrow(bot,left,right,fill);
  463. }
  464.  
  465.  
  466. void
  467. window(int left, int top, int right, int bottom)
  468. {
  469.   if (top < 1 || left < 1 || right > txinfo.screenwidth ||
  470.       bottom > txinfo.screenheight)
  471.     return;
  472.   
  473.   txinfo.wintop = top;
  474.   txinfo.winleft = left;
  475.   txinfo.winright = right;
  476.   txinfo.winbottom = bottom;
  477.   gotoxy(1,1);
  478. }
  479.  
  480.  
  481. int
  482. cputs(const char *s)
  483. {
  484.   int     row, col,c;
  485.   const unsigned char *ss = (const unsigned char *)s;
  486.   short *viaddr;
  487.   short sa = ScreenAttrib << 8;
  488.   ScreenGetCursor(&row, &col);
  489.   viaddr = (short *)VIDADDR(row,col);
  490.   /* 
  491.    * Instead of just calling putch; we do everything by hand here,
  492.    * This is much faster. We don't move the cursor after each character,
  493.    * only after the whole string is written, because ScreenSetCursor
  494.    * needs to long because of switching to real mode needed with djgpp. 
  495.    * You won't recognize the difference.
  496.    */
  497.   while ((c = *ss++))
  498.   {
  499.     /*  first, handle the character */
  500.     if (c == '\n')
  501.     {
  502.       row++;
  503.       viaddr += txinfo.screenwidth;
  504.     }
  505.     else if (c == '\r')
  506.     {
  507.       col = txinfo.winleft - 1;
  508.       viaddr = (short *)VIDADDR(row,col);
  509.     }
  510.     else if (c == '\b')
  511.     {
  512.       if (col > txinfo.winleft-1) 
  513.       {
  514.     col--;
  515.     viaddr--;
  516.       }
  517.       else if (row > txinfo.wintop -1)
  518.       {
  519.     /* 
  520.      * Turbo-C ignores this case. We want to be able to
  521.      * edit strings with backspace in gets after
  522.      * a linefeed, so we are smarter
  523.      */
  524.     row--;
  525.     col = txinfo.winright-1;
  526.     viaddr = (short *)VIDADDR(row,col);
  527.       }
  528.     }
  529.     else if (c == 0x07)
  530.       bell();
  531.     else {
  532.       short q = c | sa;
  533.       dosmemput(&q, 2, (int)viaddr);
  534.       viaddr++;
  535.       col++;
  536.     }
  537.       
  538.     /* now, readjust the window     */
  539.       
  540.     if (col >= txinfo.winright) {
  541.       col = txinfo.winleft - 1;
  542.       row++;
  543.       viaddr = (short *)VIDADDR(row,col);
  544.     }
  545.       
  546.     if (row >= txinfo.winbottom) {
  547.       if (_wscroll)
  548.       {
  549.     ScreenSetCursor(txinfo.wintop-1,0); /* goto first line in window */
  550.     delline();        /* and delete it */
  551.       }
  552.       row--;
  553.       viaddr -= txinfo.screenwidth;
  554.     }
  555.   }
  556.   
  557.   ScreenSetCursor(row, col);
  558.   txinfo.cury = row - txinfo.wintop + 2;
  559.   txinfo.curx = col - txinfo.winleft + 2;
  560.   return(*(--ss));
  561. }
  562.  
  563.  
  564. int
  565. cprintf(const char *fmt, ...)
  566. {
  567.   int     cnt;
  568.   char    buf[ 2048 ];        /* this is buggy, because buffer might be too small. */
  569.   va_list ap;
  570.   
  571.   va_start(ap, fmt);
  572.   cnt = vsprintf(buf, fmt, ap);
  573.   va_end(ap);
  574.   
  575.   cputs(buf);
  576.   return cnt;
  577. }
  578.  
  579. char *
  580. cgets(char *string)
  581. {
  582.   unsigned len = 0;
  583.   unsigned int maxlen_wanted;
  584.   char *sp;
  585.   int c;
  586.   /*
  587.    * Be smart and check for NULL pointer.
  588.    * Don't know wether TURBOC does this.
  589.    */
  590.   if (!string)
  591.     return(NULL);
  592.   maxlen_wanted = (unsigned int)((unsigned char)string[0]);
  593.   sp = &(string[2]);
  594.   /* 
  595.    * Should the string be shorter maxlen_wanted including or excluding
  596.    * the trailing '\0' ? We don't take any risk.
  597.    */
  598.   while(len < maxlen_wanted-1)
  599.   {
  600.     c=getch();
  601.     /*
  602.      * shold we check for backspace here?
  603.      * TURBOC does (just checked) but doesn't in cscanf (thats harder
  604.      * or even impossible). We do the same.
  605.      */
  606.     if (c == '\b')
  607.     {
  608.       if (len > 0)
  609.       {
  610.     cputs("\b \b");        /* go back, clear char on screen with space
  611.                    and go back again */
  612.     len--;
  613.     sp[len] = '\0';        /* clear the character in the string */
  614.       }
  615.     }
  616.     else if (c == '\r')
  617.     {
  618.       sp[len] = '\0';
  619.       break;
  620.     }
  621.     else if (c == 0)
  622.     {
  623.       /* special character ends input */
  624.       sp[len] = '\0';
  625.       ungetch(c);        /* keep the char for later processing */
  626.       break;
  627.     }
  628.     else
  629.     {
  630.       sp[len] = putch(c);
  631.       len++;
  632.     }
  633.   }
  634.   sp[maxlen_wanted-1] = '\0';
  635.   string[1] = (char)((unsigned char)len);
  636.   return(sp);   
  637. }    
  638.  
  639. int
  640. cscanf(const char *fmt, ...)
  641. {
  642.   return(_doscan_low(NULL, _scan_getche, _scan_ungetch, 
  643.              fmt, (void **)((&fmt)+1)));
  644. }
  645.  
  646. int
  647. movetext(int left, int top, int right, int bottom, int dleft, int dtop)
  648. {
  649.   char    *buf = alloca((right - left + 1) * (bottom - top + 1) * 2);
  650.   
  651.   gettext(left, top, right, bottom, buf);
  652.   puttext(dleft, dtop, dleft + right - left, dtop + bottom - top, buf);
  653.   return 1;
  654. }
  655.  
  656. static void
  657. _gettextinfo(struct text_info *t)
  658. {
  659.   int row, col;
  660.   
  661.   t->winleft = t->wintop = 1;
  662.   t->winright = t->screenwidth = ScreenCols();
  663.   t->winbottom = t->screenheight = ScreenRows();
  664.   ScreenAttrib = t->attribute = get_screenattrib();
  665.   t->normattr = oldattrib;
  666.   t->currmode = getvideomode();
  667.   ScreenGetCursor(&row, &col);
  668.   t->curx = col+1;
  669.   t->cury = row+1;
  670. #if DBGGTINFO
  671.   printf("left=%2d,right=%2d,top=%2d,bottom=%2d\n",t->winleft,
  672.      t->winright,t->wintop,t->winbottom);
  673.   printf("scrht=%2d,scrwid=%2d,norm=%2x,mode=%2d,x=%2d,y=%2d\n",
  674.      t->screenheight, t->screenwidth, t->normattr, t->currmode,
  675.      t->curx, t->cury);
  676. #endif
  677. }
  678.  
  679. void
  680. gettextinfo(struct text_info *t)
  681. {
  682.   *t = txinfo; 
  683. #if DBGGTINFO
  684.   printf("left=%2d,right=%2d,top=%2d,bottom=%2d\n",t->winleft,
  685.      t->winright,t->wintop,t->winbottom);
  686.   printf("scrht=%2d,scrwid=%2d,norm=%2x,mode=%2d,x=%2d,y=%2d\n",
  687.      t->screenheight, t->screenwidth, t->normattr, t->currmode,
  688.      t->curx, t->cury);
  689. #endif
  690. }
  691.  
  692. static int
  693. getvideomode(void)
  694. {
  695.   int mode = ScreenMode();
  696.   /* 
  697.    * in mode C80 we might have loaded a different font
  698.    */
  699.   if (mode == C80)
  700.     if (ScreenRows() > 25)
  701.       mode = C4350;
  702.   return(mode);
  703. }
  704.     
  705.  
  706. static void
  707. bell(void)
  708. {
  709.   __dpmi_regs regs;
  710.   regs.h.ah = 0x0e;        /* write */
  711.   regs.h.al = 0x07;        /* bell */
  712.   __dpmi_int(0x10, ®s);
  713. }
  714.  
  715. static int 
  716. get_screenattrib(void)
  717. {
  718.   __dpmi_regs regs;
  719.   regs.h.ah = 0x08;        /* read character and attribute */
  720.   regs.h.bh = 0;        /* video page 0 */
  721.   __dpmi_int(0x10, ®s);
  722.   return(regs.h.ah & 0x7f);    /* strip highest (BLINK) bit */
  723. }
  724.  
  725. /* Check if we have at least EGA.
  726.    Return 1 if EGA, 2 if VGA/PGA/MCGA, else 0. */
  727. static int
  728. isEGA(void)
  729. {
  730.   if (adapter_type == -1)
  731.     {
  732.       __dpmi_regs regs;
  733.  
  734.       /* Get display combination code.  */
  735.       regs.x.ax = 0x1a00;
  736.       __dpmi_int(0x10, ®s);
  737.       if (regs.h.al == 0x1a)    /* if Int 10h/AX=1A00h supported */
  738.         switch (regs.h.bl)
  739.           {
  740.             case 4:
  741.             case 5:
  742.                 adapter_type = 1; /* EGA */
  743.                 break;
  744.             case 6:             /* PGA */
  745.             case 7:             /* VGA */
  746.             case 8:             /* VGA */
  747.             case 10:            /* MCGA */
  748.             case 11:            /* MCGA */
  749.             case 12:            /* MCGA */
  750.                 adapter_type = 2;
  751.                 break;
  752.             default:
  753.                 adapter_type = 0;
  754.           }
  755.  
  756.       else
  757.         {
  758.           /* Int 10h/AX=1A00h not supported.  Try getting EGA info.  */
  759.           regs.h.ah = 0x12;
  760.           regs.h.bl = 0x10;
  761.           regs.h.bh = 0xff;
  762.           __dpmi_int(0x10, ®s);
  763.           adapter_type = (regs.h.bh != 0xff);
  764.         }
  765.     }
  766.  
  767.   return adapter_type;
  768. }
  769.  
  770. /* Set screen scan lines and load appropriate font.
  771.    SCAN_LINES and FONT are as required by Int 10h functions 12h and 11h */
  772. static void
  773. set_scan_lines_and_font(int scan_lines, int font)
  774. {
  775.   __dpmi_regs regs;
  776.  
  777.   /* Set 200/350/400 scan lines.  */
  778.   regs.h.ah = 0x12;
  779.   regs.h.al = scan_lines;       /* 0: 200, 1: 350, 2: 400 */
  780.   regs.h.bl = 0x30;
  781.   __dpmi_int(0x10, ®s);
  782.  
  783.   /* Scan lines setting only takes effect when video mode is set.  */
  784.   regs.x.ax = txinfo.currmode == 7 ? 7 : 3;
  785.   __dpmi_int(0x10, ®s);
  786.  
  787.   /* Load a ROM BIOS font (0x11: 8x14, 0x12: 8x8, 0x14: 8x16).  */
  788.   regs.h.bl = 0;                /* block zero */
  789.   regs.h.ah = 0x11;
  790.   regs.h.al = font & 0xff;
  791.   __dpmi_int(0x10, ®s);
  792. }
  793.  
  794. /* Stretch a 8x8 font to the 8x10 character box.  This is required to
  795.    use 80x40 mode on a VGA or 80x35 mode on an EGA, because the character
  796.    box is 10 lines high, and the ROM BIOS doesn't have an appropriate font.
  797.    So we create one from the 8x8 font by adding an extra blank line
  798.    from each side.  */
  799. static void
  800. maybe_create_8x10_font(void)
  801. {
  802.   unsigned char *p;
  803.   unsigned long src, dest, i, j;
  804.  
  805.   if (font_seg == -1)
  806.     {
  807.       __dpmi_regs regs;
  808.       int buf_pm_sel;
  809.       
  810.       /* Allocate buffer in conventional memory. */
  811.       font_seg = __dpmi_allocate_dos_memory(160, &buf_pm_sel);
  812.  
  813.       if (font_seg == -1)
  814.         return;
  815.  
  816.       /* Get the pointer to the 8x8 font table.  */
  817.       p = (unsigned char *)malloc(2560); /* 256 chars X 8x10 pixels */
  818.       if (p == (unsigned char *)0)
  819.         {
  820.           errno = ENOMEM;
  821.           __dpmi_free_dos_memory(buf_pm_sel);
  822.           font_seg = -1;
  823.           return;
  824.         }
  825.       regs.h.bh = 3;
  826.       regs.x.ax = 0x1130;
  827.       __dpmi_int(0x10, ®s);
  828.       src =  ( ( (unsigned)regs.x.es ) << 4 ) + regs.x.bp;
  829.       dest = ( (unsigned)font_seg ) << 4;
  830.  
  831.       /* Now copy the font to our table, stretching it to 8x10. */
  832.       _farsetsel(_dos_ds);
  833.       for (i = 0; i < 256; i++)
  834.         {
  835.           /* Fill first extra scan line with zeroes. */
  836.           _farnspokeb(dest++, 0);
  837.  
  838.           for (j = 0; j < 8; j++)
  839.             {
  840.               unsigned char val = _farnspeekb(src++);
  841.  
  842.               _farnspokeb(dest++, val);
  843.             }
  844.  
  845.           /* Fill last extra scan line with zeroes. */
  846.           _farnspokeb(dest++, 0);
  847.         }
  848.     }
  849. }
  850.  
  851. /* Load the 8x10 font we created into character generator RAM.  */
  852. static void
  853. load_8x10_font(void)
  854. {
  855.   __dpmi_regs regs;
  856.  
  857.   maybe_create_8x10_font();         /* create if needed */
  858.   if (font_seg == -1)
  859.     return;
  860.   regs.x.es = font_seg;             /* pass pointer to our font in ES:BP */
  861.   regs.x.bp = 0;
  862.   regs.x.dx = 0;                    /* 1st char: ASCII 0 */
  863.   regs.x.cx = 256;                  /* 256 chars */
  864.   regs.h.bh = 10;                   /* 10 points per char */
  865.   regs.h.bl = 0;                    /* block 0 */
  866.   regs.x.ax = 0x1110;
  867.   __dpmi_int(0x10, ®s);
  868. }
  869.  
  870. /* Set screen scan lines and load 8x10 font.
  871.    SCAN_LINES is as required by Int 10h function 12h. */
  872. static void
  873. set_scan_lines_and_8x10_font(int scan_lines)
  874. {
  875.   __dpmi_regs regs;
  876.  
  877.   regs.h.bl = 0x30;
  878.   regs.h.ah = 0x12;
  879.   regs.h.al = scan_lines;           /* 0: 200, 1: 350, 2: 400 */
  880.   __dpmi_int(0x10, ®s);
  881.  
  882.   /* Set video mode, so that scan lines we set will take effect.  */
  883.   regs.x.ax = txinfo.currmode == 7 ? 7 : 3;
  884.   __dpmi_int(0x10, ®s);
  885.  
  886.   /* Load our 8x10 font and enable intensity bit.  */
  887.   load_8x10_font();
  888. }
  889.  
  890. /* Switch to screen lines given by NLINES.  */
  891. void
  892. _set_screen_lines(int nlines)
  893. {
  894.   switch (nlines)
  895.     {
  896.       __dpmi_regs regs;
  897.  
  898.       case 25:
  899.           if (adapter_type)
  900.             {
  901.               /* Set 350 scan lines for EGA, 400 for VGA.  */
  902.               regs.h.bl = 0x30;
  903.               regs.h.ah = 0x12;
  904.               regs.h.al = (adapter_type > 1 ? 2 : 1);
  905.               __dpmi_int(0x10, ®s);
  906.  
  907.               /* Load ROM BIOS font: 8x14 for EGA, 8x16 for VGA.  */
  908.               regs.h.bl = 0;
  909.               regs.h.ah = 0x11;
  910.               regs.h.al = (adapter_type > 1 ? 0x14 : 0x11);
  911.               __dpmi_int(0x10, ®s);
  912.             }
  913.  
  914.           /* Set video mode.  */
  915.           regs.x.ax = txinfo.currmode == 7 ? 7 : 3;
  916.           __dpmi_int(0x10, ®s);
  917.           break;
  918.       case 28:      /* VGA only */
  919.           if (adapter_type > 1)
  920.             set_scan_lines_and_font(2, 0x11);
  921.           break;
  922.       case 35:      /* EGA or VGA */
  923.           if (adapter_type)
  924.             set_scan_lines_and_8x10_font(1);
  925.           break;
  926.       case 40:      /* VGA only */
  927.           if (adapter_type > 1)
  928.             set_scan_lines_and_8x10_font(2);
  929.           break;
  930.       case 43:      /* EGA or VGA */
  931.           if (adapter_type)
  932.             set_scan_lines_and_font(1, 0x12);
  933.           break;
  934.       case 50:      /* VGA only */
  935.           if (adapter_type > 1)
  936.             set_scan_lines_and_font(2, 0x12);
  937.           break;
  938.     }
  939.  
  940.   _gettextinfo(&txinfo);
  941. }
  942.  
  943. void
  944. blinkvideo(void)
  945. {
  946.  
  947.   /* Set intensity/blinking bit to BLINKING.  */
  948.   __dpmi_regs regs;
  949.   regs.h.bl = 1;
  950.   regs.x.ax = 0x1003;
  951.   __dpmi_int(0x10, ®s);
  952. }
  953.  
  954. void
  955. intensevideo(void)
  956. {
  957.  
  958.   /* Set intensity/blinking bit to INTENSE (bright background).  */
  959.   __dpmi_regs regs;
  960.   regs.h.bl = 0;
  961.   regs.x.ax = 0x1003;
  962.   __dpmi_int(0x10, ®s);
  963. }
  964.  
  965. void
  966. gppconio_init(void)
  967. {
  968.   /* Force initialization in restarted programs (emacs).  */
  969.   if (conio_count != __bss_count)
  970.     {
  971.       conio_count = __bss_count;
  972.       oldattrib = -1;
  973.       last_mode = 0xffff;
  974.     }
  975.  
  976.   (void)isEGA();    /* sets the global ADAPTER_TYPE */
  977.  
  978.   if (oldattrib == -1)
  979.     oldattrib = get_screenattrib();
  980.   if (last_mode == 0xffff)
  981.     last_mode = getvideomode();
  982.   _gettextinfo(&txinfo);
  983.   if (txinfo.currmode == 7)    /* MONO */
  984.     ScreenAddress = 0xb0000UL;
  985.   else
  986.     ScreenAddress = 0xb8000UL;
  987.  
  988. #if 0
  989.   /* Why should gppconio_init() restore OLDATTRIB?  I think it
  990.      shouldn't, because this causes change of colors when all
  991.      user wants is to update TXINFO.  And besides, _gettextinfo()
  992.      above has already set ScreenAttrib.  */
  993.   ScreenAttrib = txinfo.normattr = txinfo.attribute = oldattrib;
  994. #endif
  995. }
  996.  
  997. __asm__(".section .ctor; .long _gppconio_init; .section .text");
  998.