/***************************************
  $Revision: 1.20 $

  Error reporting (er) erroutines.h  - header file for error reporting.

  Status: NOT REVUED, TESTED, 

  Design and implementation by: Marek Bukowy

  ******************/ /******************
  Copyright (c) 1999                              RIPE NCC
 
  All Rights Reserved
  
  Permission to use, copy, modify, and distribute this software and its
  documentation for any purpose and without fee is hereby granted,
  provided that the above copyright notice appear in all copies and that
  both that copyright notice and this permission notice appear in
  supporting documentation, and that the name of the author not be
  used in advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.
  
  THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  ***************************************/

#ifndef ER_H
#define ER_H


typedef unsigned int er_mask_t;
typedef int er_ret_t;

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <stdarg.h>
#include <strings.h>

#include <sys/param.h>
#include <glib.h>
#include <pthread.h>

#include <bitmask.h>
#include <stubs.h>

#include "thread.h"

#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif

#ifdef ER_IMPL
#define EXTDEF
#define EXTINI(a,b) a = b;
#else
#define EXTDEF extern 
#define EXTINI(a,b) extern a;
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
  ER_PATH_SOCK,   /* unbuffered file/socket access via a file descriptor */
  ER_PATH_BUFPTR,   /* buffered   file access via a FILE structure  */
  ER_PATH_NAME,     /* buffered   file access via a file name 
                       (file reopened for every message) */
  ER_PATH_EXEC,     /* message constructed, send to stdin of the command
		       at the end or after one message depending on options */
  ER_PATH_SYSLOG,   /* syslog msg sent at every message */
  ER_PATH_CIRC
} er_path_mt;

EXTDEF char *er_pathtypes[]
#ifdef ER_IMPL
  = {
  "SOCK",           /* MUST BE IN SYNC WITH THE ABOVE */
  "BUFPTR",
  "NAME",
  "EXEC",
  "SYSLOG",
  "CIRC",
  NULL
  }
#endif
;

typedef union {
    struct {
      int    fd;                /* int filedescr */
    } sock;
    struct {
      FILE  *fp;                /* FILE* fp for FILEBUFPTR */
    } bufptr;
    struct {
      char  filename[80];       /* filename for FILEBUFNAM */
      int   date;               /* 'DATE' option - construct a filename */
    } name;
    struct {
      int usepath;
      char **argv;              /* parameters for exec - XXX DYNAMIC!!!! */
    } exec;
    struct {
      int facility;             /* openlog(3) parameters for SYSLOG */
      int logopt;
      char ident[32];
    } syslog;
} er_path_descr_t;

typedef struct {
  char              name[32];
  char              active;
  int               format;
  pthread_mutex_t   mutex;
  er_path_mt        type;  
  er_path_descr_t   descr;
  GList            *filters;
} er_path_t;

typedef struct {
  mask_t fac_mask;
  er_mask_t asp_mask;
  int    sev_min;
  int    sev_max;
  pthread_t thr_id;
/*  unsigned err;     -- a specific error code - or 0 to mean all errors */
} er_filter_t;

typedef struct {
  char errtxt[1024];
  int  errpos;
  char *token;
  er_path_t path;
  er_filter_t curfilt;
  int sock;
} lexerr_t;



#define MNELEN 16
typedef struct {
   er_ret_t	code;
   char		mnem[MNELEN];
   char		text[80];
} er_list_t;


typedef struct {
   er_ret_t	code;
   char		name[4];
   char 	desc[80];
   er_list_t   *errs;
} er_fac_t;


#define ER_SEV_F 0x20000000	/*+ fatal error +*/
#define ER_SEV_E 0x10000000	/*+ error +*/
#define ER_SEV_W 0x08000000	/*+ warning +*/
#define ER_SEV_I 0x04000000	/*+ information +*/
#define ER_SEV_D 0x02000000	/*+ debug message +*/
#define ER_SEV_L 0x01000000	/*+ library error +*/


