/*
Auto:		smake MCalc
*/

/* $Revision Header built automatically *************** (do not edit) ************
**
** © Copyright by GuntherSoft
**
** File             : SnakeSYS:CPrgs/MUICalc/MCalcARexx.c
** Created on       : Sunday, 05.12.93 14:37:01
** Created by       : Kai Iske
** Current revision : V1.0
**
**
** Purpose
** -------
**   - ARexx support for MUIProCalc
**
** Revision V1.0
** --------------
** created on Sunday, 05.12.93 14:37:01  by  Kai Iske.   LogMessage :
**     --- Initial release ---
**
*********************************************************************************/





/**********************************************************************/
/*                      Routines for that module                      */
/**********************************************************************/
static APTR __saveds __asm DoRXCalc(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms);
static APTR __saveds __asm DoRXCalcTeX(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms);
static APTR __saveds __asm GetOutput(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms);
static APTR __saveds __asm GetTeXOutput(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms);
static APTR __saveds __asm GetInput(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms);
static APTR __saveds __asm GetTeXInput(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms);
static APTR __saveds __asm DoFormatTeX(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms);
static APTR __saveds __asm SetMode(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms);
static APTR ReturnEntry(UWORD Mode, UWORD OutMode, LONG Pos);
static void FormatTeX(char *Source, char *Dest);


/**********************************************************************/
/*           external references to main programs variables           */
/**********************************************************************/
extern APTR	AppObject;
extern APTR	InputString;
extern APTR	OutputBox;
extern UWORD	IntType;
extern UWORD	IntBase;
extern UWORD	IntSign;
extern UWORD	IntAngle;




/**********************************************************************/
/*                               Hooks                                */
/**********************************************************************/
static struct Hook CalcHook =
{
	{NULL},
	(APTR)DoRXCalc,
	NULL,
	NULL
};

static struct Hook CalcTeXHook =
{
	{NULL},
	(APTR)DoRXCalcTeX,
	NULL,
	NULL
};

static struct Hook GetOutputHook =
{
	{NULL},
	(APTR)GetOutput,
	NULL,
	NULL
};

static struct Hook GetTeXOutputHook =
{
	{NULL},
	(APTR)GetTeXOutput,
	NULL,
	NULL
};

static struct Hook GetInputHook =
{
	{NULL},
	(APTR)GetInput,
	NULL,
	NULL
};

static struct Hook GetTeXInputHook =
{
	{NULL},
	(APTR)GetTeXInput,
	NULL,
	NULL
};

static struct Hook FormatTeXHook =
{
	{NULL},
	(APTR)DoFormatTeX,
	NULL,
	NULL
};

static struct Hook SetModeHook =
{
	{NULL},
	(APTR)SetMode,
	NULL,
	NULL
};




/**********************************************************************/
/*                       This is for our modes                        */
/**********************************************************************/
UWORD	RXIntType;
UWORD	RXIntBase;
UWORD	RXIntSign;
UWORD	RXIntAngle;




/**********************************************************************/
/*               Array of ARexx commands for MUIProCalc               */
/**********************************************************************/
struct	MUI_Command	RXCommands[] =
{
		// Calculate an expression (normal output)

	{
		"CALC",
		"EXPRESSION/A/M",
		1,
		&CalcHook
	},

		// Calculate an expression (TeX output)

	{
		"CALCTEX",
		"EXPRESSION/A/M",
		1,
		&CalcTeXHook
	},

		// Select output from history (normal output; as is)

	{
		"GETOUTPUT",
		"ENTRYNUM/N",
		1,
		&GetOutputHook
	},

		// Select output from history (TeX output)

	{
		"GETTEXOUTPUT",
		"ENTRYNUM/N",
		1,
		&GetTeXOutputHook
	},

		// Select input from history (normal output; as is)

	{
		"GETINPUT",
		"ENTRYNUM/N",
		1,
		&GetInputHook
	},

		// Select input from history (TeX output)

	{
		"GETTEXINPUT",
		"ENTRYNUM/N",
		1,
		&GetTeXInputHook
	},


		// Format an expression to TeX format

	{
		"FORMATTEX",
		"EXPRESSION/A/M",
		1,
		&FormatTeXHook
	},


		// Set output mode

	{
		"SETMODE",
		"BASE/K,SIZE/K,SIGN/K,ANGLE/K",
		4,
		&SetModeHook
	},



		// Delimiter

	{
		NULL, NULL, NULL, NULL
	}
};





