1 /*  File: messubs.c
2  *  Author: Richard Durbin (rd@mrc-lmb.cam.ac.uk)
3  *  Copyright (C) J Thierry-Mieg and R Durbin, 1992
4  *-------------------------------------------------------------------
5  * This file is part of the ACEDB genome database package, written by
6  * 	Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and
7  *	Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
8  *
9  * Description: low level: encapsulates vararg messages, *printf,
10  *			crash handler,
11  *
12  * Exported functions: see regular.h
13  *
14  * HISTORY:
15  * Last edited: Nov 27 15:36 1998 (fw)
16  * * Nov 19 13:26 1998 (edgrif): Removed the test for errorCount and messQuery
17  *              in messerror, really the wrong place.
18  * * Oct 22 15:26 1998 (edgrif): Replaced strdup's with strnew.
19  * * Oct 21 15:07 1998 (edgrif): Removed messErrorCount stuff from graphcon.c
20  *              and added to messerror (still not perfect), this was a new.
21  *              bug in the message system.
22  * * Sep 24 16:47 1998 (edgrif): Remove references to ACEDB in messages,
23  *              change messExit prefix to "EXIT: "
24  * * Sep 22 14:35 1998 (edgrif): Correct errors in buffer usage by message
25  *              outputting routines and message formatting routines.
26  * * Sep 11 09:22 1998 (edgrif): Add messExit routine.
27  * * Sep  9 16:52 1998 (edgrif): Add a messErrorInit function to allow an
28  *              application to register its name for use in crash messages.
29  * * Sep  3 11:32 1998 (edgrif): Rationalise strings used as prefixes for
30  *              messages. Add support for new messcrash macro to replace
31  *              messcrash routine, this includes file/line info. for
32  *              debugging (see regular.h for macro def.) and a new
33  *              uMessCrash routine.
34  * * Aug 25 14:51 1998 (edgrif): Made BUFSIZE enum (shows up in debugger).
35  *              Rationalise the use of va_xx calls into a single macro/
36  *              function and improve error checking on vsprintf.
37  *              messdump was writing into messbuf half way up, I've stopped
38  *              this and made two buffers of half the original size, one for
39  *              messages and one for messdump.
40  * * Aug 21 13:43 1998 (rd): major changes to make clean from NON_GRAPHICS
41  *              and ACEDB.  Callbacks can be registered for essentially
42  *              all functions.  mess*() versions continue to centralise
43  *              handling of ... via stdarg.
44  * * Aug 20 17:10 1998 (rd): moved memory handling to memsubs.c
45  * * Jul  9 11:54 1998 (edgrif):
46  *              Fixed problem with SunOS not having strerror function, system
47  *              is too old to have standard C libraries, have reverted to
48  *              referencing sys_errlist for SunOS only.
49  *              Also fixed problem with getpwuid in getLogin function, code
50  *              did not check return value from getpwuid function.
51  * * Jul  7 10:36 1998 (edgrif):
52  *      -       Replaced reference to sys_errlist with strerror function.
53  * * DON'T KNOW WHO MADE THESE CHANGES...NO RECORD IN HEADER....(edgrif)
54  *      -       newformat added for the log file on mess dump.
55  *      -       Time, host and pid are now always the first things written.
56  *      -       This is for easier checking og the log.wrm with scripts etc.
57  *      -       Messquery added for > 50 minor errors to ask if user wants to crash.
58  *      -       Made user,pid and host static in messdump.
59  * * Dec  3 15:52 1997 (rd)
60  * 	-	messout(): defined(_WINDOW) =>!defined(NON_GRAPHIC)
61  * * Dec 16 17:26 1996 (srk)
62  * * Aug 15 13:29 1996 (srk)
63  *	-	WIN32 and MACINTOSH: seteuid() etc. are stub functions
64  * * Jun 6 10:50 1996 (rbrusk): compile error fixes
65  * * Jun  4 23:31 1996 (rd)
66  * Created: Mon Jun 29 14:15:56 1992 (rd)
67  *-------------------------------------------------------------------
68  */
69 
70 /* $Id: messubs.c,v 1.1 2002/11/14 20:00:06 lstein Exp $ */
71 
72 #include <assert.h>
73 #include <errno.h>
74 #include "regular.h"
75 #include "freeout.h"				  /* messbeep uses freeOutF */
76 
77 
78 
79 /* This is horrible...a hack for sunos which is not standard C compliant.    */
80 /* to allow accessing system library error messages, will disappear....      */
81 #ifdef SUN
82 extern const char *sys_errlist[] ;
83 #endif
84 
85 
86 /* Mac has its own routine for crashing, see messcrash for usage.            */
87 #if !defined(MACINTOSH)
88 extern void crashOut (char* text) ;
89 #endif
90 
91 
92 
93 /* This buffer is used only by the routines that OUTPUT a message. Routines  */
94 /* that format messages into buffers (e.g. messprintf, messSysErrorText)     */
95 /* have their own buffers. Note that there is a problem here in that this    */
96 /* buffer can be overflowed, unfortunately because we use vsprintf to do     */
97 /* our formatting, this can only be detected after the event.                */
98 /*                                                                           */
99 /* Constraints on message buffer size - applicable to ALL routines that      */
100 /* format externally supplied strings.                                       */
101 /*                                                                           */
102 /* BUFSIZE:  size of message buffers (messbuf, a global buffer for general   */
103 /*           message stuff and a private ones in messdump & messprintf).     */
104 /* PREFIX:   length of message prefix (used to report details such as the    */
105 /*           file/line info. for where the error occurred.                   */
106 /* MAINTEXT: space left in buffer is the rest after the prefix and string    */
107 /*           terminator (NULL) are subtracted.                               */
108 /* Is there an argument for putting this buffer size in regular.h ??         */
109 /*                                                                           */
110 enum {BUFSIZE = 32768, PREFIXSIZE = 1024, MAINTEXTSIZE = BUFSIZE - PREFIXSIZE - 1} ;
111 
112 static char messbuf[BUFSIZE] ;
113 
114 
115 
116 /* Macro to format strings using va_xx calls, it calls uMessFormat whose     */
117 /* prototype is given below.                                                 */
118 /*                                                                           */
119 /* Arguments to the macro must have the following types:                     */
120 /*                                                                           */
121 /*   FORMAT_ARGS:   va_list used to get the variable argument list.          */
122 /*        FORMAT:   char *  to a string containing the printf format string. */
123 /*    TARGET_PTR:   char *  the formatted string will be returned in this    */
124 /*                          string pointer, N.B. do not put &TARGET_PTR      */
125 /*        PREFIX:   char *  to a string to be used as a prefix to the rest   */
126 /*                          of the string, or NULL.                          */
127 /*        BUFFER:   char *  the buffer where the formatting will take place, */
128 /*                          if NULL then the global messbuf buffer will be   */
129 /*                          used.                                            */
130 /*        BUFLEN:   unsigned                                                 */
131 /*                     int  the length of the buffer given by BUFFER (ignored*/
132 /*                          if BUFFER is NULL.                               */
133 /*                                                                           */
134 #define ACEFORMATSTRING(FORMAT_ARGS, FORMAT, TARGET_PTR, PREFIX, BUFFER, BUFLEN)  \
135 va_start(FORMAT_ARGS, FORMAT) ;                                                   \
136 TARGET_PTR = uMessFormat(FORMAT_ARGS, FORMAT, PREFIX, BUFFER, BUFLEN) ;           \
137 va_end(FORMAT_ARGS) ;
138 
139 static char *uMessFormat(va_list args, char *format, char *prefix,
140 			 char *buffer, unsigned int buflen) ;
141 
142 
143 /* Some standard defines for titles/text for messages:                       */
144 /*                                                                           */
145 #define ERROR_PREFIX "ERROR: "
146 #define EXIT_PREFIX "EXIT: "
147 #define CRASH_PREFIX_FORMAT "FATAL ERROR reported by %s at line %d: "
148 #define FULL_CRASH_PREFIX_FORMAT "FATAL ERROR reported by program %s, in file %s, at line %d: "
149 #if defined(MACINTOSH)
150 #define SYSERR_FORMAT "system error %d"
151 #else
152 #define SYSERR_FORMAT "system error %d - %s"
153 #endif
154 #define PROGNAME "The program"
155 
156 /* messcrash now reports the file/line no. where the messcrash was issued    */
157 /* as an aid to debugging. We do this using a static structure which holds   */
158 /* the information and a macro version of messcrash (see regular.h), the     */
159 /* structure elements are retrieved using access functions.                  */
160 typedef struct _MessErrorInfo
161   {
162   char *progname ;				  /* Name of executable reporting error. */
163   char *filename ;				  /* Filename where error reported */
164   int line_num ;				  /* Line number of file where error
165 						     reported. */
166   } MessErrorInfo ;
167 
168 static MessErrorInfo messageG = {NULL, NULL, 0} ;
169 
170 static int messGetErrorLine() ;
171 static char *messGetErrorFile() ;
172 
173 
174 /* Keeps a running total of errors so far (incremented whenever messerror is */
175 /* called).                                                                  */
176 static int errorCount_G = 0 ;
177 
178 
179 /* Function pointers for application supplied routines that are called when  */
180 /* ever messerror or messcrash are called, enables application to take       */
181 /* action on all such errors.                                                */
182 static jmp_buf *errorJmpBuf = 0 ;
183 static jmp_buf *crashJmpBuf = 0 ;
184 
185 
186 
187 /***************************************************************/
188 /********* call backs and functions to register them ***********/
189 
190 static VoidRoutine	  beepRoutine = 0 ;
191 static OutRoutine	  outRoutine = 0 ;
192 static OutRoutine	  dumpRoutine = 0 ;
193 static OutRoutine	  errorRoutine = 0 ;
194 static OutRoutine	  exitRoutine = 0 ;
195 static OutRoutine	  crashRoutine = 0 ;
196 static QueryRoutine	  queryRoutine = 0 ;
197 static PromptRoutine	  promptRoutine = 0 ;
198 static IsInterruptRoutine isInterruptRoutine = 0 ;
199 
messBeepRegister(VoidRoutine func)200 UTIL_FUNC_DEF VoidRoutine messBeepRegister (VoidRoutine func)
201 { VoidRoutine old = beepRoutine ; beepRoutine = func ; return old ; }
202 
messOutRegister(OutRoutine func)203 UTIL_FUNC_DEF OutRoutine messOutRegister (OutRoutine func)
204 { OutRoutine old = outRoutine ; outRoutine = func ; return old ; }
205 
messDumpRegister(OutRoutine func)206 UTIL_FUNC_DEF OutRoutine messDumpRegister (OutRoutine func)
207 { OutRoutine old = dumpRoutine ; dumpRoutine = func ; return old ; }
208 
messErrorRegister(OutRoutine func)209 UTIL_FUNC_DEF OutRoutine messErrorRegister (OutRoutine func)
210 { OutRoutine old = errorRoutine ; errorRoutine = func ; return old ; }
211 
messExitRegister(OutRoutine func)212 UTIL_FUNC_DEF OutRoutine messExitRegister (OutRoutine func)
213 { OutRoutine old = exitRoutine ; exitRoutine = func ; return old ; }
214 
messCrashRegister(OutRoutine func)215 UTIL_FUNC_DEF OutRoutine messCrashRegister (OutRoutine func)
216 { OutRoutine old = crashRoutine ; crashRoutine = func ; return old ; }
217 
messQueryRegister(QueryRoutine func)218 UTIL_FUNC_DEF QueryRoutine messQueryRegister (QueryRoutine func)
219 { QueryRoutine old = queryRoutine ; queryRoutine = func ; return old ; }
220 
messPromptRegister(PromptRoutine func)221 UTIL_FUNC_DEF PromptRoutine messPromptRegister (PromptRoutine func)
222 { PromptRoutine old = promptRoutine ; promptRoutine = func ; return old ; }
223 
messIsInterruptRegister(IsInterruptRoutine func)224 UTIL_FUNC_DEF IsInterruptRoutine messIsInterruptRegister (IsInterruptRoutine func)
225 { IsInterruptRoutine old = isInterruptRoutine ; isInterruptRoutine = func ; return old ; }
226 
227 
228 
229 /***************************************************/
messIsInterruptCalled(void)230 UTIL_FUNC_DEF BOOL messIsInterruptCalled (void)
231 {
232   if (isInterruptRoutine)
233     return (*isInterruptRoutine)() ;
234 
235   /* unless a routine is registered, we assume no interrupt
236      (e.g. F4 keypress in graph-window) has been called */
237   return FALSE;
238 }
239 
240 
241 /* The message output routines.                                              */
242 /*                                                                           */
243 /*                                                                           */
244 
245 
246 /***************************************************/
messbeep(void)247 UTIL_FUNC_DEF void messbeep (void)
248 {
249   if (beepRoutine)
250     (*beepRoutine)() ;
251   else
252     { freeOutf ("%c",0x07) ;  /* bell character, I hope */
253       fflush (stdout) ;	/* added by fw 02.Feb 1994 */
254     }
255 }
256 
257 
258 /*******************************/
messout(char * format,...)259 UTIL_FUNC_DEF void messout (char *format,...)
260 {
261   va_list args ;
262   char *mesg_buf ;
263 
264   /* Format the message string.                                              */
265   ACEFORMATSTRING(args, format, mesg_buf, NULL, NULL, 0)
266 
267   if (outRoutine)
268     (*outRoutine)(mesg_buf) ;
269   else
270     fprintf (stdout, "//!! %s\n", mesg_buf) ;
271 
272 }
273 
274 /*****************************/
275 
messPrompt(char * prompt,char * dfault,char * fmt)276 UTIL_FUNC_DEF BOOL messPrompt (char *prompt, char *dfault, char *fmt)
277 {
278   BOOL answer ;
279 
280   if (promptRoutine)
281     answer = (*promptRoutine)(prompt, dfault, fmt) ;
282   else
283     answer = freeprompt (prompt, dfault, fmt) ;
284 
285   return answer ;
286 }
287 
288 /*****************************/
289 
messQuery(char * format,...)290 UTIL_FUNC_DEF BOOL messQuery (char *format,...)
291 {
292   BOOL answer ;
293   char *mesg_buf = NULL ;
294   va_list args ;
295 
296   /* Format the message string.                                              */
297   ACEFORMATSTRING(args, format, mesg_buf, NULL, NULL, 0)
298 
299   if (queryRoutine)
300     answer = (*queryRoutine)(mesg_buf) ;
301   else
302     answer = freequery (mesg_buf) ;
303 
304   return answer ;
305 }
306 
307 /*****************************************************************/
308 
messdump(char * format,...)309 UTIL_FUNC_DEF void messdump (char *format,...)
310 {
311   static char dumpbuf[BUFSIZE] ;		  /* BEWARE limited buffer size. */
312   char *mesg_buf ;
313   va_list args ;
314 
315   /* Format the message string.                                              */
316   ACEFORMATSTRING(args, format, mesg_buf, NULL, &dumpbuf[0], BUFSIZE)
317 
318   strcat (mesg_buf, "\n") ;			  /* assume we are writing to a file */
319 
320   if (dumpRoutine)
321     (*dumpRoutine)(mesg_buf) ;
322 }
323 
324 
325 /*****************************************/
326 
327 
328 /* Access function for returning running error total.                        */
messErrorCount(void)329 UTIL_FUNC_DEF int messErrorCount (void) { return errorCount_G ; }
330 
331 
332 /* Output a non-fatal error message, for all messages a call to messdump is  */
333 /* made which may result in the message being logged. The single error count */
334 /* is also incremented so that functions can use this to check how many      */
335 /* errors have been recorded so far.                                         */
messerror(char * format,...)336 UTIL_FUNC_DEF void messerror (char *format, ...)
337 {
338   char *prefix = ERROR_PREFIX ;
339   char *mesg_buf = NULL ;
340   va_list args ;
341 
342   /* always increment the error count.                                       */
343   ++errorCount_G ;
344 
345   /* Format the message string.                                              */
346   ACEFORMATSTRING(args, format, mesg_buf, prefix, NULL, 0) ;
347 
348   /* If application registered an error handler routine, call it.            */
349   if (errorJmpBuf)
350     longjmp (*errorJmpBuf, 1) ;
351 
352   /* Log the message.                                                        */
353   messdump(mesg_buf) ;
354 
355   /* Now report the error to the user.                                       */
356   if (errorRoutine)
357     (*errorRoutine)(mesg_buf) ;
358   else
359     fprintf (stderr, "%s\n", mesg_buf) ;
360 
361   invokeDebugger () ;
362 }
363 
364 
365 
366 /*******************************/
367 
368 /* Use this function for errors that while being unrecoverable are not a     */
369 /* problem with the acedb code, e.g. if the user starts xace without         */
370 /* specifying a database.                                                    */
371 /* Note that there errors are logged but that this routine will exit without */
372 /* any chance to interrupt it (e.g. the crash routine in uMessCrash), this   */
373 /* could be changed to allow the application to register an exit handler.    */
374 /*                                                                           */
messExit(char * format,...)375 UTIL_FUNC_DEF void messExit(char *format, ...)
376   {
377   char *prefix = EXIT_PREFIX ;
378   char *mesg_buf = NULL ;
379   va_list args ;
380 
381   /* Format the message string.                                              */
382   ACEFORMATSTRING(args, format, mesg_buf, prefix, NULL, 0) ;
383 
384   if (exitRoutine)
385     (*exitRoutine)(mesg_buf) ;
386   else
387     fprintf (stderr, "%s\n", mesg_buf) ;
388 
389 #if defined(MACINTOSH)
390   crashOut(mesg_buf) ;
391 #else
392   messdump(mesg_buf) ;
393 
394   exit(EXIT_FAILURE) ;
395 #endif
396 
397   return ;					  /* Should never get here. */
398   }
399 
400 
401 /*******************************/
402 
403 /* This is the routine called by the messcrash macro (see regular.h) which   */
404 /* actually does the message/handling and exit.                              */
405 /* This routine may encounter errors itself, in which case it will attempt   */
406 /* to call itself to report the error. To avoid infinite recursion we limit  */
407 /* this to just one reporting of an internal error and then we abort.        */
408 /*                                                                           */
uMessCrash(char * format,...)409 UTIL_FUNC_DEF void uMessCrash(char *format, ...)
410   {
411   enum {MAXERRORS = 1} ;
412   static int internalErrors = 0 ;
413   static char prefix[1024] ;
414   int rc ;
415   char *mesg_buf = NULL ;
416   va_list args ;
417 
418   /* Check for recursive calls and abort if necessary.                       */
419   if (internalErrors > MAXERRORS)
420     {
421       fprintf (stderr, "%s : fatal internal error, abort",
422 	       messageG.progname);
423       abort() ;
424     }
425   else internalErrors++ ;
426 
427   /* Construct the message prefix, adding the program name if possible.      */
428   if (messGetErrorProgram() == NULL)
429        rc = sprintf(prefix, CRASH_PREFIX_FORMAT, messGetErrorFile(), messGetErrorLine()) ;
430   else
431        rc = sprintf(prefix, FULL_CRASH_PREFIX_FORMAT,
432 		    messGetErrorProgram(), messGetErrorFile(), messGetErrorLine()) ;
433   if (rc < 0) messcrash("sprintf failed") ;
434 
435 
436   /* Format the message string.                                              */
437   ACEFORMATSTRING(args, format, mesg_buf, prefix, NULL, 0) ;
438 
439 
440   if (crashJmpBuf)		/* throw back up to the function that registered it */
441     longjmp(*crashJmpBuf, 1) ;
442 
443 
444 #if defined(MACINTOSH)
445   crashOut(mesg_buf) ;
446 #else
447   messdump(mesg_buf) ;
448 
449   if (crashRoutine)
450     (*crashRoutine)(mesg_buf) ;
451   else
452     fprintf(stderr, "%s\n", mesg_buf) ;
453 
454   invokeDebugger() ;
455 
456   exit(EXIT_FAILURE) ;
457 #endif
458 
459   return ;					  /* Should never get here. */
460   }
461 
462 
463 
464 
465 
466 /******* interface to crash/error trapping *******/
467 
messCatchError(jmp_buf * new)468 UTIL_FUNC_DEF jmp_buf* messCatchError (jmp_buf* new)
469 {
470   jmp_buf* old = errorJmpBuf ;
471   errorJmpBuf = new ;
472   return old ;
473 }
474 
messCatchCrash(jmp_buf * new)475 UTIL_FUNC_DEF jmp_buf* messCatchCrash (jmp_buf* new)
476 {
477   jmp_buf* old = crashJmpBuf ;
478   crashJmpBuf = new ;
479   return old ;
480 }
481 
messCaughtMessage(void)482 UTIL_FUNC_DEF char* messCaughtMessage (void) { return messbuf ; }
483 
484 
485 
486 /* Message formatting routines.                                              */
487 /*                                                                           */
488 /*                                                                           */
489 
490 /* This function writes into its own buffer, note that this has finite size  */
491 /* see top of file: BUFSIZE, also note that subsequent calls will overwrite  */
492 /* this buffer.                                                              */
493 /*                                                                           */
messprintf(char * format,...)494 UTIL_FUNC_DEF char *messprintf (char *format, ...)
495   {
496   static char buffer[BUFSIZE] ;
497   char *mesg_buf ;
498   va_list args ;
499 
500   /* Format the message string.                                              */
501   ACEFORMATSTRING(args, format, mesg_buf, NULL, &buffer[0], BUFSIZE)
502 
503   return mesg_buf ;
504 }
505 
506 
507 /* Used internally for formatting into a specified buffer.                   */
508 /* (currently only used as a cover function to enable us to use ACEFORMAT-   */
509 /* STRING from messSysErrorText)                                             */
printToBuf(char * buffer,unsigned int buflen,char * format,...)510 static char *printToBuf(char *buffer, unsigned int buflen, char *format, ...)
511   {
512   char *mesg_buf ;
513   va_list args ;
514 
515   /* Format the message string.                                              */
516   ACEFORMATSTRING(args, format, mesg_buf, NULL, buffer, buflen)
517 
518   return mesg_buf ;
519   }
520 
521 
522 
523 /* Return the string for a given errno from the standard C library.          */
524 /*                                                                           */
messSysErrorText(void)525 UTIL_FUNC_DEF char* messSysErrorText (void)
526   {
527   enum {ERRBUFSIZE = 2000} ;				    /* Should be enough. */
528   static char errmess[ERRBUFSIZE] ;
529   char *mess ;
530 
531 #ifdef SUN
532   /* horrible hack for Sunos/Macs(?) which are not standard C compliant */
533   mess = printToBuf(&errmess[0], ERRBUFSIZE, SYSERR_FORMAT, errno, sys_errlist[errno]) ;
534 #elif defined(MACINTOSH)
535   mess = printToBuf(&errmess[0], ERRBUFSIZE, SYSERR_FORMAT, errno) ;
536 #else
537   mess = printToBuf(&errmess[0], ERRBUFSIZE, SYSERR_FORMAT, errno, strerror(errno)) ;
538 #endif
539 
540   return mess ;
541   }
542 
543 
544 /************************* message formatting ********************************/
545 /* This routine does the formatting of the message string using vsprintf,    */
546 /* it copes with the format string accidentally being our internal buffer.   */
547 /*                                                                           */
548 /* This routine does its best to check that the vsprintf is successful, if   */
549 /* not the routine bombs out with an error message. Note that num_bytes is   */
550 /* the return value from vsprintf.                                           */
551 /* Failures trapped:                                                         */
552 /*              num_bytes < 0  =>  vsprintf failed, reason is reported.      */
553 /*    num_bytes + 1 > BUFSIZE  =>  our internal buffer size was exceeded.    */
554 /*                                 (vsprintf returns number of bytes written */
555 /*                                  _minus_ terminating NULL)                */
556 /*                                                                           */
uMessFormat(va_list args,char * format,char * prefix,char * buffer,unsigned int buflen)557 static char *uMessFormat(va_list args, char *format, char *prefix,
558 			 char *buffer, unsigned int buflen)
559 {
560   char *buf_ptr ;
561   unsigned int buf_len ;
562   int prefix_len ;
563 
564 
565   /* Check arguments.                                                        */
566   if (format == NULL)
567     {
568       fprintf(stderr, "uMessFormat() : "
569 	      "invalid call, no format string.\n") ;
570       invokeDebugger();
571       exit (EXIT_FAILURE);
572     }
573 
574   if (prefix == NULL)
575     prefix_len = 0 ;
576   else
577     {
578       prefix_len = strlen(prefix) ;
579       if ((prefix_len + 1) > PREFIXSIZE)
580 	{
581 	  fprintf (stderr, "uMessFormat() : "
582 		   "prefix string is too long.\n") ;
583 	  invokeDebugger();
584 	  exit (EXIT_FAILURE);
585 	}
586     }
587 
588   /* If they supply their own buffer to receive the formatted
589      message then use this, otherwise use the global messbuf buffer. */
590   if (buffer != NULL)
591     {
592       buf_ptr = buffer ;
593       buf_len = buflen ;
594       if (buf_len == 0)
595 	{
596 	  fprintf (stderr, "uMessFormat() : "
597 		   "zero length buffer supplied for message format.\n") ;
598 	  invokeDebugger();
599 	  exit (EXIT_FAILURE);
600 	}
601     }
602   else
603     {
604       buf_ptr = &messbuf[0] ;
605       buf_len = BUFSIZE ;
606     }
607 
608   /* Add the prefix if there is one. */
609   if (prefix != NULL)
610     {
611       if (strcpy (buf_ptr, prefix) == NULL)
612 	{
613 	  fprintf (stderr, "uMessFormat() : strcpy failed\n") ;
614 	  invokeDebugger();
615 	  exit (EXIT_FAILURE);
616 	}
617     }
618 
619 
620   /* CHECK PERFORMANCE ISSUES....how is database dumped/logged.              */
621 
622   /* Fred has suggested that we could do a vprintf to /dev/null and see how  */
623   /* many bytes that is then we could get away from a fixed internal buffer  */
624   /* at all....but watch out, if messdump say is in a tight loop then this   */
625   /* will kill performance...                                                */
626   /* We could add a #define to allow a check to be included for debug code.  */
627   /*                                                                         */
628 
629 
630   /* Do the format. */
631 
632 #ifdef SUN
633   {
634     char *return_str;
635 
636     /* NOTE, that SUNs vsprintf returns a char* */
637     return_str = vsprintf((buf_ptr + prefix_len), format, args) + prefix_len + 1 ;
638 
639     /* Check the result. */
640     if (!return_str)
641       {
642 	fprintf(stderr, "uMessFormat() : "
643 		"vsprintf failed: %s\n", messSysErrorText()) ;
644 	invokeDebugger();
645 	exit (EXIT_FAILURE);
646       }
647     else if (strlen(return_str) > buf_len)
648       {
649 	fprintf (stderr, "uMessFormat() : "
650 		 "messubs internal buffer size (%d) exceeded, "
651 		 "a total of %ld bytes were written\n",
652 		 buf_len, strlen(return_str)) ;
653 	invokeDebugger();
654 	exit (EXIT_FAILURE);
655       }
656   }
657 #else  /* !SUN */
658   {
659     /* all other System's vsprintf returns an integer, of how many bytes have been written */
660     int num_bytes = vsprintf((buf_ptr + prefix_len), format, args) + prefix_len + 1 ;
661 
662     /* Check the result.                                                       */
663     if (num_bytes < 0)
664       {
665 	fprintf(stderr, "uMessFormat() : "
666 		"vsprintf failed: %s\n", messSysErrorText()) ;
667 	invokeDebugger();
668 	exit (EXIT_FAILURE);
669       }
670     else if (num_bytes > buf_len)
671       {
672 	fprintf (stderr, "uMessFormat() : "
673 		 "messubs internal buffer size (%d) exceeded, "
674 		 "a total of %d bytes were written\n",
675 		 buf_len, num_bytes) ;
676 	invokeDebugger();
677 	exit (EXIT_FAILURE);
678       }
679   }
680 #endif /* !SUN */
681 
682   return(buf_ptr) ;
683   }
684 
685 
686 /********************** crash file/line info routines ************************/
687 /* When the acedb needs to crash because there has been an unrecoverable     */
688 /* error we want to output the file and line number of the code that         */
689 /* detected the error. Here are the functions to do it.                      */
690 /*                                                                           */
691 
692 /* Applications can optionally initialise the error handling section of the  */
693 /* message package, currently the program name can be set (argv[0] in the    */
694 /* main routine) as there is no easy way to get at this at run time except   */
695 /* from the main.                                                            */
696 /*                                                                           */
messErrorInit(char * progname)697 UTIL_FUNC_DEF void messErrorInit(char *progname)
698   {
699 
700   if (progname != NULL) messageG.progname = strnew(filGetFilename(progname), 0) ;
701 
702   return ;
703   }
704 
705 /* This function is called by the messcrash macro which inserts the file and */
706 /* line information using the __FILE__ & __LINE__ macros.                    */
707 /*                                                                           */
uMessSetErrorOrigin(char * filename,int line_num)708 UTIL_FUNC_DEF void uMessSetErrorOrigin(char *filename, int line_num)
709 {
710 
711   assert(filename != NULL && line_num != 0) ;
712 
713   /* We take the basename here because __FILE__ can be a path rather than    */
714   /* just a filename, depending on how a module was compiled.                */
715   messageG.filename = strnew(filGetFilename(filename), 0) ;
716 
717   messageG.line_num = line_num ;
718 }
719 
720 /* mieg: protected these func against bad return, was crashing solaris server */
721 /* Access functions for message error data.                                  */
messGetErrorProgram()722 UTIL_FUNC_DEF char *messGetErrorProgram()
723 {
724   return messageG.progname ?  messageG.progname : "programme_name_unknown"  ;
725 }
726 
messGetErrorFile()727 static char *messGetErrorFile()
728 {
729   return messageG.filename ? messageG.filename  : "file_name_unknown" ;
730 }
731 
messGetErrorLine()732 static int messGetErrorLine()
733 {
734   return messageG.line_num ;
735 }
736 
737 
738 /*****************************/
739 
740 /* put "break invokeDebugger" in your favourite debugger init file */
741 
invokeDebugger(void)742 UTIL_FUNC_DEF void invokeDebugger (void)
743 {
744   static BOOL reentrant = FALSE ;
745 
746   if (!reentrant)
747     { reentrant = TRUE ;
748       messalloccheck() ;
749       reentrant = FALSE ;
750     }
751 }
752 
753 
754 
755 
756 /*************************************************************************/
757 /************************** orphan function ******************************/
758 
759 /* match to reg expression
760 
761    returns 0 if not found
762            1 + pos of first sigificant match (i.e. not a *) if found
763 */
764 
regExpMatch(char * cp,char * tp)765 UTIL_FUNC_DEF int regExpMatch (char *cp,char *tp)
766 {
767   char *c=cp, *t=tp;
768   char *ts=0, *cs=0, *s = 0 ;
769   int star=0;
770 
771   while (TRUE)
772     switch(*t)
773       {
774       case '\0':
775  	if(!*c)
776 	  return  ( s ? 1 + (s - cp) : 1) ;
777 	if (!star)
778 	  return 0 ;
779         /* else not success yet go back in template */
780 	t=ts; c=cs+1;
781 	if(ts == tp) s = 0 ;
782 	break ;
783       case '?' :
784 	if (!*c)
785 	  return 0 ;
786 	if(!s) s = c ;
787         t++ ;  c++ ;
788         break;
789       case '*' :
790         ts=t;
791         while( *t == '?' || *t == '*')
792           t++;
793         if (!*t)
794           return s ? 1 + (s-cp) : 1 ;
795         while (freeupper(*c) != freeupper(*t))
796           if(*c)
797             c++;
798           else
799             return 0 ;
800         star=1;
801         cs=c;
802 	if(!s) s = c ;
803         break;
804       case 'A' :
805 	if (!*c || (*c < 'A' || *c > 'Z'))
806 	  return 0 ;
807 	if(!s) s = c ;
808         t++ ;  c++ ;
809         break;
810       default  :
811         if (freeupper(*t++) != freeupper(*c++))
812           { if(!star)
813               return 0 ;
814             t=ts; c=cs+1;
815 	    if(ts == tp) s = 0 ;
816           }
817 	else
818 	  if(!s) s = c - 1 ;
819         break;
820       }
821 }
822 
823 /***************** another orphan function *********************/
824 
825 #ifdef SGI			/* work around SGI library bug */
826 #include "math.h"
log10(double x)827 UTIL_FUNC_DEF double log10 (double x) { return log(x) / 2.3025851 ; }
828 #endif
829 
830 /**** end of file ****/
831