/***************************************************************************
 * FREE:	Display free space on your disk devices.
 *		Author:  Daniel Jay Barrett, barrett@cs.jhu.edu.
 *		Inspired by "FREE" by Tom Smythe on Fred Fish Disk #66,
 *		 but totally rewritten.  One function, AvailSpace(), is an
 *		 updated version of Smythe's function avail().
 *
 * This program is Freely Distributable.  Make all the copies you want
 * and give them away.  Use this code in any way you like.
 *
 * Changes/Improvements over Tom Smythe's program are:
 *
 *	o	Does not use self-modifying code, so it should work on
 *		ALL Amigas, not just 68000-based systems.
 *	o	You can specify a device list on the command line.
 *	o	You can specify a device list using a Manx/ARP environment
 *		variable.
 *	o	Requestors are turned off, so non-mounted devices are just
 *		skipped.  (See -m option.)
 *	o	Data is written in correct columns, regardless of the 
 *		lengths of the volume names.  (See -l option.)
 *	o	Total memory free is shown, along with CHIP and FAST
 *		subtotals.
 *	o	Command-line options added so the user can customize the
 *		program.
 *	o	Written in ANSI C, in a modular and easy-to-read style.
 *
 * Daniel Jay Barrett makes no claims about the suitability of this program
 * for any particular purpose.  Any damages incurred through the use of
 * this program are entirely the responsibility of the USER.  Use at your
 * own risk.  So there!   :-)
 *
 ***************************************************************************/

#include "free.h"
	
main(int argc, char *argv[])
{
	char *outArray = NULL;

	InitializeGlobals();

	if ((argc == 2) && (EQUAL(argv[1], HELP_ARG)))
		Usage(argv[0]);
	else
		DoFree(argc, argv, &outArray);

	ExitCleanly(outArray, NO_ERROR, RETURN_OK);
}


/* Process the user's command-line options.
 * Allocate the out[] array for output.
 * Disable requestors, if necessary.
 * Measure the available RAM.
 * Then, measure free space on each desired device. 
 * Print the output in a quick manner, using Write().
 * Turn requestors back on, if they were turned off.
 */

void DoFree(int argc, char *argv[], char **out)
{
	struct Process *proc;
	APTR oldWindowPtr;
	long chipRam, fastRam;
	int argIndex;

	argIndex = GetOptions(argc, argv);
	*out = MakeOutArray();

	if (!(flags & FLAG_REQUESTORS))
	 	DisableRequestors(&proc, &oldWindowPtr);

	GetFreeRam(&chipRam, &fastRam);

	if (argIndex >= argc)
		FreeUsingEnv(chipRam, fastRam, *out);
	else
		FreeFromArgs(argv+argIndex, chipRam, fastRam, *out);

	Write(Output(), *out, (long)strlen(*out));	/* For speed. */

	if (!(flags & FLAG_REQUESTORS))
	 	EnableRequestors(proc, oldWindowPtr);
}


/* The user specified no volumes as command-line arguments.  So, check
 * the environment variable.  If it has no value, then use DEFAULT_VOLUMES
 * instead.
 * We use the WONDERFUL function strtok() iteratively, to get the name of
 * each volume, one at a time. */

void FreeUsingEnv(long chipRam, long fastRam, char out[])
{
	static char *defaultVolumes = DEFAULT_VOLUMES;
	char *volume, *volumeList;
	
	volumeList = GetEnv(ENV_VARIABLE);
	if (!volumeList)
		volumeList = defaultVolumes;

	volume = strtok(volumeList, ENV_SEPARATOR);
	while (volume)
	{
		ShowFree(volume, chipRam, fastRam, out);
		volume = strtok(NULL, ENV_SEPARATOR);
	}
}


/* The user specified volumes on the command-line.  Check each one. */

void FreeFromArgs(char *argv[], long chipRam, long fastRam, char out[])
{
	while (*argv)
		ShowFree(*argv++, chipRam, fastRam, out);
}


/* Process the user's command-line options.
 * Return the index of the first argument appearing AFTER all options. */

int GetOptions(int argc, char *argv[])
{
	register char c;
	long m;

	while ((c = getopt(argc, argv, OPTSTRING)) != EOF)
	{
		switch (c)
		{
			case OPT_BLOCKS:
				flags |= FLAG_BLOCKS;
				break;
			case OPT_REQUESTORS:
				flags |= FLAG_REQUESTORS;
				break;
			case OPT_MALLOC:
				flags |= FLAG_MALLOC;
				if ((m = atoi(optarg)) > 0)
					memSize = m;
				break;
			case OPT_VOLUME_NAME_LEN:
				flags |= FLAG_VOLUME_NAME_LEN;
				volumeNameLen = atoi(optarg);
				CheckVolumeNameLen(&volumeNameLen);
				break;
			case OPT_UNKNOWN:
				break;
			default:	/* Sanity check! */
				ExitCleanly((char *)NULL, ERROR_IMPOSSIBLE,
					    RETURN_FAIL);
				break;
		}
	}
	return(optind);
}


/* Deallocate memory, print a message, and exit. */
void ExitCleanly(char *arr, ERROR errorCode, int exitCode)
{
	if (arr)
		free(arr);
	if (errorCode)
		ErrorMsg(errorCode);
	exit(exitCode);
}


/* Like the name says... initialize our global variables. */

void InitializeGlobals()
{
	flags		= 0L;
	memSize		= DEFAULT_MEMORY_LIMIT;
	volumeNameLen	= DEFAULT_NAME_LEN;
}
