home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / progmisc / tde221.zip / CONSOLE.C < prev    next >
C/C++ Source or Header  |  1993-04-01  |  52KB  |  1,526 lines

  1. /*
  2.  * All video and keyboard functions were gathered into one file.
  3.  *
  4.  * This file contains the keyboard and video i/o stuff.  Most of this stuff
  5.  * is specific to the PC hardware, but it should be easily modified when
  6.  * porting to other platforms.  With a few key functions written in
  7.  * assembly, we have fairly fast video performance and good keyboard control.
  8.  * Incidentally, the commented C code in the functions perform the same
  9.  * function as the assembly code.  In earlier versions of TDE, I didn't
  10.  * update the commented C code when I changed the assembly code.  The
  11.  * C and assembly should be equivalent in version 2.2.
  12.  *
  13.  * Although using a curses type package would be more portable, curses
  14.  * can be slow on PCs.  Let's keep our video and keyboard routines in
  15.  * assembly.  I feel the need for speed.
  16.  *
  17.  * Being that TDE 2.2 keeps an accurate count of characters in each line, we
  18.  * can allow the user to enter any ASCII or Extended ASCII key.
  19.  *
  20.  * Determining the video adapter type on the PC requires a function.  In
  21.  *  TDE, that function is:
  22.  *
  23.  *                void video_config( struct vcfg *cfg )
  24.  *
  25.  * video_config( ) is based on Appendix C in _Programmer's Guide to
  26.  *  PC & PS/2 Video Systems_ by Richard Wilton.
  27.  *
  28.  * See:
  29.  *
  30.  *   Richard Wilton, _Programmer's Guide to PC & PS/2 Video Systems_,
  31.  *    Microsoft Press, Redmond, Washington, 1987, Appendix C, pp 511-521.
  32.  *    ISBN 1-55615-103-9.
  33.  *
  34.  *
  35.  * New editor name:  TDE, the Thomson-Davis Editor.
  36.  * Author:           Frank Davis
  37.  * Date:             June 5, 1991, version 1.0
  38.  * Date:             July 29, 1991, version 1.1
  39.  * Date:             October 5, 1991, version 1.2
  40.  * Date:             January 20, 1992, version 1.3
  41.  * Date:             February 17, 1992, version 1.4
  42.  * Date:             April 1, 1992, version 1.5
  43.  * Date:             June 5, 1992, version 2.0
  44.  * Date:             October 31, 1992, version 2.1
  45.  * Date:             April 1, 1993, version 2.2
  46.  *
  47.  * This code is released into the public domain, Frank Davis.
  48.  * You may distribute it freely.
  49.  */
  50.  
  51.  
  52. #include "tdestr.h"
  53. #include "common.h"
  54. #include "define.h"
  55. #include "tdefunc.h"
  56.  
  57. #include <bios.h>               /* for direct BIOS keyboard input */
  58.  
  59.  
  60. /*******************************************************/
  61. /*                                                     */
  62. /*  1) initialize the video and keyboard structures    */
  63. /*                                                     */
  64. /*******************************************************/
  65.  
  66.  
  67. /*
  68.  *   BIOS Data Areas
  69.  *
  70.  *   See:
  71.  *
  72.  *      IBM Corp., _Technical Reference:  Personal Computer AT_,
  73.  *      Boca Raton, Florida, 1984, IBM part no. 1502494,
  74.  *      pp 5-29 thru 5-32.
  75.  *
  76.  *  These addresses, variable names, types, and descriptions are directly
  77.  *   from the IBM AT Technical Reference manual, BIOS listing, copyright IBM.
  78.  *
  79.  *   Address  Name           Type   Description
  80.  *   0x0449   CRT_MODE       Byte   Current CRT mode
  81.  *   0x044a   CRT_COLS       Word   Number columns on screen
  82.  *   0x044c   CRT_LEN        Word   length of regen buffer, video buffer, bytes
  83.  *   0x044e   CRT_START      Word   Starting address of regen buffer
  84.  *   0x0450   CURSOR_POSN    Word   cursor for each of up to 8 pages.
  85.  *   0x0460   CURSOR_MODE    Word   current cursor mode setting.
  86.  *   0x0462   ACTIVE_PAGE    Byte   Current page
  87.  *   0x0463   ADDR_6845      Word   base address for active display card
  88.  *   0x0465   CRT_MODE_SET   Byte   current mode of display card
  89.  *   0x0466   CRT_PALETTE    Byte   overscan color for CGA, EGA, and VGA.
  90.  *   0x0467   io_rom_init    Word   Pointer to optional i/o rom init routine
  91.  *   0x0469   io_rom_seg     Word   Pointer to io rom segment
  92.  *   0x046b   intr_flag      Byte   Flag to indicate an interrupt happened
  93.  *   0x046c   timer_low      Word   Low word of timer count
  94.  *   0x046e   timer_high     Word   High word of timer count
  95.  *   0x0470   timer_ofl      Byte   Timer has rolled over since last count
  96.  *   0x0471   bios_break     Byte   Bit 7 = 1 if Break Key has been hit
  97.  *   0x0472   reset_flag     Word   Word = 1234h if keyboard reset underway
  98.  *   0x0484   ROWS           Byte   Number of displayed character rows - 1
  99.  *   0x0485   POINTS         Word   Height of character matrix
  100.  *   0x0487   INFO           Byte   EGA and VGA display data
  101.  *   0x0488   INFO_3         Byte   Configuration switches for EGA and VGA
  102.  *   0x0489   flags          Byte   Miscellaneous flags
  103.  *   0x0496   kb_flag_3      Byte   Additional keyboard flag
  104.  *   0x048A   DCC            Byte   Display Combination Code
  105.  *   0x04A8   SAVE_PTR       Dword  Pointer to BIOS save area
  106.  */
  107. void video_config( struct vcfg *cfg )
  108. {
  109. #pragma pack( 1 )    /* Use pragma to force packing on byte boundaries. */
  110.  
  111. struct LOWMEMVID
  112. {
  113.    char     vidmode;           /* 0x449 */
  114.    unsigned scrwid;            /* 0x44A */
  115.    unsigned scrlen;            /* 0x44C */
  116.    unsigned scroff;            /* 0x44E */
  117.    struct   LOCATE
  118.    {
  119.       unsigned char col;
  120.       unsigned char row;
  121.    } csrpos[8];                /* 0x450 */
  122.    struct   CURSIZE
  123.    {
  124.       unsigned char end;
  125.       unsigned char start;
  126.    } csrsize;                  /* 0x460 */
  127.    char      page;             /* 0x462 */
  128.    unsigned  addr_6845;        /* 0x463 */
  129.    char      crt_mode_set;     /* 0x465 */
  130.    char      crt_palette;      /* 0x466 */
  131.    char      system_stuff[29]; /* 0x467 */
  132.    char      rows;             /* 0x484 */
  133.    unsigned  points;           /* 0x485 */
  134.    char      ega_info;         /* 0x487 */
  135.    char      info_3;           /* 0x488 */
  136.    char      skip[13];         /* 0x489 */
  137.    char      kb_flag_3;        /* 0x496 */
  138. } vid;
  139. struct LOWMEMVID _far *pvid = &vid;
  140. #pragma pack( )    /* revert to previously defined pack pragma. */
  141.  
  142. union REGS in, out;
  143. unsigned char temp, active_display;
  144.  
  145.    /*
  146.     * Move system information into our video structure.
  147.     */
  148.    _fmemmove( pvid, (void far *)0x00000449l, sizeof( vid ) );
  149.  
  150.    cfg->rescan = FALSE;
  151.    in.x.ax =  0x1a00;
  152.    int86( VIDEO_INT, &in, &out );
  153.    temp = out.h.al;
  154.    active_display = out.h.bl;
  155.    if (temp == 0x1a && (active_display == 7 || active_display == 8))
  156.       g_display.adapter = VGA;
  157.    else {
  158.       in.h.ah =  0x12;
  159.       in.h.bl =  0x10;
  160.       int86( VIDEO_INT, &in, &out );
  161.       if (out.h.bl != 0x10) {         /* EGA */
  162.          if (vid.ega_info & 0x08)
  163.             g_display.adapter = vid.addr_6845 == 0x3d4 ? CGA : MDA;
  164.          else
  165.             g_display.adapter = EGA;
  166.       } else if (vid.addr_6845 == 0x3d4)
  167.          g_display.adapter = CGA;
  168.       else
  169.          g_display.adapter = MDA;
  170.    }
  171.  
  172.    if (g_display.adapter == CGA || g_display.adapter == EGA) {
  173.       if (g_display.adapter == CGA)
  174.          cfg->rescan = TRUE;
  175.       g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0607 : 0x0407;
  176.       g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x0407 : 0x0607;
  177.    } else {
  178.       g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0b0c : 0x070b;
  179.       g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x070b : 0x0b0c;
  180.    }
  181.  
  182.    cfg->mode = vid.vidmode;
  183.    if (vid.addr_6845 == 0x3D4) {
  184.       cfg->color = TRUE;
  185.       cfg->videomem = (void far *)0xb8000000l;
  186.    } else {
  187.       cfg->color = FALSE;
  188.       cfg->videomem = (void far *)0xb0000000l;
  189.    }
  190.  
  191.    /*
  192.     * let save the overscan color
  193.     */
  194.    g_display.old_overscan = vid.crt_palette;
  195.  
  196.  
  197.    /*
  198.     * Get keyboard type.  Since there is no interrupt that determines
  199.     * keyboard type, use this method.  Look at bit 4 in keyboard flag3.
  200.     * This method is not always foolproof on clones.
  201.     */
  202.    if ((vid.kb_flag_3 & 0x10) != 0)
  203.       mode.enh_kbd = TRUE;
  204.    else
  205.       mode.enh_kbd = FALSE;
  206.    if (mode.enh_kbd == FALSE)
  207.       simulate_enh_kbd( 1 );
  208. }
  209.  
  210.  
  211. /*********************************************/
  212. /*                                           */
  213. /*  2) keyboard i/o routines, PC specific    */
  214. /*                                           */
  215. /*********************************************/
  216.  
  217.  
  218. /*
  219.  * The next function was written by Tom Waters, twaters@relay.nswc.navy.mil, and
  220.  * modified extensively by Frank Davis.
  221.  *
  222.  * "I use ANSI.SYS to redefine a few of my function keys and this causes a
  223.  * problem when getch() is used in a program.  For example, instead of returning
  224.  * 321 for the F7, I get the redefined string inserted in the text. So, instead
  225.  * of using getch(), I use the following function ..."
  226.  *
  227.  * Tom, thanks for the info and solution.  I'm sure your function will be
  228.  * be appreciated by everyone with ANSI key defs, Frank.
  229.  */
  230.  
  231. /*
  232.  * Name:    getkey
  233.  * Purpose: use bios to get keyboard input (getch has trouble w/ ANSI
  234.  *          redefined keys)
  235.  * Date:    July 2, 1991
  236.  * Modified:July 12, 1991, Frank Davis - accept ALT-xxx keyboard entry
  237.  *          September 10, 1991, Frank Davis - add support for Ctrl+Up, etc...
  238.  * Passed:  None
  239.  * Notes:   Uses the BIOS to read the next keyboard character.  Service 0x00
  240.  *           is the XT keyboard read.  Service 0x10 is the extended keyboard
  241.  *           read.  Test for a bunch of special cases.  Allow the user to enter
  242.  *           any ASCII or Extended ASCII code as a normal text characters.
  243.  *
  244.  *          Control @ is defined as 0.  we need to do a special test
  245.  *           for this key, otherwise it's interpretted as an Alt key.  It's
  246.  *           the only "regular" Control key that returns 0 in AL and the scan
  247.  *           byte in AH.  The "regular" Control keys are those in the range
  248.  *           0-31 and they return the Control character in AL and the scan
  249.  *           code in AH.  All of the Alt + keys return 0 in AL and
  250.  *           the scan code in ah.
  251.  *
  252.  *          This function was written for US keyboards.  It may have to be
  253.  *           modified for other keyboards, eg. Belgium, Canada, Czech,
  254.  *           Slovak, Denmark, France, Germany, etc...
  255.  *
  256.  *          if Ctrl-Break is pressed, it returns 0xffff as the key pressed.
  257.  *           let's set it to CONTROL_BREAK == 269 and do nothing.
  258.  */
  259. int getkey( void )
  260. {
  261. unsigned key, num_lock, control, shift;
  262. register scan;
  263. register unsigned lo;
  264.  
  265. /*
  266.  * this code is used during testing to check the amount of memory
  267.  *    in the near heap.
  268.  *
  269.  * char buff[MAX_COLS];
  270.  * ultoa( _memavl( ), buff, 10 );
  271.  * s_output( "h=       ", g_display.mode_line, 37, g_display.mode_color );
  272.  * s_output( buff, g_display.mode_line, 39, g_display.mode_color );
  273.  */
  274.  
  275.    /*
  276.     * lets spin on waitkey until the user presses a key.  waitkey polls
  277.     *  the keyboard and returns 0 when a key is waiting.
  278.     */
  279.    while (waitkey( mode.enh_kbd ));
  280.  
  281.    /*
  282.     *  _bios_keybrd == int 16.  It returns the scan code in ah, hi part of key,
  283.     *   and the ascii key code in al, lo part of key.  If the character was
  284.     *   entered via ALT-xxx, the scan code, hi part of key, is 0.
  285.     */
  286.    if (mode.enh_kbd) {
  287.       key = _bios_keybrd( 0x10 );
  288.       lo  = _bios_keybrd( 0x12 );
  289.  
  290.       /*
  291.        * couple of special cases:
  292.        *   on the numeric keypad, some keys return 0xe0 in the lo byte.
  293.        *   1) if user enters Alt-224, then the hi byte == 0 and lo byte == 0xe0.
  294.        *   we need to let this get thru as an Extended ASCII char.  2) although
  295.        *   we could make the cursor pad keys do different functions than the
  296.        *   numeric pad cursor keys, let's set the 0xe0 in the lo byte to zero
  297.        *   and forget about support for those keys.
  298.        */
  299.       if ((key & 0x00ff) == 0x00e0 && (key & 0xff00) != 0)
  300.          key = key & 0xff00;
  301.    } else {
  302.       key = _bios_keybrd( 0 );
  303.       lo  = _bios_keybrd( 2 );
  304.    }
  305.    num_lock = lo & 0x20;
  306.    control  = lo & 0x04;
  307.    shift    = lo & 0x03;
  308.    scan = (key & 0xff00) >> 8;
  309.    lo = key & 0X00FF;
  310.  
  311.    if (lo == 0) {
  312.       /*
  313.        * special case for Control @, which is defined as 0 or NULL.
  314.        */
  315.       if (scan == 3)
  316.          lo = 430;
  317.  
  318.       /*
  319.        * when first byte is 0, map it above 256, so that we can
  320.        *  let ALT-xxx keys map to their 'natural' place.  In
  321.        *  otherwords, use 0-255 as normal text characters and
  322.        *  those >= 256 are function keys.
  323.        */
  324.       else
  325.          lo = scan | 0x100;
  326.  
  327.    /*
  328.     * now test for Control-Break.  let's set this to do nothing in the
  329.     *  editor.  manually map Control-Break to 269 - DO NOT assign
  330.     *  any function to 269.
  331.     */
  332.    } else if (key == 0xffff)
  333.       lo = CONTROL_BREAK;
  334.  
  335.  
  336.    /*
  337.     * Pressing Control+BackSpace generates the 0x7f character.  Instead of
  338.     * 0x7f, make lo the ASCII backspace character.  If anyone wants the
  339.     * 0x7f character, then they can enter it via ALT+xxx.
  340.     */
  341.    if (scan == 14 && lo == 0x7f)
  342.       lo = 8;
  343.  
  344.    /*
  345.     * At the bottom of page 195 in MASM 6.0 ref manual, "..when the keypad
  346.     *  ENTER and / keys are read through the BIOS interrupt 16h, only E0h
  347.     *  is seen since the interrupt only gives one-byte scan codes."
  348.     */
  349.    else if (scan == 0xe0) {
  350.       /*
  351.        * plain Grey Enter
  352.        */
  353.       if (lo == 13 && !shift)
  354.          lo = 285;
  355.       /*
  356.        * shift Grey Enter
  357.        */
  358.       else if (lo == 13)
  359.          lo = 298;
  360.       /*
  361.        * control Grey Enter
  362.        */
  363.       else if (lo == 10)
  364.          lo = 299;
  365.    }
  366.  
  367.    /*
  368.     *  let's massage all of the control key combinations.
  369.     */
  370.    if (lo < 32) {
  371.  
  372.       /*
  373.        * My machine at home is sorta weird.  On every machine that I've
  374.        *  tested at the awffice, the ALT-xxx combination returns 0 for the
  375.        *  scan byte and xxx for the ASCII code.  My machine returns 184 (decimal)
  376.        *  as the scan code?!?!?  I added the next two lines for my machine at
  377.        *  home.  I wonder if someone forgot to zero out ah for Alt keypad entry
  378.        *  when they wrote my bios?
  379.        */
  380.       if (scan > 0x80)
  381.          scan = 0;
  382.  
  383.       /*
  384.        * Separate the ESC key from the ^[ key.  The scan code for the ESC
  385.        *  key is 1.  Map this to a different index into the key function
  386.        *  array just in case someone wants to define ESC or ^[ to different
  387.        *  functions.  BTW, ESC and ^[ return the same ASCII code, 27.
  388.        */
  389.       else if (scan == 1) {
  390.          if (shift)
  391.             lo = 259;
  392.          else if (control)
  393.             lo = 260;
  394.          else
  395.             lo = 258;
  396.       }
  397.  
  398.       /*
  399.        * Scan code for Enter = 28.  Separate the various Enter keys.
  400.        */
  401.       else if (scan == 28) {
  402.          if (shift)
  403.             lo = 263;
  404.          else if (control)
  405.             lo = 264;
  406.          else
  407.             lo = 262;
  408.       }
  409.  
  410.       /*
  411.        * Scan code for Backspace = 14.  Separate the various BackSpace keys.
  412.        */
  413.       else if (scan == 14) {
  414.          if (shift)
  415.             lo = 266;
  416.          else if (control)
  417.             lo = 267;
  418.          else
  419.             lo = 265;
  420.       }
  421.  
  422.       /*
  423.        * Scan code for Tab = 15.  Separate the tab key.
  424.        */
  425.       else if (scan == 15) {
  426.          lo = 268;
  427.       }
  428.  
  429.       /*
  430.        * if scan code is not 0, then a Control key was pressed.  Map
  431.        *  those keys to the WordStar commands.
  432.        */
  433.       else if (scan > 0)
  434.          lo += 430;
  435.  
  436.    } else if (!num_lock) {
  437.       switch (scan) {
  438.          /*
  439.           * scan code for grey - == 74.  if num_lock is not toggled, assign it
  440.           *  to the scroll line up function.
  441.           */
  442.          case 74 :
  443.             lo = 423;
  444.             break;
  445.  
  446.          /*
  447.           * scan code for grey + == 78.  if num_lock is not toggled, assign it
  448.           *  to the scroll line down function.  if shift grey + then stationary
  449.           *  scroll down.
  450.           */
  451.          case 78 :
  452.             lo = 424;
  453.             break;
  454.       }
  455.    }
  456.  
  457.  
  458.    /*
  459.     * let's set up for the Shift+Alt and Control+Alt keys.
  460.     *  With these key combinations, we can do the International keyboard
  461.     *  stuff, see the Microsoft MS DOS 5.0 manual pages 623-637.
  462.     */
  463.    if (lo > 256 && (shift || control)) {
  464.  
  465.       /*
  466.        * add 55 to Ctrl+Left thru Ctrl+Home when the shift key is pressed.
  467.        *  this is not part of the International keyboard stuff, just a way
  468.        *  to assign the horizontal scroll left and right funcs to cursor keys.
  469.        */
  470.       if (shift) {
  471.          if (lo >= 371 && lo <= 374)
  472.             lo += 55;
  473.  
  474.          /*
  475.           * if shift is down, map alt 1! thru alt =+ to shift alt 1! thru alt =+
  476.           */
  477.          else if (lo >= 376 && lo <= 387)
  478.             lo += 86;
  479.  
  480.          /*
  481.           * internation keyboard stuff
  482.           */
  483.          else if (lo >= 272 && lo <= 309)
  484.             lo += 202;
  485.       }
  486.    }
  487.  
  488.    /*
  489.     * map the enter key to line feed.
  490.     */
  491.    if (lo == 10  &&  scan != 0)
  492.       lo = 425;
  493.    return( lo );
  494. }
  495.  
  496.  
  497. /*
  498.  * Name:    waitkey
  499.  * Purpose: call the BIOS keyboard status subfunction
  500.  * Date:    October 31, 1992
  501.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  502.  * Returns: 1 if no key ready, 0 if key is waiting
  503.  * Notes:   lets get the keyboard status so we can spin on this function until
  504.  *           the user presses a key.  some OS replacements for DOS want
  505.  *           application programs to poll the keyboard instead of rudely
  506.  *           sitting on the BIOS read key function.
  507.  */
  508. int  waitkey( int enh_keyboard )
  509. {
  510.    return( _bios_keybrd( enh_keyboard ? 0x11 : 0x01 ) == 0 ? 1 : 0 );
  511. }
  512.  
  513.  
  514. /*
  515.  * Name:    getfunc
  516.  * Purpose: get the function assigned to key c
  517.  * Date:    July 11, 1991
  518.  * Passed:  c:  key just pressed
  519.  * Notes:   key codes less than 256 or 0x100 are not assigned a function.
  520.  *           The codes in the range 0-255 are ASCII and extended ASCII chars.
  521.  */
  522. int getfunc( int c )
  523. {
  524. register int i = c;
  525. int  key_found;
  526.  
  527.    if (!g_status.key_pending) {
  528.       i = c;
  529.       if (i <= 256)
  530.          i = 0;
  531.       else
  532.          i = key_func.key[i-256];
  533.    } else {
  534.  
  535.       /*
  536.        * allow the user to enter two-key combinations
  537.        */
  538.       key_found = FALSE;
  539.       for (i=0; i < MAX_TWO_KEYS; i++) {
  540.          if (g_status.first_key == two_key_list.key[i].parent_key &&
  541.                                c == two_key_list.key[i].child_key) {
  542.             i = two_key_list.key[i].func;
  543.             key_found = TRUE;
  544.             break;
  545.          }
  546.       }
  547.       if (key_found == FALSE)
  548.          i = ERROR;
  549.    }
  550.    return( i );
  551. }
  552.  
  553.  
  554. /*
  555.  * Name:    two_key
  556.  * Purpose: set the two_key flag and prompt for the next key.
  557.  * Date:    April 1, 1992
  558.  * Notes:   this function accepts two key commands.
  559.  */
  560. int  two_key( WINDOW *arg_filler )
  561. {
  562.    s_output( "Next Key..", g_display.mode_line, 67, g_display.diag_color );
  563.    g_status.key_pending = TRUE;
  564.    g_status.first_key = g_status.key_pressed;
  565.    return( OK );
  566. }
  567.  
  568.  
  569. /*********************************************/
  570. /*                                           */
  571. /*  3) video output routines, PC specific    */
  572. /*                                           */
  573. /*********************************************/
  574.  
  575.  
  576. /*
  577.  * Name:    xygoto
  578.  * Purpose: To move the cursor to the required column and line.
  579.  * Date:    September 28, 1991
  580.  * Passed:  col:    desired column (0 up to max)
  581.  *          line:   desired line (0 up to max)
  582.  * Notes;   use standard BIOS video interrupt 0x10 to set the set.
  583.  */
  584. void xygoto( int col, int line )
  585. {
  586. union REGS inregs, outregs;
  587.  
  588.    inregs.h.ah = 2;
  589.    inregs.h.bh = 0;
  590.    inregs.h.dh = (unsigned char)line;
  591.    inregs.h.dl = (unsigned char)col;
  592.    int86( 0x10, &inregs, &outregs );
  593. }
  594.  
  595.  
  596. /*
  597.  * Name:    update_line
  598.  * Purpose: Display the current line in window
  599.  * Date:    June 5, 1991
  600.  * Passed:  window:  pointer to current window
  601.  * Notes:   Show string starting at column zero and if needed blank rest
  602.  *           of line.  Put max_col in cx and count down.  When we run into
  603.  *           len, cx contains number of columns to blank out.  Use the
  604.  *           fast 'rep stosw' to clear the end of line.
  605.  *          The C routine was probably fast enough, but let's do some
  606.  *           assembly because it's so fun.
  607.  *          To handle line lengths longer than 255 characters,
  608.  *           block begin and end columns were changed from real
  609.  *           to virtual columns in this display routine.
  610.  */
  611. void update_line( WINDOW *window )
  612. {
  613. text_ptr text;      /* current character of orig begin considered */
  614. char far *screen_ptr;
  615. int  off;
  616. int  attr;
  617. int  line;
  618. int  col;
  619. int  bcol;
  620. int  bc;
  621. int  ec;
  622. int  normal;
  623. int  block;
  624. int  max_col;
  625. int  block_line;
  626. int  len;
  627. int  show_eol;
  628. int  c;
  629. long rline;
  630. file_infos *file;
  631.  
  632.    if (window->rline > window->file_info->length || window->ll->len == EOF)
  633.       return;
  634.    file = window->file_info;
  635.    max_col = window->end_col + 1 - window->start_col;
  636.    line = window->cline;
  637.    normal = window->ll->dirty == FALSE ? g_display.text_color : g_display.dirty_color;
  638.    block = g_display.block_color;
  639.    show_eol = mode.show_eol;
  640.  
  641.    /*
  642.     * set the screen pointer to physical screen memory.
  643.     *       160 = 80 chars + 80 attr  for each line
  644.     */
  645.    screen_ptr = g_display.display_address;
  646.    off = line * 160 + window->start_col * 2;
  647.  
  648.    /*
  649.     * figure which line to display.
  650.     * actually, we could be displaying any line in any file.  we display
  651.     *  the line_buffer only if window->ll == g_status.buff_node
  652.     *  and window->ll-line has been copied to g_status.line_buff.
  653.     */
  654.    text = window->ll->line;
  655.    len  = window->ll->len;
  656.    if (g_status.copied && ptoul( window->ll ) == ptoul( g_status.buff_node )) {
  657.       text = (text_ptr)g_status.line_buff;
  658.       len  = g_status.line_buff_len;
  659.    }
  660.    if (mode.inflate_tabs)
  661.       text = tabout( text, &len );
  662.  
  663.    /*
  664.     * lets look at the base column.  if the line to display is shorter
  665.     *  than the base column, then set text to eol and we can't see the
  666.     *  eol either.
  667.     */
  668.    bc = window->bcol;
  669.    if (bc > 0) {
  670.       if (text == NULL) {
  671.          show_eol = FALSE;
  672.          len = 0;
  673.       } else {
  674.          if ((col = len) < bc) {
  675.             bc = col;
  676.             show_eol = FALSE;
  677.          }
  678.          text += bc;
  679.          len  -= bc;
  680.       }
  681.    }
  682.  
  683.    /*
  684.     * for display purposes, set the line length to screen width if line
  685.     *  is longer than screen.  our assembly routine uses bytes and the
  686.     *  the line length can be longer than a byte.
  687.     */
  688.    if (len > max_col)
  689.       len = max_col;
  690.  
  691.    bcol = window->bcol;
  692.    rline = window->rline;
  693.    if (file->block_type && rline >= file->block_br && rline <= file->block_er)
  694.       block_line = TRUE;
  695.    else
  696.       block_line = FALSE;
  697.  
  698.    /*
  699.     * do this if 1) a box block is marked, or 2) a stream block begins
  700.     *  and ends on the same line.
  701.     */
  702.    if (block_line == TRUE && (file->block_type == BOX ||
  703.          (file->block_type == STREAM &&
  704.          rline == file->block_br && rline == file->block_er))) {
  705.  
  706.       /*
  707.        * start with the bc and ec equal to physical block marker.
  708.        */
  709.       bc = file->block_bc;
  710.       ec = file->block_ec;
  711.       if (ec < bcol || bc >= bcol + max_col)
  712.          /*
  713.           * we can't see block if ending column is less than the base col or
  714.           *  the beginning column is greater than max_col.
  715.           */
  716.          ec = bc = max_col + 1;
  717.       else if (ec < bcol + max_col) {
  718.          /*
  719.           * if the ec is less than the max column, make ec relative to
  720.           *  base column then figure the bc.
  721.           */
  722.          ec = ec - bcol;
  723.          if (bc < bcol)
  724.             bc = 0;
  725.          else
  726.             bc = bc - bcol;
  727.       } else if (bc < bcol + max_col) {
  728.          /*
  729.           * if the bc is less than the max column, make bc relative to
  730.           *  base column then figure the ec.
  731.           */
  732.          bc = bc - bcol;
  733.          if (ec > bcol + max_col)
  734.             ec = max_col;
  735.          else
  736.             ec = ec - bcol;
  737.       } else if (bc < bcol  &&  ec >= bcol + max_col) {
  738.          /*
  739.           * if the block is wider than the screen, make bc start at the
  740.           *  logical begin and make ec end at the logical end of the
  741.           *  window.
  742.           */
  743.          bc = 0;
  744.          ec = max_col;
  745.       }
  746.  
  747.  
  748.    ASSEMBLE {
  749.         /*
  750.         ; Register strategy:
  751.         ;   bl == beginning column
  752.         ;   bh == ending column
  753.         ;   dl == normal text attribute
  754.         ;   dh == block attribute
  755.         ;   cl == current virtual column
  756.         ;   ch == maximum columns in window
  757.         ;   ES:DI == screen pointer (destination)
  758.         ;   DS:SI == text pointer (source)
  759.         ;   [bp+show_eol]  == access for local C variable
  760.         */
  761.  
  762.  
  763.         push    ds                      /* MUST save ds - push it on stack */
  764.         push    si                      /* save si on stack */
  765.         push    di                      /* save di on stack */
  766.  
  767. /*
  768. ;
  769. ; set up local register variables
  770. ;
  771. */
  772.         mov     ax, WORD PTR bc         /* get beginning column */
  773.         mov     bl, al                  /* keep it in bl */
  774.         mov     ax, WORD PTR ec         /* get ending column */
  775.         mov     bh, al                  /* keep it in bh */
  776.         mov     ax, WORD PTR normal     /* get normal attribute */
  777.         mov     dl, al                  /* keep it in dl */
  778.         mov     ax, WORD PTR block      /* get block attribute */
  779.         mov     dh, al                  /* keep it in dh */
  780.         mov     ax, WORD PTR max_col    /* get max number columns on screen */
  781.         mov     ch, al                  /* keep it in ch */
  782.         xor     cl, cl                  /* col = 0, keep col in cl */
  783. /*
  784. ;
  785. ; load screen and text pointer
  786. ;
  787. */
  788.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  789.         add     di, WORD PTR off                /* add offset of line */
  790.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  791.         mov     es, ax
  792.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  793.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  794.         mov     ds, ax                  /* move segment of text in ds */
  795.         cmp     si, 0                   /* is offset of text ptr == NULL? */
  796.         jne     not_null                /* no, output string */
  797.         cmp     ax, 0                   /* is segment of text ptr == NULL? */
  798.         je      dspl_eol                /* yes, clear end of line */
  799.    }
  800. not_null:
  801.  
  802.    ASSEMBLE {
  803.         cmp     cl, ch                  /* is col == max_col? */
  804.         jge     getout                  /* yes, thru with line */
  805.         cmp     cl, BYTE PTR len        /* is col == len? */
  806.         je      dspl_eol                /* yes, must check block past eol */
  807.    }
  808. top:
  809.  
  810.    ASSEMBLE {
  811.         lodsb                   /* get next char in string */
  812.         mov     ah, dl          /* assume normal attribute */
  813.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  814.         jl      ch_out1         /* yes, show char and normal attribute */
  815.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  816.         jg      ch_out1         /* yes, show char and normal attribute */
  817.         mov     ah, dh          /* must be in a block - block attribute */
  818.    }
  819. ch_out1:
  820.  
  821.    ASSEMBLE {
  822.         stosw                   /* now show char on screen w/ attribute */
  823.         inc     cl              /* ++col */
  824.         cmp     cl, ch          /* is col == max_col? */
  825.         jge     getout          /* yes, thru with line */
  826.         cmp     cl, BYTE PTR len        /* is col == len? */
  827.         jl      top             /* yes, must check block past eol */
  828.    }
  829. dspl_eol:
  830.  
  831.    ASSEMBLE {
  832.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  833.         je      block_eol       /* show_eol flag is FALSE, blank line */
  834.         mov     al, EOL_CHAR    /* load some eol indicator */
  835.         mov     ah, dl          /* assume normal attribute */
  836.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  837.         jl      ch_out2         /* yes, show char and normal attribute */
  838.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  839.         jg      ch_out2         /* yes, show char and normal attribute */
  840.         mov     ah, dh          /* must be in a block - show block attribute */
  841.    }
  842. ch_out2:
  843.  
  844.    ASSEMBLE {
  845.         stosw                   /* write eol and attribute to screen */
  846.         inc     cl              /* ++col */
  847.         cmp     cl, ch          /* is col == max_col? */
  848.         je      getout          /* yes, we're done */
  849.    }
  850. block_eol:
  851.  
  852.    ASSEMBLE {
  853.         mov     al, ' '         /* clear rest of line w/ spaces */
  854.    }
  855. b1:
  856.  
  857.    ASSEMBLE {
  858.         mov     ah, dl          /* assume normal attribute */
  859.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  860.         jl      ch_out3         /* yes, show char and normal attribute */
  861.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  862.         jg      ch_out3         /* yes, show char and normal attribute */
  863.         mov     ah, dh          /* must be in a block - show block attribute */
  864.    }
  865. ch_out3:
  866.  
  867.    ASSEMBLE {
  868.         stosw                   /* write blank and attribute to screen */
  869.         inc     cl              /* ++col */
  870.         cmp     cl, ch          /* is col == max_col? */
  871.         jl      b1              /* while less output block */
  872.    }
  873. getout:
  874.  
  875.    ASSEMBLE {
  876.         pop     di
  877.         pop     si
  878.         pop     ds
  879.       }
  880.  
  881. /*
  882.       screen_ptr += off;
  883.       bcol = window->start_col;
  884.       for (col=0; col < max_col; col++, bcol++) {
  885.          attr = normal;
  886.          if (col >= bc && col <= ec)
  887.             attr = block;
  888.          if (col < len)
  889.             c = *text++;
  890.          else if (col == len && show_eol)
  891.             c = EOL_CHAR;
  892.          else
  893.             c = ' ';
  894.          *screen_ptr++ = c;
  895.          *screen_ptr++ = attr;
  896.  
  897.          c_output( c, bcol, line, attr );
  898.       }
  899. */
  900.    } else if (block_line == TRUE && file->block_type == STREAM &&
  901.               (rline == file->block_br || rline == file->block_er)) {
  902.       if (rline == file->block_br)
  903.          bc = file->block_bc;
  904.       else {
  905.          bc = file->block_ec + 1;
  906.          ec = normal;
  907.          normal = block;
  908.          block = ec;
  909.       }
  910.       if (bc < bcol)
  911.          bc = 0;
  912.       else if (bc < bcol + max_col)
  913.          bc = bc - bcol;
  914.       else
  915.          bc = max_col + 1;
  916.  
  917.  
  918.    ASSEMBLE {
  919.         /*
  920.         ; Register strategy:
  921.         ;   bl == beginning column
  922.         ;   bh == relative line length
  923.         ;   dl == normal text attribute
  924.         ;   dh == block attribute
  925.         ;   cl == current virtual column
  926.         ;   ch == maximum columns in window
  927.         ;   ES:DI == screen pointer (destination)
  928.         ;   DS:SI == text pointer (source)
  929.         ;   [bp+show_eol]  == access for local C variable
  930.         */
  931.  
  932.         push    ds                      /* MUST save ds - push it on stack */
  933.         push    si                      /* save si on stack */
  934.         push    di                      /* save di on stack */
  935.  
  936. /*
  937. ;
  938. ; set up local register variables
  939. ;
  940. */
  941.         mov     ax, WORD PTR bc         /* get beginning column */
  942.         mov     bl, al                  /* keep it in bl */
  943.         mov     ax, WORD PTR len        /* get relative line length */
  944.         mov     bh, al                  /* keep it in bh */
  945.         mov     ax, WORD PTR normal     /* get normal attribute */
  946.         mov     dl, al                  /* keep it in dl */
  947.         mov     ax, WORD PTR block      /* get block attribute */
  948.         mov     dh, al                  /* keep it in dh */
  949.         mov     ax, WORD PTR max_col    /* get max number columns on screen */
  950.         mov     ch, al                  /* keep it in ch */
  951.         xor     cl, cl                  /* col = 0, keep col in cl */
  952. /*
  953. ;
  954. ; load screen and text pointer
  955. ;
  956. */
  957.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  958.         add     di, WORD PTR off                /* add offset of line */
  959.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  960.         mov     es, ax
  961.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  962.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  963.         mov     ds, ax                  /* move segment of text in ds */
  964.         cmp     si, 0                   /* is offset of text ptr == NULL? */
  965.         jne     nott_null               /* no, output string */
  966.         cmp     ax, 0                   /* is segment of text ptr == NULL? */
  967.         je      ddspl_eol               /* yes, clear end of line */
  968.    }
  969. nott_null:
  970.  
  971.    ASSEMBLE {
  972.         cmp     cl, ch          /* is col == max_col? */
  973.         je      ggetout         /* yes, thru with line */
  974.         cmp     cl, bh          /* is col == len? */
  975.         je      ddspl_eol       /* yes, check eol display */
  976.    }
  977. ttop:
  978.  
  979.    ASSEMBLE {
  980.         lodsb                   /* get next char in string */
  981.         mov     ah, dl          /* assume normal attribute */
  982.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  983.         jl      str_out1        /* yes, show char and normal attribute */
  984.         mov     ah, dh          /* must be in a block - show block attribute */
  985.    }
  986. str_out1:
  987.  
  988.    ASSEMBLE {
  989.         stosw                   /* else show char on screen */
  990.         inc     cl              /* ++col */
  991.         cmp     cl, ch          /* is col == max_col? */
  992.         je      ggetout         /* yes, thru with line */
  993.         cmp     cl, bh          /* is col == len? */
  994.         jl      ttop            /* yes, check eol display */
  995.    }
  996. ddspl_eol:
  997.  
  998.    ASSEMBLE {
  999.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1000.         je      stream_eol      /* show_eol flag is FALSE, blank line */
  1001.         mov     al, EOL_CHAR    /* load some eol indicator */
  1002.         mov     ah, dl          /* assume normal attribute */
  1003.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1004.         jl      str_out2        /* yes, show char and normal attribute */
  1005.         mov     ah, dh          /* must be in a block - show block attribute */
  1006.    }
  1007. str_out2:
  1008.  
  1009.    ASSEMBLE {
  1010.         stosw                   /* write blank and attribute to screen */
  1011.         inc     cl              /* ++col */
  1012.         cmp     cl, ch          /* is col == max_col? */
  1013.         jge     ggetout         /* yes, we're done */
  1014.    }
  1015. stream_eol:
  1016.  
  1017.    ASSEMBLE {
  1018.         mov     al, ' '         /* clear rest of line w/ spaces */
  1019.    }
  1020. c1:
  1021.  
  1022.    ASSEMBLE {
  1023.         mov     ah, dl          /* assume normal attribute */
  1024.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1025.         jl      str_out3        /* yes, show char and normal attribute */
  1026.         mov     ah, dh          /* must be in a block - show block attribute */
  1027.    }
  1028. str_out3:
  1029.  
  1030.    ASSEMBLE {
  1031.         stosw                   /* write blank and attribute to screen */
  1032.         inc     cl              /* ++col */
  1033.         cmp     cl, ch          /* is col == max_col? */
  1034.         jl      c1              /* while less output block */
  1035.    }
  1036. ggetout:
  1037.  
  1038.    ASSEMBLE {
  1039.         pop     di
  1040.         pop     si
  1041.         pop     ds
  1042.       }
  1043.  
  1044. /*
  1045.       screen_ptr += off;
  1046.       bcol = window->start_col;
  1047.       for (col=0; col < max_col; col++, bcol++) {
  1048.          attr = normal;
  1049.          if (col >= bc && col <= ec)
  1050.             attr = block;
  1051.          if (col < len)
  1052.             c = *text++;
  1053.          else if (col == len && show_eol)
  1054.             c = EOL_CHAR;
  1055.          else
  1056.             c = ' ';
  1057.          *screen_ptr++ = c;
  1058.          *screen_ptr++ = attr;
  1059.          c_output( c, bcol, line, attr );
  1060.       }
  1061. */
  1062.    } else {
  1063.       if (block_line)
  1064.          attr = block;
  1065.       else
  1066.          attr = normal;
  1067.  
  1068.       assert( len >= 0 );
  1069.       assert( len <= MAX_COLS );
  1070.  
  1071.    ASSEMBLE {
  1072.         /*
  1073.         ; Register strategy:
  1074.         ;   bl == normal text attribute
  1075.         ;   bh == relative line length
  1076.         ;   cl == current virtual column
  1077.         ;   ch == maximum columns in window
  1078.         ;   ES:DI == screen pointer (destination)
  1079.         ;   DS:SI == text pointer (source)
  1080.         ;   [bp+show_eol]  == access for local C variable
  1081.         */
  1082.  
  1083.         mov     dx, ds          /* MUST save ds - keep it in dx */
  1084.         push    di              /* save di on stack */
  1085.         push    si              /* save si on stack */
  1086.  
  1087.  
  1088.         mov     bx, WORD PTR attr               /* keep attribute in bl */
  1089.         mov     ax, WORD PTR len                /* get normalized len */
  1090.         mov     bh, al                          /* keep len in bh */
  1091.         mov     cx, WORD PTR max_col            /* get max_col in cx */
  1092.         mov     ch, cl                          /* keep it in ch */
  1093.         xor     cl, cl                          /* zero out cl */
  1094.         mov     di, WORD PTR screen_ptr         /* load OFFST of screen ptr */
  1095.         add     di, WORD PTR off                /* add offset of line */
  1096.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1097.         mov     es, ax
  1098.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  1099.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  1100.         mov     ds, ax                  /* move segment of text in ds */
  1101.         cmp     si, 0                   /* is offset of pointer == NULL? */
  1102.         jne     nnot_null               /* no, output string */
  1103.         cmp     ax, 0                   /* is segment of pointer == NULL? */
  1104.         je      normeol                 /* yes, then clear rest of line */
  1105.    }
  1106. nnot_null:
  1107.  
  1108.    ASSEMBLE {
  1109.         mov     ah, bl                  /* get attribute */
  1110.         cmp     cl, ch          /* compare count with max columns */
  1111.         jge     getoutt         /* yes, thru with line */
  1112.         cmp     cl, bh          /* compare count with len */
  1113.         je      normeol         /* yes, clear end of line */
  1114.    }
  1115. topp:
  1116.  
  1117.    ASSEMBLE {
  1118.         lodsb                   /* get next char in string */
  1119.         stosw                   /* else show char on screen */
  1120.         inc     cl              /* ++col, count up to max_column */
  1121.         cmp     cl, ch          /* compare count with max columns */
  1122.         jge     getoutt         /* yes, thru with line */
  1123.         cmp     cl, bh          /* compare count with len */
  1124.         jl      topp            /* yes, clear end of line */
  1125.    }
  1126. normeol:
  1127.  
  1128.    ASSEMBLE {
  1129.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1130.         je      clreol          /* show_eol flag is FALSE, blank line */
  1131.         mov     al, EOL_CHAR    /* load some eol indicator */
  1132.         mov     ah, bl          /* assume normal attribute */
  1133.         stosw                   /* write blank and attribute to screen */
  1134.         inc     cl              /* ++col */
  1135.         cmp     cl, ch          /* is col == max_col? */
  1136.         jge     getoutt         /* yes, we're done */
  1137.    }
  1138. clreol:
  1139.  
  1140.    ASSEMBLE {
  1141.         mov     ah, bl          /* get attribute */
  1142.         mov     al, ' '         /* clear eol with ' ' */
  1143.         sub     ch, cl          /* find number of columns left */
  1144.         mov     cl, ch          /* put number of column left in cl */
  1145.         xor     ch, ch          /* clear ch */
  1146.         rep     stosw           /* count is in cx - set rest of line to ' ' */
  1147.    }
  1148. getoutt:
  1149.  
  1150.    ASSEMBLE {
  1151.         pop     si
  1152.         pop     di
  1153.         mov     ds, dx
  1154.       }
  1155.  
  1156. /*
  1157.       screen_ptr += off;
  1158.       bcol = window->start_col;
  1159.       for (col=0; col < max_col; col++, bcol++) {
  1160.          attr = normal;
  1161.          if (col < len)
  1162.             c = *text++;
  1163.          else if (col == len && show_eol)
  1164.             c = EOL_CHAR;
  1165.          else
  1166.             c = ' ';
  1167.          *screen_ptr++ = c;
  1168.          *screen_ptr++ = attr;
  1169.          c_output( c, bcol, line, attr );
  1170.       }
  1171. */
  1172.    }
  1173. }
  1174.  
  1175.  
  1176. /*
  1177.  * Name:    c_output
  1178.  * Purpose: Output one character on prompt lines
  1179.  * Date:    June 5, 1991
  1180.  * Passed:  c:     character to output to screen
  1181.  *          col:   col to display character
  1182.  *          line:  line number to display character
  1183.  *          attr:  attribute of character
  1184.  * Returns: none
  1185.  */
  1186. void c_output( int c, int col, int line, int attr )
  1187. {
  1188. void far *screen_ptr;
  1189. int  off;
  1190.  
  1191.    screen_ptr = (void far *)g_display.display_address;
  1192.    off = line * 160 + col * 2;
  1193.  
  1194.    ASSEMBLE {
  1195.         mov     bx, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1196.         add     bx, WORD PTR off                /* add offset of line:col */
  1197.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1198.         mov     es, ax
  1199.         mov     cx, WORD PTR attr       /* get attribute */
  1200.         mov     ah, cl                  /* put in ah */
  1201.         mov     cx, WORD PTR c          /* get character */
  1202.         mov     al, cl                  /* put in al */
  1203.         mov     WORD PTR es:[bx], ax    /* show char on screen */
  1204.    }
  1205.  
  1206. /*
  1207.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  1208.    *screen_ptr++ = c;
  1209.    *screen_ptr = attr;
  1210. */
  1211. }
  1212.  
  1213.  
  1214. /*
  1215.  * Name:    s_output
  1216.  * Purpose: To output a string
  1217.  * Date:    June 5, 1991
  1218.  * Passed:  s:     string to output
  1219.  *          line:  line to display
  1220.  *          col:   column to begin display
  1221.  *          attr:  color to display string
  1222.  * Notes:   This function is used to output most strings not part of file text.
  1223.  */
  1224. void s_output( char far *s, int line, int col, int attr )
  1225. {
  1226. void far *screen_ptr;
  1227. int  off;
  1228. int  max_col;
  1229.  
  1230.    max_col = g_display.ncols;
  1231.    screen_ptr = (void far *)g_display.display_address;
  1232.    off = line * 160 + col * 2;
  1233.  
  1234.    ASSEMBLE {
  1235.         push    ds              /* save ds on stack */
  1236.         push    di              /* save di on stack */
  1237.         push    si              /* save si on stack */
  1238.  
  1239.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1240.         mov     cx, WORD PTR col                /* put cols in cx */
  1241.         mov     dx, WORD PTR max_col            /* keep max_col in dx */
  1242.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1243.         add     di, WORD PTR off                /* add offset of line:col */
  1244.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1245.         mov     es, ax
  1246.         mov     si, WORD PTR s  /* load offset of string ptr */
  1247.         or      si, si          /* is it == NULL? */
  1248.         je      getout          /* yes, no output needed */
  1249.         mov     ax, WORD PTR s+2        /* load segment of string ptr */
  1250.         or      ax, ax          /* is pointer == NULL? */
  1251.         je      getout          /* yes, no output needed */
  1252.         mov     ds, ax          /* load segment of text in ds */
  1253.         mov     ah, bl          /* put attribute in AH */
  1254.    }
  1255. top:
  1256.  
  1257.    ASSEMBLE {
  1258.         cmp     cx, dx          /* col < max_cols? */
  1259.         jge     getout          /* no, thru with line */
  1260.         lodsb                   /* get next char in string - put in al */
  1261.         or      al, al          /* is it '\0' */
  1262.         je      getout          /* yes, end of string */
  1263.         cmp     al, 0x0a        /* is it '\n'? */
  1264.         je      getout          /* yes, end of string */
  1265.         stosw                   /* else show attr + char on screen (ah + al) */
  1266.         inc     cx              /* col++ */
  1267.         jmp     SHORT top       /* get another character */
  1268.    }
  1269. getout:
  1270.  
  1271.    ASSEMBLE {
  1272.         pop     si              /* get back si */
  1273.         pop     di              /* get back di */
  1274.         pop     ds              /* get back ds */
  1275.    }
  1276.  
  1277. /*
  1278.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  1279.    max_col = g_display.ncols;
  1280.    while (*s && col < max) {
  1281.       *screen_ptr++ = *s++;
  1282.       *screen_ptr++ = attr;
  1283.    }
  1284. */
  1285. }
  1286.  
  1287.  
  1288. /*
  1289.  * Name:    eol_clear
  1290.  * Purpose: To clear the line from col to max columns
  1291.  * Date:    June 5, 1991
  1292.  * Passed:  col:   column to begin clear
  1293.  *          line:  line to clear
  1294.  *          attr:  color to clear
  1295.  * Notes:   Basic assembly
  1296.  */
  1297. void eol_clear( int col, int line, int attr )
  1298. {
  1299. int  max_col;
  1300. void far *screen_ptr;
  1301. int  off;
  1302.  
  1303.    max_col = g_display.ncols;
  1304.    screen_ptr = (void far *)g_display.display_address;
  1305.    off = line * 160 + col * 2;
  1306.  
  1307.    ASSEMBLE {
  1308.         push    di                              /* save di on stack */
  1309.  
  1310.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1311.         mov     dx, WORD PTR col                /* put cols in dx */
  1312.         mov     cx, WORD PTR max_col            /* put max_col in cx */
  1313.         cmp     dx, cx                          /* max_cols < cols? */
  1314.         jge     getout                          /* no, thru with line */
  1315.         sub     cx, dx                          /* number of column to clear */
  1316.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1317.         add     di, WORD PTR off                /* add offset of line:col */
  1318.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1319.         mov     es, ax
  1320.         mov     ah, bl                          /* get attribute in ah */
  1321.         mov     al, ' '                         /* store ' ' in al */
  1322.         rep     stosw                           /* clear to end of line */
  1323.    }
  1324. getout:
  1325.  
  1326.    ASSEMBLE {
  1327.         pop     di                              /* get back di from stack */
  1328.    }
  1329.  
  1330. /*
  1331.    for (; col < g_display.ncols; col++) {
  1332.       *p++ = ' ';
  1333.       *p++ = attr;
  1334.    }
  1335. */
  1336. }
  1337.  
  1338.  
  1339. /*
  1340.  * Name:    window_eol_clear
  1341.  * Purpose: To clear the line from start_col to end_col
  1342.  * Date:    June 5, 1991
  1343.  * Passed:  col:   column to begin clear
  1344.  *          line:  line to clear
  1345.  *          attr:  color to clear
  1346.  * Notes:   Basic assembly
  1347.  */
  1348. void window_eol_clear( WINDOW *window, int attr )
  1349. {
  1350. int  max_col;
  1351. void far *screen_ptr;
  1352. int  off;
  1353.  
  1354.    screen_ptr = (void far *)g_display.display_address;
  1355.    off = window->cline * 160 + window->start_col * 2;
  1356.    max_col = window->end_col + 1 - window->start_col;
  1357.  
  1358.    ASSEMBLE {
  1359.         push    di                              /* save di on stack */
  1360.  
  1361.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1362.         mov     cx, WORD PTR max_col            /* put max_col in cx */
  1363.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1364.         add     di, WORD PTR off                /* add offset of line:col */
  1365.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1366.         mov     es, ax
  1367.         mov     ah, bl                          /* get attribute in ah */
  1368.         mov     al, ' '                         /* store ' ' in al */
  1369.         rep     stosw                           /* clear to end of line */
  1370.  
  1371.         pop     di                              /* get back di from stack */
  1372.    }
  1373.  
  1374. /*
  1375.    for (; col < g_display.ncols; col++) {
  1376.       *p++ = ' ';
  1377.       *p++ = attr;
  1378.    }
  1379. */
  1380. }
  1381.  
  1382.  
  1383. /*
  1384.  * Name:    hlight_line
  1385.  * Date:    July 21, 1991
  1386.  * Passed:  x:     column to begin hi lite
  1387.  *          y:     line to begin hi lite
  1388.  *          lgth:  number of characters to hi lite
  1389.  *          attr:  attribute color
  1390.  * Notes:   The attribute byte is the hi byte.
  1391.  */
  1392. void hlight_line( int x, int y, int lgth, int attr )
  1393. {
  1394. int  off;
  1395. void far *screen_ptr;
  1396.  
  1397.    screen_ptr = (void far *)g_display.display_address;
  1398.    off = y * 160 + 2 * x + 1;  /* add one - so it points to attribute byte */
  1399.  
  1400.    ASSEMBLE {
  1401.         push    di              /* save di */
  1402.  
  1403.         mov     cx, lgth        /* number of characters to change color */
  1404.  
  1405.         mov     di, WORD PTR screen_ptr /* get destination - video memory */
  1406.         add     di, off                 /* add offset */
  1407.         mov     ax, WORD PTR screen_ptr+2
  1408.         mov     es, ax
  1409.         mov     ax, attr        /* attribute */
  1410.    }
  1411. lite_len:
  1412.  
  1413.    ASSEMBLE {
  1414.         stosb                   /* store a BYTE */
  1415.         inc     di              /* skip over character to next attribute */
  1416.         loop    lite_len        /* change next attribute */
  1417.         pop     di              /* restore di */
  1418.    }
  1419. }
  1420.  
  1421.  
  1422. /*
  1423.  * Name:    cls
  1424.  * Purpose: clear screen
  1425.  * Date:    June 5, 1991
  1426.  * Notes:   Call the video BIOS routine to clear the screen.
  1427.  */
  1428. void cls( void )
  1429. {
  1430. int  line;
  1431.  
  1432.      line = g_display.nlines + 1;
  1433.  
  1434.    ASSEMBLE {
  1435.         xor     ch, ch                  /* starting row in ch = 0 */
  1436.         xor     cl, cl                  /* starting column in cl = 0 */
  1437.         mov     ax, WORD PTR line       /* get ending row */
  1438.         mov     dh, al                  /* put it in dh */
  1439.         mov     dl, 79                  /* ending column in dl = 79 */
  1440.         mov     bh, 7                   /* attribute in bh  = 7 (normal) */
  1441.         mov     al, 0                   /* get number of lines */
  1442.         mov     ah, 6                   /* get function number */
  1443.         push    bp                      /* some BIOS versions wipe out bp */
  1444.         int     0x10
  1445.         pop     bp
  1446.    }
  1447. }
  1448.  
  1449.  
  1450. /*
  1451.  * Name:    set_cursor_size
  1452.  * Purpose: To set cursor size according to insert mode.
  1453.  * Date:    June 5, 1991
  1454.  * Passed:  csize:  desired cursor size
  1455.  * Notes:   use the global display structures to set the cursor size
  1456.  */
  1457. void set_cursor_size( int csize )
  1458. {
  1459.    ASSEMBLE {
  1460.         mov     ah, 1                   /* function 1 - set cursor size */
  1461.         mov     cx, WORD PTR csize      /* get cursor size ch:cl == top:bot */
  1462.         push    bp
  1463.         int     VIDEO_INT               /* video interrupt = 10h */
  1464.         pop     bp
  1465.    }
  1466. }
  1467.  
  1468.  
  1469. /*
  1470.  * Name:    set_overscan_color
  1471.  * Purpose: To set overscan color
  1472.  * Date:    April 1, 1993
  1473.  * Passed:  color:  overscan color
  1474.  * Notes:   before setting the overscan color, the old overscan color
  1475.  *           needs to be saved so it can be restored.
  1476.  */
  1477. void set_overscan_color( int color )
  1478. {
  1479.    ASSEMBLE {
  1480.         mov     ah, 0x0b                /* function 0x0b */
  1481.         mov     bl, BYTE PTR color      /* get new overscan color */
  1482.         xor     bh, bh
  1483.         push    bp
  1484.         int     VIDEO_INT               /* video interrupt = 10h */
  1485.         pop     bp
  1486.    }
  1487. }
  1488.  
  1489.  
  1490. /*
  1491.  * Name:    save_screen_line
  1492.  * Purpose: To save the characters and attributes of a line on screen.
  1493.  * Date:    June 5, 1991
  1494.  * Passed:  col:    desired column, usually always zero
  1495.  *          line:   line on screen to save (0 up to max)
  1496.  *          screen_buffer:  buffer for screen contents, must be >= 160 chars
  1497.  * Notes:   Save the contents of the line on screen where prompt is
  1498.  *           to be displayed
  1499.  */
  1500. void save_screen_line( int col, int line, char *screen_buffer )
  1501. {
  1502. char far *p;
  1503.  
  1504.    p = g_display.display_address + line * 160 + col * 2;
  1505.    _fmemcpy( screen_buffer, p, 160 );
  1506. }
  1507.  
  1508.  
  1509. /*
  1510.  * Name:    restore_screen_line
  1511.  * Purpose: To restore the characters and attributes of a line on screen.
  1512.  * Date:    June 5, 1991
  1513.  * Passed:  col:    usually always zero
  1514.  *          line:   line to restore (0 up to max)
  1515.  *          screen_buffer:  buffer for screen contents, must be >= 160 chars
  1516.  * Notes:   Restore the contents of the line on screen where the prompt
  1517.  *           was displayed
  1518.  */
  1519. void restore_screen_line( int col, int line, char *screen_buffer )
  1520. {
  1521. char far *p;
  1522.  
  1523.    p = g_display.display_address + line * 160 + col * 2;
  1524.    _fmemcpy( p, screen_buffer, 160 );
  1525. }
  1526.