/* AUC.c ********************************************************************
*
*	AUC ---	Yet another clock utility.
*
*		Well well, there are enough clock utilities available
*		already, each one claiming to be the ideal solution to
*		the problem: get time, memory, disk and additional
*		system information in readable form. This one does
*		not claim to be the perfect solution, but it is intended
*		as a demonstration for a font conversion program and
*		has some additional features the original source code
*		did not contain. To be honest, some characteristics of
*		the original source code were stripped to suit my own
*		conveniences.
*
*		This is what AUC (An Ultimate Clock) offers:
*
*		o Free RAM space (both chip and fast and a "percent
*		  full" indicator).
*
*		o Free disk space for DF0: and DF1:, as well as
*		  a protected/not protected status indicator.
*
*		o Date and time display.
*
*		o No Intuition refresh states due to ghosting or
*		  other influences.
*
*		I said I modified a program to make "AUC" look how it
*		looks now. The original program was written by
*		"Magic Ceee" in 1987 and was called "TUC". Originally
*		based on Mike Meyer's "MClk" program "AUC" can be seen
*		as a third generation clock utility. Anyway, I hope
*		you like it.
*
*		This neat program was compiled and partly rewritten
*		by (the one and only...) Olaf Barthel of ED Electronic
*		Design Hannover.
*
****************************************************************************/

#include <intuition/intuitionbase.h>
#include <libraries/dosextens.h>
#include <devices/trackdisk.h>
#include <graphics/gfxbase.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <stdio.h>

	/* Some definitions to reflect the state of the connected
	 * disk drives.
	 */

#define NO_DISK		"NO DISK"
#define NO_DRIVE	"NO DRIVE"
#define PROTECTED	"-P"
#define NO_SPACE	"FULL"

	/* Forward declarations we all need. */

extern struct FileLock	*Lock();
extern void		*AllocMem();
extern struct Window	*OpenWindow();
extern struct Library	*OpenLibrary();
extern struct Message	*GetMsg();
extern struct Task	*FindTask();
extern struct MsgPort 	*CreatePort(),*FindPort();
extern struct IORequest *CreateExtIO();

	/* Global definitions need both by the linker and some
	 * global handling routines.
	 */

struct IntuitionBase	*IntuitionBase;
struct GfxBase		*GfxBase;
struct Window		*MagicWindow;  
struct DateStamp	MagicDate;
struct IntuiMessage	*MagicMsg;
struct MsgPort		*Running;

	/* Some more global data various subroutines need. */

BYTE FreeBytes1[10],FreeBytes2[10],MagicBuffer[100],*DriveNames[2] = { "DF0:","DF1:" };
SHORT DeviceError,NoDrive = FALSE,DiskStatus,Protection;

	/* Intuition and the MaxMemSize routines need these. */

ULONG Class;
long MaxMem;

	/* This one is a fake draggadget Intuition will accept instead
	 * of a dragbar. If you can still remember Leo Schwab's Iconify-
	 * routines you will certainly remember the gadget type:
	 * WDRAGGING.
	 */

struct Gadget DragGadget =
{
	(struct Gadget *)NULL,
	0,0,
	640,10,
	GADGHNONE,
	GADGIMMEDIATE,
	WDRAGGING,
	(APTR)NULL,
	(APTR)NULL,
	(struct IntuiText *)NULL,
	0,
	(APTR)NULL,
	0,
	(APTR)NULL
};

	/* This is the window to receive the information
	 * we wish to display.
	 */

struct NewWindow NewWindow =
{
	0,0,
	640,10,
	1,2,
	CLOSEWINDOW | DISKINSERTED | DISKREMOVED,
	WINDOWCLOSE | WINDOWDEPTH | RMBTRAP,
	(struct Gadget *)&DragGadget,
	(struct Image *)NULL,
	(UBYTE *)NULL,
	(struct Screen *)NULL,
	(struct BitMap *)NULL,
	0,0,0,0,WBENCHSCREEN
};

	/* Yep, this is a font definition for a diskfont. */