/*  macro to see if the code is OK -- masks out the facility and compares,
    assuming all OK codes within the facilities are 0
*/



#define ER_SEV_TXT 20

#define ER_MSGLEN 384
#define ER_ERRLEN 2048

typedef struct {
    int 	sev;
    char 	chr[2];
    char 	txt[ER_SEV_TXT];
} er_level_t;

#define DEFFAC(a,b) { FAC_##a, #a, b, a##_mod_err }
#define ER_LASTTXT {-1}	/* macro for use in error text arrays */
#define ERDUP(a) a, #a      
#include "er_facilities.h"
/* the macro expects two arguments:
	 capital letters symbol of the facility
	 short (<80 chars) description
   which then are expanded, eg. DEFFAC(TT, "test facility") expands to:
  { FAC_TT , "TT",   "test facility" ,  NULL} ,
  Therefore, the FAC_TT must be defined in the enum below.
  The  er_fac_code_t enum   must begin with FAC_NONE=0 
			and must end   with FAC_LAST.
  The  er_fac_err array    must end   with FAC_NONE.

  The user code must contain INITFAC(a) call early in the code that
  sets the pointer to the respective ??_mod_err array. There is nothing
  wrong in calling it twice, so don't hesitate if you must do it.
 
  After a facility number changes (eg. because another one was added or
  deleted before yours) ALL your code must be recompiled before linking. 
*/


#include "er_aspects.h"
#include "er_formats.h"

#ifndef ER_IMPL /* for client modules */
extern er_level_t er_level_a[];
#else /* full definition */
er_level_t er_level_a[] = {
  { ER_SEV_F,   "F" , "fatal error" },
  { ER_SEV_E, 	"E" , "error" },
  { ER_SEV_W, 	"W" , "warning" },
  { ER_SEV_I,	"I" , "information" },
  { ER_SEV_D, 	"D" , "debug msg" },
  { ER_SEV_L, 	"L" , "library err" },
  { 0,          "-" , "BUG! no such sev 0" }
};
#endif /* ER_IMPL */


/*************************************************************************/

EXTINI(GList  *er_pathlist , NULL)
EXTDEF er_mask_t        er_asparray[FAC_LAST];
EXTDEF rw_lock_t   er_paths_lock;
EXTINI(GHashTable *er_macro_hash, NULL)

#ifdef ER_IMPL

/* global vars !!!!! must be set for reporting purposes. 
   Must be initialised in main() by ER_init().
*/
char er_progname[32];
char er_pid[16];

/* those are private variables */
pthread_mutex_t  er_pathlist_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif




void ER_init(char *progname, int processdefs);

#define ER_dbg_eq(mod, asp, typ, expr)  \
                ER_dbg_va (mod, asp, #expr " = " typ, expr)

void ER_perror(er_fac_code_t facwhere, int errcode, char *format,...)
#ifdef __GNUC__  /* let gcc check the format string for problems */
     __attribute__ ((format (printf, 3, 4)))
#endif
;
void ER_dbg_va(er_fac_code_t facwhere, er_mask_t asp, char *txt, ...);
void ER_inf_va(er_fac_code_t facwhere, er_mask_t asp, char *txt, ...);
int ER_anybody_wants(er_fac_code_t facwhere, int errcode, er_mask_t asp );
int ER_is_traced(er_fac_code_t facwhere, er_mask_t asp);

void ER_setpath(er_path_t *newset);

int NOERR(er_ret_t a);
#define ERR(a) (!NOERR(a))

char *er_getsevsym( int sev, int mode );
char *er_getfacsym(er_fac_code_t faccode);
er_mask_t er_getfacval(char *key);
unsigned int er_getaspval(char *key);
er_path_mt er_getpathval(char *key);

er_ret_t er_add_filter( er_path_t *pathptr, er_filter_t *filter );
er_ret_t er_add_path(  er_path_t *pathptr, char *key );

#ifdef __cplusplus
}
#endif

#undef EXTDEF
#undef EXTINI
#endif /* ER_H */
