home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / editors / tde150.arj / DIRLIST.C < prev    next >
C/C++ Source or Header  |  1992-04-01  |  32KB  |  950 lines

  1. /*
  2.  * I wrote this function because I'm so stupid, I constantly forget
  3.  * file names and directory stuff.  The main function prompts for a
  4.  * subdirectory name or a search path.  The default search path is the
  5.  * cwd (current working directory).  In addition to being stupid, I'm also
  6.  * lazy.  If the user types a subdirectory name, I think we can assume he
  7.  * wants to list all files w/o having to type *.*   Let's save the cwd on
  8.  * whatever drive the user wishes to search, so we can restore it we get
  9.  * thru dir'ing.  Use the standard DOS functions to get and set directories.
  10.  *
  11.  *  The search pattern can contain wild card chars, valid file names, or
  12.  *  a valid subdirectory name.
  13.  *
  14.  * New editor name:  tde, the Thomson-Davis Editor.
  15.  * Author:           Frank Davis
  16.  * Date:             June 5, 1991, version 1.0
  17.  * Date:             July 29, 1991, version 1.1
  18.  * Date:             October 5, 1991, version 1.2
  19.  * Date:             January 20, 1992, version 1.3
  20.  * Date:             February 17, 1992, version 1.4
  21.  * Date:             April 1, 1992, version 1.5
  22.  *
  23.  * This code is released into the public domain, Frank Davis.
  24.  *    You may distribute it freely.
  25.  */
  26.  
  27. #include "tdestr.h"
  28. #include "common.h"
  29. #include "define.h"
  30. #include "tdefunc.h"
  31. #include <malloc.h>
  32.  
  33.  
  34. /*
  35.  * Name:    dir_help
  36.  * Purpose: To prompt the user and list the directory contents
  37.  * Date:    February 13, 1992
  38.  * Passed:  window: current window stuff
  39.  */
  40. void dir_help( WINDOW *window )
  41. {
  42. char dname[MAX_COLS+2]; /* directory search pattern */
  43. char stem[MAX_COLS+2];  /* directory stem */
  44. int rc;
  45.  
  46.    dname[0] = '\0';
  47.    if (get_name( "Search path or pattern : ",
  48.                  window->bottom_line, dname, g_display.message_color ) == OK) {
  49.       if (validate_path( dname, stem ) == OK) {
  50.          rc = list_and_pick( dname, stem, window );
  51.  
  52.          /*
  53.           * if everything is everything, load in the file selected by user.
  54.           */
  55.          if (rc == OK)
  56.             attempt_edit_display( dname, LOCAL );
  57.       } else
  58.          error( WARNING, window->bottom_line, "Invalid path or file name" );
  59.    }
  60. }
  61.  
  62.  
  63. /*
  64.  * Name:    validate_path
  65.  * Purpose: make sure we got a valid search pattern or subdirectory
  66.  * Date:    February 13, 1992
  67.  * Passed:  dname: search path entered by user
  68.  *          stem:  directory stem is returned
  69.  * Returns: successful or not
  70.  * Notes:   we need to validate the search path or pattern.  if the search
  71.  *            pattern is valid, then we need to get the search stem.
  72.  *          the user may enter a subdirectory or some kind of search pattern.
  73.  *             if the user enters a subdirectory, then there are a few things
  74.  *             we need to take care of  1) find out if the subdirectory is
  75.  *             the root, 2) append a '\' to the subdirectory so we can create
  76.  *             a search pattern for the subdirectory, 3) don't append '\' to
  77.  *             the root, it already has a '\'.
  78.  *          if the user enters a search pattern, then we need to dissect the
  79.  *             search path.  we must create a stem from the search pattern.
  80.  */
  81. int  validate_path( char *dname, char *stem )
  82. {
  83. int rc;
  84. DTA dta;                /* temp disk transfer struct for findfirst, etc. */
  85. int fattr;
  86. int i;
  87. int len;
  88. char *p;
  89. char temp[MAX_COLS+2];  /* directory stem */
  90.  
  91.    /*
  92.     * if path name is void then the current working directory is implied.
  93.     */
  94.    if (dname[0] == '\0') {
  95.       strcpy( dname, "*.*" );
  96.       stem[0] = '\0';
  97.       rc = OK;
  98.    } else {
  99.  
  100.       /*
  101.        * get the attributes of the search pattern, so we can determine if
  102.        * this is a pattern or subdirectory.
  103.        */
  104.       rc = get_fattr( dname, &fattr );
  105.  
  106.       if (rc == OK && (fattr & SUBDIRECTORY)) {
  107.          strcpy( stem, dname );
  108.  
  109.          /*
  110.           * if this is the root directory ( \ ), don't append '\' to it.
  111.           * user entered a subdirectory - append *.* to get contents of
  112.           * subdirectory.
  113.           */
  114.          len = strlen( stem );
  115.          if (stem[len-1] != '\\') {
  116.             strcat( stem, "\\" );
  117.             strcat( dname, "\\" );
  118.          }
  119.          strcat( dname, "*.*" );
  120.  
  121.       /*
  122.        * not a subdirectory.  let's see if any files match the search
  123.        * pattern.
  124.        */
  125.       } else if (rc != ERROR) {
  126.          if ((rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN |
  127.                               SYSTEM | SUBDIRECTORY | ARCHIVE )) == OK) {
  128.  
  129.             /*
  130.              * copy dname to "temp" so we can use "temp" to find the stem.
  131.              *    we need to search the pattern backwards to figure the stem.
  132.              */
  133.             strcpy( temp, dname );
  134.             len = strlen( dname );
  135.             for (i=len,p=temp+len; i>=0; i--) {
  136.                /*
  137.                 *  if we run into the '\' or the ':', then we got a stem.
  138.                 */
  139.                if (*p == '\\' || *p == ':') {
  140.                   p = temp + i;
  141.                   *(p+1) = '\0';
  142.                   break;
  143.                /*
  144.                 * if we're at the beginning of the string, stem == '\0'
  145.                 */
  146.                } else if (i == 0) {
  147.                   *p = '\0';
  148.                   break;
  149.                }
  150.                --p;
  151.             }
  152.             strcpy( stem, temp );
  153.          } else
  154.             rc = ERROR;
  155.  
  156.       /*
  157.        * user did not enter a valid subdirectory name or search pattern.
  158.        */
  159.       } else
  160.          rc = ERROR;
  161.    }
  162.    return( rc );
  163. }
  164.  
  165.  
  166. /*
  167.  * Name:    list_and_pick
  168.  * Purpose: To show matching file names and let user pick a file
  169.  * Date:    February 13, 1992
  170.  * Passed:  dname:  directory search pattern
  171.  *          stem:   stem of directory search pattern
  172.  *          window:  current window stuff
  173.  * Returns: return code from pick.  rc = OK, then edit a new file.
  174.  * Notes:   real work routine of this function.  save the cwd and let the
  175.  *          user search upwards or downwards thru the directory structure.
  176.  *          since we are doing DOS directory functions, we need to check the
  177.  *            return code after each DOS call for critical errors.
  178.  */
  179. int  list_and_pick( char *dname, char *stem, WINDOW *window )
  180. {
  181. int rc;
  182. DTA dta;                /* disk transfer address for findfirst */
  183. DIRECTORY dir;          /* contains all info for dir display */
  184. unsigned int cnt;       /* number of matching files */
  185. FTYPE *flist, *p;       /* pointer to list of matching files */
  186. char cwd[MAX_COLS];     /* save the current working directory in this buff */
  187. char dbuff[MAX_COLS];   /* temporary directory buff */
  188. char prefix[MAX_COLS];  /* directory prefix  */
  189. int change_directory = FALSE;
  190. int stop;
  191. int len;
  192. int drive;
  193.  
  194.    /*
  195.     * Some algorithms alloc the maximum possible number of files in
  196.     *  a directory, eg. 256 or 512.  Let's count the number of matching
  197.     *  files so we know egxactly how much memory to request from calloc.
  198.     *  Depending on the op system, disk media, disk format, or version of DOS,
  199.     *  the max number of files may vary, anyway, also, additionally.
  200.     */
  201.    rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM |
  202.                                 SUBDIRECTORY | ARCHIVE );
  203.    if (rc != ERROR) {
  204.       for (cnt=1; (rc = findnext( &dta )) == OK;)
  205.          ++cnt;
  206.       flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
  207.    }
  208.    if (rc != ERROR && flist != NULL) {
  209.  
  210.       stop = FALSE;
  211.       /*
  212.        * If user entered drive name in search pattern, find out the drive and
  213.        *   directory stem.
  214.        */
  215.       if (stem[1] == ':') {
  216.  
  217.          /*
  218.           * If the second character of the search pattern is a ':', the
  219.           *   the first character of the pattern should be the drive.
  220.           *   Convert drive to lower case and get a numerical representation.
  221.           * CAVEAT:  In DOS v 2.x, there may be up to 63 logical drives.
  222.           *    this algorithm may blow up if the number of logical drives
  223.           *    is greater than 'Z'.
  224.           * For DOS >= 3, the number of drives is limited to 26, I think.
  225.           */
  226.          drive = stem[0];
  227.          if (drive < 'a')
  228.             drive += 32;
  229.          drive = stem[0] - 'a' + 1;
  230.          rc = get_current_directory( dbuff, drive );
  231.          if (rc == ERROR)
  232.             stop = TRUE;
  233.          else {
  234.  
  235.             /*
  236.              * Put drive letter, ':', and '\' in front of current directory.
  237.              */
  238.             prefix[0] = (char)(drive - 1 + 'a');
  239.             prefix[1] = ':';
  240.             prefix[2] = '\\';
  241.             prefix[3] = '\0';
  242.             strcpy( cwd, prefix );
  243.             strcat( cwd, dbuff );
  244.          }
  245.  
  246.       /*
  247.        * else get current directory from default drive
  248.        */
  249.       } else {
  250.  
  251.          /*
  252.           * 0 = default drive.
  253.           */
  254.          drive = 0;
  255.          rc = get_current_directory( dbuff, drive );
  256.          if (rc == ERROR)
  257.             stop = TRUE;
  258.          else {
  259.  
  260.             /*
  261.              * Put a '\' in front of the current directory.
  262.              */
  263.             prefix[0] = '\\';
  264.             prefix[1] = '\0';
  265.             strcpy( cwd, prefix );
  266.             strcat( cwd, dbuff );
  267.          }
  268.       }
  269.  
  270.       save_screen( );
  271.       while (stop == FALSE) {
  272.          /*
  273.           * If we had enough memory, find all matching file names.  Append
  274.           *   '\\' at the end of subdirectory names so user will know if
  275.           *    name is a directory.  Might as well find everything, because
  276.           *    i also forget subdirectory names, too.
  277.           *
  278.           * when we get here, we have already done: 1) findfirst and findnext,
  279.           *   2) counted the number of matching files, and 3) allocated space.
  280.           */
  281.          p = flist;
  282.          cnt = 0;
  283.  
  284.          rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM |
  285.                                  SUBDIRECTORY | ARCHIVE );
  286.          if (rc != ERROR) {
  287.  
  288.             /*
  289.              * p is pointer that walks down the file info structure.
  290.              *  save the file name, file size, and directory character,
  291.              *  if needed, for each matching file we find.
  292.              */
  293.             strcpy( p->fname, dta.name );
  294.             p->fsize = dta.size;
  295.             if (dta.attrib & SUBDIRECTORY)
  296.                strcat( p->fname, "\\" );
  297.             for (cnt=1; (rc = findnext( &dta )) == OK; ) {
  298.                ++p;
  299.                strcpy( p->fname, dta.name );
  300.                p->fsize = dta.size;
  301.                if (dta.attrib & SUBDIRECTORY)
  302.                   strcat( p->fname, "\\" );
  303.                cnt++;
  304.             }
  305.          }
  306.  
  307.          if (rc != ERROR) {
  308.             shell_sort( flist, cnt );
  309.  
  310.             /*
  311.              * figure out number of rows, cols, etc... then display dir list
  312.              */
  313.             setup_directory_window( &dir, cnt );
  314.             write_directory_list( flist, dir );
  315.  
  316.             /*
  317.              * Let user select file name or another search directory.
  318.              *  Save the choice in dbuff.  rc == OK if user selected file or dir.
  319.              */
  320.             rc = select_file( flist, stem, &dir );
  321.             strcpy( dbuff, flist[dir.select].fname );
  322.          }
  323.  
  324.          /*
  325.           *  give memory back.
  326.           */
  327.          free( flist );
  328.  
  329.          if (rc == ERROR)
  330.             stop = TRUE;
  331.          else {
  332.             len = strlen( dbuff );
  333.  
  334.             /*
  335.              * If the last character in a file name is '\' then let's
  336.              *   do a dir on selected directory.  See the matching
  337.              *   else when the user selects a file.
  338.              */
  339.             if (dbuff[len-1] == '\\') {
  340.  
  341.                /*
  342.                 * Stem has subdirectory path.  dbuff has selected path.
  343.                 * Create a new dname with stem and dbuff.
  344.                 */
  345.                strcpy( dname, stem );
  346.                strcat( dname, dbuff );
  347.                len = strlen( dname );
  348.                strcpy( dbuff, dname );
  349.  
  350.                /*
  351.                 * The last character in dbuff is '\', because we append the
  352.                 *   '\' to every directory entry in the file list.  Replace
  353.                 *   it with a NULL char then we will have a valid path name.
  354.                 */
  355.                dbuff[len-1] = '\0';
  356.  
  357.                /*
  358.                 * now let's change to the selected subdirectory.
  359.                 */
  360.                rc = set_current_directory( dbuff );
  361.                if (rc == OK) {
  362.  
  363.                   /*
  364.                    * Every time we change directories, we need to get the
  365.                    *   current directory so we will be sure to have the
  366.                    *   correct path.
  367.                    */
  368.                   rc = get_current_directory( dbuff, drive );
  369.                   if (rc == OK) {
  370.                      strcpy( dname, prefix );
  371.                      strcat( dname, dbuff );
  372.                      change_directory = TRUE;
  373.                   }
  374.                }
  375.  
  376.                /*
  377.                 * Validate the new path and allocate memory for the
  378.                 *   matching files.
  379.                 */
  380.                if (rc == OK)
  381.                   rc = validate_path( dname, stem );
  382.                if (rc == OK) {
  383.                   rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN |
  384.                                   SYSTEM | SUBDIRECTORY | ARCHIVE );
  385.                   if (rc != ERROR) {
  386.                      for (cnt=1; (rc = findnext( &dta )) == OK;)
  387.                         ++cnt;
  388.                      flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
  389.                   }
  390.                }
  391.                if (flist == NULL || rc == ERROR) {
  392.                   stop = TRUE;
  393.                   rc = ERROR;
  394.                }
  395.             } else {
  396.  
  397.                /*
  398.                 *  user selected a file.  store fname in dname and return.
  399.                 */
  400.                rc = OK;
  401.                stop = TRUE;
  402.                strcpy( dname, stem );
  403.                strcat( dname, dbuff );
  404.             }
  405.          }
  406.       }
  407.  
  408.       /*
  409.        * Go back to the current directory if needed.
  410.        */
  411.       if (change_directory)
  412.          set_current_directory( cwd );
  413.       restore_screen( );
  414.    } else {
  415.       error( WARNING, window->bottom_line, "Out of memory" );
  416.       rc = ERROR;
  417.    }
  418.    return( rc );
  419. }
  420.  
  421.  
  422. /*
  423.  * Name:    setup_directory_window
  424.  * Purpose: set number of rows and cols in directory window
  425.  * Date:    February 13, 1992
  426.  * Passed:  dir: pointer to directory structure
  427.  *          cnt: number of files
  428.  * Notes:   set up stuff we need to know about how to display files.
  429.  */
  430. void setup_directory_window( DIRECTORY *dir, int cnt )
  431. {
  432. int i;
  433. int wid;
  434. char temp[MAX_COLS];       /* line to output */
  435.  
  436.    /*
  437.     * setup the fixed vars used in dir display.
  438.     *    dir->col =      physical upper left column of dir screen
  439.     *    dir->row =      physical upper left row or line of dir screen
  440.     *    dir->wid =      width of physical screen
  441.     *    dir->hgt =      height of physical screen
  442.     *    dir->max_cols   number of columns of files in dir screen
  443.     *    dir->max_lines  number of lines of files in each column in dir screen
  444.     *    dir->cnt        number of files in list
  445.     */
  446.    dir->col = 3;
  447.    dir->row = 5;
  448.    wid = dir->wid = 72;
  449.    dir->hgt = 16;
  450.    dir->max_cols = 5;
  451.    dir->max_lines = 9;
  452.    dir->cnt = cnt;
  453.  
  454.    /*
  455.     *  Find out how many lines in each column are needed to display
  456.     *     matching files.
  457.     */
  458.    dir->lines = dir->cnt / dir->max_cols + (dir->cnt % dir->max_cols ? 1 : 0);
  459.    if (dir->lines > dir->max_lines)
  460.       dir->lines = dir->max_lines;
  461.  
  462.    /*
  463.     * Find out how many columns of file names we need.
  464.     */
  465.    dir->cols = dir->cnt / dir->lines + (dir->cnt % dir->lines ? 1 : 0);
  466.    if (dir->cols > dir->max_cols)
  467.       dir->cols = dir->max_cols;
  468.  
  469.  
  470.    /*
  471.     * Find the maximun number of file names we can display in help screen.
  472.     */
  473.    dir->avail = dir->lines * dir->cols;
  474.  
  475.    /*
  476.     * Now find the number of file names we do have on the screen.  Every
  477.     *   time we slide the "window", we have to calculate a new nfiles.
  478.     */
  479.    dir->nfiles = dir->cnt > dir->avail ? dir->avail : dir->cnt;
  480.  
  481.    /*
  482.     * A lot of times, the number of matching files will not fit evenly
  483.     *   in our help screen.  The last column on the right will be partially
  484.     *   filled, hence the variable name prow (partial row).  When there are
  485.     *   more file names than can fit on the screen, we have to calculate
  486.     *   prow every time we slide the "window" of files.
  487.     */
  488.    dir->prow = dir->lines - (dir->avail - dir->nfiles);
  489.  
  490.    /*
  491.     * Find out how many "virtual" columns of file names we have.  If
  492.     *   all the files can fit in the dir screen, there will be no
  493.     *   virtual columns.
  494.     */
  495.    if (dir->cnt < dir->avail)
  496.       dir->vcols = 0;
  497.    else
  498.       dir->vcols =  (dir->cnt - dir->avail) / dir->max_lines +
  499.                    ((dir->cnt - dir->avail) % dir->max_lines ? 1 : 0);
  500.  
  501.    /*
  502.     * Find the physical display column in dir screen.
  503.     */
  504.    dir->flist_col[0] = dir->col + 2;
  505.    for (i=1; i<dir->max_cols; i++)
  506.       dir->flist_col[i] = dir->flist_col[i-1] + 14;
  507.  
  508.    /*
  509.     * Now, draw the borders of the dir screen.
  510.     */
  511.    for (i=0; i < dir->hgt; i++) {
  512.       if (i == 0 || i == dir->hgt-1) {
  513.          memset( temp, '─', wid );
  514.          temp[wid] = '\0';
  515.          if (i == 0) {
  516.             temp[0] = '┌';
  517.             temp[wid-1] = '┐';
  518.          } else {
  519.             temp[0] = '└';
  520.             temp[wid-1] = '┘';
  521.          }
  522.       } else {
  523.          memset( temp, ' ', wid );
  524.          temp[wid] = '\0';
  525.          temp[0] = temp[wid-1] = '│';
  526.       }
  527.       s_output( temp, dir->row+i, dir->col, g_display.help_color );
  528.    }
  529.  
  530.    /*
  531.     * Write headings in help screen.
  532.     */
  533.    s_output( "Selected file : ", dir->row+1, dir->col+3,
  534.               g_display.help_color );
  535.    s_output( "    File size : ", dir->row+2, dir->col+3,
  536.               g_display.help_color );
  537.    s_output( "File count : ", dir->row+2, dir->col+44,
  538.               g_display.help_color );
  539.    s_output( "Cursor keys move.   Enter selects file or new directory",
  540.              dir->row+14, dir->col+8, g_display.help_color );
  541. }
  542.  
  543.  
  544. /*
  545.  * Name:    write_directory_list
  546.  * Purpose: given directory list, display matching files
  547.  * Date:    February 13, 1992
  548.  * Passed:  flist: pointer to list of files
  549.  *          dir:   directory display structure
  550.  * Notes:   blank out the previous file name and display the new one.
  551.  */
  552. void write_directory_list( FTYPE *flist, DIRECTORY dir )
  553. {
  554. FTYPE *p, *top;
  555. int i;
  556. int j;
  557. int k;
  558. int end;
  559. int line;
  560. int col;
  561. int color;
  562.  
  563.    color = g_display.help_color;
  564.    top = flist;
  565.    for (i=0; i < dir.lines; ++i) {
  566.       p = top;
  567.       end = FALSE;
  568.       for (j=0; j < dir.cols; ++j) {
  569.          col = dir.flist_col[j];
  570.          line = i + dir.row + 4;
  571.  
  572.          /*
  573.           * We need to blank out all lines and columns used to display
  574.           *   files, because there may be some residue from a previous dir
  575.           */
  576.          s_output( "            ", line, col, color );
  577.          if (!end) {
  578.             s_output( p->fname, line, col, color );
  579.             p += dir.lines;
  580.             k = p - flist;
  581.             if (k >= dir.nfiles)
  582.                end = TRUE;
  583.          }
  584.       }
  585.       ++top;
  586.    }
  587. }
  588.  
  589.  
  590. /*
  591.  * Name:    select_file
  592.  * Purpose: To let user select a file from dir list
  593.  * Date:    February 13, 1992
  594.  * Passed:  flist: pointer to list of files
  595.  *          stem:  base directory
  596.  *          dir:   directory display stuff
  597.  * Notes:   let user move thru the file names with the cursor keys
  598.  */
  599. int  select_file( FTYPE *flist, char *stem, DIRECTORY *dir )
  600. {
  601. int ch;         /* input character from user */
  602. int func;       /* function of character input by user */
  603. int fno;        /* index into flist of the file under cursor */
  604. int goodkey;    /* is key a recognized function key? */
  605. int r;          /* current row of cursor */
  606. int c;          /* current column of cursor */
  607. int offset;     /* offset into file list */
  608. int stop;       /* stop indicator */
  609. int stem_len;   /* stem length */
  610. int color;      /* color of help screen */
  611. int file_color; /* color of current file */
  612. int change;     /* boolean, hilite another file? */
  613. int oldr;       /* old row */
  614. int oldc;       /* old column */
  615. char asize[20]; /* ascii file size */
  616. char blank[20]; /* blank out file names */
  617.  
  618.    /*
  619.     * initial everything.
  620.     */
  621.    memset( blank, ' ', 12 );
  622.    blank[12] = '\0';
  623.    c = r = 1;
  624.    ch = fno = offset = 0;
  625.    color = g_display.help_color;
  626.    file_color = g_display.hilited_file;
  627.    goodkey = TRUE;
  628.    stop = FALSE;
  629.    stem_len = strlen( stem );
  630.    s_output( stem, dir->row+1, dir->col+19, color );
  631.    s_output( flist[fno].fname, dir->row+1, dir->col+19+stem_len, color );
  632.    ltoa( flist[fno].fsize, asize, 10 );
  633.    s_output( blank, dir->row+2, dir->col+19, color );
  634.    s_output( asize, dir->row+2, dir->col+19, color );
  635.    itoa( dir->cnt,  asize, 10 );
  636.    s_output( blank, dir->row+2, dir->col+57, color );
  637.    s_output( asize, dir->row+2, dir->col+57, color );
  638.    xygoto( (c-1)*14+dir->col+2, r+dir->row+3 );
  639.    hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color );
  640.    change = FALSE;
  641.    while (stop == FALSE) {
  642.       oldr = r;
  643.       oldc = c;
  644.       ch = getkey( );
  645.       func = getfunc( ch );
  646.  
  647.       /*
  648.        * User may have redefined the Enter and ESC keys.  Make the Enter key
  649.        * perform a Rturn in this function. Make the ESC key do an AbortCommand.
  650.        */
  651.       if (ch == RTURN)
  652.          func = Rturn;
  653.       else if (ch == ESC)
  654.          func = AbortCommand;
  655.  
  656.       switch (func) {
  657.          case Rturn       :
  658.          case NextLine    :
  659.          case BegNextLine :
  660.             stop = TRUE;
  661.             break;
  662.          case AbortCommand :
  663.             stop = TRUE;
  664.             break;
  665.          case LineUp :
  666.             if (r > 1) {
  667.                change = TRUE;
  668.                --r;
  669.             } else {
  670.                r = dir->lines;
  671.                change = TRUE;
  672.                if (offset == 0 || c > 1) {
  673.                   if (c > 1)
  674.                      --c;
  675.                } else if (dir->vcols > 0 && offset > 0 && c == 1) {
  676.                   /*
  677.                    * recalculate the dir display stuff.
  678.                    */
  679.                   offset -= dir->lines;
  680.                   recalculate_dir( dir, flist, offset );
  681.                }
  682.             }
  683.             goodkey = TRUE;
  684.             break;
  685.          case LineDown :
  686.             if (r < dir->prow) {
  687.                change = TRUE;
  688.                ++r;
  689.             } else if (r < dir->lines && c != dir->cols) {
  690.                change = TRUE;
  691.                ++r;
  692.             } else {
  693.                change = TRUE;
  694.                r = 1;
  695.                if (offset == dir->vcols * dir->lines || c < dir->cols) {
  696.                   if (c < dir->cols)
  697.                      ++c;
  698.                } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
  699.                          c == dir->cols) {
  700.                   offset += dir->lines;
  701.                   recalculate_dir( dir, flist, offset );
  702.                }
  703.             }
  704.             goodkey = TRUE;
  705.             break;
  706.          case CharLeft :
  707.             if (offset == 0 || c > 1) {
  708.                if (c > 1) {
  709.                   change = TRUE;
  710.                   --c;
  711.                }
  712.             } else if (dir->vcols > 0 && offset > 0 && c == 1) {
  713.                change = TRUE;
  714.  
  715.                /*
  716.                 * recalculate the dir display stuff.
  717.                 */
  718.                offset -= dir->lines;
  719.                recalculate_dir( dir, flist, offset );
  720.             }
  721.             goodkey = TRUE;
  722.             break;
  723.          case CharRight :
  724.             if (offset == dir->vcols * dir->lines || c < dir->cols) {
  725.                if (c < dir->cols) {
  726.                   change = TRUE;
  727.                   ++c;
  728.                   if (c == dir->cols) {
  729.                      if ( r > dir->prow)
  730.                         r = dir->prow;
  731.                   }
  732.                }
  733.             } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
  734.                          c == dir->cols) {
  735.                change = TRUE;
  736.                offset += dir->lines;
  737.                recalculate_dir( dir, flist, offset );
  738.                if (r > dir->prow)
  739.                   r = dir->prow;
  740.             }
  741.             goodkey = TRUE;
  742.             break;
  743.          case BegOfLine :
  744.             change = TRUE;
  745.             c = r = 1;
  746.             goodkey = TRUE;
  747.             break;
  748.          case EndOfLine :
  749.             change = TRUE;
  750.             r = dir->prow;
  751.             c = dir->cols;
  752.             goodkey = TRUE;
  753.             break;
  754.          case ScreenDown :
  755.             change = TRUE;
  756.             r = (c == dir->cols) ? r = dir->prow : dir->lines;
  757.             goodkey = TRUE;
  758.             break;
  759.          case ScreenUp :
  760.             change = TRUE;
  761.             r = 1;
  762.             goodkey = TRUE;
  763.             break;
  764.       }
  765.       if (goodkey) {
  766.          s_output( blank, dir->row+1, dir->col+19+stem_len, color );
  767.          fno = offset + (c-1)*dir->lines + (r-1);
  768.          s_output( flist[fno].fname, dir->row+1, dir->col+19+stem_len, color );
  769.          ltoa( flist[fno].fsize, asize, 10 );
  770.          s_output( blank, dir->row+2, dir->col+19, color );
  771.          s_output( asize, dir->row+2, dir->col+19, color );
  772.          xygoto( (c-1)*14+dir->col+2, r+dir->row+3 );
  773.          goodkey = FALSE;
  774.          if (change) {
  775.             hlight_line( (oldc-1)*14+dir->col+2, oldr+dir->row+3, 12, color );
  776.             hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color );
  777.             change = FALSE;
  778.          }
  779.       }
  780.    }
  781.    dir->select = fno;
  782.    if (func == AbortCommand)
  783.       ch = ERROR;
  784.    else
  785.       ch = OK;
  786.    return( ch );
  787. }
  788.  
  789.  
  790. /*
  791.  * Name:    recalculate_dir
  792.  * Purpose: To recalcute dir structure when cursor goes ahead or behind screen
  793.  * Date:    February 13, 1992
  794.  * Passed:  dir:    pointer to file structure
  795.  *          flist:  pointer to file structure
  796.  *          offset: number of files from beginning of flist
  797.  * Notes:   Find new number of files on the screen.  Then, find out
  798.  *          how many files names are in the last column.
  799.  */
  800. void recalculate_dir( DIRECTORY *dir , FTYPE *flist, int offset )
  801. {
  802. register int off;
  803.  
  804.    off = offset;
  805.    dir->nfiles = (dir->cnt - off) > dir->avail ? dir->avail :
  806.                 (dir->cnt - off);
  807.    dir->prow = dir->lines - (dir->avail - dir->nfiles);
  808.    write_directory_list( flist+off, *dir );
  809. }
  810.  
  811.  
  812. /*
  813.  * Name:    shell_sort
  814.  * Purpose: To sort file names
  815.  * Date:    February 13, 1992
  816.  * Passed:  flist: pointer to file structure
  817.  *          cnt:   number of files to sort
  818.  */
  819. void shell_sort( FTYPE *flist, int cnt )
  820. {
  821. register int i;
  822. int inc;
  823. int limit;
  824. int change;
  825. FTYPE temp;
  826. register FTYPE *fl;
  827.  
  828.    fl = flist;
  829.    inc = cnt / 2;
  830.    while (inc) {
  831.       limit = cnt - inc - 1;
  832.       do {
  833.          change = FALSE;
  834.          for (i=0; i<=limit; i++) {
  835.             if (_fmemcmp( fl[i].fname, fl[i+inc].fname, 14 ) > 0) {
  836.                memcpy( &temp, fl+i, sizeof(FTYPE) );
  837.                memcpy( fl+i, fl+i+inc, sizeof(FTYPE) );
  838.                memcpy( fl+i+inc, &temp, sizeof(FTYPE) );
  839.                change = i;
  840.             }
  841.          }
  842.          limit = change - inc;
  843.       } while (change);
  844.       inc = inc / 2;
  845.    }
  846. }
  847.  
  848.  
  849. /*
  850.  * Name:    get_current_directory
  851.  * Purpose: get current directory
  852.  * Date:    February 13, 1992
  853.  * Passed:  path:  pointer to buffer to store path
  854.  *          drive: drive to get current directory
  855.  * Notes:   use simple DOS interrupt
  856.  */
  857. int  get_current_directory( char far *path, int drive )
  858. {
  859. int rc;
  860.  
  861.    _asm {
  862.         push    si                      ; save register vars if any
  863.         push    ds                      ; save ds
  864.  
  865.         mov     dx, WORD PTR drive      ; dl = drive, 0 = default, 1 = a, etc..
  866.         mov     si, WORD PTR path       ; get OFFSET of path
  867.         mov     ax, WORD PTR path+2     ; get SEGMENT of path
  868.         mov     ds, ax                  ; put it in ds
  869.         mov     ah, 0x47                ; function 0x47 == get current dir
  870.         int     0x21                    ; standard DOS interrupt
  871.         xor     ax, ax                  ; zero out ax, return OK if no error
  872.         jnc     no_error                ; if carry set, then an error
  873.         mov     ax, -1                  ; return -1 if error
  874. no_error:
  875.         pop     ds                      ; get back ds
  876.         pop     si                      ; get back si
  877.         mov     WORD PTR rc, ax         ; save return code
  878.    }
  879.    if (ceh.flag == ERROR)
  880.       rc = ERROR;
  881.    return( rc );
  882. }
  883.  
  884.  
  885. /*
  886.  * Name:    set_current_directory
  887.  * Purpose: set current directory
  888.  * Date:    February 13, 1992
  889.  * Passed:  new_path: directory path which may include drive letter
  890.  * Notes:   use simple DOS interrupt
  891.  */
  892. int  set_current_directory( char far *new_path )
  893. {
  894. int rc;
  895.  
  896.    _asm {
  897.         push    ds                      ; save ds
  898.  
  899.         mov     dx, WORD PTR new_path   ; get OFFSET of new_path
  900.         mov     ax, WORD PTR new_path+2 ; get SEGMENT of new_path
  901.         mov     ds, ax                  ; put it in ds
  902.         mov     ah, 0x3b                ; function 0x3b == set current dir
  903.         int     0x21                    ; standard DOS interrupt
  904.         xor     ax, ax                  ; zero out ax, return OK if no error
  905.         jnc     no_error                ; if carry set, then an error
  906.         mov     ax, -1                  ; return -1 if error
  907. no_error:
  908.         pop     ds                      ; get back ds
  909.         mov     WORD PTR rc, ax         ; save return code
  910.    }
  911.    if (ceh.flag == ERROR)
  912.       rc = ERROR;
  913.    return( rc );
  914. }
  915.  
  916.  
  917. /*
  918.  * Name:    hlight_line
  919.  * Date:    July 21, 1991
  920.  * Passed:  x:     column to begin hi lite
  921.  *          y:     line to begin hi lite
  922.  *          lgth:  number of characters to hi lite
  923.  *          attr:  attribute color
  924.  * Notes:   The attribute byte is the hi byte.
  925.  */
  926. void hlight_line( int x, int y, int lgth, int attr )
  927. {
  928. int off;
  929. void far *screen_ptr;
  930.  
  931.    screen_ptr = (void far *)g_display.display_address;
  932.    off = y * 160 + 2 * x + 1;  /* add one - so it points to attribute byte */
  933.    _asm {
  934.         push    di              ; save di
  935.  
  936.         mov     cx, lgth        ; number of characters to change color
  937.  
  938.         mov     di, WORD PTR screen_ptr ; get destination - video memory
  939.         add     di, off                 ; add offset
  940.         mov     ax, WORD PTR screen_ptr+2  ;
  941.         mov     es, ax
  942.         mov     ax, attr        ; attribute
  943. lite_len:
  944.         stosb                   ; store a BYTE
  945.         inc     di              ; skip over character to next attribute
  946.         loop    lite_len        ; change next attribute
  947.         pop     di              ; restore di
  948.    }
  949. }
  950.