/*
    ####             #    #     # #
    #   #            #    #       #          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:  Desk_error_PLACE
             Sergio Monesi: Desk_error_FIXED, Desk_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 Desk_Error_OutOfMemory
            14 Jun 1993 - PJC - Allowed Desk_Error_Report(Fatal) to take
                                variable arguments
            13 Jul 1993 - PJC - Added varargs to "Internal" versions of above
            06 Jun 1995 - JPS - Added Desk_error_PLACE
            06 Jun 1995 - SM  - Added Desk_error_global and Desk_error_FIXED,
            06 Jun 1995 - JPS - made Desk_error_global DLL-friendly.
            08 Jul 1995 - JPS - Removed #include of kernel.h
            21 Jul 1995 - SM  - Added Desk_error_STATIC
*/

#ifndef __Desk_Error_h
#define __Desk_Error_h

#ifdef __cplusplus
	extern "C" {
#endif


#ifndef __Desk_Core_h
	#include "Desk.Core.h"
#endif



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


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


extern void Desk_Error_Report(int errornum, const 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 Desk_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:

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

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



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

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


extern Desk_bool Desk_Error_Check( const Desk_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 Desk_bool_TRUE. Otherwise, no action is taken, and Desk_bool_FALSE is
returned
*/


/* Desk_Error_CheckFatal --------------------------------------------------------
 * Identical to Desk_Error_Check, but calls exit() if an error ocurred
 */
extern void Desk_Error_CheckFatal( const Desk_os_error *error);


extern Desk_bool Desk_Error_OutOfMemory(Desk_bool fatal, const 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 Desk_bool_TRUE, Desk_Error_ReportFatal is used, else Desk_Error_Report is used.

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

if (spritearea == NULL) return( Desk_Error_OutOfMemory( Desk_bool_FALSE, "icon sprites"));
*/




#define Desk_error__SR(x)	Desk_error__VL(x)
#define Desk_error__VL(x)	#x


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

Thus you can use:

if (x<0) Desk_Error_Report( 0, Desk_error_PLACE "x negative (x=%g)", x);
(Note that there is no comma after Desk_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 Desk_Error_Report so that
__LINE__ and __FILE__ get inserted automatically, but macros can't cope
with variable length argument lists, as used in Desk_Error_Report().

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




#ifdef Desk__using_SDLS
  extern Desk_os_error *Desk_Error__Ref_global( void);
#endif

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

eg:

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

SeeAlso: Desk_os_error_fixed;
*/
#endif


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

Desk_os_error Desk_id_= { number, description};
Desk_os_error *id = &Desk_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 Desk_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 Desk_error_FIXED( outofmemory, 0x80003, "Not enough memory");

Desk_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:  Desk_error_global;
*/





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

static Desk_os_error Desk_id_= { number, description};
static Desk_os_error *id = &Desk_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 Desk_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 Desk_error_FIXED.

eg:

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

Desk_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:  Desk_error_global; Desk_error_FIXED;
*/






#ifdef __cplusplus
}
#endif


#endif
