📄 dirlist.c
字号:
/* * I wrote this function because I'm so stupid, I constantly forget * file names and directory stuff. The main function prompts for a * subdirectory name or a search path. The default search path is the * cwd (current working directory). In addition to being stupid, I'm also * lazy. If the user types a subdirectory name, I think we can assume he * wants to list all files w/o having to type *.* Let's save the cwd on * whatever drive the user wishes to search, so we can restore it we get * thru dir'ing. Use the standard DOS functions to get and set directories. * * The search pattern can contain wild card chars, valid file names, or a * valid subdirectory name. * * Being that TDE 2.2 now handles binary files, lets make .EXE and .COM files * autoload in binary mode. * * Before matching files are displayed on the screen, file names are sorted * using the easy-to-implement and fairly fast Shellsort algorithm. * * See: * * Donald Lewis Shell, "A High-Speed Sorting Procedure." _Communications of * the ACM_ 2 (No. 2): 30-32, 1959. * * See also: * * Donald Ervin Knuth, _The Art of Computer Programming; Volume 3: Sorting * and Searching_, Addison-Wesley, Reading, Mass., 1973, Chapter 5, * "Sorting", pp 84-95. ISBN 0-201-03803-X. * * Robert Sedgewick, _Algorithms in C_, Addison-Wesley, Reading, Mass., * 1990, Chapter 8, "Elementary Sorting Methods", pp 107-111. * ISBN 0-201-51425-7. * * * New editor name: TDE, the Thomson-Davis Editor. * Author: Frank Davis * Date: June 5, 1991, version 1.0 * Date: July 29, 1991, version 1.1 * Date: October 5, 1991, version 1.2 * Date: January 20, 1992, version 1.3 * Date: February 17, 1992, version 1.4 * Date: April 1, 1992, version 1.5 * Date: June 5, 1992, version 2.0 * Date: October 31, 1992, version 2.1 * Date: April 1, 1993, version 2.2 * Date: June 5, 1993, version 3.0 * Date: August 29, 1993, version 3.1 * Date: November 13, 1993, version 3.2 * Date: June 5, 1994, version 4.0 * Date: December 5, 1998, version 5.0 (jmh) * * This code is released into the public domain, Frank Davis. * You may distribute it freely. */#include "tdestr.h"#include "common.h"#include "define.h"#include "tdefunc.h"#include <time.h>static int row_ofs; /* row of first name (jmh 060830) */static int fofs; /* offset in the file list for the */ /* first file (jmh 980523) */static int win_cmp( char *, char * ); /* GotoWindow sort function */static int shl_cmp( char *, char * ); /* SyntaxSelect sort function */static int name_ofs; /* GotoWindow offset to window name *//* * Name: dir_help * Purpose: To prompt the user and list the directory contents * Date: February 13, 1992 * Passed: window: pointer to current window * * jmh 980528: disable command line language; * use return code of attempt_edit_display. * jmh 020723: auto-detect binary files (disable command line -b). * jmh 021023: handle command line options in attempt_edit_display(). */int dir_help( TDE_WIN *window ){char dname[PATH_MAX+2]; /* directory search pattern */int rc;int prompt_line; if (window != NULL) { if (un_copy_line( window->ll, window, TRUE, TRUE ) == ERROR) return( ERROR ); prompt_line = window->bottom_line; } else prompt_line = g_display.end_line; /* * search path or pattern */ dname[0] = '\0'; rc = get_name( dir1, prompt_line, dname, &h_file ); if (rc != ERROR) { rc = list_and_pick( dname, window ); /* * if everything is everything, load in the file selected by user. */ if (rc == OK) rc = attempt_edit_display( dname, (window != NULL) ? LOCAL : GLOBAL ); } return( rc );}/* * Name: dir_help_name * Purpose: To display name of directory * Date: February 13, 1992 * Passed: window: pointer to current window */int dir_help_name( TDE_WIN *window, char *name ){char dname[PATH_MAX+2]; /* directory search pattern */int rc; rc = OK; if (window != NULL) { if (un_copy_line( window->ll, window, TRUE, TRUE ) == ERROR) return( ERROR ); } strcpy( dname, name ); rc = list_and_pick( dname, window ); /* * if everything is everything, load in the file selected by user. */ if (rc == OK) rc = attempt_edit_display( dname, (window != NULL) ? LOCAL : GLOBAL ); return( rc );}/* * Name: list_and_pick * Purpose: To show matching file names and let user pick a file * Date: February 13, 1992 * Passed: dname: directory search pattern * window: pointer to current window * Returns: return code from pick. rc = OK, then edit a new file. * Notes: real work routine of this function. save the cwd and let the * user search upwards or downwards thru the directory structure. * since we are doing DOS directory functions, we need to check the * return code after each DOS call for critical errors. * * jmh 020924: made FTYPE.fname a pointer, allocating exactly as much as space * as required. Tweaked the loop to code the allocation once. * jmh 021019: display the full path, rather than what was initially entered; * don't actually change directory (use the stem); * rather than abort, don't allow selection of an empty directory. */int list_and_pick( char *dname, TDE_WIN *window ){int rc = OK;FFIND dta; /* file finding info */DIRECTORY dir; /* contains all info for dir display */unsigned int cnt; /* number of matching files */LIST *flist, *pl; /* pointer to list of matching files */FTYPE *pf, *ffind;char dbuff[PATH_MAX]; /* temporary directory buff */int stop;int len;char *n;int prompt_line; prompt_line = (window != NULL) ? window->bottom_line : g_display.end_line; ffind = my_findfirst( dname, &dta, ALL_DIRS ); if (ffind == NULL) { error( WARNING, prompt_line, dir2 ); return( ERROR ); } xygoto( -1, -1 ); stop = FALSE; while (stop == FALSE) { /* * Some algorithms alloc the maximum possible number of files in * a directory, eg. 256 or 512. Let's count the number of matching * files so we know exactly how much memory to request from malloc. */ cnt = len = 0; do { ++cnt; len += strlen( ffind->fname ) + 1; ffind = my_findnext( &dta ); } while (ffind != NULL); flist = malloc( cnt * (sizeof(LIST) + sizeof(FTYPE)) + len ); if (flist == NULL) { /* * out of memory */ error( WARNING, prompt_line, main4 ); rc = ERROR; break; } /* * If we had enough memory, find all matching file names. * * when we get here, we have already done: 1) my_findfirst and * my_findnext, 2) counted the number of matching files, and * 3) allocated space. */ pl = flist; pf = (FTYPE *)(pl + cnt); n = (char *)(pf + cnt); ffind = my_findfirst( dname, &dta, ALL_DIRS ); do { /* * pl is pointer that walks down the list info structure. * pf is pointer that walks down the file info structure. * save the file name and file size for each matching * file we find. jmh 980527: save attribute as well. * jmh 031202: save time. */ pl->name = pf->fname = n; pl->color =#if !defined( __UNIX__ ) (ffind->fattr & (HIDDEN | SYSTEM)) ? Color( Disabled ) :#endif Color( Dialog ); pl->data = pf; ++pl;#if defined( __DJGPP__ ) || defined( __TURBOC__ ) n = stpcpy( pf->fname, ffind->fname ) + 1;#else strcpy( pf->fname, ffind->fname ); n += strlen( pf->fname ) + 1;#endif pf->fsize = ffind->fsize; pf->fattr = ffind->fattr; pf->ftime = ffind->ftime; ++pf; ffind = my_findnext( &dta ); } while (ffind != NULL); shell_sort( flist, cnt ); /* * figure out number of rows, cols, etc... then display dir list */ setup_directory_window( &dir, flist, cnt ); write_directory_list( flist, &dir );#if !defined( __UNIX__ ) /* * If only a drive was specified, append the current directory, * to have the trailing slash for get_full_path(). */ if (dta.stem[1] == ':' && dta.stem[2] == '\0') strcpy( dta.stem + 2, "./" );#endif /* * Let user select file name or another search directory. */ get_full_path( dta.stem, dname ); strcat( dname, dta.pattern ); rc = select_file( flist, dname, &dir ); if (rc == OK) { assert( strlen(dta.stem)+strlen(flist[dir.select].name) < PATH_MAX ); get_full_path( dta.stem, dbuff ); strcat( dbuff, flist[dir.select].name ); } /* * give memory back. */ free( flist ); if (rc == ERROR) stop = TRUE; else if (rc == TRUE) { /* * Prompt for a new path/pattern. */ strcpy( dbuff, dname ); len = DIR3_COL + strlen( dir3 ); if (get_string( dir.col+len, dir.row+DIR3_ROW, dir.wid - len - 2, Color( Dialog ), '_', dbuff, &h_file ) == ERROR) { stop = TRUE; rc = ERROR; } else xygoto( -1, -1 ); } /* * If rc is not OK or ERROR, a drive was selected. */#if !defined( __UNIX__ ) else if (rc != OK) { dbuff[0] = rc; dbuff[1] = ':'; strcpy( dbuff + 2, dta.pattern ); }#endif else { /* * If the last character in a file name is '/' then let's * do a dir on selected directory. */ len = strlen( dbuff ); if (dbuff[len-1] == '/') strcpy( dbuff + len, dta.pattern ); else { /* * user selected a file. */ stop = TRUE; strcpy( dname, dbuff ); } } if (!stop) { /* * Ensure there is something to display. If not, redisplay the * current directory. (This will probably only happen on floppies.) */ ffind = my_findfirst( dbuff, &dta, ALL_DIRS ); if (ffind == NULL) ffind = my_findfirst( dname, &dta, ALL_DIRS ); else strcpy( dname, dbuff ); } } if (window != NULL) redraw_screen( window ); return( rc );}/* * Name: setup_directory_window * Purpose: set number of rows and cols in directory window * Date: February 13, 1992 * Passed: dir: pointer to directory structure * list: list of names to be displayed * cnt: number of files * Notes: set up stuff we need to know about how to display files. * * jmh 980524: displayed a few more lines. * jmh 991019: custom frame style based on graphic set. * jmh 991025: use 15 lines if display is over 30; * center. */void setup_directory_window( DIRECTORY *dir, LIST *list, int cnt ){int i, j;int cols[5] = { 0, 0, 0, 0, 0 }; /* number of columns to use */int wid;const char *fc1;const char *fc2;int DIR8_ROW;int inner[2];char temp[40]; /* * setup the fixed vars used in dir display. * dir->col = physical upper left column of dir screen * dir->row = physical upper left row or line of dir screen * dir->wid = width of physical screen * dir->hgt = height of physical screen * dir->max_cols number of columns of files in dir screen * dir->max_lines number of lines of files in each column in dir screen * dir->cnt number of files in list */ dir->cnt = cnt; if (g_status.command == GotoWindow) { /* * Use at most two-thirds of the screen for the window list. */ dir->max_lines = g_display.nlines * 2 / 3; if (cnt < dir->max_lines) dir->max_lines = cnt; /* * Find the longest window name. */ for (i = 0; i < cnt; ++i) { j = strlen( list[i].name ); if (j > cols[0]) cols[0] = j; } /* * Determine the number of columns and lines to use. If they'll all fit * in only one column, use that. Otherwise use the smaller of the * number of columns that fits the lines, or the number of columns that * fits the width. Adjust the lines to fit those columns. */ if (cnt <= dir->max_lines) dir->max_cols = 1; else { cols[1] = (cnt - 1) / dir->max_lines + 1; cols[2] = (g_display.ncols - 4 - 4 + 3) / (cols[0] + 3); dir->max_cols = cols[1] < cols[2] ? cols[1] : cols[2]; dir->max_lines = cnt / dir->max_cols + (cnt % dir->max_cols ? 1 : 0); if (dir->max_lines > g_display.nlines - 6) dir->max_lines = g_display.nlines - 6; } /* * Now set the dimensions of the surrounding frame and each column. */ dir->hgt = dir->max_lines + 2; dir->wid = dir->max_cols * (cols[0] + 3) - 3 + 4; dir->len = cols[0]; } else { dir->max_lines = g_display.nlines > 30 ? 15 : 10; dir->hgt = dir->max_lines + (g_status.command == SyntaxSelect ? 6 : 9); dir->wid = 76;#if defined( __DOS16__ ) dir->len = 12; dir->max_cols = 5;#else /* * Figure out the width of each column (ie. the highlight bar/filename * length). We'll make 12 the smallest ("standard" 8.3) for five columns. * If the overall width is limited to 76, then the longest name can be * 72 (two characters for the frame, space each side). However, let's try * and be clever - if the majority of files are "short", use more columns * and truncate the longer names. */ for (i = 0; i < cnt; ++i) { j = strlen( list[i].name ); if (j <= 12) ++cols[4]; /* depending on the length */ else if (j <= 16) ++cols[3]; /* of the name, increase */ else if (j <= 22) ++cols[2]; /* the appropriate number */ else if (j <= 35) ++cols[1]; /* of columns */ else ++cols[0]; } /* * The number of columns used most is the one selected, unless there's * enough space to display all files without truncation. */ for (i = 0; cols[i] == 0; ++i) ; /* assumes cnt > 0 */ dir->max_cols = i+1; if (cnt > (i+1) * dir->max_lines) { j = cols[i]; for (++i; i < 5; ++i) { if (cols[i] > j) j = cols[i], dir->max_cols = i+1; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -