/*
    ####             #    #     # #
    #   #            #    #       #          The FreeWare C library for 
    #   #  ##   ###  #  # #     # ###             RISC OS machines
    #   # #  # #     # #  #     # #  #   ___________________________________
    #   # ####  ###  ##   #     # #  #                                      
    #   # #        # # #  #     # #  #    Please refer to the accompanying
    ####   ### ####  #  # ##### # ###    documentation for conditions of use
    ________________________________________________________________________

    File:    Error.h
    Author:  Copyright  1992 Jason Williams
             Philip Colmer: Varargs improvements.
             Julian Smith:  error_PLACE
             Sergio Monesi: error_FIXED, error_global (with some ideas and code from
                            Martin Ebourne)
    Version: 1.60 (06 Jun 1995)
    Purpose: Centralised error reporting, with hopefully useful routines,
             but which YOU (the user) can change if you want something
             different.
             Also, a few useful error-releated macros.
    Mods:    7 Apr 1992 - JCW - Added Error_OutOfMemory
            14 Jun 1993 - PJC - Allowed Error_Report(Fatal) to take
                                variable arguments
            13 Jul 1993 - PJC - Added varargs to "Internal" versions of above
            06 Jun 1995 - JPS - Added error_PLACE
            06 Jun 1995 - SM  - Added error_global and error_FIXED,
            06 Jun 1995 - JPS - made error_global DLL-friendly.
            08 Jul 1995 - JPS - Removed #include of kernel.h
            21 Jul 1995 - SM  - Added error_STATIC
*/

#ifndef __dl_error_h
#define __dl_error_h

