/* stats.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "swis.h"


/***************************************************************************/

static char dir_name[256];

typedef struct {
  unsigned load;
  unsigned exec;
  int length;
  unsigned attributes;
  int object_type;
  char name[12];
} DirEntry;

enum {
  FILE_OBJECT = 1,
  DIR_OBJECT = 2
};

static DirEntry buff;


static int tot_file_size;
static int tot_dir_size;

#define MAX_FILE_BREAKS 29
static int file_breaks[] = {1, 2, 4, 8, 16,
                            32, 64, 128, 256, 512, 1024, 2048, 4096,
                            8192, 16384, 32768, 65536, 131072, 262144,
                            524288, 1048576, 2097152, 4194304, 8388608,
                            16777216, 33554432, 67108864, 134217728,
                            0x7fffffff};
static int file_counts[MAX_FILE_BREAKS];

#define MAX_DIR_BREAKS 18
static int dir_breaks[] =  {2048, 4096,
                            8192, 16384, 32768, 65536, 131072, 262144,
                            524288, 1048576, 2097152, 4194304, 8388608,
                            16777216, 33554432, 67108864, 134217728,
                            0x7fffffff};
static int dir_counts[MAX_DIR_BREAKS];


/***************************************************************************/

static void process_directory(int size)

{
  int index = 0;
  int res;

  tot_dir_size += size;    /* just a total of directory space used */
  tot_file_size -= size;   /* we don't want to include directory size here */

  do
  {
    _swi(OS_GBPB, I0|I1|I2|I3|I4|I5|I6|O3|O4,
           10,                /* OS_GBPB 10 - read directory entries */
           (int)dir_name,     /* from this directory */
           (int)&buff,        /* into this buffer */
           1,                 /* one at a time */
           index,             /* starting with this one */
           sizeof(buff),      /* length of buffer */
           0,                 /* read all of them */
           &res,              /* set to number read - or -1 if none */
           &index             /* identifies next entry to read */
        );

    if (res == 1)             /* I expect this is always the case, but ... */
    {
      if (buff.object_type == DIR_OBJECT)
      {
        int len = strlen(dir_name);

        dir_name[len] = '.';
        strcpy(dir_name+len+1, buff.name);

        process_directory(buff.length);

        dir_name[len] = 0;
      }
      else                    /* treat anything else as a file */
      {
        int i = 0;

        size += buff.length;

if (buff.length > 262144) printf("File %s.%s is large (%d bytes)\n",
                                  dir_name, buff.name, buff.length);
        while (buff.length > file_breaks[i])
          i++;
        file_counts[i]++;
      }
    }

  } while (index >= 0);       /* -1 => no more entries to read */

  {
    int i = 0;

    tot_file_size += size;

if (size > 524288) printf("Directory %s is large (%d bytes)\n",
                           dir_name, size);

    while (size > dir_breaks[i])
      i++;
    dir_counts[i]++;
  }

  return;
}

/***************************************************************************/

int main(int argc, char *argv[])

{
  int i, j;
  int length;

  if (argc != 2)
    strcpy(dir_name, "$");
  else
    strcpy(dir_name, argv[1]);

  tot_file_size = 0;
  tot_dir_size = 0;

  for (i=0; i<MAX_FILE_BREAKS; i++)
    file_counts[i] = 0;

  for (i=0; i<MAX_DIR_BREAKS; i++)
    dir_counts[i] = 0;

 /* find size of root directory */
  _swi(OS_File, I0|I1|O4,
         20,                /*  OS_File 20 */
         dir_name,
         &length
      );

  process_directory(length);

 /* list results */
  {
    int num_files = 0;
    int num_dirs = 0;

    printf("File length statistics:\n\n");
    j = MAX_FILE_BREAKS-1;
    while (file_counts[j]==0 && j>0)
      j--;
    for (i=0; i<=j; i++)
    {
      num_files += file_counts[i];
      printf("%12d %5d  %5d\n", file_breaks[i], file_counts[i], num_files);
    }
    printf("\nTotal number of files = %6d\n\n", num_files);

    printf("Directory size statistics:\n\n");
    j = MAX_DIR_BREAKS-1;
    while (dir_counts[j]==0 && j>0)
      j--;
    for (i=0; i<=j; i++)
    {
      num_dirs += dir_counts[i];
      printf("%12d %5d  %5d\n", dir_breaks[i], dir_counts[i], num_dirs);
    }
    printf("\nTotal number of directories = %6d\n\n", num_dirs);

    printf("Total number of bytes in files = %12d, average file length = %6d\n",
            tot_file_size, (int)(tot_file_size/num_files));

    printf("    (Directories occupy %d bytes)\n", tot_dir_size);

  }
    
  return 0;
}

/***************************************************************************/
