/*
 *  Baltisot
 *  Copyright (C) 1999-2003 Nicolas "Pixel" Noble
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* $Id: Exceptions.h,v 1.43 2006-10-28 16:42:19 pixel Exp $ */

#ifndef __EXCEPTIONS_H__
#define __EXCEPTIONS_H__

#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <vector>
#include <generic.h>

#if !defined pid_t && !defined _SYS_TYPES_H
typedef int pid_t;
#endif

#ifdef _MSC_VER
#pragma warning (disable:4290)
#endif

class String;
struct ugly_string;

void xfree(unsigned char *&);

//! The Base class, that everybody should use.
/*!
  This base class should be derivated for every single class you create. That
  way, common functions will be overloaded and safe to use (like malloc)12~
*/

class Base {
  public:
      virtual ~Base() {};
    static char * strdup(const char * s);
    static void * malloc(ssize_t s);
    static void * realloc(void * p, size_t s);
    static void * calloc(size_t n, size_t s);
    static int dup(int);
    void * operator new(size_t s);
    void * operator new(size_t s, void * p);
    void operator delete(void * p);
    template <class T>
    static void free(T *& p) {
        unsigned char * t = (unsigned char *) p;
	xfree(t);
	p = 0;
    }
    static int pipe(int * p, int flag = 0);
    static pid_t fork();
    static pid_t wait(int *);
    //! This wrapper will call the xexit function.
    static void exit(int);
    static void printm(int level, const ugly_string &, ...);
    static void printm(int level, const char *, ...);
    static void exception(const String &);
    static void pushcontext(const String &);
    static void popcontext(void);
    static void flushcontext(void);
  private:
    static std::vector<String> context;
};

//! Every exception class should inherit from this one.
/*!
  This generic class should be handled from the main, so that the software
  can exit nicely if an exception is thrown, with a built-in message.
*/
class GeneralException : public Base {
  public:
     //! The constructor has to provide a string describing the exception.
      GeneralException(String);
      GeneralException(const GeneralException &);
      ~GeneralException();
    //! This should only be used by the exception manager in order to display what went wrong.
    const char * GetMsg() const;

  protected:
      GeneralException();
    char * msg;
    static char t[BUFSIZ];
};

char * xstrdup(const char *);
void * xmalloc(size_t) throw (GeneralException);
void * xrealloc(void *, size_t);
int xdup(int) throw (GeneralException);
int xpipe(int *, int = 0) throw (GeneralException);
pid_t xfork() throw (GeneralException);
pid_t xwait(int *) throw (GeneralException);
//! This will simply throw the Exit exception.
void xexit(int) throw (GeneralException);
void xexception(const String &) throw (GeneralException);

class MemoryException : public GeneralException {
  public:
      MemoryException(ssize_t);
};

class TaskNotFound : public GeneralException {
  public:
      TaskNotFound();
};

enum op_t {
  IO_WRITE = 1,
  IO_READ
};

class IOGeneral : public GeneralException {
  public:
      IOGeneral(String);
  protected:
      IOGeneral();
};

class IOException : public IOGeneral {
  public:
      IOException(String, op_t, ssize_t);
};

class IOAgain : public IOGeneral {
  public:
      IOAgain();
};

class TaskSwitch : public GeneralException {
  public:
      TaskSwitch();
};

//! This exception can be thrown anyway, in order to exit nicely the software.
/*!
  My suggestion when using this exception, is to add a special manager, in order to
  handle clean up, in the same manner as the atexit function.
*/
class Exit : public GeneralException {
  public:
      //! The provided code should be the exit code.
      Exit(int code);
    //! Fetches the exit code out of the Exit exception.
    int GetCode();
  private:
    int code;
};


/*!
  The printer class, if it exists, will be used as another way to display
  informations from printm. 
*/

class printer_t : public Base {
  public:
    virtual bool printm(int, const char *, va_list) = 0;
};

extern printer_t * printer;


/*!
  The locker class, if it exists, will be used to produce interlocking
  inside the nested classes when needed. Define it if you're going to build
  a real threaded software with Baltisot.
*/

class locker_t : public Base {
  public:
    virtual void lock() = 0;
    virtual void unlock() = 0;
};

extern locker_t * locker;

#define LOCK if (locker) locker->lock()
#define UNLOCK if (locker) locker->unlock();

#include <BString.h>

#endif