struct TextAttr PleasureFont =
{
	(UBYTE *)"Narrow.font",
	8,
	FS_NORMAL,
	FPF_DISKFONT
};

	/* This is the "container" for the information string. */

struct IntuiText TimeString =
{
	1,2,
	JAM2,
	0,0,
	(struct TextAttr *)&PleasureFont,
	(UBYTE *)MagicBuffer,
	(struct IntuiText *)NULL
};

	/* This is >ME<, we need >US< to avoid dreadful DOS
	 * requesters.
	 */

struct Process *Me;

	/* Two lines save more than 1000 Bytes... */

void _wb_parse(){}
void _cli_parse(){}

	/* Global data needed by detach.o32 */

long  _stack        = 8000;
long  _priority     = 0;
long  _BackGroundIO = 0;
char *_procname     = "An Ultimate Clock";

	/* MaxMemSize(MemType) :
	 *
	 *	This one was borrowed from GfxMem 0.4 by
	 *	Louis A. Mamakos. MaxMemSize will return the
	 *	length of the memory blocks linked via
	 *	the MemList to be found in ExecBase.
	 */

long
MaxMemSize(MemType)
register unsigned long MemType;
{
	register long BlockSize = 0;
	register struct MemHeader *MemHeader;
	extern struct ExecBase *SysBase;

	Forbid();

		/* Walk through the list entries adding the sizes
		 * of the blocks...
		 */

	for(MemHeader = (struct MemHeader *)SysBase -> MemList . lh_Head ; MemHeader -> mh_Node . ln_Succ ; MemHeader = (struct MemHeader *)MemHeader -> mh_Node . ln_Succ)
		if(MemHeader -> mh_Attributes & MemType)
			BlockSize += ((ULONG)MemHeader -> mh_Upper - (ULONG)MemHeader -> mh_Lower);

	Permit();

	return(BlockSize);
}

	/* WhichDate() :
	 *
	 *	This one was rewritten from Rob Pecks book
	 *	"Programmer's Guide to the Amiga". It converts
	 *	the contents from a datestamp to a date string
	 *	"LIST" and other programs display.
	 */

char *
WhichDate()
{
	static char Buff[20];

	static char *Months[12] =
	{
		"Jan","Feb","Mar","Apr",
		"May","Jun","Jul","Aug",
		"Sep","Oct","Nov","Dec"
	};

	struct DateStamp Date;

	long n,Month,Day,Year;

		/* Initialize the string. */

	DateStamp(&Date);

		/* Recalculate year, month and day. */

	n = Date . ds_Days - 2251;
	Year = (4 * n + 3) / 1461;
	n -= 1461 * Year / 4;
	Year += 1984;
	Month = (5 * n + 2) / 153;
	Day = n - (153 * Month + 2) / 5 + 1;
	Month += 3;

		/* Strange... increment month. */

	if(Month > 12)
	{
		Year++;
		Month -= 12;
	}

		/* We need the two last digits. */

	Year -= 1900;

		/* Put it into the buffer and return a pointer
		 * to it.
		 */

	sprintf(Buff,"%02d-%s-%02d",Day,Months[Month - 1],Year);

	return(Buff);
}

	/* ToggleNarrowFont() :
	 *
	 *	This is it! TUC used a font called d132.font
	 *	to display the information in its statusline.
	 *	NewZAP 3.0 contained some font information whose
	 *	structure "inspired" me to write a small program
	 *	to convert fixed-width fonts into program source
	 *	code. The following routine was generated by this
	 *	program. The most interesting fact is connected with
	 *	the Node initialization and the AddFont()/RemFont()
	 *	in the following lines. These measures insure that
	 *	the font will be linked into the system's list of
	 *	open fonts even though it has not passed
	 *	diskfont.library.
	 */

