/* "AList" 0.06 ... Disk Directory (catalog) Utility by Ed Kivi */ /* This command is designed to get an AmigaDOS directory and display the full contents to the screen. Later it will create an AmigaDOS file of PathNames to be used as a Library of files on disk storage. */ #include /* order is important, else "NULL" */ #include #include /* will be 'redefined' in compiler's eye */ #include #include #include /* #define AEKfilenote -* long version of aekDC desired */ #undef AEKfilenote /* short version of aekDC desired */ #undef DEBUG /* [dis|en]able de-bugging printf statements */ #ifndef HIGHVALUE #define HIGHVALUE 127 #endif #define AmigaFIB struct FileInfoBlock #define aekDC struct DCatalog /* A. E. Kivi Disk Catalog */ #define volsize 31 /* maximum length of volume name (31) */ #ifndef AEKfilenote #define pathsize 36 /* maximum length of path name */ #else #define pathsize 61 /* maximum length of path name */ #endif #define filesize 31 /* maximum length of file name (31) */ #define extsize 11 /* maximum length of file name extension */ extern struct FileLock *Lock(); /* preliminary disk catalog record layout, growing from Ram: to file */ aekDC { aekDC *DC_next; /* pointer to next record */ aekDC *DC_prior; /* pointer to prior record */ #ifdef AEKfilenote aekDC *DC_altnext; /* pointer to next record (alt seq) */ aekDC *DC_altprior; /* pointer to prior record (alt seq) */ #endif long DC_key; /* Ram: address, Disk: track */ long DC_size; /* 0, or size in bytes of a file */ long DC_blocks; /* number of blocks required */ char DC_type; /* V= Volume, D= Directory, F= File */ char DC_volume[volsize]; /* disk name, as "WorkBench_1.2" */ char DC_path[pathsize]; /* first 'n' chars of the Path Name */ char DC_file[filesize]; /* file name, as "DLibrary" */ char DC_ext[extsize]; /* extension, as ".c" (without .) */ char DC_icon; /* Y = has .info, N = no .info */ char DC_dmy[12]; /* Date, as "05-Sep-1987 " */ char DC_time[9]; /* Time-of-day, as "14:45:13" */ #ifdef AEKfilenote char DC_filenote[71]; /* Comments about the file */ #endif } ; /* This is probably unnecessary, but nothing obvious in AmigaDOS */ struct Calendar { int yearday; /* number of days in prior months, as "243" */ int lastday; /* last day in the month, as "30" */ char monname[4]; /* month name, as "Sep " */ } ; /* This is the format used by gmtime() and localtime() */ struct DateTime { char DT_wday[4]; /* Day-of-the-week, as "Sat" */ char DT_month[4]; /* month name, as "Sep " */ char DT_mday[3]; /* Day-of-the-month, as "05" */ char DT_time[9]; /* Time-of-day, as "14:45:13" */ char DT_year[5]; /* Year, as "1987" */ char DT_filler[1]; /* NewLine */ } ; /* replace/rename above when (if?) found in AmigaDOS */ AmigaFIB *fb; /* File Info from locked directory */ struct FileLock *dir; /* Locked AmigaDOS directory */ struct FileLock *olddir; /* AmigaDOS directory to be restored */ struct DateTime *ud; /* Date stamp info from FileInfoBlock */ aekDC *pdc; /* Disk Catalog record to be inserted */ aekDC *pdc1; /* Root (Volume) Disk Catalog record */ aekDC *pdEnd; /* End-of-List Disk Catalog record */ aekDC *pdTop; /* Directory record #1 (Volume Name only) */ int nestedDir; /* number of sub-directories found */ aekDC *pdirn; /* last Directory record (Path only) */ aekDC *pdir; /* Directory record (Path Name only) */ aekDC *getDCmem(aekDC *); /* storage for Disk Catalog record */ char *append( char *, char *, int ); /* string concatenation */ char *copyn( char *, char *, int ); /* Copy n chars. */ char *copy( char *, char * ); /* Copy string of chars. */ char *fill_area( char *, unsigned char, int ); /* string (area) fill */ char *ign; /* throw-away pointer from memset */ char DiskName[volsize]; /* name of the disk from FileInfoBlock */ char dirname[volsize]; /* name of the disk: from FileInfoBlock */ char work[108]; /* volume/path/file name work area */ int compareci( char *, char * ); /* string compare, case insensitive */ static int keyed = 0; /* return from 'getchar' */ static int calls = 0; /* number of entries in core */ static int passno = 0; /* number of directory passes made */ static int fullpage = 22; /* number of lines displayed per page */ static int thispage = 0; /* number of lines displayed so far */ static int bytes = 0; /* number of bytes stored on disk */ static int blocks = 0; /* number of blocks on disk used */ static int mask = 0; /* clean-up requirement indicators */ #define allocud 0x00000001 /* allocated storage for DateTime */ #define allocfb 0x00000002 /* allocated storage for FileInfoBlock */ #define svolddir 0x00000004 /* saved old directory */ #define allocpdTop 0x00000010 /* allocated storage for Head-of-List */ #define allocpdEnd 0x00000020 /* allocated storage for Tail-of-List */ #define allocpdc 0x00000040 /* allocated storage for at least 1 record */ BOOL fail; /* Directory Access Failure */ BOOL noargs = FALSE; /* TRUE if argument(s) supplied */ BOOL color = FALSE; /* TRUE if color display desired */ BOOL verbose = FALSE; /* TRUE if Version, count, etc. */ BOOL redirect = FALSE; /* TRUE if >prt: being used */ void close_things(); /* clean-up memory, etc. */ void Delay(); /* delay for de-bugging */ void usage(); /* invalid argument(s), display usage */ void options( char *, int ); /* parse options */ void Traverse( aekDC *, int, struct FileLock * ); void MergeDC( aekDC * , aekDC * , aekDC * ); /* Filer */ void print_headings(); /* headings over column data */ void main(argc,argv) int argc; char *argv[]; { int ai = 0; if ( argc >= 7 ) usage(); if (argc == 1) { ign = copy( dirname, "" ); noargs = TRUE; } else { while ( argv [ai + 1] && ai++ <= argc - 1 ) { ign = copy( work, argv [ai] ); if ( work[0] == '?' ) usage(); if ( ( work[0] == 'o' || work[0] == 'O') && (work[1] == 'p' || work[1] == 'P') && ( work[2] == 't' || work[2] == 'T') ) { ign = copy( work, argv [++ai] ); options( work, 0); } else { if ( work[0] == '-' ) options( work, 1); else { ign = copy( dirname, work ); if ( dirname == '\0' ) usage(); } } } } if ( fullpage < 3 ) fullpage = 22; ud = (struct DateTime *) AllocMem( sizeof( struct DateTime ), MEMF_CLEAR | MEMF_PUBLIC ); mask |= allocud; fb = (AmigaFIB *) AllocMem( sizeof( AmigaFIB ), MEMF_CLEAR | MEMF_PUBLIC ); mask |= allocfb; dir = Lock(dirname, ACCESS_READ); if ( !dir ) { printf( "Could not Lock '%s'.\n", dirname ); close_things(); } olddir = CurrentDir( dir ); mask |= svolddir; /* Read "Root" directory FileInfoBlock */ fail = (dir == NULL) | !Examine(dir,fb); if (fail) { printf("Sorry, '%s' is not a directory\n", dirname); close_things(); } ign = copy( work, fb->fib_FileName ); ign = append( work, ":", sizeof(work) ); if ( work[0] == ':' ) ign = copy( work, dirname ); work[volsize-1] = '\0'; ign = copy( DiskName, work ); /* Build specified Root directory name and information */ pdTop = getDCmem( NULL ); /* get memory for top-of-list */ if ( !pdTop ) close_things(); mask |= allocpdTop; pdTop->DC_key = fb->fib_DiskKey; pdTop->DC_size = 0; pdTop->DC_blocks = fb->fib_NumBlocks; pdTop->DC_type = 'V' ; ign = copy( pdc->DC_volume, DiskName ); ign = fill_area( pdTop->DC_path, (unsigned char) '\0', sizeof(pdTop->DC_path) ); ign = fill_area( pdTop->DC_file, (unsigned char) '\0', sizeof(pdTop->DC_file) ); ign = fill_area( pdTop->DC_ext, (unsigned char) '\0', sizeof(pdTop->DC_ext) ); pdTop->DC_icon = 'N' ; /* Root entry has been initialized */ pdEnd = getDCmem( pdTop ); /* get memory for end-of-list */ if ( !pdEnd ) close_things(); mask |= allocpdTop; pdTop->DC_prior = NULL; pdEnd->DC_next = NULL; pdTop->DC_next = pdEnd; pdEnd->DC_prior = pdTop; ign = fill_area( pdEnd->DC_volume, (unsigned char) HIGHVALUE, sizeof(pdEnd->DC_volume) ); ign = fill_area( pdEnd->DC_path, (unsigned char) HIGHVALUE, sizeof(pdEnd->DC_path) ); ign = fill_area( pdEnd->DC_file, (unsigned char) HIGHVALUE, sizeof(pdEnd->DC_file) ); ign = fill_area( pdEnd->DC_ext, (unsigned char) HIGHVALUE, sizeof(pdEnd->DC_ext) ); /* End-of-list entry has been initialized */ pdc1 = pdTop; /* This one gets changed */ pdc = pdc1; /* set generic pointer to root */ calls--; /* do not count end-of-list */ /* Build File and Directory records, Print from record */ if ( redirect ) /* form feed and indent for printer */ printf( "\f " ); if ( verbose ) { printf( "\033[1mAList V0.06\033[0m compiled at 14:45:13 on Sat 05-Sep-1987.\n" ); thispage = 2; } Traverse( pdc1, passno, dir ); print_headings(); pdc = pdTop; /* Print specified directory name and information */ while ( pdc != pdEnd) { if ( !redirect && verbose && thispage >= fullpage ) { printf( "Press \033[37m\033[3menter\033[0m to continue." ); keyed = getchar(); thispage = 0; print_headings(); } if ( redirect ) printf( " " ); /* indent for printer */ if ( pdc->DC_type == 'V' ) printf( "\033[1m%-30s ", pdc->DC_volume ); else { if ( pdc->DC_type == 'D' ) { if ( color ) printf( "\033[37m" ); printf( "\033[3m%-30s ", pdc->DC_path ); } else { if ( pdc->DC_path[0] == '\0' ) ign = copy( work, pdc->DC_file ); else { ign = copy( work, " " ); ign = append( work, pdc->DC_file, sizeof(work) ); } work[volsize-1] = '\0'; printf( "%-30s ", work); } } printf( "%7d ", pdc->DC_key ); if ( pdc->DC_type == 'V' ) printf( " Root "); else if ( pdc->DC_type == 'D' ) printf( " Dir " ); else { bytes += pdc->DC_size; printf( "%6d ", pdc->DC_size ); } blocks += pdc->DC_blocks; printf( "%4d ", pdc->DC_blocks ); printf( "%s ", pdc->DC_dmy ); printf( "%s\033[0m\n", pdc->DC_time ); thispage++; pdc1 = pdc; pdc = pdc->DC_next; pdTop->DC_next = pdc; /* remove record from the linked-list */ if ( pdc1 != pdTop ) FreeMem( pdc1, sizeof(aekDC) ); /* Free memory for 2 -> n-1 */ } mask ^= allocpdc; /* freed all file/directory records */ if ( redirect ) printf( " " ); /* indent for printer */ printf( "%d members in %d blocks, storing %d bytes.\n", calls, blocks, bytes ); close_things(); } /* end of main-line of program "DLibrary" */ /* Append a string to the end of a string up to 'limit' characters. */ char *append( to, from, limit ) char *to; char *from; int limit; { char *temp = to; if ( !to ) return( temp ); while ( *to && limit > 1 ) /* find current end-of-string */ { to++; limit--; } while ( *from && limit > 1 ) /* extend string */ { *to = *from++; to++; limit--; } *to++ = '\0'; /* ensure NULL terminated */ return( temp ); } /* Close off (as friendly as possible) */ void close_things() { if ( mask & allocud ) /* FreeMem for date work area */ FreeMem( ud, sizeof(struct DateTime) ); if ( mask & allocfb ) /* FreeMem for FileInfoBlock */ FreeMem( fb, sizeof(AmigaFIB) ); if ( mask & allocpdTop ) /* at least 1 record allocated */ { if ( mask & allocpdc ) /* FreeMem for 2 -> n-1 */ { pdc = pdTop->DC_next; while ( pdc != pdEnd) { pdc1 = pdc; pdc = pdc->DC_next; pdTop->DC_next = pdc; /* maintain the linked-list */ if ( pdc1 != pdTop ) FreeMem( pdc1, sizeof(aekDC) ); } } FreeMem( pdTop, sizeof(aekDC) ); /* FreeMem for record 1 */ } if ( mask & allocpdEnd ) FreeMem( pdEnd, sizeof(aekDC) ); /* FreeMem for record n */ if ( mask & svolddir ) dir = CurrentDir( olddir ); Exit(); } /* Compares string to string (case insensitive). */ int compareci( to, from ) char *to; char *from; { char a; char b; int c; for ( ; ; *to++, *from++ ) { a = *to; b = *from; if ( a >= 'A' && a <= 'Z' ) a = a - 'A' + 'a'; if ( b >= 'A' && b <= 'Z' ) b = b - 'A' + 'a'; c = ( int ) a - ( int) b; if ( c || !a || !b ) return( c ); } } /* Copy string of characters (ending with NULL terminator) */ char *copy( to, from ) char *to; /* destination string */ char *from; /* source string */ { char *temp = to; while ( to && *from ) /* no zero destination allowed */ *to++ = *from++; *to++ = '\0'; return(temp); } /* Copy exactly "n" characters (regardless of NULL terminator) */ char *copyn(to, from, n) char *to; /* destination string */ char *from; /* source string */ int n; /* number of characters to be copied */ { char *temp = to; while ( n-- && to ) /* no zero destination allowed */ ( *to++ = *from++ ); return(temp); } /* Fills a string with the specified character. */ char *fill_area( to, what, howmany) char *to; unsigned char what; int howmany; { char *temp = to; while ( howmany-- > 1 ) { *to++ = what; } *to = '\0'; return(temp); } /* get memory to use as Disk Catalog record */ aekDC *getDCmem(source) aekDC *source; { pdc = (aekDC *) AllocMem( sizeof( aekDC ), MEMF_CLEAR | MEMF_PUBLIC ); if ( !pdc ) { printf( "Out of memory large enough for another record.\n" ); return( pdc ); } calls++; if ( source ) ign = copyn( (char *) pdc, (char *) source, sizeof(aekDC) ); UnDateStamp(ud, fb); return(pdc); } /* Find proper location for "New", given ("Top", "End", "New"). */ void MergeDC(top, end, new) aekDC *top; aekDC *end; aekDC *new; { int HiLo; while (top != end) /* someone created a highvalues disk/path/file */ { HiLo = compareci( top->DC_volume, new->DC_volume ); if (HiLo > 0) break; if (!HiLo) { HiLo = compareci( top->DC_path, new->DC_path ); if (HiLo > 0) break; if (!HiLo) { HiLo = compareci( top->DC_file, new->DC_file ); if (HiLo > 0) break; if (!HiLo) { HiLo = compareci( top->DC_ext, new->DC_ext ); if (HiLo > 0) break; } } } top = top->DC_next; } top = top->DC_prior; end = top->DC_next; new->DC_next = top->DC_next; new->DC_prior = top; top->DC_next = new; end->DC_prior = new; } /* Parse option string(s) and set indicators */ void options( array, oi ) char array[]; int oi; { int i = 0, j = 0; while ( array[ oi + i ] ) { if ( array[ oi + i ] == 'c' || array[ oi + i ] == 'C' ) { color = TRUE; i++; } else if ( array[ oi + i ] == 'v' || array[ oi + i ] == 'V' ) { verbose = TRUE; i++; } else if ( array[ oi + i ] == 'p' || array[ oi + i ] == 'P' ) { redirect = TRUE; i++; } else { if ( array[ oi + i ] == 'l' || array[ oi + i ] == 'L' ) { fullpage = 0; for ( j = 0; j = 2; j++ ) { i++; if ( array[ oi + i ] >= '0' && array[ oi + i ] <= '9' ) { fullpage *= 10; fullpage += array[ oi + i ] - '0'; } else break; } } else usage(); } } } /* Print "Headings" for information display */ void print_headings() { printf( "\n" ); if ( redirect ) printf( " " ); /* indent for printer */ printf("F_i_l_e___N_a_m_e_____________ "); printf("__Keys_ "); printf("_Size_ "); printf("Blks "); printf("DD-MMM-YYYY "); printf("__Time__\n"); thispage++; } /* Traverse a Directory until ERROR_NO_MORE_ENTRIES * parent points to the directory record in core * level is the number of ancestors in core */ void Traverse( parent, Level, pasdir ) aekDC *parent; /* Parent record to be cloned */ int Level; /* Number of branches from the trunk */ struct FileLock *pasdir; /* AmigaDOS directory I am examining */ { struct FileLock *mydir; /* AmigaDOS directory my child will examine */ char mydirname[volsize+pathsize]; /* Selected AmigaDOS directory */ int subs = 0; /* number of sub-directories I found */ Level++; while ( ExNext( dir, fb) != 0 || IoErr() != ERROR_NO_MORE_ENTRIES ) { pdc = getDCmem( parent ); if ( pdc ) mask |= allocpdc; else break; if ( verbose && !redirect ) printf( "%02d Files/Directories in Level %02d.\r", calls, Level); pdc->DC_key = fb->fib_DiskKey; pdc->DC_size = 0; pdc->DC_blocks = fb->fib_NumBlocks; if ( fb->fib_DirEntryType > 0 ) { subs++; pdc->DC_type = 'D' ; pdc->DC_size = ( long ) Level; if ( pdc->DC_path[0] == ' ' || !pdc->DC_path[0] ) { ign = copy( pdc->DC_path, "" ); } else { ign = append( pdc->DC_path, "/", sizeof(pdc->DC_path) ); } ign = append( pdc->DC_path, fb->fib_FileName, sizeof(pdc->DC_path) ); } else { pdc->DC_size = fb->fib_Size; pdc->DC_type = 'F' ; ign = copy( pdc->DC_file, fb->fib_FileName ); } MergeDC( parent, pdEnd, pdc ); } UnLock( pasdir ); /* release parent directory */ while ( subs-- > 0 ) { pdc = parent; while ( pdc->DC_type != 'D' || pdc->DC_size == 0 ) { if ( pdc->DC_volume[0] == HIGHVALUE ) break; else pdc = pdc->DC_next; } pdc->DC_size = 0; ign = copy( mydirname, pdc->DC_volume ); ign = append( mydirname, pdc->DC_path, sizeof(mydirname) ); mydir = Lock( mydirname, ACCESS_READ ); if ( !mydir | !Examine( mydir, fb ) ) { printf( "Program error, '%s' is not a directory\n", mydirname ); close_things(); } Traverse( pdc, Level, mydir ); /* follow limb thru branches to leaves */ } } /* Translate DateStamp to "Sat Sep 05 14:45:13 1987 !" */ UnDateStamp( o, i ) struct DateTime *o; AmigaFIB *i; { static struct Calendar Mon_table[] = { 0, 0, " ", /* null entry for month number "00" */ 0, 31, "Jan", /* non-leap year calendar */ 31, 28, "Feb", 59, 31, "Mar", 90, 30, "Apr", 120, 31, "May", 151, 30, "Jun", 181, 31, "Jul", 212, 31, "Aug", 243, 30, "Sep", 273, 31, "Oct", 304, 30, "Nov", 334, 31, "Dec", 0, 31, "Jan", /* leap year calendar */ 31, 29, "Feb", 60, 31, "Mar", 91, 30, "Apr", 121, 31, "May", 152, 30, "Jun", 182, 31, "Jul", 213, 31, "Aug", 244, 30, "Sep", 274, 31, "Oct", 305, 30, "Nov", 335, 31, "Dec" } ; /* Day-of-the-week array */ static char WeekDays[][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } ; int h, m, s, d, mm, y, ly, wd, j; /* work fields */ d = i->fib_Date.ds_Days - 1; /* days since 12/31/1977 */ wd = i->fib_Date.ds_Days % 7; /* day-of-the-week */ y = 1978; /* years (base was 1978) */ for (;;) { h = y % 4; if (h = 0) ly = 12; else ly = 0; j = Mon_table[12+ly].yearday + Mon_table[12+ly].lastday; if (d >= j) { y++; d = d - j; } else break; } for (mm = 1; mm < 13; mm++) if (d > Mon_table[mm+ly].lastday) d = d - Mon_table[mm+ly].lastday; else break; h = i->fib_Date.ds_Minute / 60; /* hours */ m = i->fib_Date.ds_Minute % 60; /* minutes */ s = i->fib_Date.ds_Tick / TICKS_PER_SECOND; /* seconds */ ign = copy(o->DT_wday, WeekDays[wd]); ign = copy(o->DT_month, Mon_table[mm].monname); sprintf(o->DT_mday, "%02d", d); sprintf(o->DT_time, "%02d:%02d:%02d", h, m, s); sprintf(o->DT_year, "%04d", y); ign = copy( pdc->DC_dmy, o->DT_mday ); ign = append( pdc->DC_dmy, "-", sizeof(pdc->DC_dmy) ); ign = append( pdc->DC_dmy, o->DT_month, sizeof(pdc->DC_dmy) ); ign = append( pdc->DC_dmy, "-", sizeof(pdc->DC_dmy) ); ign = append( pdc->DC_dmy, o->DT_year, sizeof(pdc->DC_dmy) ); ign = copy( pdc->DC_time, o->DT_time ); return(0); } /* Display format of AList command */ void usage() { printf("Usage: AList [>prt:] [dirname] [opt pcvl19 | -c -v -l45 -p]\n"); printf( " where: c=color display\n" ); printf( " p=printer re-direction [>prt:] used\n" ); printf( " v=verbose\n" ); printf( " and l=lines/'page' (22 = full med-res CLI)\n"); Exit(); }