/**********************************************************************/
/*        Let MUIProCalc (normal output) calculate through ARexx      */
/*        ------------------------------------------------------      */
/* Parameters must be :                                               */
/* Expr  = Expression to calculate                                    */
/**********************************************************************/
static APTR __saveds __asm DoRXCalc(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms)
{
	UWORD	BackIntType, BackIntBase, BackIntSign, BackIntAngle;
	char	NewBuff[258], **Exprs;
	BOOL	GoOn = TRUE;

		// Build expression from partial input

	strcpy(NewBuff, "");
	Exprs = (char **)Parms[0];
	while(*Exprs && GoOn)
	{
		if((strlen(*Exprs) + strlen(NewBuff)) < 256)
			strcat(NewBuff, *Exprs);
		else
			GoOn = FALSE;

		Exprs++;
	}

		// Set input string to current expression

	set(InputString, MUIA_String_Contents, NewBuff);

		// Calculate expression (with ARexx settings)

	BackIntType	= IntType;
	BackIntBase	= IntBase;
	BackIntSign	= IntSign;
	BackIntAngle	= IntAngle;

	IntType		= RXIntType;
	IntBase		= RXIntBase;
	IntSign		= RXIntSign;
	IntAngle	= RXIntAngle;

	GoOn = FormatOutput(FALSE);

	IntType		= BackIntType;
	IntBase		= BackIntBase;
	IntSign		= BackIntSign;
	IntAngle	= BackIntAngle;

	if(GoOn)
	{

			// Return output

		return(ReturnEntry(GET_OUTPUT, NORMAL_OUTPUT, GET_ACTIVE));
	}
	else
		return((APTR)set(AppObject, MUIA_Application_RexxString,  " "));
}






/**********************************************************************/
/*         Let MUIProCalc (TeX output) calculate through ARexx        */
/*         ---------------------------------------------------        */
/* Parameters must be :                                               */
/* Expr  = Expression to calculate                                    */
/**********************************************************************/
static APTR __saveds __asm DoRXCalcTeX(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms)
{
	UWORD	BackIntType, BackIntBase, BackIntSign, BackIntAngle;
	char	NewBuff[258], **Exprs;
	BOOL	GoOn = TRUE;

		// Build expression from partial input

	strcpy(NewBuff, "");
	Exprs = (char **)Parms[0];
	while(*Exprs && GoOn)
	{
		if((strlen(*Exprs) + strlen(NewBuff)) < 256)
			strcat(NewBuff, *Exprs);
		else
			GoOn = FALSE;

		Exprs++;
	}

		// Set input string to current expression

	set(InputString, MUIA_String_Contents, NewBuff);

		// Calculate expression (with ARexx settings)

	BackIntType	= IntType;
	BackIntBase	= IntBase;
	BackIntSign	= IntSign;
	BackIntAngle	= IntAngle;

	IntType		= RXIntType;
	IntBase		= RXIntBase;
	IntSign		= RXIntSign;
	IntAngle	= RXIntAngle;

	GoOn = FormatOutput(FALSE);

	IntType		= BackIntType;
	IntBase		= BackIntBase;
	IntSign		= BackIntSign;
	IntAngle	= BackIntAngle;

	if(GoOn)
	{

			// Return output

		return(ReturnEntry(GET_OUTPUT, TEX_OUTPUT, GET_ACTIVE));
	}
	else
		return((APTR)set(AppObject, MUIA_Application_RexxString,  " "));
}






/**********************************************************************/
/*               GetOutput (normal output) from History               */
/*               --------------------------------------               */
/* Parameters may be :                                                */
/* n    = Nth entry                                                   */
/* -1   = Active entry                                                */
/* -2   = TopMost entry                                               */
/* -3   = BottomMost entry                                            */
/* default :                                                          */
/*        get active entry                                            */
/**********************************************************************/
static APTR __saveds __asm GetOutput(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms)
{
	LONG	*ValuePtr = (LONG *)Parms[0],
		Value;

	if(ValuePtr)
		Value	= *ValuePtr;
	else
		Value	= -1;

	return(ReturnEntry(GET_OUTPUT, NORMAL_OUTPUT, Value));
}






/**********************************************************************/
/*                GetOutput (TeX output) from History                 */
/*                -----------------------------------                 */
/* Parameters may be :                                                */
/* n    = Nth entry                                                   */
/* -1   = Active entry                                                */
/* -2   = TopMost entry                                               */
/* -3   = BottomMost entry                                            */
/* default :                                                          */
/*        get active entry                                            */
/**********************************************************************/
static APTR __saveds __asm GetTeXOutput(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms)
{
	LONG	*ValuePtr = (LONG *)Parms[0],
		Value;

	if(ValuePtr)
		Value	= *ValuePtr;
	else
		Value	= -1;

	return(ReturnEntry(GET_OUTPUT, TEX_OUTPUT, Value));
}