struct TextFont *
ToggleNarrowFont()
{
	static BOOL Access = FALSE;		/* Already linked? */
	static struct TextFont Narrow8Font;	/* We will fake it. */

		/* This is a full featured data dump of the d132.font
		 * used by this program.
		 */

	static long Narrow8Dump[485] =
	{
		0x0224A648,0x88362400,0x00026218,0xC378DE63,
		0x0001020C,0x7338CE7B,0xCC971D28,0x4A4CE338,
		0xCE4A5294,0xBDE87980,0x80200100,0x8082050C,
		0x00000000,0x04000000,0x00646159,0xF8246E01,
		0xCE000044,0x03D08739,0xC0024000,0x0002110C,
		0x9314E670,0x50648506,0x49428324,0xA00A0C90,
		0xB8090A0C,0x91140018,0x50648506,0x49421419,
		0x22000000,0x0724A709,0x48412480,0x00029625,
		0x25410294,0x98C20112,0x94A52942,0x12920928,
		0x7B5294A5,0x244A5294,0x85080A40,0x80200101,
		0x40800104,0x00000000,0x04000000,0x00841286,
		0x8924A91A,0x14001004,0x00129108,0x49200013,
		0x24052092,0x00294948,0x88900889,0x02844481,
		0x41111201,0x10001112,0x00280020,0x88900889,
		0x02842224,0x04200000,0x0701E808,0x90809880,
		0x0004B204,0x29720294,0x98C47882,0xF4A50942,
		0x10920948,0x7B5294A5,0x044A5294,0x89040800,
		0x4338E731,0x0CE60524,0x49CCE3A8,0xEE4A5294,
		0xBC841019,0x8BA48E21,0x944C804E,0x7B94A338,
		0xC6224424,0xA545318C,0x6319484B,0xDEF7B9CE,
		0x734C6318,0xC74A5294,0x98C9318C,0x6319A611,
		0x8C630000,0x201E0000,0x09318000,0x0200A611,
		0x0080BDC0,0x7804F208,0xC90B8463,0x80080044,
		0xF7B90973,0x96F20988,0x4AD2E4B8,0xC44A5263,
		0x19040800,0x00A5094B,0x92920544,0x7A5294B5,
		0x044A5294,0x85040806,0x8D19C822,0x54925084,
		0x03884720,0x46224E44,0x81464A52,0x94A5E86A,
		0x10841084,0x235294A5,0x294A5294,0x95290842,
		0x1084590A,0x52949084,0x21D294A5,0x29284000,
		0x0200A122,0x80809880,0x0008D210,0x2F0A4490,
		0x80040088,0x84A50942,0x12922948,0x4AD284A8,
		0x244A5E93,0x11020800,0x03A50979,0x12920584,
		0x4A5294A0,0xC44A5264,0x98841019,0x8D3C8EF2,
		0x4C4C9104,0x7A92B879,0xC9224483,0x01497BDE,
		0xF7BD494B,0x9CE71084,0x235294A5,0x294A5293,
		0x18C639CE,0x739CF83B,0xDEF79084,0x225E94A5,
		0x2F29C000,0x0001EE42,0x40412484,0x03089221,
		0x214A4490,0x98C27900,0x84A52942,0x12922928,
		0x4AD284A5,0x24499E93,0x21020800,0x04A50941,
		0x0E922544,0x4A52E3A0,0x25499E93,0xA0841006,
		0x8B998D21,0x84001120,0x024A1940,0x00214000,
		0x01C94A52,0x94A5474A,0x10841084,0x22D294A5,
		0x2E4A5293,0x10064A52,0x94A5474A,0x10841084,
		0x224894A5,0x21324000,0x0200A649,0x80362404,
		0x0310673C,0xC1318463,0x18C10208,0x74B8CE7A,
		0x0C97112F,0x4A4C83A4,0xC4319293,0x3DE17800,
		0x03B8E73B,0x8297252E,0x4A4C80A1,0xC3399290,
		0xBC646019,0xF93DECA0,0x4E0010CF,0x000E21C0,
		0x00204000,0x01264A52,0x94A56173,0xDEF7B9CE,
		0x72CC6318,0xC87BDEF3,0x39E639CE,0x739DB131,
		0xCE738842,0x1250739C,0xE941C000,0x00000000,
		0x00000008,0x00100000,0x00000000,0x01800000,
		0x00000000,0x00000000,0x00000040,0x00000000,
		0x0001001F,0x00000000,0x1C001800,0x00008080,
		0x00000007,0x00000006,0x00180D43,0x80000000,
		0x03C27840,0x00018000,0x00080000,0x00000200,
		0x00000000,0x00000000,0x00000000,0x00000000,
		0x00000200,0x00000000,0x00000000,0x0603C000,
		0x00000005,0x00050005,0x000A0005,0x000F0005,
		0x00140005,0x00190005,0x001E0005,0x00230005,
		0x00280005,0x002D0005,0x00320005,0x00370005,
		0x003C0005,0x00410005,0x00460005,0x004B0005,
		0x00500005,0x00550005,0x005A0005,0x005F0005,
		0x00640005,0x00690005,0x006E0005,0x00730005,
		0x00780005,0x007D0005,0x00820005,0x00870005,
		0x008C0005,0x00910005,0x00960005,0x009B0005,
		0x00A00005,0x00A50005,0x00AA0005,0x00AF0005,
		0x00B40005,0x00B90005,0x00BE0005,0x00C30005,
		0x00C80005,0x00CD0005,0x00D20005,0x00D70005,
		0x00DC0005,0x00E10005,0x00E60005,0x00EB0005,
		0x00F00005,0x00F50005,0x00FA0005,0x00FF0005,
		0x01040005,0x01090005,0x010E0005,0x01130005,
		0x01180005,0x011D0005,0x01220005,0x01270005,
		0x012C0005,0x01310005,0x01360005,0x013B0005,
		0x01400005,0x01450005,0x014A0005,0x014F0005,
		0x01540005,0x01590005,0x015E0005,0x01630005,
		0x01680005,0x016D0005,0x01720005,0x01770005,
		0x017C0005,0x01810005,0x01860005,0x018B0005,
		0x01900005,0x01950005,0x019A0005,0x019F0005,
		0x01A40005,0x01A90005,0x01AE0005,0x01B30005,
		0x01B80005,0x01BD0005,0x01C20005,0x01C70005,
		0x01CC0005,0x01D10005,0x01D60005,0x01DB0005,
		0x01E00005,0x01E00005,0x01E00005,0x01E00005,
		0x01E00005,0x01E00005,0x01E00005,0x01E00005,
		0x01E00005,0x01E00005,0x01E00005,0x01E00005,
		0x01E00005,0x01E00005,0x01E00005,0x01E00005,
		0x01E00005,0x01E00005,0x01E00005,0x01E00005,
		0x01E00005,0x01E00005,0x01E00005,0x01E00005,
		0x01E00005,0x01E00005,0x01E00005,0x01E00005,
		0x01E00005,0x01E00005,0x01E00005,0x01E00005,
		0x00000005,0x01E50005,0x01EA0005,0x01EF0005,
		0x00140005,0x01F40005,0x01F90005,0x01FE0005,
		0x02030005,0x02080005,0x020D0005,0x02120005,
		0x02170005,0x021C0005,0x02210005,0x02260005,
		0x022B0005,0x02300005,0x02350005,0x023A0005,
		0x023F0005,0x02440005,0x00000005,0x00000005,
		0x02490005,0x024E0005,0x02530005,0x02580005,
		0x025D0005,0x02620005,0x02670005,0x026C0005,
		0x02710005,0x02760005,0x027B0005,0x02800005,
		0x02850005,0x028A0005,0x028F0005,0x02940005,
		0x02990005,0x029E0005,0x02A30005,0x02A80005,
		0x02AD0005,0x02B20005,0x02B70005,0x02BC0005,
		0x02C10005,0x02C60005,0x02CB0005,0x02D00005,
		0x02D50005,0x02DA0005,0x02DF0005,0x02E40005,
		0x02E90005,0x02EE0005,0x02F30005,0x02F80005,
		0x02FD0005,0x03020005,0x03070005,0x030C0005,
		0x03110005,0x03160005,0x031B0005,0x03200005,
		0x03250005,0x032A0005,0x032F0005,0x03340005,
		0x03390005,0x033E0005,0x03430005,0x03480005,
		0x034D0005,0x03520005,0x03570005,0x035C0005,
		0x03610005,0x03660005,0x02CB0005,0x02D00005,
		0x02D50005,0x02DA0005,0x02DF0005,0x036B0005,
		0x03700005,0x03750005,0x037A0005,0x037F0005,
		0x03840005,0x03890005,0x038E0005,0x01DB0005,
		0x00000005,0x00000000,0x00000000,0x02600030,
		0x235D0000,0x000000C6,0x59BC00C6,0x588C00FF,
		0xA78C00C6,0x580400FF,0x4F0800FF,0xA78C0031,
		0x8D5D0030,0x84890000,0x00000000,0x01C30000,
		0x02010000,0x00F00000,0x00F00000,0x000B0000,
		0x00000030,0xBBB70000,0x14000000,0x14000000,
		0x00010000,0x02010000,0x00000030,0x859D0030,
		0x22930000
	};

		/* Initialize the head of the TextFont structure
		 * to allow us to add the font to the system list.
		 */

	Narrow8Font . tf_Message . mn_Node . ln_Name = "Narrow.font";
	Narrow8Font . tf_Message . mn_Node . ln_Type = NT_FONT;
	Narrow8Font . tf_Message . mn_Node . ln_Pri  = 0;

		/* This is a TextFont structure, initialized as if
		 * it had been returned by OpenDiskFont().
		 */

	Narrow8Font . tf_YSize     = 8;
	Narrow8Font . tf_Style     = 0;
	Narrow8Font . tf_Flags     = 67;
	Narrow8Font . tf_XSize     = 5;
	Narrow8Font . tf_Baseline  = 6;
	Narrow8Font . tf_BoldSmear = 1;
	Narrow8Font . tf_Accessors = 0;
	Narrow8Font . tf_LoChar    = 32;
	Narrow8Font . tf_HiChar    = 255;
	Narrow8Font . tf_CharData  = (APTR)&Narrow8Dump[0];
	Narrow8Font . tf_Modulo    = 116;
	Narrow8Font . tf_CharLoc   = (APTR)((char *)&Narrow8Dump[0] + (0xC65476 - 0xC650D6));
	Narrow8Font . tf_CharSpace = 0;
	Narrow8Font . tf_CharKern  = 0;

		/* Toggle access count. */

	Access ^= TRUE;

		/* Add it or remove it. */

	if(Access)
		AddFont(&Narrow8Font);
	else
		RemFont(&Narrow8Font);

		/* Here we go... */

	return(&Narrow8Font);
}

	/* CheckDrive(WhichDrive,Command) :
	 *
	 *	Checks DF0: and DF1: and tries to get some information
	 *	on both units.
	 */

