/*
 * libsal/debug/debug_stack.c
 * Functions to handle the function call stack
 * 
 * DESCRIPTION
 * 
 * 	The routines in this file exist to handle the function call
 * 	stack support for debugging.
 * 
 * 	Original Author
 * 	===============
 * 	Stuart Herbert
 * 	Academic Computing Services, University of Sheffield
 */

#include <libsal/license.h>
#include <libsal/debug/internal.h>
#include <libsal/proto.h>
#include <libsal/defines.h>
#include <stdlib.h>

static sal_debug_func_t *pstStack = NULL;

/*
 * !! FIXME:	Future changes to work with Dynamic Data Manager
 * !! DESC:	Once my dynamic data manager is added to libsal
 * !! DESC:	(future mod planned as part of Generic NQS v4,
 * !! DESC:	so it may, or may not, actually happen), it can
 * !! DESC:	provide all of the stack management we require.
 * !! END_FIXME:
 */

void sal_debug_CallStack_Push
(
  const char    * szFile,
  unsigned long   ulLine,
  const char    * szFunction
)
{
  sal_debug_func_t *pstNew;
  
  TEST_ARG(szFile     != NULL, 1);
  TEST_ARG(szFunction != NULL, 3);

  /* allocate memory for the new stack entry.  If we can't, report
   * the error and abort. */
  pstNew = (sal_debug_func_t *) malloc(sizeof(sal_debug_func_t));
  ENSURE_RESOURCE(pstNew != NULL, "memory");
  
  /* initialise the new stack entry */
  pstNew->szFile     = szFile;
  pstNew->ulLine     = ulLine;
  pstNew->szFunction = szFunction;
  
  pstNew->pstNext = pstStack;
  
  /* add the new entry to the top of the stack */
  pstStack = pstNew;
  
  sal_dprintf(szFile, ulLine, SAL_DEBUG_MSG_DEBUGMEDIUM, "Entering function %s\n", szFunction);
}

void sal_debug_CallStack_Pop
(
  const char    *szFile,
  unsigned long  ulLine
)
{
  sal_debug_func_t * pstTop;
  
  /* we can't pop from an empty stack ... */
  ENSURE_DATA(pstStack != NULL, "function call stack");

  /* we take a pointer to the top of the stack */
  pstTop   = pstStack;
  /* adjust the stack to move the next item to the top */
  pstStack = pstStack->pstNext;
  
  sal_dprintf(szFile, ulLine, SAL_DEBUG_MSG_DEBUGMEDIUM, "Exiting function %s\n", pstTop->szFunction);
  /* release the memory used by the item we've popped off */
  free(pstTop);
}

const sal_debug_func_t * sal_debug_CallStack_Peep
(
  const sal_debug_func_t * pstStackMember
)
{
  /* if we have no stack, we can't return an element from it, can we? */
  if (pstStack == NULL)
    return NULL;
  
  /* if we have no pointer into the stack, we return the top of it */
  if (pstStackMember == NULL)
    return pstStack;
  
  /* otherwise, we return the next element on the stack */
  
  /* 
   * !! FIXME:	Runtime type information needed
   * !! DESC:	In a truely type-safe environment, we would use
   * !! DESC:	runtime type information to guarentee that pstStackMember
   * !! DESC:	really does point to a piece of memory of type
   * !! DESC:	sal_debug_func_t, rather than to garbage
   * !! END_FIXME:
   */
  
  return pstStackMember->pstNext;
}
