#include <workbench/startup.h>
#include <intuition/intuitionbase.h>
#include <dos/dos.h>
#include <dos/exall.h>
#include <exec/memory.h>
#include <functions.h>
#include <stdio.h>

#define NAME		"Drawer Usage Utility"
#define VERSION		"2"
#define REVISION	"0a"
#define TITLE		NAME" "VERSION"."REVISION

char version[] = "\0$VER: "TITLE;
char copyright[] =
	"This software is Public Domain\n"
	"written by Stefan Reisner, 1992";

struct IntuitionBase *IntuitionBase;

/* count objects in specified directory (recursively) */
int get_quantities( BPTR lock,
	ULONG *nfiles, ULONG *ndrawers, ULONG *nbytes,
	ULONG *nsoftlinks, ULONG *nlinkfiles, ULONG *nlinkdirs )
{
	BPTR oldCurDir, sublock;
	struct ExAllControl *eac;
	#define EAD_SIZE 1024
	void *EAData;
	int status = 0;	/* assume failure */

	oldCurDir = CurrentDir( lock );

	if( eac = AllocDosObject( DOS_EXALLCONTROL, NULL ) )
	{
		eac->eac_LastKey = 0;
		eac->eac_MatchString = NULL;
		eac->eac_MatchFunc = NULL;
		if( EAData = AllocMem( EAD_SIZE, MEMF_PUBLIC ) )
		{
			int more;

			status = 1;	/* assume success */
			do
			{
				struct ExAllData *ead;
				long err;

				more = ExAll( lock, EAData, EAD_SIZE, ED_SIZE, eac );

				err = IoErr();

				if( (!more) && ( err != ERROR_NO_MORE_ENTRIES ) )
				{
					status = 0;
					break;
				}

				if( !eac->eac_Entries )
					continue;
				ead = (struct ExAllData *)EAData;
				do
				{
					switch( ead->ed_Type )
					{
					case ST_FILE:
						(*nfiles)++;
						*nbytes += ead->ed_Size;
						break;
					case ST_USERDIR:
					case ST_ROOT:
						(*ndrawers)++;
						*nbytes += ead->ed_Size;
						if( sublock = Lock( ead->ed_Name, ACCESS_READ ) )
						{
							get_quantities( sublock,
								nfiles, ndrawers, nbytes,
								nsoftlinks, nlinkfiles, nlinkdirs );
							UnLock( sublock );
						}
						else
							status = 0;
						break;
					case ST_SOFTLINK:
						(*nsoftlinks)++;
						break;
					case ST_LINKFILE:
						(*nlinkfiles)++;
						break;
					case ST_LINKDIR:
						(*nlinkdirs)++;
						break;
					}
					ead = ead->ed_Next;
				} while( ead );
			} while( more );
			FreeMem( EAData, EAD_SIZE );
		}
		FreeDosObject( DOS_EXALLCONTROL, eac );
	}
	CurrentDir( oldCurDir );
	return status;
}

int display_quantities( BPTR lock )
{
	ULONG nbytes = 0, nfiles = 0, ndrawers = 0,
		nsoftlinks = 0, nlinkfiles = 0, nlinkdirs = 0;
	struct FileInfoBlock *fib;
	int status = 0;

	if( get_quantities( lock, &nfiles, &ndrawers, &nbytes,
	&nsoftlinks, &nlinkfiles, &nlinkdirs ) )
		if( fib = AllocDosObject( DOS_FIB, NULL ) )
		{
			struct EasyStruct easy =
			{
				sizeof( struct EasyStruct ),
				0,
				TITLE,
				"Drawer %s contains:\n\n"
				"%ld bytes (user data) in\n\n"
				"%ld file(s)\n"
				"%ld subdrawer(s)\n"
				"%ld soft link(s)\n"
				"%ld (hard) file link(s)\n"
				"%ld (hard) directory link(s)\n\n"
				"%s\n",
				"Ok"
			};

			Examine( lock, fib );
			EasyRequest( NULL, &easy, NULL,
				fib->fib_FileName, nbytes, nfiles, ndrawers,
				nsoftlinks, nlinkfiles, nlinkdirs, copyright );
			FreeDosObject( DOS_FIB, fib );
			status = 1;
		}
	return status;
}

void main( int argc, struct WBStartup *argmsg )
{
	struct WBArg *wb_arg;
	int iarg, status = RETURN_OK;

	if( argc )
	{
		fprintf( stderr,
			"Usage : %s can only be used as a Workbench tool.\n"
			"        Apply it to a Workbench drawer or disk in order\n"
			"        to learn how many bytes of disk storage, files,\n"
			"        subdrawers, soft and hard links it contains.\n"
			"%s\n",
			((char **)argmsg)[0], copyright );
		SetIoErr( ERROR_OBJECT_WRONG_TYPE );
		exit( RETURN_ERROR );
	}
	if( IntuitionBase =
	(struct IntuitionBase *)OpenLibrary( "intuition.library", 0 ) )
	{
		for( iarg = 0; iarg < argmsg->sm_NumArgs; iarg++ )
		{
			wb_arg = argmsg->sm_ArgList + iarg;
			if( wb_arg->wa_Lock && !wb_arg->wa_Name[0] )
			{
				if( !display_quantities( wb_arg->wa_Lock ) )
					status = RETURN_ERROR;
			}
		}
		CloseLibrary( &IntuitionBase->LibNode );
	}
	if( status != RETURN_OK )
		DisplayBeep( IntuitionBase->ActiveScreen );
	exit( status );
}
