#include "BaseConv.h"

STXT VersTag[]      = "$VER: " VSTR;
STXT Compiled[]     = "Compiled on " __DATE__ " at " __TIME__;
STXT Copyright[]    = "Copyright © 1994,95 Klaus Alexander Seistrup @ Magnetic Ink";
STXT EMail[]        = "E-mail: kas@mink.ping.dk";

STXT Template[]		= "BaseFrom/A,BaseTo/A,Numbers/A/M,-u=ToUpper/S,-l=ToLower/S";
STXT ExtHelp[]		= \
"\n" \
"›33mUSAGE:›0m ›1mBaseConv›0m <BaseFrom> <BaseTo> <Number1> [<Number2>...<NumberN>]\n" \
"\n" \
"\t<›3mBaseFrom›0m> and <›3mBaseTo›0m> must be numbers between 2 and 36\n" \
"\t<›3mNumber›0m> must be lower than 2^32\n\n" \
"BaseFrom/A,BaseTo/A,Numbers/A/M,-u=ToUpper/S,-l=ToLower/S";

STXT OrigAuthor[]	= \
"Original author:\n" \
"Xavier SIRVENT" \
"71 Cours Saint Andr‚" \
"F-38800 Le Pont de Claix";


CFG GlobCFG;



Prototype LONG	 FPrintF(BPTR,TEXT *,...);
//
LONG FPrintF(fh,ctl,...)
BPTR fh;
TEXT *ctl;
{
	LONG cnt;
	va_list va;

	va_start(va,ctl);
	cnt = VFPrintf(fh,ctl,va);
	va_end(va);

	return (cnt);
}


Prototype VOID	 Usage(CFG *);
//
VOID 
Usage(cfg)
CFG *cfg;
{
	BPTR fh = cfg->fe ? cfg->fe : cfg->fo;

	if (fh)
		FPuts(fh,ExtHelp);

	Cleanup(cfg);
}


Prototype ULONG	 Rank(TEXT,ULONG);
//
ULONG
Rank(charac,BaseFrom)	// Returns the value of the "charac" given in base "BaseFrom"
TEXT charac;
ULONG BaseFrom;
{

	LONG i = -1L;
	TEXT c = ToLower(charac);

	if (c >= '0' && c <= '9')
		i = c - '0';
	else if (c >= 'a' && c <= 'z')
		i = c - ('a' - 10);

	if ((i == -1) || (i >= BaseFrom))
	{
		CFG *cfg = &GlobCFG;
		BPTR fh  = cfg->fe ? cfg->fe : cfg->fo;

		cfg->RC  = RETURN_WARN;
		cfg->R2	 = ERROR_BAD_NUMBER;
		cfg->ErrMsg = NULL;

		c = cfg->ToLower ? ToLower(c) : ToUpper(c);

		if (fh)
			FPrintF(fh,"›33mERROR:›0m ›1m%lc›0m is forbidden in base ›1m%ld›0m\n",c,BaseFrom);

		Cleanup(cfg);
	}
	return ((ULONG) i);
}


/*
**	CSI = ›
*/


Prototype ULONG	 ToBase10(TEXT *,ULONG);
//
ULONG
ToBase10(num,BaseFrom)	// Returns base 10 of "num" given in base "BaseFrom"
TEXT *num;
ULONG BaseFrom;
{
	ULONG i;
	ULONG res1 = 0L;
	ULONG slen = strlen(num);

	for (i = 0l ; i < slen ; ++i)
	{
		ULONG res2 = UMul32(res1,BaseFrom) + Rank(num[i],BaseFrom);

		if (res2 <= res1)
		{
			CFG *cfg = &GlobCFG;
			BPTR fh  = cfg->fe ? cfg->fe : cfg->fo;

			cfg->RC  = RETURN_WARN;
			cfg->R2	 = ERROR_BAD_NUMBER;
			cfg->ErrMsg = NULL;

			if (fh)
				FPrintF(fh,"›33mERROR:›0m ›1m%s›0m > ›1m2^32›0m\n",num);

			Cleanup(cfg);
		}
		res1 = res2;
	}
	return (res1);
}



Prototype TEXT	*FromBase10(ULONG,ULONG);
//
TEXT *
FromBase10(num,BaseTo)	// Display the number in BaseTo
ULONG num,BaseTo;
{
	STATIC TEXT RevBuf[128];

	TEXT  tmp;
	TEXT *res = RevBuf;

	TEXT uchar = GlobCFG.ToLower ? 'a' : 'A';

	ULONG i = 0L;
	ULONG j = 0L;
	ULONG mod = 0L;

	/*
	** The result is generated in reverse order
	*/
	while ((num != 0L) && (i < 80L))
	{
		mod = UMod32(num,BaseTo);

		res[i++] = (mod <= 9) ? (mod + '0') : (mod - (10 - uchar));
		res[i] = 0;

		num = UDiv32(num,BaseTo);
	}

	/*
	** making the result right order 
	*/
	while (j < (i >> 1))
	{
		ULONG k = i - j - 1;

		tmp = res[j];

		res[j] = res[k];
		res[k] = tmp;

		++j;
	}
	return (res);
}



