/* * du.c * (C) 1986 Software Solution, all rights reserved *---------------------------------------------------------------------------- * * Original taken from Fish Disk #48 * * - modified on May 89, emitted Mar 90 (since no original enhancements) by:- * * Gary Duncan * 24 Inkster St * Kambah ACT 2902 * Australia * ~~~~~~~~~ * * * reasons as follows :- * * 1. print all files in dir at once ( original algorithm printed * files and sub-dirs in given, unordered way ). * - this is the major functional change. * * 2. allow ^C abort - every text-cruncher should have it. * * 3. print dirs in a redpen if not deselected ( looks much better ) * * 4. changed code to be compiled under AZTEC 16-bit ints * ( it would be helpful if people flagged their code with * the compilation environment - hint ). * * Limitations ( the excession of will cause a GURU most likely ) * * a. 50 levels of dir nesting ( unreasonable ???!!!! ) * b. file name path length < 200 ( " " ) * * *---------------------------------------------------------------------------- * * du is patterned after the Unix(tm) du command. Its default action is to * give the total number of disk blocks used by a directory and recursively, * its subdirectories. * * options: * * -a ; prints blocks use by files and Directories * * -s ; sum of all blocks used by a directory and its subdirectories. * * -n ; no redpen for dir'd --GMD-- * * Bug reports or suggestions should be sent to: <<< original >>> * The Software Solution * 16850 S.W. Timberland Dr. * Aloha, Oregon 97007 */ #include #include "libraries/dos.h" #include "libraries/dosextens.h" #include "exec/memory.h" #include "gd_functions.h" extern char *indent() ; extern long Recursive_Sum () ; extern char *MakeDate[] ; char *version = "V1.1" ; /* every PD program should have one */ /* Vers1.0 is the presumed version GMD modified */ char banner[100] ; int t_flag = 0; /* summary only flag */ int a_flag = 0; /* list disk usage for both files and directories */ struct FileLock *flockstt = NULL ; char *mostbug = "\n\n" ; /* extra \n for 'most' - see intro */ char *myname; /* name by which this command has been called i.e."du" */ char *redpen = " \x1b[33m"; /* red pen */ char *witepen = "\x1b[0m "; /* white pen */ #define NEST_LVL 50 /* arbitrary dir nesting level */ char *dirs[NEST_LVL] = NULL ; int level = 0 ; int Xblksz ; main(argc, argv) int argc; char **argv; { int j , ch ; char *cur_dir , *ptr ,*rtp ; long total = 0 ; ptr = MakeDate[0] ; /* * fiddle around to extract only the ddmmyy from date string */ while ( *ptr++ != ' ') ; rtp=ptr;while(*rtp++!=' ');*--rtp='\0'; /* hackers practise, avoid */ sprintf ( banner , "DU : %s ; (original by Joe Mueller) , (v1.1 by Gary Duncan)\n" , ptr , version ) ; printf ( "%s" , banner ) ; /* announce program */ myname = *argv++; for ( j=0 ; j < 50 ; ++j ) /* clear array */ dirs[j] = NULL ; while ( --argc ) { if ( *(ptr = *argv ) == '-' ) { /* handle options ( - ) */ ++argv ; ch = *++ptr ; ++ptr ; switch ( ch ) { case 'n': /* no redpen for dirs */ case 'N': redpen = " " ; witepen = "" ; break; case 't': case 'T': if (a_flag) usage(); t_flag++; /* sum only */ break; case 's': /* block size filter */ case 'S': if ( *ptr ) /* check for block size filter */ { if ( sscanf (ptr , "%d" , &Xblksz ) != 1 ) usage () ; } else usage() ; break; case 'a': case 'A': if (t_flag) usage(); a_flag++; /* all files reported */ break; default: usage(); } } } if (*argv) { while (cur_dir = *argv++) { total = Recursive_Sum(cur_dir) ; printf("%5ld %s%s%s%s", total, redpen, dirs[0] ,witepen , mostbug ); } } else { total = Recursive_Sum(argv); printf("%5ld %s%s%s%s", total , redpen , dirs[0] , witepen , mostbug ); } exit (0); } /*************************************************************************** Name : Recursive_Sum Purpose: Entry : Returns : ****************************************************************************/ long Recursive_Sum (fn) char *fn; /* directory file name */ { long total = 0 ; int val; long temp ; struct FileLock *flock, *flockold ; struct FileInfoBlock *fib ; struct FileInfoBlock *fiblast; char *gfib ; int foxy = 0 ; level++ ; /* dir indentation level */ fib = AllocMem((long)sizeof(*fib), MEMF_CLEAR); if (fib == NULL) { fprintf(stderr,"%s: unable to allocate space for fileinfo block\n", myname); return 0; } if ( (flock = Lock(fn, ACCESS_READ)) == NULL ) { fprintf(stderr,"%s: unable to lock %s\n", myname, fn); FreeMem(fib, (long)sizeof(*fib)); return 0; } flockold = NULL; if (Examine(flock,fib)) /* process all under this dir */ { if (fib->fib_DirEntryType > 0) { /* it's a directory */ flockold = CurrentDir(flock); if ( flockstt == NULL ) flockstt = flockold ; /* hold initial dir ptr for a ^C */ gfib = fib->fib_FileName ; /* last is current */ temp = strlen(gfib) + 1 ; /* 1 for \0 */ dirs[level-1] = AllocMem( temp , MEMF_CLEAR); /* mem for dir string */ if (dirs[level-1] == NULL) { fprintf(stderr,"%s: unable to allocate space for dir ptr\n", myname); return 0; } strcpy ( dirs[level-1] , gfib ) ; /* copy dir name */ } total += fib->fib_NumBlocks; /* --- now scan for files --------------------*/ val = 0 ; Examine(flock,fib) ; /* now look for dirs */ while (ExNext(flock, fib)) { if ( breakcheck() ) break ; if ( fib->fib_DirEntryType < 0 ) /* file ? */ { ++foxy ; val = fib->fib_NumBlocks; /* yes */ ++val ; /* add 1 for info block - ?? correct */ if (a_flag && (val > Xblksz) ) printf("%5d %s%s\n", val , indent(level), fib->fib_FileName ); total += val ; } else foxy = -1 ; } if ( (foxy < 0) && (a_flag) ) { foxy = 147 ; /* mysterious magic # */ printf ( "\n" ) ; } Examine(flock,fib) ; /* now look for dirs */ while (ExNext(flock, fib)) { if ( breakcheck() ) break ; if ( fib->fib_DirEntryType > 0) /* dir ? */ { /* found a subdirectory */ val = Recursive_Sum(fib->fib_FileName); /* recursive call */ ++val ; /* add 1 for info block - ?? correct */ if ( (t_flag==0) && (val > Xblksz) ) printf("%5d %s%s%s%s\n", val,redpen,indent(level), fib->fib_FileName, witepen ); total += val ; } } } FreeMem(fib, (long)sizeof(*fib)); if (flockold != NULL) CurrentDir(flockold); /* change directories back */ UnLock(flock); FreeMem ( dirs[level] , (long)strlen(dirs[level]) ) ; dirs[level--] = NULL ; if ( breakcheck() ) /* ^C abort check */ { fprintf ( stderr , "\n^C\n" ) ; hexit () ; } return total; } /*************************************************************************** Name : indent Purpose: generates a dir string , given level req'd. - uses external list of ptrs to dir names. Entry : Returns : ****************************************************************************/ char *indent ( no ) int no ; { static char citats[200] ; /* indentation space buffer - nom. size */ int j ; citats[0] = 0 ; for ( j=0 ; j < no ; ++j ) { strcat (citats , dirs[j]); strcat (citats , "/" ) ; } return ( citats ) ; } /*************************************************************************** Name : breakcheck Purpose: Entry : Returns : ****************************************************************************/ breakcheck() { return ((SetSignal(0L,0L) & SIGBREAKF_CTRL_C) ); } /*************************************************************************** Name : hexit Purpose: Entry : Returns : ****************************************************************************/ int hexit () { int j ; fflush ( stdout ) ; if (flockstt != NULL) CurrentDir(flockstt); /* change to orig dir */ while ( level ) { FreeMem ( dirs[level] , (long)strlen(dirs[level]) ) ; --level ; } exit (0) ; } Chk_Abort() { return(0); } /*************************************************************************** Name : usage Purpose: Entry : Returns : ****************************************************************************/ int usage () { static char *rats[] = { "Usage: du [-a] [-t] [-n] [-sNNN] [vol: / dir list]...\n" , " a = print # of blocks used in all files and dirs \n" , " n = deselect pretty red-pen DIR hiliting\n", " s = don't print those with lesser than NNN blocks\n", " t = grand total of blocks only \n" , "\n", " no a,t options = directories only\n", "" } ; int j = 0 ; char *ptr ; while ( *(ptr = rats[j++]) ) fprintf ( stderr, ptr ) ; hexit () ; }