home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / jove-4.16-src.tgz / tar.out / bsd / jove / ibmpcdos.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  10KB  |  489 lines

  1. /************************************************************************
  2.  * This program is Copyright (C) 1986-1996 by Jonathan Payne.  JOVE is  *
  3.  * provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is *
  5.  * included in all the files.                                           *
  6.  ************************************************************************/
  7.  
  8. #include "jove.h"
  9.  
  10. #ifdef IBMPCDOS    /* the body is the rest of this file */
  11.  
  12. #include "fp.h"    /* scr_putchar */
  13. #include "chars.h"
  14. #include "screen.h"
  15. #include "term.h"
  16.  
  17. /* here come the actual emulation routines */
  18.  
  19. #include <dos.h>
  20. #include <conio.h>
  21.  
  22. typedef unsigned char    BYTE;
  23. typedef unsigned int    WORD;
  24.  
  25. #define VBS_set_cursor_position    0x02
  26. #define VBS_get_cursor_position_and_size    0x03
  27. #define VBS_select_active_display_page    0x05
  28. #define VBS_scroll_window_up    0x06
  29. #define VBS_scroll_window_down    0x07
  30. #define VBS_read_character_and_attribute    0x08
  31. #define VBS_write_character_and_attribute    0x09
  32. #define VBS_TTY_character_output    0x0e
  33. #define VBS_get_current_video_state    0x0f
  34.  
  35. #define VBSF_get_font_information    0x1130
  36.  
  37. #define VideoBIOS(r)    int86(0x10, (r), (r));
  38.  
  39. private BYTE
  40.     c_attr = 0x07,    /* current attribute white on black */
  41.     c_row = 0,    /* current row */
  42.     c_col = 0;    /* current column */
  43.  
  44. int
  45.     Txattr = 0x07,    /* VAR: text-attribute (white on black) */
  46.     Mlattr = 0x70,    /* VAR: mode-line-attribute (black on white) */
  47.     Hlattr = 0x10;    /* VAR: highlight-attribute */
  48.  
  49. void
  50. getTERM()
  51. {
  52.     /* Check if 101- or 102-key keyboard is installed.
  53.      * This test is apparently unreliable, so we allow override.
  54.      * Courtesy of Ralph Brown's interrupt list.
  55.      */
  56.     char _far *kbd_stat_byte3 = (char _far *)0x00400096UL;
  57.     enhanced_keybrd = (0x10 & *kbd_stat_byte3) != 0;
  58.     pcSetTerm();
  59. }
  60.  
  61. private void
  62. setcolor(attr)
  63. BYTE attr;
  64. {
  65.     c_attr = attr;
  66. }
  67.  
  68. private void
  69. set_cur()
  70. {
  71.     union REGS vr;
  72.  
  73.     vr.h.ah = VBS_set_cursor_position;
  74.     vr.h.bh = 0;    /* video page 0 */
  75.     vr.h.dl = c_col;
  76.     vr.h.dh = c_row;
  77.     VideoBIOS(&vr);
  78. }
  79.  
  80. private void
  81. get_cur()
  82. {
  83.     union REGS vr;
  84.  
  85.     vr.h.ah = VBS_get_cursor_position_and_size;
  86.     vr.h.bh = 0;    /* video page 0 */
  87.     VideoBIOS(&vr);
  88.     c_col = vr.h.dl;
  89.     c_row = vr.h.dh;
  90. }
  91.  
  92. private BYTE
  93. chpl()
  94. {
  95.     union REGS vr;
  96.  
  97.     vr.h.ah = VBS_get_current_video_state;
  98.     VideoBIOS(&vr);
  99.     return vr.h.ah;
  100. }
  101.  
  102. #define cur_mov(r, c)    { c_row = (r); c_col = (c); set_cur(); }
  103.  
  104. private void
  105. scr_win(op, no, ur, lr)
  106. int op, no, ur, lr;
  107. {
  108.     union REGS vr;
  109.  
  110.     vr.h.ah = op;    /* scroll window up or down */
  111.     vr.h.al = no;    /* number of rows to scroll */
  112.  
  113.     vr.h.ch = ur;    /* upper row */
  114.     vr.h.cl = 0;    /* left column */
  115.     vr.h.dh = lr;    /* lower row */
  116.     vr.h.dl = CO-1;    /* right column */
  117.  
  118.     vr.h.bh = c_attr;
  119.     VideoBIOS(&vr);
  120. }
  121.  
  122. void
  123. i_lines(top, bottom, num)
  124. int top, bottom, num;
  125. {
  126.     scr_win(VBS_scroll_window_down, num, top, bottom);
  127. }
  128.  
  129. void
  130. d_lines(top, bottom, num)
  131. int top, bottom, num;
  132. {
  133.     scr_win(VBS_scroll_window_up, num, top, bottom);
  134. }
  135.  
  136. void
  137. clr_page()
  138. {
  139.     SO_off();
  140.     /* Note: VBS_scroll_window_up with a count of 0 clears the screen! */
  141.     scr_win(VBS_scroll_window_up, 0, 0, ILI);
  142.     cur_mov(0, 0);
  143. }
  144.  
  145. private void
  146. ch_out(c, n)
  147. BYTE c, n;
  148. {
  149.     union REGS vr;
  150.  
  151.     vr.h.ah = VBS_write_character_and_attribute;
  152.     vr.h.al = c;
  153.     vr.h.bl = c_attr;
  154.     vr.h.bh = 0;    /* video page 0 */
  155.     vr.x.cx = n;
  156.     VideoBIOS(&vr);
  157. }
  158.  
  159. void
  160. clr_eoln()
  161. {
  162.     ch_out(' ', CO-c_col);
  163. }
  164.  
  165. /* Video mode setting derived from code posted to comp.os.msdos.programmer
  166.  * by Joe Huffman 1990 August 15 (found on SIMTEL in msdos/screen/vidmode.zip)
  167.  */
  168.  
  169. private BYTE
  170. lpp()
  171. {
  172.     union REGS vr;
  173.     int    lines;
  174.  
  175.     vr.x.ax = VBSF_get_font_information;
  176.     vr.h.bh = 0;    /* we don't care which pointer we get back */
  177.     vr.h.dl = 0;    /* default, if BIOS doesn't know how to this */
  178.     VideoBIOS(&vr);
  179.     lines = vr.h.dl;    /* number of last line on screen */
  180.     switch (lines) {
  181.     default:
  182.         return lines + 1;
  183.     case 25:
  184.     case 28:
  185.     case 43:
  186.     case 50:
  187.         return lines;    /* IBM EGA BUG!*/
  188.     case 0:
  189.         return 25;    /* Who knows?  Just a guess. */
  190.     }
  191. }
  192.  
  193. /* discover current video attribute */
  194.  
  195. private void
  196. get_c_attr()
  197. {
  198.     union REGS vr;
  199.  
  200.     vr.h.dl = ' ';    /* write out a SPace, using DOS */
  201.     vr.h.ah = 0x02;
  202.     int86(0x21, &vr, &vr);
  203.  
  204.     vr.h.ah = VBS_TTY_character_output;    /* backspace over it, using BIOS */
  205.     vr.h.al = BS;
  206.     vr.h.bh = 0;    /* page number 0 */
  207.     VideoBIOS(&vr);
  208.  
  209.     vr.h.ah = VBS_read_character_and_attribute;    /* find out attribute */
  210.     VideoBIOS(&vr);
  211.     c_attr = vr.h.ah;
  212. }
  213.  
  214. /* codes for selecting scan lines for alpha mode (service 0x12, function 0x30) */
  215.  
  216. #define EGA200    0
  217. #define EGA350    1
  218. #define EGA400    2
  219.  
  220. /* codes for selecting ROM font (function code for service 0x11)
  221.  * Notes from Ralf Brown's Interrupt List:
  222.  *      The routines called with AL=1xh are designed to be called only
  223.  *      immediately after a mode set and are similar to the routines called
  224.  *      with AL=0xh, except that:
  225.  *          Page 0 must be active.
  226.  *          Bytes/character is recalculated.
  227.  *          Max character rows is recalculated.
  228.  *          CRT buffer length is recalculated.
  229.  *          CRTC registers are reprogrammed as follows:
  230.  *             R09 = bytes/char-1 ; max scan line (mode 7 only)
  231.  *             R0A = bytes/char-2 ; cursor start
  232.  *             R0B = 0        ; cursor end
  233.  *             R12 = ((rows+1)*(bytes/char))-1 ; vertical display end
  234.  *             R14 = bytes/char    ; underline loc
  235.  *               (*** BUG: should be 1 less ***)
  236.  *    the current block specifiers may be determined with INT 10/AH=1Bh,
  237.  *      looking at offsets 2Bh and 2Ch of the returned data (VGA only)
  238.  */
  239.  
  240. #define    EGA8x8    0x12    /* not 0x02 or 0x23 */
  241. #define    EGA8x14    0x11    /* not 0x01 or 0x22 */
  242. #define    EGA8x16    0x14    /* not 0x04 or 0x24 */
  243.  
  244. private void
  245. EGAsetup(scanlines, font)
  246. BYTE    scanlines;
  247. BYTE    font;
  248. {
  249.     union REGS vr;
  250.     vr.h.ah = VBS_select_active_display_page;
  251.     vr.h.al = 0;    /* page 0 */
  252.     VideoBIOS(&vr);
  253.  
  254.     vr.h.ah = 0x12;    /* request EGA information */
  255.     vr.h.bl = 0x10;    /* function number */
  256.     vr.x.cx = 0x0000;
  257.     VideoBIOS(&vr);
  258.  
  259.     if (vr.x.cx != 0) {
  260.         /* the display seems to be EGA or better */
  261.         vr.h.ah = 0x12;    /* select scan lines for alpha mode */
  262.         vr.h.al = scanlines;
  263.         vr.h.bl = 0x30;
  264.         VideoBIOS(&vr);
  265.  
  266.         /* Note: bh is left over from VideoBIOS call *before* last! */
  267.         if (vr.h.bh == 0)
  268.             vr.x.ax = 0x0003;    /* monochrome */
  269.         else
  270.             vr.x.ax = 0x0007;    /* 80x25 color text */
  271.         VideoBIOS(&vr);
  272.  
  273.         vr.h.ah = 0x11;    /* load ROM font */
  274.         vr.h.al = font;
  275.         vr.h.bl = 0;    /* into block 0 */
  276.         VideoBIOS(&vr);
  277.     }
  278.     get_c_attr();
  279. }
  280.  
  281. private bool
  282. set_lines(lines)
  283. int    lines;
  284. {
  285.     switch (lines) {
  286.     case 25:
  287.         EGAsetup(EGA400, EGA8x16);
  288.         break;
  289.     case 28:
  290.         EGAsetup(EGA400, EGA8x14);
  291.         break;
  292.     case 43:
  293.         EGAsetup(EGA350, EGA8x8);
  294.         break;
  295.     case 50:
  296.         EGAsetup(EGA400, EGA8x8);
  297.         break;
  298.     default:
  299.         return NO;
  300.     }
  301.     return YES;
  302. }
  303.  
  304. private bool    pc_set = NO;
  305. private int    unsetLI;
  306.  
  307. void
  308. pcSetTerm()
  309. {
  310.     char    *t = getenv("TERM");
  311.  
  312.     if (!pc_set) {
  313.         int    lines = lpp();
  314.  
  315.         unsetLI = lines;
  316.         if (t != NULL) {
  317.             if (stricmp(t, "ega25") == 0)
  318.                 lines = 25;
  319.             else if (stricmp(t, "ega28") == 0)
  320.                 lines = 28;
  321.             else if (stricmp(t, "ega43") == 0)
  322.                 lines = 43;
  323.             else if (stricmp(t, "ega50") == 0)
  324.                 lines = 50;
  325.         }
  326.         if (lines != unsetLI && set_lines(lines))
  327.             pc_set = YES;
  328.     }
  329.     CO = chpl();
  330.     if (CO > MAXCOLS)
  331.         CO = MAXCOLS;
  332.     LI = lpp();
  333.     ILI = LI - 1;
  334.     get_cur();
  335. }
  336.  
  337. void
  338. ttsize()
  339. {
  340. }
  341.  
  342. void
  343. pcUnsetTerm()
  344. {
  345.     if (pc_set) {
  346.         pc_set = NO;
  347.         (void) set_lines(unsetLI);
  348.     }
  349. }
  350.  
  351. private void
  352. line_feed()
  353. {
  354.     if (++c_row > ILI) {
  355.         c_row = ILI;
  356.         scr_win(VBS_scroll_window_up, 1, 0, ILI);
  357.     }
  358.     set_cur();
  359. }
  360.  
  361. #define BELL_P 0x61            /* speaker */
  362. #define BELL_D 0x2dc            /* 550 hz  */
  363. #define TIME_P 0x40            /* timer   */
  364. #define TINI   182            /* 10110110b timer initialization */
  365.  
  366. void
  367. dobell(n)    /* declared in term.h */
  368. int    n;
  369. {
  370.     unsigned char    spkr_state = inp(BELL_P);
  371.  
  372.     /* ??? Should accesses to timer be run with interrupts disabled?
  373.      * It looks as if the timer would be in a bad state if a sequence
  374.      * of accesses is interrupted. -- DHR 1995 Sept.
  375.      */
  376.     outp(TIME_P+3, TINI);
  377.     outp(TIME_P+2, BELL_D&0xff);
  378.     outp(TIME_P+2, BELL_D>>8);
  379.     outp(BELL_P, spkr_state|3);        /* turn speaker on  */
  380.     while (n-- > 0) {
  381. #ifdef NEVER
  382.         /* Control duration by counting half cycles of the audio tone.
  383.          * We detect a half-cycle boundary by noting when the high-order
  384.          * byte of the counter changes between zero and non-zero.
  385.          * This should be unaffected by CPU speed.
  386.          * We can't use the BIOS interval timer facility because
  387.          * I think it would use the timer channel we're already using.
  388.          */
  389.         int    half_cycs = 200;    /* number of half-cycles to play */
  390.         bool    hi_is_0 = NO;    /* detect zero transitions; initial lie unimportant */
  391.  
  392.         for (;;) {
  393.             (void) inp(TIME_P+2);    /* low-order counter 2 byte */
  394.             if ((inp(TIME_P+2) == 0) != hi_is_0) {
  395.                 hi_is_0 = !hi_is_0;
  396.                 if (--half_cycs <= 0)
  397.                     break;
  398.             }
  399.         }
  400. #else
  401.         unsigned int i = 0x8888;    /* a CPU-speed dependent duration */
  402.  
  403.         do ; while (--i > 0);
  404. #endif
  405.     }
  406.     outp(BELL_P, spkr_state);
  407. }
  408.  
  409. /* scr_putchar: put char on screen.  Declared in fp.h */
  410.  
  411. #ifdef USE_PROTOTYPES
  412. /* char is subject to default argument promotions */
  413. void
  414. scr_putchar(char c)
  415. #else
  416. void
  417. scr_putchar(c)
  418. char c;
  419. #endif
  420. {
  421.     switch (c) {
  422.     case LF:
  423.         line_feed();
  424.         break;
  425.     case CR:
  426.         c_col = 0;
  427.         set_cur();
  428.         break;
  429.     case BS:
  430.         if (c_col > 0)
  431.             c_col--;
  432.         set_cur();
  433.         break;
  434.     case CTL('G'):    /* ??? is this ever used? */
  435.         dobell(1);
  436.         break;
  437.     default:
  438.         ch_out((c), 1);
  439.         if (++c_col > CO-1) {
  440.             c_col = 0;
  441.             line_feed();
  442.         }
  443.         set_cur();
  444.         break;
  445.     }
  446. }
  447.  
  448. /* No cursor optimization on an IBMPCDOS, this simplifies things a lot.
  449.  * Think about it: it would be silly!
  450.  */
  451.  
  452. void
  453. Placur(line, col)
  454. int line,
  455.     col;
  456. {
  457.     cur_mov(line, col);
  458.     CapCol = col;
  459.     CapLine = line;
  460. }
  461.  
  462. private bool
  463.     doing_so = NO,
  464.     doing_us = NO;
  465.  
  466. private void
  467. doattr()
  468. {
  469.     setcolor((doing_so? Mlattr : Txattr) ^ (doing_us? Hlattr : 0));
  470. }
  471.  
  472. void
  473. SO_effect(f)
  474. bool f;
  475. {
  476.     doing_so = f;
  477.     doattr();
  478. }
  479.  
  480. void
  481. US_effect(f)
  482. bool    f;
  483. {
  484.     doing_us = f;
  485.     doattr();
  486. }
  487.  
  488. #endif /* IBMPCDOS */
  489.