home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR8 / TDE32.ZIP / CONSOLE.C < prev    next >
C/C++ Source or Header  |  1993-11-13  |  75KB  |  2,305 lines

  1. /*
  2.  * All video and keyboard functions were gathered into one file.
  3.  *
  4.  * In version 3.2, this file was split into 3 sections:  1) unix curses
  5.  * made to look and feel like a PC, 2) our PC hardware specific stuff,
  6.  * and 3) hardware independent stuff.
  7.  *
  8.  * This file contains the keyboard and video i/o stuff.  Most of this stuff
  9.  * is specific to the PC hardware, but it should be easily modified when
  10.  * porting to other platforms.  With a few key functions written in
  11.  * assembly, we have fairly fast video performance and good keyboard control.
  12.  * Incidentally, the commented C code in the functions perform the same
  13.  * function as the assembly code.  In earlier versions of TDE, I didn't
  14.  * update the commented C code when I changed the assembly code.  The
  15.  * C and assembly should be equivalent in version 2.2.
  16.  *
  17.  * Although using a curses type package would be more portable, curses
  18.  * can be slow on PCs.  Let's keep our video and keyboard routines in
  19.  * assembly.  I feel the need for speed.
  20.  *
  21.  * Being that TDE 2.2 keeps an accurate count of characters in each line, we
  22.  * can allow the user to enter any ASCII or Extended ASCII key.
  23.  *
  24.  * Determining the video adapter type on the PC requires a function.  In
  25.  *  TDE, that function is:
  26.  *
  27.  *                void video_config( struct vcfg *cfg )
  28.  *
  29.  * video_config( ) is based on Appendix C in _Programmer's Guide to
  30.  *  PC & PS/2 Video Systems_ by Richard Wilton.
  31.  *
  32.  * See:
  33.  *
  34.  *   Richard Wilton, _Programmer's Guide to PC & PS/2 Video Systems_,
  35.  *    Microsoft Press, Redmond, Washington, 1987, Appendix C, pp 511-521.
  36.  *    ISBN 1-55615-103-9.
  37.  *
  38.  *
  39.  * New editor name:  TDE, the Thomson-Davis Editor.
  40.  * Author:           Frank Davis
  41.  * Date:             June 5, 1991, version 1.0
  42.  * Date:             July 29, 1991, version 1.1
  43.  * Date:             October 5, 1991, version 1.2
  44.  * Date:             January 20, 1992, version 1.3
  45.  * Date:             February 17, 1992, version 1.4
  46.  * Date:             April 1, 1992, version 1.5
  47.  * Date:             June 5, 1992, version 2.0
  48.  * Date:             October 31, 1992, version 2.1
  49.  * Date:             April 1, 1993, version 2.2
  50.  * Date:             June 5, 1993, version 3.0
  51.  * Date:             August 29, 1993 version 3.1
  52.  * Date:             November 13, version 3.2
  53.  *
  54.  * This code is released into the public domain, Frank Davis.
  55.  * You may distribute it freely.
  56.  */
  57.  
  58.  
  59. #include "tdestr.h"
  60. #include "common.h"
  61. #include "define.h"
  62. #include "tdefunc.h"
  63.  
  64. #if defined( __UNIX__ )
  65. /*
  66.  **********************************************************************
  67.  ******************************  PART 1  ******************************
  68.  **********************************************************************
  69.  *
  70.  * Let's try to make unix have the look and feel of a PC.
  71.  */
  72.  
  73.  
  74. /*
  75.  * Name:    video_config
  76.  * Purpose: simulate a call the BIOS keyboard status subfunction
  77.  * Date:    November 13, 1993
  78.  * Passed:  cfg:  not used
  79.  * Notes:   curses has three (?) cursor shapes:  invisible, normal, large.
  80.  */
  81. void video_config( struct vcfg *cfg )
  82. {
  83. /*
  84.    g_display.insert_cursor =
  85.                  mode.cursor_size == SMALL_INS ? CURSES_SMALL : CURSES_LARGE;
  86.    g_display.overw_cursor =
  87.                  mode.cursor_size == SMALL_INS ? CURSES_LARGE : CURSES_SMALL;
  88. */
  89.  
  90.    g_display.insert_cursor = g_display.overw_cursor = CURSES_SMALL;
  91.    if (mode.insert)
  92.       g_display.curses_cursor = g_display.insert_cursor;
  93.    else
  94.       g_display.curses_cursor = g_display.overw_cursor;
  95. }
  96.  
  97.  
  98. /*
  99.  * Name:    getkey
  100.  * Purpose: use unix curses to get keyboard input
  101.  * Date:    November 13, 1993
  102.  * Passed:  None
  103.  * Notes:   the getch( ) function is not part of the ANSI C standard.
  104.  *            most (if not all) PC C compilers include getch( ) with the
  105.  *            conio stuff.  in unix, getch( ) is in the curses package.
  106.  *          in TDE, lets try to map the curses function keys to their
  107.  *            "natural" positions on PC hardware.  most of the key mapping
  108.  *            is at the bottom of default.h.
  109.  *          this function is based on the ncurses package in Linux.  It
  110.  *            probably needs to be modified for curses in other unices.
  111.  */
  112. int getkey( void )
  113. {
  114. unsigned key;
  115.  
  116.    key = getch( );
  117.  
  118.    /*
  119.     * map the Control keys to their natural place in TDE.
  120.     */
  121.    if (key < 32)
  122.       key += 430;
  123.    else if (key > 255) {
  124.  
  125.       /*
  126.        * map ncurses keys to their natural place in TDE.
  127.        * ncurses defines function keys in the range 256-408.
  128.        */
  129.       if (key > 408)
  130.          key = 256;
  131.       key = curses_to_tde[key - 256];
  132.    }
  133.    return( key );
  134. }
  135.  
  136.  
  137. /*
  138.  * Name:    waitkey
  139.  * Purpose: nothing right now
  140.  * Date:    November 13, 1993
  141.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  142.  * Returns: 1 if no key ready, 0 if key is waiting
  143.  * Notes:   we might do something with this function later...
  144.  */
  145. int  waitkey( int enh_keyboard )
  146. {
  147.    return( 0 );
  148. }
  149.  
  150.  
  151. /*
  152.  * Name:    flush_keyboard
  153.  * Purpose: flush keys from the keyboard buffer.  flushinp is a curses func.
  154.  * Date:    November 13, 1993
  155.  * Passed:  none
  156.  */
  157. void flush_keyboard( void )
  158. {
  159.    flushinp( );
  160. }
  161.  
  162.  
  163. /*
  164.  * Name:    xygoto
  165.  * Purpose: To move the cursor to the required column and line.
  166.  * Date:    November 13, 1993
  167.  * Passed:  col:    desired column (0 up to max)
  168.  *          line:   desired line (0 up to max)
  169.  * Notes;   on the PC, we use col = -1 and line = -1 to turn the cursor off.
  170.  *            in unix, we try to trap the -1's.
  171.  *          curs_set is a curses function.
  172.  */
  173. void xygoto( int col, int line )
  174. {
  175.    if (col < 0 || line < 0) {
  176.       curs_set( CURSES_INVISBL );
  177.       g_display.curses_cursor = CURSES_INVISBL;
  178.    } else {
  179.  
  180.       /*
  181.        * if the unix cursor is invisible, lets turn it back on.
  182.        */
  183.       if (g_display.curses_cursor == CURSES_INVISBL) {
  184. /*
  185.          if (mode.insert == TRUE) {
  186.             if (g_display.insert_cursor == SMALL_INS)
  187.                set_cursor_size( CURSES_SMALL );
  188.             else
  189.                set_cursor_size( CURSES_LARGE );
  190.          } else {
  191.             if (g_display.insert_cursor == SMALL_INS)
  192.                set_cursor_size( CURSES_LARGE );
  193.             else
  194.                set_cursor_size( CURSES_SMALL );
  195.          }
  196. */
  197.          set_cursor_size( CURSES_SMALL );
  198.          g_display.curses_cursor = CURSES_SMALL;
  199.       }
  200.       move( line, col );
  201.    }
  202. }
  203.  
  204.  
  205. /*
  206.  * Name:    update_line
  207.  * Purpose: Display the current line in window
  208.  * Date:    November 13, 1993
  209.  * Passed:  window:  pointer to current window
  210.  * Notes:   use the curses mvaddch( ) function to put char + attribute
  211.  *           on the screen.
  212.  *          let's check for control characters before they get to curses.
  213.  *            unix and/or curses is brain-damaged when it comes to
  214.  *            control characters and extended ASCII characters.
  215.  */
  216. void update_line( TDE_WIN *window )
  217. {
  218. text_ptr text;      /* current character of orig begin considered */
  219. int  attr;          /* index into TDE's chtype table */
  220. int  line;
  221. int  col;
  222. int  bcol;
  223. int  bc;
  224. int  ec;
  225. int  normal;
  226. int  block;
  227. int  max_col;
  228. int  block_line;
  229. int  len;
  230. int  show_eol;
  231. unsigned int  c;
  232. long rline;
  233. file_infos *file;
  234. chtype curses_attribute;        /* chtype is defined in curses.h */
  235.  
  236.    /*
  237.     * we don't use this function the display the EOF message.
  238.     * return if this display is turned off.
  239.     */
  240.    if (window->rline > window->file_info->length || window->ll->len == EOF
  241.              || !g_status.screen_display)
  242.       return;
  243.  
  244.    file = window->file_info;
  245.    max_col = window->end_col + 1 - window->start_col;
  246.    line = window->cline;
  247.    normal = window->ll->dirty == FALSE ? g_display.text_color : g_display.dirty_color;
  248.    block = g_display.block_color;
  249.    show_eol = mode.show_eol;
  250.  
  251.    /*
  252.     * figure which line to display.
  253.     * actually, we could be displaying any line in any file.  we display
  254.     *  the line_buffer only if window->ll == g_status.buff_node
  255.     *  and window->ll-line has been copied to g_status.line_buff.
  256.     */
  257.    text = window->ll->line;
  258.    len  = window->ll->len;
  259.    if (g_status.copied && ptoul( window->ll ) == ptoul( g_status.buff_node )) {
  260.       text = (text_ptr)g_status.line_buff;
  261.       len  = g_status.line_buff_len;
  262.    }
  263.    if (mode.inflate_tabs)
  264.       text = tabout( text, &len );
  265.  
  266.    /*
  267.     * lets look at the base column.  if the line to display is shorter
  268.     *  than the base column, then set text to eol and we can't see the
  269.     *  eol either.
  270.     */
  271.    bc = window->bcol;
  272.    if (bc > 0) {
  273.       if (text == NULL) {
  274.          show_eol = FALSE;
  275.          len = 0;
  276.       } else {
  277.          if ((col = len) < bc) {
  278.             bc = col;
  279.             show_eol = FALSE;
  280.          }
  281.          text += bc;
  282.          len  -= bc;
  283.       }
  284.    }
  285.  
  286.    /*
  287.     * for display purposes, set the line length to screen width if line
  288.     *  is longer than screen.  our assembly routine uses bytes and the
  289.     *  the line length can be longer than a byte.
  290.     */
  291.    if (len > max_col)
  292.       len = max_col;
  293.  
  294.    bcol = window->bcol;
  295.    rline = window->rline;
  296.    if (file->block_type && rline >= file->block_br && rline <= file->block_er)
  297.       block_line = TRUE;
  298.    else
  299.       block_line = FALSE;
  300.  
  301.    /*
  302.     * do this if 1) a box block is marked, or 2) a stream block begins
  303.     *  and ends on the same line.
  304.     */
  305.    if (block_line == TRUE && (file->block_type == BOX ||
  306.          (file->block_type == STREAM &&
  307.          rline == file->block_br && rline == file->block_er))) {
  308.  
  309.       /*
  310.        * start with the bc and ec equal to physical block marker.
  311.        */
  312.       bc = file->block_bc;
  313.       ec = file->block_ec;
  314.       if (ec < bcol || bc >= bcol + max_col)
  315.          /*
  316.           * we can't see block if ending column is less than the base col or
  317.           *  the beginning column is greater than max_col.
  318.           */
  319.          ec = bc = max_col + 1;
  320.       else if (ec < bcol + max_col) {
  321.          /*
  322.           * if the ec is less than the max column, make ec relative to
  323.           *  base column then figure the bc.
  324.           */
  325.          ec = ec - bcol;
  326.          if (bc < bcol)
  327.             bc = 0;
  328.          else
  329.             bc = bc - bcol;
  330.       } else if (bc < bcol + max_col) {
  331.          /*
  332.           * if the bc is less than the max column, make bc relative to
  333.           *  base column then figure the ec.
  334.           */
  335.          bc = bc - bcol;
  336.          if (ec > bcol + max_col)
  337.             ec = max_col;
  338.          else
  339.             ec = ec - bcol;
  340.       } else if (bc < bcol  &&  ec >= bcol + max_col) {
  341.          /*
  342.           * if the block is wider than the screen, make bc start at the
  343.           *  logical begin and make ec end at the logical end of the
  344.           *  window.
  345.           */
  346.          bc = 0;
  347.          ec = max_col;
  348.       }
  349.       bcol = window->start_col;
  350.       for (col=0; col < max_col; col++, bcol++) {
  351.          attr = normal;
  352.          if (col >= bc && col <= ec)
  353.             attr = block;
  354.          if (col < len)
  355.             c = *text++;
  356.          else if (col == len && show_eol)
  357.             c = EOL_CHAR;
  358.          else
  359.             c = ' ';
  360.          if (c < 32)
  361.             mvaddch( line, bcol, (c+64) | tde_color_table[g_display.curl_color] );
  362.          else if (c >= 127)
  363.             mvaddch( line, bcol, '.' | tde_color_table[g_display.curl_color] );
  364.          else
  365.             mvaddch( line, bcol, c | tde_color_table[attr] );
  366.       }
  367.    } else if (block_line == TRUE && file->block_type == STREAM &&
  368.               (rline == file->block_br || rline == file->block_er)) {
  369.       if (rline == file->block_br)
  370.          bc = file->block_bc;
  371.       else {
  372.          bc = file->block_ec + 1;
  373.          ec = normal;
  374.          normal = block;
  375.          block = ec;
  376.       }
  377.  
  378.       ec = max_col + 1;
  379.       if (bc < bcol)
  380.          bc = 0;
  381.       else if (bc < bcol + max_col)
  382.          bc = bc - bcol;
  383.       else
  384.          bc = max_col + 1;
  385.       bcol = window->start_col;
  386.  
  387.       for (col=0; col < max_col; col++, bcol++) {
  388.          attr = normal;
  389.          if (col >= bc && col <= ec)
  390.             attr = block;
  391.          if (col < len)
  392.             c = *text++;
  393.          else if (col == len && show_eol)
  394.             c = EOL_CHAR;
  395.          else
  396.             c = ' ';
  397.          if (c < 32)
  398.             mvaddch( line, bcol, (c+64) | tde_color_table[g_display.curl_color] );
  399.          else if (c >= 127)
  400.             mvaddch( line, bcol, '.' | tde_color_table[g_display.curl_color] );
  401.          else
  402.             mvaddch( line, bcol, c | tde_color_table[attr] );
  403.       }
  404.    } else {
  405.       if (block_line)
  406.          attr = block;
  407.       else
  408.          attr = normal;
  409.  
  410.       assert( len >= 0 );
  411.       assert( len <= g_display.ncols );
  412.  
  413.       curses_attribute = tde_color_table[attr];
  414.       bcol = window->start_col;
  415.       for (col=0; col < max_col; col++, bcol++) {
  416.          if (col < len)
  417.             c = *text++;
  418.          else if (col == len && show_eol)
  419.             c = EOL_CHAR;
  420.          else
  421.             c = ' ';
  422.          if (c < 32)
  423.             mvaddch( line, bcol, (c+64) | tde_color_table[g_display.curl_color] );
  424.          else if (c >= 127)
  425.             mvaddch( line, bcol, '.' | tde_color_table[g_display.curl_color] );
  426.          else
  427.             mvaddch( line, bcol, c | curses_attribute );
  428.       }
  429.    }
  430. }
  431.  
  432.  
  433. /*
  434.  * Name:    c_output
  435.  * Purpose: Output one character on prompt lines
  436.  * Date:    November 13, 1993
  437.  * Passed:  c:     character to output to screen
  438.  *          col:   col to display character
  439.  *          line:  line number to display character
  440.  *          attr:  attribute of character
  441.  * Returns: none
  442.  */
  443. void c_output( int c, int col, int line, int attr )
  444. {
  445. register unsigned int uc;
  446.  
  447.    uc = c;
  448.  
  449.    if (uc < 32)
  450.       mvaddch( line, col, (uc+64) | tde_color_table[g_display.curl_color] );
  451.    else if (uc >= 127)
  452.       mvaddch( line, col, '.' | tde_color_table[g_display.curl_color] );
  453.    else
  454.       mvaddch( line, col, uc | tde_color_table[attr] );
  455. }
  456.  
  457.  
  458. /*
  459.  * Name:    s_output
  460.  * Purpose: To output a string
  461.  * Date:    November 13, 1993
  462.  * Passed:  s:     string to output
  463.  *          line:  line to display
  464.  *          col:   column to begin display
  465.  *          attr:  color to display string
  466.  * Notes:   This function is used to output most strings not part of file text.
  467.  */
  468. void s_output( char *s, int line, int col, int attr )
  469. {
  470. int max;
  471. register unsigned int uc;
  472.  
  473.    max = g_display.ncols;
  474.    if (line == g_display.mode_line  &&  (strlen( s ) + col >= g_display.ncols))
  475.       max--;
  476.  
  477.    while ((uc = (unsigned int)*s)  &&  col < max) {
  478.       if (uc < 32)
  479.          mvaddch( line, col, (uc + 64) | tde_color_table[g_display.curl_color] );
  480.       else if (uc >= 127)
  481.          mvaddch( line, col, '.' | tde_color_table[g_display.curl_color] );
  482.       else
  483.          mvaddch( line, col, uc | tde_color_table[attr] );
  484.       col++;
  485.       s++;
  486.    }
  487. }
  488.  
  489.  
  490. /*
  491.  * Name:    eol_clear
  492.  * Purpose: To clear the line from col to max columns
  493.  * Date:    November 13, 1993
  494.  * Passed:  col:   column to begin clear
  495.  *          line:  line to clear
  496.  *          attr:  color to clear
  497.  * Notes:   use unix curses clrtoeol( ) to clear the line.
  498.  */
  499. void eol_clear( int col, int line, int attr )
  500. {
  501.    move( line, col );
  502.    clrtoeol( );
  503. }
  504.  
  505.  
  506. /*
  507.  * Name:    window_eol_clear
  508.  * Purpose: To clear the line from start_col to end_col
  509.  * Date:    November 13, 1993
  510.  * Passed:  window:  pointer to window
  511.  *          attr:  color to clear
  512.  * Notes:   don't use unix curses clrtoeol, because we could be in a
  513.  *            vertical window.  lines don't always extend to end of screen
  514.  *            in a vertical window.
  515.  */
  516. void window_eol_clear( TDE_WIN *window, int attr )
  517. {
  518. int max_col;
  519. chtype c;       /* chtype is defined in curses.h */
  520.  
  521.    if (!g_status.screen_display)
  522.       return;
  523.  
  524.    assert( attr >= 0 && attr < 128 );
  525.  
  526.    c = ' ' | tde_color_table[attr];
  527.    max_col = window->start_col;
  528.    while (max_col <= window->end_col)
  529.       mvaddch( window->cline, max_col++, c );
  530. }
  531.  
  532.  
  533. /*
  534.  * Name:    hlight_line
  535.  * Date:    November 13, 1993
  536.  * Passed:  x:     column to begin hi lite
  537.  *          y:     line to begin hi lite
  538.  *          lgth:  number of characters to hi lite
  539.  *          attr:  attribute color
  540.  */
  541. void hlight_line( int x, int y, int lgth, int attr )
  542. {
  543. int max;
  544.  
  545.    max = g_display.ncols;
  546.    if (y == g_display.mode_line)
  547.       max--;
  548.  
  549.    for (; lgth > 0 && x < max; x++, lgth--) {
  550.       move( y, x );
  551.       addch( (inch( ) & A_CHARTEXT) | tde_color_table[attr] );
  552.    }
  553. }
  554.  
  555.  
  556. /*
  557.  * Name:    cls
  558.  * Purpose: clear screen
  559.  * Date:    November 13, 1993
  560.  * Notes:   Call the curses clear screen function.
  561.  */
  562. void cls( void )
  563. {
  564.    clear( );
  565.    refresh( );
  566. }
  567.  
  568.  
  569. /*
  570.  * Name:    set_cursor_size
  571.  * Purpose: To set cursor size according to insert mode.
  572.  * Date:    November 13, 1993
  573.  * Passed:  csize:  not used in unix curses
  574.  * Notes:   use the global display structures to set the cursor size
  575.  *          curs_set( ) is a curses function.
  576.  */
  577. void set_cursor_size( int csize )
  578. {
  579. /*
  580.    if (mode.insert == TRUE) {
  581.       if (g_display.insert_cursor == SMALL_INS)
  582.          curs_set( CURSES_SMALL );
  583.       else
  584.          curs_set( CURSES_LARGE );
  585.    } else {
  586.       if (g_display.insert_cursor == SMALL_INS)
  587.          curs_set( CURSES_LARGE );
  588.       else
  589.          curs_set( CURSES_SMALL );
  590.    }
  591. */
  592.    curs_set( CURSES_SMALL );
  593.    g_display.curses_cursor = CURSES_SMALL;
  594. }
  595.  
  596.  
  597. /*
  598.  * Name:    set_overscan_color
  599.  * Purpose: To set overscan color
  600.  * Date:    November 13, 1993
  601.  * Passed:  color:  overscan color
  602.  * Notes:   i'm not sure how to set the overscan in Linux (yet?).
  603.  */
  604. void set_overscan_color( int color )
  605. {
  606. }
  607.  
  608.  
  609. /*
  610.  * Name:    save_screen_line
  611.  * Purpose: To save the characters and attributes of a line on screen.
  612.  * Date:    November 13, 1993
  613.  * Passed:  col:    desired column, usually always zero
  614.  *          line:   line on screen to save (0 up to max)
  615.  *          screen_buffer:  buffer for screen contents, must be >= 80 chtype
  616.  * Notes:   Save the contents of the line on screen where prompt is
  617.  *           to be displayed.
  618.  */
  619. void save_screen_line( int col, int line, chtype *screen_buffer )
  620. {
  621. int i;
  622.  
  623.    for (i=0; col < g_display.ncols; col++, i++)
  624.       screen_buffer[i] = mvinch( line, col );
  625. }
  626.  
  627.  
  628. /*
  629.  * Name:    restore_screen_line
  630.  * Purpose: To restore the characters and attributes of a line on screen.
  631.  * Date:    November 13, 1993
  632.  * Passed:  col:    usually always zero
  633.  *          line:   line to restore (0 up to max)
  634.  *          screen_buffer:  buffer for screen contents, must be >= 80 chtype
  635.  * Notes:   Restore the contents of the line on screen where the prompt
  636.  *           was displayed
  637.  */
  638. void restore_screen_line( int col, int line, chtype *screen_buffer )
  639. {
  640. int i;
  641.  
  642.    for (i=0; col < g_display.ncols; col++, i++)
  643.       mvaddch( line, col, screen_buffer[i] );
  644. }
  645.  
  646.  
  647.  
  648. /*
  649.  * Name:    save_minor_area
  650.  * Purpose: save text and attribute under the pulled menu
  651.  * Date:    November 13, 1993
  652.  * Passed:  buffer: storage for text and attribute
  653.  *          wid: width of the pulled menu
  654.  *          len: length of pulled menu
  655.  *          row: starting row of pulled menu
  656.  *          col: starting column of pulled menu
  657.  * Notes:   use curses to get char and attr
  658.  */
  659. void save_minor_area( chtype *buffer, int wid, int len, int row, int col )
  660. {
  661. int i;
  662. int j;
  663.  
  664.    wid--;
  665.    len--;
  666.    for (i=0; len >= 0; len--) {
  667.       for (j=wid; j >= 0; j--, i++)
  668.          buffer[i] = mvinch( row+len, col+j );
  669.    }
  670. }
  671.  
  672.  
  673. /*
  674.  * Name:    retore_minor_area
  675.  * Purpose: restore text and attribute under the pulled menu
  676.  * Date:    November 13, 1993
  677.  * Passed:  buffer: storage for text and attribute
  678.  *          wid: width of the pulled menu
  679.  *          len: length of pulled menu
  680.  *          row: starting row of pulled menu
  681.  *          col: starting column of pulled menu
  682.  * Notes:   use curses to set char and attr
  683.  */
  684. void restore_minor_area( chtype *buffer, int wid, int len, int row, int col )
  685. {
  686. int i;
  687. int j;
  688.  
  689.    wid--;
  690.    len--;
  691.    for (i=0; len >= 0; len--) {
  692.       for (j=wid; j >= 0; j--, i++)
  693.          mvaddch( row+len, col+j, buffer[i] );
  694.    }
  695. }
  696.  
  697.  
  698. #else
  699. /*
  700.  **********************************************************************
  701.  ******************************  PART 2  ******************************
  702.  **********************************************************************
  703.  *
  704.  * Calls to BIOS and writes to PC hardware.
  705.  */
  706.  
  707. #include <bios.h>               /* for direct BIOS keyboard input */
  708.  
  709.  
  710. /*
  711.  *   BIOS Data Areas
  712.  *
  713.  *   See:
  714.  *
  715.  *      IBM Corp., _Technical Reference:  Personal Computer AT_,
  716.  *      Boca Raton, Florida, 1984, IBM part no. 1502494,
  717.  *      pp 5-29 thru 5-32.
  718.  *
  719.  *  These addresses, variable names, types, and descriptions are directly
  720.  *   from the IBM AT Technical Reference manual, BIOS listing, copyright IBM.
  721.  *
  722.  *   Address  Name           Type   Description
  723.  *   0x0449   CRT_MODE       Byte   Current CRT mode
  724.  *   0x044a   CRT_COLS       Word   Number columns on screen
  725.  *   0x044c   CRT_LEN        Word   length of regen buffer, video buffer, bytes
  726.  *   0x044e   CRT_START      Word   Starting address of regen buffer
  727.  *   0x0450   CURSOR_POSN    Word   cursor for each of up to 8 pages.
  728.  *   0x0460   CURSOR_MODE    Word   current cursor mode setting.
  729.  *   0x0462   ACTIVE_PAGE    Byte   Current page
  730.  *   0x0463   ADDR_6845      Word   base address for active display card
  731.  *   0x0465   CRT_MODE_SET   Byte   current mode of display card
  732.  *   0x0466   CRT_PALETTE    Byte   overscan color for CGA, EGA, and VGA.
  733.  *   0x0467   io_rom_init    Word   Pointer to optional i/o rom init routine
  734.  *   0x0469   io_rom_seg     Word   Pointer to io rom segment
  735.  *   0x046b   intr_flag      Byte   Flag to indicate an interrupt happened
  736.  *   0x046c   timer_low      Word   Low word of timer count
  737.  *   0x046e   timer_high     Word   High word of timer count
  738.  *   0x0470   timer_ofl      Byte   Timer has rolled over since last count
  739.  *   0x0471   bios_break     Byte   Bit 7 = 1 if Break Key has been hit
  740.  *   0x0472   reset_flag     Word   Word = 1234h if keyboard reset underway
  741.  *   0x0484   ROWS           Byte   Number of displayed character rows - 1
  742.  *   0x0485   POINTS         Word   Height of character matrix
  743.  *   0x0487   INFO           Byte   EGA and VGA display data
  744.  *   0x0488   INFO_3         Byte   Configuration switches for EGA and VGA
  745.  *   0x0489   flags          Byte   Miscellaneous flags
  746.  *   0x0496   kb_flag_3      Byte   Additional keyboard flag
  747.  *   0x048A   DCC            Byte   Display Combination Code
  748.  *   0x04A8   SAVE_PTR       Dword  Pointer to BIOS save area
  749.  */
  750. void video_config( struct vcfg *cfg )
  751. {
  752. #pragma pack( 1 )    /* Use pragma to force packing on byte boundaries. */
  753.  
  754. struct LOWMEMVID
  755. {
  756.    char     vidmode;           /* 0x449 */
  757.    unsigned scrwid;            /* 0x44A */
  758.    unsigned scrlen;            /* 0x44C */
  759.    unsigned scroff;            /* 0x44E */
  760.    struct   LOCATE
  761.    {
  762.       unsigned char col;
  763.       unsigned char row;
  764.    } csrpos[8];                /* 0x450 */
  765.    struct   CURSIZE
  766.    {
  767.       unsigned char end;
  768.       unsigned char start;
  769.    } csrsize;                  /* 0x460 */
  770.    char      page;             /* 0x462 */
  771.    unsigned  addr_6845;        /* 0x463 */
  772.    char      crt_mode_set;     /* 0x465 */
  773.    char      crt_palette;      /* 0x466 */
  774.    char      system_stuff[29]; /* 0x467 */
  775.    char      rows;             /* 0x484 */
  776.    unsigned  points;           /* 0x485 */
  777.    char      ega_info;         /* 0x487 */
  778.    char      info_3;           /* 0x488 */
  779.    char      skip[13];         /* 0x489 */
  780.    char      kb_flag_3;        /* 0x496 */
  781. } vid;
  782. struct LOWMEMVID _far *pvid = &vid;
  783. #pragma pack( )    /* revert to previously defined pack pragma. */
  784.  
  785. union REGS in, out;
  786. unsigned char temp, active_display;
  787.  
  788.    /*
  789.     * Move system information into our video structure.
  790.     */
  791.    my_memmove( pvid, (void FAR *)0x00000449l, sizeof( vid ) );
  792.  
  793.    cfg->rescan = FALSE;
  794.    in.x.ax =  0x1a00;
  795.    int86( VIDEO_INT, &in, &out );
  796.    temp = out.h.al;
  797.    active_display = out.h.bl;
  798.    if (temp == 0x1a && (active_display == 7 || active_display == 8))
  799.       g_display.adapter = VGA;
  800.    else {
  801.       in.h.ah =  0x12;
  802.       in.h.bl =  0x10;
  803.       int86( VIDEO_INT, &in, &out );
  804.       if (out.h.bl != 0x10) {         /* EGA */
  805.          if (vid.ega_info & 0x08)
  806.             g_display.adapter = vid.addr_6845 == 0x3d4 ? CGA : MDA;
  807.          else
  808.             g_display.adapter = EGA;
  809.       } else if (vid.addr_6845 == 0x3d4)
  810.          g_display.adapter = CGA;
  811.       else
  812.          g_display.adapter = MDA;
  813.    }
  814.  
  815.    if (g_display.adapter == CGA || g_display.adapter == EGA) {
  816.       if (g_display.adapter == CGA)
  817.          cfg->rescan = TRUE;
  818.       g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0607 : 0x0407;
  819.       g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x0407 : 0x0607;
  820.    } else {
  821.       g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0b0c : 0x070b;
  822.       g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x070b : 0x0b0c;
  823.    }
  824.  
  825.    cfg->mode = vid.vidmode;
  826.    if (vid.addr_6845 == 0x3D4) {
  827.       cfg->color = TRUE;
  828.       cfg->videomem = (void FAR *)0xb8000000l;
  829.    } else {
  830.       cfg->color = FALSE;
  831.       cfg->videomem = (void FAR *)0xb0000000l;
  832.    }
  833.  
  834.    /*
  835.     * let save the overscan color
  836.     */
  837.    g_display.old_overscan = vid.crt_palette;
  838.  
  839.  
  840.    /*
  841.     * Get keyboard type.  Since there is no interrupt that determines
  842.     * keyboard type, use this method.  Look at bit 4 in keyboard flag3.
  843.     * This method is not always foolproof on clones.
  844.     */
  845.    if ((vid.kb_flag_3 & 0x10) != 0)
  846.       mode.enh_kbd = TRUE;
  847.    else
  848.       mode.enh_kbd = FALSE;
  849.    if (mode.enh_kbd == FALSE)
  850.       simulate_enh_kbd( 1 );
  851. }
  852.  
  853.  
  854. /*
  855.  * The next function was written by Tom Waters, twaters@relay.nswc.navy.mil, and
  856.  * modified extensively by Frank Davis.
  857.  *
  858.  * "I use ANSI.SYS to redefine a few of my function keys and this causes a
  859.  * problem when getch() is used in a program.  For example, instead of returning
  860.  * 321 for the F7, I get the redefined string inserted in the text. So, instead
  861.  * of using getch(), I use the following function ..."
  862.  *
  863.  * Tom, thanks for the info and solution.  I'm sure your function will be
  864.  * be appreciated by everyone with ANSI key defs, Frank.
  865.  */
  866.  
  867. /*
  868.  * Name:    getkey
  869.  * Purpose: use bios to get keyboard input (getch has trouble w/ ANSI
  870.  *          redefined keys)
  871.  * Date:    July 2, 1991
  872.  * Modified:July 12, 1991, Frank Davis - accept ALT-xxx keyboard entry
  873.  *          September 10, 1991, Frank Davis - add support for Ctrl+Up, etc...
  874.  * Passed:  None
  875.  * Notes:   Uses the BIOS to read the next keyboard character.  Service 0x00
  876.  *           is the XT keyboard read.  Service 0x10 is the extended keyboard
  877.  *           read.  Test for a bunch of special cases.  Allow the user to enter
  878.  *           any ASCII or Extended ASCII code as a normal text characters.
  879.  *
  880.  *          Control @ is defined as 0.  we need to do a special test
  881.  *           for this key, otherwise it's interpretted as an Alt key.  It's
  882.  *           the only "regular" Control key that returns 0 in AL and the scan
  883.  *           byte in AH.  The "regular" Control keys are those in the range
  884.  *           0-31 and they return the Control character in AL and the scan
  885.  *           code in AH.  All of the Alt + keys return 0 in AL and
  886.  *           the scan code in ah.
  887.  *
  888.  *          This function was written for US keyboards.  It may have to be
  889.  *           modified for other keyboards, eg. Belgium, Canada, Czech,
  890.  *           Slovak, Denmark, France, Germany, etc...
  891.  *
  892.  *          if Ctrl-Break is pressed, it returns 0xffff as the key pressed.
  893.  *           let's set it to CONTROL_BREAK == 269 and do nothing.
  894.  */
  895. int getkey( void )
  896. {
  897. unsigned key, num_lock, control, shift;
  898. register scan;
  899. register unsigned lo;
  900.  
  901. /*
  902.  * this code is used during testing to check the amount of memory
  903.  *    in the near heap.
  904.  *
  905.  * char temp[MAX_COLS+2];
  906.  *
  907.  * ultoa( _memavl( ), temp, 10 );
  908.  * s_output( "h=       ", g_display.mode_line, 37, g_display.mode_color );
  909.  * s_output( temp, g_display.mode_line, 39, g_display.mode_color );
  910.  */
  911.  
  912.    /*
  913.     * lets spin on waitkey until the user presses a key.  waitkey polls
  914.     *  the keyboard and returns 0 when a key is waiting.
  915.     */
  916.    while (waitkey( mode.enh_kbd ));
  917.  
  918.    /*
  919.     *  _bios_keybrd == int 16.  It returns the scan code in ah, hi part of key,
  920.     *   and the ascii key code in al, lo part of key.  If the character was
  921.     *   entered via ALT-xxx, the scan code, hi part of key, is 0.
  922.     */
  923.    if (mode.enh_kbd) {
  924.       key = _bios_keybrd( 0x10 );
  925.       lo  = _bios_keybrd( 0x12 );
  926.  
  927.       /*
  928.        * couple of special cases:
  929.        *   on the numeric keypad, some keys return 0xe0 in the lo byte.
  930.        *   1) if user enters Alt-224, then the hi byte == 0 and lo byte == 0xe0.
  931.        *   we need to let this get thru as an Extended ASCII char.  2) although
  932.        *   we could make the cursor pad keys do different functions than the
  933.        *   numeric pad cursor keys, let's set the 0xe0 in the lo byte to zero
  934.        *   and forget about support for those keys.
  935.        */
  936.       if ((key & 0x00ff) == 0x00e0 && (key & 0xff00) != 0)
  937.          key = key & 0xff00;
  938.    } else {
  939.       key = _bios_keybrd( 0 );
  940.       lo  = _bios_keybrd( 2 );
  941.    }
  942.    num_lock = lo & 0x20;
  943.    control  = lo & 0x04;
  944.    shift    = lo & 0x03;
  945.    scan = (key & 0xff00) >> 8;
  946.    lo = key & 0X00FF;
  947.  
  948.    if (lo == 0) {
  949.       /*
  950.        * special case for Control @, which is defined as 0 or NULL.
  951.        */
  952.       if (scan == 3)
  953.          lo = 430;
  954.  
  955.       /*
  956.        * when first byte is 0, map it above 256, so that we can
  957.        *  let ALT-xxx keys map to their 'natural' place.  In
  958.        *  otherwords, use 0-255 as normal text characters and
  959.        *  those >= 256 are function keys.
  960.        */
  961.       else
  962.          lo = scan | 0x100;
  963.  
  964.    /*
  965.     * now test for Control-Break.  let's set this to do nothing in the
  966.     *  editor.  manually map Control-Break to 269 - DO NOT assign
  967.     *  any function to 269.
  968.     */
  969.    } else if (key == 0xffff)
  970.       lo = CONTROL_BREAK;
  971.  
  972.  
  973.    /*
  974.     * Pressing Control+BackSpace generates the 0x7f character.  Instead of
  975.     * 0x7f, make lo the ASCII backspace character.  If anyone wants the
  976.     * 0x7f character, then they can enter it via ALT+xxx.
  977.     */
  978.    if (scan == 14 && lo == 0x7f)
  979.       lo = 8;
  980.  
  981.    /*
  982.     * At the bottom of page 195 in MASM 6.0 ref manual, "..when the keypad
  983.     *  ENTER and / keys are read through the BIOS interrupt 16h, only E0h
  984.     *  is seen since the interrupt only gives one-byte scan codes."
  985.     */
  986.    else if (scan == 0xe0) {
  987.       /*
  988.        * plain Grey Enter
  989.        */
  990.       if (lo == 13 && !shift)
  991.          lo = 285;
  992.       /*
  993.        * shift Grey Enter
  994.        */
  995.       else if (lo == 13)
  996.          lo = 298;
  997.       /*
  998.        * control Grey Enter
  999.        */
  1000.       else if (lo == 10)
  1001.          lo = 299;
  1002.    }
  1003.  
  1004.    /*
  1005.     *  let's massage all of the control key combinations.
  1006.     */
  1007.    if (lo < 32) {
  1008.  
  1009.       /*
  1010.        * My machine at home is sorta weird.  On every machine that I've
  1011.        *  tested at the awffice, the ALT-xxx combination returns 0 for the
  1012.        *  scan byte and xxx for the ASCII code.  My machine returns 184 (decimal)
  1013.        *  as the scan code?!?!?  I added the next two lines for my machine at
  1014.        *  home.  I wonder if someone forgot to zero out ah for Alt keypad entry
  1015.        *  when they wrote my bios?
  1016.        */
  1017.       if (scan > 0x80)
  1018.          scan = 0;
  1019.  
  1020.       /*
  1021.        * Separate the ESC key from the ^[ key.  The scan code for the ESC
  1022.        *  key is 1.  Map this to a different index into the key function
  1023.        *  array just in case someone wants to define ESC or ^[ to different
  1024.        *  functions.  BTW, ESC and ^[ return the same ASCII code, 27.
  1025.        */
  1026.       else if (scan == 1) {
  1027.          if (shift)
  1028.             lo = 259;
  1029.          else if (control)
  1030.             lo = 260;
  1031.          else
  1032.             lo = 258;
  1033.       }
  1034.  
  1035.       /*
  1036.        * Scan code for Enter = 28.  Separate the various Enter keys.
  1037.        */
  1038.       else if (scan == 28) {
  1039.          if (shift)
  1040.             lo = 263;
  1041.          else if (control)
  1042.             lo = 264;
  1043.          else
  1044.             lo = 262;
  1045.       }
  1046.  
  1047.       /*
  1048.        * Scan code for Backspace = 14.  Separate the various BackSpace keys.
  1049.        */
  1050.       else if (scan == 14) {
  1051.          if (shift)
  1052.             lo = 266;
  1053.          else if (control)
  1054.             lo = 267;
  1055.          else
  1056.             lo = 265;
  1057.       }
  1058.  
  1059.       /*
  1060.        * Scan code for Tab = 15.  Separate the tab key.
  1061.        */
  1062.       else if (scan == 15) {
  1063.          lo = 268;
  1064.       }
  1065.  
  1066.       /*
  1067.        * if scan code is not 0, then a Control key was pressed.  Map
  1068.        *  those keys to the WordStar commands.
  1069.        */
  1070.       else if (scan > 0)
  1071.          lo += 430;
  1072.  
  1073.    } else if (!num_lock) {
  1074.       switch (scan) {
  1075.          /*
  1076.           * scan code for grey - == 74.  if num_lock is not toggled, assign it
  1077.           *  to the scroll line up function.
  1078.           */
  1079.          case 74 :
  1080.             lo = 423;
  1081.             break;
  1082.  
  1083.          /*
  1084.           * scan code for grey + == 78.  if num_lock is not toggled, assign it
  1085.           *  to the scroll line down function.  if shift grey + then stationary
  1086.           *  scroll down.
  1087.           */
  1088.          case 78 :
  1089.             lo = 424;
  1090.             break;
  1091.       }
  1092.    }
  1093.  
  1094.  
  1095.    /*
  1096.     * let's set up for the Shift+Alt and Control+Alt keys.
  1097.     *  With these key combinations, we can do the International keyboard
  1098.     *  stuff, see the Microsoft MS DOS 5.0 manual pages 623-637.
  1099.     */
  1100.    if (lo > 256 && (shift || control)) {
  1101.  
  1102.       /*
  1103.        * add 55 to Ctrl+Left thru Ctrl+Home when the shift key is pressed.
  1104.        *  this is not part of the International keyboard stuff, just a way
  1105.        *  to assign the horizontal scroll left and right funcs to cursor keys.
  1106.        */
  1107.       if (shift) {
  1108.          if (lo >= 371 && lo <= 374)
  1109.             lo += 55;
  1110.  
  1111.          /*
  1112.           * if shift is down, map alt 1! thru alt =+ to shift alt 1! thru alt =+
  1113.           */
  1114.          else if (lo >= 376 && lo <= 387)
  1115.             lo += 86;
  1116.  
  1117.          /*
  1118.           * internation keyboard stuff
  1119.           */
  1120.          else if (lo >= 272 && lo <= 309)
  1121.             lo += 202;
  1122.       }
  1123.    }
  1124.  
  1125.    /*
  1126.     * map the enter key to line feed.
  1127.     */
  1128.    if (lo == 10  &&  scan != 0)
  1129.       lo = 425;
  1130.    return( lo );
  1131. }
  1132.  
  1133.  
  1134. /*
  1135.  * Name:    waitkey
  1136.  * Purpose: call the BIOS keyboard status subfunction
  1137.  * Date:    October 31, 1992
  1138.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  1139.  * Returns: 1 if no key ready, 0 if key is waiting
  1140.  * Notes:   lets get the keyboard status so we can spin on this function until
  1141.  *           the user presses a key.  some OS replacements for DOS want
  1142.  *           application programs to poll the keyboard instead of rudely
  1143.  *           sitting on the BIOS read key function.
  1144.  */
  1145. int  waitkey( int enh_keyboard )
  1146. {
  1147.    return( _bios_keybrd( enh_keyboard ? 0x11 : 0x01 ) == 0 ? 1 : 0 );
  1148. }
  1149.  
  1150.  
  1151. /*
  1152.  * Name:    flush_keyboard
  1153.  * Purpose: flush keys from the keyboard buffer
  1154.  * Date:    June 5, 1993
  1155.  * Passed:  enh_keyboard:  boolean - TRUE if 101 keyboard, FALSE otherwise
  1156.  * Returns: 1 if no key ready, 0 if key is waiting
  1157.  * Notes:   lets get the keyboard status so we can spin on this function until
  1158.  *           the user presses a key.  some OS replacements for DOS want
  1159.  *           application programs to poll the keyboard instead of rudely
  1160.  *           sitting on the BIOS read key function.
  1161.  */
  1162. void flush_keyboard( void )
  1163. {
  1164.    if (mode.enh_kbd) {
  1165.       while (!waitkey( mode.enh_kbd ))
  1166.          _bios_keybrd( 0x10 );
  1167.    } else {
  1168.       while (!waitkey( mode.enh_kbd ))
  1169.          _bios_keybrd( 0 );
  1170.    }
  1171. }
  1172.  
  1173.  
  1174. /*********************************************/
  1175. /*                                           */
  1176. /*  3) video output routines, PC specific    */
  1177. /*                                           */
  1178. /*********************************************/
  1179.  
  1180.  
  1181. /*
  1182.  * Name:    xygoto
  1183.  * Purpose: To move the cursor to the required column and line.
  1184.  * Date:    September 28, 1991
  1185.  * Passed:  col:    desired column (0 up to max)
  1186.  *          line:   desired line (0 up to max)
  1187.  * Notes;   use standard BIOS video interrupt 0x10 to set the set.
  1188.  */
  1189. void xygoto( int col, int line )
  1190. {
  1191. union REGS inregs, outregs;
  1192.  
  1193.    inregs.h.ah = 2;
  1194.    inregs.h.bh = 0;
  1195.    inregs.h.dh = (unsigned char)line;
  1196.    inregs.h.dl = (unsigned char)col;
  1197.    int86( 0x10, &inregs, &outregs );
  1198. }
  1199.  
  1200.  
  1201. /*
  1202.  * Name:    update_line
  1203.  * Purpose: Display the current line in window
  1204.  * Date:    June 5, 1991
  1205.  * Passed:  window:  pointer to current window
  1206.  * Notes:   Show string starting at column zero and if needed blank rest
  1207.  *           of line.  Put max_col in cx and count down.  When we run into
  1208.  *           len, cx contains number of columns to blank out.  Use the
  1209.  *           fast 'rep stosw' to clear the end of line.
  1210.  *          The C routine was probably fast enough, but let's do some
  1211.  *           assembly because it's so fun.
  1212.  *          To handle line lengths longer than 255 characters,
  1213.  *           block begin and end columns were changed from real
  1214.  *           to virtual columns in this display routine.
  1215.  */
  1216. void update_line( TDE_WIN *window )
  1217. {
  1218. text_ptr text;      /* current character of orig begin considered */
  1219. char FAR *screen_ptr;
  1220. int  off;
  1221. int  attr;
  1222. int  line;
  1223. int  col;
  1224. int  bcol;
  1225. int  bc;
  1226. int  ec;
  1227. int  normal;
  1228. int  block;
  1229. int  max_col;
  1230. int  block_line;
  1231. int  len;
  1232. int  show_eol;
  1233. int  c;
  1234. long rline;
  1235. file_infos *file;
  1236.  
  1237.    if (window->rline > window->file_info->length || window->ll->len == EOF
  1238.              || !g_status.screen_display)
  1239.       return;
  1240.    file = window->file_info;
  1241.    max_col = window->end_col + 1 - window->start_col;
  1242.    line = window->cline;
  1243.    normal = window->ll->dirty == FALSE ? g_display.text_color : g_display.dirty_color;
  1244.    block = g_display.block_color;
  1245.    show_eol = mode.show_eol;
  1246.  
  1247.    /*
  1248.     * set the screen pointer to physical screen memory.
  1249.     *       160 = 80 chars + 80 attr  for each line
  1250.     */
  1251.    screen_ptr = g_display.display_address;
  1252.    off = line * 160 + window->start_col * 2;
  1253.  
  1254.    /*
  1255.     * figure which line to display.
  1256.     * actually, we could be displaying any line in any file.  we display
  1257.     *  the line_buffer only if window->ll == g_status.buff_node
  1258.     *  and window->ll-line has been copied to g_status.line_buff.
  1259.     */
  1260.    text = window->ll->line;
  1261.    len  = window->ll->len;
  1262.    if (g_status.copied && ptoul( window->ll ) == ptoul( g_status.buff_node )) {
  1263.       text = (text_ptr)g_status.line_buff;
  1264.       len  = g_status.line_buff_len;
  1265.    }
  1266.    if (mode.inflate_tabs)
  1267.       text = tabout( text, &len );
  1268.  
  1269.    /*
  1270.     * lets look at the base column.  if the line to display is shorter
  1271.     *  than the base column, then set text to eol and we can't see the
  1272.     *  eol either.
  1273.     */
  1274.    bc = window->bcol;
  1275.    if (bc > 0) {
  1276.       if (text == NULL) {
  1277.          show_eol = FALSE;
  1278.          len = 0;
  1279.       } else {
  1280.          if ((col = len) < bc) {
  1281.             bc = col;
  1282.             show_eol = FALSE;
  1283.          }
  1284.          text += bc;
  1285.          len  -= bc;
  1286.       }
  1287.    }
  1288.  
  1289.    /*
  1290.     * for display purposes, set the line length to screen width if line
  1291.     *  is longer than screen.  our assembly routine uses bytes and the
  1292.     *  the line length can be longer than a byte.
  1293.     */
  1294.    if (len > max_col)
  1295.       len = max_col;
  1296.  
  1297.    bcol = window->bcol;
  1298.    rline = window->rline;
  1299.    if (file->block_type && rline >= file->block_br && rline <= file->block_er)
  1300.       block_line = TRUE;
  1301.    else
  1302.       block_line = FALSE;
  1303.  
  1304.    /*
  1305.     * do this if 1) a box block is marked, or 2) a stream block begins
  1306.     *  and ends on the same line.
  1307.     */
  1308.    if (block_line == TRUE && (file->block_type == BOX ||
  1309.          (file->block_type == STREAM &&
  1310.          rline == file->block_br && rline == file->block_er))) {
  1311.  
  1312.       /*
  1313.        * start with the bc and ec equal to physical block marker.
  1314.        */
  1315.       bc = file->block_bc;
  1316.       ec = file->block_ec;
  1317.       if (ec < bcol || bc >= bcol + max_col)
  1318.          /*
  1319.           * we can't see block if ending column is less than the base col or
  1320.           *  the beginning column is greater than max_col.
  1321.           */
  1322.          ec = bc = max_col + 1;
  1323.       else if (ec < bcol + max_col) {
  1324.          /*
  1325.           * if the ec is less than the max column, make ec relative to
  1326.           *  base column then figure the bc.
  1327.           */
  1328.          ec = ec - bcol;
  1329.          if (bc < bcol)
  1330.             bc = 0;
  1331.          else
  1332.             bc = bc - bcol;
  1333.       } else if (bc < bcol + max_col) {
  1334.          /*
  1335.           * if the bc is less than the max column, make bc relative to
  1336.           *  base column then figure the ec.
  1337.           */
  1338.          bc = bc - bcol;
  1339.          if (ec > bcol + max_col)
  1340.             ec = max_col;
  1341.          else
  1342.             ec = ec - bcol;
  1343.       } else if (bc < bcol  &&  ec >= bcol + max_col) {
  1344.          /*
  1345.           * if the block is wider than the screen, make bc start at the
  1346.           *  logical begin and make ec end at the logical end of the
  1347.           *  window.
  1348.           */
  1349.          bc = 0;
  1350.          ec = max_col;
  1351.       }
  1352.  
  1353.  
  1354.    ASSEMBLE {
  1355.         /*
  1356.         ; Register strategy:
  1357.         ;   bl == beginning column
  1358.         ;   bh == ending column
  1359.         ;   dl == normal text attribute
  1360.         ;   dh == block attribute
  1361.         ;   cl == current virtual column
  1362.         ;   ch == maximum columns in window
  1363.         ;   ES:DI == screen pointer (destination)
  1364.         ;   DS:SI == text pointer (source)
  1365.         ;   [bp+show_eol]  == access for local C variable
  1366.         */
  1367.  
  1368.  
  1369.         push    ds                      /* MUST save ds - push it on stack */
  1370.         push    si                      /* save si on stack */
  1371.         push    di                      /* save di on stack */
  1372.  
  1373. /*
  1374. ;
  1375. ; set up local register variables
  1376. ;
  1377. */
  1378.         mov     ax, WORD PTR bc         /* get beginning column */
  1379.         mov     bl, al                  /* keep it in bl */
  1380.         mov     ax, WORD PTR ec         /* get ending column */
  1381.         mov     bh, al                  /* keep it in bh */
  1382.         mov     ax, WORD PTR normal     /* get normal attribute */
  1383.         mov     dl, al                  /* keep it in dl */
  1384.         mov     ax, WORD PTR block      /* get block attribute */
  1385.         mov     dh, al                  /* keep it in dh */
  1386.         mov     ax, WORD PTR max_col    /* get max number columns on screen */
  1387.         mov     ch, al                  /* keep it in ch */
  1388.         xor     cl, cl                  /* col = 0, keep col in cl */
  1389. /*
  1390. ;
  1391. ; load screen and text pointer
  1392. ;
  1393. */
  1394.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1395.         add     di, WORD PTR off                /* add offset of line */
  1396.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1397.         mov     es, ax
  1398.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  1399.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  1400.         mov     ds, ax                  /* move segment of text in ds */
  1401.         cmp     si, 0                   /* is offset of text ptr == NULL? */
  1402.         jne     not_null                /* no, output string */
  1403.         cmp     ax, 0                   /* is segment of text ptr == NULL? */
  1404.         je      dspl_eol                /* yes, clear end of line */
  1405.    }
  1406. not_null:
  1407.  
  1408.    ASSEMBLE {
  1409.         cmp     cl, ch                  /* is col == max_col? */
  1410.         jge     getout                  /* yes, thru with line */
  1411.         cmp     cl, BYTE PTR len        /* is col == len? */
  1412.         je      dspl_eol                /* yes, must check block past eol */
  1413.    }
  1414. top:
  1415.  
  1416.    ASSEMBLE {
  1417.         lodsb                   /* get next char in string */
  1418.         mov     ah, dl          /* assume normal attribute */
  1419.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1420.         jl      ch_out1         /* yes, show char and normal attribute */
  1421.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  1422.         jg      ch_out1         /* yes, show char and normal attribute */
  1423.         mov     ah, dh          /* must be in a block - block attribute */
  1424.    }
  1425. ch_out1:
  1426.  
  1427.    ASSEMBLE {
  1428.         stosw                   /* now show char on screen w/ attribute */
  1429.         inc     cl              /* ++col */
  1430.         cmp     cl, ch          /* is col == max_col? */
  1431.         jge     getout          /* yes, thru with line */
  1432.         cmp     cl, BYTE PTR len        /* is col == len? */
  1433.         jl      top             /* yes, must check block past eol */
  1434.    }
  1435. dspl_eol:
  1436.  
  1437.    ASSEMBLE {
  1438.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1439.         je      block_eol       /* show_eol flag is FALSE, blank line */
  1440.         mov     al, EOL_CHAR    /* load some eol indicator */
  1441.         mov     ah, dl          /* assume normal attribute */
  1442.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1443.         jl      ch_out2         /* yes, show char and normal attribute */
  1444.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  1445.         jg      ch_out2         /* yes, show char and normal attribute */
  1446.         mov     ah, dh          /* must be in a block - show block attribute */
  1447.    }
  1448. ch_out2:
  1449.  
  1450.    ASSEMBLE {
  1451.         stosw                   /* write eol and attribute to screen */
  1452.         inc     cl              /* ++col */
  1453.         cmp     cl, ch          /* is col == max_col? */
  1454.         je      getout          /* yes, we're done */
  1455.    }
  1456. block_eol:
  1457.  
  1458.    ASSEMBLE {
  1459.         mov     al, ' '         /* clear rest of line w/ spaces */
  1460.    }
  1461. b1:
  1462.  
  1463.    ASSEMBLE {
  1464.         mov     ah, dl          /* assume normal attribute */
  1465.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1466.         jl      ch_out3         /* yes, show char and normal attribute */
  1467.         cmp     cl, bh          /* is col > ec? (greater than ending col) */
  1468.         jg      ch_out3         /* yes, show char and normal attribute */
  1469.         mov     ah, dh          /* must be in a block - show block attribute */
  1470.    }
  1471. ch_out3:
  1472.  
  1473.    ASSEMBLE {
  1474.         stosw                   /* write blank and attribute to screen */
  1475.         inc     cl              /* ++col */
  1476.         cmp     cl, ch          /* is col == max_col? */
  1477.         jl      b1              /* while less output block */
  1478.    }
  1479. getout:
  1480.  
  1481.    ASSEMBLE {
  1482.         pop     di
  1483.         pop     si
  1484.         pop     ds
  1485.       }
  1486.  
  1487. /*
  1488.       screen_ptr += off;
  1489.       bcol = window->start_col;
  1490.       for (col=0; col < max_col; col++, bcol++) {
  1491.          attr = normal;
  1492.          if (col >= bc && col <= ec)
  1493.             attr = block;
  1494.          if (col < len)
  1495.             c = *text++;
  1496.          else if (col == len && show_eol)
  1497.             c = EOL_CHAR;
  1498.          else
  1499.             c = ' ';
  1500.          *screen_ptr++ = c;
  1501.          *screen_ptr++ = attr;
  1502.  
  1503.          c_output( c, bcol, line, attr );
  1504.       }
  1505. */
  1506.    } else if (block_line == TRUE && file->block_type == STREAM &&
  1507.               (rline == file->block_br || rline == file->block_er)) {
  1508.       if (rline == file->block_br)
  1509.          bc = file->block_bc;
  1510.       else {
  1511.          bc = file->block_ec + 1;
  1512.          ec = normal;
  1513.          normal = block;
  1514.          block = ec;
  1515.       }
  1516.       if (bc < bcol)
  1517.          bc = 0;
  1518.       else if (bc < bcol + max_col)
  1519.          bc = bc - bcol;
  1520.       else
  1521.          bc = max_col + 1;
  1522.  
  1523.  
  1524.    ASSEMBLE {
  1525.         /*
  1526.         ; Register strategy:
  1527.         ;   bl == beginning column
  1528.         ;   bh == relative line length
  1529.         ;   dl == normal text attribute
  1530.         ;   dh == block attribute
  1531.         ;   cl == current virtual column
  1532.         ;   ch == maximum columns in window
  1533.         ;   ES:DI == screen pointer (destination)
  1534.         ;   DS:SI == text pointer (source)
  1535.         ;   [bp+show_eol]  == access for local C variable
  1536.         */
  1537.  
  1538.         push    ds                      /* MUST save ds - push it on stack */
  1539.         push    si                      /* save si on stack */
  1540.         push    di                      /* save di on stack */
  1541.  
  1542. /*
  1543. ;
  1544. ; set up local register variables
  1545. ;
  1546. */
  1547.         mov     ax, WORD PTR bc         /* get beginning column */
  1548.         mov     bl, al                  /* keep it in bl */
  1549.         mov     ax, WORD PTR len        /* get relative line length */
  1550.         mov     bh, al                  /* keep it in bh */
  1551.         mov     ax, WORD PTR normal     /* get normal attribute */
  1552.         mov     dl, al                  /* keep it in dl */
  1553.         mov     ax, WORD PTR block      /* get block attribute */
  1554.         mov     dh, al                  /* keep it in dh */
  1555.         mov     ax, WORD PTR max_col    /* get max number columns on screen */
  1556.         mov     ch, al                  /* keep it in ch */
  1557.         xor     cl, cl                  /* col = 0, keep col in cl */
  1558. /*
  1559. ;
  1560. ; load screen and text pointer
  1561. ;
  1562. */
  1563.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1564.         add     di, WORD PTR off                /* add offset of line */
  1565.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1566.         mov     es, ax
  1567.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  1568.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  1569.         mov     ds, ax                  /* move segment of text in ds */
  1570.         cmp     si, 0                   /* is offset of text ptr == NULL? */
  1571.         jne     nott_null               /* no, output string */
  1572.         cmp     ax, 0                   /* is segment of text ptr == NULL? */
  1573.         je      ddspl_eol               /* yes, clear end of line */
  1574.    }
  1575. nott_null:
  1576.  
  1577.    ASSEMBLE {
  1578.         cmp     cl, ch          /* is col == max_col? */
  1579.         je      ggetout         /* yes, thru with line */
  1580.         cmp     cl, bh          /* is col == len? */
  1581.         je      ddspl_eol       /* yes, check eol display */
  1582.    }
  1583. ttop:
  1584.  
  1585.    ASSEMBLE {
  1586.         lodsb                   /* get next char in string */
  1587.         mov     ah, dl          /* assume normal attribute */
  1588.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1589.         jl      str_out1        /* yes, show char and normal attribute */
  1590.         mov     ah, dh          /* must be in a block - show block attribute */
  1591.    }
  1592. str_out1:
  1593.  
  1594.    ASSEMBLE {
  1595.         stosw                   /* else show char on screen */
  1596.         inc     cl              /* ++col */
  1597.         cmp     cl, ch          /* is col == max_col? */
  1598.         je      ggetout         /* yes, thru with line */
  1599.         cmp     cl, bh          /* is col == len? */
  1600.         jl      ttop            /* yes, check eol display */
  1601.    }
  1602. ddspl_eol:
  1603.  
  1604.    ASSEMBLE {
  1605.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1606.         je      stream_eol      /* show_eol flag is FALSE, blank line */
  1607.         mov     al, EOL_CHAR    /* load some eol indicator */
  1608.         mov     ah, dl          /* assume normal attribute */
  1609.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1610.         jl      str_out2        /* yes, show char and normal attribute */
  1611.         mov     ah, dh          /* must be in a block - show block attribute */
  1612.    }
  1613. str_out2:
  1614.  
  1615.    ASSEMBLE {
  1616.         stosw                   /* write blank and attribute to screen */
  1617.         inc     cl              /* ++col */
  1618.         cmp     cl, ch          /* is col == max_col? */
  1619.         jge     ggetout         /* yes, we're done */
  1620.    }
  1621. stream_eol:
  1622.  
  1623.    ASSEMBLE {
  1624.         mov     al, ' '         /* clear rest of line w/ spaces */
  1625.    }
  1626. c1:
  1627.  
  1628.    ASSEMBLE {
  1629.         mov     ah, dl          /* assume normal attribute */
  1630.         cmp     cl, bl          /* is col < bc? (less than beginning col) */
  1631.         jl      str_out3        /* yes, show char and normal attribute */
  1632.         mov     ah, dh          /* must be in a block - show block attribute */
  1633.    }
  1634. str_out3:
  1635.  
  1636.    ASSEMBLE {
  1637.         stosw                   /* write blank and attribute to screen */
  1638.         inc     cl              /* ++col */
  1639.         cmp     cl, ch          /* is col == max_col? */
  1640.         jl      c1              /* while less output block */
  1641.    }
  1642. ggetout:
  1643.  
  1644.    ASSEMBLE {
  1645.         pop     di
  1646.         pop     si
  1647.         pop     ds
  1648.       }
  1649.  
  1650. /*
  1651.       screen_ptr += off;
  1652.       bcol = window->start_col;
  1653.       for (col=0; col < max_col; col++, bcol++) {
  1654.          attr = normal;
  1655.          if (col >= bc && col <= ec)
  1656.             attr = block;
  1657.          if (col < len)
  1658.             c = *text++;
  1659.          else if (col == len && show_eol)
  1660.             c = EOL_CHAR;
  1661.          else
  1662.             c = ' ';
  1663.          *screen_ptr++ = c;
  1664.          *screen_ptr++ = attr;
  1665.          c_output( c, bcol, line, attr );
  1666.       }
  1667. */
  1668.    } else {
  1669.       if (block_line)
  1670.          attr = block;
  1671.       else
  1672.          attr = normal;
  1673.  
  1674.       assert( len >= 0 );
  1675.       assert( len <= g_display.ncols );
  1676.  
  1677.    ASSEMBLE {
  1678.         /*
  1679.         ; Register strategy:
  1680.         ;   bl == normal text attribute
  1681.         ;   bh == relative line length
  1682.         ;   cl == current virtual column
  1683.         ;   ch == maximum columns in window
  1684.         ;   ES:DI == screen pointer (destination)
  1685.         ;   DS:SI == text pointer (source)
  1686.         ;   [bp+show_eol]  == access for local C variable
  1687.         */
  1688.  
  1689.         mov     dx, ds          /* MUST save ds - keep it in dx */
  1690.         push    di              /* save di on stack */
  1691.         push    si              /* save si on stack */
  1692.  
  1693.  
  1694.         mov     bx, WORD PTR attr               /* keep attribute in bl */
  1695.         mov     ax, WORD PTR len                /* get normalized len */
  1696.         mov     bh, al                          /* keep len in bh */
  1697.         mov     cx, WORD PTR max_col            /* get max_col in cx */
  1698.         mov     ch, cl                          /* keep it in ch */
  1699.         xor     cl, cl                          /* zero out cl */
  1700.         mov     di, WORD PTR screen_ptr         /* load OFFST of screen ptr */
  1701.         add     di, WORD PTR off                /* add offset of line */
  1702.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1703.         mov     es, ax
  1704.         mov     si, WORD PTR text       /* load OFFSET of text ptr */
  1705.         mov     ax, WORD PTR text+2     /* load SEGMENT of text ptr */
  1706.         mov     ds, ax                  /* move segment of text in ds */
  1707.         cmp     si, 0                   /* is offset of pointer == NULL? */
  1708.         jne     nnot_null               /* no, output string */
  1709.         cmp     ax, 0                   /* is segment of pointer == NULL? */
  1710.         je      normeol                 /* yes, then clear rest of line */
  1711.    }
  1712. nnot_null:
  1713.  
  1714.    ASSEMBLE {
  1715.         mov     ah, bl                  /* get attribute */
  1716.         cmp     cl, ch          /* compare count with max columns */
  1717.         jge     getoutt         /* yes, thru with line */
  1718.         cmp     cl, bh          /* compare count with len */
  1719.         je      normeol         /* yes, clear end of line */
  1720.    }
  1721. topp:
  1722.  
  1723.    ASSEMBLE {
  1724.         lodsb                   /* get next char in string */
  1725.         stosw                   /* else show char on screen */
  1726.         inc     cl              /* ++col, count up to max_column */
  1727.         cmp     cl, ch          /* compare count with max columns */
  1728.         jge     getoutt         /* yes, thru with line */
  1729.         cmp     cl, bh          /* compare count with len */
  1730.         jl      topp            /* yes, clear end of line */
  1731.    }
  1732. normeol:
  1733.  
  1734.    ASSEMBLE {
  1735.         cmp     WORD PTR show_eol, FALSE        /* look at the show_eol flag */
  1736.         je      clreol          /* show_eol flag is FALSE, blank line */
  1737.         mov     al, EOL_CHAR    /* load some eol indicator */
  1738.         mov     ah, bl          /* assume normal attribute */
  1739.         stosw                   /* write blank and attribute to screen */
  1740.         inc     cl              /* ++col */
  1741.         cmp     cl, ch          /* is col == max_col? */
  1742.         jge     getoutt         /* yes, we're done */
  1743.    }
  1744. clreol:
  1745.  
  1746.    ASSEMBLE {
  1747.         mov     ah, bl          /* get attribute */
  1748.         mov     al, ' '         /* clear eol with ' ' */
  1749.         sub     ch, cl          /* find number of columns left */
  1750.         mov     cl, ch          /* put number of column left in cl */
  1751.         xor     ch, ch          /* clear ch */
  1752.         rep     stosw           /* count is in cx - set rest of line to ' ' */
  1753.    }
  1754. getoutt:
  1755.  
  1756.    ASSEMBLE {
  1757.         pop     si
  1758.         pop     di
  1759.         mov     ds, dx
  1760.       }
  1761.  
  1762. /*
  1763.       screen_ptr += off;
  1764.       bcol = window->start_col;
  1765.       for (col=0; col < max_col; col++, bcol++) {
  1766.          if (col < len)
  1767.             c = *text++;
  1768.          else if (col == len && show_eol)
  1769.             c = EOL_CHAR;
  1770.          else
  1771.             c = ' ';
  1772.          *screen_ptr++ = c;
  1773.          *screen_ptr++ = attr;
  1774.          c_output( c, bcol, line, attr );
  1775.       }
  1776. */
  1777.    }
  1778. }
  1779.  
  1780.  
  1781. /*
  1782.  * Name:    c_output
  1783.  * Purpose: Output one character on prompt lines
  1784.  * Date:    June 5, 1991
  1785.  * Passed:  c:     character to output to screen
  1786.  *          col:   col to display character
  1787.  *          line:  line number to display character
  1788.  *          attr:  attribute of character
  1789.  * Returns: none
  1790.  */
  1791. void c_output( int c, int col, int line, int attr )
  1792. {
  1793. void FAR *screen_ptr;
  1794. int  off;
  1795.  
  1796.    screen_ptr = (void FAR *)g_display.display_address;
  1797.    off = line * 160 + col * 2;
  1798.  
  1799.    ASSEMBLE {
  1800.         mov     bx, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1801.         add     bx, WORD PTR off                /* add offset of line:col */
  1802.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1803.         mov     es, ax
  1804.         mov     cx, WORD PTR attr       /* get attribute */
  1805.         mov     ah, cl                  /* put in ah */
  1806.         mov     cx, WORD PTR c          /* get character */
  1807.         mov     al, cl                  /* put in al */
  1808.         mov     WORD PTR es:[bx], ax    /* show char on screen */
  1809.    }
  1810.  
  1811. /*
  1812.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  1813.    *screen_ptr++ = c;
  1814.    *screen_ptr = attr;
  1815. */
  1816. }
  1817.  
  1818.  
  1819. /*
  1820.  * Name:    s_output
  1821.  * Purpose: To output a string
  1822.  * Date:    June 5, 1991
  1823.  * Passed:  s:     string to output
  1824.  *          line:  line to display
  1825.  *          col:   column to begin display
  1826.  *          attr:  color to display string
  1827.  * Notes:   This function is used to output most strings not part of file text.
  1828.  */
  1829. void s_output( char FAR *s, int line, int col, int attr )
  1830. {
  1831. void FAR *screen_ptr;
  1832. int  off;
  1833. int  max_col;
  1834.  
  1835.    max_col = g_display.ncols;
  1836.    screen_ptr = (void FAR *)g_display.display_address;
  1837.    off = line * 160 + col * 2;
  1838.  
  1839.    ASSEMBLE {
  1840.         push    ds              /* save ds on stack */
  1841.         push    di              /* save di on stack */
  1842.         push    si              /* save si on stack */
  1843.  
  1844.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1845.         mov     cx, WORD PTR col                /* put cols in cx */
  1846.         mov     dx, WORD PTR max_col            /* keep max_col in dx */
  1847.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1848.         add     di, WORD PTR off                /* add offset of line:col */
  1849.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1850.         mov     es, ax
  1851.         mov     si, WORD PTR s  /* load offset of string ptr */
  1852.         or      si, si          /* is it == NULL? */
  1853.         je      getout          /* yes, no output needed */
  1854.         mov     ax, WORD PTR s+2        /* load segment of string ptr */
  1855.         or      ax, ax          /* is pointer == NULL? */
  1856.         je      getout          /* yes, no output needed */
  1857.         mov     ds, ax          /* load segment of text in ds */
  1858.         mov     ah, bl          /* put attribute in AH */
  1859.    }
  1860. top:
  1861.  
  1862.    ASSEMBLE {
  1863.         cmp     cx, dx          /* col < max_cols? */
  1864.         jge     getout          /* no, thru with line */
  1865.         lodsb                   /* get next char in string - put in al */
  1866.         or      al, al          /* is it '\0' */
  1867.         je      getout          /* yes, end of string */
  1868.         cmp     al, 0x0a        /* is it '\n'? */
  1869.         je      getout          /* yes, end of string */
  1870.         stosw                   /* else show attr + char on screen (ah + al) */
  1871.         inc     cx              /* col++ */
  1872.         jmp     SHORT top       /* get another character */
  1873.    }
  1874. getout:
  1875.  
  1876.    ASSEMBLE {
  1877.         pop     si              /* get back si */
  1878.         pop     di              /* get back di */
  1879.         pop     ds              /* get back ds */
  1880.    }
  1881.  
  1882. /*
  1883.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  1884.    max_col = g_display.ncols;
  1885.    while (*s && col < max) {
  1886.       *screen_ptr++ = *s++;
  1887.       *screen_ptr++ = attr;
  1888.    }
  1889. */
  1890. }
  1891.  
  1892.  
  1893. /*
  1894.  * Name:    eol_clear
  1895.  * Purpose: To clear the line from col to max columns
  1896.  * Date:    June 5, 1991
  1897.  * Passed:  col:   column to begin clear
  1898.  *          line:  line to clear
  1899.  *          attr:  color to clear
  1900.  * Notes:   Basic assembly
  1901.  */
  1902. void eol_clear( int col, int line, int attr )
  1903. {
  1904. int  max_col;
  1905. void FAR *screen_ptr;
  1906. int  off;
  1907.  
  1908.    max_col = g_display.ncols;
  1909.    screen_ptr = (void FAR *)g_display.display_address;
  1910.    off = line * 160 + col * 2;
  1911.  
  1912.    ASSEMBLE {
  1913.         push    di                              /* save di on stack */
  1914.  
  1915.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1916.         mov     dx, WORD PTR col                /* put cols in dx */
  1917.         mov     cx, WORD PTR max_col            /* put max_col in cx */
  1918.         cmp     dx, cx                          /* max_cols < cols? */
  1919.         jge     getout                          /* no, thru with line */
  1920.         sub     cx, dx                          /* number of column to clear */
  1921.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1922.         add     di, WORD PTR off                /* add offset of line:col */
  1923.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1924.         mov     es, ax
  1925.         mov     ah, bl                          /* get attribute in ah */
  1926.         mov     al, ' '                         /* store ' ' in al */
  1927.         rep     stosw                           /* clear to end of line */
  1928.    }
  1929. getout:
  1930.  
  1931.    ASSEMBLE {
  1932.         pop     di                              /* get back di from stack */
  1933.    }
  1934.  
  1935. /*
  1936.    for (; col < g_display.ncols; col++) {
  1937.       *p++ = ' ';
  1938.       *p++ = attr;
  1939.    }
  1940. */
  1941. }
  1942.  
  1943.  
  1944. /*
  1945.  * Name:    window_eol_clear
  1946.  * Purpose: To clear the line from start_col to end_col
  1947.  * Date:    June 5, 1991
  1948.  * Passed:  window:  pointer to window
  1949.  *          attr:  color to clear
  1950.  * Notes:   Basic assembly
  1951.  */
  1952. void window_eol_clear( TDE_WIN *window, int attr )
  1953. {
  1954. int  max_col;
  1955. void FAR *screen_ptr;
  1956. int  off;
  1957.  
  1958.    if (!g_status.screen_display)
  1959.       return;
  1960.    screen_ptr = (void FAR *)g_display.display_address;
  1961.    off = window->cline * 160 + window->start_col * 2;
  1962.    max_col = window->end_col + 1 - window->start_col;
  1963.  
  1964.    ASSEMBLE {
  1965.         push    di                              /* save di on stack */
  1966.  
  1967.         mov     bx, WORD PTR attr               /* keep attribute in bx */
  1968.         mov     cx, WORD PTR max_col            /* put max_col in cx */
  1969.         mov     di, WORD PTR screen_ptr         /* load OFFSET of screen ptr */
  1970.         add     di, WORD PTR off                /* add offset of line:col */
  1971.         mov     ax, WORD PTR screen_ptr+2       /* load SEGMENT of screen ptr */
  1972.         mov     es, ax
  1973.         mov     ah, bl                          /* get attribute in ah */
  1974.         mov     al, ' '                         /* store ' ' in al */
  1975.         rep     stosw                           /* clear to end of line */
  1976.  
  1977.         pop     di                              /* get back di from stack */
  1978.    }
  1979.  
  1980. /*
  1981.    for (max_col=window->start_col; max_col <= window->end_col; max_col++) {
  1982.       *screen_ptr++ = ' ';
  1983.       *screen_ptr++ = attr;
  1984.    }
  1985. */
  1986. }
  1987.  
  1988.  
  1989. /*
  1990.  * Name:    hlight_line
  1991.  * Date:    July 21, 1991
  1992.  * Passed:  x:     column to begin hi lite
  1993.  *          y:     line to begin hi lite
  1994.  *          lgth:  number of characters to hi lite
  1995.  *          attr:  attribute color
  1996.  * Notes:   The attribute byte is the hi byte.
  1997.  */
  1998. void hlight_line( int x, int y, int lgth, int attr )
  1999. {
  2000. int  off;
  2001. void FAR *screen_ptr;
  2002.  
  2003.    screen_ptr = (void FAR *)g_display.display_address;
  2004.    off = y * 160 + 2 * x + 1;  /* add one - so it points to attribute byte */
  2005.  
  2006.    ASSEMBLE {
  2007.         push    di              /* save di */
  2008.  
  2009.         mov     cx, lgth        /* number of characters to change color */
  2010.  
  2011.         mov     di, WORD PTR screen_ptr /* get destination - video memory */
  2012.         add     di, off                 /* add offset */
  2013.         mov     ax, WORD PTR screen_ptr+2
  2014.         mov     es, ax
  2015.         mov     ax, attr        /* attribute */
  2016.    }
  2017. lite_len:
  2018.  
  2019.    ASSEMBLE {
  2020.         stosb                   /* store a BYTE */
  2021.         inc     di              /* skip over character to next attribute */
  2022.         loop    lite_len        /* change next attribute */
  2023.         pop     di              /* restore di */
  2024.    }
  2025. }
  2026.  
  2027.  
  2028. /*
  2029.  * Name:    cls
  2030.  * Purpose: clear screen
  2031.  * Date:    June 5, 1991
  2032.  * Notes:   Call the video BIOS routine to clear the screen.
  2033.  */
  2034. void cls( void )
  2035. {
  2036. int  line;
  2037.  
  2038.      line = g_display.nlines + 1;
  2039.  
  2040.    ASSEMBLE {
  2041.         xor     ch, ch                  /* starting row in ch = 0 */
  2042.         xor     cl, cl                  /* starting column in cl = 0 */
  2043.         mov     ax, WORD PTR line       /* get ending row */
  2044.         mov     dh, al                  /* put it in dh */
  2045.         mov     dl, 79                  /* ending column in dl = 79 */
  2046.         mov     bh, 7                   /* attribute in bh  = 7 (normal) */
  2047.         mov     al, 0                   /* get number of lines */
  2048.         mov     ah, 6                   /* get function number */
  2049.         push    bp                      /* some BIOS versions wipe out bp */
  2050.         int     0x10
  2051.         pop     bp
  2052.    }
  2053. }
  2054.  
  2055.  
  2056. /*
  2057.  * Name:    set_cursor_size
  2058.  * Purpose: To set cursor size according to insert mode.
  2059.  * Date:    June 5, 1991
  2060.  * Passed:  csize:  desired cursor size
  2061.  * Notes:   use the global display structures to set the cursor size
  2062.  */
  2063. void set_cursor_size( int csize )
  2064. {
  2065.    ASSEMBLE {
  2066.         mov     ah, 1                   /* function 1 - set cursor size */
  2067.         mov     cx, WORD PTR csize      /* get cursor size ch:cl == top:bot */
  2068.         push    bp
  2069.         int     VIDEO_INT               /* video interrupt = 10h */
  2070.         pop     bp
  2071.    }
  2072. }
  2073.  
  2074.  
  2075. /*
  2076.  * Name:    set_overscan_color
  2077.  * Purpose: To set overscan color
  2078.  * Date:    April 1, 1993
  2079.  * Passed:  color:  overscan color
  2080.  * Notes:   before setting the overscan color, the old overscan color
  2081.  *           needs to be saved so it can be restored.
  2082.  */
  2083. void set_overscan_color( int color )
  2084. {
  2085.    ASSEMBLE {
  2086.         mov     ah, 0x0b                /* function 0x0b */
  2087.         mov     bl, BYTE PTR color      /* get new overscan color */
  2088.         xor     bh, bh
  2089.         push    bp
  2090.         int     VIDEO_INT               /* video interrupt = 10h */
  2091.         pop     bp
  2092.    }
  2093. }
  2094.  
  2095.  
  2096. /*
  2097.  * Name:    save_screen_line
  2098.  * Purpose: To save the characters and attributes of a line on screen.
  2099.  * Date:    June 5, 1991
  2100.  * Passed:  col:    desired column, usually always zero
  2101.  *          line:   line on screen to save (0 up to max)
  2102.  *          screen_buffer:  buffer for screen contents, must be >= 160 chars
  2103.  * Notes:   Save the contents of the line on screen where prompt is
  2104.  *           to be displayed
  2105.  */
  2106. void save_screen_line( int col, int line, char *screen_buffer )
  2107. {
  2108. char FAR *p;
  2109.  
  2110.    p = g_display.display_address + line * 160 + col * 2;
  2111.    _fmemcpy( screen_buffer, p, 160 );
  2112. }
  2113.  
  2114.  
  2115. /*
  2116.  * Name:    restore_screen_line
  2117.  * Purpose: To restore the characters and attributes of a line on screen.
  2118.  * Date:    June 5, 1991
  2119.  * Passed:  col:    usually always zero
  2120.  *          line:   line to restore (0 up to max)
  2121.  *          screen_buffer:  buffer for screen contents, must be >= 160 chars
  2122.  * Notes:   Restore the contents of the line on screen where the prompt
  2123.  *           was displayed
  2124.  */
  2125. void restore_screen_line( int col, int line, char *screen_buffer )
  2126. {
  2127. char FAR *p;
  2128.  
  2129.    p = g_display.display_address + line * 160 + col * 2;
  2130.    _fmemcpy( p, screen_buffer, 160 );
  2131. }
  2132.  
  2133.  
  2134. /*
  2135.  * Name:    save_minor_area
  2136.  * Purpose: save text and attribute under the pulled menu
  2137.  * Date:    November 13, 1993
  2138.  * Passed:  buffer: storage for text and attribute
  2139.  *          wid: width of the pulled menu
  2140.  *          len: length of pulled menu
  2141.  *          row: starting row of pulled menu
  2142.  *          col: starting column of pulled menu
  2143.  * Notes:   assume 80 column mode
  2144.  */
  2145. void save_minor_area( int *buffer, int wid, int len, int row, int col )
  2146. {
  2147. int off;
  2148. int FAR *pointer;
  2149. int i;
  2150. int j;
  2151.  
  2152.    wid--;
  2153.    off = row * 80 + col;
  2154.    pointer = (int FAR *)g_display.display_address + off;
  2155.    for (i=0; len > 0; len--) {
  2156.       for (j=wid; j >= 0; j--, i++)
  2157.          buffer[i] = pointer[j];
  2158.       pointer += 80;
  2159.    }
  2160. }
  2161.  
  2162.  
  2163. /*
  2164.  * Name:    retore_minor_area
  2165.  * Purpose: restore text and attribute under the pulled menu
  2166.  * Date:    November 13, 1993
  2167.  * Passed:  buffer: storage for text and attribute
  2168.  *          wid: width of the pulled menu
  2169.  *          len: length of pulled menu
  2170.  *          row: starting row of pulled menu
  2171.  *          col: starting column of pulled menu
  2172.  * Notes:   assume 80 column mode
  2173.  */
  2174. void restore_minor_area( int *buffer, int wid, int len, int row, int col )
  2175. {
  2176. int off;
  2177. int FAR *pointer;
  2178. int i;
  2179. int j;
  2180.  
  2181.    wid--;
  2182.    off = row * 80 + col;
  2183.    pointer = (int FAR *)g_display.display_address + off;
  2184.    for (i=0; len > 0; len--) {
  2185.       for (j=wid; j >= 0; j--, i++)
  2186.          pointer[j] = buffer[i];
  2187.       pointer += 80;
  2188.    }
  2189. }
  2190.  
  2191. #endif
  2192.  
  2193. /*
  2194.  **********************************************************************
  2195.  ******************************  PART 3  ******************************
  2196.  **********************************************************************
  2197.  *
  2198.  * System independent keyboard stuff.
  2199.  */
  2200.  
  2201.  
  2202. /*
  2203.  * Name:    getfunc
  2204.  * Purpose: get the function assigned to key c
  2205.  * Date:    July 11, 1991
  2206.  * Passed:  c:  key just pressed
  2207.  * Notes:   key codes less than 256 or 0x100 are not assigned a function.
  2208.  *           The codes in the range 0-255 are ASCII and extended ASCII chars.
  2209.  */
  2210. int  getfunc( int c )
  2211. {
  2212. register int i = c;
  2213. int  key_found;
  2214.  
  2215.    if (!g_status.key_pending) {
  2216.       i = c;
  2217.       if (i <= 256)
  2218.          i = 0;
  2219.       else
  2220.          i = key_func.key[i-256];
  2221.    } else {
  2222.  
  2223.       /*
  2224.        * allow the user to enter two-key combinations
  2225.        */
  2226.       key_found = FALSE;
  2227.       for (i=0; i < MAX_TWO_KEYS; i++) {
  2228.          if (g_status.first_key == two_key_list.key[i].parent_key &&
  2229.                                c == two_key_list.key[i].child_key) {
  2230.             i = two_key_list.key[i].func;
  2231.             key_found = TRUE;
  2232.             break;
  2233.          }
  2234.       }
  2235.       if (key_found == FALSE)
  2236.          i = ERROR;
  2237.    }
  2238.    return( i );
  2239. }
  2240.  
  2241.  
  2242. /*
  2243.  * Name:    two_key
  2244.  * Purpose: set the two_key flag and prompt for the next key.
  2245.  * Date:    April 1, 1992
  2246.  * Notes:   this function accepts two key commands.
  2247.  */
  2248. int  two_key( TDE_WIN *arg_filler )
  2249. {
  2250.    s_output( console1, g_display.mode_line, 67, g_display.diag_color );
  2251.    g_status.key_pending = TRUE;
  2252.    g_status.first_key = g_status.key_pressed;
  2253.    return( OK );
  2254. }
  2255.  
  2256.  
  2257. /*
  2258.  * Name:     getanswerkey
  2259.  * Purpose:  To get answer to questions etc.
  2260.  * Author:   Byrial Jensen
  2261.  * Date:     September 2, 1993
  2262.  * Modified: Frank Davis, November 13, 1993 (comments and bj_toupper())
  2263.  * Returns:  The pressed key, changed to uppercase if alfabetic
  2264.  * Notes:    If a key of a macro starting with:
  2265.  *             IfCapsLock character, or IfNotCapsLock character
  2266.  *           is presed, the character will be returned, changed to uppercase
  2267.  *           if a letter.
  2268.  */
  2269. int  getanswerkey( void )
  2270. {
  2271. int key;
  2272. int macrokey;
  2273. int macrofunc;
  2274. int macronext;
  2275.  
  2276.    /*
  2277.     * get a response from the user.  if ascii or extended ascii, return upper
  2278.     */
  2279.    key = getkey( );
  2280.    if (key <= 255)
  2281.       key = bj_toupper( key );
  2282.  
  2283.    /*
  2284.     * else if key is assigned a character via macro, return upper key
  2285.     */
  2286.    else if (getfunc( key ) == PlayBack) {
  2287.       macronext = macro.first_stroke[key - 256];
  2288.       macrokey = macro.strokes[macronext].key;
  2289.       macrofunc = getfunc( macrokey );
  2290.  
  2291.       /*
  2292.        * if this a letter, return upper.
  2293.        */
  2294.       if (macrofunc == IfCapsLock || macrofunc == IfNotCapsLock) {
  2295.          macronext = macro.strokes[macronext].next;
  2296.          if (macronext != -1) {
  2297.             macrokey = macro.strokes[macronext].key;
  2298.             if (macrokey <= 255)
  2299.                key = bj_toupper( macrokey );
  2300.          }
  2301.       }
  2302.    }
  2303.    return( key );
  2304. }
  2305.