/*
 * Simple C++ exception classes
 * Header file
 *
 * $Id: exception.h,v 1.4 2003/03/13 02:34:40 hsteoh Exp hsteoh $
 * ---------------------------------------------------------------------------
 * USAGE NOTES
 *
 * These classes are intended to be used in a similar way to prog/lib's
 * error.h typedefs. Except that since we can use C++ classes, we have more
 * flexibility here.
 *
 *
 * CONVENTIONS
 *
 * Especially for library subsystems, each subsystem ought to derive their
 * own exception class and use that to throw exceptions. This will allow
 * applications to implement simple exception locus detection by catching
 * the appropriate base class.
 */

#ifndef EXCEPTION_H
#define EXCEPTION_H

#include <stdarg.h>


// USAGE NOTES:
// - there are two subtypes of exceptions: one based on a static string, and
//   the other based on a dynamic (variable) string.
// - static exceptions should pass only a single argument, the error message.
// - variable exceptions must have '@' as their first character; the char*
//   argument is then treated as a printf format string, with optional
//   arguments that follow.
// - WARNING: variable exceptions keeps an internal pointer to a formatted
//   string buffer which is dynamically allocated. For this reason, variable
//   exceptions should NOT be used for critical exceptions like out of memory
//   errors, where there is no guarantee the ctor won't fail.
class exception {
  int is_variable;
  char *msg;

  void out_of_memory();			// does not return
  void varinit(char *msg, va_list args);
protected:
  // NOTE: the dummy argument is a dirty, cruel hack necessary because the
  // stdarg in glibc defines va_list as char*, and the bogonous C++ compiler
  // (g++) does not know how to find a next-better ctor match when this one
  // is protected. It's not my fault! Derived exception classes will just
  // have to cope.
  exception(int dummy, char *error_msg, va_list args) :
	is_variable(*error_msg=='@') {
    if (is_variable)
      varinit(error_msg+1, args);
    else
      msg=error_msg;
  }
public:
  exception(char *error_msg, ...);
  exception(const exception &e);
  virtual ~exception();

  virtual char *message();
};


#endif // EXCEPTION_H
