/* panic.c - fatal errors
 *
 ****************************************************************
 * Copyright (C) 1998, 2000 Thomas Lord
 * 
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */



#include "hackerlab/os/unistd.h"
#include "hackerlab/char/str.h"
#include "hackerlab/fmt/cvt.h"
#include "hackerlab/bugs/exception.h"
#include "hackerlab/bugs/panic-exit.h"
#include "hackerlab/bugs/panic.h"
#include "hackerlab/vu/safe.h"

static int raise_exceptions = 0;
struct exception_context the_exception_context[1];


/************************************************************************
 *(h1 "Panic"
 * 	:includes ("hackerlab/bugs/panic.h"))
 * 
 * |panic|
 * |invariant|
 */



/*(c panic)
 * int panic (char const * str);
 * 
 * Print an error message containing `str' on descriptor 2 and exit
 * the process by calling `panic_exit'.
 * 
 * This function uses `write' to print `str'.
 * 
 * This function does not return.
 */
void
panic (char const * str)
{
  if (raise_exceptions)
      Throw (exception(-1, str));
  write (2, "PANIC: ", str_length ("PANIC: "));
  write (2, str, str_length (str));
  write (2, "\n", 1);
  panic_exit ();
}


/*(c panic_msg)
 * int panic_msg (char * str);
 * 
 * Print an error message containing `str' on descriptor 2.
 * 
 * This function uses `write' to print `str'.
 * 
 * This function *does* return.
 */
void
panic_msg (char * str)
{
  write (2, "PANIC MESSAGE: ", str_length ("PANIC MESSAGE: "));
  write (2, str, str_length (str));
  write (2, "\n", 1);
}




/*(c invariant :category macro)
 * void invariant(CONDITION);
 * 
 * Defined as:
 * 
 *   #define invariant(X) invariant_test(X, #X, __FILE__, __LINE__)
 * 
 * 
 * If `CONDITION' evaluates to 0, write a message to the standard
 * error output (descriptor 2) and exit by calling `panic_exit'.
 * See xref:"panic".
 */



/*(c invariant_test)
 * void invariant_test (int condition, char * str, char * file, int line);
 * 
 * If `condition' is 0, write a message to stderr (fd 2) and exit.
 * See xref:"invariant".
 */
void
invariant_test (int condition, char * str, char * file, int line)
{
  char buffer[2 + sizeof (long) * 3];

# define botched "botched invariant\n    "

  if (condition)
    return;
  cvt_long_to_decimal (buffer, line);
  write (2, file, str_length (file));
  write (2, ":", 1);
  write (2, buffer, str_length (buffer));
  write (2, ":", 1);
  write (2, botched, str_length (botched));
  write (2, str, str_length (str));
  write (2, "\n", 1);
  while (1)
    panic ("exiting on botched invariant");
}

/**
 * \brief assert two strings are identical
 */
void
invariant_str_cmp_4(t_uchar const *left, t_uchar const *right, char const * file, int const line)
{
    if (str_cmp (left, right))
      {
	safe_printfmt (2, "assertion failed: '%s' != '%s' %s:%d\n", left, right, file,line);
        panic("assertion failed\n");
      }
}

/**
 * \brief assert two ints are identical
 */
void
invariant_int_cmp_4(int const left, int const right, char const * file, int const line)
{
    if (left != right)
      {
	safe_printfmt (2, "assertion failed: '%d' != '%d' %s:%d\n", left, right, file,line);
        panic("assertion failed\n");
      }
}

void 
panic_should_throw (int yes)
{
    raise_exceptions=yes;
}


syntax highlighted by Code2HTML, v. 0.9.1