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

  1. /*
  2.  * This file contains the file i/o stuff.  These functions get stuff from
  3.  * from the outside world into a form for TDE.  The form TDE uses is a
  4.  * double linked list.  Each node in the list points to the prev and
  5.  * the next nodes, if they exist.  Also in each node is a pointer to a
  6.  * line of text, a line length variable, and a dirty node indicator.  In
  7.  * earlier versions of TDE, a '\n' was used to terminate a line of text.
  8.  * In this version, we must keep an accurate count of characters in
  9.  * each line of text, as no character is used to terminate the line.
  10.  *
  11.  * Each file must contain at least one node.  That node is called the
  12.  * EOF node.  The EOF node terminates the double linked list for each
  13.  * file.  The EOF node has a NULL pointer in the line field, a NULL
  14.  * pointer in the next field, and an EOF in the len field.  Here's
  15.  * a crude picture of the double linked list structure:
  16.  *
  17.  *              Regular node                             EOF node
  18.  *     ---------                                 ---------
  19.  *     | prev  | ---> pointer to prev node       | prev  | ---> unknown
  20.  *     | line  | ---> "Hello world"              | line  | ---> NULL
  21.  *     | len   | ---> 11                         | len   | ---> EOF
  22.  *     | dirty | ---> TRUE | FALSE               | dirty | ---> FALSE
  23.  *     | next  | ---> pointer to next node       | next  | ---> NULL
  24.  *     ---------                                 ---------
  25.  *
  26.  * Implicitly, I am assuming that EOF is defined as (-1) in stdio.h.
  27.  *
  28.  * The load_file function is probably more complicated than expected, but
  29.  * I was trying to read chunks of text that match the disk cluster size
  30.  * and/or some multiple of the cache in the disk controller.
  31.  *
  32.  *
  33.  * New editor name:  TDE, the Thomson-Davis Editor.
  34.  * Author:           Frank Davis
  35.  * Date:             June 5, 1991, version 1.0
  36.  * Date:             July 29, 1991, version 1.1
  37.  * Date:             October 5, 1991, version 1.2
  38.  * Date:             January 20, 1992, version 1.3
  39.  * Date:             February 17, 1992, version 1.4
  40.  * Date:             April 1, 1992, version 1.5
  41.  * Date:             June 5, 1992, version 2.0
  42.  * Date:             October 31, 1992, version 2.1
  43.  * Date:             April 1, 1993, version 2.2
  44.  * Date:             June 5, 1993, version 3.0
  45.  * Date:             August 29, 1993, version 3.1
  46.  * Date:             November 13, 1993, version 3.2
  47.  *
  48.  * This code is released into the public domain, Frank Davis.
  49.  * You may distribute it freely.
  50.  */
  51.  
  52.  
  53. #include "tdestr.h"             /* tde types */
  54. #include "common.h"
  55. #include "define.h"
  56. #include "tdefunc.h"
  57.  
  58. #if !defined( __UNIX__ )
  59.  #include <dos.h>                /* for renaming files */
  60.  #include <bios.h>               /* for direct BIOS keyboard input */
  61.  #include <io.h>                 /* for file attribute code */
  62.  #if defined( __MSC__ )
  63.   #include <errno.h>
  64.   #include <sys\types.h>         /* S_IWRITE etc */
  65.  #endif
  66.  #include <sys\stat.h>           /* S_IWRITE etc */
  67. #endif
  68.  
  69. #include <fcntl.h>              /* open flags */
  70.  
  71. /*
  72.  * Name:    write_file
  73.  * Purpose: To write text to a file
  74.  *           way.
  75.  * Date:    June 5, 1991
  76.  * Passed:  name:  name of disk file or device
  77.  *          open_mode:  fopen flags to be used in open
  78.  *          file:  pointer to file structure to write
  79.  *          start: first node to write
  80.  *          end:   last node to write
  81.  *          block: write a file or a marked block
  82.  * Returns: OK, or ERROR if anything went wrong
  83.  */
  84. int  write_file( char *name, int open_mode, file_infos *file, long start,
  85.                  long end, int block )
  86. {
  87. FILE *fp;       /* file to be written */
  88. char *p;
  89. char *z = "\x1a";
  90. register int rc;
  91. int  bc;
  92. int  ec;
  93. int  len;
  94. int  write_z;
  95. int  write_eol;
  96. long number;
  97. line_list_ptr ll;
  98. char *open_string;
  99. char *eol;
  100. size_t eol_count;
  101.  
  102.    write_z = mode.control_z;
  103.    switch (open_mode) {
  104.       case APPEND :
  105.          open_string = "ab";
  106.          break;
  107.       case OVERWRITE :
  108.       default :
  109.          open_string = "wb";
  110.          break;
  111.    }
  112.    switch (file->crlf) {
  113.       case BINARY   :
  114.          eol_count = 0;
  115.          eol = "";
  116.          write_z = FALSE;
  117.          break;
  118.       case CRLF   :
  119.          eol_count = 2;
  120.          eol = "\r\n";
  121.          break;
  122.       case LF     :
  123.          eol_count = 1;
  124.          eol = "\n";
  125.          break;
  126.       default     :
  127.          eol_count = 0;
  128.          eol = "";
  129.          assert( FALSE );
  130.    }
  131.    rc = OK;
  132.    if ((fp = fopen( name, open_string )) == NULL || ceh.flag == ERROR)
  133.       rc = ERROR;
  134.    else {
  135.       ec = bc = len = 0;
  136.       ll = file->line_list;
  137.       if (block == LINE || block == BOX || block == STREAM) {
  138.          if (g_status.marked_file == NULL)
  139.             rc = ERROR;
  140.          else
  141.             file = g_status.marked_file;
  142.          if (rc != ERROR) {
  143.             ll = file->line_list;
  144.             for (number=1; number<start && ll->next != NULL; number++)
  145.                ll = ll->next;
  146.          }
  147.          if (rc != ERROR && (block == BOX || block == STREAM)) {
  148.             bc  = file->block_bc;
  149.             ec  = file->block_ec;
  150.             len = ec + 1 - bc;
  151.          }
  152.          if (rc != ERROR  &&  block == STREAM) {
  153.             if (start == end )
  154.                block = BOX;
  155.          }
  156.       } else {
  157.          for (number=1; number<start && ll->next != NULL; number++)
  158.             ll = ll->next;
  159.       }
  160.       p = g_status.line_buff;
  161.       if (rc == OK) {
  162.          if (block == BOX) {
  163.  
  164.             assert( len >= 0 );
  165.             assert( len < MAX_LINE_LENGTH );
  166.  
  167.             for (;start <= end  &&  ll->len != EOF && rc == OK; start++) {
  168.                g_status.copied = FALSE;
  169.                load_box_buff( p, ll, bc, ec, ' ' );
  170.                if (fwrite( p, sizeof( char ), len, fp ) < (unsigned)len ||
  171.                           ceh.flag == ERROR)
  172.                   rc = ERROR;
  173.                if ((rc != ERROR  &&
  174.                     fwrite( eol, sizeof( char ), eol_count, fp ) < eol_count)
  175.                               || ceh.flag == ERROR)
  176.                   rc = ERROR;
  177.                ll = ll->next;
  178.                if (ll == NULL)
  179.                   rc = ERROR;
  180.             }
  181.          } else {
  182.             for (number=start; number <= end && rc == OK && ll->len != EOF;
  183.                       number++) {
  184.                g_status.copied = FALSE;
  185.                copy_line( ll );
  186.                len = g_status.line_buff_len;
  187.                if (block == STREAM) {
  188.                   if (number == start) {
  189.                      bc = bc > len ? len : bc;
  190.                      len = len - bc;
  191.  
  192.                      assert( len >= 0 );
  193.  
  194.                      memmove( p, p + bc, len );
  195.                   } else if (number == end) {
  196.                      ++ec;
  197.                      len =  ec > len ? len : ec;
  198.                   }
  199.                }
  200.  
  201.                assert( len >= 0 );
  202.                assert( len < MAX_LINE_LENGTH );
  203.  
  204.                if (fwrite( p, sizeof( char ), len, fp ) < (unsigned)len ||
  205.                        ceh.flag == ERROR)
  206.                   rc = ERROR;
  207.  
  208.                /*
  209.                 * if a Control-Z is already at EOF, don't write another one.
  210.                 */
  211.                write_eol = TRUE;
  212.                if (number == end) {
  213.                   if (file->crlf == CRLF ||  file->crlf == LF) {
  214.                      if (len > 0  &&  *(p + len - 1) == '\x1a') {
  215.                         write_eol = FALSE;
  216.                         write_z = FALSE;
  217.                      }
  218.                   }
  219.                }
  220.  
  221.                if ((write_eol == TRUE  &&  rc != ERROR  &&
  222.                      fwrite( eol, sizeof( char ), eol_count, fp ) < eol_count)
  223.                      || ceh.flag == ERROR)
  224.                   rc = ERROR;
  225.                ll = ll->next;
  226.                if (ll == NULL)
  227.                   rc = ERROR;
  228.             }
  229.          }
  230.          if (rc != ERROR  &&  write_z) {
  231.             if (fwrite( z, sizeof( char ), 1, fp ) < 1 || ceh.flag == ERROR)
  232.                rc = ERROR;
  233.          }
  234.          g_status.copied = FALSE;
  235.          if (ceh.flag != ERROR) {
  236.             if (fclose( fp ) != 0)
  237.                rc = ERROR;
  238.          }
  239.       }
  240.    }
  241.    return( rc );
  242. }
  243.  
  244.  
  245. /*
  246.  * Name:    hw_save
  247.  * Purpose: To save text to a file
  248.  * Date:    November 11, 1989
  249.  * Passed:  name:  name of disk file
  250.  *          file:  pointer to file structure
  251.  *          start: first character in text buffer
  252.  *          end:   last character (+1) in text buffer
  253.  *          block: type of block defined
  254.  * Returns: OK, or ERROR if anything went wrong
  255.  */
  256. int hw_save( char *name, file_infos *file, long start, long end, int block )
  257. {
  258.    return( write_file( name, OVERWRITE, file, start, end, block ) );
  259. }
  260.  
  261.  
  262. /*
  263.  * Name:    hw_append
  264.  * Purpose: To append text to a file.
  265.  * Date:    November 11, 1989
  266.  * Passed:  name:  name of disk file
  267.  *          file:  pointer to file structure
  268.  *          start: first character in text buffer
  269.  *          end:   last character (+1) in text buffer
  270.  *          block: type of defined block
  271.  * Returns: OK, or ERROR if anything went wrong
  272.  */
  273. int hw_append( char *name, file_infos *file, long start, long end, int block )
  274. {
  275.    return( write_file( name, APPEND, file, start, end, block ) );
  276. }
  277.  
  278.  
  279. /*
  280.  * Name:    load_file
  281.  * Purpose: To load a file into the array of text pointers.
  282.  * Date:    December 1, 1992
  283.  * Passed:  name:       name of disk file
  284.  *          fp:         pointer to file structure
  285.  *          file_mode:  BINARY or TEXT
  286.  *          bin_len:    if opened in BINARY mode, length of node line
  287.  * Returns: OK, or ERROR if anything went wrong
  288.  */
  289. int  load_file( char *name, file_infos *fp, int *file_mode, int bin_len )
  290. {
  291. FILE *stream;                           /* stream to read */
  292. int  rc;
  293. text_ptr l;
  294. line_list_ptr ll;
  295. line_list_ptr temp_ll;
  296. unsigned long line_count;
  297. char *e;
  298. char *residue;
  299. int  len;
  300. int  res;
  301. size_t t1, t2;
  302. int  crlf;
  303. int  prompt_line;
  304. char temp[MAX_COLS+2];
  305. #if defined( __UNIX__ )
  306.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  307. #else
  308.  char display_buff[(MAX_COLS+2)*2];
  309. #endif
  310.  
  311.    /*
  312.     * initialize the counters and pointers
  313.     */
  314.    rc = OK;
  315.    len = 1;
  316.    line_count = 0;
  317.    res = 0;
  318.    residue = g_status.line_buff;
  319.    prompt_line = g_display.nlines;
  320.    fp->length  = 0;
  321.    fp->undo_count = 0;
  322.    fp->undo_top = fp->undo_bot = NULL;
  323.    fp->line_list_end = fp->line_list = NULL;
  324.    ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  325.  
  326.    if (ll != NULL) {
  327.       ll->dirty = FALSE;
  328.       ll->len   = EOF;
  329.       ll->line  = NULL;
  330.       ll->next  = ll->prev = NULL;
  331.       fp->undo_top = fp->undo_bot = ll;
  332.    }
  333.  
  334.    ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  335.  
  336.    if (ll != NULL) {
  337.       ll->dirty = FALSE;
  338.       ll->len   = EOF;
  339.       ll->line  = NULL;
  340.       ll->next  = ll->prev = NULL;
  341.       fp->line_list_end = fp->line_list = ll;
  342.    }
  343.  
  344.    if ((stream = fopen( name, "rb" )) == NULL || ceh.flag == ERROR ||
  345.          rc == ERROR) {
  346.       /*
  347.        * file not found or error loading file
  348.        */
  349.       combine_strings( temp, main7a, name, main7b );
  350.       save_screen_line( 0, prompt_line, display_buff );
  351.       set_prompt( temp, prompt_line );
  352.       getkey( );
  353.       restore_screen_line( 0, prompt_line, display_buff );
  354.       if (fp->line_list != NULL)
  355.          my_free( fp->line_list );
  356.       if (fp->undo_top != NULL)
  357.          my_free( fp->undo_top );
  358.       rc = ERROR;
  359.    } else {
  360.       if (*file_mode == BINARY) {
  361.          mode.trailing = FALSE;
  362.          crlf = BINARY;
  363.          if (bin_len < 0  ||  bin_len > READ_LENGTH)
  364.             bin_len = DEFAULT_BIN_LENGTH;
  365.          for (; rc == OK;) {
  366.             t1 = fread( g_status.line_buff, sizeof(char), bin_len, stream );
  367.             if (ferror( stream )  ||  ceh.flag == ERROR) {
  368.                combine_strings( temp, main9, name, "'" );
  369.                error( WARNING, prompt_line, temp );
  370.                rc = ERROR;
  371.             } else if (t1) {
  372.  
  373.                assert( t1 < MAX_LINE_LENGTH );
  374.  
  375.                l = (text_ptr)my_malloc( t1 * sizeof(char), &rc );
  376.                temp_ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  377.  
  378.                if (rc != ERROR) {
  379.  
  380.                   /*
  381.                    * if everything is everything, copy from io buff to
  382.                    *   dynamic mem.
  383.                    */
  384.                   if (t1 > 0)
  385.                      my_memcpy( l, g_status.line_buff, t1 );
  386.  
  387.                   ++line_count;
  388.                   temp_ll->line = l;
  389.                   temp_ll->dirty = FALSE;
  390.                   temp_ll->len  = t1;
  391.                   insert_node( fp, ll, temp_ll );
  392.                   ll = temp_ll;
  393.                } else
  394.                   rc = show_file_2big( name, prompt_line, temp_ll, l );
  395.             } else
  396.                break;
  397.          }
  398.       } else {
  399.          crlf = LF;
  400.          for (; rc == OK;) {
  401.             t1 = fread( g_status.line_buff, sizeof(char), READ_LENGTH, stream );
  402.             if (ferror( stream )  ||  ceh.flag == ERROR) {
  403.                combine_strings( temp, main9, name, "'" );
  404.                error( WARNING, prompt_line, temp );
  405.                rc = ERROR;
  406.             } else {
  407.  
  408.                /*
  409.                 * "e" walks down io buffer 1 looking for end of lines.  "t1"
  410.                 *   keeps count of number of characters in io buffer 1.
  411.                 */
  412.                e = g_status.line_buff;
  413.                while (t1 && rc == OK) {
  414.  
  415.                   /*
  416.                    * while "t1" is not zero and "len" is less than max line length,
  417.                    *   let "e" walk down the buffer until it find <LF>.
  418.                    */
  419.                   for (; t1 && len < READ_LENGTH &&  *e != '\n'; len++, e++, t1--);
  420.  
  421.                   /*
  422.                    * if "t1" is not zero, we either found a <LF> or the line
  423.                    *   length max'd out.
  424.                    */
  425.                   if (t1  ||  len >= READ_LENGTH) {
  426.  
  427.                      if (len > 1 && *e == '\n') {
  428.                         if (len - res == 1) {
  429.                            if (*(residue + res - 1) == '\r') {
  430.                               --len;
  431.                               --res;
  432.                               crlf = CRLF;
  433.                            }
  434.                         } else {
  435.                            if (*(e - 1) == '\r') {
  436.                               --len;
  437.                               crlf = CRLF;
  438.                            }
  439.                         }
  440.                      }
  441.                      if (len > 0)
  442.                         --len;
  443.  
  444.                      assert( len >= 0 );
  445.                      assert( len < MAX_LINE_LENGTH );
  446.  
  447.                      /*
  448.                       * allocate space for relocatable array of line pointers and
  449.                       *   allocate space for the line we just read.
  450.                       */
  451.                      l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  452.                      temp_ll =
  453.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  454.  
  455.                      if (rc != ERROR) {
  456.  
  457.                         /*
  458.                          * if everything is everything, copy from io buff to
  459.                          *   dynamic mem.  "residue" keeps up with the beginning
  460.                          *   of line in io buffer.
  461.                          */
  462.                         if (res > 0) {
  463.  
  464.                            assert( res >= 0 );
  465.                            assert( len - res >= 0 );
  466.  
  467.                            if (res > 0)
  468.                               my_memcpy( l, residue, res );
  469.                            if (len - res > 0)
  470.                               my_memcpy( l + res, g_status.line_buff, len - res );
  471.                            res = 0;
  472.                         } else
  473.                            if (len > 0)
  474.                               my_memcpy( l, residue, len );
  475.  
  476.                         ++line_count;
  477.                         temp_ll->line = l;
  478.                         temp_ll->dirty = FALSE;
  479.                         temp_ll->len  = len;
  480.                         insert_node( fp, ll, temp_ll );
  481.                         ll = temp_ll;
  482.  
  483.                         /*
  484.                          * reset io buffer pointers and counters.
  485.                          */
  486.                         len = 1;
  487.                         if (t1 == 0)
  488.                            residue = g_status.tabout_buff;
  489.                         else {
  490.                            t1--;
  491.                            residue =  t1 == 0 ? g_status.tabout_buff : ++e;
  492.                         }
  493.                      } else
  494.                         rc = show_file_2big( name, prompt_line, temp_ll, l );
  495.                   } else if (len < READ_LENGTH ) {
  496.                      if (!feof( stream ))
  497.                         res = len - 1;
  498.                   } else {
  499.                      error( WARNING, prompt_line, main9a );
  500.                      rc = ERROR;
  501.                   }
  502.                }
  503.             }
  504.  
  505.             if (rc != OK)
  506.                break;
  507.  
  508.             /*
  509.              * we may have read all lines that end in '\n', but there may
  510.              *   be some residue after the last '\n'.  ^Z is a good example.
  511.              */
  512.             if (feof( stream )) {
  513.                if (len > 1) {
  514.                   --len;
  515.                   if (t1 == 0)
  516.                      --e;
  517.  
  518.                   assert( len >= 0 );
  519.                   assert( len < MAX_LINE_LENGTH );
  520.  
  521.                   /*
  522.                    * allocate space for relocatable array of line pointers and
  523.                    *   allocate space for the line we just read.
  524.                    */
  525.                   l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  526.                   temp_ll =
  527.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  528.  
  529.                   if (rc != ERROR) {
  530.  
  531.                      /*
  532.                       * if everything is everything, copy from io buff to
  533.                       *   dynamic mem.  "residue" keeps up with the beginning
  534.                       *   of line in io buffer.
  535.                       */
  536.                      if (res > 0) {
  537.  
  538.                         assert( res >= 0 );
  539.                         assert( res < MAX_LINE_LENGTH);
  540.                         assert( len - res >= 0 );
  541.                         assert( len - res < MAX_LINE_LENGTH);
  542.  
  543.                         if (res > 0 )
  544.                            my_memcpy( l, residue, res );
  545.                         if (len - res > 0)
  546.                            my_memcpy( l + res, g_status.line_buff, len - res );
  547.                      } else
  548.                         if (len > 0)
  549.                            my_memcpy( l, residue, len );
  550.                      ++line_count;
  551.                      temp_ll->line = l;
  552.                      temp_ll->dirty = FALSE;
  553.                      temp_ll->len  = len;
  554.                      insert_node( fp, ll, temp_ll );
  555.                   } else
  556.                      rc = show_file_2big( name, prompt_line, temp_ll, l );
  557.                }
  558.                break;
  559.             }
  560.  
  561.             t2 = fread( g_status.tabout_buff, sizeof(char), READ_LENGTH, stream );
  562.             if (ferror( stream )  ||  ceh.flag == ERROR) {
  563.                combine_strings( temp, main9, name, "'" );
  564.                error( WARNING, prompt_line, temp );
  565.                rc = ERROR;
  566.             } else if (rc == OK) {
  567.                e = g_status.tabout_buff;
  568.                while (t2 && rc == OK) {
  569.                   for (; t2 && len < READ_LENGTH &&  *e != '\n'; len++, e++, t2--);
  570.                   if (t2  ||  len >= READ_LENGTH) {
  571.  
  572.                      if (len > 1 && *e == '\n') {
  573.                         if (len - res == 1) {
  574.                            if (*(residue + res - 1) == '\r') {
  575.                               --len;
  576.                               --res;
  577.                               crlf = CRLF;
  578.                            }
  579.                         } else {
  580.                            if (*(e - 1) == '\r') {
  581.                               --len;
  582.                               crlf = CRLF;
  583.                            }
  584.                         }
  585.                      }
  586.                      if (len > 0)
  587.                         --len;
  588.  
  589.                      assert( len >= 0 );
  590.                      assert( len < MAX_LINE_LENGTH );
  591.  
  592.                      l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  593.                      temp_ll =
  594.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  595.  
  596.                      if (rc != ERROR) {
  597.                         if (res > 0) {
  598.  
  599.                            assert( res >= 0 );
  600.                            assert( res < MAX_LINE_LENGTH);
  601.                            assert( len - res >= 0 );
  602.                            assert( len - res < MAX_LINE_LENGTH);
  603.  
  604.                            if (res > 0)
  605.                               my_memcpy( l, residue, res );
  606.                            if (len - res > 0)
  607.                               my_memcpy( l+res, g_status.tabout_buff, len - res );
  608.                            res = 0;
  609.                         } else
  610.                            if (len > 0)
  611.                               my_memcpy( l, residue, len );
  612.  
  613.                         ++line_count;
  614.                         temp_ll->line = l;
  615.                         temp_ll->dirty = FALSE;
  616.                         temp_ll->len  = len;
  617.                         insert_node( fp, ll, temp_ll );
  618.                         ll = temp_ll;
  619.  
  620.                         len = 1;
  621.                         if (t2 == 0)
  622.                            residue = g_status.line_buff;
  623.                         else {
  624.                            t2--;
  625.                            residue =  t2 == 0 ? g_status.line_buff : ++e;
  626.                         }
  627.                      } else
  628.                         rc = show_file_2big( name, prompt_line, temp_ll, l );
  629.                   } else if (len < READ_LENGTH) {
  630.                      if (!feof( stream ))
  631.                         res = len - 1;
  632.                   } else {
  633.                      error( WARNING, prompt_line, main9a );
  634.                      rc = ERROR;
  635.                   }
  636.                }
  637.             }
  638.  
  639.             if (rc != ERROR  &&  feof( stream )) {
  640.                if (len > 1) {
  641.                   --len;
  642.                   if (t2 == 0)
  643.                      --e;
  644.  
  645.                   assert( len >= 0 );
  646.                   assert( len < MAX_LINE_LENGTH );
  647.  
  648.                   l = (text_ptr)my_malloc( len * sizeof(char), &rc );
  649.                   temp_ll =
  650.                        (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  651.  
  652.                   if (rc != ERROR) {
  653.                      if (res > 0) {
  654.  
  655.                         assert( res >= 0 );
  656.                         assert( res < MAX_LINE_LENGTH);
  657.                         assert( len - res >= 0 );
  658.                         assert( len - res < MAX_LINE_LENGTH);
  659.  
  660.                         if (res > 0)
  661.                            my_memcpy( l, residue, res );
  662.                         if (len - res > 0)
  663.                            my_memcpy( l+res, g_status.tabout_buff, len - res );
  664.                      } else
  665.                         if (len > 0)
  666.                            my_memcpy( l, residue, len );
  667.  
  668.                      ++line_count;
  669.                      temp_ll->line = l;
  670.                      temp_ll->dirty = FALSE;
  671.                      temp_ll->len  = len;
  672.                      insert_node( fp, ll, temp_ll );
  673.                   } else
  674.                      rc = show_file_2big( name, prompt_line, temp_ll, l );
  675.                }
  676.                break;
  677.             }
  678.          }
  679.          *file_mode = crlf;
  680.       }
  681.  
  682.       /*
  683.        * close the file
  684.        */
  685.       fp->length = line_count;
  686.    }
  687.    if (stream != NULL)
  688.       fclose( stream );
  689.    return( rc );
  690. }
  691.  
  692.  
  693. /*
  694.  * Name:    insert_node
  695.  * Purpose: To insert a node into a double linked list
  696.  * Date:    December 1, 1992
  697.  * Passed:  fp:  pointer to file structure that owns the double linked list
  698.  *          current: pointer to current node in double linked list
  699.  *          new:     pointer to new node to insert into double linked list
  700.  * Notes:   if the current list pointer is the last node in the list, insert
  701.  *            new code behind current node.
  702.  */
  703. void insert_node( file_infos *fp, line_list_ptr current, line_list_ptr new )
  704. {
  705.  
  706.    /*
  707.     * standard double linked list insert
  708.     */
  709.    if (current->next != NULL) {
  710.       current->next->prev = new;
  711.       new->next = current->next;
  712.       current->next = new;
  713.       new->prev = current;
  714.    /*
  715.     * if the current node is the NULL node, insert the new node behind current
  716.     */
  717.    } else {
  718.       new->next = current;
  719.       if (current->prev != NULL)
  720.          current->prev->next = new;
  721.       new->prev = current->prev;
  722.       current->prev = new;
  723.       if (new->prev == NULL)
  724.          fp->line_list = new;
  725.    }
  726. }
  727.  
  728.  
  729. /*
  730.  * Name:    show_file_2big
  731.  * Purpose: tell user we ran out of room loading file
  732.  * Date:    December 1, 1992
  733.  * Passed:  name:  name of disk file
  734.  *          line:  line to display messages
  735.  *          ll:    double linked list pointer
  736.  *          t:     text line pointer
  737.  * Returns: WARNING
  738.  * Notes:   one or both of the malloc requests overflowed the heap.  free the
  739.  *            dynamic if allocated.
  740.  */
  741. int  show_file_2big( char *name, int prompt_line, line_list_ptr ll, text_ptr t )
  742. {
  743. char temp[MAX_COLS+2];
  744.  
  745.    combine_strings( temp, main10a, name, main10b );
  746.    error( WARNING, prompt_line, temp );
  747.    if (t != NULL)
  748.       my_free( t );
  749.    if (ll != NULL)
  750.       my_free( ll );
  751.    return( WARNING );
  752. }
  753.  
  754.  
  755. /*
  756.  * Name:    backup_file
  757.  * Purpose: To make a back-up copy of current file.
  758.  * Date:    June 5, 1991
  759.  * Passed:  window:  current window pointer
  760.  */
  761. int  backup_file( TDE_WIN *window )
  762. {
  763. char *old_line_buff;
  764. char *old_tabout_buff;
  765. int  old_line_buff_len;
  766. int  old_tabout_buff_len;
  767. int  old_copied;
  768. int  rc;
  769. file_infos *file;
  770.  
  771.    rc = OK;
  772.    file = window->file_info;
  773.    if (file->backed_up == FALSE  &&  file->modified == TRUE) {
  774.       old_copied = g_status.copied;
  775.       old_line_buff_len = g_status.line_buff_len;
  776.       old_line_buff = calloc( MAX_LINE_LENGTH, sizeof(char) );
  777.       old_tabout_buff_len = g_status.tabout_buff_len;
  778.       old_tabout_buff = calloc( MAX_LINE_LENGTH, sizeof(char) );
  779.  
  780.       if (old_line_buff != NULL  &&  old_tabout_buff != NULL) {
  781.          memcpy( old_line_buff, g_status.line_buff, MAX_LINE_LENGTH );
  782.          memcpy( old_tabout_buff, g_status.tabout_buff, MAX_LINE_LENGTH );
  783.          if ((rc = save_backup( window )) != ERROR)
  784.             file->backed_up = TRUE;
  785.          else
  786.             rc = ERROR;
  787.          memcpy( g_status.line_buff, old_line_buff, MAX_LINE_LENGTH );
  788.          memcpy( g_status.tabout_buff, old_tabout_buff, MAX_LINE_LENGTH );
  789.          g_status.line_buff_len = old_line_buff_len;
  790.          g_status.tabout_buff_len = old_tabout_buff_len;
  791.          g_status.copied = old_copied;
  792.       } else {
  793.          error( WARNING, window->bottom_line, main4 );
  794.          rc = ERROR;
  795.       }
  796.       if (old_line_buff != NULL)
  797.          free( old_line_buff );
  798.       if (old_tabout_buff != NULL)
  799.          free( old_tabout_buff );
  800.    }
  801.    return( rc );
  802. }
  803.  
  804.  
  805. /*
  806.  * Name:    edit_file
  807.  * Purpose: To allocate space for a new file structure and set up some
  808.  *           of the relevant fields.
  809.  * Date:    June 5, 1991
  810.  * Modified: November 13, 1993, Frank Davis per Byrial Jensen
  811.  * Passed:  name:  name of the file to edit
  812.  *          file_mode:  BINARY or TEXT
  813.  *          bin_length: if opened in BINARY mode, length of binary lines
  814.  * Returns: OK if file structure could be created
  815.  *          ERROR if out of memory
  816.  *
  817.  * Change:  file->next_letter is initialized to 0 instead 'a'
  818.  */
  819. int  edit_file( char *name, int file_mode, int bin_length )
  820. {
  821. int  rc;        /* return code */
  822. int  existing;
  823. int  line;
  824. int  rcol;
  825. register file_infos *file; /* file structure for file belonging to new window */
  826. file_infos *fp;
  827. long found_line;
  828. line_list_ptr ll;
  829. line_list_ptr temp_ll;
  830.  
  831.    line = g_display.nlines;
  832.    rc = OK;
  833.    /*
  834.     * allocate a file structure for the new file
  835.     */
  836.    file = (file_infos *)calloc( 1, sizeof(file_infos) );
  837.    if (file == NULL) {
  838.       error( WARNING, line, main4 );
  839.       rc = ERROR;
  840.    }
  841.    existing = FALSE;
  842.    if (rc == OK  &&  hw_fattrib( name ) == OK) {
  843.       existing = TRUE;
  844.       /*
  845.        * g_status.temp_end is set last character read in file
  846.        */
  847.  
  848.       if (g_status.command != DefineGrep  &&
  849.           g_status.command != DefineRegXGrep  &&
  850.           g_status.command != RepeatGrep)
  851.          rc = load_file( name, file, &file_mode, bin_length );
  852.       else {
  853.          if (g_status.sas_defined) {
  854.             rc = load_file( name, file, &file_mode, bin_length );
  855.             if (rc != ERROR) {
  856.                found_line = 1L;
  857.                rcol = 0;
  858.                if (g_status.sas_search_type == BOYER_MOORE)
  859.                   ll = search_forward( file->line_list, &found_line,
  860.                                        (size_t *)&rcol );
  861.                else
  862.                   ll = regx_search_forward( file->line_list, &found_line,
  863.                                             &rcol );
  864.                if (ll == NULL)
  865.                   rc = ERROR;
  866.                else {
  867.                   g_status.sas_rline = found_line;
  868.                   g_status.sas_rcol  = rcol;
  869.                   g_status.sas_ll    = ll;
  870.                }
  871.             }
  872.          } else
  873.             rc = ERROR;
  874.       }
  875.    } else {
  876.       if (ceh.flag == ERROR)
  877.          rc = ERROR;
  878.       else {
  879.          existing = FALSE;
  880.          file->length = 0l;
  881.          file->undo_top = file->undo_bot = NULL;
  882.          file->line_list_end = file->line_list = NULL;
  883.          file->undo_count = 0;
  884.          ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  885.          if (ll != NULL) {
  886.             ll->line  = NULL;
  887.             ll->next  = ll->prev = NULL;
  888.             ll->dirty = FALSE;
  889.             ll->len   = EOF;
  890.             file->undo_top = file->undo_bot = ll;
  891.          } else
  892.             rc = ERROR;
  893.  
  894.          ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  895.          if (ll != NULL) {
  896.             ll->line = NULL;
  897.             ll->next = ll->prev = NULL;
  898.             ll->dirty = FALSE;
  899.             ll->len   = EOF;
  900.             file->line_list_end = file->line_list = ll;
  901.          } else
  902.             rc = ERROR;
  903.          if (rc == ERROR) {
  904.             if (file->undo_top != NULL)
  905.                my_free( file->undo_top );
  906.             if (file->line_list != NULL)
  907.                my_free( file->line_list );
  908.          } else
  909.             if (file_mode == TEXT)
  910. #if defined( __UNIX__ )
  911.                file_mode = LF;
  912. #else
  913.                file_mode = CRLF;
  914. #endif
  915.       }
  916.    }
  917.  
  918.    if (rc != ERROR) {
  919.       /*
  920.        * add file into list
  921.        */
  922.       file->prev = NULL;
  923.       file->next = NULL;
  924.       if (g_status.file_list == NULL)
  925.          g_status.file_list = file;
  926.       else {
  927.          fp = g_status.current_file;
  928.          file->prev = fp;
  929.          if (fp->next)
  930.             fp->next->prev = file;
  931.          file->next = fp->next;
  932.          fp->next = file;
  933.       }
  934.  
  935.       /*
  936.        * set up all the info we need to know about a file.
  937.        */
  938.  
  939.       assert( file_mode == CRLF  ||  file_mode == LF  ||  file_mode == BINARY );
  940.       assert( strlen( name ) < (size_t)g_display.ncols );
  941.  
  942.       strcpy( file->file_name, name );
  943. #if defined( __UNIX__ )
  944.       get_fattr( name, &file->file_attrib );
  945. #else
  946.       get_fattr( name, (int *)&file->file_attrib );
  947. #endif
  948.       file->block_type  = NOTMARKED;
  949.       file->block_br    = file->block_er = 0l;
  950.       file->block_bc    = file->block_ec = 0;
  951.       file->ref_count   = 0;
  952.       file->modified    = FALSE;
  953.       file->backed_up   = FALSE;
  954.       file->new_file    = !existing;
  955.       file->next_letter = 0;
  956.       file->file_no     = ++g_status.file_count;
  957.       file->crlf        = file_mode;
  958.       g_status.current_file = file;
  959.       make_backup_fname( file );
  960.    } else if (file != NULL) {
  961.       /*
  962.        * free the line pointers and linked list of line pointers.
  963.        */
  964.       ll = file->undo_top;
  965.       while (ll != NULL) {
  966.          temp_ll = ll->next;
  967.          if (ll->line != NULL)
  968.             my_free( ll->line );
  969.          my_free( ll );
  970.          ll = temp_ll;
  971.       }
  972.  
  973.       ll = file->line_list;
  974.       while (ll != NULL) {
  975.          temp_ll = ll->next;
  976.          if (ll->line != NULL)
  977.             my_free( ll->line );
  978.          my_free( ll );
  979.          ll = temp_ll;
  980.       }
  981.  
  982. #if defined( __MSC__ )
  983.       _fheapmin( );
  984. #endif
  985.  
  986.       free( file );
  987.    }
  988.    return( rc );
  989. }
  990.  
  991.  
  992. /*
  993.  * Name:    edit_another_file
  994.  * Purpose: Bring in another file to editor.
  995.  * Date:    June 5, 1991
  996.  * Passed:  window:  pointer to current window
  997.  * Notes:   New window replaces old window.  Old window becomes invisible.
  998.  */
  999. int  edit_another_file( TDE_WIN *window )
  1000. {
  1001. #if defined( __UNIX__ )
  1002.  char fname[PATH_MAX];          /* new name for file */
  1003. #else
  1004.  char fname[MAX_COLS];          /* new name for file */
  1005.  char spdrive[_MAX_DRIVE];       /* splitpath drive buff */
  1006.  char spdir[_MAX_DIR];           /* splitpath dir buff */
  1007.  char spname[_MAX_FNAME];        /* splitpath fname buff */
  1008.  char spext[_MAX_EXT];           /* splitpath ext buff */
  1009. #endif
  1010. register TDE_WIN *win;           /* put window pointer in a register */
  1011. int  rc;
  1012. int  file_mode;
  1013. int  bin_length;
  1014.  
  1015.    win = window;
  1016.    entab_linebuff( );
  1017.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1018.       return( ERROR );
  1019.    /*
  1020.     * read in name, no default
  1021.     */
  1022.    fname[0] = '\0';
  1023.    /*
  1024.     * file name to edit
  1025.     */
  1026.    if ((rc = get_name( ed15, win->bottom_line, fname,
  1027.                  g_display.message_color )) == OK  &&  *fname != '\0') {
  1028.  
  1029. #if defined( __UNIX__ )
  1030.  
  1031.       assert( strlen( fname ) < PATH_MAX );
  1032.  
  1033.       /*
  1034.        * X_OK is defined in unistd.h and tests for execute permission
  1035.        */
  1036.       if (access( fname, X_OK ) != ERROR) {
  1037.          file_mode = BINARY;
  1038.          bin_length = g_status.file_chunk;
  1039.       } else {
  1040.          file_mode = TEXT;
  1041.          bin_length = 0;
  1042.       }
  1043. #else
  1044.  
  1045.       file_mode = TEXT;
  1046.       bin_length = 0;
  1047.  
  1048.       assert( strlen( fname ) < (size_t)g_display.ncols );
  1049.  
  1050.       _splitpath( fname, spdrive, spdir, spname, spext );
  1051.       if (stricmp( spext, ".exe" ) == 0  ||  stricmp( spext, ".com" ) == 0) {
  1052.          file_mode = BINARY;
  1053.          bin_length = g_status.file_chunk;
  1054.       }
  1055. #endif
  1056.       rc = attempt_edit_display( fname, LOCAL, file_mode, bin_length );
  1057.       if (rc == OK)
  1058.          show_avail_mem( );
  1059.    }
  1060.    return( rc );
  1061. }
  1062.  
  1063.  
  1064. /*
  1065.  * Name:    attempt_edit_display
  1066.  * Purpose: try to load then display a file
  1067.  * Date:    June 5, 1991
  1068.  * Passed:  fname:       file name to load
  1069.  *          update_type: update current window or entire screen
  1070.  *          file_mode:   BINARY or TEXT
  1071.  *          bin_len:     if opened in BINARY mode, length of binary lines
  1072.  * Notes:   When we first start the editor, we need to update the entire
  1073.  *          screen.  When we load in a new file, we only need to update
  1074.  *          the current window.
  1075.  */
  1076. int  attempt_edit_display( char *fname, int update_type, int file_mode,
  1077.                            int bin_len )
  1078. {
  1079. register int rc;
  1080. TDE_WIN *win;
  1081.  
  1082.    rc = edit_file( fname, file_mode, bin_len );
  1083.    if (rc != ERROR) {
  1084.       rc = initialize_window( );
  1085.       if (rc != ERROR) {
  1086.          win = g_status.current_window;
  1087.          if (update_type == LOCAL) {
  1088.             if (g_status.command != DefineGrep  &&
  1089.                         g_status.command != DefineRegXGrep  &&
  1090.                         g_status.command != RepeatGrep)
  1091.                redraw_current_window( win );
  1092.             show_file_count( g_status.file_count );
  1093.             show_window_count( g_status.window_count );
  1094.             show_avail_mem( );
  1095.          } else if (update_type == GLOBAL)
  1096.             redraw_screen( win );
  1097.          if (win->file_info->new_file) {
  1098.             g_status.command = AddLine;
  1099.             insert_newline( win );
  1100.             win->file_info->modified = FALSE;
  1101.          }
  1102.       }
  1103.    }
  1104.    return( rc );
  1105. }
  1106.  
  1107.  
  1108. /*
  1109.  * Name:    file_file
  1110.  * Purpose: To file the current file to disk.
  1111.  * Date:    September 17, 1991
  1112.  * Passed:  window:  pointer to current window
  1113.  */
  1114. int  file_file( TDE_WIN *window )
  1115. {
  1116.    if (save_file( window ) == OK)
  1117.       finish( window );
  1118.    return( OK );
  1119. }
  1120.  
  1121.  
  1122. /*
  1123.  * Name:    save_file
  1124.  * Purpose: To save the current file to disk.
  1125.  * Date:    June 5, 1991
  1126.  * Passed:  window:  pointer to current window
  1127.  * Notes:   If anything goes wrong, then the modified flag is set.
  1128.  *          If the file is saved successfully, then modified flag is
  1129.  *           cleared.
  1130.  */
  1131. int  save_file( TDE_WIN *window )
  1132. {
  1133. register file_infos *file;
  1134. int  rc;
  1135. line_list_ptr temp_ll;
  1136. #if defined( __UNIX__ )
  1137.  char temp[PATH_MAX+2];
  1138. #else
  1139.  char temp[MAX_COLS+2];
  1140. #endif
  1141.  
  1142.    entab_linebuff( );
  1143.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  1144.       return( ERROR );
  1145.    file = window->file_info;
  1146.    if (file->modified == FALSE)
  1147.       return( OK );
  1148.    /*
  1149.     * set up file name
  1150.     */
  1151. #if defined( __UNIX__ )
  1152.    assert( strlen( file->file_name ) < PATH_MAX );
  1153. #else
  1154.    assert( strlen( file->file_name ) < (size_t)g_display.ncols );
  1155. #endif
  1156.  
  1157.    strcpy( temp, file->file_name );
  1158.  
  1159.    /*
  1160.     * see if there was a file name - if not, then make the user
  1161.     *  supply one.
  1162.     */
  1163.    if (strlen( temp ) == 0)
  1164.       rc = save_as_file( window );
  1165.    else {
  1166.       /*
  1167.        * save the file
  1168.        */
  1169.       rc = write_to_disk( window, temp );
  1170.       if (rc != ERROR) {
  1171.          file->modified = FALSE;
  1172.          file->new_file = FALSE;
  1173.       }
  1174.    }
  1175.  
  1176.    /*
  1177.     * clear the dirty flags
  1178.     */
  1179.    if (rc == OK) {
  1180.       temp_ll = window->file_info->line_list;
  1181.       for (; temp_ll->len != EOF; temp_ll=temp_ll->next)
  1182.          temp_ll->dirty = FALSE;
  1183.       window->file_info->dirty = GLOBAL;
  1184.    }
  1185.  
  1186.    return( rc );
  1187. }
  1188.  
  1189.  
  1190. /*
  1191.  * Name:    save_backup
  1192.  * Purpose: To save a backup copy of the current file to disk.
  1193.  * Date:    June 5, 1991
  1194.  * Passed:  window:  pointer to current window
  1195.  */
  1196. int  save_backup( TDE_WIN *window )
  1197. {
  1198.    /*
  1199.     * set up file name
  1200.     */
  1201.    return( write_to_disk( window, window->file_info->backup_fname ) );
  1202. }
  1203.  
  1204.  
  1205. /*
  1206.  * Name:    save_as_file
  1207.  * Purpose: To save the current file to disk, but under a new name.
  1208.  * Date:    June 5, 1991
  1209.  * Passed:  window:  pointer to current window
  1210.  */
  1211. int  save_as_file( TDE_WIN *window )
  1212. {
  1213. int  prompt_line;
  1214. int  rc;
  1215. register TDE_WIN *win;           /* put window pointer in a register */
  1216. line_list_ptr temp_ll;
  1217. #if defined( __UNIX__ )
  1218.  char answer[PATH_MAX+2];
  1219.  chtype display_buff[MAX_COLS+2];       /* chtype is defined in curses.h */
  1220.  mode_t fattr;
  1221. #else
  1222.  char answer[MAX_COLS+2];
  1223.  char display_buff[(MAX_COLS+2)*2];
  1224.  int  fattr;
  1225. #endif
  1226.  
  1227.    win = window;
  1228.    entab_linebuff( );
  1229.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1230.       return( ERROR );
  1231.    /*
  1232.     * read in name
  1233.     */
  1234.    prompt_line = win->bottom_line;
  1235.    save_screen_line( 0, prompt_line, display_buff );
  1236.  
  1237.    answer[0] = '\0';
  1238.    /*
  1239.     * new file name:
  1240.     */
  1241.    if ((rc = get_name( utils9, prompt_line, answer,
  1242.                 g_display.message_color )) == OK  &&  *answer != '\0') {
  1243.  
  1244. #if defined( __UNIX__ )
  1245.        /*
  1246.         * make sure it is OK to overwrite any existing file
  1247.         */
  1248.       rc = get_fattr( answer, &fattr );
  1249.       if (rc == OK) {
  1250.  
  1251.          /*
  1252.           * file exists. make sure this is a regular file, first
  1253.           */
  1254.          if (S_ISREG( fattr )) {
  1255.             /*
  1256.              * overwrite existing file?
  1257.              */
  1258.             set_prompt( utils10, prompt_line );
  1259.             if (get_yn( ) != A_YES  ||
  1260.                            change_mode( answer, prompt_line ) == ERROR)
  1261.                rc = ERROR;
  1262.          } else
  1263.             rc = ERROR;
  1264.       } else
  1265.          /*
  1266.           * file name does not exist. take a chance on a valid file name.
  1267.           */
  1268.          rc = OK;
  1269.  
  1270.       if (rc != ERROR)
  1271.          rc = write_to_disk( win, answer );
  1272. #else
  1273.        /*
  1274.         * make sure it is OK to overwrite any existing file
  1275.         */
  1276.       rc = get_fattr( answer, &fattr );
  1277.       if (rc == OK) {   /* file exists */
  1278.          /*
  1279.           * overwrite existing file?
  1280.           */
  1281.          set_prompt( utils10, prompt_line );
  1282.          if (get_yn( ) != A_YES  ||
  1283.                         change_mode( answer, prompt_line ) == ERROR)
  1284.             rc = ERROR;
  1285.       }
  1286.       if (rc != ERROR)
  1287.          rc = write_to_disk( win, answer );
  1288. #endif
  1289.  
  1290.       /*
  1291.        * depending on personal taste, you may want to uncomment the next
  1292.        *  lines to clear the dirty flags.
  1293.        */
  1294. /*
  1295.  *     if (rc == OK) {
  1296.  *        temp_ll = window->file_info->line_list;
  1297.  *        for (; temp_ll->len != EOF; temp_ll=temp_ll->next)
  1298.  *           temp_ll->dirty = FALSE;
  1299.  *        window->file_info->dirty = GLOBAL;
  1300.  *     }
  1301.  */
  1302.    }
  1303.    restore_screen_line( 0, prompt_line, display_buff );
  1304.    return( rc );
  1305. }
  1306.  
  1307.  
  1308. #if defined( __UNIX__ )
  1309. /*
  1310.  **********************************************************************
  1311.  ******************************  PART 1  ******************************
  1312.  **********************************************************************
  1313.  *
  1314.  * Let's try to make unix have the look and feel of a PC.
  1315.  */
  1316.  
  1317.  
  1318. /*
  1319.  * Name:    make_backup_fname
  1320.  * Purpose: insert a .bak to back of UNIX file name
  1321.  * Date:    November 13, 1993
  1322.  * Passed:  file: information allowing access to the current file
  1323.  */
  1324. void make_backup_fname( file_infos *file )
  1325. {
  1326. char *p;
  1327. int  i;
  1328. int  len;
  1329. char temp[PATH_MAX+2];
  1330.  
  1331.    /*
  1332.     * if this is a new file then don't create a backup - can't backup
  1333.     *   a nonexisting file.
  1334.     */
  1335.    if (file->new_file)
  1336.       file->backed_up = TRUE;
  1337.  
  1338.    /*
  1339.     * find the file name extension if it exists
  1340.     */
  1341.    else {
  1342.       assert( strlen( file->file_name ) < PATH_MAX );
  1343.  
  1344.       strcpy( temp, file->file_name );
  1345.       len = strlen( temp );
  1346.       for (i=len, p=temp + len; i>=0; i--) {
  1347.  
  1348.          /*
  1349.           * we found the '.' extension character.  get out
  1350.           */
  1351.          if (*p == '.')
  1352.             break;
  1353.  
  1354.          /*
  1355.           * we're at the beginning of the string -  no directory char was
  1356.           *  found.  set the pointer to the beginning of file name string.
  1357.           */
  1358.          else if (i == 0) {
  1359.             p = temp + len;
  1360.             break;
  1361.          } else if (*p == '/') {
  1362.             /*
  1363.              * we found the directory character.
  1364.              */
  1365.             p = temp + len;
  1366.             break;
  1367.          }
  1368.          --p;
  1369.       }
  1370.  
  1371.       assert( strlen( temp ) + 5 < PATH_MAX );
  1372.  
  1373.       strcpy( p, ".bak" );
  1374.       strcpy( file->backup_fname, temp );
  1375.    }
  1376. }
  1377.  
  1378.  
  1379. /*
  1380.  * Name:    write_to_disk
  1381.  * Purpose: To write file from memory to disk
  1382.  * Date:    November 13, 1993
  1383.  * Passed:  window:  pointer to current window
  1384.  *          fname:   file name to save on disk
  1385.  */
  1386. int  write_to_disk( TDE_WIN *window, char *fname )
  1387. {
  1388. register file_infos *file;
  1389. int  rc;
  1390. int  prompt_line;
  1391. char temp[MAX_COLS+2];
  1392. char answer[PATH_MAX+2];
  1393. mode_t fattr;
  1394. chtype display_buff[MAX_COLS+2];        /* chtype is defined in curses.h */
  1395.  
  1396.    file = window->file_info;
  1397.    prompt_line = window->bottom_line;
  1398.  
  1399.    /*
  1400.     * set up file name
  1401.     */
  1402.    assert( strlen( fname ) < PATH_MAX );
  1403.  
  1404.    strcpy( answer, fname );
  1405.    save_screen_line( 0, prompt_line, display_buff );
  1406.    eol_clear( 0, prompt_line, g_display.message_color );
  1407.  
  1408.    /*
  1409.     * saving
  1410.     */
  1411.    if (strlen( answer ) > 50 )
  1412.       answer[50] ='\0';
  1413.    combine_strings( temp, utils6, answer, "'" );
  1414.    s_output( temp, prompt_line, 0, g_display.message_color );
  1415.    strcpy( answer, fname );
  1416.    if ((rc = hw_save( answer, file, 1L, file->length, NOTMARKED )) == ERROR) {
  1417.       if (ceh.flag != ERROR) {
  1418.          if (get_fattr( answer, &fattr ) == OK &&
  1419.                                     !(fattr & (S_IWUSR | S_IWGRP | S_IWOTH)))
  1420.             /*
  1421.              * file is read only
  1422.              */
  1423.             combine_strings( temp, utils7a, answer, utils7b );
  1424.          else
  1425.             /*
  1426.              * cannot write to
  1427.              */
  1428.             combine_strings( temp, utils8, answer, "'" );
  1429.          error( WARNING, prompt_line, temp );
  1430.       }
  1431.    }
  1432.    restore_screen_line( 0, prompt_line, display_buff );
  1433.    return( rc );
  1434. }
  1435.  
  1436.  
  1437. /*
  1438.  * Name:    search_and_seize
  1439.  * Purpose: search files for a pattern
  1440.  * Date:    November 13, 1993
  1441.  * Passed:  window:  pointer to current window
  1442.  * Notes:   New window replaces old window.  Old window becomes invisible.
  1443.  */
  1444. int  search_and_seize( TDE_WIN *window )
  1445. {
  1446. char name[PATH_MAX];            /* new name for file */
  1447. char temp[PATH_MAX];            /* new name for file */
  1448. char *eos;
  1449. char searching[MAX_COLS];       /* buffer for displaying file name */
  1450. int  file_mode;
  1451. mode_t file_attr;
  1452. UNIX_DTA unix_dta;
  1453. struct stat fstat;
  1454. int  bin_length;
  1455. int  i;
  1456. int  update_type;
  1457. char *tokens;
  1458. register int rc = ERROR;
  1459. register TDE_WIN *win;           /* put window pointer in a register */
  1460. int  bottom_line;
  1461. chtype display_buff[MAX_COLS+2];
  1462.  
  1463.    win = window;
  1464.    update_type = win == NULL ? GLOBAL : LOCAL;
  1465.    if (update_type == LOCAL) {
  1466.       if (!g_status.sas_defined ||  g_status.command == DefineGrep ||
  1467.                               g_status.command == DefineRegXGrep) {
  1468.  
  1469.          /*
  1470.           * prompt for the search pattern and the seize path.
  1471.           *   initialize all this stuff.
  1472.           */
  1473.          if (g_status.command == DefineGrep)
  1474.             g_status.sas_search_type = BOYER_MOORE;
  1475.          else
  1476.             g_status.sas_search_type = REG_EXPRESSION;
  1477.  
  1478.          if (g_status.sas_search_type == BOYER_MOORE) {
  1479.             *sas_bm.pattern = '\0';
  1480.             if (get_name( win16a, win->bottom_line, (char *)sas_bm.pattern,
  1481.                              g_display.message_color ) == ERROR)
  1482.                return( ERROR );
  1483.             if (*sas_bm.pattern == '\0')
  1484.                return( ERROR );
  1485.          } else {
  1486.             *sas_regx.pattern = '\0';
  1487.             if (get_name( win16b, win->bottom_line, (char *)sas_regx.pattern,
  1488.                              g_display.message_color ) == ERROR)
  1489.                return( ERROR );
  1490.             if (*sas_regx.pattern == '\0')
  1491.                return( ERROR );
  1492.             else
  1493.                strcpy( (char *)regx.pattern, (char *)sas_regx.pattern );
  1494.          }
  1495.          *g_status.sas_tokens = '\0';
  1496.          if (get_name( win17, win->bottom_line, g_status.sas_tokens,
  1497.                           g_display.message_color ) == ERROR)
  1498.             return( ERROR );
  1499.          i = 0;
  1500.          tokens = strtok( g_status.sas_tokens, SAS_DELIMITERS );
  1501.          while (tokens != NULL) {
  1502.             g_status.sas_arg_pointers[i++] = tokens;
  1503.             tokens = strtok( NULL, SAS_DELIMITERS );
  1504.          }
  1505.          if (i == 0)
  1506.             return( ERROR );
  1507.          g_status.sas_arg_pointers[i] = NULL;
  1508.          g_status.sas_argc = i;
  1509.          g_status.sas_arg = 0;
  1510.          g_status.sas_argv = g_status.sas_arg_pointers;
  1511.          g_status.sas_found_first = FALSE;
  1512.          if (g_status.command == DefineGrep) {
  1513.             g_status.sas_defined = TRUE;
  1514.             bm.search_defined = sas_bm.search_defined = OK;
  1515.             build_boyer_array( );
  1516.          } else {
  1517.             i = build_nfa( );
  1518.             if (i == OK) {
  1519.                g_status.sas_defined = TRUE;
  1520.                regx.search_defined = sas_regx.search_defined = OK;
  1521.             } else
  1522.                g_status.sas_defined = FALSE;
  1523.          }
  1524.       }
  1525.       bottom_line = win->bottom_line;
  1526.    } else
  1527.       bottom_line = g_display.nlines;
  1528.    if (g_status.sas_defined && g_status.sas_arg < g_status.sas_argc) {
  1529.       if (win != NULL) {
  1530.          entab_linebuff( );
  1531.          un_copy_line( win->ll, win, TRUE );
  1532.       }
  1533.  
  1534.       /*
  1535.        * while we haven't found a valid file, search thru the command
  1536.        * line path.
  1537.        * we may have an invalid file name when we finish matching all
  1538.        * files according to a pattern.  then, we need to go to the next
  1539.        * command line argument if it exists.
  1540.        */
  1541.       while (rc == ERROR && g_status.sas_arg < g_status.sas_argc) {
  1542.  
  1543.          /*
  1544.           * if we haven't starting searching for a file, check to see if
  1545.           * the file is a valid file name.  if no file is found, then let's
  1546.           * see if we can find according to a search pattern.
  1547.           */
  1548.          if (g_status.sas_found_first == FALSE) {
  1549.  
  1550.             assert( strlen( g_status.sas_argv[g_status.sas_arg] )
  1551.                         < PATH_MAX );
  1552.  
  1553.             strcpy( name, g_status.sas_argv[g_status.sas_arg] );
  1554.             rc = get_fattr( name, &file_attr );
  1555.  
  1556.             /*
  1557.              * file exists.
  1558.              */
  1559.             if (rc == OK)
  1560.                ++g_status.sas_arg;
  1561.  
  1562.             /*
  1563.              * if we get this far, we may have a path name.
  1564.              */
  1565.             else if (rc != ERROR) {
  1566.  
  1567.                rc = OK;
  1568.                if ((g_status.sas_dp = opendir( name )) == NULL)
  1569.                   rc = ERROR;
  1570.                else {
  1571.  
  1572.                   /*
  1573.                    * eos == end of stem
  1574.                    */
  1575.                   strcpy( temp, name );
  1576.                   i = strlen( temp );
  1577.                   if (temp[i-1] != '/')
  1578.                      strcat( temp, "/" );
  1579.                   eos = temp + strlen( temp );
  1580.  
  1581.                   while ((rc = my_findnext( g_status.sas_dp, &unix_dta )) == OK) {
  1582.                      strcpy( eos, unix_dta.fname );
  1583.                      if (stat( eos, &fstat ) >= 0  && S_ISREG( fstat.st_mode ))
  1584.                         break;
  1585.                   }
  1586.                   if (rc == ERROR) {
  1587.                      closedir( g_status.sas_dp );
  1588.                      g_status.sas_dp = NULL;
  1589.                   }
  1590.                }
  1591.  
  1592.                /*
  1593.                 * if we found a file using wildcard characters,
  1594.                 * set the g_status.sas_found_first flag to true so we can
  1595.                 * find the next matching file.  we need to save the
  1596.                 * pathname stem so we know which directory we are working in.
  1597.                 */
  1598.                if (rc == OK) {
  1599.                   g_status.found_first = TRUE;
  1600.  
  1601.                   assert( strlen( temp ) < PATH_MAX );
  1602.  
  1603.                   strcpy( name, temp );
  1604.  
  1605.                   /*
  1606.                    * g_status.sas_path includes the '/' at end of path
  1607.                    */
  1608.                   *eos = '\0';
  1609.                   strcpy( g_status.sas_path, temp );
  1610.                } else {
  1611.                   ++g_status.sas_arg;
  1612.                   if (win != NULL)
  1613.                      /*
  1614.                       * invalid path or file name
  1615.                       */
  1616.                      error( WARNING, win->bottom_line, win8 );
  1617.                }
  1618.             } else if (rc == ERROR)
  1619.                ++g_status.sas_arg;
  1620.          } else {
  1621.  
  1622.             /*
  1623.              * we already found one file with wild card characters,
  1624.              * find the next matching file.
  1625.              */
  1626.             strcpy( temp, g_status.sas_path );
  1627.             eos = temp + strlen( temp );
  1628.  
  1629.             while ((rc = my_findnext( g_status.sas_dp, &unix_dta )) == OK) {
  1630.                strcpy( eos, unix_dta.fname );
  1631.                if (stat( eos, &fstat ) >= 0  &&  S_ISREG( fstat.st_mode ))
  1632.                   break;
  1633.             }
  1634.  
  1635.             if (rc == OK) {
  1636.  
  1637.                assert( strlen( temp ) < PATH_MAX );
  1638.  
  1639.                strcpy( name, temp );
  1640.             } else {
  1641.                g_status.sas_found_first = FALSE;
  1642.                ++g_status.sas_arg;
  1643.                if (g_status.sas_dp != NULL)
  1644.                   closedir( g_status.sas_dp );
  1645.             }
  1646.          }
  1647.  
  1648.          /*
  1649.           * if everything is everything so far, set up the file
  1650.           * and window structures and bring the file into the editor.
  1651.           */
  1652.          if (rc == OK) {
  1653.  
  1654.             assert( strlen( win19 ) + strlen( name ) < g_display.ncols );
  1655.  
  1656.             strcpy( searching, win19 );
  1657.             strcpy( temp, unix_dta.fname );
  1658.             if (strlen( temp ) > 50)
  1659.                temp[50] = '\0';
  1660.             strcat( searching, temp );
  1661.             save_screen_line( 0, bottom_line, display_buff );
  1662.             set_prompt( searching, bottom_line );
  1663.             file_mode = TEXT;
  1664.             bin_length = 0;
  1665.  
  1666.             assert( strlen( name ) < PATH_MAX );
  1667.  
  1668.             if (access( name, X_OK ) != ERROR) {
  1669.                file_mode = BINARY;
  1670.                bin_length = g_status.file_chunk;
  1671.             }
  1672.  
  1673.             rc = attempt_edit_display( name, update_type, file_mode, bin_length );
  1674.             if (rc == OK)
  1675.                show_avail_mem( );
  1676.             restore_screen_line( 0, bottom_line, display_buff );
  1677.  
  1678.             if (rc == OK) {
  1679.                win = g_status.current_window;
  1680.                bin_offset_adjust( win, g_status.sas_rline );
  1681.                find_adjust( win, g_status.sas_ll, g_status.sas_rline,
  1682.                             g_status.sas_rcol );
  1683.                make_ruler( win );
  1684.                show_ruler( win );
  1685.                show_ruler_pointer( win );
  1686.                show_window_header( win );
  1687.                if (win->vertical)
  1688.                   show_vertical_separator( win );
  1689.                win->file_info->dirty = LOCAL;
  1690.             }
  1691.          }
  1692.  
  1693.          /*
  1694.           * either there are no more matching files or we had an
  1695.           * invalid file name, set rc to ERROR and let's look at the
  1696.           * next file name or pattern on the command line.
  1697.           */
  1698.          else
  1699.             rc = ERROR;
  1700.       }
  1701.    }
  1702.    if (rc == ERROR &&  g_status.sas_arg >= g_status.sas_argc  && win != NULL)
  1703.       /*
  1704.        * no more files to load
  1705.        */
  1706.       error( WARNING, win->bottom_line, win9 );
  1707.    return( rc );
  1708. }
  1709.  
  1710.  
  1711. /*
  1712.  * Name:    edit_next_file
  1713.  * Purpose: edit next file on command line.
  1714.  * Date:    November 13, 1993
  1715.  * Passed:  window:  pointer to current window
  1716.  * Notes:   New window replaces old window.  Old window becomes invisible.
  1717.  */
  1718. int  edit_next_file( TDE_WIN *window )
  1719. {
  1720. char name[PATH_MAX+2];  /* new name for file */
  1721. char temp[PATH_MAX+2];  /* temp for new name for file */
  1722. char *eos;              /* end of string */
  1723. mode_t  file_type;
  1724. UNIX_DTA unix_dta;
  1725. struct stat fstat;
  1726. int  file_mode;
  1727. int  bin_length;
  1728. int  i;
  1729. int  update_type;
  1730. register int rc = ERROR;
  1731. register TDE_WIN *win;           /* put window pointer in a register */
  1732.  
  1733.    win = window;
  1734.    update_type = win == NULL ? GLOBAL : LOCAL;
  1735.    if (g_status.arg < g_status.argc) {
  1736.       if (win != NULL) {
  1737.          entab_linebuff( );
  1738.          if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1739.             return( ERROR );
  1740.       }
  1741.  
  1742.       /*
  1743.        * while we haven't found a valid file, search thru the command
  1744.        * line path.
  1745.        * we may have an invalid file name when we finish matching all
  1746.        * files according to a pattern.  then, we need to go to the next
  1747.        * command line argument if it exists.
  1748.        */
  1749.       while (rc == ERROR && g_status.arg < g_status.argc) {
  1750.  
  1751.          /*
  1752.           * if we haven't starting searching for a file, check to see if
  1753.           * the file is a valid file name.  if no file is found, then let's
  1754.           * see if we can find according to a search pattern.
  1755.           */
  1756.          if (g_status.found_first == FALSE) {
  1757.  
  1758.             assert( strlen( g_status.argv[g_status.arg] ) < PATH_MAX );
  1759.  
  1760.             strcpy( name, g_status.argv[g_status.arg] );
  1761.             rc = get_fattr( name, &file_type );
  1762.  
  1763.             /*
  1764.              * file exists
  1765.              */
  1766.             if (rc == OK)
  1767.                ++g_status.arg;
  1768.  
  1769.             /*
  1770.              * if we get this far, we may have a path name.
  1771.              */
  1772.             else {
  1773.  
  1774.                rc = OK;
  1775.  
  1776.                /*
  1777.                 * try to open arg as a directory name.
  1778.                 */
  1779.                if ((g_status.dp = opendir( name )) == NULL) {
  1780.  
  1781.                   /*
  1782.                    * failed as a directory name.  now, try to open a new file
  1783.                    */
  1784.                   ++g_status.arg;
  1785.                } else {
  1786.  
  1787.                   /*
  1788.                    * eos == end of stem
  1789.                    */
  1790.                   strcpy( temp, name );
  1791.                   i = strlen( temp );
  1792.                   if (temp[i-1] != '/')
  1793.                      strcat( temp, "/" );
  1794.                   eos = temp + strlen( temp );
  1795.  
  1796.                   while ((rc = my_findnext( g_status.dp, &unix_dta )) == OK) {
  1797.                      strcpy( eos, unix_dta.fname );
  1798.                      if (stat( eos, &fstat ) >= 0  && S_ISREG( fstat.st_mode ))
  1799.                         break;
  1800.                   }
  1801.                   if (rc == ERROR) {
  1802.                      closedir( g_status.dp );
  1803.                      g_status.dp = NULL;
  1804.                      ++g_status.arg;
  1805.                      if (win != NULL)
  1806.                         /*
  1807.                          * invalid path or file name
  1808.                          */
  1809.                         error( WARNING, win->bottom_line, win8 );
  1810.                   } else {
  1811.  
  1812.                   /*
  1813.                    * if we found a file using wildcard characters,
  1814.                    * set the g_status.found_first flag to true so we can
  1815.                    * find the next matching file.  we need to save the
  1816.                    * pathname stem so we know which directory we are working in.
  1817.                    */
  1818.                      g_status.found_first = TRUE;
  1819.  
  1820.                      assert( strlen( temp ) < PATH_MAX );
  1821.  
  1822.                      strcpy( name, temp );
  1823.  
  1824.                      /*
  1825.                       * g_status.path includes the '/' at end of path
  1826.                       */
  1827.                      *eos = '\0';
  1828.                      strcpy( g_status.path, temp );
  1829.                   }
  1830.                }
  1831.             }
  1832.          } else {
  1833.  
  1834.             /*
  1835.              * we already found one file with wild card characters,
  1836.              * find the next matching file.
  1837.              */
  1838.             strcpy( temp, g_status.path );
  1839.             eos = temp + strlen( temp );
  1840.  
  1841.             while ((rc = my_findnext( g_status.dp, &unix_dta )) == OK) {
  1842.                strcpy( eos, unix_dta.fname );
  1843.                if (stat( eos, &fstat ) >= 0  &&  S_ISREG( fstat.st_mode ))
  1844.                   break;
  1845.             }
  1846.  
  1847.             if (rc == OK) {
  1848.  
  1849.                assert( strlen( temp ) < PATH_MAX );
  1850.  
  1851.                strcpy( name, temp );
  1852.             } else {
  1853.                g_status.found_first = FALSE;
  1854.                ++g_status.arg;
  1855.                if (g_status.dp != NULL)
  1856.                   closedir( g_status.dp );
  1857.             }
  1858.          }
  1859.  
  1860.          /*
  1861.           * if everything is everything so far, set up the file
  1862.           * and window structures and bring the file into the editor.
  1863.           */
  1864.          if (rc == OK) {
  1865.             file_mode = g_status.file_mode;
  1866.             bin_length = g_status.file_chunk;
  1867.  
  1868.             assert( strlen( name ) < PATH_MAX );
  1869.  
  1870.             if (access( name, X_OK ) != ERROR) {
  1871.                file_mode = BINARY;
  1872.                bin_length = g_status.file_chunk;
  1873.             }
  1874.  
  1875.             rc = attempt_edit_display( name, update_type, file_mode, bin_length );
  1876.             if (rc == OK)
  1877.                show_avail_mem( );
  1878.          }
  1879.  
  1880.          /*
  1881.           * either there are no more matching files or we had an
  1882.           * invalid file name, set rc to ERROR and let's look at the
  1883.           * next file name or pattern on the command line.
  1884.           */
  1885.          else
  1886.             rc = ERROR;
  1887.       }
  1888.    }
  1889.    if (rc == ERROR  &&  g_status.arg >= g_status.argc  &&  win != NULL)
  1890.       /*
  1891.        * no more files to load
  1892.        */
  1893.       error( WARNING, win->bottom_line, win9 );
  1894.    return( rc );
  1895. }
  1896.  
  1897.  
  1898. /*
  1899.  * Name:    hw_fattrib
  1900.  * Purpose: To determine the current file attributes.
  1901.  * Date:    November 13, 1993
  1902.  * Passed:  name: name of file to be checked
  1903.  * Returns: use the function in the tdeasm file to get the DOS file
  1904.  *          attributes.  get_fattr() returns 0 or OK if no error.
  1905.  */
  1906. int  hw_fattrib( char *name )
  1907. {
  1908. register int rc;
  1909. mode_t fattr;
  1910.  
  1911.    rc = get_fattr( name, &fattr );
  1912.    return( rc == OK ? rc : ERROR );
  1913. }
  1914.  
  1915.  
  1916. /*
  1917.  * Name:    change_mode
  1918.  * Purpose: To prompt for file access mode.
  1919.  * Date:    November 13, 1993
  1920.  * Passed:  name:  name of file
  1921.  *          line:  line to display message
  1922.  * Returns: OK if file could be changed
  1923.  *          ERROR otherwise
  1924.  * Notes:   function is used to change file attributes for save_as function.
  1925.  */
  1926. int  change_mode( char *name, int line )
  1927. {
  1928. mode_t  fattr;
  1929. register int rc;
  1930. chtype display_buff[MAX_COLS+2];
  1931.  
  1932.    rc = get_fattr( name, &fattr );
  1933.    if (rc == OK  &&  !(fattr & S_IWUSR)) {
  1934.       /*
  1935.        * file cannot be written
  1936.        */
  1937.       save_screen_line( 0, line, display_buff );
  1938.       /*
  1939.        * file is write protected. overwrite anyway (y/n)?
  1940.        */
  1941.       set_prompt( main6, line );
  1942.       if (get_yn( ) != A_YES)
  1943.          rc = ERROR;
  1944.       else if (set_fattr( name, fattr & S_IWUSR & S_IWGRP & S_IWOTH ) != OK)
  1945.          rc = ERROR;
  1946.       restore_screen_line( 0, line, display_buff );
  1947.    }
  1948.    return( rc );
  1949. }
  1950.  
  1951.  
  1952. /*
  1953.  * Name:    change_fattr
  1954.  * Purpose: To change the file attributes
  1955.  * Date:    December 31, 1991
  1956.  * Passed:  window:  pointer to current window
  1957.  */
  1958. int  change_fattr( TDE_WIN *window )
  1959. {
  1960. file_infos *file;
  1961. TDE_WIN *wp;
  1962. int  prompt_line;
  1963. register int ok;
  1964. mode_t  fattr;
  1965. char *s;
  1966. int  rc;
  1967. char answer[MAX_COLS+2];
  1968. chtype display_buff[MAX_COLS+2];
  1969.  
  1970.    prompt_line = window->bottom_line;
  1971.    save_screen_line( 0, prompt_line, display_buff );
  1972.  
  1973.    answer[0] = '\0';
  1974.    /*
  1975.     * enter new file attributes
  1976.     */
  1977.    rc = OK;
  1978.    if ((ok = get_name( utils14, prompt_line, answer,
  1979.                        g_display.message_color )) == OK) {
  1980.       if (*answer != '\0') {
  1981.          fattr = window->file_info->file_attrib;
  1982.  
  1983.          /*
  1984.           * turn off rwx for user, group, and other.
  1985.           */
  1986.          fattr &= ~S_IRWXU;
  1987.          fattr &= ~S_IRWXG;
  1988.          fattr &= ~S_IRWXO;
  1989.          s = answer;
  1990.  
  1991.          while (ok = toupper( *s )) {
  1992.             switch (*s) {
  1993.                case L_UNIX_READ :
  1994.                   fattr |= S_IRUSR;
  1995.                   fattr |= S_IRGRP;
  1996.                   fattr |= S_IROTH;
  1997.                   break;
  1998.                case L_UNIX_WRITE :
  1999.                   fattr |= S_IWUSR;
  2000.                   fattr |= S_IWGRP;
  2001.                   fattr |= S_IWOTH;
  2002.                   break;
  2003.                case L_UNIX_EXECUTE :
  2004.                   fattr |= S_IXUSR;
  2005.                   fattr |= S_IXGRP;
  2006.                   fattr |= S_IXOTH;
  2007.                   break;
  2008.                default :
  2009.                   break;
  2010.             }
  2011.             s++;
  2012.          }
  2013.          file = window->file_info;
  2014.          if (set_fattr( file->file_name, fattr ) == ERROR) {
  2015.             /*
  2016.              * new file attributes not set
  2017.              */
  2018.             error( WARNING, prompt_line, utils15 );
  2019.             rc = ERROR;
  2020.          } else {
  2021.             file->file_attrib = fattr;
  2022.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  2023.                if (wp->file_info == file && wp->visible)
  2024.                   show_window_fname( wp );
  2025.             }
  2026.          }
  2027.       }
  2028.    } else
  2029.       rc = ERROR;
  2030.    restore_screen_line( 0, prompt_line, display_buff );
  2031.    return( rc );
  2032. }
  2033.  
  2034.  
  2035. /*
  2036.  * Name:    get_fattr
  2037.  * Purpose: To get unix file attributes
  2038.  * Date:    November 13, 1993
  2039.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  2040.  *          fattr: pointer to file attributes
  2041.  * Returns: OK if successful, ERROR if error
  2042.  * Notes:   Use stat( ) to get file attributes.
  2043.  */
  2044. int  get_fattr( char *fname, mode_t *fattr )
  2045. {
  2046. int  rc;                /* return code */
  2047. struct stat fstat;
  2048.  
  2049.    assert( fname != NULL  &&  fattr != NULL);
  2050.  
  2051.    rc = OK;
  2052.    ceh.flag = OK;
  2053.    if (stat( fname, &fstat) != ERROR)
  2054.       *fattr = fstat.st_mode;
  2055.    else
  2056.       rc = ERROR;
  2057.    if (ceh.flag == ERROR)
  2058.       rc = ERROR;
  2059.    return( rc );
  2060. }
  2061.  
  2062.  
  2063. /*
  2064.  * Name:    set_fattr
  2065.  * Purpose: To set unix file attributes
  2066.  * Date:    November 13, 1993
  2067.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  2068.  *          fattr: mode_t file attributes
  2069.  * Returns: 0 if successfull, non zero if not
  2070.  * Notes:   Use chmod( ) function to set file attributes.  To change a
  2071.  *           file mode, the effective user ID of the process must equal the
  2072.  *           owner of the file, or be a superuser.
  2073.  */
  2074. int  set_fattr( char *fname, mode_t fattr )
  2075. {
  2076. int  rc;                /* return code */
  2077.  
  2078.    assert( fname != NULL );
  2079.  
  2080.    ceh.flag = OK;
  2081.    rc = OK;
  2082.    if (chmod( fname, fattr ) == ERROR)
  2083.       rc = ERROR;
  2084.    if (ceh.flag == ERROR)
  2085.       rc = ERROR;
  2086.    return( rc );
  2087. }
  2088.  
  2089.  
  2090. /*
  2091.  * Name:    get_current_directory
  2092.  * Purpose: get current directory
  2093.  * Date:    November 13, 1993
  2094.  * Passed:  path:  pointer to buffer to store path
  2095.  *          drive: drive to get current directory
  2096.  * Notes:   use simple DOS interrupt
  2097.  */
  2098. int  get_current_directory( char *path, size_t path_size )
  2099. {
  2100. register int  rc;
  2101.  
  2102.    assert( path != NULL );
  2103.  
  2104.    rc = OK;
  2105.    ceh.flag = OK;
  2106.    if (getcwd( path, path_size ) == NULL)
  2107.       rc = ERROR;
  2108.    if (ceh.flag == ERROR)
  2109.       rc = ERROR;
  2110.    return( rc );
  2111. }
  2112.  
  2113.  
  2114. /*
  2115.  * Name:    set_current_directory
  2116.  * Purpose: set current directory
  2117.  * Date:    November 13, 1993
  2118.  * Passed:  new_path: directory path, which may include drive letter
  2119.  * Notes:   use simple DOS interrupt
  2120.  */
  2121. int  set_current_directory( char *new_path )
  2122. {
  2123. register int  rc;
  2124.  
  2125.    assert( new_path != NULL );
  2126.  
  2127.    rc = OK;
  2128.    ceh.flag = OK;
  2129.    if( chdir( new_path ) == ERROR)
  2130.       rc = ERROR;
  2131.    if (ceh.flag == ERROR)
  2132.       rc = ERROR;
  2133.    return( rc );
  2134. }
  2135.  
  2136. #else
  2137. /*
  2138.  **********************************************************************
  2139.  ******************************  PART 2  ******************************
  2140.  **********************************************************************
  2141.  *
  2142.  * Calls to BIOS and writes to PC hardware.
  2143.  */
  2144.  
  2145.  
  2146. /*
  2147.  * Name:    make_backup_fname
  2148.  * Purpose: add .bak to file name
  2149.  * Date:    January 6, 1992
  2150.  * Passed:  file: information allowing access to the current file
  2151.  */
  2152. void make_backup_fname( file_infos *file )
  2153. {
  2154. char *p;
  2155. int  i;
  2156. int  len;
  2157. char temp[MAX_COLS+2];
  2158.  
  2159.    /*
  2160.     * if this is a new file then don't create a backup - can't backup
  2161.     *   a nonexisting file.
  2162.     */
  2163.    if (file->new_file)
  2164.       file->backed_up = TRUE;
  2165.  
  2166.    /*
  2167.     * find the file name extension if it exists
  2168.     */
  2169.    else {
  2170.       assert( strlen( file->file_name ) < (size_t)g_display.ncols );
  2171.  
  2172.       strcpy( temp, file->file_name );
  2173.       len = strlen( temp );
  2174.       for (i=len, p=temp + len; i>=0; i--) {
  2175.  
  2176.          /*
  2177.           * we found the '.' extension character.  get out
  2178.           */
  2179.          if (*p == '.')
  2180.             break;
  2181.  
  2182.          /*
  2183.           * we found the drive or directory character.  no extension so
  2184.           *  set the pointer to the end of file name string.
  2185.           */
  2186.          else if (*p == '\\' || *p == ':') {
  2187.             p = temp + len;
  2188.             break;
  2189.  
  2190.          /*
  2191.           * we're at the beginning of the string - no '.', drive, or directory
  2192.           *  char was found.  set the pointer to the end of file name string.
  2193.           */
  2194.          } else if (i == 0) {
  2195.             p = temp + len;
  2196.             break;
  2197.          }
  2198.          --p;
  2199.       }
  2200.       assert( strlen( temp ) < (size_t)g_display.ncols );
  2201.       strcpy( p, ".bak" );
  2202.       strcpy( file->backup_fname, temp );
  2203.    }
  2204. }
  2205.  
  2206.  
  2207. /*
  2208.  * Name:    write_to_disk
  2209.  * Purpose: To write file from memory to disk
  2210.  * Date:    June 5, 1991
  2211.  * Passed:  window:  pointer to current window
  2212.  *          fname:   file name to save on disk
  2213.  */
  2214. int  write_to_disk( TDE_WIN *window, char *fname )
  2215. {
  2216. register file_infos *file;
  2217. int  rc;
  2218. int  prompt_line;
  2219. char temp[MAX_COLS+2];
  2220. char answer[MAX_COLS+2];
  2221. char display_buff[(MAX_COLS+2)*2];
  2222. int  fattr;
  2223.  
  2224.    file = window->file_info;
  2225.    prompt_line = window->bottom_line;
  2226.  
  2227.    /*
  2228.     * set up file name
  2229.     */
  2230.    assert( strlen( fname ) < (size_t)g_display.ncols );
  2231.  
  2232.    strcpy( answer, fname );
  2233.    save_screen_line( 0, prompt_line, display_buff );
  2234.    eol_clear( 0, prompt_line, g_display.message_color );
  2235.  
  2236.    /*
  2237.     * saving
  2238.     */
  2239.    combine_strings( temp, utils6, answer, "'" );
  2240.    s_output( temp, prompt_line, 0, g_display.message_color );
  2241.    if ((rc = hw_save( answer, file, 1L, file->length, NOTMARKED )) == ERROR) {
  2242.       if (ceh.flag != ERROR) {
  2243.          if (get_fattr( answer, &fattr ) == OK && fattr & READ_ONLY)
  2244.             /*
  2245.              * file is read only
  2246.              */
  2247.             combine_strings( temp, utils7a, answer, utils7b );
  2248.          else
  2249.             /*
  2250.              * cannot write to
  2251.              */
  2252.             combine_strings( temp, utils8, answer, "'" );
  2253.          error( WARNING, prompt_line, temp );
  2254.       }
  2255.    }
  2256.    restore_screen_line( 0, prompt_line, display_buff );
  2257.    return( rc );
  2258. }
  2259.  
  2260.  
  2261. /*
  2262.  * Name:    search_and_seize
  2263.  * Purpose: search files for a pattern
  2264.  * Date:    October 31, 1992
  2265.  * Passed:  window:  pointer to current window
  2266.  * Notes:   New window replaces old window.  Old window becomes invisible.
  2267.  */
  2268. int  search_and_seize( TDE_WIN *window )
  2269. {
  2270. char name[MAX_COLS];            /* new name for file */
  2271. char searching[MAX_COLS];       /* buffer for displaying file name */
  2272. char spdrive[_MAX_DRIVE];       /* splitpath drive buff */
  2273. char spdir[_MAX_DIR];           /* splitpath dir buff */
  2274. char spname[_MAX_FNAME];        /* splitpath fname buff */
  2275. char spext[_MAX_EXT];           /* splitpath ext buff */
  2276. int  file_mode;
  2277. int  bin_length;
  2278. int  i;
  2279. int  update_type;
  2280. char *tokens;
  2281. register int rc = ERROR;
  2282. register TDE_WIN *win;           /* put window pointer in a register */
  2283. int  bottom_line;
  2284. char display_buff[(MAX_COLS+2)*2];
  2285.  
  2286.    win = window;
  2287.    update_type = win == NULL ? GLOBAL : LOCAL;
  2288.    if (update_type == LOCAL) {
  2289.       if (!g_status.sas_defined ||  g_status.command == DefineGrep ||
  2290.                               g_status.command == DefineRegXGrep) {
  2291.  
  2292.          /*
  2293.           * prompt for the search pattern and the seize path.
  2294.           *   initialize all this stuff.
  2295.           */
  2296.          if (g_status.command == DefineGrep)
  2297.             g_status.sas_search_type = BOYER_MOORE;
  2298.          else
  2299.             g_status.sas_search_type = REG_EXPRESSION;
  2300.  
  2301.          if (g_status.sas_search_type == BOYER_MOORE) {
  2302.             *sas_bm.pattern = '\0';
  2303.             if (get_name( win16a, win->bottom_line, (char *)sas_bm.pattern,
  2304.                              g_display.message_color ) == ERROR)
  2305.                return( ERROR );
  2306.             if (*sas_bm.pattern == '\0')
  2307.                return( ERROR );
  2308.          } else {
  2309.             *sas_regx.pattern = '\0';
  2310.             if (get_name( win16b, win->bottom_line, (char *)sas_regx.pattern,
  2311.                              g_display.message_color ) == ERROR)
  2312.                return( ERROR );
  2313.             if (*sas_regx.pattern == '\0')
  2314.                return( ERROR );
  2315.             else
  2316.                strcpy( (char *)regx.pattern, (char *)sas_regx.pattern );
  2317.          }
  2318.          *g_status.sas_tokens = '\0';
  2319.          if (get_name( win17, win->bottom_line, g_status.sas_tokens,
  2320.                           g_display.message_color ) == ERROR)
  2321.             return( ERROR );
  2322.          i = 0;
  2323.          tokens = strtok( g_status.sas_tokens, SAS_DELIMITERS );
  2324.          while (tokens != NULL) {
  2325.             g_status.sas_arg_pointers[i++] = tokens;
  2326.             tokens = strtok( NULL, SAS_DELIMITERS );
  2327.          }
  2328.          if (i == 0)
  2329.             return( ERROR );
  2330.          g_status.sas_arg_pointers[i] = NULL;
  2331.          g_status.sas_argc = i;
  2332.          g_status.sas_arg = 0;
  2333.          g_status.sas_argv = g_status.sas_arg_pointers;
  2334.          g_status.sas_found_first = FALSE;
  2335.          if (g_status.command == DefineGrep) {
  2336.             g_status.sas_defined = TRUE;
  2337.             bm.search_defined = sas_bm.search_defined = OK;
  2338.             build_boyer_array( );
  2339.          } else {
  2340.             i = build_nfa( );
  2341.             if (i == OK) {
  2342.                g_status.sas_defined = TRUE;
  2343.                regx.search_defined = sas_regx.search_defined = OK;
  2344.             } else
  2345.                g_status.sas_defined = FALSE;
  2346.          }
  2347.       }
  2348.       bottom_line = win->bottom_line;
  2349.    } else
  2350.       bottom_line = g_display.nlines;
  2351.    if (g_status.sas_defined && g_status.sas_arg < g_status.sas_argc) {
  2352.       if (win != NULL) {
  2353.          entab_linebuff( );
  2354.          un_copy_line( win->ll, win, TRUE );
  2355.       }
  2356.  
  2357.       /*
  2358.        * while we haven't found a valid file, search thru the command
  2359.        * line path.
  2360.        * we may have an invalid file name when we finish matching all
  2361.        * files according to a pattern.  then, we need to go to the next
  2362.        * command line argument if it exists.
  2363.        */
  2364.       while (rc == ERROR && g_status.sas_arg < g_status.sas_argc) {
  2365.  
  2366.          /*
  2367.           * if we haven't starting searching for a file, check to see if
  2368.           * the file is a valid file name.  if no file is found, then let's
  2369.           * see if we can find according to a search pattern.
  2370.           */
  2371.          if (g_status.sas_found_first == FALSE) {
  2372.  
  2373.             assert( strlen( g_status.sas_argv[g_status.sas_arg] )
  2374.                         < (size_t)g_display.ncols );
  2375.  
  2376.             strcpy( name, g_status.sas_argv[g_status.sas_arg] );
  2377.             rc = get_fattr( name, &i );
  2378.  
  2379.             /*
  2380.              * a new or blank file generates a return code of 2.
  2381.              * a pattern with wild cards generates a return code of 3.
  2382.              */
  2383.             if (rc == OK || rc == 2) {
  2384.                ++g_status.sas_arg;
  2385.                rc = OK;
  2386.  
  2387.             /*
  2388.              * if we get this far, we got an invalid path name.
  2389.              *  let's try to find a matching file name using pattern.
  2390.              */
  2391.             } else if (rc != ERROR) {
  2392.                rc = my_findfirst( &g_status.sas_dta, name, NORMAL | READ_ONLY |
  2393.                                HIDDEN | SYSTEM | ARCHIVE );
  2394.  
  2395.                /*
  2396.                 * if we found a file using wildcard characters,
  2397.                 * set the g_status.sas_found_first flag to true so we can
  2398.                 * find the next matching file.  we need to save the
  2399.                 * pathname stem so we know which directory we are working in.
  2400.                 */
  2401.                if (rc == OK) {
  2402.                   g_status.sas_found_first = TRUE;
  2403.                   i = strlen( name ) - 1;
  2404.                   while (i >= 0) {
  2405.                      if (name[i] == ':' || name[i] == '\\')
  2406.                         break;
  2407.                      --i;
  2408.                   }
  2409.                   name[++i] = '\0';
  2410.  
  2411.                   assert( strlen( name ) + strlen( g_status.sas_dta.name )
  2412.                                    < (size_t)g_display.ncols );
  2413.  
  2414.                   strcpy( g_status.sas_path, name );
  2415.                   strcpy( name, g_status.sas_path );
  2416.                   strcat( name, g_status.sas_dta.name );
  2417.                } else {
  2418.                   ++g_status.sas_arg;
  2419.                   if (win != NULL)
  2420.                      /*
  2421.                       * invalid path or file name
  2422.                       */
  2423.                      error( WARNING, win->bottom_line, win8 );
  2424.                }
  2425.             } else if (rc == ERROR)
  2426.                ++g_status.sas_arg;
  2427.          } else {
  2428.  
  2429.             /*
  2430.              * we already found one file with wild card characters,
  2431.              * find the next matching file.
  2432.              */
  2433.             rc = my_findnext( &g_status.sas_dta );
  2434.             if (rc == OK) {
  2435.  
  2436.                assert( strlen( g_status.sas_path ) +
  2437.                    strlen( g_status.sas_dta.name ) < (size_t)g_display.ncols );
  2438.  
  2439.                strcpy( name, g_status.sas_path );
  2440.                strcat( name, g_status.sas_dta.name );
  2441.             } else {
  2442.                g_status.sas_found_first = FALSE;
  2443.                ++g_status.sas_arg;
  2444.             }
  2445.          }
  2446.  
  2447.          /*
  2448.           * if everything is everything so far, set up the file
  2449.           * and window structures and bring the file into the editor.
  2450.           */
  2451.          if (rc == OK) {
  2452.  
  2453.             assert( strlen( win19 ) + strlen( name ) < (size_t)g_display.ncols );
  2454.  
  2455.             strcpy( searching, win19 );
  2456.             strcat( searching, name );
  2457.             save_screen_line( 0, bottom_line, display_buff );
  2458.             set_prompt( searching, bottom_line );
  2459.             file_mode = TEXT;
  2460.             bin_length = 0;
  2461.  
  2462.             assert( strlen( name ) <= (size_t)g_display.ncols );
  2463.  
  2464.             _splitpath( name, spdrive, spdir, spname, spext );
  2465.             if (stricmp( spext, ".exe" ) == 0 || stricmp( spext, ".com" ) == 0){
  2466.                file_mode = BINARY;
  2467.                bin_length = g_status.file_chunk;
  2468.             }
  2469.             rc = attempt_edit_display( name, update_type, file_mode, bin_length );
  2470.             if (rc == OK)
  2471.                show_avail_mem( );
  2472.             restore_screen_line( 0, bottom_line, display_buff );
  2473.  
  2474.             if (rc == OK) {
  2475.                win = g_status.current_window;
  2476.                bin_offset_adjust( win, g_status.sas_rline );
  2477.                find_adjust( win, g_status.sas_ll, g_status.sas_rline,
  2478.                             g_status.sas_rcol );
  2479.                make_ruler( win );
  2480.                show_ruler( win );
  2481.                show_ruler_pointer( win );
  2482.                show_window_header( win );
  2483.                if (win->vertical)
  2484.                   show_vertical_separator( win );
  2485.                win->file_info->dirty = LOCAL;
  2486.             }
  2487.          }
  2488.  
  2489.          /*
  2490.           * either there are no more matching files or we had an
  2491.           * invalid file name, set rc to ERROR and let's look at the
  2492.           * next file name or pattern on the command line.
  2493.           */
  2494.          else
  2495.             rc = ERROR;
  2496.       }
  2497.    }
  2498.    if (rc == ERROR &&  g_status.sas_arg >= g_status.sas_argc  && win != NULL)
  2499.       /*
  2500.        * no more files to load
  2501.        */
  2502.       error( WARNING, win->bottom_line, win9 );
  2503.    return( rc );
  2504. }
  2505.  
  2506.  
  2507. /*
  2508.  * Name:    edit_next_file
  2509.  * Purpose: edit next file on command line.
  2510.  * Date:    January 6, 1992
  2511.  * Passed:  window:  pointer to current window
  2512.  * Notes:   New window replaces old window.  Old window becomes invisible.
  2513.  */
  2514. int  edit_next_file( TDE_WIN *window )
  2515. {
  2516. char name[MAX_COLS];            /* new name for file */
  2517. char spdrive[_MAX_DRIVE];       /* splitpath drive buff */
  2518. char spdir[_MAX_DIR];           /* splitpath dir buff */
  2519. char spname[_MAX_FNAME];        /* splitpath fname buff */
  2520. char spext[_MAX_EXT];           /* splitpath ext buff */
  2521. int  file_mode;
  2522. int  bin_length;
  2523. int  i;
  2524. int  update_type;
  2525. register int rc = ERROR;
  2526. register TDE_WIN *win;           /* put window pointer in a register */
  2527.  
  2528.    win = window;
  2529.    update_type = win == NULL ? GLOBAL : LOCAL;
  2530.    if (g_status.arg < g_status.argc) {
  2531.       if (win != NULL) {
  2532.          entab_linebuff( );
  2533.          if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2534.             return( ERROR );
  2535.       }
  2536.  
  2537.       /*
  2538.        * while we haven't found a valid file, search thru the command
  2539.        * line path.
  2540.        * we may have an invalid file name when we finish matching all
  2541.        * files according to a pattern.  then, we need to go to the next
  2542.        * command line argument if it exists.
  2543.        */
  2544.       while (rc == ERROR && g_status.arg < g_status.argc) {
  2545.  
  2546.          /*
  2547.           * if we haven't starting searching for a file, check to see if
  2548.           * the file is a valid file name.  if no file is found, then let's
  2549.           * see if we can find according to a search pattern.
  2550.           */
  2551.          if (g_status.found_first == FALSE) {
  2552.  
  2553.             assert( strlen( g_status.argv[g_status.arg] ) <
  2554.                                              (size_t)g_display.ncols );
  2555.  
  2556.             strcpy( name, g_status.argv[g_status.arg] );
  2557.             rc = get_fattr( name, &i );
  2558.  
  2559.             /*
  2560.              * a new or blank file generates a return code of 2.
  2561.              * a pattern with wild cards generates a return code of 3.
  2562.              */
  2563.             if (rc == OK || rc == 2) {
  2564.                ++g_status.arg;
  2565.                rc = OK;
  2566.  
  2567.             /*
  2568.              * if we get this far, we got an invalid path name.
  2569.              *  let's try to find a matching file name using pattern.
  2570.              */
  2571.             } else if (rc != ERROR) {
  2572.                rc = my_findfirst( &g_status.dta, name, NORMAL | READ_ONLY |
  2573.                                HIDDEN | SYSTEM | ARCHIVE );
  2574.  
  2575.                /*
  2576.                 * if we found a file using wildcard characters,
  2577.                 * set the g_status.found_first flag to true so we can
  2578.                 * find the next matching file.  we need to save the
  2579.                 * pathname stem so we know which directory we are working in.
  2580.                 */
  2581.                if (rc == OK) {
  2582.                   g_status.found_first = TRUE;
  2583.                   i = strlen( name ) - 1;
  2584.                   while (i >= 0) {
  2585.                      if (name[i] == ':' || name[i] == '\\')
  2586.                         break;
  2587.                      --i;
  2588.                   }
  2589.                   name[++i] = '\0';
  2590.  
  2591.                   assert( strlen( name ) < (size_t)g_display.ncols );
  2592.  
  2593.                   strcpy( g_status.path, name );
  2594.                   strcpy( name, g_status.path );
  2595.                   strcat( name, g_status.dta.name );
  2596.                } else {
  2597.                   ++g_status.arg;
  2598.                   if (win != NULL)
  2599.                      /*
  2600.                       * invalid path or file name
  2601.                       */
  2602.                      error( WARNING, win->bottom_line, win8 );
  2603.                }
  2604.             } else if (rc == ERROR)
  2605.                ++g_status.arg;
  2606.          } else {
  2607.  
  2608.             /*
  2609.              * we already found one file with wild card characters,
  2610.              * find the next matching file.
  2611.              */
  2612.             rc = my_findnext( &g_status.dta );
  2613.             if (rc == OK) {
  2614.  
  2615.                assert( strlen( g_status.path ) + strlen( g_status.dta.name )
  2616.                            < (size_t)g_display.ncols );
  2617.  
  2618.                strcpy( name, g_status.path );
  2619.                strcat( name, g_status.dta.name );
  2620.             } else {
  2621.                g_status.found_first = FALSE;
  2622.                ++g_status.arg;
  2623.             }
  2624.          }
  2625.  
  2626.          /*
  2627.           * if everything is everything so far, set up the file
  2628.           * and window structures and bring the file into the editor.
  2629.           */
  2630.          if (rc == OK) {
  2631.             file_mode = g_status.file_mode;
  2632.             bin_length = g_status.file_chunk;
  2633.  
  2634.             assert( strlen( name ) <= (size_t)g_display.ncols );
  2635.  
  2636.             _splitpath( name, spdrive, spdir, spname, spext );
  2637.             if (stricmp( spext, ".exe" ) == 0 || stricmp( spext, ".com" ) == 0)
  2638.                file_mode = BINARY;
  2639.             rc = attempt_edit_display( name, update_type, file_mode, bin_length );
  2640.             if (rc == OK)
  2641.                show_avail_mem( );
  2642.          }
  2643.  
  2644.          /*
  2645.           * either there are no more matching files or we had an
  2646.           * invalid file name, set rc to ERROR and let's look at the
  2647.           * next file name or pattern on the command line.
  2648.           */
  2649.          else
  2650.             rc = ERROR;
  2651.       }
  2652.    }
  2653.    if (rc == ERROR  &&  g_status.arg >= g_status.argc  &&  win != NULL)
  2654.       /*
  2655.        * no more files to load
  2656.        */
  2657.       error( WARNING, win->bottom_line, win9 );
  2658.    return( rc );
  2659. }
  2660.  
  2661.  
  2662. /*
  2663.  * Name:    hw_fattrib
  2664.  * Purpose: To determine the current file attributes.
  2665.  * Date:    December 26, 1991
  2666.  * Passed:  name: name of file to be checked
  2667.  * Returns: use the function in the tdeasm file to get the DOS file
  2668.  *          attributes.  get_fattr() returns 0 or OK if no error.
  2669.  */
  2670. int  hw_fattrib( char *name )
  2671. {
  2672. register int rc;
  2673. int  fattr;
  2674.  
  2675.    rc = get_fattr( name, &fattr );
  2676.    return( rc == OK ? rc : ERROR );
  2677. }
  2678.  
  2679.  
  2680. /*
  2681.  * Name:    change_mode
  2682.  * Purpose: To prompt for file access mode.
  2683.  * Date:    January 11, 1992
  2684.  * Passed:  name:  name of file
  2685.  *          line:  line to display message
  2686.  * Returns: OK if file could be changed
  2687.  *          ERROR otherwise
  2688.  * Notes:   function is used to change file attributes for save_as function.
  2689.  */
  2690. int  change_mode( char *name, int line )
  2691. {
  2692. int  result;
  2693. int  fattr;
  2694. register int rc;
  2695. char display_buff[(MAX_COLS+2)*2];
  2696.  
  2697.    rc = OK;
  2698.    result = get_fattr( name, &fattr );
  2699.    if (result != OK)
  2700.       rc = ERROR;
  2701.    else if (result == OK && fattr & READ_ONLY) {
  2702.       /*
  2703.        * file is read only
  2704.        */
  2705.       save_screen_line( 0, line, display_buff );
  2706.       /*
  2707.        * file is write protected. overwrite anyway (y/n)?
  2708.        */
  2709.       set_prompt( main6, line );
  2710.       if (get_yn( ) != A_YES)
  2711.          rc = ERROR;
  2712.       if (rc == OK && set_fattr( name, ARCHIVE ) != OK)
  2713.          rc = ERROR;
  2714.       restore_screen_line( 0, line, display_buff );
  2715.    }
  2716.    return( rc );
  2717. }
  2718.  
  2719.  
  2720. /*
  2721.  * Name:    change_fattr
  2722.  * Purpose: To change the file attributes
  2723.  * Date:    December 31, 1991
  2724.  * Passed:  window:  pointer to current window
  2725.  */
  2726. int  change_fattr( TDE_WIN *window )
  2727. {
  2728. file_infos *file;
  2729. TDE_WIN *wp;
  2730. int  prompt_line;
  2731. register int ok;
  2732. unsigned char fattr;
  2733. char *s;
  2734. int  rc;
  2735. char answer[MAX_COLS+2];
  2736. char display_buff[(MAX_COLS+2)*2];
  2737.  
  2738.    prompt_line = window->bottom_line;
  2739.    save_screen_line( 0, prompt_line, display_buff );
  2740.  
  2741.    answer[0] = '\0';
  2742.    /*
  2743.     * enter new file attributes
  2744.     */
  2745.    if ((ok = get_name( utils14, prompt_line, answer,
  2746.                        g_display.message_color )) == OK) {
  2747.       if (*answer != '\0') {
  2748.          fattr = 0;
  2749.          s = answer;
  2750.  
  2751.          /*
  2752.           * yes, I know lint complains about "ok = *s++".
  2753.           */
  2754.          while (ok = toupper( *s )) {
  2755.             switch (ok) {
  2756.                case L_DOS_ARCHIVE :
  2757.                   fattr |= ARCHIVE;
  2758.                   break;
  2759.                case L_DOS_SYSTEM :
  2760.                   fattr |= SYSTEM;
  2761.                   break;
  2762.                case L_DOS_HIDDEN :
  2763.                   fattr |= HIDDEN;
  2764.                   break;
  2765.                case L_DOS_READ_ONLY :
  2766.                   fattr |= READ_ONLY;
  2767.                   break;
  2768.                default :
  2769.                   break;
  2770.             }
  2771.             s++;
  2772.          }
  2773.          file = window->file_info;
  2774.          if (set_fattr( file->file_name, fattr ))
  2775.             /*
  2776.              * new file attributes not set
  2777.              */
  2778.             error( WARNING, prompt_line, utils15 );
  2779.          else {
  2780.             file->file_attrib = fattr;
  2781.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  2782.                if (wp->file_info == file && wp->visible)
  2783.                   show_window_fname( wp );
  2784.             }
  2785.          }
  2786.       }
  2787.       rc = OK;
  2788.    } else
  2789.       rc = ERROR;
  2790.    restore_screen_line( 0, prompt_line, display_buff );
  2791.    return( rc );
  2792. }
  2793.  
  2794.  
  2795. /*
  2796.  * Name:    get_fattr
  2797.  * Purpose: To get dos file attributes
  2798.  * Date:    December 26, 1991
  2799.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  2800.  *          fattr: pointer to file attributes
  2801.  * Returns: 0 if successfull, non zero if not
  2802.  * Notes:   Uses the DOS function to get file attributes.  I really didn't
  2803.  *           like the file attribute functions in the C library:  fstat() and
  2804.  *           stat() or access() and chmod().
  2805.  *           FYI, File Attributes:
  2806.  *              0x00 = Normal.  Can be read or written w/o restriction
  2807.  *              0x01 = Read-only.  Cannot be opened for write; a file with
  2808.  *                     the same name cannot be created.
  2809.  *              0x02 = Hidden.  Not found by directory search.
  2810.  *              0x04 = System.  Not found by directory search.
  2811.  *              0x08 = Volumn Label.
  2812.  *              0x10 = Directory.
  2813.  *              0x20 = Archive.  Set whenever the file is changed, or
  2814.  *                     cleared by the Backup command.
  2815.  *           Return codes:
  2816.  *              0 = No error
  2817.  *              1 = AL not 0 or 1
  2818.  *              2 = file is invalid or does not exist
  2819.  *              3 = path is invalid or does not exist
  2820.  *              5 = Access denied
  2821.  */
  2822. int  get_fattr( char FAR *fname, int *fattr )
  2823. {
  2824. int  rc;                /* return code */
  2825. int  attr;
  2826.  
  2827.    ASSEMBLE {
  2828.         push    ds
  2829.         mov     dx, WORD PTR fname      /* get OFFSET of filename string */
  2830.         mov     ax, WORD PTR fname+2    /* get SEGMENT of filename string */
  2831.         mov     ds, ax                  /* put SEGMENT in ds */
  2832.         mov     ax, 0x4300              /* function:  get file attributes */
  2833.         int     0x21                    /* DOS interrupt */
  2834.         pop     ds
  2835.  
  2836.         jc      an_error                /* save the error code from get attr */
  2837.         xor     ax, ax                  /* if no carry, no error */
  2838.         jmp     SHORT get_out           /* lets get out */
  2839.    }
  2840. an_error:
  2841.  
  2842.  
  2843.    ASSEMBLE {
  2844.         xor     cx, cx                  /* if error, then zero out cx - attrs */
  2845.    }
  2846. get_out:
  2847.  
  2848.    ASSEMBLE {
  2849.         mov     WORD PTR rc, ax         /* ax contains error number on error */
  2850.         mov     WORD PTR attr, cx       /* cx contains file attributes */
  2851.    }
  2852.    *fattr = attr;
  2853.    if (ceh.flag == ERROR)
  2854.       rc = ERROR;
  2855.    return( rc );
  2856. }
  2857.  
  2858.  
  2859. /*
  2860.  * Name:    set_fattr
  2861.  * Purpose: To set dos file attributes
  2862.  * Date:    December 26, 1991
  2863.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  2864.  *          fattr: file attributes
  2865.  * Returns: 0 if successfull, non zero if not
  2866.  * Notes:   Uses the DOS function to get file attributes.
  2867.  *           Return codes:
  2868.  *              0 = No error
  2869.  *              1 = AL not 0 or 1
  2870.  *              2 = file is invalid or does not exist
  2871.  *              3 = path is invalid or does not exist
  2872.  *              5 = Access denied
  2873.  */
  2874. int  set_fattr( char FAR *fname, int fattr )
  2875. {
  2876. int  rc;                /* return code */
  2877.  
  2878.    ASSEMBLE {
  2879.         push    ds
  2880.         mov     dx, WORD PTR fname      /* get OFFSET of filename string */
  2881.         mov     ax, WORD PTR fname+2    /* get SEGMENT of filename string */
  2882.         mov     ds, ax                  /* put SEGMENT in ds */
  2883.         mov     cx, WORD PTR fattr      /* cx contains file attributes */
  2884.         mov     ax, 0x4301              /* function:  get file attributes */
  2885.         int     0x21                    /* DOS interrupt */
  2886.         pop     ds
  2887.  
  2888.         jc      get_out                 /* save the error code from get attr */
  2889.         xor     ax, ax                  /* if no carry, no error */
  2890.    }
  2891. get_out:
  2892.  
  2893.    ASSEMBLE {
  2894.         mov     WORD PTR rc, ax         /* ax contains error number on error */
  2895.    }
  2896.    if (ceh.flag == ERROR)
  2897.       rc = ERROR;
  2898.    return( rc );
  2899. }
  2900.  
  2901.  
  2902. /*
  2903.  * Name:    get_current_directory
  2904.  * Purpose: get current directory
  2905.  * Date:    February 13, 1992
  2906.  * Passed:  path:  pointer to buffer to store path
  2907.  *          drive: drive to get current directory
  2908.  * Notes:   use simple DOS interrupt
  2909.  */
  2910. int  get_current_directory( char FAR *path, int drive )
  2911. {
  2912. int  rc;
  2913.  
  2914.    ASSEMBLE {
  2915.         push    si                      /* save register vars if any */
  2916.         push    ds                      /* save ds */
  2917.  
  2918.         mov     dx, WORD PTR drive      /* dl = drive, 0 = default, 1 = a, etc.. */
  2919.         mov     si, WORD PTR path       /* get OFFSET of path */
  2920.         mov     ax, WORD PTR path+2     /* get SEGMENT of path */
  2921.         mov     ds, ax                  /* put it in ds */
  2922.         mov     ah, 0x47                /* function 0x47 == get current dir */
  2923.         int     0x21                    /* standard DOS interrupt */
  2924.         xor     ax, ax                  /* zero out ax, return OK if no error */
  2925.         jnc     no_error                /* if carry set, then an error */
  2926.         mov     ax, ERROR               /* return -1 if error */
  2927.    }
  2928. no_error:
  2929.  
  2930.    ASSEMBLE {
  2931.         pop     ds                      /* get back ds */
  2932.         pop     si                      /* get back si */
  2933.         mov     WORD PTR rc, ax         /* save return code */
  2934.    }
  2935.    if (ceh.flag == ERROR)
  2936.       rc = ERROR;
  2937.    return( rc );
  2938. }
  2939.  
  2940.  
  2941. /*
  2942.  * Name:    set_current_directory
  2943.  * Purpose: set current directory
  2944.  * Date:    February 13, 1992
  2945.  * Passed:  new_path: directory path, which may include drive letter
  2946.  * Notes:   use simple DOS interrupt
  2947.  */
  2948. int  set_current_directory( char FAR *new_path )
  2949. {
  2950. int  rc;
  2951.  
  2952.    ASSEMBLE {
  2953.         push    ds                      /* save ds */
  2954.  
  2955.         mov     dx, WORD PTR new_path   /* get OFFSET of new_path */
  2956.         mov     ax, WORD PTR new_path+2 /* get SEGMENT of new_path */
  2957.         mov     ds, ax                  /* put it in ds */
  2958.         mov     ah, 0x3b                /* function 0x3b == set current dir */
  2959.         int     0x21                    /* standard DOS interrupt */
  2960.         xor     ax, ax                  /* zero out ax, return OK if no error */
  2961.         jnc     no_error                /* if carry set, then an error */
  2962.         mov     ax, ERROR               /* return -1 if error */
  2963.    }
  2964. no_error:
  2965.  
  2966.    ASSEMBLE {
  2967.         pop     ds                      /* get back ds */
  2968.         mov     WORD PTR rc, ax         /* save return code */
  2969.    }
  2970.    if (ceh.flag == ERROR)
  2971.       rc = ERROR;
  2972.    return( rc );
  2973. }
  2974. #endif
  2975.