/***** ** ** Module Header ******************************************************* ** ** ** ** Modules Revision 3.0 ** ** Providing a flexible user environment ** ** ** ** File: Modulate_Avail.c ** ** First Edition: 1991/10/23 ** ** ** ** Authors: John Furlan, jlf@behere.com ** ** Jens Hamisch, jens@Strawberry.COM ** ** R.K. Owen, or ** ** ** ** Description: This module command prints out the modulefiles that ** ** are available in the directories listed in the ** ** MODULEPATH environment variable. ** ** ** ** Exports: ModuleCmd_Avail ** ** print_aligned_files ** ** check_dir ** ** get_dir ** ** dirlst_to_list ** ** delete_dirlst ** ** delete_cache_list ** ** ** ** Notes: ** ** ** ** ************************************************************************ ** ****/ /** ** Copyright *********************************************************** ** ** ** ** Copyright 1991-1994 by John L. Furlan. ** ** see LICENSE.GPL, which must be provided, for details ** ** ** ** ************************************************************************ **/ static char Id[] = "@(#)$Id: ModuleCmd_Avail.c,v 1.20 2009/09/02 20:37:38 rkowen Exp $"; static void *UseId[] = { &UseId, Id }; /** ************************************************************************ **/ /** HEADERS **/ /** ************************************************************************ **/ #include #include "modules_def.h" /** ************************************************************************ **/ /** LOCAL DATATYPES **/ /** ************************************************************************ **/ /** ** Structure for a linked list that stores directories to be listed. **/ typedef struct _subdir_node { fi_ent* sd_dir; struct _subdir_node* sd_next; } sd_node; /** ************************************************************************ **/ /** CONSTANTS **/ /** ************************************************************************ **/ /** ** I tried having a test for isgraph() in the configuration file, ** but it fails on AIX. This is the best I could come up with... **/ #if !defined(isgraph) && defined(_P) && defined(_N) # define isgraph(c) ((_ctype_+1)[c]&(_P|_U|_L|_N)) #endif #define DIREST 50 /** ************************************************************************ **/ /** MACROS **/ /** ************************************************************************ **/ /** not applicable **/ /** ************************************************************************ **/ /** LOCAL DATA **/ /** ************************************************************************ **/ static char buffer[MOD_BUFSIZE]; static char buf[ LINELENGTH]; static char module_name[] = __FILE__; static char short_format[] = "%s"; static char short_format_part[] = "%s/%s"; static char short_format_full[] = "%s/%s(%s)"; static char long_format[] = "%-39.39s %-10.10s %17s\n"; char long_header[] = "\ - Package -----------------------------+- Versions -+- Last mod. ------\n"; /** ** Terse file list buffer **/ #define FILE_LIST_SEGM_SIZE 100 static char _file_list_buffer[ 200]; static char **_file_list_ptr = (char **) NULL; static int _file_list_cnt = 0; static int _file_list_wr_ndx = 0; static int _file_list_rd_ndx = 0; /** ************************************************************************ **/ /** PROTOTYPES **/ /** ************************************************************************ **/ static int print_dir( Tcl_Interp*, char*, char*); static void print_spaced_file( char*, int, int, int); static char *mkdirnm( char*, char*); static int fi_ent_cmp( const void*, const void*); static void _init_file_list(void); static void _add_file_list( char *name); static char *_get_file_list(void); static char *_pick_file_list( int ndx); static void print_terse_files( int terminal_width, int len, char *header, int numbered); /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: ModuleCmd_Avail ** ** ** ** Description: Execution of the 'module avail' command ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: Tcl_Interp *interp Current Tcl Interpr. ** ** char *argv[] Arguments to the ** ** command ** ** ** ** Result: int TCL_OK Successful operation ** ** TCL_ERROR Any failure ** ** ** ** Attached Globals: g_specified_module The module name from the ** ** command line. ** ** ** ** ************************************************************************ ** ++++*/ int ModuleCmd_Avail( Tcl_Interp * interp, int argc, char *argv[] ) { char **dirname; uvec *modpath; int Result = -TCL_ERROR; /** ** Load the MODULEPATH and split it into a list of paths. Assume success ** if no list to output ... **/ if (!(modpath = ModulePathList())) goto unwind0; if (!uvec_number(modpath)) { Result = TCL_OK; goto success0; } /** ** If we're given a full-path, then we'll just check that directory. ** Otherwise, we'll check every directory in MODULESPATH. **/ if (argc > 0 && **argv == '/') { while (argc--) { /** ** Set the name of the module specified on the command line **/ g_specified_module = *argv; if (!check_dir(*argv)) { if (OK != ErrorLogger(ERR_PARAM, LOC, NULL)) { Result = TCL_ERROR; /** --- EXIT PROCEDURE (FAILURE) --> **/ } } else { print_dir(interp, *argv, NULL); } argv++; } } else { /** ** We're not given a full path. Tokenize the module path string and ** print the contents of each directory specified (if it exists ;-) **/ if (sw_format & SW_LONG) fprintf(stderr,"%s", _(long_header)); /** ** If a module category is specified check whether it is part ** of the directory we're scanning at the moment. **/ if (argc > 0) { /* show sub directory */ while (argc--) { /** ** Set the name of the module specified on the command line **/ g_specified_module = *argv; dirname = uvec_vector(modpath); while (dirname && *dirname) { /** ** Print the category **/ if (check_dir(*dirname)) print_dir(interp,*dirname,*argv); dirname++; } argv++; } /** ** Otherwise, if there's no category given, descend the current ** directory and print its contents. **/ } else { dirname = uvec_vector(modpath); while (dirname && *dirname) { if (check_dir(*dirname)) print_dir(interp, *dirname, NULL); dirname++; } } /** argc **/ } /** if( no full path name given) **/ /** ** Free up what has been allocated and exit from this procedure **/ /* if got here via this path ... it must have been OK */ if (Result < 0) Result = TCL_OK; FreeList(&modpath); unwind0: /* if Result is negative here ... must have been an unwind */ if (Result < 0) Result = -Result; success0: return (Result); /** --- EXIT PROCEDURE (FAILURE/SUCCESS) --> **/ } /** End of 'ModuleCmd_Avail' **/ /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: check_dir ** ** ** ** Description: Open and close the passed directory in order to check** ** if it does exist and is readable ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: char *dirname Name of the directory to be ** ** checked ** ** ** ** Result: int 0 Not a directory or unreadable ** ** 1 OK ** ** ** ** Attached Globals: - ** ** ** ** ************************************************************************ ** ++++*/ int check_dir( char *dirname) { DIR* dirp; if( !(dirp = opendir( dirname))) return( 0); if( -1 == closedir( dirp)) if( OK != ErrorLogger( ERR_CLOSEDIR, LOC, dirname, NULL)) return( 0); return( 1); } /** End of 'check_dir' **/ /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: print_dir ** ** ** ** Description: Print all files beyond the passed directory ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: char *dir Directory to be scanned ** ** char *module A selcted module name or NULL** ** ** ** Result: int TCL_OK Successful operation ** ** ** ** Attached Globals: - ** ** ** ** ************************************************************************ ** ++++*/ static int print_dir( Tcl_Interp * interp, char *dir, char *module ) { fi_ent *dirlst_head = NULL; /** Directory list base pointer **/ int count = 0, /** Number of elements in the top **/ /** level directory list **/ tcount = 0, /** Total number of files to print **/ start = 0, dirlen; char **cache_list = NULL; char *selection, *s; /** ** Print the directory name **/ if ((sw_format & (SW_PARSE | SW_TERSE | SW_LONG)) && !(sw_format & (SW_HUMAN | SW_LIST))) { fprintf(stderr, "%s:\n", dir); } if (dir) dirlen = strlen(dir) + 1; else dirlen = 0; /** ** If the is a module selection given, build the whole selected path **/ if (module) { if (dir) { if ((char *)NULL == (selection = stringer(NULL, 0, dir, "/", module, NULL))) { ErrorLogger(ERR_STRING, LOC, NULL); goto unwind0; /** ---- EXIT (FAILURE) ---> **/ } } else selection = module; } else selection = (char *)NULL; if (!cache_list) { /** ** Normal reading of the files **/ if (NULL == (dirlst_head = get_dir(dir, NULL, &count, &tcount))) if (OK != ErrorLogger(ERR_READDIR, LOC, dir, NULL)) goto unwind1; if (NULL == (cache_list = (char **)module_malloc(tcount * sizeof(char **)))) if (OK != ErrorLogger(ERR_ALLOC, LOC, NULL)) goto unwind1; (void)memset(cache_list, 0, tcount * sizeof(char **)); start = 0; dirlst_to_list(cache_list, dirlst_head, count, &start, dir, selection); } /** ** In case of any selection, we have to force all .modulrc's and .versions ** on the path **/ if (dir) { s = dir; while (s) { if ((s = strchr(s, '/'))) *s = '\0'; else break; SourceRC(interp, dir, modulerc_file); SourceVers(interp, dir, module); if (s) *s++ = '/'; } /** ** Finally source the rc files in the directory itself **/ SourceRC(interp, dir, modulerc_file); SourceVers(interp, dir, module); } if (dir && selection) null_free((void *)&selection); /** ** Print and remove the cache list **/ delete_dirlst(dirlst_head, count); print_aligned_files(interp, dir, dir, cache_list, tcount, (sw_format & SW_LIST ? 1 : -1)); delete_cache_list(cache_list, start); if (sw_format & SW_LONG) fprintf(stderr, "\n"); return (TCL_OK); /** ------- EXIT (SUCCESS) --------> **/ unwind1: if (dir && selection) null_free((void *)&selection); unwind0: return (TCL_ERROR); /** ------- EXIT (FAILURE) --------> **/ } /** End of 'print_dir' **/ /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: get_dir ** ** ** ** Description: Read in the passed directory and save every interes- ** ** ting item in the directory list ** ** skipping known version control directories: ** ** CVS RCS .git .svn ** ** unless they contain .version files ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: char *dir Directory to be read ** ** char *prefix Directory prefix (path) ** ** int *listcount Buffer to store the number of** ** elements in the current ** ** directory list ** ** int *total_count Buffer for the total number ** ** of files read ** ** ** ** Result: fi_ent* NULL Failure ** ** else Directory list base pointer ** ** *listcount Number of elements in the ** ** top level directory list ** ** *total_count Total number of files read ** ** ** ** Attached Globals: - ** ** ** ** ************************************************************************ ** ++++*/ fi_ent *get_dir( char *dir, char *prefix, int *listcount, int *total_count) { struct dirent *dp; /** Directory read pointer **/ DIR *dirptr; /** Directory handle **/ fi_ent *dirlst_head, /** Directory list pointers. Head, **/ *dirlst_cur, /** current **/ *dirlst_last; /** and last **/ char *dirname; /** Expanded directory path name **/ char *tmp; int count = 0; /** ** Open the desired directiory **/ if( !(dirptr = opendir( dir))) { #if 0 /* if you can't open a directory ... is that really an error? */ if( OK != ErrorLogger( ERR_OPENDIR, LOC, dir, NULL)) #endif return( NULL); /** ----------- EXIT (FAILURE) ------------> **/ } /** ** Allocate memory for reading in the directory **/ if( NULL == (dirlst_cur = dirlst_head = (fi_ent*) module_calloc( DIREST, sizeof( fi_ent)))) { if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) { if( -1 == closedir( dirptr)) ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL); goto unwind0; } } dirlst_last = dirlst_head + DIREST; /** ** Read in the contents of the directory. Ignore dotfiles ** and version directories. **/ for( count = 0, dp = readdir( dirptr); dp != NULL; dp = readdir( dirptr)) { if( *dp->d_name == '.') continue; /** ** Conditionally double up the space allocated for reading the direc- ** tory **/ if(dirlst_cur == dirlst_last) { if( NULL == (dirlst_head = (fi_ent*) module_realloc( (char*) dirlst_head, (count<<1) * sizeof( fi_ent)))) if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) goto unwind0; dirlst_cur = dirlst_head + count; dirlst_last = dirlst_head + (count<<1); } /** ** Build the complete path name and get information about the file **/ if( !( dirname = mkdirnm( dir, dp->d_name))) if( OK != ErrorLogger( ERR_DIRNAME, LOC, NULL)) { if( -1 == closedir( dirptr)) ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL); goto unwind1; } if( stat( dirname, &(dirlst_cur->fi_stats)) < 0) if( OK != ErrorLogger( ERR_DIRNOTFOUND, LOC, dirname, NULL)) { if( -1 == closedir( dirptr)) ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL); goto unwind1; } /** ** If it is a directory, recursively delve into it .. **/ if(dirlst_cur->fi_stats.st_mode & S_IFDIR) { char* np; char* ndir; int tmpcount = 0; /** ** Build the new base points for the recursion **/ if( !( tmp = mkdirnm( prefix, dp->d_name))) { if( OK != ErrorLogger( ERR_DIRNAME, LOC, NULL)) { if( -1 == closedir( dirptr)) ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL); goto unwind1; } } else { if( NULL == (np = stringer(NULL,0, tmp, NULL))) if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) goto unwind1; } if( !( tmp = mkdirnm( dir, dp->d_name))) { if( OK != ErrorLogger( ERR_DIRNAME, LOC, NULL)) { if( -1 == closedir( dirptr)) ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL); goto unwind1; } } else { if( NULL == (ndir = stringer(NULL,0, tmp, NULL))) if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) goto unwind1; } /** ** What if it's a known version control directory ** check if it has a .version file **/ if (!strcmp("CVS",dp->d_name) || !strcmp("RCS",dp->d_name) || !strcmp(".git",dp->d_name) || !strcmp(".svn",dp->d_name)) { FILE *fi; if( (char *) NULL == stringer(buffer, MOD_BUFSIZE, tmp, "/.version", NULL)) if( OK != ErrorLogger( ERR_STRING, LOC, NULL)) goto unwind1; if( NULL == (fi = fopen( buffer, "r"))) { /* does not have a .version file */ continue; } else { /* has a .version file ... assume to be module dir */ fclose(fi); } } /** ** The recursion itself ... **/ dirlst_cur->fi_subdir = get_dir( ndir,np,&dirlst_cur->fi_listcount, &tmpcount); /** ** Add the number of real modulefiles (i.e. not subdirs and ** not non-modulefiles) to our total number of modulefiles ** contained in the structure. **/ *total_count += tmpcount; /** ** This means that it's an empty directory so the prefix is ** never used **/ if( !dirlst_cur->fi_listcount) null_free((void *) &np); null_free((void *) &ndir); /** ** if it is not a directory check the magic cookie of the file. Only ** files with the modules magic cookie will be accepted. Also tem- ** porary files are to be ignored. **/ } else if( dp->d_name[NLENGTH(dp)-1] == '~' || !check_magic( dirname, MODULES_MAGIC_COOKIE, MODULES_MAGIC_COOKIE_LENGTH)) { continue; } else { dirlst_cur->fi_subdir = NULL; } /** ** Put the name of the file on the directory list **/ dirlst_cur->fi_prefix = prefix; if( NULL == (dirlst_cur->fi_name = stringer(NULL,0, dp->d_name, NULL))) if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) goto unwind1; /** ** Count even the number of elements in the current list as the ** total number of elements read in so far. ** Increment the list index to be prepared for the next entry. **/ count++; (*total_count)++; dirlst_cur++; } /** for **/ /** ** Now sort alphabetically what has been read **/ if( count > 1) qsort( dirlst_head, count, sizeof(fi_ent), fi_ent_cmp); /** ** Close the directory, set up return values **/ if( -1 == closedir( dirptr)) if( OK != ErrorLogger( ERR_CLOSEDIR, LOC, dir, NULL)) goto unwind1; *listcount = count; return( dirlst_head); /** ----------- EXIT (SUCCESS) ------------> **/ unwind1: null_free((void *) &dirlst_cur); unwind0: return( NULL); /** ----------- EXIT (FAILURE) ------------> **/ } /** End of 'get_dir' **/ /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: dirlst_to_list ** ** ** ** Description: Transform the passed nested directory list into a ** ** flat list of strings ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: char **list List to be created ** ** fi_ent *dirlst_head Head of the directory list ** ** to be transformed ** ** int count Number of elements in the ** ** directory list ** ** int *beginning Index of the element in List ** ** to start appending the file- ** ** names at. ** ** char *path prepend pathname to list ** ** char *module A search pattern ** ** ** ** Result: - ** ** ** ** Attached Globals: - ** ** ** ** ************************************************************************ ** ++++*/ void dirlst_to_list( char **list, fi_ent *dirlst_head, int count, int *beginning, char *path, char *module) { fi_ent *dirlst_cur; int i; char *ptr; int mlen; /** ** If there's any selection given, figure out its length **/ if( module) mlen = strlen( module); /** ** Put all files in the directory list at the end of the passed list ** of character arrays **/ for( i=0, dirlst_cur=dirlst_head; ifi_prefix) { if( path) { if( (char *) NULL == stringer(buf, MOD_BUFSIZE, path,"/", dirlst_cur->fi_prefix,"/", dirlst_cur->fi_name, NULL)) return; } else { if( (char *) NULL == stringer(buf, MOD_BUFSIZE, dirlst_cur->fi_prefix,"/", dirlst_cur->fi_name, NULL)) return; } ptr = buf; } else { if( path) { if( (char *) NULL == stringer(buf, MOD_BUFSIZE, path,"/", dirlst_cur->fi_name, NULL)) return; ptr = buf; } else ptr = dirlst_cur->fi_name; } /** ** Check whether this is part of the selected modules ... **/ if( !module || !strncmp( module, buf, mlen)) { /** ** Put this guy on the list **/ if( NULL == (list[(*beginning)++] = stringer(NULL,0, ptr, NULL))) { if( OK != ErrorLogger( ERR_ALLOC, LOC, NULL)) { while( i--) null_free((void *) list + (--(*beginning))); return; /** ------- EXIT (FAILURE) --------> **/ } } } /** ** recursively descend to subdirectories **/ if( dirlst_cur->fi_subdir) dirlst_to_list( list, dirlst_cur->fi_subdir, dirlst_cur->fi_listcount, beginning, path, module); } /** for **/ } /** end of 'dirlst_to_list' **/ /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: delete_dirlst ** ** ** ** Description: Delete an entire directory list including all sub- ** ** directory lists ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: fi_ent *dirlst_head Head of the list to be re- ** ** moved ** ** ** ** Result: - ** ** ** ** Attached Globals: - ** ** ** ** ************************************************************************ ** ++++*/ void delete_dirlst( fi_ent *dirlst_head, int count) { fi_ent *dirlst_cur; int i; if( !dirlst_head) return; /** ** Free all filenames stored in the list **/ for( i=0, dirlst_cur=dirlst_head; ifi_name)); /** ** Recursivle decend to subdirectories **/ if( dirlst_cur->fi_subdir) delete_dirlst( dirlst_cur->fi_subdir, dirlst_cur->fi_listcount); } /** for **/ /** ** Remove the entire list **/ if( dirlst_head->fi_prefix) null_free((void *) &(dirlst_head->fi_prefix)); null_free((void *) &dirlst_head); } /** End of 'delete_dirlst' **/ /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: delete_cache_list ** ** ** ** Description: Remove an entire list of allocated strings and free ** ** up the used memory ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: char **list List of filenames to be print** ** int tcount Size ofd the list in elements** ** ** ** Result: - ** ** ** ** Attached Globals: - ** ** ** ** ************************************************************************ ** ++++*/ void delete_cache_list( char **list, int tcount) { int i; for( i=0; i maxPrefixLength)) { /* partial match */ maxPrefixLength = pathlen; } dirname++; } /** ** Skip over '/' **/ if (maxPrefixLength > 0) maxPrefixLength += 1; module = stringer(NULL, 0, *list + maxPrefixLength, NULL); } else { t = strlen(path); if (*(*list + t) == '/') t++; module = stringer(NULL, 0, *list + t, NULL); } if ((char *)NULL == module) { if (OK != ErrorLogger(ERR_ALLOC, LOC, NULL)) break; else continue; } /** ** Expand the symbols and get the version of the module **/ if ((char *)NULL == (symbols = ExpandVersions(module))) symbols = ""; if ((sw_format & SW_LONG) || (char *)NULL == (release = strchr(module, '/'))) release = ""; /* no release info */ else *release++ = '\0'; /** ** Long or short format **/ if (sw_format & (SW_TERSE | SW_PARSE | SW_HUMAN)) { /** short format **/ int tmp_len; if (sw_format & SW_PARSE) { sprintf(_file_list_buffer, short_format_full, module, release, symbols); } else { /* assume a human readable format */ if (*symbols) { sprintf(_file_list_buffer, short_format_full, module, release, symbols); } else { if (*release) { sprintf (_file_list_buffer, short_format_part, module, release); } else { sprintf (_file_list_buffer, short_format, module); } } } _add_file_list(_file_list_buffer); tmp_len = strlen(_file_list_buffer); if (tmp_len > maxlen) maxlen = tmp_len; } else if (sw_format & SW_LONG) { /** long format **/ /** ** Get the time of last modification **/ if ((struct tm *)NULL != (tm = gmtime(&stats.st_mtime))) { sprintf(buffer, "%04d/%02d/%02d %2d:%02d:%02d", 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); timestr = buffer; } else timestr = ""; /** ** Now print and free what we've allocated **/ fprintf(stderr, long_format, module, symbols, timestr); } null_free((void *)&module); } /** if( !stat) **/ list++; } /** while **/ /** ** In case of terse output we have to flush our buffer **/ if (!(sw_format & SW_LONG)) { if (_file_list_wr_ndx > 0) print_terse_files(terminal_width, maxlen, header, numbered); } if (!path) FreeList(&modpath); } /** End of 'print_aligned_files' **/ /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: print_terse_files ** ** ** ** Description: Print out the filenames in the _file_list array in ** ** case of terse output ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: int terminal_width Terminal size ** ** int len max. filename length ** ** char *header header to print ** ** int number value to start number** ** use -1 for none ** ** ** ** Result: - ** ** ** ** Attached Globals: - ** ** ** ** ************************************************************************ ** ++++*/ static void print_terse_files( int terminal_width, int len, char *header, int numbered) { char *module; char *moduleright; /** ** Print human readable lists **/ len += (numbered != -1 ? 6 : 1); if( sw_format & SW_HUMAN ) { int columns = (terminal_width - 1) / len; int col_ndx, row_ndx; int rows; int mod_ndx; /** ** Print the header line **/ if( header) { int lin_len = terminal_width - strlen( header) - 2; int i; fprintf( stderr, "\n"); if( lin_len >= 2) for( i = 0; i < lin_len / 2; i++) fprintf( stderr, "-"); fprintf( stderr, " %s ", header); if( lin_len >= 2) for( i = 0; i < (lin_len+1) / 2; i++) fprintf( stderr, "-"); fprintf( stderr, "\n"); } /** ** Print the columns **/ if( !columns) columns = 1; rows = (_file_list_wr_ndx + columns - 1) / columns; for( row_ndx = 0; row_ndx < rows; row_ndx++) { for( col_ndx = 0; col_ndx < columns; col_ndx++) { mod_ndx = row_ndx + col_ndx * rows; if( (module = _pick_file_list( mod_ndx)) ) { moduleright = _pick_file_list( row_ndx + (col_ndx+1)* rows); print_spaced_file( module, len, ( (col_ndx == columns - 1) || (moduleright == (char *) NULL) ? 0 : 1 ), ( (numbered == -1) ? numbered : ++mod_ndx) ); } } fprintf( stderr, "\n"); } } /** ** Print parseable lists **/ else { while( (module = _get_file_list()) ) { fprintf( stderr, "%s\n", module); } } } /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: _add_file_list ** ** _init_file_list ** ** _get_file_list ** ** _pick_file_list ** ** ** ** Description: File list functions for terse module display mode ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: char *name Name to be stored ** ** ** ** Result: - ** ** ** ** Attached Globals: - ** ** ** ** ************************************************************************ ** ++++*/ static void _init_file_list() { if( _file_list_ptr && !_file_list_cnt) { null_free((void *) &_file_list_ptr); _file_list_cnt = 0; } _file_list_wr_ndx = 0; _file_list_rd_ndx = 0; } static void _add_file_list( char *name) { /** ** Parameter check **/ if( !name || !*name) return; /** ** Reallocate if the current array is to small **/ if( _file_list_cnt <= _file_list_wr_ndx) { _file_list_cnt += FILE_LIST_SEGM_SIZE; if( !_file_list_ptr) _file_list_ptr = (char **) module_malloc(_file_list_cnt * sizeof(char *)); else _file_list_ptr = (char **) module_realloc( _file_list_ptr, _file_list_cnt * sizeof(char *)); } /** ** Save the passed name, if the allocation succeeded **/ if( !_file_list_ptr) { ErrorLogger( ERR_ALLOC, LOC, NULL); _file_list_cnt = 0; _file_list_wr_ndx = 0; _file_list_rd_ndx = 0; } else { _file_list_ptr[ _file_list_wr_ndx++] = stringer(NULL,0, name, NULL); } } static char *_get_file_list() { return((_file_list_rd_ndx < _file_list_wr_ndx) ? _file_list_ptr[ _file_list_rd_ndx++] : (char *) NULL); } static char *_pick_file_list( int ndx) { return((ndx < _file_list_wr_ndx) ? _file_list_ptr[ ndx] : (char *) NULL); } /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: print_spaced_file ** ** ** ** Description: Print out the passed filename and fill the output ** ** area up to the passed number of characters ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: char *name Name to be printed ** ** int maxwidth With of the output field to ** ** be filled up ** ** int space Boolean value controlling if ** ** the output area should be ** ** filled up with spaces or not ** ** int number value to start number list ** ** use -1 for none ** ** ** ** Result: - ** ** ** ** Attached Globals: - ** ** ** ** ************************************************************************ ** ++++*/ static void print_spaced_file( char *name, int maxwidth, int space, int number) { int filelen; /** Length of the filename to print **/ chk4spch( name); /** turn any weird characters into ? marks **/ /** ** Print the name and calculate its length **/ filelen = strlen( name); if( -1 != number) { fprintf( stderr, "%3d) ", number); filelen += 5; } fprintf(stderr, "%s", name); /** ** Conditionally fill the output area with spaces **/ if( space) { putc(' ', stderr); while( ++filelen < maxwidth) putc(' ', stderr); } } /** end of 'print_spaced_file' **/ /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: mkdirnm ** ** ** ** Description: Build a full pathname out of the passed directory ** ** and file ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: char *dir The directory to be used ** ** char *file The filename w/o path ** ** ** ** Result: char* NULL Compound filename to long ** ** else Pointer to the full path ** ** ** ** Attached Globals: - ** ** ** ** ************************************************************************ ** ++++*/ static char *mkdirnm( char *dir, char *file) { static char dirbuf[ MOD_BUFSIZE]; /** Buffer for path creation **/ /** ** If only a file is given, or the file is in the current directory ** return just the file. **/ if( dir == NULL || *dir == '\0' || !strcmp(dir,".")) return( strcpy( dirbuf, file)); /** ** Check whether the full path fits into the buffer **/ if( (int) ( strlen( dir) + 1 + strlen( file) + 1 ) > MOD_BUFSIZE) { if( OK != ErrorLogger( ERR_NAMETOLONG, LOC, dir, file, NULL)) return( NULL); } /** ** Copy directory and file into the buffer taking care that there will ** be no double slash ... **/ strcpy( dirbuf, dir); if( dir[ strlen( dir) - 1] != '/' && file[0] != '/') strcat( dirbuf, "/"); return( strcat( dirbuf, file)); } /** End of 'mkdirnm' **/ /*++++ ** ** Function-Header ***************************************************** ** ** ** ** Function: fi_ent_cmp ** ** ** ** Description: compares two file entry structures ** ** Different cmdline arguments (i.e. -u, -c, -t, -z) ** ** will change what value is compared. As a default, ** ** the name is used. ** ** ** ** Notes: This procedure is used as comparison function for ** ** qsort() ** ** ** ** First Edition: 1991/10/23 ** ** ** ** Parameters: const void *fi1 First file entry ** ** const void *fi2 Second one to compare ** ** ** ** Result: int 1 fi2 > fi1 ** ** -1 fi2 < fi1 ** ** 0 fi2 == fi1 ** ** ** ** Attached Globals: ** ** ** ** ************************************************************************ ** ++++*/ static int fi_ent_cmp( const void *fi1, const void *fi2) { #ifdef DEF_COLLATE_BY_NUMBER return colcomp( ((fi_ent*)fi1)->fi_name, ((fi_ent*)fi2)->fi_name); #else return strcmp( ((fi_ent*)fi1)->fi_name, ((fi_ent*)fi2)->fi_name); #endif }