/*
 * serdate 38.2
 *
 * Display current date and time using locale.library's format capabilities.
 * This is NOT a "Date"-replacement !!!
 *
 * You may find this program useful for date stamps in logfiles, for example.
 * I need it to show the time on a serial port LED-display, this may explain
 * the strange name... ;-)
 */

#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/locale_pragmas.h>
#include <stdlib.h>

#define BUFSIZE 256

/* Taken from the autodocs and slightly modified... */
STRPTR helptext =
"%a - abbreviated weekday name           %A - weekday name\n"
"%b - abbreviated month name             %B - month name\n"
"%c - same as %a %b %d %H:%M:%S %Y       %C - same as %a %b %e %T %Z %Y\n"
"%d - day number with leading 0s         %D - same as %m/%d/%y\n"
"%e - day number with leading spaces\n"
"%h - abbreviated month name             %H - hour 24-hour style, leading 0s\n"
"%I - hour, 12-hour style, leading 0s\n"
"%j - julian date\n"
"%m - month number with leading 0s       %M - number of minutes, leading 0s\n"
"%n - insert a linefeed\n"
"%p - AM or PM strings\n"
"%q - hour using 24-hour style\n"
"%Q - hour using 12-hour style\n"
"%r - same as %I:%M:%S %p                %R - same as %H:%M\n"
"%S - number of seconds, leadings 0s\n"
"%t - insert a tab character             %T - same as %H:%M:%S\n"
"%U - week number, Sunday first weekday\n"
"%w - weekday number                     %W - week number, Monday first weekday\n"
"%x - same as %m/%d/%y                   %X - same as %H:%M:%S\n"
"%y - year, two digits, leading 0s       %Y - year, four digits, leading 0s\n";

/* BEWARE: The "__DATE__" and "__DATE2__" macro from MaxonDevelop V4 is not Y2K-ready !!! */
const STRPTR versionstring = "$VER:serdate 38.2 (01.01.2000) "__TIME__;

struct Library *LocaleBase = NULL;

/* Function prototypes */
ULONG print(register __a0 struct Hook *h, register __a1 APTR data, register __a2 APTR locale);
void wbmain(APTR wbarg);

/* System data structures */
struct DateStamp dateStamp =
{
	0L,	/* ds_Days */
	0L,	/* ds_Minute */
	0L		/* ds_Tick */
};

struct Hook dateHook =
{
	{NULL, NULL},	/* h_MinNode */
	NULL,				/* h_Entry */
	NULL,				/* h_SubEntry */
	NULL				/* h_Data */
};

/* Private data structures */
struct hookData
{
	UBYTE *string;
	ULONG counter;
	ULONG maxcount;
};

struct hookData hdata =
{
	NULL,
	0U,
	BUFSIZE - 1
};

/* Main function */
void main(ULONG mode, APTR args)
{
	struct Locale *locale;
	struct RDArgs *rda;
	UBYTE buffer[BUFSIZE];
	LONG arg[2] = {0L, 0L};
	STRPTR dateformat = "%A %d-%b-%Y  %H:%M:%S%n";
	
	LocaleBase = OpenLibrary("locale.library", 38U);
	if(!LocaleBase)
	{
		/* Write() is OS1.2-safe... :) */
		Write(Output(), "This program needs OS2.1+ !\n", 28U);
		exit(RETURN_FAIL);
	}
	
	/* Format date function needs current locale */
	locale = OpenLocale(NULL);
	if(!locale)
	{
		PutStr("Error opening standard Locale\n");
		CloseLibrary(LocaleBase);
		exit(RETURN_FAIL);
	}
	
	if(mode)
	{
		rda = ReadArgs("FORMAT,HELP/S", arg, NULL);
		if(rda)
		{
			/* At first, answer call for help... */
			if(arg[1])
			{
				PutStr(helptext);
				Printf("\nBuilt-in format is \"%s\": ", dateformat);
			}
			
			/* Change date format, only if no help requested */
			if(arg[0] && (!arg[1]))
			{
				dateformat = (STRPTR) arg[0];
			}
		}
	}
	
	/* Initialize Hook-related data structures */
	hdata.string = buffer;
	
	dateHook.h_Entry = (HOOKFUNC) print;
	dateHook.h_Data = &hdata;
	
	/* At last: format date string */
	FormatDate(locale, dateformat, DateStamp(&dateStamp), &dateHook);
	
	/* Release all (used) resources */
	if(mode)
	{
		FreeArgs(rda);
	}
	
	CloseLocale(locale);
	CloseLibrary(LocaleBase);
	
	/* Finally output date string to stdout */
	PutStr(buffer);
	
	exit(RETURN_OK);
}

/* Hook-function to handle parsed chars (Maxon registerized format) */
ULONG print(register __a0 struct Hook *h, register __a1 APTR data, register __a2 APTR locale)
{
	register UBYTE *tmp, c;
	register ULONG cnt;
	
	/* Data must be copied from adress register to someplace else in order to be accessed properly... */
	c = (UBYTE) data;
	
	/* Only do structure offset calculations once - use local variables ! */
	tmp = ((struct hookData *)h->h_Data)->string;
	cnt = ((struct hookData *)h->h_Data)->counter;
	
	/* Check for buffer overflow */
	if(cnt < (BUFSIZE - 1))
	{
		tmp[cnt] = c;
	}
	else
	{
		/* If buffer is full, just set final null-byte and exit */
		tmp[BUFSIZE - 1] = 0;
		return(0U);
	}
	
	/* This could only be optimized by a pointer reference, which means overhead... */
	((struct hookData *)h->h_Data)->counter = cnt + 1;
	
	/* Just a dummy... */
	return((ULONG) data);
}

/* Workbench functionality not yet implemented */
void wbmain(APTR wbarg)
{
	main(0, wbarg);
}

