/******************************************************************************

    MODUL
	lowlevelmacros.c

    DESCRIPTION
	die schnittstelle zu den wichtigsten Macro-funktionen,
	die von anderen Moduln verwendet werden duerfen.

    NOTES
	dies ist nur ein Dummy - Modul, das zwar alle
	Funktionen exportiert, die beschrieben wurden,
	ihre Realisierung ist jedoch stark eingeschraenkt,
	sie sind auf einfache Strings zurueckgeschraubt,
	so dass die sie verwendenden Moduln wie vorher
	angesprochen werden koennen.

    BUGS

    TODO
	bei Gelegenheit sollte dieses Modul komplett neu geschrieben werden
	und mit alias.c und main.c neu abgestimmt werden
	(so dass main.c callmacro verwendet neque vero do_command)

    EXAMPLES

    SEE ALSO

    INDEX

    HISTORY

******************************************************************************/

/**************************************
		Includes
**************************************/
#include "defs.h"


/**************************************
	    Globale Variable
**************************************/
Prototype void	 unlinkmacro (APTR);
Prototype APTR	 linkmacro   (char *);
Prototype APTR	 tempmacro   (char *);
Prototype char * macroname   (APTR);
Prototype char * GetArg      (int);
Prototype char * CommandName (void);


/**************************************
      Interne Defines & Strukturen
**************************************/


/**************************************
	    Interne Variable
**************************************/
static char tempmacro_buffer[LINE_LENGTH];


/**************************************
	   Interne Prototypes
**************************************/


	    /***********************************************
	    ***********************************************

		Dies ist lediglich eine Uebergangsloesung,
		solange wir alias.c und main.c noch nicht
		umgeschrieben haben

	    ***********************************************
	    ***********************************************/




#ifndef NOT_DEF

char * CommandName ()
{
    return (av[0]);
} /* CommandName */

char * GetArg (int num)
{
    return(av[num]);
} /* GetArg */


/* fuer keyctl - wohl auch bald obsolet */
APTR tempmacro (char * name)
{
    strncpy (tempmacro_buffer, name, LINE_LENGTH);
    return  (tempmacro_buffer);
} /* tempmacro */


#ifdef NOT_DEF

void unlinkmacro (APTR macro)
{
    if (macro == tempmacro_buffer) {
	tempmacro_buffer[0] = 0;
    } else {
	free (macro);
    } /* if */
} /* unlinkmacro */


APTR linkmacro (char * name)
{
    return (strdup (name));
} /* linkmacro */


char * macroname (APTR macro)
{
    return (macro);
} /* macroname */

#endif
#else

	    /***********************************************
	    ************************************************

		So oder so aehnlich sollte die richtige
		Version der Macro-interfaces aussehen:

	    ************************************************
	    ***********************************************/



#define MF_DeleteMe   1 /* for temp_macros:   delete if UseCount == 0			    */
#define MF_NameEQBody 2 /* for pseudo_macros: there is no difference between name and body  */
#define MF_PreParsed  4 /* for real Macros:   that macro is already preparsed		    */
#define MF_Binary     8 /* for real Macros:   that macro is compiled and cannot be parsed   */

typedef struct macro {
    XNode   Node;	/* Search-header with name-entry; combined AVL- & LIST-Node  */
    long    Flags;	/* Characteristica - see above MF_...			     */
    long    BodySize;	/* the Body maybe binary, so it might contain "\0"           */
    APTR    Body;	/* reference to the body that is executed at a macrocall     */
    char *  HelpText;	/* optional ONLINE-HELP-TEXT for help-function		     */
    UWORD   UseCount;	/* number of current links to or usages of that Macro	     */
    UWORD   NumStatics; /* number of static Variables				     */
    UWORD   NumArgs;	/* number of Arguments to be filled at a macrocall	     */
    UWORD   NumTemps;	/* number of temp. Variables to be created at a macrocall    */
    APTR  * Arguments;	/* names of the macroArgs (and their types, flags, defaults) */
    APTR  * TempVars;	/* names of the tempVars  (and their types, flags, defaults) */
    AVLTree StaticVars; /* Variable-nodes of the staticVars */
} Macro;



Macro * NewMacro (char * name, long blen, APTR body, UWORD nargs, UWORD nvars)
{
    Macro * nm = NULL;

    if (nm = AllocFunc (sizeof (Macro), MEMF_ANY)) {
	setmem (mn, sizeof (Macro), 0);
	nm->Node.xn_Name = name;
	nm->BodySize	 = blen;
	nm->Body	 = body;
	if (nm->NumArgs  = nargs) {
	    nm->Arguments= AllocFunc (nargs * sizeof (APTR), MEMF_ANY);
	    setmem	   (nm->Arguments, nargs * sizeof (APTR), 0);
	} /* if #args>0 */
	if (nm->NumTemps = nvars) {
	    nm->TempVars = AllocFunc (nvars * sizeof (APTR), MEMF_ANY);
	    setmem	   (nm->TempVars, nvars * sizeof (APTR), 0);
	} /* if #vars>0 */
    } /* if */

    return (nm);
} /* NewMacro */



