AcePerl
view release on metacpan or search on metacpan
acelib/messubs.c view on Meta::CPAN
if (queryRoutine)
answer = (*queryRoutine)(mesg_buf) ;
else
answer = freequery (mesg_buf) ;
return answer ;
}
/*****************************************************************/
UTIL_FUNC_DEF void messdump (char *format,...)
{
static char dumpbuf[BUFSIZE] ; /* BEWARE limited buffer size. */
char *mesg_buf ;
va_list args ;
/* Format the message string. */
ACEFORMATSTRING(args, format, mesg_buf, NULL, &dumpbuf[0], BUFSIZE)
strcat (mesg_buf, "\n") ; /* assume we are writing to a file */
if (dumpRoutine)
(*dumpRoutine)(mesg_buf) ;
}
/*****************************************/
/* Access function for returning running error total. */
UTIL_FUNC_DEF int messErrorCount (void) { return errorCount_G ; }
/* Output a non-fatal error message, for all messages a call to messdump is */
/* made which may result in the message being logged. The single error count */
/* is also incremented so that functions can use this to check how many */
/* errors have been recorded so far. */
UTIL_FUNC_DEF void messerror (char *format, ...)
{
char *prefix = ERROR_PREFIX ;
char *mesg_buf = NULL ;
va_list args ;
/* always increment the error count. */
++errorCount_G ;
/* Format the message string. */
ACEFORMATSTRING(args, format, mesg_buf, prefix, NULL, 0) ;
/* If application registered an error handler routine, call it. */
if (errorJmpBuf)
longjmp (*errorJmpBuf, 1) ;
/* Log the message. */
messdump(mesg_buf) ;
/* Now report the error to the user. */
if (errorRoutine)
(*errorRoutine)(mesg_buf) ;
else
fprintf (stderr, "%s\n", mesg_buf) ;
invokeDebugger () ;
}
/*******************************/
/* Use this function for errors that while being unrecoverable are not a */
/* problem with the acedb code, e.g. if the user starts xace without */
/* specifying a database. */
/* Note that there errors are logged but that this routine will exit without */
/* any chance to interrupt it (e.g. the crash routine in uMessCrash), this */
/* could be changed to allow the application to register an exit handler. */
/* */
UTIL_FUNC_DEF void messExit(char *format, ...)
{
char *prefix = EXIT_PREFIX ;
char *mesg_buf = NULL ;
va_list args ;
/* Format the message string. */
ACEFORMATSTRING(args, format, mesg_buf, prefix, NULL, 0) ;
if (exitRoutine)
(*exitRoutine)(mesg_buf) ;
else
fprintf (stderr, "%s\n", mesg_buf) ;
#if defined(MACINTOSH)
crashOut(mesg_buf) ;
#else
messdump(mesg_buf) ;
exit(EXIT_FAILURE) ;
#endif
return ; /* Should never get here. */
}
/*******************************/
/* This is the routine called by the messcrash macro (see regular.h) which */
/* actually does the message/handling and exit. */
/* This routine may encounter errors itself, in which case it will attempt */
/* to call itself to report the error. To avoid infinite recursion we limit */
/* this to just one reporting of an internal error and then we abort. */
/* */
UTIL_FUNC_DEF void uMessCrash(char *format, ...)
{
enum {MAXERRORS = 1} ;
static int internalErrors = 0 ;
static char prefix[1024] ;
int rc ;
char *mesg_buf = NULL ;
va_list args ;
/* Check for recursive calls and abort if necessary. */
if (internalErrors > MAXERRORS)
{
fprintf (stderr, "%s : fatal internal error, abort",
messageG.progname);
abort() ;
}
else internalErrors++ ;
/* Construct the message prefix, adding the program name if possible. */
if (messGetErrorProgram() == NULL)
rc = sprintf(prefix, CRASH_PREFIX_FORMAT, messGetErrorFile(), messGetErrorLine()) ;
else
rc = sprintf(prefix, FULL_CRASH_PREFIX_FORMAT,
messGetErrorProgram(), messGetErrorFile(), messGetErrorLine()) ;
if (rc < 0) messcrash("sprintf failed") ;
/* Format the message string. */
ACEFORMATSTRING(args, format, mesg_buf, prefix, NULL, 0) ;
if (crashJmpBuf) /* throw back up to the function that registered it */
longjmp(*crashJmpBuf, 1) ;
#if defined(MACINTOSH)
crashOut(mesg_buf) ;
#else
messdump(mesg_buf) ;
if (crashRoutine)
(*crashRoutine)(mesg_buf) ;
else
fprintf(stderr, "%s\n", mesg_buf) ;
invokeDebugger() ;
exit(EXIT_FAILURE) ;
#endif
return ; /* Should never get here. */
}
/******* interface to crash/error trapping *******/
UTIL_FUNC_DEF jmp_buf* messCatchError (jmp_buf* new)
{
jmp_buf* old = errorJmpBuf ;
errorJmpBuf = new ;
return old ;
}
UTIL_FUNC_DEF jmp_buf* messCatchCrash (jmp_buf* new)
{
jmp_buf* old = crashJmpBuf ;
crashJmpBuf = new ;
return old ;
}
UTIL_FUNC_DEF char* messCaughtMessage (void) { return messbuf ; }
/* Message formatting routines. */
/* */
/* */
/* This function writes into its own buffer, note that this has finite size */
/* see top of file: BUFSIZE, also note that subsequent calls will overwrite */
/* this buffer. */
/* */
UTIL_FUNC_DEF char *messprintf (char *format, ...)
{
static char buffer[BUFSIZE] ;
char *mesg_buf ;
va_list args ;
/* Format the message string. */
ACEFORMATSTRING(args, format, mesg_buf, NULL, &buffer[0], BUFSIZE)
return mesg_buf ;
}
/* Used internally for formatting into a specified buffer. */
/* (currently only used as a cover function to enable us to use ACEFORMAT- */
/* STRING from messSysErrorText) */
static char *printToBuf(char *buffer, unsigned int buflen, char *format, ...)
{
char *mesg_buf ;
va_list args ;
/* Format the message string. */
ACEFORMATSTRING(args, format, mesg_buf, NULL, buffer, buflen)
return mesg_buf ;
}
/* Return the string for a given errno from the standard C library. */
/* */
UTIL_FUNC_DEF char* messSysErrorText (void)
{
enum {ERRBUFSIZE = 2000} ; /* Should be enough. */
static char errmess[ERRBUFSIZE] ;
char *mess ;
#ifdef SUN
/* horrible hack for Sunos/Macs(?) which are not standard C compliant */
mess = printToBuf(&errmess[0], ERRBUFSIZE, SYSERR_FORMAT, errno, sys_errlist[errno]) ;
#elif defined(MACINTOSH)
mess = printToBuf(&errmess[0], ERRBUFSIZE, SYSERR_FORMAT, errno) ;
#else
mess = printToBuf(&errmess[0], ERRBUFSIZE, SYSERR_FORMAT, errno, strerror(errno)) ;
#endif
return mess ;
}
/************************* message formatting ********************************/
/* This routine does the formatting of the message string using vsprintf, */
/* it copes with the format string accidentally being our internal buffer. */
/* */
/* This routine does its best to check that the vsprintf is successful, if */
/* not the routine bombs out with an error message. Note that num_bytes is */
/* the return value from vsprintf. */
/* Failures trapped: */
/* num_bytes < 0 => vsprintf failed, reason is reported. */
/* num_bytes + 1 > BUFSIZE => our internal buffer size was exceeded. */
/* (vsprintf returns number of bytes written */
/* _minus_ terminating NULL) */
/* */
static char *uMessFormat(va_list args, char *format, char *prefix,
char *buffer, unsigned int buflen)
{
char *buf_ptr ;
unsigned int buf_len ;
int prefix_len ;
/* Check arguments. */
if (format == NULL)
{
fprintf(stderr, "uMessFormat() : "
"invalid call, no format string.\n") ;
invokeDebugger();
exit (EXIT_FAILURE);
}
if (prefix == NULL)
prefix_len = 0 ;
else
{
prefix_len = strlen(prefix) ;
if ((prefix_len + 1) > PREFIXSIZE)
{
fprintf (stderr, "uMessFormat() : "
"prefix string is too long.\n") ;
invokeDebugger();
exit (EXIT_FAILURE);
}
}
/* If they supply their own buffer to receive the formatted
message then use this, otherwise use the global messbuf buffer. */
if (buffer != NULL)
{
buf_ptr = buffer ;
buf_len = buflen ;
if (buf_len == 0)
{
fprintf (stderr, "uMessFormat() : "
"zero length buffer supplied for message format.\n") ;
invokeDebugger();
exit (EXIT_FAILURE);
}
}
else
{
buf_ptr = &messbuf[0] ;
buf_len = BUFSIZE ;
}
/* Add the prefix if there is one. */
if (prefix != NULL)
{
if (strcpy (buf_ptr, prefix) == NULL)
{
fprintf (stderr, "uMessFormat() : strcpy failed\n") ;
invokeDebugger();
exit (EXIT_FAILURE);
}
}
/* CHECK PERFORMANCE ISSUES....how is database dumped/logged. */
/* Fred has suggested that we could do a vprintf to /dev/null and see how */
/* many bytes that is then we could get away from a fixed internal buffer */
/* at all....but watch out, if messdump say is in a tight loop then this */
/* will kill performance... */
/* We could add a #define to allow a check to be included for debug code. */
/* */
/* Do the format. */
#ifdef SUN
{
char *return_str;
/* NOTE, that SUNs vsprintf returns a char* */
return_str = vsprintf((buf_ptr + prefix_len), format, args) + prefix_len + 1 ;
/* Check the result. */
if (!return_str)
{
fprintf(stderr, "uMessFormat() : "
"vsprintf failed: %s\n", messSysErrorText()) ;
invokeDebugger();
exit (EXIT_FAILURE);
}
else if (strlen(return_str) > buf_len)
{
fprintf (stderr, "uMessFormat() : "
"messubs internal buffer size (%d) exceeded, "
"a total of %ld bytes were written\n",
buf_len, strlen(return_str)) ;
invokeDebugger();
exit (EXIT_FAILURE);
}
}
#else /* !SUN */
{
/* all other System's vsprintf returns an integer, of how many bytes have been written */
int num_bytes = vsprintf((buf_ptr + prefix_len), format, args) + prefix_len + 1 ;
/* Check the result. */
if (num_bytes < 0)
{
fprintf(stderr, "uMessFormat() : "
"vsprintf failed: %s\n", messSysErrorText()) ;
invokeDebugger();
exit (EXIT_FAILURE);
}
else if (num_bytes > buf_len)
{
fprintf (stderr, "uMessFormat() : "
"messubs internal buffer size (%d) exceeded, "
"a total of %d bytes were written\n",
buf_len, num_bytes) ;
invokeDebugger();
exit (EXIT_FAILURE);
}
}
#endif /* !SUN */
return(buf_ptr) ;
}
/********************** crash file/line info routines ************************/
/* When the acedb needs to crash because there has been an unrecoverable */
/* error we want to output the file and line number of the code that */
/* detected the error. Here are the functions to do it. */
/* */
/* Applications can optionally initialise the error handling section of the */
/* message package, currently the program name can be set (argv[0] in the */
/* main routine) as there is no easy way to get at this at run time except */
/* from the main. */
/* */
UTIL_FUNC_DEF void messErrorInit(char *progname)
{
if (progname != NULL) messageG.progname = strnew(filGetFilename(progname), 0) ;
return ;
}
/* This function is called by the messcrash macro which inserts the file and */
/* line information using the __FILE__ & __LINE__ macros. */
/* */
UTIL_FUNC_DEF void uMessSetErrorOrigin(char *filename, int line_num)
{
assert(filename != NULL && line_num != 0) ;
/* We take the basename here because __FILE__ can be a path rather than */
/* just a filename, depending on how a module was compiled. */
messageG.filename = strnew(filGetFilename(filename), 0) ;
messageG.line_num = line_num ;
}
/* mieg: protected these func against bad return, was crashing solaris server */
/* Access functions for message error data. */
UTIL_FUNC_DEF char *messGetErrorProgram()
{
return messageG.progname ? messageG.progname : "programme_name_unknown" ;
}
static char *messGetErrorFile()
{
return messageG.filename ? messageG.filename : "file_name_unknown" ;
}
static int messGetErrorLine()
( run in 1.477 second using v1.01-cache-2.11-cpan-97f6503c9c8 )