/*   Free.c  -  (c) 1989  Mike 'Sirius' Stilson - Sirius Software
 *   Ver1.0	January 1989.  Written, Tested, Debugged, Re-Tested, and Finished.
 *   Ver2.0 May 1989.  Ported to Lattice 5.0.2, Made re-entrant/pure. Added
 *                     Prototypes, and report the filesystem.
 *          Should work under Manx, remove the prototypes & use +l to compile.
 *          LMK Makefile provided for lattice.
 *
 *			Display free/total bytes & blocks, name, and FileSys for a volume.
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <proto/dos.h>
#include <proto/exec.h>

/* Structure for all the variables we'll use */
struct Variables {
    struct InfoData *idata;
    struct FileLock *lock;
    BPTR   mylock;
    struct DeviceList *dev;
    char   name[80];
    char  *temp;
    ULONG  usedbytes,
           totalbytes,
           freebytes,
           bpb;
};

/* Macro to convert a BPTR to a C Pointer.  Just for readability */
#define BPTR_TO_C(cast, var) ((struct cast *)(BADDR((ULONG)var)))

/* Function prototypes.. */
extern __stdargs int printf(char *,...);
extern __stdargs int strlen(char *);
extern __stdargs void strncpy(char *, char *, int);
extern __stdargs void exit(long);

int   main(int, char **av);
char *GetName(struct Variables *);
void  GetFree(struct Variables *);
void  Oops(struct Variables *, int);

main(ac,av)
int ac; char *av[];
{

    /* Declare a pointer to our variable structure */
    register struct Variables *Var;

    /* Allocate space for our variables */
    if(!(Var=(struct Variables *)
        AllocMem(sizeof(struct Variables),MEMF_PUBLIC|MEMF_CLEAR))) {
        printf("Cannot allocate space for variables.\n");
        Oops(Var,0);
    }

    /* space for InfoData structure..  must be chip */
    if(!(Var->idata=(struct InfoData *)
        AllocMem(sizeof(struct InfoData),MEMF_CLEAR|MEMF_CHIP))) {
        printf("Unable to allocate space.\n");
        Oops(Var,1);
    }

    /* Lock the drive */
    if((Var->mylock=Lock(av[1],ACCESS_READ))==NULL) {
        printf("Attempt to lock %s failed.\n",av[1]);
        Oops(Var,2);
    }

    /* Fill the infodata structure */
    if(!(Info(Var->mylock,Var->idata))) {
        printf("Unable to obtain info for device %s.\n",av[1]);
        Oops(Var,3);
    }

    /* Get the volume name.  */
    printf("Volume Name: [1;4m%s[0m[%dC",GetName(Var),19-strlen(Var->name));

    /* Get and display the free space for this volume */
    GetFree(Var);

    Oops(Var,3);
}

void Oops(Var,level)
struct Variables *Var;
int level;
{
    switch(level) {
        case 3: UnLock((BPTR)Var->mylock);
        case 2: FreeMem(Var->idata,sizeof(struct InfoData));
        case 1: FreeMem(Var,sizeof(struct Variables));
        case 0: exit(0);
    }
}


/*
 *  The devicelist is the only way I've managed to get the Volume name.
 *  InfoData->id_VolumeNode->ln_Name doesn't seem to work.
 */

char *GetName(Var)
struct Variables *Var;
{

	Forbid();

		Var->lock = BPTR_TO_C(FileLock, Var->mylock);
		Var->dev = BPTR_TO_C(DeviceList, Var->lock->fl_Volume);
		Var->temp = (char *)BADDR(Var->dev->dl_Name);
        strncpy(Var->name, &Var->temp[1], Var->temp[0]);
		Var->name[Var->temp[0]] = NULL;

	Permit();

	return(Var->name);
}


static char *FileSystem[] = {"OFS", "FFS", "???"};

void GetFree(Var)
struct Variables *Var;
{
	Var->bpb         =  Var->idata->id_BytesPerBlock;
	Var->usedbytes   =  Var->bpb * Var->idata->id_NumBlocksUsed;
	Var->totalbytes  =  Var->bpb * Var->idata->id_NumBlocks;
	Var->freebytes   =  Var->totalbytes - Var->usedbytes;

    switch(Var->bpb) {
        case 488: Var->bpb=0;
                  break;
        case 512: Var->bpb=1;
                  break;
            /* The only two DOS knows about for now.. */
        default:  Var->bpb=2;
                  break;
    }

	printf("FileSystem: %3s\n",FileSystem[Var->bpb]);
	printf("Total bytes: %-7ld\t\tFree Bytes: %-7ld\n",Var->totalbytes,Var->freebytes);
	printf("Total blocks: %-7ld\t\tFree Blocks: %-7ld\n\n",Var->idata->id_NumBlocks,
		(Var->idata->id_NumBlocks - Var->idata->id_NumBlocksUsed));
}