void RemMacro (Macro * macro)
{
    if (macro) {
	FreeFunc (macro->Node.xn_Name, strlen (macro->Node.xn_Name)+1);
	if (!macro->Flags & MF_NameEQBody) {
	    if (macro->Body) {
		FreeFunc (macro->Body, macro->BodySize);
	    } /* if */
	} /* if */
	if (macro->HelpText) {
	    FreeFunc (macro->HelpText, strlen (macro->HelpText)+1);
	} /* if */

	if (macro->Arguments) {
	    FreeFunc (macro->Arguments, macro->NumArgs * sizeof (APTR));
	} /* if */
	if (macro->TempVars) {
	    FreeFunc (macro->TempVars, macro->NumTemps * sizeof (APTR));
	} /* if */

    /* --- evtl noch irgendwo raus hebeln */

	FreeFunc (macro, sizeof (Macro));
    } /* if */
} /* RemMacro */



/*****************************************************************************

    NAME
	unlinkmacro

    PARAMETER
	Macro * macro

    RESULT
	-/-

    RETURN
	void

    DESCRIPTION
	remove a link to a macro

    NOTES

    BUGS

    EXAMPLES

    SEE ALSO

    INTERNALS
	unlinkmacro macro*
	    setze die benutzerzahl um eins herab;
	    falls die beutzerzahl 0 ist und das macro zu loeschen ist, dann loesche es

    HISTORY
	27 Dec 1992  b_null created

******************************************************************************/

void unlinkmacro (Macro * macro)
{
    macro->UseCount --;
    if (macro->UseCount == 0) {
	FromList (Normal,  macro);
	FromList (Delenda, macro);
	RemMacro (macro);
    } /* if */
} /* unlinkmacro */



/*****************************************************************************

    NAME
	linkmacro

    PARAMETER
	char * name

    RESULT
	the macro associated with name

    RETURN
	Macro *

    DESCRIPTION
	search for a macro, that has a certain name
	(perhaps create a macro of that name - if possible)

    NOTES

    BUGS

    EXAMPLES

    SEE ALSO

    INTERNALS
	macro* = linkmacro  name*
	    durchsuche die commandos nach einem, das keine parameter erwartet,
	    und auf name hoert falls es gefunden wurde markiere es als benutzt und
	    gib es aus
	    falls es nicht gefunden wurde oder mehr als 0 argumente verlangt
		gib NULL zurueck
	    zusatz bei verwendung von alias.c:
		falls es nicht gefunden wurde, und name aus mehr als 1 wort besteht, dann erstelle ein pseudo-macro
		das nur aus name besteht , markiere es als benutzt und als ein nach letzter benutzung zu loeschendes (in der Delenda Liste ???)

    HISTORY
	27 Dec 1992  b_null created

******************************************************************************/

Macro * linkmacro (char * name)
{
    Maro * om = NULL;
    if (om = FindMacro (name, 0, -1)) {
	om->UseCount ++;
	return (om);
    } else {
	Maro * nm = NULL;
	if (nm = NewMacro (name, 0, NULL, 0, 0)) {
	    nm->Body	= nm->Node.xn_Name;
	    nm->Flags	= MF_NameEQBody|MF_DeleteMe;
	    nm-UseCount = 1;
	    ToList (Normals, nm);   /* Wenn wir sagen Normals, dann kann es wiedergefunden werden, wenn Delenda, dann haben wir fast ein tempmacro + inc(UseCount) */
	    return (nm);
	} /* if */
    } /* if */
    return (NULL);
} /* linkmacro */



/*****************************************************************************

    NAME
	tempmacro

    PARAMETER
	char * name

    RESULT
	a temporary macro, that will be deleted after its first and
	only call

    RETURN
	Macro *

    DESCRIPTION
	create a temporary macro

    NOTES

    BUGS

    EXAMPLES

    SEE ALSO

    INTERNALS

    HISTORY
	27 Dec 1992  b_null created

******************************************************************************/

Macro * tempmacro (char * name)
{
    Maro * nm = NULL;
    if (nm = NewMacro (name, 0, NULL, 0, 0)) {
	nm->Body  = nm->Node.xn_Name;
	nm->Flags = MF_DeleteMe|MF_NameEQ_Body;
	ToList (Delenda, nm);
    } /* if */
    return (nm);
} /* tempmacro */



/*****************************************************************************

    NAME
	macroname

    PARAMETER
	Macro * macro

    RESULT
	the name string of the macro

    RETURN
	char *

    DESCRIPTION
	return the of a macro

    NOTES

    BUGS

    EXAMPLES

    SEE ALSO

    INTERNALS
	name* = nameofmacro macro*
	    gib den name des macros zurueck
	    (macros koennen so als opaque type verwendet werden)

    HISTORY
	27 Dec 1992  b_null created

******************************************************************************/

char * macroname (Macro * macro)
{
    return (macro->XNode.xn_Name);
} /* macroname */

#endif /* LONG_VERS */

/******************************************************************************
*****  ENDE macros.c
******************************************************************************/