void
CheckDrive(WhichDrive,Command)
long WhichDrive;
long Command;
{
	struct MsgPort	*DiskPort;
	struct IOExtTD	*DiskReq;

	if(!(DiskPort = (struct MsgPort *)CreatePort(NULL,0)))
		return;

	if(!(DiskReq = (struct IOExtTD *)CreateExtIO(DiskPort,sizeof(struct IOExtTD))))
	{
		DeletePort(DiskPort);
		return;
	}
 
	if(OpenDevice(TD_NAME,WhichDrive,DiskReq,0))
	{
		if(WhichDrive == 0)
			sprintf(FreeBytes1,NO_DRIVE);

		if(WhichDrive == 1)
			sprintf(FreeBytes2,NO_DRIVE);

		NoDrive = TRUE;
		goto Leave;
	}

	DiskReq -> iotd_Req . io_Command = Command;
	DoIO(DiskReq);

	if(DiskStatus = DiskReq -> iotd_Req . io_Actual == 255)
	{
		if(WhichDrive == 0)
			sprintf(FreeBytes1,NO_DISK);

 		if(WhichDrive == 1)
			sprintf(FreeBytes2,NO_DISK);

		NoDrive = TRUE;
	}

	CloseDevice(DiskReq);

Leave:	DeleteExtIO(DiskReq,sizeof(struct IOExtTD));
	DeletePort(DiskPort);
}

	/* AvailDiskBytes(WhichDrive) :
	 *
	 *	Ask DOS to tell us how many blocks are still
	 *	vacant.
	 */