#ifdef __cplusplus
extern "C" {
#endif


#ifndef __dl_core_h
#include "Core.h"
#endif



extern void Error_ReportInternal(int errornum, char *report, ...);
/*
This is identical to Error_Report, except it is used for most DeskLib
library internal errors. User code should use Error_Report. This allows
you to modify the treatment of internal errors, without affecting your
own error handling.
*/


extern void Error_ReportFatalInternal(int errornum, char *report, ...);
/*
This does an Error_ReportInternal, and then calls exit()
*/


extern void Error_Report(int errornum, char *report, ...);
/*
This is a centralised user-error reporting function. Call it, citing any
error number you want, and any error string you want. The current
implementation merely invokes Wimp_ReportError, but use it from your
code, as then the method by which you report errors can be altered just
by changing Error.c

The report is a 'printf' style formatting string, optionally followed by
arguments just as in printf commands. This saves you from having to
pre-assemble strings to pass in.

examples:

Error_Report(5, "My VIDC just blew up!");

Error_Report(6, "You can't put the number %d in there!", thenumber);
*/



extern void Error_ReportFatal(int errornum, char *report, ...);
/*
Exactly the same as Error_Report, except after reporting the error, it
terminates the program by calling exit()

Takes variable arguments a la 'printf'. See Error_Report for more info.
*/


extern BOOL Error_Check(os_error *error);
/*
Used to encapsulate an OS call to automatically check for error return.
If the OS call returns an error, then it will be reported, and the
function returns TRUE. Otherwise, no action is taken, and FALSE is
returned
*/


/* Error_CheckFatal --------------------------------------------------------
 * Identical to Error_Check, but calls exit() if an error ocurred
 */
extern void Error_CheckFatal(os_error *error);


extern BOOL Error_OutOfMemory(BOOL fatal, char *place);
/*
Reports a memory error (e.g. "Unable to claim enough memory for
[Messages]"), where you supply just the "place" of the failure
(e.g. in this case, in the "Messages" section)
if "fatal" is TRUE, Error_ReportFatal is used, else Error_Report is used.

This function ALWAYS returns FALSE (== 0 == NULL), so you can use:

if (spritearea == NULL) return( Error_OutOfMemory( FALSE, "icon sprites"));
*/




#define error__SR(x)	error__VL(x)
#define error__VL(x)	#x


#define error_PLACE	"File '" __FILE__ "', line " error__SR( __LINE__) ". "
/*
error_PLACE turns into something like: "File 'c.main', line 67. "

Thus you can use:

if (x<0) Error_Report( 0, error_PLACE "x negative (x=%g)", x);
(Note that there is no comma after error_PLACE.)

- and automatically get the filename and linenumber where the error
occurred: e.g. "File 'c.main', line 67. x negative (x=-3.5)"

It would be nicer to use a macro to #define Error_Report so that
__LINE__ and __FILE__ get inserted automatically, but macros can't cope
with variable length argument lists, as used in Error_Report().

ALl the clever macro stuff is copied from DeskLib:WAssert.h
*/




#ifdef _DeskLib_SDLS
  extern os_error *Error__Ref_global( void);
#endif

#if defined( _DeskLib_SDLS) && !defined( _DeskLib_Error)
  #define error_global (*Error__Ref_global())
#else
  extern os_error error_global;
/*
error_global is a global variable that can be used by any function that
needs to return a custom (os_error *). This should be used if you want
to build the error inside the function itself (using, for example,
sprintf()). You should use error_FIXED if the error is fixed (ie.
hard-coded into the program).

eg:

os_error *Function(...)
{
[...]
if ( (buf=malloc(buflen)) == NULL) {
  error_global.errnum=0x80003;
  sprintf( error_global.errmess,
           "Unable to allocate %d bytes",
           buflen
           );
  return &error_global;
  }
[...]
}

SeeAlso: os_error_fixed;
*/
#endif


#define error_FIXED( id, number, description) \
  const struct {                              \
    int  errnum;                              \
    char errmess[ 1 + sizeof( description)];  \
    }                                         \
  id##_= { number, description};              \
  os_error *id = (os_error *) &id##_
/*
This defines a fixed error message. The result of this macro can be
achieved in the following way:

os_error id_= { number, description};
os_error *id = &id_;

By using this macro however, no space will be lost if 'description' is
less than 252 chars (usually it is just a short string) while the
equivalent os_error definition will allocate all the 252 chars
regardless of the length of 'description'.

The typical use of this macro is to define the 'custom' errors returned
by the user's functions. This definition should be static and should be
placed at top level (ie. not inside a function).

eg:

static error_FIXED( outofmemory, 0x80003, "Not enough memory");

os_error *function(...)
{
[...]
if ( ( buf=malloc( buflen)) == NULL)
return outofmemory;
[...]
}

Inputs:

id          - The name of the error that will be defined. You can
              then use this name as a pointer to the error block
              itself.
number      - The error number.
description - The error message. This should be a constant string

SeeAlso:  error_global;
*/





#define error_STATIC( id, number, description) \
  static const struct {                              \
    int  errnum;                              \
    char errmess[ 1 + sizeof( description)];  \
    }                                         \
  id##_= { number, description};              \
  static os_error *id = (os_error *) &id##_
/*
This defines a fixed (and static) error message. The result of this macro can
be achieved in the following way:

static os_error id_= { number, description};
static os_error *id = &id_;

By using this macro however, no space will be lost if 'description' is
less than 252 chars (usually it is just a short string) while the
equivalent os_error definition will allocate all the 252 chars
regardless of the length of 'description'.

The typical use of this macro is to define the 'custom' errors returned
by the user's functions.
If you need a global definition of the error you should use error_FIXED.

eg:

error_STATIC( outofmemory, 0x80003, "Not enough memory");

os_error *function(...)
{
[...]
if ( ( buf=malloc( buflen)) == NULL)
return outofmemory;
[...]
}

Inputs:

id          - The name of the error that will be defined. You can
              then use this name as a pointer to the error block
              itself.
number      - The error number.
description - The error message. This should be a constant string

SeeAlso:  error_global; error_FIXED;
*/






#ifdef __cplusplus
}
#endif


#endif
