/*@z27.c:Debug Service:Debug flags@*******************************************/
/*                                                                           */
/*  THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.42)                       */
/*  COPYRIGHT (C) 1991, 2008 Jeffrey H. Kingston                             */
/*                                                                           */
/*  Jeffrey H. Kingston (jeff@it.usyd.edu.au)                                */
/*  School of Information Technologies                                       */
/*  The University of Sydney 2006                                            */
/*  AUSTRALIA                                                                */
/*                                                                           */
/*  This program is free software; you can redistribute it and/or modify     */
/*  it under the terms of the GNU General Public License as published by     */
/*  the Free Software Foundation; either Version 3, or (at your option)      */
/*  any later version.                                                       */
/*                                                                           */
/*  This program is distributed in the hope that it will be useful,          */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
/*  GNU General Public License for more details.                             */
/*                                                                           */
/*  You should have received a copy of the GNU General Public License        */
/*  along with this program; if not, write to the Free Software              */
/*  Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA   */
/*                                                                           */
/*  FILE:         z27.c                                                      */
/*  MODULE:       Debug Service                                              */
/*  EXTERNS:      dbg[], DebugInit(), Debug()                                */
/*                ProfileOn(), ProfileOff(), ProfilePrint()                  */
/*                                                                           */
/*****************************************************************************/
#include "externs.h"

#if DEBUG_ON
struct dbs  dbg[] = {
    {"zz",    {0, 0, 0}},		/* - unused -                */
    {"sp",    {0, 0, 0}},		/* Supervise                 */
    {"la",    {0, 0, 0}},		/* Lexical Analyser          */
    {"fs",    {0, 0, 0}},		/* File Service              */
    {"ts",    {0, 0, 0}},		/* Token Service             */
    {"rd",    {0, 0, 0}},		/* Read Definitions          */
    {"op",    {0, 0, 0}},		/* Object Parser             */
    {"os",    {0, 0, 0}},		/* Object Service            */
    {"om",    {0, 0, 0}},		/* Object Manifest           */
    {"ce",    {0, 0, 0}},		/* Closure Expansion         */
    {"cr",    {0, 0, 0}},		/* Cross References          */
    {"ss",    {0, 0, 0}},		/* Style Service             */
    {"sf",    {0, 0, 0}},		/* Size Finder               */
    {"ob",    {0, 0, 0}},		/* Object Breaking           */
    {"of",    {0, 0, 0}},		/* Object Filling            */
    {"sc",    {0, 0, 0}},		/* Size Constraints          */
    {"sa",    {0, 0, 0}},		/* Size Adjustments          */
    {"gw",    {0, 0, 0}},		/* Gap Widths                */
    {"gt",    {0, 0, 0}},		/* Galley Transfer           */
    {"ga",    {0, 0, 0}},		/* Galley Attaching          */
    {"gf",    {0, 0, 0}},		/* Galley Flusher            */
    {"gm",    {0, 0, 0}},		/* Galley Maker              */
    {"gs",    {0, 0, 0}},		/* Galley Service            */
    {"gp",    {0, 0, 0}},		/* Galley Printer            */
    {"ps",    {0, 0, 0}},		/* Print Service             */
    {"oe",    {0, 0, 0}},		/* Object Echo               */
    {"es",    {0, 0, 0}},		/* Echo Service              */
    {"zz",    {0, 0, 0}},		/* Debug Service (unused)    */
    {"yy",    {0, 0, 0}},		/* Error Service             */
    {"st",    {0, 0, 0}},		/* Symbol Table              */
    {"su",    {0, 0, 0}},		/* Symbol Uses               */
    {"ma",    {0, 0, 0}},		/* Memory Allocator          */
    {"cs",    {0, 0, 0}},		/* Counter Service           */
    {"bs",    {0, 0, 0}},		/* Database Service          */
    {"rs",    {0, 0, 0}},		/* Rotation Service          */
    {"tk",    {0, 0, 0}},		/* Time Keeper               */
    {"hy",    {0, 0, 0}},		/* Hyphenation               */
    {"ft",    {0, 0, 0}},		/* Font Tables               */
    {"cm",    {0, 0, 0}},		/* Character Mappings        */
    {"sh",    {0, 0, 0}},		/* String Handler            */
    {"fh",    {0, 0, 0}},		/* Filter Handler            */
    {"io",    {0, 0, 0}},		/* Object Input-Output       */
    {"co",    {0, 0, 0}},		/* Colour Service            */
    {"ls",    {0, 0, 0}},		/* Language Service          */
    {"vh",    {0, 0, 0}},		/* Vertical Hyphenation      */
    {"ex",    {0, 0, 0}},		/* External Sort             */
    {"og",    {0, 0, 0}},		/* Optimal Galleys           */
    {"et",    {0, 0, 0}},		/* Environment Table         */
    {"pd",    {0, 0, 0}},		/* PDF Back End (old)        */
    {"po",    {0, 0, 0}},		/* PostScript Back End       */
    {"pf",    {0, 0, 0}},		/* PDF Back End              */
    {"pt",    {0, 0, 0}},		/* Plain Text Back End       */
    {"tx",    {0, 0, 0}},		/* Texture Service           */
    {"pp",    {0, 0, 0}},		/* Profiling                 */
    {"",      {0, 0, 0}},		/* any                       */
};