long
AvailDiskBytes(WhichDrive)
struct FileLock *WhichDrive;
{
	struct InfoData *DiskInfo;
	long BytesFree = 0;

	if(DiskInfo = (struct InfoData *)AllocMem(sizeof(struct InfoData),MEMF_PUBLIC))
	{
		if(Info(WhichDrive,DiskInfo))
			BytesFree = (DiskInfo -> id_NumBlocks - DiskInfo -> id_NumBlocksUsed) * DiskInfo -> id_BytesPerBlock;

		FreeMem(DiskInfo,sizeof(struct InfoData));
	}

	return(BytesFree);
}

	/* GetDFree(WhichDrive) :
	 *
	 *	Sets up the various information strings.
	 */

void
GetDFree(WhichDrive)
long WhichDrive;
{
	long FreeBytes;
	struct FileLock *MyLock;

	if(MyLock = (struct FileLock *)Lock(DriveNames[WhichDrive],ACCESS_READ))
	{
		FreeBytes = AvailDiskBytes(MyLock);
		UnLock(MyLock);
	}   
	else
	{
		if(WhichDrive == 0)
			sprintf(FreeBytes1,NO_DISK);

 		if(WhichDrive == 1)
			sprintf(FreeBytes2,NO_DISK);

		return;
	}

	if(WhichDrive == 0 && FreeBytes)
		sprintf(FreeBytes1,"%6ld",FreeBytes);
	else
		if(WhichDrive == 0 && !FreeBytes)
			sprintf(FreeBytes1,"%s",NO_SPACE);

	if(WhichDrive == 1 && FreeBytes)
		sprintf(FreeBytes2,"%6ld",FreeBytes);
	else
		if(WhichDrive == 1 && !FreeBytes)
			sprintf(FreeBytes2,"%s",NO_SPACE);

	if(Protection)
	{
		if(WhichDrive == 0)
			strcat(FreeBytes1,PROTECTED);

		if(WhichDrive == 1)
			strcat(FreeBytes2,PROTECTED);
	}
}

	/* CheckProt(WhichDrive) :
	 *
	 *	Asks DOS to tell us about the protection states of
	 *	the disk drives.
	 */

