/* Mayan Moudgill July 1994
   Induprakas Kodukula Jun 1995
 */

#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "stdarg.h"
#include "errno.h"
#include "unistd.h"
#include <sys/errno.h>
#include <sys/time.h>

extern void *sbrk(int);
#if !(defined(__sparc__) && defined(__svr4__))
extern int gettimeofday(struct timeval *Tp, struct timezone *Tzp);
#endif

/*#include "cstring.h"*/

#include "assert.h"
static FILE * logFile = stderr;
static FILE * statFile = stderr;

void
error(char * fmt, ...)
{
  va_list	args;

  va_start(args, fmt);
  fprintf(stderr, "ERROR: ");
  vfprintf(stderr, fmt, args);
  va_end(args);
  fputc('\n', stderr);
  if( logFile ) {
    va_start(args, fmt);
    fprintf(logFile, "ERROR: ");
    vfprintf(logFile, fmt, args);
    va_end(args);
    fputc('\n', logFile);
    fflush(logFile);
  }
  abort();
}

void
warn(char * fmt, ...)
{
  va_list	args;

  va_start(args, fmt);
  fprintf(stderr, "WARNING: ");
  vfprintf(stderr, fmt, args);
  va_end(args);
  fputc( '\n', stderr);

  if( logFile ) {
    va_start(args, fmt);
    fprintf(logFile, "WARNING: ");
    vfprintf(logFile, fmt, args);
    va_end(args);
    fputc( '\n', logFile);
    fflush(logFile);
  }
}

void
monitor(char * file, int line, char * fmt, ...)
{
  va_list	args;

  va_start(args, fmt);
  fprintf(stderr, "MONITOR %s %d: ", file, line);
  vfprintf(stderr, fmt, args);
  va_end(args);
  fputc( '\n', stderr);
  if( logFile ) {
    va_start(args, fmt);
    fprintf(logFile, "MONITOR %s %d: ", file, line);
    vfprintf(logFile, fmt, args);
    va_end(args);
    fputc( '\n', logFile);
    fflush(logFile);
  }
}

struct timeval	func_timer;
struct timeval	elapse_timer;
struct timeval	curr_timer;
static struct timezone ignored_timezone;

void
reset_func_timer(void)
{
  int	f;
  f = gettimeofday(&func_timer, &ignored_timezone);

  if( f != 0) {
    warn( "gettimeofday func_timer failed: %d\n", errno);
  }
}

double
get_func_timer(void)
{
  double		secs;
  int			f;

  f = gettimeofday(&curr_timer, &ignored_timezone);
  if( f != 0) {
    warn( "gettimeofday curr_timer failed: %d\n", errno);
  }

  secs = (curr_timer.tv_sec+1.0e-6*curr_timer.tv_usec)-
	  (func_timer.tv_sec+1.0e-6*func_timer.tv_usec);
  assert( secs >= 0.0);
  return secs;
}

void
reset_elapse_timer(void)
{
  int	f;

  f = gettimeofday(&elapse_timer,&ignored_timezone);
  if( f != 0) {
    warn( "gettimeofday elapse_timer failed: %d\n", errno);
  }
}

double
get_elapse_timer(void)
{
  double		secs;
  int			f;
  
  f = gettimeofday(&curr_timer,&ignored_timezone);
  if( f != 0) {
    warn( "gettimeofday curr_timer failed: %d\n", errno);
  }

  secs = (curr_timer.tv_sec+1.0e-6*curr_timer.tv_usec)-
	  (elapse_timer.tv_sec+1.0e-6*elapse_timer.tv_usec);
  assert( secs >= 0.0);
  return secs;
}

