| 1 | #ifndef lint | 
| 2 | static const char RCSid[] = "$Id$"; | 
| 3 | #endif | 
| 4 | /* | 
| 5 | *  dmessage.c | 
| 6 | *  panlib | 
| 7 | * | 
| 8 | *  Debug message reporting routines. | 
| 9 | * | 
| 10 | *  Created by gward on Thu May 10 2001. | 
| 11 | *  Copyright (c) 2001 Anyhere Software. All rights reserved. | 
| 12 | * | 
| 13 | */ | 
| 14 |  | 
| 15 | #include <stdio.h> | 
| 16 | #include <stdlib.h> | 
| 17 | #include <string.h> | 
| 18 | #include <errno.h> | 
| 19 | #include "dmessage.h" | 
| 20 |  | 
| 21 | #define DM_NCLASSES     DMCnerr         /* number of message classes */ | 
| 22 | #define DM_MOSTFLAGS    (DMFrecord|DMFlog|DMFstderr|DMFalert) | 
| 23 |  | 
| 24 | char                    dmessage_buf[DM_BUF_LEN]; | 
| 25 | const char *            dmessage_class_name[DM_NCLASSES+1] = { | 
| 26 | "assert", | 
| 27 | "memory", | 
| 28 | "system", | 
| 29 | "parameter", | 
| 30 | "resource", | 
| 31 | "data", | 
| 32 | "input", | 
| 33 | "warning", | 
| 34 | "info", | 
| 35 | "trace", | 
| 36 | "none" | 
| 37 | }; | 
| 38 | int                     dmessage_class_flags[DM_NCLASSES+1] = { | 
| 39 | DM_MOSTFLAGS|DMFabort, | 
| 40 | DM_MOSTFLAGS|DMFexit, | 
| 41 | DM_MOSTFLAGS, | 
| 42 | DM_MOSTFLAGS, | 
| 43 | DM_MOSTFLAGS, | 
| 44 | DM_MOSTFLAGS, | 
| 45 | DM_MOSTFLAGS, | 
| 46 | DMFrecord|DMFlog|DMFstderr, | 
| 47 | DMFrecord|DMFlog, | 
| 48 | DMFrecord, | 
| 49 | 0 | 
| 50 | }; | 
| 51 | int                     dmessage_class_done[DM_NCLASSES]; | 
| 52 | const char *            dmessage_file[DM_NCLASSES]; | 
| 53 | int                     dmessage_line[DM_NCLASSES]; | 
| 54 | const char *            dmessage_record[DM_NCLASSES+1]; | 
| 55 | DMsgClass               dmessage_last_class = DMCnerr; | 
| 56 | FILE *                  dmessage_logfp = NULL; | 
| 57 | int                     (*dmessage_call)(DMsgClass cls, const char *msg, | 
| 58 | const char *file, int line) = NULL; | 
| 59 | int                     (*dmessage_alert)(const char *msg) = NULL; | 
| 60 | void                    (*dmessage_exit)(int status) = exit; | 
| 61 | void                    (*dmessage_abort)() = abort; | 
| 62 |  | 
| 63 | #define DM_MAX_RECORD   128 | 
| 64 |  | 
| 65 | static char             dmessage_mine[DM_NCLASSES][DM_MAX_RECORD]; | 
| 66 |  | 
| 67 | /* Report/record message, aborting program if cls is DMCassert */ | 
| 68 | int | 
| 69 | dmessage(DMsgClass cls, const char *msg, const char *file, int line) | 
| 70 | { | 
| 71 | int             todo; | 
| 72 | const char      *cp; | 
| 73 | if ((cls < 0) | (cls >= DMCnerr)) | 
| 74 | return 0; | 
| 75 | todo = dmessage_class_flags[cls]; | 
| 76 | if (msg == NULL || !*msg) | 
| 77 | msg = "(missing message)"; | 
| 78 | if (file != NULL && ((cp = strrchr(file, '/')) != NULL || | 
| 79 | (cp = strrchr(file, '\\')) != NULL)) | 
| 80 | file = cp+1;                            /* use tail */ | 
| 81 | dmessage_file[cls] = file;                      /* remember call */ | 
| 82 | dmessage_line[cls] = line; | 
| 83 | dmessage_class_done[cls] = todo; | 
| 84 | if (cls < dmessage_last_class)                  /* mark class */ | 
| 85 | dmessage_last_class = cls; | 
| 86 | if (dmessage_call != NULL)                      /* notify callback */ | 
| 87 | todo &= ~(*dmessage_call)(cls, msg, file, line); | 
| 88 | if (todo & DMFrecord) {                         /* save message */ | 
| 89 | if (msg != dmessage_buf && strlen(msg) >= DM_MAX_RECORD) { | 
| 90 | dmessage_record[cls] = msg; | 
| 91 | } else { | 
| 92 | strncpy(dmessage_mine[cls], msg, DM_MAX_RECORD-1); | 
| 93 | dmessage_record[cls] = dmessage_mine[cls]; | 
| 94 | } | 
| 95 | todo &= ~DMFrecord; | 
| 96 | } | 
| 97 | if (todo & DMFstderr) {                         /* send to stderr */ | 
| 98 | if (file != NULL) | 
| 99 | fprintf(stderr, "%s@%d>%s: %s", file, line, | 
| 100 | dmessage_class_name[cls], msg); | 
| 101 | else | 
| 102 | fprintf(stderr, "%s: %s", | 
| 103 | dmessage_class_name[cls], msg); | 
| 104 | if ((cls == DMCsystem) | (cls == DMCresource) && errno) { | 
| 105 | fputs(": ", stderr); | 
| 106 | perror(NULL); | 
| 107 | } else | 
| 108 | fputc('\n', stderr); | 
| 109 | if (fflush(stderr) != EOF) { | 
| 110 | todo &= ~DMFstderr; | 
| 111 | if (dmessage_logfp == stderr) | 
| 112 | todo &= ~DMFlog; | 
| 113 | } | 
| 114 | } | 
| 115 | if (todo & DMFlog && dmessage_logfp != NULL) {  /* log to file */ | 
| 116 | if (file != NULL) | 
| 117 | fprintf(dmessage_logfp, "%s@%d>%s: %s\n", file, line, | 
| 118 | dmessage_class_name[cls], msg); | 
| 119 | else | 
| 120 | fprintf(dmessage_logfp, "%s: %s\n", | 
| 121 | dmessage_class_name[cls], msg); | 
| 122 | if (fflush(dmessage_logfp) != EOF) | 
| 123 | todo &= ~DMFlog; | 
| 124 | } | 
| 125 | if (todo & DMFalert && dmessage_alert != NULL)  /* alert user */ | 
| 126 | if ((*dmessage_alert)(msg)) | 
| 127 | todo &= ~DMFalert; | 
| 128 |  | 
| 129 | if (todo & DMFabort && dmessage_abort != NULL) {/* abort */ | 
| 130 | (*dmessage_abort)(); | 
| 131 | todo &= ~DMFabort; | 
| 132 | } | 
| 133 | if (todo & DMFexit && dmessage_exit != NULL) {  /* exit */ | 
| 134 | (*dmessage_exit)(1); | 
| 135 | todo &= ~DMFexit; | 
| 136 | } | 
| 137 | /* say what was done */ | 
| 138 | return dmessage_class_done[cls] = (dmessage_class_flags[cls] & ~todo); | 
| 139 | } |