void
CheckProt(WhichDrive)
long WhichDrive;
{
	struct InfoData	*DiskInfo;
	struct FileLock	*TempLock;

	Protection = FALSE;

	if(DiskInfo = (struct InfoData *)AllocMem(sizeof(struct InfoData),MEMF_CLEAR))
	{
		if(TempLock = (struct FileLock *)Lock(DriveNames[WhichDrive],ACCESS_READ))
		{
			if(Info(TempLock,DiskInfo))
				if(DiskInfo -> id_DiskState == ID_WRITE_PROTECTED)
					Protection = TRUE;

			UnLock(TempLock);
		}

		FreeMem(DiskInfo,sizeof(struct InfoData));
	}
}

	/* UpdateDisks() :
	 *
	 *	Will update the disk information for the main program.
	 */

void
UpdateDisks()
{
	long i;

	for(i = 0 ; i < 2 ; i++)
	{
		CheckDrive(i,TD_CHANGESTATE);

		if(NoDrive)
			NoDrive = FALSE;
		else
		{
			CheckProt(i);
			GetDFree(i);
		}
	}
}

	/* Done(how) :
	 *
	 *	Deallocates anything there is to deallocate and closes
	 *	everything there is to close.
	 */

void
Done(how)
long how;
{
	if(Running)
		DeletePort(Running);

	if(MagicWindow)
	{
		while(MagicMsg = (struct IntuiMessage *)GetMsg(MagicWindow -> UserPort))
			ReplyMsg(MagicMsg);

		CloseWindow(MagicWindow);
	}

	CloseTimerDevice();

	if(IntuitionBase)
		CloseLibrary(IntuitionBase);

	if(GfxBase)
		CloseLibrary(GfxBase);

	ToggleNarrowFont();

	Me -> pr_WindowPtr = (APTR)0;

	exit(how);
}

	/* main() :
	 *
	 *	This is where everything starts.
	 */

