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

    MODUL
	varstack.c

    DESCRIPTION
	Variable Stack for DME/XDME

    NOTES
	-/-

    BUGS
	<none known>

    TODO
	-/-

    EXAMPLES
	-/-

    SEE ALSO
	vars.c

    INDEX

    HISTORY
	<see RCS-File>


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

/*
**  (C)Copyright 1992 by Bernd Noll for null/zero-soft
**  All Rights Reserved
**
**  RCS Header: $Id: varstack.c,v 1.65 92/12/05 12:47:24 b_noll Exp $
**
**
*!**********************************************************
*!
*!  Variable Stacking:
*!
*!  Stacking for all structures, which may be read and
*!  written via GetTypedVar()
*!  (Please notice that stackable are only variables,
*!   not macros, menues or mappings (they are stackable, but
*!   popping or picking might fail))
*!
*!  Users should be aware to pop their entries from the stack
*!  when they are needed not any more
*!  (We have NOT planned to create a garbage-collector :-))
*!
************************************************************
**
**  Implementator's note:
**
**  variable stacking is done in a quiet simple way:
**  all variables are searched with gettypedvar and their types
**  are used as Node.ln_Type - entry
**
**  currently (12-92) we use the same structure for storing variables
**  on varstack which is used for storage in the main variable
**  lists, but I preferred redefining that structure, as this method
**  gives us the possibility of changing our definitions locally.
**  (This is as we are just implementing AVL-Trees for Varstorage)
*/

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


/**************************************
	    Globale Exports
**************************************/
Prototype void do_pushVAR  (void);
Prototype void do_pickVAR  (void);
Prototype void do_popVAR   (void);
Prototype void do_swapVAR  (void);
Prototype void do_purgeVAR (void);


#ifdef PATCH_NULL
#ifdef PATCH_VARS


/**************************************
      Interne Defines & Strukturen
**************************************/
#define MLIST struct MinList
#define MNODE struct MinNode

static MLIST varstack =
{ (MNODE*)&varstack.mlh_Tail, NULL, (MNODE*)&varstack.mlh_Head };


typedef struct _VARS
{
    NODE    Node;
    CHAR*   Str;
} VARS;


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


/**************************************
	   Impementation
**************************************/

/*
*! >PUSHVAR varname
*!
*!	push the contents of the variable varname onto variable-stack
*!
*/

void do_pushVAR (void)
{
    VARS* v;
    int type;

    if (v = malloc (sizeof (VARS)))
    {		  /* allocate a node */
	setmem(v, sizeof (VARS), 0);
	v->Node.ln_Name = strdup (av[1]);        /* and space for name and value */
	v->Str = GetTypedVar (av[1], &type);
	if (v->Node.ln_Name && v->Str)
	{	 /* if its done, fill in all values and push the node onto the varstack */
	    v->Node.ln_Type = type;
	    AddHead((LIST*)&varstack, (NODE*)v);
	} else
	{
	    if (v->Node.ln_Name)
	    {		   /* else free all what yu have already allocated */
		free(v->Node.ln_Name);
	    } /* if */
	    if (v->Str)
	    {
		free(v->Str);
	    } /* if */
	    free(v);

	    error ("%s: failure!\nno memory or unknown variable", av[0]);
	} /* if (not) malloced|found */
    } else
    {
	error ("%s: no memory for stack-entry", av[0]);
    } /* if (not) malloced */
} /* do_pushVAR */



/*
*! >POPVAR varname
*!
*!	get the latest to variable-stack pushed contents of the variable
*!	varname back and free the stack-entry
*!
*/

void do_popVAR (void)
{
    VARS* v;

    if (v = (VARS*)FindName((LIST*)&varstack, av[1]))
    { /* if there is a stack-entry of the right name */
	SetTypedVar(av[1], v->Str, v->Node.ln_Type); /* do a setvar to the right variable and the right contents */
	Remove((NODE*)v);                       /* then remove the node from varstack and */
	free(v->Str);                           /* free all its data */
	free(v->Node.ln_Name);
	free(v);
    } else
    {
	error ("%s: stackentry %s not found", av[0], av[1]);
    } /* if (not) found */
} /* do_popVAR */



/*
*! >PICKVAR varname
*!
*!	get the latest to variable-stack pushed contents of the variable
*!	varname back without freeing the stack-entry
*!
*/

void do_pickVAR (void)
{
    VARS* v;

    if (v = (VARS*)FindName((LIST*)&varstack, av[1]))
    { /* if there is a stack-entry of the right name */
	SetTypedVar(av[1], v->Str, v->Node.ln_Type); /* do a setvar to the right variable and the right contents */
    } else
    {
	error ("%s: stackentry %s not found", av[0], av[1]);
    } /* if (not) found */
} /* do_pickVAR */



/*
*! >SWAPVAR varname
*!
*!	swap the contents of the variable varname and of its first occurancy in variable-stack
*!
**  this is not a very effective way of change, I would say,
**  but it is one of the shortest
*/

void do_swapVAR (void)
{
    VARS* v;

    if (v = (VARS*)FindName((LIST*)&varstack, av[1]))
    { /* if there is a stack-entry of the right name */
	Remove((NODE*)v);                        /* remove it */
	do_pushVAR();                            /* push the variables current contents onto stack */
	AddHead((LIST*)&varstack, (NODE*)v);     /* set the elder stack-entry before that new node */
	do_popVAR();                             /* and then pop it into the variable */
    } else
    {
	error ("%s: stackentry %s not found", av[0], av[1]);
    } /* if (not) found */
} /* do_swapVAR */



/*
*! >PURGEVAR varname
*!
*!	remove all entries with the name varname from varstack
*!
*/

void do_purgeVAR (void)
{
    VARS* v;

    for (v = (VARS*)varstack.mlh_Head; v; v = (VARS*)v->Node.ln_Succ)
    { /* with all entries of varstack do */
	if (strcmp(v->Node.ln_Name, av[1]) == 0)
	{ /* if they match the requested name */
	    Remove((NODE*)v);                      /* remove them and free their parts */
	    free(v->Str);
	    free(v->Node.ln_Name);
	    free(v);
	} /* if */
    } /* for */
} /* do_purgeVAR */


#endif /* PATCH_VARS */
#endif /* PATCH_NULL */
/******************************************************************************
*****  ENDE varstack.c
******************************************************************************/

