/* * 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 * * 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" #if defined( __UNIX__ ) /* ********************************************************************** ****************************** PART 1 ****************************** ********************************************************************** * * Let's try to make unix have the look and feel of a PC. */ /* * Name: dir_help * Purpose: To prompt the user and list the directory contents * Date: November 13, 1993 * Passed: window: pointer to current window */ int dir_help( TDE_WIN *window ) { char dname[PATH_MAX+2]; /* directory search pattern */ char stem[PATH_MAX+2]; /* directory stem */ int rc; int file_mode; int bin_length; int prompt_line; if (window != NULL) { entab_linebuff( ); if (un_copy_line( window->ll, window, TRUE ) == ERROR) return( ERROR ); prompt_line = window->bottom_line; } else prompt_line = g_display.nlines; /* * search path or pattern */ dname[0] = '\0'; rc = get_name( dir1, prompt_line, dname, g_display.message_color ); if (rc == OK) { if (validate_path( dname, stem ) == OK) { rc = list_and_pick( dname, stem, window ); if (access( dname, F_OK ) == ERROR) rc = ERROR; /* * if everything is everything, load in the file selected by user. * dname contains complete path to file. stem contains file name. */ if (rc == OK) { if (access( dname, X_OK ) != ERROR) { file_mode = BINARY; bin_length = g_status.file_chunk; } else { file_mode = TEXT; bin_length = 0; } if (window != NULL) attempt_edit_display( dname, LOCAL, file_mode, bin_length ); else attempt_edit_display( dname, GLOBAL, file_mode, bin_length ); } } else { /* * invalid path or file name */ error( WARNING, window != NULL ? window->bottom_line : g_display.nlines, dir2 ); rc = ERROR; } } return( rc ); } /* * Name: dir_help_name * Purpose: Use name entered by user * Date: November 13, 1993 * Passed: window: pointer to current window */ int dir_help_name( TDE_WIN *window, char *name ) { char dname[PATH_MAX+2]; /* directory search pattern */ char stem[PATH_MAX+2]; /* directory stem */ int rc; int file_mode; int bin_length; int prompt_line; rc = OK; if (window != NULL) { entab_linebuff( ); if (un_copy_line( window->ll, window, TRUE ) == ERROR) return( ERROR ); prompt_line = window->bottom_line; } else prompt_line = g_display.nlines; /* * search path or pattern */ strcpy( dname, name ); if (rc == OK) { if ((rc = validate_path( dname, stem )) == OK) { rc = list_and_pick( dname, stem, window ); if (access( dname, F_OK ) == ERROR) rc = ERROR; /* * if everything is everything, load in the file selected by user. * dname contains complete path to file. stem contains file name. */ if (rc == OK) { if (access( dname, X_OK ) != ERROR) { file_mode = BINARY; bin_length = g_status.file_chunk; } else { file_mode = TEXT; bin_length = 0; } if (window != NULL) attempt_edit_display( dname, LOCAL, file_mode, bin_length ); else attempt_edit_display( dname, GLOBAL, file_mode, bin_length ); } } else /* * invalid path or file name */ error( WARNING, window != NULL ? window->bottom_line : g_display.nlines, dir2 ); } return( rc ); } /* * Name: validate_path * Purpose: make sure we got a valid search pattern or subdirectory * Date: November 13, 1993 * Passed: dname: search path entered by user * stem: directory stem is returned * Returns: successful or not * Notes: we need to validate the search directory. we only let the * user enter a valid directory name -- there are too damn * many expections and special cases in unix. * if the user presses enter, lets assume he wants cwd. */ int validate_path( char *dname, char *stem ) { int rc; int len; int i; char *p; char temp[PATH_MAX+2]; /* directory stem */ struct stat fstat; DIR *dp; /* DIR is defined in */ rc = OK; /* * if path name is empty then the current working directory is implied. */ if (dname[0] == '\0') { if (getcwd( temp, PATH_MAX+2 ) != NULL) { /* * copy current working directory into stem. */ strcpy( dname, temp ); strcpy( stem, dname ); } else rc = ERROR; } if (rc == OK) { /* * get the attributes of the search pattern. unlike DOS where we * can do file patterns, ie. *.c, lets only do directories in unix. * the functions below are POSIX, i think... */ if (stat( dname, &fstat ) >= 0) { if (!S_ISDIR( fstat.st_mode )) rc = ERROR; else strcpy( stem, dname ); } #if defined( __TDE_JUNK__ ) else { /* * OK. now let's try to do a UNIX file pattern, i.e. *.c */ if ((dp = opendir( dname )) == NULL) { /* * if user entered something like *.c, UNIX returns an ERROR. * now, let's get the FULL path and try it again. */ if (getcwd( temp, PATH_MAX+2 ) != NULL) { len = strlen( temp ); if (temp[len-1] != '/') strcat( temp, "/" ); strcat( temp, dname ); if ((dp = opendir( temp )) == NULL) rc = ERROR; else { strcpy( dname, temp ); closedir( dp ); } } else rc = ERROR; } else closedir( dp ); if (rc == OK) { strcpy( temp, dname ); len = strlen( dname ); for (i=len,p=temp+len; i>=0; i--) { /* * if we run into the '/' then we got a stem. */ if (*p == '/') { p = temp + i; *(p+1) = '\0'; break; /* * if we're at the beginning of the string, stem == '\0' */ } else if (i == 0) { strcpy( temp, "/" ); break; } --p; } strcpy( stem, temp ); } } #endif } if (rc == OK) { /* * if this is the root directory ( / ), don't append '/' to it. */ len = strlen( stem ); if (stem[len-1] != '/') strcat( stem, "/" ); } return( rc ); } /* * Name: list_and_pick * Purpose: To show matching file names and let user pick a file * Date: November 13, 1993 * Passed: dname: directory search pattern * stem: stem of directory search pattern (directory name with '/') * 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. */ int list_and_pick( char *dname, char *stem, TDE_WIN *window ) { int rc; UNIX_DTA unix_dta; /* our unix dta */ DIR *dp; /* DIR is defined in */ struct stat fstat; /* stat buffer */ DIRECTORY dir; /* contains all info for dir display */ unsigned int cnt; /* number of matching files */ FTYPE *flist, *p; /* pointer to list of matching files */ char cwd[PATH_MAX+2]; /* save the current working directory in this buff */ char dbuff[PATH_MAX+2]; /* temporary directory buff */ char prefix[PATH_MAX+2];/* directory prefix */ char *eos; /* end of stem pointer */ int change_directory = FALSE; int stop; int len; int prompt_line; /* * who knows the directory structure for unix systems??? it varies from * release to release and from port to port. use POSIX functions, which * also change from release to release (IEEE 1003.1 vs IEEE 1003.1a), * to get directory elements. */ rc = OK; if ((dp = opendir( dname )) == NULL) { rc = ERROR; flist = NULL; } else { /* * eos == end of stem */ strcpy( prefix, stem ); eos = prefix + strlen( prefix ); for (cnt=1; my_findnext( dp, &unix_dta ) == OK;) { strcpy( eos, unix_dta.fname ); if (stat( eos, &fstat ) >= 0) { if (S_ISREG( fstat.st_mode ) || S_ISDIR( fstat.st_mode )) ++cnt; } } closedir( dp ); flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) ); } if (rc != ERROR && flist != NULL) { prompt_line = g_display.nlines; stop = FALSE; if (getcwd( cwd, PATH_MAX+2 ) == NULL) { stop = TRUE; rc = ERROR; } while (stop == FALSE) { /* * If we had enough memory, find all matching file names. Append * '/' to the end of subdirectory names so user will know if * name is a directory. Might as well find everything, because * i also forget subdirectory names, too. * * 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. */ p = flist; cnt = 0; if ((dp = opendir( dname )) == NULL) rc = ERROR; if (rc != ERROR) { /* * p is pointer that walks down the file info structure. * save the file name, file size, and directory character, * if needed, for each matching file we find. */ /* * eos == end of stem */ strcpy( prefix, stem ); eos = prefix + strlen( prefix ); for (cnt=0; my_findnext( dp, &unix_dta ) == OK;) { assert( strlen( unix_dta.fname ) < NAME_MAX + 2 ); strcpy( eos, unix_dta.fname ); if (stat( eos, &fstat ) >= 0) { if (S_ISREG( fstat.st_mode ) || S_ISDIR( fstat.st_mode )) { strcpy( p->fname, unix_dta.fname ); p->fsize = fstat.st_size; p->access = OK; if (S_ISDIR( fstat.st_mode )) { strcat( p->fname, "/" ); /* * test for permission */ if (access( prefix, X_OK | R_OK ) < 0 ) p->access = ERROR; } ++cnt; ++p; } } } closedir( dp ); } if (rc != ERROR) { shell_sort( flist, cnt ); /* * figure out number of rows, cols, etc... then display dir list */ setup_directory_window( &dir, cnt ); write_directory_list( flist, dir ); /* * Let user select file name or another search directory. * Save the choice in dbuff. rc == OK if user selected file or dir. */ rc = select_file( flist, stem, &dir ); assert( strlen( flist[dir.select].fname ) < NAME_MAX ); strcpy( dbuff, flist[dir.select].fname ); } /* * give memory back. */ free( flist ); flist = NULL; if (rc == ERROR) stop = TRUE; else { len = strlen( dbuff ); /* check this */ /* * If the last character in a file name is '/' then let's * do a dir on selected directory. See the matching * else when the user selects a file. */ if (dbuff[len-1] == '/') { /* * Stem has subdirectory path. dbuff has selected path. * Create a new dname with stem and dbuff. */ assert( strlen( stem ) + strlen( dbuff ) < PATH_MAX ); strcpy( dname, stem ); strcat( dname, dbuff ); len = strlen( dname ); strcpy( dbuff, dname ); /* * The last character in dbuff is '/', because we append the * '/' to every directory entry in the file list. Replace * it with a NULL char then we will have a valid path name. */ dbuff[len-1] = '\0'; /* * now let's change to the selected subdirectory. */ rc = set_current_directory( dbuff ); if (rc == OK) { /* * Every time we change directories, we need to get the * current directory so we will be sure to have the * correct path. */ rc = get_current_directory( dbuff, PATH_MAX + 2 ); if (rc == OK) { assert( strlen( dbuff ) < PATH_MAX ); strcpy( dname, dbuff ); change_directory = TRUE; } } /* * Validate the new path and allocate memory for the * matching files. */ if (rc == OK) rc = validate_path( dname, stem ); if (rc == OK) { if ((dp = opendir( dname )) == NULL) { rc = ERROR; flist = NULL; } else { /* * eos == end of stem. here, we just count the * number of files and subdirectories and allocate * enough memory for the flist. */ strcpy( prefix, stem ); eos = prefix + strlen( prefix ); for (cnt=1; my_findnext( dp, &unix_dta ) == OK;) { strcpy( eos, unix_dta.fname ); if (stat( eos, &fstat ) >= 0) { if (S_ISREG( fstat.st_mode ) || S_ISDIR( fstat.st_mode )) ++cnt; } } closedir( dp ); flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) ); } } if (flist == NULL || rc == ERROR) { stop = TRUE; rc = ERROR; if (flist != NULL) { free( flist ); flist = NULL; } } } else { /* * user selected a file. store complete path in dname and * file name in stem. */ rc = OK; stop = TRUE; assert( strlen( stem ) + strlen( dbuff ) < PATH_MAX ); strcpy( dname, stem ); strcat( dname, dbuff ); strcpy( stem, dbuff ); } } } /* * Go back to the current directory if needed. */ if (change_directory) set_current_directory( cwd ); if (window != NULL) redraw_screen( window ); } else { /* * out of memory */ error( WARNING, window != NULL ? window->bottom_line : g_display.nlines, dir3 ); rc = ERROR; } return( rc ); } /* * Name: setup_directory_window * Purpose: set number of rows and cols in directory window * Date: November 13, 1993 * Modified: November 13, 1993, Frank Davis per Byrial Jensen * Passed: dir: pointer to directory structure * cnt: number of files * Notes: set up stuff we need to know about how to display files. */ void setup_directory_window( DIRECTORY *dir, int cnt ) { int i; int wid; char temp[MAX_COLS]; /* line to output */ /* * 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->col = 3; dir->row = 5; wid = dir->wid = 72; dir->hgt = 16; dir->max_cols = 4; dir->max_lines = 10; dir->cnt = cnt; /* * Find out how many lines in each column are needed to display * matching files. */ dir->lines = dir->cnt / dir->max_cols + (dir->cnt % dir->max_cols ? 1 : 0); if (dir->lines > dir->max_lines) dir->lines = dir->max_lines; /* * Find out how many columns of file names we need. */ dir->cols = dir->cnt / dir->lines + (dir->cnt % dir->lines ? 1 : 0); if (dir->cols > dir->max_cols) dir->cols = dir->max_cols; /* * Find the maximun number of file names we can display in help screen. */ dir->avail = dir->lines * dir->cols; /* * Now find the number of file names we do have on the screen. Every * time we slide the "window", we have to calculate a new nfiles. */ dir->nfiles = dir->cnt > dir->avail ? dir->avail : dir->cnt; /* * A lot of times, the number of matching files will not fit evenly * in our help screen. The last column on the right will be partially * filled, hence the variable name prow (partial row). When there are * more file names than can fit on the screen, we have to calculate * prow every time we slide the "window" of files. */ dir->prow = dir->lines - (dir->avail - dir->nfiles); /* * Find out how many "virtual" columns of file names we have. If * all the files can fit in the dir screen, there will be no * virtual columns. */ if (dir->cnt < dir->avail) dir->vcols = 0; else dir->vcols = (dir->cnt - dir->avail) / dir->max_lines + ((dir->cnt - dir->avail) % dir->max_lines ? 1 : 0); /* * Find the physical display column in dir screen. */ dir->flist_col[0] = dir->col + 2; for (i=1; imax_cols; i++) dir->flist_col[i] = dir->flist_col[i-1] + 17; /* * Now, draw the borders of the dir screen. */ for (i=0; i < dir->hgt; i++) { if (i == 0 || i == dir->hgt-1) { memset( temp, HORIZONTAL_LINE, wid ); temp[wid] = '\0'; if (i == 0) { temp[0] = CORNER_LEFT_UP; temp[wid-1] = CORNER_RIGHT_UP; } else { temp[0] = CORNER_LEFT_DOWN; temp[wid-1] = CORNER_RIGHT_DOWN; } } else { memset( temp, ' ', wid ); temp[wid] = '\0'; temp[0] = temp[wid-1] = VERTICAL_LINE; } s_output( temp, dir->row+i, dir->col, g_display.help_color ); } /* * Write headings in help screen. */ s_output( dir1, dir->row+DIR1_ROW, dir->col+DIR1_COL, g_display.help_color ); s_output( dir4, dir->row+DIR4_ROW, dir->col+DIR4_COL, g_display.help_color ); s_output( dir5, dir->row+DIR5_ROW, dir->col+DIR5_COL, g_display.help_color ); s_output( dir6, dir->row+DIR6_ROW, dir->col+DIR6_COL, g_display.help_color ); s_output( dir7, dir->row+DIR7_ROW, dir->col+DIR7_COL, g_display.help_color ); } /* * Name: write_directory_list * Purpose: given directory list, display matching files * Date: November 13, 1993 * Passed: flist: pointer to list of files * dir: directory display structure * Notes: blank out the previous file name and display the new one. */ void write_directory_list( FTYPE *flist, DIRECTORY dir ) { FTYPE *p, *top; int i; int j; int k; int end; int line; int col; int color; char temp[NAME_MAX+2]; char blank[20]; /* blank out file names */ memset( blank, ' ', 15 ); blank[15] = '\0'; color = g_display.help_color; top = flist; for (i=0; i < dir.lines; ++i) { p = top; end = FALSE; for (j=0; j < dir.cols; ++j) { col = dir.flist_col[j]; line = i + dir.row + 5; /* * We need to blank out all lines and columns used to display * files, because there may be some residue from a previous dir */ s_output( blank, line, col, color ); if (!end) { if (strlen( p->fname ) <= 15) s_output( p->fname, line, col, color ); else { assert( strlen( p->fname ) < NAME_MAX + 1 ); strcpy( temp, p->fname ); temp[15] = '\0'; s_output( temp, line, col, color ); } p += dir.lines; k = p - flist; if (k >= dir.nfiles) end = TRUE; } } ++top; } } /* * Name: select_file * Purpose: To let user select a file from dir list * Date: November 13, 1993 * Modified: November 13, 1993, Frank Davis per Byrial Jensen * Passed: flist: pointer to list of files * stem: base directory * dir: directory display stuff * Notes: let user move thru the file names with the cursor keys */ int select_file( FTYPE *flist, char *stem, DIRECTORY *dir ) { int ch; /* input character from user */ int func; /* function of character input by user */ int fno; /* index into flist of the file under cursor */ int goodkey; /* is key a recognized function key? */ int r; /* current row of cursor */ int c; /* current column of cursor */ int offset; /* offset into file list */ int stop; /* stop indicator */ int color; /* color of help screen */ int file_color; /* color of current file */ int change; /* boolean, hilite another file? */ int oldr; /* old row */ int oldc; /* old column */ char asize[20]; /* ascii file size */ char blank[NAME_MAX]; /* blank out file names */ char temp[PATH_MAX]; /* * initial everything. */ memset( blank, ' ', 15 ); blank[15] = '\0'; c = r = 1; ch = fno = offset = 0; color = g_display.help_color; file_color = g_display.hilited_file; goodkey = TRUE; stop = FALSE; /* * UNIX directory names can get quite long. lets only show the first 50. */ if (strlen( stem ) < 50) s_output( stem, dir->row+DIR1_ROW, dir->col+strlen( dir1 )+3, color ); else { strcpy( temp, stem ); temp[50] = '\0'; s_output( temp, dir->row+DIR1_ROW, dir->col+strlen( dir1 )+3, color ); } if (strlen( flist[fno].fname ) < 50 ) s_output( flist[fno].fname, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3, color ); else { strcpy( temp, flist[fno].fname ); temp[50] = '\0'; s_output( temp, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3, color ); } my_ltoa( flist[fno].fsize, asize, 10 ); s_output( blank, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color ); s_output( asize, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color ); my_ltoa( dir->cnt, asize, 10 ); s_output( blank, dir->row+DIR6_ROW, dir->col+DIR6_COL+strlen( dir6 ), color); s_output( asize, dir->row+DIR6_ROW, dir->col+DIR6_COL+strlen( dir6 ), color); xygoto( (c-1)*17+dir->col+2, r+dir->row+4 ); hlight_line( (c-1)*17+dir->col+2, r+dir->row+4, 15, file_color ); refresh( ); change = FALSE; func = AbortCommand; while (stop == FALSE) { oldr = r; oldc = c; ch = getkey( ); func = getfunc( ch ); /* * User may have redefined the Enter and ESC keys. Make the Enter key * perform a Rturn in this function. Make the ESC key do an AbortCommand. */ if (ch == RTURN) func = Rturn; else if (ch == ESC) func = AbortCommand; switch (func) { case Rturn : case NextLine : case BegNextLine : if (flist[fno].access == ERROR) { error( WARNING, g_display.nlines, dir8 ); xygoto( (c-1)*17+dir->col+2+15, r+dir->row+4 ); } else stop = TRUE; break; case AbortCommand : stop = TRUE; break; case LineUp : if (r > 1) { change = TRUE; --r; } else { r = dir->lines; change = TRUE; if (offset == 0 || c > 1) { if (c > 1) --c; } else if (dir->vcols > 0 && offset > 0 && c == 1) { /* * recalculate the dir display stuff. */ offset -= dir->lines; recalculate_dir( dir, flist, offset ); } } goodkey = TRUE; break; case LineDown : if (r < dir->prow) { change = TRUE; ++r; } else if (r < dir->lines && c != dir->cols) { change = TRUE; ++r; } else { change = TRUE; r = 1; if (offset == dir->vcols * dir->lines || c < dir->cols) { if (c < dir->cols) ++c; } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines && c == dir->cols) { offset += dir->lines; recalculate_dir( dir, flist, offset ); } } goodkey = TRUE; break; case CharLeft : if (offset == 0 || c > 1) { if (c > 1) { change = TRUE; --c; } } else if (dir->vcols > 0 && offset > 0 && c == 1) { change = TRUE; /* * recalculate the dir display stuff. */ offset -= dir->lines; recalculate_dir( dir, flist, offset ); } goodkey = TRUE; break; case CharRight : if (offset == dir->vcols * dir->lines || c < dir->cols) { if (c < dir->cols) { change = TRUE; ++c; if (c == dir->cols) { if ( r > dir->prow) r = dir->prow; } } } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines && c == dir->cols) { change = TRUE; offset += dir->lines; recalculate_dir( dir, flist, offset ); if (r > dir->prow) r = dir->prow; } goodkey = TRUE; break; case BegOfLine : change = TRUE; c = r = 1; goodkey = TRUE; break; case EndOfLine : change = TRUE; r = dir->prow; c = dir->cols; goodkey = TRUE; break; case ScreenDown : change = TRUE; r = (c == dir->cols) ? r = dir->prow : dir->lines; goodkey = TRUE; break; case ScreenUp : change = TRUE; r = 1; goodkey = TRUE; break; default : break; } if (goodkey) { memset( temp, ' ', 50 ); temp[50] = '\0'; s_output( temp, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3, color ); fno = offset + (c-1)*dir->lines + (r-1); if (strlen( flist[fno].fname ) < 50) s_output( flist[fno].fname, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3, color ); else { strcpy( temp, flist[fno].fname ); temp[50] = '\0'; s_output( temp, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3,color); } my_ltoa( flist[fno].fsize, asize, 10 ); s_output( blank, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color ); s_output( asize, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color ); xygoto( (c-1)*17+dir->col+2, r+dir->row+4 ); goodkey = FALSE; if (change) { hlight_line( (oldc-1)*17+dir->col+2, oldr+dir->row+4, 15, color ); hlight_line( (c-1)*17+dir->col+2, r+dir->row+4, 15, file_color ); change = FALSE; } } refresh( ); } dir->select = fno; return( func == AbortCommand ? ERROR : OK ); } #else /* ********************************************************************** ****************************** PART 2 ****************************** ********************************************************************** * * Calls to BIOS and writes to PC hardware. */ /* * Name: dir_help * Purpose: To prompt the user and list the directory contents * Date: February 13, 1992 * Passed: window: pointer to current window */ int dir_help( TDE_WIN *window ) { char dname[MAX_COLS+2]; /* directory search pattern */ char stem[MAX_COLS+2]; /* directory stem */ char drive[_MAX_DRIVE]; /* splitpath drive buff */ char dir[_MAX_DIR]; /* splitpath dir buff */ char fname[_MAX_FNAME]; /* splitpath fname buff */ char ext[_MAX_EXT]; /* splitpath ext buff */ char display_buff[(MAX_COLS+2)*2]; int rc; int file_mode; int bin_length; int prompt_line; if (window != NULL) { entab_linebuff( ); if (un_copy_line( window->ll, window, TRUE ) == ERROR) return( ERROR ); prompt_line = window->bottom_line; } else prompt_line = g_display.nlines; /* * search path or pattern */ dname[0] = '\0'; rc = get_name( dir1, prompt_line, dname, g_display.message_color ); if (rc == OK) { if (validate_path( dname, stem ) == OK) { rc = list_and_pick( dname, stem, window ); /* * if everything is everything, load in the file selected by user. */ if (rc == OK) { file_mode = TEXT; bin_length = 0; _splitpath( dname, drive, dir, fname, ext ); if (stricmp( ext, ".exe" ) == 0 || stricmp( ext, ".com" ) == 0) { file_mode = BINARY; bin_length = g_status.file_chunk; } else if (g_status.file_mode == BINARY) { save_screen_line( 0, prompt_line, display_buff ); /* * open file in BINARY mode (y/n) */ set_prompt( ed18, prompt_line ); if (get_yn( ) == A_YES) { file_mode = BINARY; bin_length = g_status.file_chunk; } restore_screen_line( 0, prompt_line, display_buff ); } if (window != NULL) attempt_edit_display( dname, LOCAL, file_mode, bin_length ); else attempt_edit_display( dname, GLOBAL, file_mode, bin_length ); } } else { /* * invalid path or file name */ error( WARNING, window != NULL ? window->bottom_line : g_display.nlines, dir2 ); rc = ERROR; } } 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[MAX_COLS+2]; /* directory search pattern */ char stem[MAX_COLS+2]; /* directory stem */ char drive[_MAX_DRIVE]; /* splitpath drive buff */ char dir[_MAX_DIR]; /* splitpath dir buff */ char fname[_MAX_FNAME]; /* splitpath fname buff */ char ext[_MAX_EXT]; /* splitpath ext buff */ int rc; int file_mode; int bin_length; int prompt_line; rc = OK; if (window != NULL) { entab_linebuff( ); if (un_copy_line( window->ll, window, TRUE ) == ERROR) return( ERROR ); prompt_line = window->bottom_line; } else prompt_line = g_display.nlines; /* * search path or pattern */ strcpy( dname, name ); if (rc == OK) { if ((rc = validate_path( dname, stem )) == OK) { rc = list_and_pick( dname, stem, window ); /* * if everything is everything, load in the file selected by user. */ if (rc == OK) { file_mode = TEXT; bin_length = 0; _splitpath( dname, drive, dir, fname, ext ); if (stricmp( ext, ".exe" ) == 0 || stricmp( ext, ".com" ) == 0) { file_mode = BINARY; bin_length = g_status.file_chunk; } if (window != NULL) attempt_edit_display( dname, LOCAL, file_mode, bin_length ); else attempt_edit_display( dname, GLOBAL, file_mode, bin_length ); } } else /* * invalid path or file name */ error( WARNING, window != NULL ? window->bottom_line : g_display.nlines, dir2 ); } return( rc ); } /* * Name: validate_path * Purpose: make sure we got a valid search pattern or subdirectory * Date: February 13, 1992 * Passed: dname: search path entered by user * stem: directory stem is returned * Returns: successful or not * Notes: we need to validate the search path or pattern. if the search * pattern is valid, then we need to get the search stem. * the user may enter a subdirectory or some kind of search pattern. * if the user enters a subdirectory, then there are a few things * we need to take care of 1) find out if the subdirectory is * the root, 2) append a '\' to the subdirectory so we can create * a search pattern for the subdirectory, 3) don't append '\' to * the root, it already has a '\'. * if the user enters a search pattern, then we need to dissect the * search path. we must create a stem from the search pattern. */ int validate_path( char *dname, char *stem ) { int rc; DTA dta; /* temp disk transfer struct for findfirst, etc. */ int fattr; int i; int len; char *p; char temp[MAX_COLS+2]; /* directory stem */ /* * if path name is void then the current working directory is implied. */ if (dname[0] == '\0') { assert( strlen( stardotstar ) < MAX_COLS ); strcpy( dname, stardotstar ); stem[0] = '\0'; rc = OK; } else { /* * get the attributes of the search pattern, so we can determine if * this is a pattern or subdirectory. */ rc = get_fattr( dname, &fattr ); if (rc == OK && (fattr & SUBDIRECTORY)) { assert( strlen( dname ) < MAX_COLS ); strcpy( stem, dname ); /* * if this is the root directory ( \ ), don't append '\' to it. * user entered a subdirectory - append *.* to get contents of * subdirectory. */ len = strlen( stem ); if (stem[len-1] != '\\') { strcat( stem, "\\" ); strcat( dname, "\\" ); } strcat( dname, stardotstar ); /* * not a subdirectory. let's see if any files match the search * pattern. */ } else if (rc != ERROR) { if ((rc = my_findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM | SUBDIRECTORY | ARCHIVE )) == OK) { /* * copy dname to "temp" so we can use "temp" to find the stem. * we need to search the pattern backwards to figure the stem. */ assert( strlen( dname ) < MAX_COLS ); strcpy( temp, dname ); len = strlen( dname ); for (i=len,p=temp+len; i>=0; i--) { /* * if we run into the '\' or the ':', then we got a stem. */ if (*p == '\\' || *p == ':') { p = temp + i; *(p+1) = '\0'; break; /* * if we're at the beginning of the string, stem == '\0' */ } else if (i == 0) { *p = '\0'; break; } --p; } assert( strlen( temp ) < MAX_COLS ); strcpy( stem, temp ); } else rc = ERROR; /* * user did not enter a valid subdirectory name or search pattern. */ } else rc = ERROR; } 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 * stem: stem of 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. */ int list_and_pick( char *dname, char *stem, TDE_WIN *window ) { int rc; DTA dta; /* disk transfer address for findfirst */ DIRECTORY dir; /* contains all info for dir display */ unsigned int cnt; /* number of matching files */ FTYPE *flist, *p; /* pointer to list of matching files */ char cwd[MAX_COLS]; /* save the current working directory in this buff */ char dbuff[MAX_COLS]; /* temporary directory buff */ char prefix[MAX_COLS]; /* directory prefix */ int change_directory = FALSE; int stop; int len; int drive; /* * 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 egxactly how much memory to request from calloc. * Depending on the op system, disk media, disk format, or version of DOS, * the max number of files may vary, anyway, also, additionally. * (see the unix section above, where the number of files changes with * each port of unix to new toasters.) */ rc = my_findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM | SUBDIRECTORY | ARCHIVE ); if (rc != ERROR) { for (cnt=1; (rc = my_findnext( &dta )) == OK;) ++cnt; flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) ); } else flist = NULL; if (rc != ERROR && flist != NULL) { stop = FALSE; /* * If user entered drive name in search pattern, find out the drive and * directory stem. */ if (stem[1] == ':') { /* * If the second character of the search pattern is a ':', the * the first character of the pattern should be the drive. * Convert drive to lower case and get a numerical representation. * CAVEAT: In DOS v 2.x, there may be up to 63 logical drives. * my algorithm may blow up if the number of logical drives * is greater than 'Z'. * For DOS >= 3, the number of drives is limited to 26, I think. */ drive = stem[0]; if (drive < 'a') drive += 32; drive = drive - 'a' + 1; rc = get_current_directory( dbuff, drive ); if (rc == ERROR) stop = TRUE; else { /* * Put drive letter, ':', and '\' in front of current directory. */ prefix[0] = (char)(drive - 1 + 'a'); prefix[1] = ':'; prefix[2] = '\\'; prefix[3] = '\0'; assert( strlen( prefix ) + strlen( dbuff ) < MAX_COLS ); strcpy( cwd, prefix ); strcat( cwd, dbuff ); } /* * else get current directory from default drive */ } else { /* * 0 = default drive. */ drive = 0; rc = get_current_directory( dbuff, drive ); if (rc == ERROR) stop = TRUE; else { /* * Put a '\' in front of the current directory. */ prefix[0] = '\\'; prefix[1] = '\0'; assert( strlen( prefix ) + strlen( dbuff ) < MAX_COLS ); strcpy( cwd, prefix ); strcat( cwd, dbuff ); } } while (stop == FALSE) { /* * If we had enough memory, find all matching file names. Append * '\\' at the end of subdirectory names so user will know if * name is a directory. Might as well find everything, because * i also forget subdirectory names, too. * * 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. */ p = flist; cnt = 0; rc = my_findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM | SUBDIRECTORY | ARCHIVE ); if (rc != ERROR) { /* * p is pointer that walks down the file info structure. * save the file name, file size, and directory character, * if needed, for each matching file we find. */ assert( strlen( dta.name ) < 14 ); strcpy( p->fname, dta.name ); p->fsize = dta.size; if (dta.attrib & SUBDIRECTORY) strcat( p->fname, "\\" ); for (cnt=1; (rc = my_findnext( &dta )) == OK; ) { ++p; assert( strlen( dta.name ) < 14 ); strcpy( p->fname, dta.name ); p->fsize = dta.size; if (dta.attrib & SUBDIRECTORY) strcat( p->fname, "\\" ); cnt++; } } if (rc != ERROR) { shell_sort( flist, cnt ); /* * figure out number of rows, cols, etc... then display dir list */ setup_directory_window( &dir, cnt ); write_directory_list( flist, dir ); /* * Let user select file name or another search directory. * Save the choice in dbuff. rc == OK if user selected file or dir. */ rc = select_file( flist, stem, &dir ); assert( strlen( flist[dir.select].fname ) < MAX_COLS ); strcpy( dbuff, flist[dir.select].fname ); } /* * give memory back. */ free( flist ); flist = NULL; if (rc == ERROR) stop = TRUE; else { len = strlen( dbuff ); /* * If the last character in a file name is '\' then let's * do a dir on selected directory. See the matching * else when the user selects a file. */ if (dbuff[len-1] == '\\') { /* * Stem has subdirectory path. dbuff has selected path. * Create a new dname with stem and dbuff. */ assert( strlen( stem ) + strlen( dbuff ) < MAX_COLS ); strcpy( dname, stem ); strcat( dname, dbuff ); len = strlen( dname ); strcpy( dbuff, dname ); /* * The last character in dbuff is '\', because we append the * '\' to every directory entry in the file list. Replace * it with a NULL char then we will have a valid path name. */ dbuff[len-1] = '\0'; /* * now let's change to the selected subdirectory. */ rc = set_current_directory( dbuff ); if (rc == OK) { /* * Every time we change directories, we need to get the * current directory so we will be sure to have the * correct path. */ rc = get_current_directory( dbuff, drive ); if (rc == OK) { assert( strlen( prefix ) + strlen( dbuff ) < MAX_COLS ); strcpy( dname, prefix ); strcat( dname, dbuff ); change_directory = TRUE; } } /* * Validate the new path and allocate memory for the * matching files. */ if (rc == OK) rc = validate_path( dname, stem ); if (rc == OK) { rc = my_findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM | SUBDIRECTORY | ARCHIVE ); if (rc != ERROR) { for (cnt=1; (rc = my_findnext( &dta )) == OK;) ++cnt; flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) ); } } if (flist == NULL || rc == ERROR) { stop = TRUE; rc = ERROR; if (flist != NULL) { free( flist ); flist = NULL; } } } else { /* * user selected a file. store fname in dname and return. */ rc = OK; stop = TRUE; assert( strlen( stem ) + strlen( dbuff ) < MAX_COLS ); strcpy( dname, stem ); strcat( dname, dbuff ); } } } /* * Go back to the current directory if needed. */ if (change_directory) set_current_directory( cwd ); if (window != NULL) redraw_screen( window ); } else { /* * out of memory or bad dir */ error( WARNING, window != NULL ? window->bottom_line : g_display.nlines, dir3 ); rc = ERROR; } 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 * cnt: number of files * Notes: set up stuff we need to know about how to display files. */ void setup_directory_window( DIRECTORY *dir, int cnt ) { int i; int wid; char temp[MAX_COLS]; /* line to output */ /* * 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->col = 3; dir->row = 5; wid = dir->wid = 72; dir->hgt = 16; dir->max_cols = 5; dir->max_lines = 9; dir->cnt = cnt; /* * Find out how many lines in each column are needed to display * matching files. */ dir->lines = dir->cnt / dir->max_cols + (dir->cnt % dir->max_cols ? 1 : 0); if (dir->lines > dir->max_lines) dir->lines = dir->max_lines; /* * Find out how many columns of file names we need. */ dir->cols = dir->cnt / dir->lines + (dir->cnt % dir->lines ? 1 : 0); if (dir->cols > dir->max_cols) dir->cols = dir->max_cols; /* * Find the maximun number of file names we can display in help screen. */ dir->avail = dir->lines * dir->cols; /* * Now find the number of file names we do have on the screen. Every * time we slide the "window", we have to calculate a new nfiles. */ dir->nfiles = dir->cnt > dir->avail ? dir->avail : dir->cnt; /* * A lot of times, the number of matching files will not fit evenly * in our help screen. The last column on the right will be partially * filled, hence the variable name prow (partial row). When there are * more file names than can fit on the screen, we have to calculate * prow every time we slide the "window" of files. */ dir->prow = dir->lines - (dir->avail - dir->nfiles); /* * Find out how many "virtual" columns of file names we have. If * all the files can fit in the dir screen, there will be no * virtual columns. */ if (dir->cnt < dir->avail) dir->vcols = 0; else dir->vcols = (dir->cnt - dir->avail) / dir->max_lines + ((dir->cnt - dir->avail) % dir->max_lines ? 1 : 0); /* * Find the physical display column in dir screen. */ dir->flist_col[0] = dir->col + 2; for (i=1; imax_cols; i++) dir->flist_col[i] = dir->flist_col[i-1] + 14; /* * Now, draw the borders of the dir screen. */ for (i=0; i < dir->hgt; i++) { if (i == 0 || i == dir->hgt-1) { memset( temp, HORIZONTAL_LINE, wid ); temp[wid] = '\0'; if (i == 0) { temp[0] = CORNER_LEFT_UP; temp[wid-1] = CORNER_RIGHT_UP; } else { temp[0] = CORNER_LEFT_DOWN; temp[wid-1] = CORNER_RIGHT_DOWN; } } else { memset( temp, ' ', wid ); temp[wid] = '\0'; temp[0] = temp[wid-1] = VERTICAL_LINE; } s_output( temp, dir->row+i, dir->col, g_display.help_color ); } /* * Write headings in help screen. */ s_output( dir4, dir->row+DIR4_ROW, dir->col+DIR4_COL, g_display.help_color ); s_output( dir5, dir->row+DIR5_ROW, dir->col+DIR5_COL, g_display.help_color ); s_output( dir6, dir->row+DIR6_ROW, dir->col+DIR6_COL, g_display.help_color ); s_output( dir7, dir->row+DIR7_ROW, dir->col+DIR7_COL, g_display.help_color ); } /* * Name: write_directory_list * Purpose: given directory list, display matching files * Date: February 13, 1992 * Passed: flist: pointer to list of files * dir: directory display structure * Notes: blank out the previous file name and display the new one. */ void write_directory_list( FTYPE *flist, DIRECTORY dir ) { FTYPE *p, *top; int i; int j; int k; int end; int line; int col; int color; char blank[20]; /* blank out file names */ memset( blank, ' ', 12 ); blank[12] = '\0'; color = g_display.help_color; top = flist; for (i=0; i < dir.lines; ++i) { p = top; end = FALSE; for (j=0; j < dir.cols; ++j) { col = dir.flist_col[j]; line = i + dir.row + 4; /* * We need to blank out all lines and columns used to display * files, because there may be some residue from a previous dir */ s_output( blank, line, col, color ); if (!end) { s_output( p->fname, line, col, color ); p += dir.lines; k = p - flist; if (k >= dir.nfiles) end = TRUE; } } ++top; } } /* * Name: select_file * Purpose: To let user select a file from dir list * Date: February 13, 1992 * Passed: flist: pointer to list of files * stem: base directory * dir: directory display stuff * Notes: let user move thru the file names with the cursor keys */ int select_file( FTYPE *flist, char *stem, DIRECTORY *dir ) { int ch; /* input character from user */ int func; /* function of character input by user */ int fno; /* index into flist of the file under cursor */ int goodkey; /* is key a recognized function key? */ int r; /* current row of cursor */ int c; /* current column of cursor */ int offset; /* offset into file list */ int stop; /* stop indicator */ int stem_len; /* stem length */ int color; /* color of help screen */ int file_color; /* color of current file */ int change; /* boolean, hilite another file? */ int oldr; /* old row */ int oldc; /* old column */ char asize[20]; /* ascii file size */ char blank[20]; /* blank out file names */ /* * initial everything. */ memset( blank, ' ', 12 ); blank[12] = '\0'; c = r = 1; ch = fno = offset = 0; color = g_display.help_color; file_color = g_display.hilited_file; goodkey = TRUE; stop = FALSE; stem_len = strlen( stem ); s_output( stem, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3, color ); s_output( flist[fno].fname, dir->row + DIR4_ROW, dir->col+strlen( dir4 )+3+stem_len, color ); my_ltoa( flist[fno].fsize, asize, 10 ); s_output( blank, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color ); s_output( asize, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color ); my_ltoa( dir->cnt, asize, 10 ); s_output( blank, dir->row+DIR6_ROW, dir->col+DIR6_COL+strlen( dir6 ), color); s_output( asize, dir->row+DIR6_ROW, dir->col+DIR6_COL+strlen( dir6 ), color); xygoto( (c-1)*14+dir->col+2, r+dir->row+3 ); hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color ); change = FALSE; while (stop == FALSE) { oldr = r; oldc = c; ch = getkey( ); func = getfunc( ch ); /* * User may have redefined the Enter and ESC keys. Make the Enter key * perform a Rturn in this function. Make the ESC key do an AbortCommand. */ if (ch == RTURN) func = Rturn; else if (ch == ESC) func = AbortCommand; switch (func) { case Rturn : case NextLine : case BegNextLine : stop = TRUE; break; case AbortCommand : stop = TRUE; break; case LineUp : if (r > 1) { change = TRUE; --r; } else { r = dir->lines; change = TRUE; if (offset == 0 || c > 1) { if (c > 1) --c; } else if (dir->vcols > 0 && offset > 0 && c == 1) { /* * recalculate the dir display stuff. */ offset -= dir->lines; recalculate_dir( dir, flist, offset ); } } goodkey = TRUE; break; case LineDown : if (r < dir->prow) { change = TRUE; ++r; } else if (r < dir->lines && c != dir->cols) { change = TRUE; ++r; } else { change = TRUE; r = 1; if (offset == dir->vcols * dir->lines || c < dir->cols) { if (c < dir->cols) ++c; } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines && c == dir->cols) { offset += dir->lines; recalculate_dir( dir, flist, offset ); } } goodkey = TRUE; break; case CharLeft : if (offset == 0 || c > 1) { if (c > 1) { change = TRUE; --c; } } else if (dir->vcols > 0 && offset > 0 && c == 1) { change = TRUE; /* * recalculate the dir display stuff. */ offset -= dir->lines; recalculate_dir( dir, flist, offset ); } goodkey = TRUE; break; case CharRight : if (offset == dir->vcols * dir->lines || c < dir->cols) { if (c < dir->cols) { change = TRUE; ++c; if (c == dir->cols) { if ( r > dir->prow) r = dir->prow; } } } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines && c == dir->cols) { change = TRUE; offset += dir->lines; recalculate_dir( dir, flist, offset ); if (r > dir->prow) r = dir->prow; } goodkey = TRUE; break; case BegOfLine : change = TRUE; c = r = 1; goodkey = TRUE; break; case EndOfLine : change = TRUE; r = dir->prow; c = dir->cols; goodkey = TRUE; break; case ScreenDown : change = TRUE; r = (c == dir->cols) ? r = dir->prow : dir->lines; goodkey = TRUE; break; case ScreenUp : change = TRUE; r = 1; goodkey = TRUE; break; default : break; } if (goodkey) { s_output( blank, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3+stem_len, color ); fno = offset + (c-1)*dir->lines + (r-1); s_output( flist[fno].fname, dir->row+DIR4_ROW, dir->col+strlen( dir4 )+3+stem_len, color ); my_ltoa( flist[fno].fsize, asize, 10 ); s_output( blank, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color ); s_output( asize, dir->row+DIR5_ROW, dir->col+strlen( dir5 )+3, color ); xygoto( (c-1)*14+dir->col+2, r+dir->row+3 ); goodkey = FALSE; if (change) { hlight_line( (oldc-1)*14+dir->col+2, oldr+dir->row+3, 12, color ); hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color ); change = FALSE; } } } dir->select = fno; return( func == AbortCommand ? ERROR : OK ); } #endif /* * Name: recalculate_dir * Purpose: To recalcute dir structure when cursor goes ahead or behind screen * Date: November 13, 1993 * Passed: dir: pointer to file structure * flist: pointer to file structure * offset: number of files from beginning of flist * Notes: Find new number of files on the screen. Then, find out * how many files names are in the last column. */ void recalculate_dir( DIRECTORY *dir , FTYPE *flist, int offset ) { register int off; off = offset; dir->nfiles = (dir->cnt - off) > dir->avail ? dir->avail : (dir->cnt - off); dir->prow = dir->lines - (dir->avail - dir->nfiles); write_directory_list( flist+off, *dir ); } /* * Name: shell_sort * Purpose: To sort file names * Date: February 13, 1992 * Modified: November 13, 1993, Frank Davis per Byrial Jensen * Passed: flist: pointer to file structure * cnt: number of files to sort * Notes: this implementation of Shellsort is based on the one by Robert * Sedgewick on page 109, _Algorithms in C_. * * Change: Use of my_memcmp instead memcmp * (In somes cases not-english people wants to use their own letters * even in filenames; I am such one, Byrial). */ void shell_sort( FTYPE *flist, int cnt ) { int i; register int j; register int inc; FTYPE temp; FTYPE *fl; if (cnt > 1) { sort.order_array = (mode.search_case == IGNORE) ? sort_order.ignore : sort_order.match; fl = flist; /* * figure the increments, per Donald Knuth, _Sorting and Searching_, and * Robert Sedgewick, _Algorithms in C_. */ j = cnt / 9; for (inc=1; inc <= j; inc = 3 * inc + 1); /* * now, Shellsort the directory file names. */ for (; inc > 0; inc /= 3) { for (i=inc; i < cnt; i++) { j = i; memcpy( &temp, fl+j, sizeof(FTYPE) ); #if defined( __UNIX__ ) while (j >= inc && my_memcmp( (text_ptr)fl[j-inc].fname, (text_ptr)temp.fname, NAME_MAX+2 ) > 0) { memcpy( fl+j, fl+j-inc, sizeof(FTYPE) ); j -= inc; } #else while (j >= inc && my_memcmp( (text_ptr)fl[j-inc].fname, (text_ptr)temp.fname, 14 ) > 0) { memcpy( fl+j, fl+j-inc, sizeof(FTYPE) ); j -= inc; } #endif memcpy( fl+j, &temp, sizeof(FTYPE) ); } } } }