/****************************************************************************/
/*                                  Time.c                                  */
/*                     Measure command execution time                       */
/*                    Copyright © 1994 Michael Letowski                     */
/****************************************************************************/

#define __USE_SYSBASE

#include <exec/types.h>
#include <dos/dos.h>
#include <dos/rdargs.h>
#include <dos/dostags.h>
#include <devices/timer.h>
#include <utility/tagitem.h>
#include <support/types.h>
#include <support/dos.h>

#include <string.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/timer.h>

#include "time.rev.h"

#define DOS_NAME		"dos.library"
#define DOS_VERN		37
#define TIMER_NAME	"timer.device"

STATIC CONST TEXT VersionString[]=
	VERSION(PROG_NAME,PROG_VERSION,PROG_REVISION,PROG_DATE);

#define TEMPLATE		"NOHEADER/S,COMMAND/F/A"

struct Options
{
	LONG opt_NoHeader;
	STRPTR opt_Command;
};

ULONG Time(VOID)
{
	struct ExecBase *SysBase=*((struct ExecBase **)4);
	struct DosLibrary *DOSBase;
	struct Library *TimerBase;

	struct RDArgs *Args;
	struct MsgPort *Port;
	struct timerequest *TR;
	struct Options Opts;
	struct timeval TV1,TV2;
	ULONG RC=RETURN_FAIL;

	/* Open libraries */
	unless(DOSBase=(struct DosLibrary *)OpenLibrary(DOS_NAME,DOS_VERN))
	{
		SetResult2(ERROR_INVALID_RESIDENT_LIBRARY);
		raise(NO_DOS);
	}

	/* Read args */
	clear(&Opts);
	unless(Args=ReadArgs(TEMPLATE,(LONG *)&Opts,NULL))
	{
		PrintFault(IoErr(),PROG_NAME);						/* Inform user */
		raise(NO_ARGS);
	}

	/* Do timing */
	if(Port=CreateMsgPort())
	{
		if(TR=CreateIORequest(Port,sizeof(struct timerequest)))
		{
			if(OpenDevice(TIMER_NAME,UNIT_VBLANK,(struct IORequest *)TR,0)==0)
			{
				TimerBase=(struct Library *)TR->tr_node.io_Device;

				GetSysTime(&TV1);
				RC=SystemTags(Opts.opt_Command,SYS_UserShell,TRUE,TAG_DONE) ? 
						RETURN_ERROR : RETURN_OK;
				GetSysTime(&TV2);
				SubTime(&TV2,&TV1);

				/* Print results */
				if(RC==RETURN_ERROR)										/* Error during execution */
					PrintFault(IoErr(),PROG_NAME);
				if(Opts.opt_NoHeader)
					VPrintf("%lu.%06lu\n",&TV2);
				else
					VPrintf("Execution time: %lu.%06lu s.\n",&TV2);

				CloseDevice((struct IORequest *)TR);
			}
			DeleteIORequest(TR);
		}
		DeleteMsgPort(Port);
	}

	if(RC==RETURN_FAIL)												/* Couldn't use timer */
		CauseIoErr(ERROR_NO_FREE_STORE,PROG_NAME);

	except(NO_ARGS,FreeArgs(Args));
	except(NO_DOS,CloseLibrary((struct Library *)DOSBase));

	return(RC);
}	/* Time */