void
main()
{
	long Hours,Minutes,Seconds,i;
	long ChipFree,FastFree,TotalFree;

	char *TheDateIs;

		/* Are we already around somewhere? */

	if(Running = (struct MsgPort *)FindPort("AUC Running!"))
		exit(0);

		/* Tell DOS no to bring requesters to the front
		 * as soon as we try to lock something that isn't
		 * present.
		 */

	Me = (struct Process *)FindTask(NULL);

	Me -> pr_WindowPtr = (APTR)-1;

		/* Just say that we are here. */

	if(!(Running = (struct MsgPort *)CreatePort("AUC Running!",0)))
		Done(20);

		/* Open all the libraries we need. */

	if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
		Done(20);

	if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)))
		Done(20);

		/* Open the timer, the window and activate the font. */

	if(!OpenTimerDevice())
		Done(20);

	if(!(MagicWindow = (struct Window *)OpenWindow(&NewWindow)))
		Done(20);

	ToggleNarrowFont();

		/* Get some information we might need on startup. */

	MaxMem		= MaxMemSize(MEMF_CHIP) + MaxMemSize(MEMF_FAST);
	ChipFree	= AvailMem(MEMF_CHIP);
	FastFree	= AvailMem(MEMF_FAST);
	TotalFree	= FastFree + ChipFree;

	TheDateIs	= WhichDate();

	UpdateDisks();

		/* Ad infinitum... */

	FOREVER
	{
			/* This is just an example to obtain
			 * the same information offered by DateStamp()
			 * via CurrentTime(). If you should need it
			 * some time, here is how you can split up
			 * the data.
			 */

/*		CurrentTime(&Secs,&Micros);

		Hours	= (Secs / (60 * 60)) % 24;
		Minutes = (Secs / 60) % 60;
		Seconds = Secs % 60;
*/
			/* Recalculate the time. */

		DateStamp(&MagicDate);

		Hours	= MagicDate . ds_Minute / 60;
		Minutes	= MagicDate . ds_Minute % 60;
		Seconds	= MagicDate . ds_Tick / TICKS_PER_SECOND;

			/* Update the disk info every five seconds. */

		if(!(Seconds % 5))
			UpdateDisks();

			/* Take care of the memory usage every two
			 * seconds.
			 */

		if(!(Seconds % 2))
		{
	 		ChipFree = AvailMem(MEMF_CHIP);
			FastFree = AvailMem(MEMF_FAST);
			TotalFree= FastFree + ChipFree;
		}

			/* Each hour update the date info. */

		if(!Minutes)
			TheDateIs = WhichDate();

			/* Fill the output string. */

		sprintf(MagicBuffer," Chip: %6ld  Fast: %7ld  Memory: %02d%% full  DF0: %8s  DF1: %8s  Date: %s  Time: %02d:%02d:%02d",
			ChipFree,FastFree,100 - ((TotalFree * 100) / MaxMem),
			FreeBytes1,FreeBytes2,
			TheDateIs,Hours,Minutes,Seconds);

			/* Print it. This line took me very, very, very long
			 * to program. Why? Some spying with XOper revealed
			 * that AUC consumed sometimes more than 12% of
			 * processor time. I tried to find the reason why
			 * and found out that the Text() routine slows the
			 * system down dramatically if asked to render
			 * a diskfont. To keep the rendering (and time
			 * consumption) in reasonable dimensions the
			 * update happens only once per second now.
			 */

		PrintIText(MagicWindow -> RPort,&TimeString,28,1);

			/* Wait a second... */

		WaitTime(1,0);

			/* Look for mail... */

		while(MagicMsg = (struct IntuiMessage *)GetMsg(MagicWindow -> UserPort))
		{
			Class = MagicMsg -> Class;
			ReplyMsg(MagicMsg);

			if(Class == CLOSEWINDOW)
				Done(0);

				/* Something has changed, take care
				 * of it immediately.
				 */

			if(Class == DISKINSERTED || Class == DISKREMOVED)
				UpdateDisks();
		}
	}
}
