1 /*
2 * $Header: /home/kline/devel/atom/RCS/msg.c,v 1.1 1996/09/04 04:56:19 kline Exp kline $
3 * msg.c - routines to handle debug and error messages
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stddef.h>
9 #include <stdarg.h>
10 #include <string.h>
11 #include <time.h>
12 #include "msg.h"
13 /*
14 * Default levels for masking out messages.
15 */
16 MSG_CONST msg_severity_t msg_level[MSG_CATEGORIES] = {
17 5, 5, 0, 0, 0,
18 };
19
20 /* The string prepended to each message. You may use date directives
21 * like %T for time (see strftime(3)). Extension: You can use %s for
22 * the severity level.
23 */
24 static const char *msg_preface[MSG_CATEGORIES] = {
25 "Trace\t",
26 "Debug\t",
27 "Warning [%Y-%m-%d %H:%M.%S] level %s\n\t",
28 "Error [%Y-%m-%d %H:%M.%S] level %s\n\t",
29 "Fatal [%Y-%m-%d %H:%M.%S] level %s\n\t",
30 };
31
32 #if defined(MSG_COUNT_CALLS)
33 /* How many messages to accept in a given class before calling
34 * MSG_EXIT.
35 * 0 means never exit.
36 */
37 int msg_warnings[MSG_CATEGORIES] = {
38 0, 0, 0, 0, 0,
39 };
40 #endif
41
42 msg_category_t msg_category; /* global used for communication from macro */
43 msg_severity_t msg_severity; /* global used for communication from macro */
44 static FILE *msg_file;
45 static int msg_parse_preface[MSG_CATEGORIES]; /* really Boolean */
46 static int msg_init_done = 0;
47
48 /* Prototypes
49 */
50 static void parse_envir(void);
51 static char *parse_preface(const char *);
52 static void msg_fatal(char *);
53
54
55 void
msg_init()56 msg_init()
57 {
58 const char *env;
59 register short int i;
60
61 msg_init_done = 1;
62 env = getenv("MSG_FILE");
63 if (env && *env) {
64 msg_file = fopen(env, "a");
65 if (msg_file == NULL) {
66 perror(env);
67 msg_file = stderr;
68 }
69 setbuf(msg_file, NULL);
70 } else
71 msg_file = stderr;
72
73 for (i = MSG_CATEGORIES; i--;)
74 msg_parse_preface[i] = strchr(msg_preface[i], '%') ? 1 : 0;
75
76 parse_envir();
77 }
78
79
80 static void
parse_envir()81 parse_envir()
82 {
83 #if defined(MSG_PARSE_ENVIR)
84 register short int i = 0;
85 const char *env;
86
87 env = getenv("MSG_LEVEL");
88 /* Parse the environment variable:
89 * "5,,-,"
90 * becomes
91 * [ 5, OLD VALUE, MSG_MAX_SEVERITY + 1, OLD VALUE, OLD VALUE ]
92 */
93 if (env && *env) {
94 enum { fresh, number, junk } state = fresh;
95 register short int value = 0;
96
97 do {
98 if (*env == ',') {
99 if (state == number || state == junk)
100 msg_level[i] = value;
101 value = 0;
102 state = fresh;
103 if (++i >= MSG_CATEGORIES)
104 break;
105 } else if (state != junk && isdigit(*env)) {
106 value *= 10;
107 value += *env - '0';
108 if (value > MSG_MAX_SEVERITY + 1) {
109 value = MSG_MAX_SEVERITY + 1;
110 state = junk;
111 } else
112 state = number;
113 } else if (*env == '-') {
114 value = MSG_MAX_SEVERITY + 1;
115 state = junk;
116 } else if (*env == '+') {
117 value = 0;
118 state = junk;
119 } else if (state == number) /* non-digit, change state */
120 state = junk; /* so "4k5, 7" becomes "4,7", not "45,7" */
121 } while (*++env);
122
123 if (state == number || state == junk)
124 msg_level[i] = value;
125 }
126 #endif
127 }
128
129
130 void
msg_printf(const char * fmt,...)131 msg_printf(const char *fmt, ...)
132 {
133 char buff[1024];
134 va_list args;
135 register short int prelen, msglen;
136
137 if (!msg_init_done)
138 msg_init();
139
140 if (msg_parse_preface[msg_category]) {
141 struct tm *tm;
142 time_t clock;
143 char *fmt;
144
145 fmt = parse_preface(msg_preface[msg_category]);
146 time(&clock);
147 tm = localtime(&clock);
148 prelen = strftime(buff, sizeof(buff), fmt, tm);
149 if (prelen == 0) /* Error condition from strftime */
150 msg_fatal("Buffer too small");
151 free(fmt);
152 } else {
153 strncpy(buff, msg_preface[msg_category], sizeof(buff));
154 prelen = strlen(msg_preface[msg_category]);
155 }
156
157 va_start(args, fmt);
158 #if defined(_POSIX_SOURCE)
159 msglen = vsprintf(buff + prelen, fmt, args);
160
161 if (prelen + msglen > sizeof(buff))
162 msg_fatal("Buffer too small");
163 #else
164 /* BSD vsprintf() returns the first argument - can't be used
165 * for detecting buffer over-runs.
166 */
167 (void) vsprintf(buff + prelen, fmt, args);
168 #endif
169
170 va_end(args);
171 fprintf(msg_file, "%s\n", buff);
172 }
173
174
175 static char *
parse_preface(const char * template)176 parse_preface(const char *template) {
177 char *fmt;
178 size_t fmt_size;
179 ptrdiff_t p = 0;
180 enum { normal, percent } state = normal;
181
182 fmt_size = strlen(template) + 1;
183 fmt = (char *) malloc(fmt_size);
184 if (fmt == NULL)
185 msg_fatal("Out of memory");
186
187 for (; *template; template++) {
188 if (p > fmt_size) {
189 fmt_size += 16;
190 fmt = realloc(fmt, fmt_size);
191 if (fmt == NULL)
192 msg_fatal("Out of memory");
193 }
194 fmt[p++] = *template;
195 if (state == percent) {
196 if (*template == 's')
197 #if defined(_POSIX_SOURCE)
198 p += sprintf(fmt + p - 2, "%d", msg_severity) - 2;
199 #else
200 p = strchr(sprintf(fmt + p - 2, "%d", msg_severity), 0) - fmt;
201 #endif
202 state = normal;
203 } else if (*template == '%')
204 state = percent;
205 }
206 fmt[p] = 0;
207 return fmt;
208 }
209
210 static void
msg_fatal(char * msg)211 msg_fatal(char *msg)
212 {
213 fprintf(msg_file, "Fatal error: %s\n", msg);
214 fclose(msg_file);
215 exit(1);
216 }
217