home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / EDITOR / TDE120.ZIP / MAIN.C < prev    next >
Encoding:
Text File  |  1991-10-05  |  33.2 KB  |  1,064 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - hardware dependent module
  10.  * Purpose: This file contains all the code that needs to be different on
  11.  *           different hardware.
  12.  * File:    hwibm.c
  13.  * Author:  Douglas Thomson
  14.  * System:  This particular version is for the IBM PC and close compatibles.
  15.  *           It write directly to video RAM, so it is faster than other
  16.  *           techniques, but will cause "snow" on most CGA cards. See the
  17.  *           file "hwibmcga.c" for a version that avoids snow.
  18.  *          The compiler is Turbo C 2.0, using one of the large data memory
  19.  *           models.
  20.  * Date:    October 10, 1989
  21.  * Notes:   This module has been kept as small as possible, to facilitate
  22.  *           porting between different systems.
  23.  */
  24. /*********************  end of original comments   ********************/
  25.  
  26.  
  27. /*
  28.  * These routines were rewritten for Microsoft C.  They are pretty much system
  29.  * dependent and pretty much Microsoft C dependent.  I also renamed this file
  30.  * "main.c" - easier to find the main function.
  31.  *
  32.  * New editor name:  tde, the Thomson-Davis Editor.
  33.  * Author:           Frank Davis
  34.  * Date:             June 5, 1991
  35.  *
  36.  * This modification of Douglas Thomson's code is released into the
  37.  * public domain, Frank Davis.  You may distribute it freely.
  38.  */
  39.  
  40. char *greatest_composer_ever = "W. A. Mozart, 1756-1791";
  41.  
  42. #include "tdestr.h"     /* tde types */
  43. #include "common.h"
  44. #include "define.h"
  45. #include "default.h"
  46. #include "help.h"
  47. #include "tdefunc.h"
  48. #include <dos.h>        /* for renaming files */
  49. #ifdef __TURBOC__
  50.    #include <dir.h>        /* for searching the current path */
  51. #endif
  52. #include <bios.h>       /* for direct BIOS keyboard input */
  53. #if defined( __TURBOC__ )
  54.    #include <alloc.h>      /* for memory allocation */
  55. #elif defined( __MSC__ )
  56.    #include <malloc.h>      /* for memory allocation */
  57. #endif
  58. #include <io.h>         /* for file attribute code */
  59. #include <fcntl.h>      /* open flags */
  60. #if defined( __MSC__ )
  61.    #include <bios.h>
  62.    #include <errno.h>
  63.    #include <sys\types.h>   /* S_IWRITE etc */
  64. #endif
  65. #include <sys\stat.h>   /* S_IWRITE etc */
  66.  
  67. #if defined( __MSC__ )
  68. void (interrupt far *old_control_c)( void );  /* variable for old CNTL-C */
  69. #endif
  70.  
  71. int full_screen_buffer[2000];  /* 25 lines * 80 columns = 2000 characters */
  72.                                /* (make it an int for the attribute)      */
  73.  
  74.  
  75. /*
  76.  * Default color settings.  Incidentally, I'm color blind (mild red-green) and
  77.  * the default colors look fine to me.
  78.  */
  79. static int colors[2][8] = {
  80.    { HERC_REVERSE, HERC_NORMAL, HERC_REVERSE, HERC_REVERSE, HERC_HIGH,
  81.      HERC_NORMAL, HERC_NORMAL, HERC_HIGH },
  82.    { COLOR_HEAD, COLOR_TEXT, COLOR_MODE, COLOR_BLOCK, COLOR_MESSAGE,
  83.      COLOR_HELP, COLOR_DIAG, COLOR_EOF }
  84. };
  85.  
  86.  
  87. /*
  88.  * original control-break checking flag
  89.  */
  90. static int s_cbrk;
  91.  
  92. /*
  93.  * Name:    main
  94.  * Purpose: To do any system dependent command line argument processing,
  95.  *           and then call the main editor function.
  96.  * Date:    October 10, 1989
  97.  * Passed:  argc:   number of command line arguments
  98.  *          argv:   text of command line arguments
  99.  */
  100. void main( int argc, char *argv[] )
  101. {
  102. #if defined( __MSC__ )
  103.    union REGS inregs, outregs;
  104. #endif
  105.  
  106.    /*
  107.     * trap control-break to make it harmless, and turn checking off
  108.     */
  109. #if defined( __MSC__ )
  110.    inregs.h.ah = 0x33;
  111.    inregs.h.al = 0;
  112.    intdos( &inregs, &outregs );
  113.    s_cbrk = outregs.h.dl;
  114.    old_control_c = _dos_getvect( 0x23 );
  115.    _dos_setvect( 0x23, harmless );
  116.    inregs.h.ah = 0x33;
  117.    inregs.h.al = 1;
  118.    inregs.h.dl = 0;
  119.    intdos( &inregs, &outregs );
  120. #else
  121.    s_cbrk = getcbrk( );
  122.    ctrlbrk( harmless );
  123.    setcbrk( 0 );
  124. #endif
  125.  
  126.    initialize( );
  127.    editor( argc, argv );
  128.    terminate( );
  129. }
  130.  
  131.  
  132. /*
  133.  * Name:    error
  134.  * Purpose: To report an error, and usually make the user type <ESC> before
  135.  *           continuing.
  136.  * Date:    June 5, 1991
  137.  * Passed:  kind:   an indication of how serious the error was:
  138.  *                      WARNING: error, but editor can continue after <ESC>
  139.  *                      FATAL:   abort the editor!
  140.  *          line:    line to display message
  141.  *          message: string to be printed
  142.  * Notes:   Show dummy the message and ask for <ESC> if needed.
  143.  */
  144. void error( int kind, int line, char *message )
  145. {
  146. char buff[MAX_COLS+2];          /* somewhere to store error before printing */
  147. register int c;                 /* character entered by user to continue */
  148. int func;
  149. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  150.  
  151.    /*
  152.     * tell the user what kind of an error it is
  153.     */
  154.    switch (kind) {
  155.       case FATAL:
  156.          strcpy( buff, "Fatal error: " );
  157.          break;
  158.      case WARNING:
  159.          strcpy( buff, "Warning: " );
  160.          break;
  161.    }
  162.  
  163.    /*
  164.     * prepare the error message itself
  165.     */
  166.    strcat( buff, message );
  167.  
  168.    /*
  169.     * tell the user how to continue editing if necessary
  170.     */
  171.    if (kind == WARNING)
  172.       strcat( buff, ": type <ESC>" );
  173.  
  174.    /*
  175.     * output the error message
  176.     */
  177.    save_screen_line( 0, line, line_buff );
  178.    set_prompt( buff, line );
  179.  
  180.    if (kind == FATAL) {
  181.       /*
  182.        * no point in making the user type <ESC>, since the program is
  183.        *  about to abort anyway...
  184.        */
  185.       terminate( );
  186.       exit( 1 );
  187.    } else {
  188.       /*
  189.        * If necessary, force the user to acknowledge the error by
  190.        *  typing <ESC> (or ^U).
  191.        * This prevents any extra commands the user has entered from
  192.        *  causing problems after an error may have made them inappropriate.
  193.        */
  194.  
  195.       c = getkey( );
  196.       func = getfunc( c );
  197.  
  198.       while (func != AbortCommand && c != ESC) {
  199.          c = getkey( );
  200.          func = getfunc( c );
  201.       }
  202.    }
  203.    restore_screen_line( 0, line, line_buff );
  204.    s_output( "          ", g_display.mode_line, 63, g_display.mode_color );
  205. }
  206.  
  207.  
  208. /*
  209.  * Name:    harmless
  210.  * Purpose: To process control-break by ignoring it, so that the editor is
  211.  *           not aborted.
  212.  * Date:    June 5, 1991
  213.  */
  214. #if defined( __MSC__ )
  215. int interrupt far harmless( void )
  216. #else
  217. static int harmless(void)
  218. #endif
  219. {
  220.    return( 1 );   /* ignore */
  221. }
  222.  
  223.  
  224. /*
  225.  * Name:    terminate
  226.  * Purpose: To restore the terminal to a safe state prior to leaving the
  227.  *           editor.
  228.  * Date:    October 10, 1989
  229.  */
  230. void terminate( void )
  231. {
  232. #if defined( __MSC__ )
  233.    union REGS inregs, outregs;
  234. #endif
  235.  
  236.    /*
  237.     * restore control-break checking
  238.     */
  239. #if defined( __MSC__ )
  240.    _dos_setvect( 0x23, old_control_c );
  241.    inregs.h.ah = 0x33;
  242.    inregs.h.al = 1;
  243.    inregs.h.dl = s_cbrk;
  244.    intdos( &inregs, &outregs );
  245. #else
  246.    setcbrk( s_cbrk );
  247. #endif
  248.  
  249. #if defined( __MSC__ )
  250.    hfree( (void huge *)g_status.start_mem );
  251. #endif
  252.  
  253.    set_cursor_size( g_display.insert_cursor );
  254.    if (mode.enh_kbd == FALSE)
  255.       simulate_enh_kbd( 0 );
  256. }
  257.  
  258. /*
  259.  * Name:    hw_initialize
  260.  * Purpose: To initialize the display ready for editor use.
  261.  * Date:    June 5, 1991
  262.  */
  263. void hw_initialize( void )
  264. {
  265. #if defined( __MSC__ )
  266.    struct vcfg cfg;
  267. #else
  268.    struct text_info buff; /* for discovering display type */
  269. #endif
  270. unsigned paragraphs;
  271. long space;            /* amount of memory to use */
  272. register int *clr;
  273.  
  274.    /*
  275.     * set up screen size
  276.     */
  277.    g_display.ncols     = MAX_COLS;
  278.    g_display.nlines    = MAX_LINES - 1;
  279.    g_display.mode_line = MAX_LINES;
  280.    g_display.line_length = MAX_LINE_LENGTH;
  281.  
  282.    /*
  283.     * work out what kind of display is in use, and set attributes and
  284.     *  display address accordingly. Note that this will only work with
  285.     *  close IBM compatibles.
  286.     */
  287.  
  288.    video_config( &cfg );
  289.    g_display.display_address = (char far *)cfg.videomem;
  290.  
  291.    /*
  292.     * Use an integer pointer to go thru the color array for setting up the
  293.     * various color fields.
  294.     */
  295.    if (cfg.color == FALSE)
  296.       clr = &colors[0][0];
  297.    else
  298.       clr = &colors[1][0];
  299.  
  300.    g_display.head_color    = *clr++;
  301.    g_display.text_color    = *clr++;
  302.    g_display.mode_color    = *clr++;
  303.    g_display.block_color   = *clr++;
  304.    g_display.message_color = *clr++;
  305.    g_display.help_color    = *clr++;
  306.    g_display.diag_color    = *clr++;
  307.    g_display.eof_color     = *clr++;
  308.  
  309.    /*
  310.     * all the available memory for the text buffer
  311.     */
  312. #if defined( __MSC__ )
  313.    _dos_allocmem( 0xffff, ¶graphs );
  314.    /*
  315.     * A paragraph is 16 bytes.  Convert paragraphs to bytes by shifting left
  316.     * 4 bits.
  317.     */
  318.    space = (long)paragraphs << 4;
  319.  
  320.    /*
  321.     * if using Microsoft C, allocate all available memory.  If debugging in
  322.     * in QC 2.5, uncomment the next lines so the debugger will have some room.
  323.     */
  324. /*  if (space > 20000l)
  325.       space = 20000l;   */
  326.    if (space <= 0)
  327.       return;
  328. #else
  329.    space = farcoreleft() - 30000L;
  330. #endif
  331.  
  332. #if defined( __MSC__ )
  333.    if ((g_status.start_mem = (text_ptr)halloc( space, sizeof( char ))) == NULL)
  334.       error( FATAL, g_display.nlines, "out of memory???" );
  335. #else
  336.    if ((g_status.start_mem = farmalloc(space)) == NULL)
  337.       error( FATAL, g_display.nlines, "out of memory???" );
  338. #endif
  339.    g_status.max_mem = addltop( space, g_status.start_mem );
  340. }
  341.  
  342.  
  343. /*
  344.  *   Video BIOS Data Areas
  345.  *   The BIOS routines maintain several dynamic variables in an area of
  346.  *   memory called the Video Display Data Area.  The following contains a
  347.  *   summary of these variables' addresses, their symbolic names, and
  348.  *   their contents.  All addresses are relative to the 0x0000h segment.
  349.  *   From the IBM Technical Reference and other sources.
  350.  *
  351.  *   Address  Name           Type   Description
  352.  *   0x0449   CRT_MODE       Byte   Current BIOS video number
  353.  *   0x044a   CRT_COLS       Word   Number of displayed character columns
  354.  *   0x044c   CRT_LEN        Word   Size of video buffer in bytes
  355.  *   0x044e   CRT_START      Word   Offset of start of video buffer
  356.  *   0x0450   CURSOR_POSN    Word   Array of eight words containing the cursor
  357.  *                                    position for each of eight possible
  358.  *                                    video pages.  The high-order byte of
  359.  *                                    each word contains the character row,
  360.  *                                    the low-order byte the character column
  361.  *   0x0460   CURSOR_MODE    Word   Starting and ending lines for alphanumeric
  362.  *                                    cursor.  The high-order byte contains
  363.  *                                    the starting (top) line; the low-order
  364.  *                                    byte contains the ending (bottom) line
  365.  *   0x0462   ACTIVE_PAGE    Byte   Currently displayed video page number
  366.  *   0x0463   ADDR_6845      Word   I/O port address of CRT Controller's
  367.  *                                    Address register (3B4h for mono;
  368.  *                                    3D4h for color)
  369.  *   0x0465   CRT_MODE_SET   Byte   Current value for Mode Control register
  370.  *                                    (3B8h on MDA, 3D8h on CGA).  On the
  371.  *                                    EGA and VGA, the value emulates those
  372.  *                                    used on the MDA and CGA.
  373.  *   0x0466   CRT_PALETTE    Byte   Current value for the CGA Color Select
  374.  *                                    register (3D9h).  On the EGA and VGA,
  375.  *                                    the value emulates those used on the
  376.  *                                    MDA and CGA.
  377.  *   0x0467   io_rom_init    Word   Pointer to optional i/o rom init routine
  378.  *   0x0469   io_rom_seg     Word   Pointer to io rom segment
  379.  *   0x046b   intr_flag      Byte   Flag to indicate an interrupt happened
  380.  *   0x046c   timer_low      Word   Low word of timer count
  381.  *   0x046e   timer_high     Word   High word of timer count
  382.  *   0x0470   timer_ofl      Byte   Timer has rolled over since last count
  383.  *   0x0471   bios_break     Byte   Bit 7 = 1 if Break Key has been hit
  384.  *   0x0472   reset_flag     Word   Word = 1234h if keyboard reset underway
  385.  *   0x0484   ROWS           Byte   Number of displayed character rows - 1
  386.  *   0x0485   POINTS         Word   Height of character matrix
  387.  *   0x0487   INFO           Byte   EGA and VGA display data
  388.  *   0x0488   INFO_3         Byte   Configuration switches for EGA and VGA
  389.  *   0x0489   flags          Byte   Miscellaneous flags
  390.  *   0x0496   kb_flag_3      Byte   Additional keyboard flag
  391.  *   0x048A   DCC            Byte   Display Combination Code
  392.  *   0x04A8   SAVE_PTR       Dword  Pointer to BIOS save area
  393.  *
  394. */
  395. void video_config( struct vcfg *cfg )
  396. {
  397. #pragma pack( 1 )    /* Use pragma to force packing on byte boundaries. */
  398.  
  399. struct LOWMEMVID
  400. {
  401.    char     vidmode;           /* 0x449 */
  402.    unsigned scrwid;            /* 0x44A */
  403.    unsigned scrlen;            /* 0x44C */
  404.    unsigned scroff;            /* 0x44E */
  405.    struct   LOCATE
  406.    {
  407.       unsigned char col;
  408.       unsigned char row;
  409.    } csrpos[8];                /* 0x450 */
  410.    struct   CURSIZE
  411.    {
  412.       unsigned char end;
  413.       unsigned char start;
  414.    } csrsize;                  /* 0x460 */
  415.    char      page;             /* 0x462 */
  416.    unsigned  addr_6845;        /* 0x463 */
  417.    char      crt_mode_set;     /* 0x465 */
  418.    char      crt_palette[30];  /* 0x466 */
  419.    char      rows;             /* 0x484 */
  420.    unsigned  points;           /* 0x485 */
  421.    char      ega_info;         /* 0x487 */
  422.    char      info_3;           /* 0x488 */
  423.    char      skip[13];         /* 0x489 */
  424.    char      kb_flag_3;        /* 0x496 */
  425. } vid;
  426. struct LOWMEMVID _far *pvid = &vid;
  427. #pragma pack( )    /* revert to previously defined pack pragma. */
  428.  
  429. union REGS in, out;
  430. unsigned char temp, active_display;
  431.  
  432.    /* Move system information into uninitialized structure variable. */
  433.    movedata( 0, 0x449, FP_SEG( pvid ), FP_OFF( pvid ), sizeof( vid ) );
  434.  
  435.    cfg->rescan = FALSE;
  436.    in.x.ax =  0x1a00;
  437.    int86( VIDEO_INT, &in, &out );
  438.    temp = out.h.al;
  439.    active_display = out.h.bl;
  440.    if (temp == 0x1a && (active_display == 7 || active_display == 8))
  441.       g_display.adapter = VGA;
  442.    else {
  443.       in.h.ah =  0x12;
  444.       in.h.bl =  0x10;
  445.       int86( VIDEO_INT, &in, &out );
  446.       if (out.h.bl != 0x10) {         /* EGA */
  447.          if (vid.ega_info & 0x08) {
  448.             if (vid.addr_6845 == 0x3d4)
  449.                g_display.adapter = CGA;
  450.             else
  451.                g_display.adapter = MDA;
  452.          } else
  453.             g_display.adapter = EGA;
  454.       } else if (vid.addr_6845 == 0x3d4)
  455.          g_display.adapter = CGA;
  456.       else
  457.          g_display.adapter = MDA;
  458.    }
  459.  
  460.    if (g_display.adapter == CGA || g_display.adapter == EGA) {
  461.       if (g_display.adapter == CGA)
  462.          cfg->rescan = TRUE;
  463.       g_display.insert_cursor = 0x0607;
  464.       g_display.overw_cursor = 0x0407;
  465.    } else {
  466.       g_display.insert_cursor = 0x0b0c;
  467.       g_display.overw_cursor = 0x070b;
  468.    }
  469.  
  470.    cfg->mode = vid.vidmode;
  471.    if (vid.addr_6845 == 0x3D4) {
  472.       cfg->color = TRUE;
  473.       FP_SEG( cfg->videomem ) = 0xb800;
  474.    } else {
  475.       cfg->color = FALSE;
  476.       FP_SEG( cfg->videomem ) = 0xb000;
  477.    }
  478.    FP_OFF( cfg->videomem ) = 0x0000;
  479.  
  480.    /*
  481.     * Set up keyboard type.  Since there is no interrupt that determines
  482.     * keyboard type, use this method.  Look at bit 4 in keyboard flag3.
  483.     * This method is not always foolproof on clones.
  484.     */
  485.    if ((vid.kb_flag_3 & 0x10) != 0)
  486.       mode.enh_kbd = TRUE;
  487.    else
  488.       mode.enh_kbd = FALSE;
  489.    if (mode.enh_kbd == FALSE)
  490.       simulate_enh_kbd( 1 );
  491. }
  492.  
  493.  
  494. /*
  495.  * Name:    set_cursor_size
  496.  * Purpose: To set cursor size according to insert mode.
  497.  * Date:    June 5, 1991
  498.  * Passed:  csize:  desired cursor size
  499.  * Notes:   use the global display structures to set the cursor size
  500.  */
  501. void set_cursor_size( int csize )
  502. {
  503.    _asm {
  504.         mov     ah, 1                   ; function 1 - set cursor size
  505.         mov     cx, WORD PTR csize      ; get cursor size ch:cl == top:bot
  506.         int     VIDEO_INT               ; video interrupt = 10h
  507.    }
  508. }
  509.  
  510.  
  511. /*
  512.  * Name:    hw_move
  513.  * Purpose: To move data from one place to another as efficiently as
  514.  *           possible.
  515.  * Date:    October 10, 1989
  516.  * Passed:  dest:   where to copy to
  517.  *          source: where to copy from
  518.  *          number: number of bytes to copy
  519.  * Notes:   moves may be (usually will be) overlapped.  Although we can
  520.  *          move up to 64k-1 bytes at once, we can safely  move only
  521.  *          0xfff0 bytes at one time.  Let's try only 0xf000.
  522.  */
  523. void hw_move( text_ptr dest, text_ptr source, long number )
  524. {
  525. unsigned long s, d;
  526.  
  527.    s = ptoul( source );
  528.    d = ptoul( dest );
  529.    if (number < 0)
  530.       /*
  531.        * this should never happen...
  532.        */
  533.       error( WARNING, g_display.nlines, "negative move - contact Frank Davis" );
  534.    else if (s == d)
  535.       /*
  536.        * nothing to be done
  537.        */
  538.       ;
  539.    else if (s > d) {
  540.       while (number > 0xF000L) {
  541.          dest = nptop( dest );
  542.          source = nptop( source );
  543.          _fmemmove( dest, source, 0xF000 );
  544.          dest = addltop( 0xF000L, dest );
  545.          source = addltop( 0xF000L, source );
  546.          number -= 0xF000L;
  547.       }
  548.       dest = nptop( dest );
  549.       source = nptop( source );
  550.       _fmemmove( dest, source, (unsigned)number );
  551.    } else {
  552.       source = addltop( number, source );
  553.       dest = addltop( number, dest );
  554.       while (number > 0xF000L) {
  555.          source = addltop( -0xF000L, source );
  556.          source = nptop( source );
  557.          dest = addltop( -0xF000L, dest );
  558.          dest = nptop ( dest );
  559.          _fmemmove( dest, source, 0xF000 );
  560.          number -= 0xF000L;
  561.       }
  562.       source = addltop( -number, source );
  563.       dest = addltop( -number, dest );
  564.       source = nptop( source );
  565.       dest = nptop ( dest );
  566.       _fmemmove( dest, source, (unsigned)number );
  567.    }
  568. }
  569.  
  570. /*
  571.  * Name:    hw_fattrib
  572.  * Purpose: To determine the current file attributes.
  573.  * Date:    October 17, 1989
  574.  * Passed:  name: name of file to be checked
  575.  * Returns: current read/write/execute etc attributes of the file, or
  576.  *          ERROR if file did not exist etc.
  577.  */
  578. int hw_fattrib( char *name )
  579. {
  580. register int rc;
  581.  
  582. #if defined( __MSC__ )
  583.    rc = access( name, EXIST );
  584. #else
  585.    rc = _chmod( name, EXIST );
  586. #endif
  587.    return( rc );
  588. }
  589.  
  590. /*
  591.  * Name:    hw_unlink
  592.  * Purpose: To delete a file, regardless of access modes.
  593.  * Date:    October 17, 1989
  594.  * Passed:  name:  name of file to be removed
  595.  *          line:  line to display message
  596.  * Returns: OK if file could be removed
  597.  *          ERROR otherwise
  598.  */
  599. int  hw_unlink( char *name, int line )
  600. {
  601. int result;
  602. register int rc;
  603. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  604.  
  605.    rc = OK;
  606. #if defined( __MSC__ )
  607.    if ((result = access( name, EXIST )) != -1 && errno != EACCES) {
  608. #else
  609.    if ((result = _chmod( name, EXIST )) != -1 && (result & FA_RDONLY) != 0) {
  610. #endif
  611.       /*
  612.        * file cannot be written
  613.        */
  614.       save_screen_line( 0, line, line_buff );
  615.       set_prompt( "File is write protected! Overwrite anyway? (y/n): ", line );
  616.       if (get_yn( ) != A_YES)
  617.          rc = ERROR;
  618. #if defined( __MSC__ )
  619.       if (rc == OK && chmod( name, S_IWRITE ) == ERROR)
  620.          rc = ERROR;
  621. #else
  622.       if (rc == OK && _chmod( name, 1, 0 ) == ERROR)
  623.          rc = ERROR;
  624. #endif
  625.       restore_screen_line( 0, line, line_buff );
  626.    }
  627.    if (rc == OK)
  628.       rc = unlink( name );
  629.    return( rc );
  630. }
  631.  
  632. /*
  633.  * Name:    write_file
  634.  * Purpose: To write text to a file, eliminating trailing space on the
  635.  *           way.
  636.  * Date:    June 5, 1991
  637.  * Passed:  name:  name of disk file or device
  638.  *          mode:  fopen flags to be used in open
  639.  *          start: first character in text buffer
  640.  *          end:   last character (+1) in text buffer
  641.  *          block: write a file or a marked block
  642.  * Returns: OK, or ERROR if anything went wrong
  643.  */
  644. int  write_file( char *name, char *mode, text_ptr start, text_ptr end,
  645.                  int  block )
  646. {
  647. FILE *fp;       /* file to be written */
  648. int rc;
  649. char *p;
  650. int len;
  651. int bc, ec, last_c;
  652. file_infos *file;
  653. long lend;
  654. long number;
  655.  
  656.    rc = OK;
  657.    if ((fp = fopen( name, mode )) == NULL)
  658.       rc = ERROR;
  659.    else {
  660.       start = cpf( start );
  661.       if (block == LINE || block == BOX) {
  662.          if (g_status.marked_file == NULL)
  663.             rc = ERROR;
  664.          else if (block == BOX) {
  665.             file = g_status.marked_file;
  666.             bc = file->block_bc;
  667.             ec = file->block_ec;
  668.             last_c = ec + 1 - bc;
  669.          }
  670.       }
  671.       p = g_status.line_buff;
  672.       if (rc == OK) {
  673.          if (block == BOX) {
  674.             lend = ptoul( end );
  675.             for (;ptoul( start ) <= lend && rc == OK;) {
  676.                g_status.copied = FALSE;
  677.                load_buff( p, start, bc, ec, BOX );
  678.                *(p+last_c) = '\n';
  679.                *(p+last_c+1) = CONTROL_Z;
  680.                len = find_CONTROL_Z( p );
  681.                if (fwrite( p, sizeof( char ), len, fp ) < len)
  682.                   rc = ERROR;
  683.                start = find_next( start );
  684.                if (start == NULL)
  685.                   start = end + 1;
  686.             }
  687.             g_status.copied = FALSE;
  688.          } else {
  689.             number = ptoul( end ) - ptoul( start );
  690.             len = 0x0800;
  691.             start = nptop( start );
  692.             while (number > 0x0800L && rc != ERROR) {
  693.                _fmemcpy( full_screen_buffer, start, len );
  694.                if (fwrite( full_screen_buffer, sizeof(char), len, fp )< len)
  695.                   rc = ERROR;
  696.                number -= 0x0800L;
  697.                start += 0x0800;
  698.                start = nptop( start );
  699.             }
  700.             /*
  701.              * now less than 2k is left, so finish off the write
  702.              */
  703.             len = number;
  704.             _fmemcpy( full_screen_buffer, start, len );
  705.             if (fwrite( full_screen_buffer, sizeof( char ), len, fp ) < len)
  706.                rc = ERROR;
  707.          }
  708.          if (rc != ERROR)
  709.             rc = fclose( fp );
  710.       }
  711.    }
  712.    return( rc );
  713. }
  714.  
  715. /*
  716.  * Name:    hw_save
  717.  * Purpose: To save text to a file, eliminating trailing space on the
  718.  *           way.
  719.  * Date:    November 11, 1989
  720.  * Passed:  name:  name of disk file
  721.  *          start: first character in text buffer
  722.  *          end:   last character (+1) in text buffer
  723.  *          block: type of block defined
  724.  * Returns: OK, or ERROR if anything went wrong
  725.  * Notes:   Trailing space at the very end of the file is NOT removed,
  726.  *           so that a block write of a block of spaces will work.
  727.  *          No error messages are displayed here, so the caller must
  728.  *           both tell the user what is happening, and print an error
  729.  *           message if anything goes wrong.
  730.  *          This function is in the hardware dependent module because
  731.  *           some computers require non-standard open parameters...
  732.  */
  733. int hw_save( char *name, text_ptr start, text_ptr end, int block )
  734. {
  735.    return write_file( name, "w", start, end, block );
  736. }
  737.  
  738. /*
  739.  * Name:    hw_append
  740.  * Purpose: To append text to a file.
  741.  * Date:    November 11, 1989
  742.  * Passed:  name:  name of disk file
  743.  *          start: first character in text buffer
  744.  *          end:   last character (+1) in text buffer
  745.  *          block: type of defined block
  746.  * Returns: OK, or ERROR if anything went wrong
  747.  * Notes:   No error messages are displayed here, so the caller must
  748.  *           both tell the user what is happening, and print an error
  749.  *           message if anything goes wrong.
  750.  *          This function is in the hardware dependent module because
  751.  *           some computers require non-standard open parameters...
  752.  */
  753. int hw_append( char *name, text_ptr start, text_ptr end, int block )
  754. {
  755.    return write_file( name, "a", start, end, block );
  756. }
  757.  
  758. /*
  759.  * Name:    hw_load
  760.  * Purpose: To load a file into the text buffer.
  761.  * Date:    November 11, 1989
  762.  * Passed:  name:  name of disk file
  763.  *          start: first character in text buffer
  764.  *          limit: last available character in text buffer
  765.  *          end:   last character of file in text buffer
  766.  *          line:  line to display messages
  767.  * Returns: OK, or ERROR if anything went wrong
  768.  * Notes:   All error messages are displayed here, so the caller should
  769.  *           neither tell the user what is happening, nor print an error
  770.  *           message if anything goes wrong.
  771.  *          This function is in the hardware dependent module because
  772.  *           some computers require non-standard open parameters...
  773.  */
  774. int hw_load( char *name, text_ptr start, text_ptr limit, text_ptr *end,
  775.              int line )
  776. {
  777. int fd;         /* file being read */
  778. int length;     /* number of bytes actually read */
  779. int rc;
  780. char buff[MAX_COLS+2];
  781. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  782.  
  783.    /*
  784.     * try reading the file
  785.     */
  786.    rc = OK;
  787.    if ((fd = open( name, O_RDONLY )) == ERROR) {
  788.       combine_strings( buff, "File '", name,"'not found or error loading file");
  789.       save_screen_line( 0, line, line_buff );
  790.       set_prompt( buff, line );
  791.       getkey( );
  792.       restore_screen_line( 0, line, line_buff );
  793.       rc = ERROR;
  794.    } else {
  795.       /*
  796.        * read the entire file, without going past end of buffer.
  797.        * Note that this means a file that is within 1K of the limit
  798.        *  will not be accepted.  length set to a number > 0 for first loop
  799.        */
  800.       limit = addltop( -1024, limit );
  801.       start = cpf( start );
  802.       for (length=1; rc == OK && length > 0;) {
  803.          if (ptoul( start ) >= ptoul( limit )) {
  804.             combine_strings( buff, "file '", name, "'too big" );
  805.             error( WARNING, line, buff );
  806.             rc = WARNING;
  807.          } else {
  808.             if ((length = read( fd, full_screen_buffer, 2048 )) == ERROR) {
  809.                combine_strings( buff, "error reading file '", name, "'" );
  810.                error( WARNING, line, buff );
  811.                rc = ERROR;
  812.             } else {
  813.                _fmemcpy( start, full_screen_buffer, length );
  814.                start = addltop( length, start );
  815.             }
  816.             start = cpf( start );
  817.          }
  818.       }
  819.       if (rc != ERROR) {
  820.          if (*(start-1) != '\n')
  821.             *start++ = '\n';
  822.       }
  823.       /*
  824.        * close the file and report the final character in the buffer
  825.        */
  826.       close( fd );
  827.       *end = start;
  828.    }
  829.    return( rc );
  830. }
  831.  
  832.  
  833. /*
  834.  * Name:    get_help
  835.  * Purpose: save the screen and display key definitions
  836.  * Date:    June 5, 1991
  837.  * Notes:   This routine is dependent on the length of the strings in the
  838.  *          help screen.  To make it easy to load in a new help screen,
  839.  *          the strings are assumed to be 80 characters long followed by
  840.  *          the '\0' character.  It is assumed each that string contains
  841.  *          exactly 81 characters.
  842.  */
  843. void get_help( windows *window )
  844. {
  845. register char *help;
  846. register int line;
  847.  
  848.    xygoto( -1, -1 );
  849.    _fmemcpy( full_screen_buffer, g_display.display_address, 4000 );
  850.    help = help_screen[0];
  851.    for (line=0; help != NULL; ) {
  852.       s_output( help, line, 0, g_display.help_color );
  853.       help = help_screen[++line];
  854.    }
  855.    line = getkey( );
  856.    _fmemcpy( g_display.display_address, full_screen_buffer, 4000 );
  857. }
  858.  
  859.  
  860. /*
  861.  * Name:    show_credits
  862.  * Purpose: display authors
  863.  * Date:    June 5, 1991
  864.  */
  865. void show_credits( void )
  866. {
  867. register char *credit;
  868. int line;
  869.  
  870.    xygoto( -1, -1 );
  871.    credit = credit_screen[0];
  872.    for (line=0; credit != NULL; ) {
  873.       s_output( credit, line+2, 11, g_display.text_color );
  874.       credit = credit_screen[++line];
  875.    }
  876. }
  877.  
  878. /*
  879.  * The next function was written by Tom Waters, twaters@nswc-wo.navy.mil and
  880.  * modified extensively by Frank Davis.
  881.  *
  882.  * "I use ANSI.SYS to redefine a few of my function keys and this causes a
  883.  * problem when getch() is used in a program.  For example, instead of returning
  884.  * 321 for the F7, I get the redefined string inserted in the text. So, instead
  885.  * of using getch(), I use the following function ..."
  886.  *
  887.  * Tom, thanks for the info and solution.  I'm sure your function will be
  888.  * be appreciated by everyone with ANSI key defs, Frank.
  889.  */
  890.  
  891. /*
  892.  * Name:    getkey
  893.  * Purpose: use bios to get keyboard input (getch has trouble w/ ANSI
  894.  *          redefined keys)
  895.  * Date:    July 2, 1991
  896.  * Modified:July 12, 1991, Frank Davis - accept ALT-xxx keyboard entry
  897.  *          September 10, 1991, Frank Davis - add support for Ctrl+Up, etc...
  898.  * Passed:  None
  899.  * Notes:   Uses the BIOS to read the next keyboard character.  Service
  900.  *          0 is keyboard read.  Service 0x10 is the extended keyboard read.
  901.  *          Test for a bunch of special cases.  Allow the user to enter any
  902.  *          ASCII or Extended ASCII code as a normal text characters,
  903.  *          exceptions are 10, 13, and 26 (CR, LF, EOF).
  904.  */
  905. int getkey( void )
  906. {
  907. unsigned key, scan, num_lock, control, shift;
  908. register unsigned lo;
  909.  
  910.    /*
  911.     *  _bios_keybrd == int 16.  It returns the scan code in ah, hi part of key,
  912.     *  and the ascii key code in al, lo part of key.  If the character was
  913.     *  entered via ALT-xxx, the scan code, hi part of key, is 0.
  914.     */
  915.    if (mode.enh_kbd) {
  916.       key = _bios_keybrd( 0x10 );
  917.       lo  = _bios_keybrd( 0x12 );
  918.       if ((key & 0x00ff) == 0x00e0)
  919.          key = key & 0xff00;
  920.    } else {
  921.       key = _bios_keybrd( 0 );
  922.       lo  = _bios_keybrd( 2 );
  923.    }
  924.    num_lock = lo & 0x20;
  925.    control  = lo & 0x04;
  926.    shift    = lo & 0x03;
  927.    scan = (key & 0xff00) >> 8;
  928.    lo = key & 0X00FF;
  929.    lo = (lo == 0) ? (scan | 0x100) : lo;
  930.  
  931.    /*
  932.     * Pressing Control+BackSpace generates the 0x7f character.  Instead of
  933.     * 0x7f, make lo the ASCII backspace character.  If anyone wants the
  934.     * 0x7f character, then they can enter it via ALT+xxx.
  935.     */
  936.    if (scan == 14 && lo == 0x7f)
  937.       lo = 8;
  938.  
  939.  
  940.    if (lo < 32) {
  941.  
  942.       /*
  943.        * My machine at home is sorta weird.  On every machine that I've
  944.        * tested at the awffice, the ALT-xxx combination returns 0 for the
  945.        * scan byte and xxx for the ASCII code.  My machine returns 184 (decimal)
  946.        * as the scan code?!?!?  I added the next two lines for my machine at
  947.        * home.  I wonder if someone forgot to zero out ah for Alt keypad entry
  948.        * when they wrote my bios.
  949.        */
  950.       if (scan > 0x80)
  951.          scan = 0;
  952.  
  953.       /*
  954.        * If user enters ALT+010 or ALT+013 make this a return.  CR and LF
  955.        * are special characters and they need to be handled by the editor.
  956.        */
  957.       if (scan == 0 && (lo == 10 || lo == 13))
  958.          lo = 425;
  959.  
  960.       /*
  961.        * Separate the ESC key from the ^[ key.  The scan code for the ESC
  962.        * key is 1.  Map this to a different index into the key function
  963.        * array just in case someone wants to define ESC or ^[ to different
  964.        * functions.  BTW, ESC and ^[ return the same ASCII code, 27.
  965.        *
  966.        */
  967.       else if (scan == 1) {
  968.          if (shift)
  969.             lo = 260;
  970.          else if (control)
  971.             lo = 261;
  972.          else
  973.             lo = 258;
  974.       }
  975.  
  976.       /*
  977.        * Scan code for Enter = 28.  Separate the various Enter keys.
  978.        */
  979.       else if (scan == 28) {
  980.          if (shift)
  981.             lo = 263;
  982.          else if (control)
  983.             lo = 264;
  984.          else
  985.             lo = 262;
  986.       }
  987.  
  988.       /*
  989.        * Scan code for Backspace = 14.  Separate the various BackSpace keys.
  990.        */
  991.       else if (scan == 14) {
  992.          if (shift)
  993.             lo = 266;
  994.          else if (control)
  995.             lo = 267;
  996.          else
  997.             lo = 265;
  998.       }
  999.  
  1000.       /*
  1001.        * Scan code for Tab = 15.  Separate the tab key.
  1002.        */
  1003.       else if (scan == 15) {
  1004.          lo = 268;
  1005.       }
  1006.  
  1007.       /*
  1008.        * if scan code is not 0, then a Control+a thru z was pressed.  Map
  1009.        * those keys to the WordStar commands.  If the scan code is 0, let
  1010.        * all ASCII and Extended ASCII character get thru except 10, 13, and 26.
  1011.        */
  1012.       else if (scan > 0)
  1013.          lo += 430;
  1014.  
  1015.       /*
  1016.        * Do not allow control z to get thru.  Code 256 is not assigned to
  1017.        * any function, see default.h for more info.
  1018.        */
  1019.       if (lo == 26)
  1020.          lo = 256;
  1021.  
  1022.    } else if (!num_lock) {
  1023.       switch (scan) {
  1024.          /*
  1025.           * scan code for grey - == 74.  if num_lock is not toggled, assign it
  1026.           * to the scroll line up function.
  1027.           */
  1028.          case 74 :
  1029.             lo = 423;
  1030.             break;
  1031.  
  1032.          /*
  1033.           * scan code for grey + == 78.  if num_lock is not toggled, assign it
  1034.           * to the scroll line down function.  if shift grey + then stationary
  1035.           * scroll down.
  1036.           */
  1037.          case 78 :
  1038.             lo = 424;
  1039.             break;
  1040.       }
  1041.    }
  1042.    return( lo );
  1043. }
  1044.  
  1045.  
  1046. /*
  1047.  * Name:    getfunc
  1048.  * Purpose: get the function assigned to key c
  1049.  * Date:    July 11, 1991
  1050.  * Passed:  c:  key just pressed
  1051.  * Notes:   key codes less than 256 or 0x100 are not assigned a function.
  1052.  *          The codes in the range 0-255 are ASCII and extended ASCII chars.
  1053.  */
  1054. int getfunc( int c )
  1055. {
  1056. unsigned rc;
  1057.  
  1058.    if (c < 256)
  1059.       rc = 0;
  1060.    else
  1061.       rc = key_func[c-256].func;
  1062.    return( rc );
  1063. }
  1064.