/*
 * du.c
 * (C) 1986 Software Solution, all rights reserved
 */

/*
 * 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. If the -a flag is used the command reports the number
 * of blocks used for both files and directories. The -s flag gives the
 * sum of all blocks used by a directory and its subdirectories. The -a and
 * -s flags are mutually exclusive. If a name is not given, the current
 * directory is used.
 *
 * The command tells you if a file is a directory if the -a flag is used
 * to lessen the chance of confusion.
 *
 * Bug reports or suggestions should be sent to:
 *    The Software Solution
 *    16850 S.W. Timberland Dr.
 *    Aloha, Oregon 97007
 */

#include <stdio.h>
#include "libraries/dos.h"
#include "libraries/dosextens.h"
#include "exec/memory.h"

extern struct FileLock *Lock(), *CurrentDir();

struct FileLock *src_dir_lock;  /* Lock on source dir */

int s_flag = 0;   /* summary only flag */
int a_flag = 0;   /* list disk usage for both files and directories */

char *myname;     /* name by which this command has been called i.e."du" */

main(argc, argv)
   int argc;
   char **argv;
{
   int j;
   char *cur_dir;  /* current directory name */
   int total;

   myname = *argv;

   /* parse the arguments */
   argv++;
   while ((*argv)[0] == '-') {   /* handle options */
      j = 1;               /* start past the "-" character */
      while ((*argv)[j]) {
         switch ((*argv)[j++]) {
            case 's':
            case 'S':
               if (a_flag)
                  goto usage;
               s_flag++;   /* sum only */
               break;
            case 'a':
            case 'A':
               if (s_flag)
                  goto usage;
               a_flag++;   /* all files reported */
               break;
            default:
               goto usage;
         }
      }
      argv++;
   }

   if (*argv) {
      while (cur_dir = *argv++) {
         total = sum(cur_dir);
         if (total)
             printf("%s %d\n",cur_dir, total);
      }
   } else {
      total = sum(argv);
      printf(". %d\n", total);
   }

   exit (0);

usage:
   fprintf(stderr,"%s: usage %s [-a] [-s] name ...\n", myname, myname);
   exit (1);
}

int
sum(fn)
char *fn;  /* directory file name */
{
   register int total, val;
   register struct FileLock *fl;
   register struct FileInfoBlock *fib;
   struct FileLock *ol;    /* old current directory lock */

   fib = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR);
   if (fib == NULL) {
      fprintf(stderr,"%s: unable to allocate space for fileinfo block\n",myname);
      return 0;
   }
   fl = Lock(fn, ACCESS_READ);
   if (fl == 0) {
      fprintf(stderr,"%s: unable to lock %s\n", myname, fn);
      FreeMem(fib, sizeof(struct FileInfoBlock));
      return 0;
   }
   total = 0;
   ol = NULL;
   if (Examine(fl,fib)) {  /* take a look at the directory */
      if (fib->fib_DirEntryType > 0) {   /* it's a directory */
         ol = CurrentDir(fl);
      }
      total += fib->fib_NumBlocks;
      while (ExNext(fl, fib)) { /* found a file or directory */
         if (fib->fib_DirEntryType > 0) { /* found a subdirectory */
               val = sum(fib->fib_FileName);
               if (!s_flag)
                  printf("%s (dir) %d\n", fib->fib_FileName, val);
         } else {
            val = fib->fib_NumBlocks;
            if (a_flag)
               printf("%s %d\n", fib->fib_FileName, val);
         }
         total += val;
      }
      FreeMem(fib, sizeof(struct FileInfoBlock));
      if (ol != NULL)
         CurrentDir(ol);   /* change directories back */
      UnLock(fl);
      return total;
   }
}