void
phase(char * fmt, ...)
{
  va_list	args;
  double	et = get_elapse_timer();
  double	ft = get_func_timer();
  void *	brk = (void *) sbrk(0);
  reset_elapse_timer();

  fprintf(stderr, "elapsed time %12.4f sec\ttotal time %12.4f sec brk = %p\n", et, ft, brk);
  va_start(args, fmt);
  fprintf(stderr, "PHASE: ");
  vfprintf(stderr, fmt, args);
  va_end(args);
  fputc( '\n', stderr);

  if( logFile ) {
    fprintf(logFile, "elapsed time %12.4f sec\ttotal time %12.4f sec brk = %p\n",et,ft, brk);
    va_start(args, fmt);
    fprintf(logFile, "PHASE: ");
    vfprintf(logFile, fmt, args);
    va_end(args);
    fputc( '\n', logFile);
    fflush(logFile);
  }
}

void
record(char * fmt, ...)
{
  va_list	args;

  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
  va_end(args);

  if( logFile ) {
    va_start(args, fmt);
    vfprintf(logFile, fmt, args);
    va_end(args);
    fflush(logFile);
  }
}

void
vrecord(const char * fmt, va_list args)
{
  vfprintf(stderr, fmt, args);

  if( logFile ) {
    vfprintf(logFile, fmt, args);
    fflush(logFile);
  }
}

#if 0
char *
get_grapher_name()
{
  char *path_name = getenv("VGRAPH");
 
  if (path_name == 0) { /* User better have it in his path */
    return make_cstring ("xvcg");
  }
  else 
    return make_cstring (path_name);
}

char *
get_temp_file()
{
  return tmpnam((char *)NULL);
}

#define XCALL_STACK_DEPTH	16384

struct xcall_stack_cell {
  int		line;
  cstring	file;
};

static struct xcall_stack_cell xcall_stack[XCALL_STACK_DEPTH];
static int		xcall_stack_depth = 0;

#define xcall_stack_line(i)	(xcall_stack[bounds(i,XCALL_STACK_DEPTH)].line)
#define xcall_stack_file(i)	(xcall_stack[bounds(i,XCALL_STACK_DEPTH)].file)

void
simple_push_call_stack(char * file, int line)
{
  if( xcall_stack_depth < XCALL_STACK_DEPTH ) {
    xcall_stack_file(xcall_stack_depth) = make_cstring(file);
    xcall_stack_line(xcall_stack_depth) = line;
  }
  xcall_stack_depth++;
  return;
}

void
pop_call_stack(void)
{
  xcall_stack_depth--;
  assert( xcall_stack_depth >= 0);
}

void
dump_call_stack(void)
{
  int	i;

  fprintf(stderr, "CALL STACK:\n");
  if( xcall_stack_depth > XCALL_STACK_DEPTH ) {
    fprintf(stderr, "    ignoring %d calls that overflowed stack\n",
	xcall_stack_depth - XCALL_STACK_DEPTH);
    i = XCALL_STACK_DEPTH-1;
  }
  else {
    i = xcall_stack_depth-1;
  }
  for( ; i >= 0; i-- ) {
    fprintf(stderr, "  %s:%d\n", xcall_stack_file(i), xcall_stack_line(i));
  }

  if( logFile ) {
    fprintf(logFile, "CALL STACK:\n");
    if( xcall_stack_depth > XCALL_STACK_DEPTH ) {
      fprintf(logFile, "    ignoring %d calls that overflowed stack\n",
	  xcall_stack_depth - XCALL_STACK_DEPTH);
      i = XCALL_STACK_DEPTH-1;
    }
    else {
      i = xcall_stack_depth-1;
    }
    for( ; i >= 0; i-- ) {
      fprintf(logFile, "  %s:%d\n", xcall_stack_file(i), xcall_stack_line(i));
    }
  }
}

#endif

void
record_stat(char * fmt, ...)
{
  va_list	args;

  va_start(args, fmt);
  vrecord(fmt, args);
  va_end(args);
  record("\n");

  if( statFile ) {
    va_start(args, fmt);
    vfprintf(statFile, fmt, args);
    va_end(args);
    fflush(statFile);
  }
}
