/*-----------------------------------------------------------
 *  Name: 	stack.h
 *  Created:	Fri Aug 26 17:45:02 1994
 *  Author: 	Jonathan DeKock   <dekock@winter>
 *  DESCR:  	provides a stack of elements
 */

#ifndef _STACK_H
#define _STACK_H

#include <New.h>
   
#ifdef __cplusplus
extern "C" {
#define STACK_EXPLICIT_TYPE
#endif

/**************  Debug Turned ON or OFF? *****************/
#ifdef STRUCT_DEBUG
#define STACK_DEBUG
#endif

/**************  Use Prototype definitions?  *************/
#ifdef  _NO_PROTO
#define _STACK_NO_PROTO
#else
#if    !(defined(__STDC__) && __STDC__) \
    && !defined(__cplusplus) && !defined(c_plusplus) \
    && !defined(FUNCPROTO) && !defined(XTFUNCPROTO) && !defined(XMFUNCPROTO)
#define _STACK_NO_PROTO
#endif /* __STDC__ */
#endif  /*  _NO_PROTO  */

#ifdef _STACK_NO_PROTO
#define _STACK_P(ARGS) ()
#else
#define _STACK_P(ARGS) ARGS
#endif

/*************  Global Variables **********************/
extern const char *STACK_errlist[];

/*************  Definitions  **************************/
enum STACK_ATTR {
   STACK_DYNAMIC = (1 << 0),
   STACK_REPORT  = (1 << 1)
};

enum STACK_ERROR {
   STACK_UnknownErr,
   STACK_MemoryErr,
   STACK_Full,
   STACK_Empty,
   STACK_BadArgument
};
    
#if !defined(True) && !defined(False)
#define True  1
#define False 0
#endif
    
/*************  Type Definitions  *********************/
typedef char *STACK_TYPE;

typedef struct stack {
   unsigned long size;
   unsigned long top;
   STACK_TYPE *array;
   enum STACK_ATTR attr;
} STACK;

/*************  Prototypes   **************************/
typedef void (*STACK_ErrorProc)   _STACK_P((STACK*, int, char*));
typedef void (*STACK_PrintProc)   _STACK_P((int, STACK_TYPE));

/*************  Function Definitions  *****************/
extern STACK*          STACK_Create         _STACK_P((unsigned));
extern void            STACK_Destroy        _STACK_P((STACK*));

extern void            STACK_Push           _STACK_P((STACK*, STACK_TYPE));
extern STACK_TYPE      STACK_Pop            _STACK_P((STACK*));

extern STACK_ErrorProc STACK_SetHandler     _STACK_P((STACK_ErrorProc, char*));
extern void            STACK_DefaultHandler _STACK_P((STACK*, enum STACK_ERROR, char*));

extern void            STACK_Print          _STACK_P((STACK*, STACK_PrintProc));
extern void            STACK_DefaultPrintFn _STACK_P((unsigned, STACK_TYPE));

/************  Macros  *******************************/
#define Create_STACK(size)        STACK_Create(size)
#define Destroy_STACK(s)          STACK_Destroy(s)
#define Clear_STACK(s)            (s->top = 0)
#define Print_STACK(s, fn)        STACK_Print(s, (STACK_PrintProc)fn)
#define Set_STACK_Dynamic(s, val) (s->attr = (enum STACK_ATTR)((val) ? s->attr | STACK_DYNAMIC : s->attr & ~STACK_DYNAMIC))
#define Get_STACK_Dynamic(s)      (s->attr & STACK_Dynamic)
#define Set_STACK_Report(s, val)  (s->attr = (enum STACK_ATTR)((val) ? s->attr | STACK_REPORT  : s->attr & ~STACK_REPORT))
#define Get_STACK_Report(s)       (s->attr >> 1)
#define Get_STACK_Count(s)        (s->top)
#define Get_STACK_Size(s)         (s->size)

/*  Fast Macro Push and Pop for static sized stacks _only_ */
#define PushM(s, d)          (s->array[s->top++] = (STACK_TYPE)d)
#define PopM(s)              (s->array[--s->top])

#ifdef STACK_DEBUG  /*  Debugging ON  */
#define Push(s, d)            STACK_Push(s, (STACK_TYPE)d)
#define Pop(s)                STACK_Pop(s)
#define Set_STACK_Handler(fn) STACK_SetHandler((STACK_ErrorProc)fn, #fn)
#else               /*  Debugging OFF  */
#define Push(s, d)            if (s->top != s->size) PushM(s, d); else STACK_Push(s, (STACK_TYPE)d)
#define Pop(s)                ((s->top != 0) ? PopM(s) : STACK_Pop(s))
#define Set_STACK_Handler(fn) STACK_SetHandler((STACK_ErrorProc)fn, NULL)
#endif

    
#define MultiPush(s, d)      {  STACK_TYPE *stack_type_ptr = (STACK_TYPE*)&d; int stack_type_index;\
				for(stack_type_index = 0;\
				    stack_type_index < (sizeof(d) + sizeof(STACK_TYPE) - 1)/sizeof(STACK_TYPE);\
				    stack_type_index++) {\
				   Push(s, stack_type_ptr[stack_type_index]);\
				}\
			     }
#define MultiPop(s, d)       {  STACK_TYPE *stack_type_ptr = (STACK_TYPE*)&d; int stack_type_index;\
				for(stack_type_index =  ((sizeof(d) + sizeof(STACK_TYPE) - 1)/sizeof(STACK_TYPE)) - 1;\
				    stack_type_index >= 0;\
				    stack_type_index--) {\
				   stack_type_ptr[stack_type_index] = Pop(s);\
				}\
			     }
			           
#define MultiPushM(s, d)     {  STACK_TYPE *stack_type_ptr = (STACK_TYPE*)&d; int stack_type_index;\
				for(stack_type_index = 0;\
				    stack_type_index < (sizeof(d) + sizeof(STACK_TYPE) - 1)/sizeof(STACK_TYPE);\
				    stack_type_index++) {\
				   PushM(s, stack_type_ptr[stack_type_index]);\
				}\
			     }
#define MultiPopM(s, d)      {  STACK_TYPE *stack_type_ptr = (STACK_TYPE*)&d; int stack_type_index;\
				for(stack_type_index =  ((sizeof(d) + sizeof(STACK_TYPE) - 1)/sizeof(STACK_TYPE)) - 1;\
				    stack_type_index >= 0;\
				    stack_type_index--) {\
				   stack_type_ptr[stack_type_index] = PopM(s);\
				}\
			     }
			           
   
#undef _STACK_NO_PROTO
#undef _STACK_P

#ifdef __cplusplus
}
#endif

#endif  /* _STACK_H  */