Prototype VOID	 Cleanup(CFG *);
//
VOID
Cleanup(cfg)
CFG *cfg;
{
	BPTR fh = NULL;

	if (cfg->Args)
		FreeArgs(cfg->Args);

	if (cfg->DObj)
		FreeDosObject(DOS_RDARGS,cfg->DObj);

	if (cfg->fe)
	{
		fh = SelectOutput(cfg->fe);

		if (fh)
			Flush(fh);
	}

	if (cfg->R2 && cfg->RC != RETURN_WARN)
		PrintFault(cfg->R2,cfg->ErrMsg);
	else
	if (cfg->ErrMsg)
		PutStr(cfg->ErrMsg);

	if (cfg->fe)
	{
		fh = SelectOutput(fh);

		if (fh)
			Flush(fh);

		if (cfg->CloseFE)
			Close(cfg->fe);
	}
	SetIoErr(cfg->R2);

	_exit(cfg->RC);
}


Prototype TEXT	*StrLower(TEXT *);
//
TEXT *
StrLower(str)
TEXT *str;
{
	if (str)
	{
		TEXT *low = str;

		while (*str)
		{
			*str = ToLower(*str);
			++str;
		}
		return (low);
	}
	return (NULL);
}


Prototype TEXT	*StrUpper(TEXT *);
//
TEXT *
StrUpper(str)
TEXT *str;
{
	if (str)
	{
		TEXT *upr = str;

		while (*str)
		{
			*str = ToUpper(*str);
			++str;
		}
		return (upr);
	}
	return (NULL);
}



Prototype CFG	*InitCFG(CFG *);
//
CFG *
InitCFG(cfg)
CFG *cfg;
{
	cfg->fi = Input();
	cfg->fo = Output();
	cfg->fe = ((struct Process *)FindTask(NULL))->pr_CES;

	if (cfg->fe == NULL)
	{
		cfg->fe = Open("Console:",MODE_READWRITE);

		if (cfg->fe)
			cfg->CloseFE = TRUE;
		else
			cfg->fe = cfg->fo;
	}
	cfg->ErrMsg = VersTag+6;

	if ((cfg->DObj = (ARGS *)AllocDosObject(DOS_RDARGS,NULL)) == NULL)
	{
		cfg->RC = RETURN_ERROR;
		cfg->R2 = ERROR_NO_FREE_STORE;
		cfg->ErrMsg = "AllocDosObject()";

		Cleanup(cfg);
	}
	cfg->DObj->RDA_ExtHelp = ExtHelp;

	if ((cfg->Args = ReadArgs(Template,(LONG *)&(cfg->From),cfg->DObj)) == NULL)
	{
		cfg->RC = RETURN_ERROR;
		cfg->R2 = IoErr();

		Cleanup(cfg);
	}

	if (cfg->ToLower)
		cfg->ToLower = TRUE;

	if (cfg->ToUpper)
		cfg->ToUpper = TRUE;

	if (!(cfg->ToLower ^ cfg->ToUpper))
	{
		cfg->ToLower = TRUE;
		cfg->ToUpper = FALSE;
	}

	cfg->From = cfg->ToLower ? StrLower(cfg->From) : StrUpper(cfg->From);
	cfg->To	  = cfg->ToLower ? StrLower(cfg->To)   : StrUpper(cfg->To);
	{
		ULONG i = 0L;
		TEXT **num = cfg->Number;

		while (num[i])
		{
			num[i] = cfg->ToLower ? StrLower(num[i]) : StrUpper(num[i]);
			++i;
		}
	}
	return (cfg);
}




Prototype LONG	_main(VOID);
//
LONG
_main(VOID)
{
	if (Cli())
	{
		ULONG i  = 0L;
		CFG *cfg = InitCFG(&GlobCFG);

		StrToLong(cfg->From,&(cfg->BaseFrom));
		StrToLong(cfg->To,&(cfg->BaseTo));

		if ((cfg->BaseFrom > 36) || (cfg->BaseTo > 36) || (cfg->BaseFrom < 2) || (cfg->BaseTo < 2))
		{
			BPTR fh  = cfg->fe ? cfg->fe : cfg->fo;

			cfg->RC  = RETURN_WARN;
			cfg->R2	 = ERROR_BAD_NUMBER;
			cfg->ErrMsg = NULL;

			if (fh)
				FPuts(fh,"›33mERROR:›0m <›3mBaseFrom›0m> and <›3mBaseTo›0m> must be in [2..36]\n");

			Cleanup(cfg);
		}

		while (cfg->Number[i])
		{
			FPrintf(cfg->fo,"%s = %s\n",cfg->Number[i],FromBase10(ToBase10(cfg->Number[i],cfg->BaseFrom),cfg->BaseTo));
			++i;

			if (CheckSignal(SIGBREAKF_CTRL_C))
			{
				cfg->RC = 1L;
				cfg->R2 = 304L;

				cfg->ErrMsg = NULL;

				Cleanup(cfg);
			}
		}
		cfg->RC = 0L;
		cfg->R2 = 0L;
		cfg->ErrMsg = 0L;

		Cleanup(cfg);
	}
	return (-1L);
}


/*
**	EOF
*/
