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

#include <exec/types.h>
#include <exec/memory.h>

#include <dos/dos.h>
#include <dos/dosextens.h>

#include <clib/dos_protos.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>

#include <dos/stdio.h>

struct Library *DosBase = NULL;
BPTR  stdout;

char *v = "$VER: MyFree 0.2 (19.6.93) (c) 1993 by Rolf Böhme";

long maxfree = 0L, maxvol = 0L;

#define null(type) ((type)NULL)
#define ENTRY     ((UBYTE *)"%-20.20s %8lD %8lD %5lD%% %5s\n")
#define ENTRY2    ((UBYTE *)"\33[32;41m%-20.20s %8lD %8lD %5lD%% %5s\33[0m\n")
#define HEADER    ((UBYTE *)"\n%-20.20s  KB-%4s  KB-%4s %5s%% %5s\n%s\n")

void
FreeBytes(char *Vol)
{
   BPTR  lock = null(BPTR);
   register struct InfoData *ID = NULL;
   long  num = 0L;
   long free, used, usedpercent;
   char state[6];

   free = 0L;
   used = 0L;
   usedpercent = 0;
   *state = 0;

   if ((ID = (struct InfoData *)
        AllocVec(sizeof(struct InfoData), MEMF_CLEAR | MEMF_PUBLIC)) != NULL)
   {
      if (lock = Lock((UBYTE *) Vol, ACCESS_READ))
      {
         if (Info(lock, ID))
         {
            free = (((ID->id_NumBlocks - ID->id_NumBlocksUsed) *
                     ID->id_BytesPerBlock) >> 10);

            maxfree += free;

            used = ((ID->id_NumBlocksUsed * ID->id_BytesPerBlock) >> 10);

            maxvol += (free + used);

            usedpercent = (100 * ID->id_NumBlocksUsed) / ID->id_NumBlocks;

            switch (ID->id_DiskState)
            {
               case ID_WRITE_PROTECTED:
                  strcpy(state, "R/O");
                  break;

               case ID_VALIDATING:
                  strcpy(state, "VAL");
                  break;

               case ID_VALIDATED:
                  strcpy(state, "R/W");
                  break;

               default:
                  strcpy(state, "???");
                  break;
            }
         }
         else
            strcpy(state, "NST");

         UnLock(lock);
      }
      else
         strcpy(state, "NOL");

      FreeVec(ID);

      Printf((usedpercent > 90) || !strcmp(state,"NOL") ? ENTRY : ENTRY2,
             Vol, free, used, usedpercent, state);
   }

   return;
}

void
DisableSysRequest(int disable)
{
   static APTR wind;
   struct Process *p = (struct Process *) FindTask(NULL);

   if (disable)
   {
      wind = (APTR) p->pr_WindowPtr;
      p->pr_WindowPtr = (APTR) (-1);
   }
   else
      p->pr_WindowPtr = wind;

   return;
}

   /*
    * B2CStr() wandelt einen BCPL-String in einen C-String um
    */
char *
B2CStr(char *ret, BSTR inp, int len)
{
   register int i;
   char *help = (char *)BADDR(inp);

   for (i = 0; (i < *help) && i < (len - 1); i++)
      *(ret + i) = *(help + i + 1);

   *(ret + i) = '\0';

   return (ret);
}

void
MakeVolumeList(void)
{
   struct DosList *dl;
   char  name[100];
   ULONG mask = LDF_VOLUMES|LDF_READ;

   DisableSysRequest(TRUE);

   dl = LockDosList(mask);

   while (dl = NextDosEntry(dl, mask))
   {
      B2CStr(name, dl->dol_Name, 100);
      strcat(name, ":");

      FreeBytes(name);
   }

   UnLockDosList(mask);

   DisableSysRequest(FALSE);

   return;
}

void
MakeVolume(char *vol)
{
   DisableSysRequest(TRUE);

   FreeBytes(vol);

   DisableSysRequest(FALSE);

   return;
}

void
main(int argc, char *argv[])
{
   char  line[52];
   long fast, chip, total;

   if ((argc != 0) && (DosBase = OpenLibrary((STRPTR) "dos.library", 37)))
   {
      stdout = Output();

      memset(line, '-', sizeof(line));
      line[51] = '\0';

      Printf((UBYTE *)"%s\n%s",(ULONG)(&v[6]), line);

      Printf(HEADER, (ULONG) "Volume", "Free", "Used", "Used", "State",
             line);

      if (argc != 2)
         MakeVolumeList();
      else
         MakeVolume(argv[1]);

      Forbid();
      chip = AvailMem(MEMF_CHIP) >> 10;
      fast = AvailMem(MEMF_FAST) >> 10;
      total = chip + fast;
      Permit();

      Printf((UBYTE *)"%s\nMax. free: %lD KB - Max. avail: %lD KB\n%s\n"
                      "CHIP: %lD KB - FAST: %lD KB - Total: %lD KB\n",
             (ULONG)line,
             maxfree, maxvol,
             line,
             chip, fast, total);

      CloseLibrary(DosBase);
   }
}