/**********************************************************************/
/*                GetInput (normal input) from History                */
/*                ------------------------------------                */
/* Parameters may be :                                                */
/* n    = Nth entry                                                   */
/* -1   = Active entry                                                */
/* -2   = TopMost entry                                               */
/* -3   = BottomMost entry                                            */
/* default :                                                          */
/*        get active entry                                            */
/**********************************************************************/
static APTR __saveds __asm GetInput(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms)
{
	LONG	*ValuePtr = (LONG *)Parms[0],
		Value;

	if(ValuePtr)
		Value	= *ValuePtr;
	else
		Value	= -1;

	return(ReturnEntry(GET_INPUT, NORMAL_OUTPUT, Value));
}







/**********************************************************************/
/*                 GetInput (TeX input) from History                  */
/*                 ---------------------------------                  */
/* Parameters may be :                                                */
/* n    = Nth entry                                                   */
/* -1   = Active entry                                                */
/* -2   = TopMost entry                                               */
/* -3   = BottomMost entry                                            */
/* default :                                                          */
/*        get active entry                                            */
/**********************************************************************/
static APTR __saveds __asm GetTeXInput(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms)
{
	LONG	*ValuePtr = (LONG *)Parms[0],
		Value;

	if(ValuePtr)
		Value	= *ValuePtr;
	else
		Value	= -1;

	return(ReturnEntry(GET_INPUT, TEX_OUTPUT, Value));
}








/**********************************************************************/
/*                 Format an expression to TeX format                 */
/*                 ----------------------------------                 */
/* Parameters must be                                                 */
/* Expr  = Expression to convert                                      */
/**********************************************************************/
static APTR __saveds __asm DoFormatTeX(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms)
{
	char	NewBuff[512], **Exprs;
	char	OutBuff[840];
	BOOL	GoOn = TRUE;

		// Build expression from partial input

	strcpy(NewBuff, "");
	Exprs = (char **)Parms[0];
	while(*Exprs && GoOn)
	{
		if((strlen(*Exprs) + strlen(NewBuff)) < 256)
			strcat(NewBuff, *Exprs);
		else
			GoOn = FALSE;

		Exprs++;
	}

		// Format output

	FormatTeX(NewBuff, OutBuff);

		// Return RexxString

	return((APTR)set(AppObject, MUIA_Application_RexxString,  OutBuff));
}





/**********************************************************************/
/*               Set outputmodes for ARexx Calculation                */
/*               -------------------------------------                */
/* Parameters may be :                                                */
/* BASE  = Set the output base                                        */
/* SIZE  = Set output size                                            */
/* SIGN  = Set signed/unsigned output                                 */
/* ANGLE = Set default angle                                          */
/**********************************************************************/
static APTR __saveds __asm SetMode(register __a0 struct Hook *MyHook, register __a2 APTR *MyObject, register __a1 ULONG *Parms)
{
	char	*ThisVal;

		// Check for BASE keyword

	if((ThisVal = (char *)Parms[0]))
	{
		if(MatchToolValue(ThisVal, "DEC"))
			RXIntType	= ID_DECIMAL;
		else if(MatchToolValue(ThisVal, "HEX"))
			RXIntType	= ID_HEXDECIMAL;
		else if(MatchToolValue(ThisVal, "OCT"))
			RXIntType	= ID_OCTAL;
		else if(MatchToolValue(ThisVal, "BIN"))
			RXIntType	= ID_BINARY;
	}

		// Check for SIZE keyword

	if((ThisVal = (char *)Parms[1]))
	{
		if(MatchToolValue(ThisVal, "8"))
			RXIntBase	= ID_8BIT;
		else if(MatchToolValue(ThisVal, "16"))
			RXIntBase	= ID_16BIT;
		else if(MatchToolValue(ThisVal, "32"))
			RXIntBase	= ID_32BIT;
	}

		// Check for SIGN keyword

	if((ThisVal = (char *)Parms[2]))
	{
		if(MatchToolValue(ThisVal, "SIGNED"))
			RXIntSign	= ID_SIGNED;
		else if(MatchToolValue(ThisVal, "UNSIGNED"))
			RXIntSign	= ID_UNSIGNED;
	}


		// Check for ANGLE keyword

	if((ThisVal = (char *)Parms[3]))
	{
		if(MatchToolValue(ThisVal, "RAD"))
			RXIntAngle	= ID_RAD;
		else if(MatchToolValue(ThisVal, "DEG"))
			RXIntAngle	= ID_DEG;
	}

	return(NULL);
}



