home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / editor / stevie / dos.c < prev    next >
C/C++ Source or Header  |  1994-01-31  |  24KB  |  1,086 lines

  1. /* $Header:
  2.  *
  3.  * MSDOS support for Stevie.
  4.  * Many of the functions in this file have two versions:
  5.  *   -    The original version, using ANSI escape sequences
  6.  *    (by Tim Thompson and/or Tony Andrews).
  7.  *    It requires a non-IBM ANSI driver, such as the shareware NANSI.SYS.
  8.  *   -    The BIOS-function version (by Larry A. Shurr).  The BIOS version
  9.  *    doesn't require an enhanced console driver such as NANSI.SYS.
  10.  *    Invoke it by #defining BIOS in ENV.H.
  11.  * Dave Tutelman has incorporated many features of Larry Shurr's BIOS
  12.  * version (such as colors and 43-line mode) into the ANSI version.
  13.  */
  14.  
  15. #include "stevie.h"
  16. #include <stdio.h>
  17. #include <dos.h>
  18. #include <signal.h>
  19.  
  20. char    *getenv();
  21.  
  22. static    char    getswitch();
  23. static    void    setswitch();
  24.  
  25. #ifdef BIOS
  26. void bios_t_ed();
  27. void bios_t_el();
  28. #endif
  29.  
  30. enum hostval_e {hIBMPC, hTIPRO};
  31. typedef enum hostval_e hostval;
  32. static    hostval    host_type   = 0;    /* Gets host computer type */
  33.  
  34. static    char    bgn_color   = 0x7;    /* For saving orig color */
  35. static    char    quitting_now= 0;    /* Set for windexit() */
  36. static    int    crt_int     = 0;    /* Gets CRT BIOS interrupt */
  37. static    char    bgn_page    = 0;    /* For saving current page (IBM PC) */
  38. static    char    bgn_mode    = 0;    /* For saving video mode (IBM PC) */
  39.  
  40. #ifdef BIOS
  41. static    int    sav_curattr = 0;    /* For saving cursor attributes */
  42. static    int    sav_curpos  = 0;    /* For saving cursor position */
  43. #endif
  44.  
  45. /*
  46.  * inchar() - get a character from the keyboard
  47.  */
  48. int
  49. inchar()
  50. {
  51.     int    c;
  52.  
  53.     got_int = FALSE;
  54.  
  55.     for (;;beep()) {    /* loop until we get a valid character */
  56.  
  57.         flushbuf();    /* flush any pending output */
  58.  
  59.         switch (c = getch()) {
  60.         case 0x1e:
  61.             return K_CCIRCM;
  62.         case 0:                /* special key */
  63.             if (State != NORMAL) {
  64.                 c = getch();    /* throw away next char */
  65.                 continue;    /* and loop for another char */
  66.             }
  67.             switch (c = getch()) {
  68.             case 0x50:
  69.                 return K_DARROW;
  70.             case 0x48:
  71.                 return K_UARROW;
  72.             case 0x4b:
  73.                 return K_LARROW;
  74.             case 0x4d:
  75.                 return K_RARROW;
  76.             case 0x47:        /* Home key */
  77.                 stuffin("1G");
  78.                 return -1;
  79.             case 0x4f:        /* End key */
  80.                 stuffin("G");
  81.                 return -1;
  82.             case 0x51:        /* PgDn key */
  83.                 stuffin(mkstr(CTRL('F')));
  84.                 return -1;
  85.             case 0x49:        /* PgUp key */
  86.                 stuffin(mkstr(CTRL('B')));
  87.                 return -1;
  88.             case 0x52:        /* insert key */
  89.                 return K_INSERT;
  90.             case 0x53:        /* delete key */
  91.                 stuffin("x");
  92.                 return -1;
  93.             /*
  94.              * Hard-code some useful function key macros.
  95.              */
  96.             case 0x3b: /* F1 */
  97.                 stuffin(":help\n");
  98.                 return -1;
  99.             case 0x3c: /* F2 */
  100.                 stuffin(":n\n");
  101.                 return -1;
  102.             case 0x55: /* SF2 */
  103.                 stuffin(":n!\n");
  104.                 return -1;
  105.             case 0x3d: /* F3 */
  106.                 stuffin(":N\n");
  107.                 return -1;
  108.             case 0x56: /* SF3 */
  109.                 stuffin(":N!\n");
  110.                 return -1;
  111.             case 0x3e: /* F4 */
  112.                 stuffin(":e #\n");
  113.                 return -1;
  114.             case 0x57: /* SF4 */
  115.                 stuffin(":e! #\n");
  116.                 return -1;
  117.             case 0x3f: /* F5 */
  118.                 stuffin(":rew\n");
  119.                 return -1;
  120.             case 0x58: /* SF5 */
  121.                 stuffin(":rew!\n");
  122.                 return -1;
  123.             case 0x40: /* F6 */
  124.                 stuffin("]]");
  125.                 return -1;
  126.             case 0x59: /* SF6 */
  127.                 stuffin("[[");
  128.                 return -1;
  129.             case 0x42: /* F8 - Set up global substitute */
  130.                 stuffin(":1,$s/");
  131.                 return -1;
  132.             case 0x43: /* F9 - declare C variable */
  133.                 stuffin("yyp!!cdecl\n");
  134.                 return -1;
  135.             case 0x5C: /* SF9 - explain C declaration */
  136.                 stuffin("yyp^iexplain \033!!cdecl\n");
  137.                 return -1;
  138.             case 0x44: /* F10 - save & quit */
  139.                 stuffin(":x\n");
  140.                 return -1;
  141.             case 0x5D: /* F10 - quit without saving */
  142.                 stuffin(":q!\n");
  143.                 return -1;
  144.             default:
  145.                 break;
  146.             }
  147.             break;
  148.  
  149.         default:
  150.             return c;
  151.         }
  152.     }
  153. }
  154.  
  155.  
  156. static    int    bpos = 0;
  157. #ifdef BIOS
  158.  
  159. #define    BSIZE    256
  160. static    char    outbuf[BSIZE];
  161.  
  162. /* Flushbuf() is used a little differently here in the BIOS-only interface
  163.  * than in the case of other systems.  In general, the other systems buffer
  164.  * large amounts of text and screen management data (escape sequences).
  165.  * Here, only text is buffered, screen management is performed using BIOS
  166.  * calls.  Hence, the buffer is much smaller since no more than one line of
  167.  * text is buffered.  Also, screen management calls must assure that the
  168.  * buffered text is output before performing the requested function.
  169.  *
  170.  * O.K.  Now I had better explain the tricky code sequences for IBM PC and
  171.  * TI Pro.  In both cases, the tricks involve: 1) getting the text written
  172.  * to the display as quickly as possible in the desired color and 2) assur-
  173.  * ing that the cursor is positioned immediately following the latest text
  174.  * output.
  175.  *
  176.  * On the IBM PC, we output the first character using the "write character
  177.  * with attribute" function followed by code which outputs the buffer, a
  178.  * character at a time, using the "write tty" function.  The first write
  179.  * sets the display attributes, which are then reused by the "write tty"
  180.  * function.  The "write tty" is then used to quickly write the data while
  181.  * advancing the cursor.  The "write character with attribute" function
  182.  * does not advance the cursor and so cannot be used to write the entire
  183.  * buffer without additional code to advance the cursor in a separate oper-
  184.  * ation.  Even though the first character in each buffer gets written
  185.  * twice, the result is still substantially faster than it would be using a
  186.  * "write character with attribute" - "[re]position cursor" sequence.
  187.  *
  188.  * On the TI Pro, we output the entire buffer using the "write character
  189.  * string with attribute" function which is fast and convenient.  Unfortun-
  190.  * ately, it does not advance the cursor.  Therefore, we include code which
  191.  * determines the current location of the cursor, writes the buffer, then
  192.  * positions the cursor at the end of the new data.
  193.  *
  194.  * I admit it, this is tricky, but it makes display updates much faster
  195.  * than the would be using a more straightforward approach.
  196.  */
  197.  
  198.  
  199. void
  200. flushbuf()                /* Flush buffered output to display */
  201. {
  202.     union    REGS    inregs, curregs, outregs;
  203.  
  204.     if (bpos != 0) {
  205.         char    *bptr = outbuf;
  206.  
  207.         switch (host_type) {
  208.         case hIBMPC:
  209.             inregs.h.ah = 0x09;
  210.             inregs.h.al = *bptr;
  211.             inregs.h.bh = bgn_page;
  212.             inregs.h.bl = P(P_CO);
  213.             inregs.x.cx = 1;
  214.             int86(crt_int, &inregs, &outregs);
  215.             inregs.h.ah = 0x0E;
  216.             while (bpos-- > 0) {
  217.                 inregs.h.al = *bptr++;
  218.                 int86(crt_int, &inregs, &outregs);
  219.             }
  220.             break;
  221.         case hTIPRO:
  222.             curregs.h.ah = 0x03;
  223.             int86(crt_int, &curregs, &curregs);
  224.             inregs.h.ah = 0x10;
  225.             inregs.h.al = P(P_CO);
  226.             inregs.x.bx = FP_OFF(outbuf);
  227.             inregs.x.cx = bpos;
  228.             inregs.x.dx = FP_SEG(outbuf);
  229.             int86(crt_int, &inregs, &outregs);
  230.             curregs.h.ah = 0x02;
  231.             curregs.h.dh += bpos;
  232.             int86(crt_int, &curregs, &outregs);
  233.             break;
  234.         }
  235.     }
  236.     bpos = 0;
  237. }
  238.  
  239. void
  240. write_tty(c)                /* Used to execute control chars */
  241. char    c;
  242. {
  243.     int    curcol;
  244.  
  245.     union    REGS    inregs, curregs, outregs;
  246.  
  247.     flushbuf(); \
  248.  
  249.     switch (c) {
  250.     case '\t':
  251.         inregs.h.ah = 0x09;
  252.         inregs.h.al = ' ';
  253.         inregs.h.bh = bgn_page;
  254.         inregs.h.bl = P(P_CO);
  255.         inregs.x.cx = 1;
  256.         int86(crt_int, &inregs, &outregs);
  257.         inregs.h.ah = 0x0E;
  258.         int86(crt_int, &inregs, &outregs);
  259.         curregs.h.ah = 0x03;
  260.         curregs.h.bh = bgn_page;
  261.         int86(crt_int, &curregs, &outregs);
  262.         curcol = host_type == hIBMPC ? outregs.h.dl : outregs.h.dh;
  263.         while (curcol++ % P(P_TS)) int86(crt_int, &inregs, &outregs);
  264.         break;
  265.     case '\n':
  266.         if (host_type == hTIPRO) bios_t_el();
  267.         /* No break, fall through to default action. */
  268.     default:
  269.         inregs.h.ah = 0x0E;
  270.         inregs.h.bh = bgn_page;
  271.         inregs.h.al = c;
  272.         int86(crt_int, &inregs, &outregs);
  273.         break;
  274.     }
  275. }
  276.  
  277. #else        /* Not BIOS */
  278.  
  279. #define    BSIZE    2048
  280. static    char    outbuf[BSIZE];
  281.  
  282. void
  283. flushbuf()
  284. {
  285.     if (bpos != 0)
  286.         write(1, outbuf, bpos);
  287.     bpos = 0;
  288. }
  289.  
  290. #endif
  291.  
  292.  
  293. /*
  294.  * Macro to output a character. Used within this file for speed.
  295.  *
  296.  * This macro had to be upgraded for the BIOS-only version because we
  297.  * cannot count on flushbuf() to execute control characters such as
  298.  * end-of-line or tab.  Therefore, when we encounter one, we flush
  299.  * the buffer and call a routine which executes the character.
  300.  */
  301.  
  302. #ifdef BIOS
  303.  
  304. #define    outone(cc) {                 \
  305.   register char ch = cc;             \
  306.   if (ch >= ' ') {                   \
  307.     outbuf[bpos++] = ch;             \
  308.     if (bpos >= BSIZE) flushbuf();   \
  309.   } else write_tty(ch);              \
  310. }
  311.  
  312. #else
  313.  
  314. #define    outone(c)    outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
  315.  
  316. #endif
  317.  
  318. /*
  319.  * Function version for use outside this file.
  320.  */
  321.  
  322. void
  323. outchar(c)
  324. char    c;
  325. {
  326.     outone(c);
  327. }
  328.  
  329. /*
  330.  * outstr(s) - write a string to the console
  331.  */
  332.  
  333. void
  334. outstr(s)
  335. char    *s;
  336. {
  337.     while (*s) {
  338.         outone(*s++);
  339.     }
  340. }
  341.  
  342. void
  343. beep()
  344. {
  345.     if ( P(P_VB) )
  346.         vbeep();
  347.     else
  348.         outchar('\007');
  349. }
  350.  
  351. vbeep()        /* "Visual Bell" - reverse color flash */
  352. {
  353.     unsigned char oldcolor, revcolor, temp;
  354.  
  355.     oldcolor = P(P_CO);
  356.  
  357.     /* put reverse color in revcolor */
  358.     revcolor = (P(P_CO) & 0x07) << 4;    /* foregnd -> bkgnd */
  359.     temp     = (P(P_CO) & 0x70) >> 4;    /* bkgnd -> foregnd */
  360.     revcolor  |= temp;
  361.  
  362.     /* Flash revcolor, then back */
  363.     setcolor (revcolor);
  364.     flushbuf();
  365. #ifdef TURBOC
  366.     delay (100);
  367. #endif
  368.     setcolor (oldcolor);
  369.     windgoto (Cursrow, Curscol);
  370.     flushbuf();
  371. }
  372.  
  373.  
  374. #ifndef TURBOC
  375. sleep(n)
  376. int    n;
  377. {
  378.     /*
  379.      * Should do something reasonable here.
  380.      */
  381. }
  382. #endif
  383.  
  384. void
  385. pause()
  386. {
  387.     long    l;
  388.  
  389.     flushbuf();
  390.  
  391. #ifdef TURBOC
  392.     delay (600);    /* "stop" for a fraction of a second */
  393. #else
  394.     /*
  395.      * Should do something better here...
  396.      */
  397.     for (l=0; l < 5000 ;l++)
  398.         ;
  399. #endif
  400. }
  401.  
  402. void
  403. sig()
  404. {
  405.     signal(SIGINT, sig);
  406.  
  407.     got_int = TRUE;
  408. }
  409.  
  410. static    char    schar;        /* save original switch character */
  411.  
  412. /*    While Larry Shurr's addition of color and mode support was
  413.  *    dependent on #define BIOS, there's no reason it needs to be.
  414.  *    The BIOS is always there, even if NANSI.SYS isn't.  We'll
  415.  *    use the BIOS where appropriate, and extend support to
  416.  *    all cases of #define DOS.  This is especially true of the
  417.  *    setup in windinit() and the termination in windexit().
  418.  */
  419.  
  420. void
  421. windinit()
  422. {
  423.     union    REGS    regs;
  424.     struct    SREGS    sregs;
  425.  
  426.     /* The "SYSROM..." string is a signature in the TI Pro's ROM which
  427.      * which we can look for to determine whether or not we're running
  428.      * on a TI Pro.  If we don't find it at F400:800D,
  429.      * we assume we're running on an IBM PC or clone.
  430.      * Unfortunately, the signature is actually
  431.      * the system ROM's copyright notice though you will note that the
  432.      * year is omitted.  Still, placing it in this program might
  433.      * inadvertantly make it appear to be an official copyright notice
  434.      * for THIS program.  Hence, I have surrounded the signature
  435.      * string with disclaimers.
  436.      */
  437.  
  438.         static    char far *disclaimer1 =
  439.       "The following is *NOT* a copyright notice for this program: ";
  440.  
  441.     static    char far *ti_sig =
  442.           "SYSROM (c) Copyright Texas Instruments Inc.";
  443.  
  444.     static    char far *disclaimer2[] = {
  445.       "\nInstead, it is a signature string we look for ",
  446.       "to distinguish the TI Pro computer.\n",
  447.       "Actually, this program is in the public domain."
  448.     };
  449.  
  450.     static char far    *ti_sig_addr = (char far *)0xF400800D;
  451.     static int ti_sig_len = sizeof(ti_sig) - 1;
  452.  
  453.     /* Identify the host type.  Look for signature in TI Pro ROM.  If */
  454.     /* found, set host type to TI Pro, else assume host is an IBM PC. */
  455.  
  456.     host_type = strncmp(ti_sig, ti_sig_addr, ti_sig_len) ? hIBMPC : hTIPRO;
  457.  
  458.     /* Next, perform host-dependent initialization. */
  459.  
  460.     switch (host_type) {
  461.     case hIBMPC:
  462.         /* Get the video mode info */
  463.         crt_int = 0x10;
  464.         regs.h.ah = 0x0F;
  465.         int86(crt_int, ®s, ®s);
  466.         bgn_page = regs.h.bh;
  467.         bgn_mode = regs.h.al;
  468.         Columns = regs.h.ah;
  469.         /*  Find the starting color, and save to restore later */
  470.         regs.h.ah = 8;        /* Read char/attr BIOS fn */
  471.         regs.h.bh = bgn_page;
  472.         int86(crt_int, ®s, ®s);
  473.         bgn_color = (int) regs.h.ah;
  474.         P(P_CO) = bgn_color;
  475.         break;
  476.     case hTIPRO:
  477.         Columns = 80;
  478.         crt_int = 0x49;
  479.         P(P_CO) = 0x0F;
  480.         break;
  481.  
  482.     default:
  483.         Columns = 80;
  484.         break;
  485.     }
  486.  
  487.     P(P_LI) = Rows = 25;
  488.  
  489.     schar = getswitch();
  490.     setswitch('/');
  491.  
  492.     signal(SIGINT, sig);
  493. #ifndef BIOS
  494.     setraw (1);
  495. #endif
  496. }
  497.  
  498. void
  499. windexit(r)
  500. int r;
  501. {
  502.  
  503.     union    REGS    regs;
  504.  
  505.     quitting_now = 1;
  506.  
  507.     /* Restore original color */
  508.     setcolor (bgn_color);
  509.  
  510.     if (host_type == hIBMPC) {
  511.         /* If we've changed any of the setup, reset the mode.
  512.          * Otherwise, leave stuff on the screen.
  513.          */
  514.         regs.h.ah = 0x0F;    /* "Get-mode" BIOS fn */
  515.         int86(0x10, ®s, ®s);
  516.         if (bgn_mode != regs.h.al)
  517.             set_mode (bgn_mode);
  518.     }
  519.  
  520.     flushbuf();
  521.     setswitch(schar);
  522. #ifndef BIOS
  523.     setraw(0);
  524. #endif
  525.     exit(r);
  526. }
  527.  
  528.  
  529. #ifndef BIOS
  530. /*    Setraw sets the console driver into raw mode, which makes it run
  531.  *    somewhat faster.  Details of the function:
  532.  *    If r=1, remember current mode, and set into raw mode.
  533.  *       r=0, return to the original mode.
  534.  */
  535.  
  536. setraw (r)
  537.   int    r;
  538. {
  539.     static int origr=0;    /* save the original r */
  540.     union REGS rr;
  541.  
  542.     /* Do IOCTL call to get current control info */
  543.     rr.x.ax = 0x4400;    /* Read IOCTL info - DOS fn */
  544.     rr.x.bx = 1;        /* Handle for stdout */
  545.     intdos (&rr, &rr);
  546.  
  547.     /* Save relevant info, and modify for "set" call */
  548.     if (r) {
  549.         origr = rr.h.dl & 0x20;        /* save current "raw" bit */
  550.         rr.h.dl = rr.h.dl | 0x20;    /* set "raw" bit */
  551.     }
  552.     else
  553.         rr.h.dl = (rr.h.dl & (~0x20)) | (origr & 0x20);
  554.  
  555.     /* Do IOCTL call to set control info */
  556.     rr.x.ax = 0x4401;    /* Set IOCTL function call */
  557.     rr.x.bx = 1;        /* Handle for stdout */
  558.     rr.h.dh = 0;        /* DL already set up */
  559.     intdos (&rr, &rr);
  560. }
  561. #endif
  562.  
  563.  
  564. void
  565. windgoto(r, c)                /* Move cursor to r'ow & c'olumn */
  566. register int    r, c;
  567. {
  568. #ifdef BIOS
  569.     union    REGS    inregs, outregs;
  570.  
  571.     if (bpos > 0) flushbuf();
  572.  
  573.     inregs.h.ah = 0x02;
  574.  
  575.     switch (host_type) {
  576.     case hIBMPC :
  577.         inregs.h.bh = bgn_page;
  578.         inregs.h.dh = r;
  579.         inregs.h.dl = c;
  580.         break;
  581.     case hTIPRO:
  582.         inregs.h.dh = c;
  583.         inregs.h.dl = r;
  584.         break;
  585.     }
  586.  
  587.     int86(crt_int, &inregs, &outregs);
  588.  
  589. #else        /* Not BIOS */
  590.  
  591.     r += 1;
  592.     c += 1;
  593.  
  594.     /*
  595.      * Check for overflow once, to save time.
  596.      */
  597.     if (bpos + 8 >= BSIZE)
  598.         flushbuf();
  599.  
  600.     outbuf[bpos++] = '\033';
  601.     outbuf[bpos++] = '[';
  602.     if (r >= 10)
  603.         outbuf[bpos++] = r/10 + '0';
  604.     outbuf[bpos++] = r%10 + '0';
  605.     outbuf[bpos++] = ';';
  606.     if (c >= 10)
  607.         outbuf[bpos++] = c/10 + '0';
  608.     outbuf[bpos++] = c%10 + '0';
  609.     outbuf[bpos++] = 'H';
  610.  
  611. #endif
  612. }
  613.  
  614. FILE *
  615. fopenb(fname, mode)
  616. char    *fname;
  617. char    *mode;
  618. {
  619.     FILE    *fopen();
  620.     char    modestr[16];
  621.  
  622.     sprintf(modestr, "%sb", mode);
  623.     return fopen(fname, modestr);
  624. }
  625.  
  626. static    char
  627. getswitch()
  628. {
  629.     union    REGS    inregs, outregs;
  630.  
  631.     inregs.h.ah = 0x37;
  632.     inregs.h.al = 0;
  633.  
  634.     intdos(&inregs, &outregs);
  635.  
  636.     return outregs.h.dl;
  637. }
  638.  
  639. static    void
  640. setswitch(c)
  641. char    c;
  642. {
  643.     union    REGS    inregs, outregs;
  644.  
  645.     inregs.h.ah = 0x37;
  646.     inregs.h.al = 1;
  647.     inregs.h.dl = c;
  648.  
  649.     intdos(&inregs, &outregs);
  650. }
  651.  
  652. #define    PSIZE    128
  653.  
  654. /*
  655.  * fixname(s) - fix up a dos name
  656.  *
  657.  * Takes a name like:
  658.  *
  659.  *    \x\y\z\base.ext
  660.  *
  661.  * and trims 'base' to 8 characters, and 'ext' to 3.
  662.  */
  663. char *
  664. fixname(s)
  665. char    *s;
  666. {
  667.     char    *strchr(), *strrchr();
  668.     static    char    f[PSIZE];
  669.     char    base[32];
  670.     char    ext[32];
  671.     char    *p;
  672.     int    i;
  673.  
  674.     strcpy(f, s);
  675.  
  676.     for (i=0; i < PSIZE ;i++)
  677.         if (f[i] == '/')
  678.             f[i] = '\\';
  679.  
  680.     /*
  681.      * Split the name into directory, base, extension.
  682.      */
  683.     if ((p = strrchr(f, '\\')) != NULL) {
  684.         strcpy(base, p+1);
  685.         p[1] = '\0';
  686.     } else {
  687.         strcpy(base, f);
  688.         f[0] = '\0';
  689.     }
  690.  
  691.     if ((p = strchr(base, '.')) != NULL) {
  692.         strcpy(ext, p+1);
  693.         *p = '\0';
  694.     } else
  695.         ext[0] = '\0';
  696.  
  697.     /*
  698.      * Trim the base name if necessary.
  699.      */
  700.     if (strlen(base) > 8)
  701.         base[8] = '\0';
  702.  
  703.     if (strlen(ext) > 3)
  704.         ext[3] = '\0';
  705.  
  706.     /*
  707.      * Paste it all back together
  708.      */
  709.     strcat(f, base);
  710.     strcat(f, ".");
  711.     strcat(f, ext);
  712.  
  713.     return f;
  714. }
  715.  
  716. void
  717. doshell(cmd)
  718. char    *cmd;
  719. {
  720.     if (cmd == NULL)
  721.         if ((cmd = getenv ("COMSPEC")) == NULL)
  722.             cmd = "command.com";
  723.  
  724.     system(cmd);
  725.     wait_return();
  726. }
  727.  
  728.  
  729. /*
  730.  *    setcolor (color)
  731.  *    Set the screen attributes (basically, color) to value co.
  732.  *    The color attributes for a DOS machine are the BIOS colors
  733.  *    for text.  Where BIOS is not defined, we map the Escape
  734.  *    sequences to the NANSI.SYS equivalents of the BIOS colors.
  735.  */
  736.  
  737. setcolor (color)
  738.   int    color;
  739. {
  740. #ifdef BIOS
  741.     P(P_CO) = host_type == hIBMPC ? color : ((color & 0x17) | 0x08);
  742. #else
  743.     unsigned char work;
  744.  
  745.     /* Send the ANSI define-attribute sequence */
  746.     outone('\033');
  747.     outone('[');
  748.     outone('0');        /* Normal color */
  749.     outone(';');
  750.     /* BIOS-to-NANSI color conversion may look a little bizarre.
  751.      * They have different bit orderings to represent the
  752.      * color (BIOS=RGB, NANSI=BGR).
  753.      *
  754.      * First put the foreground color.
  755.      */
  756.     work = 0;
  757.     if (color & 1)        work += 4;    /* Blue */
  758.     if (color & 2)        work += 2;    /* Green */
  759.     if (color & 4)        work += 1;    /* Red */
  760.     outone('3');        /* NANSI foreground starts at 30 */
  761.     outone(work + '0');
  762.     outone(';');
  763.     /*  Now the background color */
  764.     work = 0;
  765.     if (color & 0x10)    work += 4;    /* Blue */
  766.     if (color & 0x20)    work += 2;    /* Green */
  767.     if (color & 0x40)    work += 1;    /* Red */
  768.     outone('4');        /* NANSI background starts at 40 */
  769.     outone(work + '0');
  770.     /*  Do the intensity and blinking, if any  */
  771.     if (color & 8) {    /* intensity */
  772.         outone(';');
  773.         outone('1');
  774.     }
  775.     if (color & 0x80) {    /* blink */
  776.         outone(';');
  777.         outone('5');
  778.     }
  779.     /*  The 'm' suffix means "set graphic rendition"  */
  780.     outone('m');
  781.     P(P_CO) = color;
  782.  
  783. #endif        /* Not BIOS */
  784.  
  785.     if (!quitting_now) {
  786.         screenclear();
  787.         updatescreen();
  788.     }
  789. }
  790.  
  791.  
  792. /*    setrows (r)
  793.  *    Sets the screen to "r" rows, or lines, where "r" is a feasible
  794.  *    value for the IBM PC with some common display.  In this function:
  795.  *   -    We set the mode to 25-line or 43-line mode, assuming the display
  796.  *    supports the requested mode.
  797.  *   -    We set the logical number of lines that Stevie uses to "r",
  798.  *    so that the screen USED may not be the same as the physical screen.
  799.  *
  800.  *    The function returns the number of rows set.
  801.  */
  802. setrows (r)
  803.   int r;
  804. {
  805.     int    rphys, rlog;    /* physical and logical "r" */
  806.  
  807.     rphys = (r <= 25) ? 25 : 43 ;
  808.     rlog  = (r <= 50) ? r : 50;
  809.  
  810.     /* Set the mode to correspond to the number of lines */
  811.     set_mode (rphys);
  812.  
  813.     return (rlog);
  814. }
  815.  
  816.  
  817. set_mode (m)
  818.   int m;
  819. {
  820.     set_25 ();
  821.     if (m == 43)
  822.         set_43 ();
  823. }
  824.  
  825. #ifdef BIOS
  826.  
  827. int
  828. set_25(lines)            /* Set display to 25 line mode */
  829. int    lines;
  830. {
  831.     union    REGS    inregs, outregs;
  832.  
  833.     switch (host_type) {
  834.     case hIBMPC:
  835.         inregs.h.ah = 0x00;
  836.         inregs.h.al = bgn_mode;
  837.         int86(crt_int, &inregs, &outregs);
  838.         break;
  839.     case hTIPRO:
  840.         windgoto(0, 0);
  841.         inregs.h.ah = 0x09;
  842.         inregs.h.al = ' ';
  843.         inregs.h.bl = P(P_CO);
  844.         inregs.x.cx = 80 * 25;
  845.         int86(crt_int, &inregs, &outregs);
  846.         if (lines > 25) lines = 25;
  847.         break;
  848.     }
  849.  
  850.     return(lines);
  851. }
  852.  
  853. int
  854. set_43(lines)            /* Set display to 43/50 line mode */
  855. int    lines;
  856. {
  857.     union    REGS    inregs, outregs;
  858.  
  859.     switch (host_type) {
  860.     case hIBMPC:
  861.         inregs.x.ax = 0x1112;
  862.         inregs.h.bl = 0;
  863.         int86(crt_int, &inregs, &outregs);
  864.         inregs.x.ax = 0x1200;
  865.         inregs.h.bl = 0x20;
  866.         int86(crt_int, &inregs, &outregs);
  867.         inregs.h.ah = 0x01;
  868.         inregs.x.cx = 0x0707;
  869.         int86(crt_int, &inregs, &outregs);
  870.         break;
  871.     case hTIPRO:
  872.         if (lines > 25) lines = 25;
  873.         break;
  874.     }
  875.  
  876.     return(lines);
  877. }
  878.  
  879. #else        /* Not BIOS */
  880.  
  881. set_25 ()
  882. {
  883.     send_setmode (bgn_mode);
  884. }
  885.  
  886. set_43 ()
  887. {
  888.     send_setmode (43);
  889. }
  890.  
  891. send_setmode (m)
  892. {
  893.     outone('\033');
  894.     outone('[');
  895.  
  896.     /* Convert 2-digit decimal to ASCII */
  897.     if (m >= 10)
  898.         outone( m/10 + '0' );
  899.     outone( m%10 + '0' );
  900.     outone ('h');
  901. }
  902.  
  903. #endif        /* Not BIOS */
  904.  
  905. #ifdef BIOS
  906. /*
  907.  *    The rest of the file is BIOS-specific
  908.  */
  909.  
  910. void
  911. bios_t_ci()                /* Make cursor invisible */
  912. {
  913.     union    REGS    inregs, outregs;
  914.  
  915.     if (sav_curattr == 0) {
  916.         inregs.h.ah = 0x03;
  917.         inregs.h.bh = bgn_page;
  918.         int86(crt_int, &inregs, &outregs);
  919.         sav_curattr = outregs.x.cx;
  920.         inregs.h.ah = 0x01;
  921.         inregs.x.cx = 0x2000;
  922.         int86(crt_int, &inregs, &outregs);
  923.     }
  924. }
  925.  
  926. void
  927. bios_t_cv()                /* Make cursor visible */
  928. {
  929.     union    REGS    inregs, outregs;
  930.  
  931.     if (sav_curattr != 0) {
  932.         inregs.h.ah = 0x01;
  933.         inregs.h.bh = bgn_page;
  934.         inregs.x.cx = sav_curattr;
  935.         int86(crt_int, &inregs, &outregs);
  936.         sav_curattr = 0;
  937.     }
  938. }
  939.  
  940. /*
  941.  * O.K., I have tried to keep bios.c as "pure" as possible. I.e., I have used
  942.  * BIOS calls for everything instead of going for all-out speed by using
  943.  * direct-video access for updating the display - after all, I named it this
  944.  * module bios.c.  There is one area, however, where using the BIOS is just
  945.  * too much of a compromise... the TI Pro's "scroll display" functions are so
  946.  * slow and ugly that I hate them.  True, they are very flexible, but their
  947.  * poor on-screen appearance and low performance are a liability - you prob-
  948.  * ably think I'm exaggerating, but you're wrong - it is truly bad.  There-
  949.  * fore, I am bypassing them and scrolling the screen myself; something I
  950.  * nearly always do.  From a purist like me, that really says something.
  951.  */
  952.  
  953. void
  954. bios_t_dl(r,l)                /* Delete lines */
  955. int r, l;
  956. {
  957.     char    far    *end;        /* End ptr for TI Pro screen */
  958.     char    far    *dst;        /* Dest ptr for scrolling TI Pro scrn */
  959.     char    far    *src;        /* Src  ptr for scrolling TI Pro scrn */
  960.  
  961.     union    REGS    inregs, outregs;
  962.  
  963.     switch (host_type) {
  964.     case hIBMPC:
  965.         inregs.h.ah = 0x06;
  966.         inregs.h.al = l;
  967.         inregs.h.bh = P(P_CO);
  968.         inregs.h.ch = r;
  969.         inregs.h.cl = 0;
  970.         inregs.h.dh = Rows - 1;
  971.         inregs.h.dl = Columns - 1;
  972.         int86(crt_int, &inregs, &outregs);
  973.         break;
  974.     case hTIPRO:
  975.         inregs.h.ah = 0x17;
  976.         int86(crt_int, &inregs, &outregs);
  977.         dst = MK_FP(0xDE00, outregs.x.dx + (r * Columns));
  978.         src = dst + (l * Columns);
  979.         end = MK_FP(0xDE00, outregs.x.dx + ((Rows - 1) * Columns));
  980.         while (src < end) *dst++ = *src++;
  981.         while (dst < end) *dst++ = ' ';
  982.         break;
  983.     }
  984. }
  985.  
  986. void
  987. bios_t_ed()                /* Home cursor, erase display */
  988. {
  989.     union    REGS    inregs, outregs;
  990.  
  991.     windgoto(0, 0);
  992.  
  993.     inregs.h.ah = 0x09;
  994.     inregs.h.al = ' ';
  995.     inregs.h.bh = bgn_page;
  996.     inregs.h.bl = P(P_CO);
  997.     inregs.x.cx = Columns * Rows;
  998.     int86(crt_int, &inregs, &outregs);
  999. }
  1000.  
  1001. void
  1002. bios_t_el()                /* Erase to end-of-line */
  1003. {
  1004.     short    ccol;
  1005.  
  1006.     union    REGS    inregs, outregs;
  1007.  
  1008.     inregs.h.ah = 0x03;
  1009.     inregs.h.bh = bgn_page;
  1010.     int86(crt_int, &inregs, &outregs);
  1011.  
  1012.     inregs.h.ah = 0x09;
  1013.     inregs.h.al = ' ';
  1014.     inregs.h.bl = P(P_CO);
  1015.  
  1016.     ccol = host_type == hIBMPC ? outregs.h.dl : outregs.h.dh;
  1017.  
  1018.     inregs.x.cx = Columns - ccol;
  1019.     int86(crt_int, &inregs, &outregs);
  1020. }
  1021.  
  1022. /* As in the delete-line function, we scroll the TI display ourselves
  1023.  * rather than the use the slow-and-ugly software scroll in the BIOS.  See
  1024.  * the remarks for bios_t_dl() additional information.
  1025.  */
  1026.  
  1027. void
  1028. bios_t_il(r,l)                /* Insert lines */
  1029. int r, l;
  1030. {
  1031.     char    far    *end;        /* End ptr for TI Pro screen */
  1032.     char    far    *dst;        /* For scrolling TI Pro screen */
  1033.     char    far    *src;        /* For scrolling TI Pro screen */
  1034.  
  1035.     union    REGS    inregs, outregs;
  1036.  
  1037.     switch (host_type) {
  1038.     case hIBMPC:
  1039.         inregs.h.ah = 0x07;
  1040.         inregs.h.al = l;
  1041.         inregs.h.bh = P(P_CO);
  1042.         inregs.h.ch = r;
  1043.         inregs.h.cl = 0;
  1044.         inregs.h.dh = Rows - 1;
  1045.         inregs.h.dl = Columns - 1;
  1046.         int86(crt_int, &inregs, &outregs);
  1047.         break;
  1048.     case hTIPRO:
  1049.         inregs.h.ah = 0x17;
  1050.         int86(crt_int, &inregs, &outregs);
  1051.         dst = MK_FP(0xDE00, outregs.x.dx + (Columns * (Rows - 1)) - 1);
  1052.         src = dst - (Columns * l);
  1053.         end = MK_FP(0xDE00, outregs.x.dx + (Columns * r));
  1054.         while (src >= end) *dst-- = *src--;
  1055.         src = MK_FP(0xDE00, outregs.x.dx + (r * Columns));
  1056.         end = src + (l * Columns);
  1057.         while (src < end) *src++ = ' ';
  1058.         break;
  1059.     }
  1060. }
  1061.  
  1062. void
  1063. bios_t_rc()                /* Restore saved cursor position */
  1064. {
  1065.     union    REGS    inregs, outregs;
  1066.  
  1067.     inregs.h.ah = 0x02;
  1068.     inregs.h.bh = bgn_page;
  1069.     inregs.x.dx = sav_curpos;
  1070.     int86(crt_int, &inregs, &outregs);
  1071. }
  1072.  
  1073. void
  1074. bios_t_sc()                /* Save cursor position */
  1075. {
  1076.     union    REGS    inregs, outregs;
  1077.  
  1078.     inregs.h.ah = 0x03;
  1079.     inregs.h.bh = bgn_page;
  1080.     int86(crt_int, &inregs, &outregs);
  1081.     sav_curpos = outregs.x.dx;
  1082. }
  1083.  
  1084. #endif
  1085.  
  1086.