function_backtrace_1.0/
/*
 * backtrace.c
 * Function backtracing code (original code by Balloon)
 * ---------------------------------------------------------------------------
 */

#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdarg.h>

#include "include/config.h"
#include "include/player.h"
#include "include/proto.h"

#define MAX_DEBUG_LEN 50
#define MAX_DEPTH 250
#define MAX_MARK_LEN 250

struct FunctionTrack
{
   char File[MAX_DEBUG_LEN];
   int  Line;
   char Function[MAX_DEBUG_LEN];
   char MarkMessage[MAX_MARK_LEN];
   int MarkLine;
};

static int TrackingDepth = -1;
static int ActualDepth   = -1;
static struct FunctionTrack Tracks[MAX_DEPTH];

void EnterFunction(int Line, char *File, char *Function)
{
  if (sys_flags & DONT_TRACE)
    return;

  sys_flags |= DONT_TRACE;

  if (TrackingDepth == -1)
    memset(Tracks, 0, MAX_DEPTH * sizeof(struct FunctionTrack));

  if (TrackingDepth == MAX_DEPTH)
  {
    if (TrackingDepth == ActualDepth++)
      LOGF("error", "Gone deeper than tracking allows!"); 
    sys_flags &= ~DONT_TRACE;
    return;
  }

  TrackingDepth++;
  ActualDepth++;

  strncpy(Tracks[TrackingDepth].File,     File,     MAX_DEBUG_LEN);
  strncpy(Tracks[TrackingDepth].Function, Function, MAX_DEBUG_LEN);
  Tracks[TrackingDepth].Line = Line;
  Tracks[TrackingDepth].MarkMessage[0] = 0;

  sys_flags &= ~DONT_TRACE;
}

void ExitFunction(int Line, char *File, char *Function)
{
  int temp;

  if (sys_flags & DONT_TRACE)
    return;

  sys_flags |= DONT_TRACE;

  if (ActualDepth > TrackingDepth)
  {
    if ((ActualDepth - 1) == TrackingDepth)
      LOGF("error", "Leaving function (too deep)");
    ActualDepth--;
    sys_flags &= ~DONT_TRACE;
    return;
  }

  if (TrackingDepth < 0)
  {
    LOGF("error", "Leaving  : %s : %s : Line %d", File, Function, Line);
    LOGF("error", "Tracking claims not to be in any function!");
    sys_flags &= ~DONT_TRACE;
    return;
  }

  if ((strncmp(File, Tracks[TrackingDepth].File, MAX_DEBUG_LEN)) ||
       (strncmp(Function, Tracks[TrackingDepth].Function, MAX_DEBUG_LEN)))
  {    
    LOGF("error", "Leaving  : %s : %s : Line %d", File, Function, Line);
    LOGF("error", "Not left : %s : %s : Line %d", Tracks[TrackingDepth].Function, Tracks[TrackingDepth].File, Tracks[TrackingDepth].Line);

    temp = TrackingDepth;
    while ((temp > -1) &&
           ((strncmp(File, Tracks[temp].File, MAX_DEBUG_LEN)) ||
           (strncmp(Function, Tracks[temp].Function, MAX_DEBUG_LEN))))
      temp--;

    if (temp > -1)
    {
      LOGF("error","Hopefully recovered tracking.");
      TrackingDepth = temp - 1;
      ActualDepth   = TrackingDepth;
    }
    else
      LOGF("error","Not recovered as yet.");
  }

  Tracks[TrackingDepth].File[0] = 0;
  Tracks[TrackingDepth].Function[0] = 0;
  Tracks[TrackingDepth].Line = 0; 
  Tracks[TrackingDepth].MarkMessage[0] = 0;

  TrackingDepth--;
  ActualDepth--;

  sys_flags &= ~DONT_TRACE;
}

void MarkFunction(int Line, char *File, char *Function, char *Format, ...)
{
  int temp;
  va_list ap;

  if (sys_flags & DONT_TRACE)
    return;

  sys_flags |= DONT_TRACE;

  if (ActualDepth > TrackingDepth)
  {
    LOGF("error", "Marking     : %s : %s : Line %d", File, Function, Line);
    LOGF("error", "Too deep to Mark function.");
    sys_flags &= ~DONT_TRACE;
    return;
  }

  if (TrackingDepth < 0)
  {
    LOGF("error", "Marking     : %s : %s : Line %d", File, Function, Line);
    LOGF("error", "Tracking claims not to be in any function!");
    sys_flags &= ~DONT_TRACE;
    return;
  }

  temp = TrackingDepth;
  if ((strncmp(File, Tracks[TrackingDepth].File, MAX_DEBUG_LEN)) ||
       (strncmp(Function, Tracks[TrackingDepth].Function, MAX_DEBUG_LEN)))
  {    
    LOGF("error", "Marking     : %s : %s : Line %d", File, Function, Line);
    LOGF("error", "Actually in : %s : %s : Line %d", Tracks[TrackingDepth].Function, Tracks[TrackingDepth].File, Tracks[TrackingDepth].Line);

    while ((temp > -1) &&
           ((strncmp(File, Tracks[temp].File, MAX_DEBUG_LEN)) ||
           (strncmp(Function, Tracks[temp].Function, MAX_DEBUG_LEN))))
      temp--;

    if (temp > -1)
      LOGF("error","Hopefully found correct function to mark.");
    else
      LOGF("error","Cant find correct function to mark.");
  }

  if (temp > -1)
  {
    /* It's safe to do the mark. */
    va_start(ap, Format);
    vsnprintf(Tracks[temp].MarkMessage, MAX_MARK_LEN, Format, ap);
    va_end(ap);
    Tracks[temp].MarkMessage[MAX_MARK_LEN - 1] = 0;
    Tracks[temp].MarkLine = Line;
  }
  sys_flags &= ~DONT_TRACE;
}

void DumpTraceInfo(char *logfile)
{
  int temp;

  if (sys_flags & DONT_TRACE)
    return;

  sys_flags |= DONT_TRACE;

  LOGF(logfile, "==== Showing last function calls");
  for (temp = 0; temp <= TrackingDepth; temp++)
  {
    LOGF(logfile, "  %s : %s : Line %d", Tracks[temp].Function, Tracks[temp].File, Tracks[temp].Line);
    if (Tracks[temp].MarkMessage[0])
      LOGF(logfile, "  -- %s : Line %d", Tracks[temp].MarkMessage, Tracks[temp].MarkLine);
  }

  LOGF(logfile, "==== End of function calls");
  sys_flags &= ~DONT_TRACE;
}