/**********************************************************************/
/*                       Return a normal entry                        */
/**********************************************************************/
static APTR ReturnEntry(UWORD Mode, UWORD OutMode, LONG Pos)
{
	struct	ListStruct	*LSV	= NULL;
	char	*Source;
	char	OutBuffer[300];

		// Get appropriate entry

	if(Pos == GET_ACTIVE)
		DoMethod(OutputBox, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &LSV);
	else if(Pos == GET_TOPMOST)
		DoMethod(OutputBox, MUIM_List_GetEntry, 0, &LSV);
	else if(Pos == GET_BOTTOMMOST)
	{
		struct	ListStruct	*Dummy;
		ULONG	i;

			// Move to end of list

		for(i = 0;; i++)
		{
			DoMethod(OutputBox, MUIM_List_GetEntry, i, &Dummy);

			if(Dummy)
				LSV = Dummy;
			else
				break;
		}
	}
	else
	{
		ULONG	NumEntries;

			// First check, whether entry argument is appropriate

		get(OutputBox, MUIA_List_Entries, &NumEntries);

		if(Pos < GET_BOTTOMMOST || Pos >= NumEntries)
			Pos	= MUIV_List_GetEntry_Active;

		DoMethod(OutputBox, MUIM_List_GetEntry, Pos, &LSV);
	}

	if(LSV)
	{
			// Get correct source of input

		Source	= ((Mode == GET_OUTPUT) ? LSV->Output : LSV->Input);

		if(OutMode == NORMAL_OUTPUT)
			strncpy(OutBuffer, Source, 299);
		else
			FormatTeX(Source, OutBuffer);

			// Return RexxString

		return((APTR)set(AppObject, MUIA_Application_RexxString,  OutBuffer));
	}
	else
		return((APTR)set(AppObject, MUIA_Application_RexxString,  " "));
}








/**********************************************************************/
/*            Format a given entry according to TeX rules             */
/**********************************************************************/
static void FormatTeX(char *Source, char *Dest)
{
	char	*CopyDest	= Dest;
	BOOL	HexMode		= FALSE;
	BOOL	PowMode		= FALSE;
	UWORD	BraceMode	= 0;

	while(*Source)
	{
		if(*Source == '$')
		{
			*Dest++	= '\\';
			*Dest++	= '$';
			Source++;

			HexMode	= TRUE;
		}

		if(*Source == '0' && (*(Source + 1) == 'x' || *(Source + 1) == 'X'))
		{
			*Dest++	= '\\';
			*Dest++	= '$';
			Source++;
			Source++;

			HexMode	= TRUE;
		}

		else if(*Source == '*')
		{
			*Dest	= '\0';
			strcat(CopyDest, "\\cdot ");
			Dest	= CopyDest + strlen(CopyDest);
			Source++;

			HexMode	= FALSE;
		}

		else if(*Source == '\\')
		{
			*Dest++	= '\\';

			HexMode	= FALSE;
		}

		else if(*Source == '&')
		{
			*Dest++	= '\\';
			*Dest++	= *Source++;

			HexMode	= FALSE;
		}

		else if(*Source == '%')
		{
			*Dest++	= '\\';
			*Dest++	= *Source++;

			HexMode	= FALSE;
		}

		else if(*Source == '(')
		{
			*Dest++		= *Source++;
			BraceMode++;
		}

		else if(*Source == ')')
		{
			*Dest++		= *Source++;
			BraceMode--;
			if(PowMode && !BraceMode)
			{
				*Dest++	= '}';
				PowMode	= FALSE;
			}
		}

		else if(*Source == '^')
		{
			*Dest++		= *Source++;
			*Dest++		= '{';
			PowMode		= TRUE;
		}

		else if((*Source == 'e' || *Source == 'E') && !HexMode)
		{
			*Dest	= '\0';
			strcat(CopyDest, "\\cdot 10^{");
			Dest	= CopyDest + strlen(CopyDest);
			Source++;
			while(*Source == '-' || (*Source >= '0' && *Source <= '9'))
				*Dest++	= *Source++;
			*Dest++	= '}';
		}

		else if((*Source >= '0' && *Source <= '9') || *Source == '.' || *Source == '/' || *Source == '+' || *Source == '-' || *Source == ' ' || (*Source >= 'a' && *Source <= 'f') || (*Source >= 'A' && *Source <= 'F'))
		{
			*Dest++	= *Source++;
			if(*Source == ' ' && PowMode && !BraceMode)
			{
				*Dest++	= '}';
				PowMode	= FALSE;
			}
		}

		else
			Source++;
	}

	*Dest	= '\0';
}
