/*
 * Simple C++ exception classes
 * Implementation file
 *
 * $Id: exception.cc,v 1.4 2003/03/13 01:54:31 hsteoh Exp hsteoh $
 */

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "exception.h"


// This is a fatal, irrecoverable error, because there is no guarantee we
// can still throw an exception.
void exception::out_of_memory() {
  fprintf(stderr, "Fatal error: out of memory in exception ctor\n");
  abort();			// fatal: cannot create exception
}

void exception::varinit(char *fmt, va_list args) {
  size_t bufsize, msglen;

  // Initial attempt to format message string
  bufsize = 3*strlen(fmt)/2;		// guesstimate of required length
  msg = new char[bufsize];
  if (!msg) out_of_memory();		// die horribly
  msglen=vsnprintf(msg, bufsize, fmt, args);

  // If we didn't get the complete message, reallocate a buffer that is large
  // enough (vsnprintf() returns the number of chars that would've been written
  // excluding '\0', although it won't write more than bufsize bytes including
  // the '\0'.)
  if (msglen+1 > bufsize) {
    bufsize = msglen+1;
    delete msg;				// reallocate buffer
    msg = new char[bufsize];
    if (!msg) out_of_memory();		// die horribly

    vsnprintf(msg, bufsize, fmt, args);
  }
}

exception::exception(char *error_msg, ...) : is_variable(*error_msg=='@') {
  if (!is_variable) {			// Static exception
    msg = error_msg;
  } else {				// Variable exception
    va_list args;

    va_start(args, error_msg);
    varinit(error_msg+1, args);		// (skip the '@')
    va_end(args);
  }
}

exception::exception(const exception &e) : is_variable(e.is_variable) {
  if (is_variable) {
    msg = new char[strlen(e.msg)+1];
    if (!msg) out_of_memory();		// no memory: die horribly
    strcpy(msg, e.msg);
  } else {
    msg = e.msg;			// static message; just copy pointer
  }
}

exception::~exception() {
  if (is_variable) delete msg;
}

char *exception::message() {
  return msg;
}

