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