/* error.c: communication of informational, warning, error and 
 * fatal error messages for the xrml library. */

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

#include "error.H"
#include "xrmlP.H"

namespace xrml {

/* default callback for showing error messages */
void printmsg(char *message)
{
  fprintf(stderr, "%s.\n", message);
}

MSG_CALLBACK_FUNC info_callback_func = NULL,
                        warning_callback_func = printmsg,
                        error_callback_func = printmsg,
                        fatal_callback_func = printmsg;

/* The SetCallback functions return the previously set callback function */
MSG_CALLBACK_FUNC SetInfoCallback(MSG_CALLBACK_FUNC func)
{
  MSG_CALLBACK_FUNC old_func = info_callback_func;
  info_callback_func = func;
  return old_func;
}

MSG_CALLBACK_FUNC SetWarningCallback(MSG_CALLBACK_FUNC func)
{
  MSG_CALLBACK_FUNC old_func = warning_callback_func;
  warning_callback_func = func;
  return old_func;
}

MSG_CALLBACK_FUNC SetErrorCallback(MSG_CALLBACK_FUNC func)
{
  MSG_CALLBACK_FUNC old_func = error_callback_func;
  error_callback_func = func;
  return old_func;
}

MSG_CALLBACK_FUNC SetFatalCallback(MSG_CALLBACK_FUNC func)
{
  MSG_CALLBACK_FUNC old_func = fatal_callback_func;
  fatal_callback_func = func;
  return old_func;
}

/* prints an informational message */
void Info(char *routine, char *text, ...)
{
  va_list pvar;
  static char buf[MAX_MESSAGE_LENGTH], *p;
  int n;

  p = buf;
  if (current_linenr > 0) {
    sprintf(p, "%s:%d: %n", current_filename, current_linenr, &n);
    p += n;
  }

  if (routine) {
    sprintf(p, "%s(): %n", routine, &n);
    p += n;
  }
  
  va_start(pvar, text);
  vsprintf(p, text, pvar);
  va_end(pvar);

  if (info_callback_func)
    info_callback_func(buf);
}

/* prints a warning message */
void Warning(char *routine, char *text, ...)
{
  va_list pvar;
  char buf[MAX_MESSAGE_LENGTH], *p;
  int n;

  p = buf;
  if (current_linenr > 0) {
    sprintf(p, "%s:%d: %n", current_filename, current_linenr, &n);
    p += n;
  }

  if (routine) {
    sprintf(p, "%s(): %n", routine, &n);
    p += n;
  }

  sprintf(p, "warning: %n", &n);
  p += n;
  
  va_start(pvar, text);
  vsprintf(p, text, pvar);
  va_end(pvar);
  
  if (warning_callback_func)
    warning_callback_func(buf);
}

/* prints an error message */
void Error(char *routine, char *text, ...)
{
  va_list pvar;
  char buf[MAX_MESSAGE_LENGTH], *p;
  int n;

  p = buf;
  if (current_linenr > 0) {
    sprintf(p, "%s:%d: %n", current_filename, current_linenr, &n);
    p += n;
  }

  if (routine) {
    sprintf(p, "%s(): %n", routine, &n);
    p += n;
  }

  sprintf(p, "error: %n", &n);
  p += n;
  
  va_start(pvar, text);
  vsprintf(p, text, pvar);
  va_end(pvar);
  
  if (error_callback_func)
    error_callback_func(buf);
}

/* prints a fatal error message */
void Fatal(int errcode, char *routine, char *text, ...)
{
  va_list pvar;
  char buf[MAX_MESSAGE_LENGTH], *p;
  int n;

  p = buf;
  if (current_linenr > 0) {
    sprintf(p, "%s:%d: %n", current_filename, current_linenr, &n);
    p += n;
  }

  if (routine) {
    sprintf(p, "%s(): %n", routine, &n);
    p += n;
  }

  sprintf(p, "fatal error: %n", &n);
  p += n;

  va_start(pvar, text);
  vsprintf(p, text, pvar);
  va_end(pvar);
  
  if (fatal_callback_func)
    fatal_callback_func(buf);
  exit(errcode);
}

} // namespace xrml