/*@::DebugInit(), Debug()@****************************************************/
/*                                                                           */
/*  DebugInit(str)                                                           */
/*                                                                           */
/*  Turn on the debug flag given by str.                                     */
/*                                                                           */
/*****************************************************************************/

void DebugInit(FULL_CHAR *str)
{ int j, urg;
  for( urg = 0;  urg < 2 && str[urg+2] == CH_FLAG_DEBUG;  urg++ );
  if( StringEqual(AsciiToFull("al"), &str[urg+2]) )
  { for( j = 1; !StringEqual(AsciiToFull(dbg[j].flag), STR_EMPTY); j++ )
    { for( urg = 0; urg < 3; urg++ ) dbg[j].on[urg] = dbg[ANY].on[urg] = TRUE;
    }
    return;
  }
  for( j = 1;  ;  j++ )
  { if( StringEqual(AsciiToFull(dbg[j].flag), &str[urg+2]) )  break;
    if( StringEqual(AsciiToFull(dbg[j].flag), STR_EMPTY) )
      Error(27, 1, "unknown debug flag %s", FATAL, no_fpos, str);
  }
  for( ;  urg >= 0;  urg-- )  dbg[j].on[urg] = dbg[ANY].on[urg] = TRUE;
} /* end DebugInit */


/*****************************************************************************/
/*                                                                           */
/*  Debug(category, urgency, str, ...)                                       */
/*                                                                           */
/*  Print str on debug output, if the flag corresponding to the given        */
/*  debug category and urgency is on.                                        */
/*                                                                           */
/*****************************************************************************/

void Debug(int category, int urgency, char *str, ...)
{ static BOOLEAN first_message = TRUE;
  va_list ap;
  if( first_message )
  {
    fprintf(stderr, "%s", STR_NEWLINE);
    fprintf(stderr, "Lout Debug Output:");
    fprintf(stderr, "%s", STR_NEWLINE);
    first_message = FALSE;
  }
  fprintf(stderr, "%2s: ", dbg[category].flag);
  va_start(ap, str);
  vfprintf(stderr, str, ap);
  va_end(ap);
  fprintf(stderr, "%s", STR_NEWLINE);
  fflush(stderr);
} /* end Debug */


/*@::ProfileOn(), ProfileOff(), ProfilePrint()@*******************************/
/*                                                                           */
/*  ProfileOn(str)                                                           */
/*                                                                           */
/*  Start profiling label str.                                               */
/*                                                                           */
/*****************************************************************************/
#define MAXPROF	20
#include <time.h>

struct profrec
{ char *label;			/* label of the profile              */
  int calls;			/* number of calls with this label   */
  long time;			/* total time of this label          */
};

static struct profrec profstack[MAXPROF];
static struct profrec profstore[MAXPROF];
static int proftop = 0, profsize = 0;

void ProfileOn(char *str)
{ int i;  time_t raw_time;
  for( i = 0;  i < proftop;  i++ )
  { if( strcmp(profstack[i].label, str) == 0 )
    { for( i = 0;  i < proftop;  i++ )
      {
	fprintf(stderr, "profstack[%d] = %s", i, profstack[i].label);
	fprintf(stderr, "%s", STR_NEWLINE);
      }
      assert1(FALSE, "ProfileOn: restarted", str);
    }
  }
  assert(proftop < MAXPROF, "ProfileOn: overflow");
  time(&raw_time);  profstack[proftop].label = str;
  profstack[proftop++].time  = raw_time;
} /* end ProfileOn */


/*****************************************************************************/
/*                                                                           */
/*  ProfileOff(str)                                                          */
/*                                                                           */
/*  Stop profiling label str.                                                */
/*                                                                           */
/*****************************************************************************/

void ProfileOff(char *str)
{ int i;  time_t raw_time;
  assert1(proftop > 0 && strcmp(profstack[proftop-1].label, str) == 0,
    "ProfileOff: not current", str);
  for( i = 0;  i < profsize && strcmp(profstore[i].label, str) != 0; i++ );
  if( i >= profsize )
  { profsize++;
    assert(profsize < MAXPROF, "ProfileOff: overflow");
    profstore[i].label = str;
    profstore[i].calls = 0;
    profstore[i].time  = 0;
  }
  time(&raw_time);  profstore[i].calls += 1;
  profstore[i].time  += (raw_time - profstack[--proftop].time);
} /* end ProfileOff */


/*****************************************************************************/
/*                                                                           */
/*  ProfilePrint()                                                           */
/*                                                                           */
/*  Print results of profiling.                                              */
/*                                                                           */
/*****************************************************************************/

void ProfilePrint(void)
{ int i;
  for( i = 0;  i < profsize;  i++ )
  { fprintf(stderr, "Profile %-20s  %6ld secs, %3d calls, %6.2f secs/call",
	profstore[i].label, profstore[i].time, profstore[i].calls,
	(float) profstore[i].time / profstore[i].calls );
    fprintf(stderr, "%s", STR_NEWLINE);
  }
} /* end ProfilePrint */
#endif
