Lely core libraries 1.9.2
diag.c
Go to the documentation of this file.
1
24#include "util.h"
25#include <lely/libc/stdio.h>
26#include <lely/util/diag.h>
27
28#include <assert.h>
29#include <stdlib.h>
30#include <string.h>
31#include <time.h>
32
33#ifdef _WIN32
34#include <wtsapi32.h>
35#ifdef _MSC_VER
36#pragma comment(lib, "wtsapi32.lib")
37#endif
38#elif _POSIX_C_SOURCE >= 200809L && !defined(__NEWLIB__)
39#include <syslog.h>
40#endif
41
42#ifdef _WIN32
43#ifndef LELY_DIALOG_DIAG_TIMEOUT
44#define LELY_DIALOG_DIAG_TIMEOUT 10
45#endif
46#endif
47
48static diag_handler_t *diag_handler = &default_diag_handler;
49static void *diag_handle;
50static diag_at_handler_t *diag_at_handler = &default_diag_at_handler;
51static void *diag_at_handle;
52
53size_t
54floc_lex(struct floc *at, const char *begin, const char *end)
55{
56 assert(begin);
57 assert(!end || end >= begin);
58
59 const char *cp = begin;
60 while ((!end || cp < end) && *cp) {
61 switch (*cp++) {
62 case '\r':
63 if ((!end || cp < end) && *cp == '\n')
64 cp++;
65 // ... falls through ...
66 case '\n':
67 if (at) {
68 at->line++;
69 at->column = 1;
70 }
71 break;
72 case '\t':
73 if (at)
74 at->column = ((at->column + 7) & ~7) + 1;
75 break;
76 default:
77 if (at)
78 at->column++;
79 break;
80 }
81 }
82 return cp - begin;
83}
84
85int
86snprintf_floc(char *s, size_t n, const struct floc *at)
87{
88 assert(at);
89
90 if (!s)
91 n = 0;
92
93 int r, t = 0;
94
95 if (at->filename) {
96 r = snprintf(s, n, "%s:", at->filename);
97 if (r < 0)
98 return r;
99 t += r;
100 r = MIN((size_t)r, n);
101 s += r;
102 n -= r;
103 if (at->line) {
104 r = snprintf(s, n, "%d:", at->line);
105 if (r < 0)
106 return r;
107 t += r;
108 r = MIN((size_t)r, n);
109 s += r;
110 n -= r;
111 if (at->column) {
112 r = snprintf(s, n, "%d:", at->column);
113 if (r < 0)
114 return r;
115 t += r;
116 }
117 }
118 }
119
120 return t;
121}
122
123void
124diag_get_handler(diag_handler_t **phandler, void **phandle)
125{
126 if (phandler)
127 *phandler = diag_handler;
128 if (phandle)
129 *phandle = diag_handle;
130}
131
132void
133diag_set_handler(diag_handler_t *handler, void *handle)
134{
135 diag_handler = handler;
136 diag_handle = handle;
137}
138
139void
140diag_at_get_handler(diag_at_handler_t **phandler, void **phandle)
141{
142 if (phandler)
143 *phandler = diag_at_handler;
144 if (phandle)
145 *phandle = diag_at_handle;
146}
147
148void
150{
151 diag_at_handler = handler;
152 diag_at_handle = handle;
153}
154
155void
156diag(enum diag_severity severity, int errc, const char *format, ...)
157{
158 va_list ap;
159 va_start(ap, format);
160 vdiag(severity, errc, format, ap);
161 va_end(ap);
162}
163
164void
165vdiag(enum diag_severity severity, int errc, const char *format, va_list ap)
166{
167 if (diag_handler)
168 diag_handler(diag_handle, severity, errc, format, ap);
169}
170
171void
172diag_at(enum diag_severity severity, int errc, const struct floc *at,
173 const char *format, ...)
174{
175 va_list ap;
176 va_start(ap, format);
177 vdiag_at(severity, errc, at, format, ap);
178 va_end(ap);
179}
180
181void
182vdiag_at(enum diag_severity severity, int errc, const struct floc *at,
183 const char *format, va_list ap)
184{
185 if (diag_at_handler)
186 diag_at_handler(diag_at_handle, severity, errc, at, format, ap);
187}
188
189void
190diag_if(enum diag_severity severity, int errc, const struct floc *at,
191 const char *format, ...)
192{
193 va_list ap;
194 va_start(ap, format);
195 vdiag_if(severity, errc, at, format, ap);
196 va_end(ap);
197}
198
199void
200vdiag_if(enum diag_severity severity, int errc, const struct floc *at,
201 const char *format, va_list ap)
202{
203 if (at)
204 vdiag_at(severity, errc, at, format, ap);
205}
206
207void
208default_diag_handler(void *handle, enum diag_severity severity, int errc,
209 const char *format, va_list ap)
210{
211 default_diag_at_handler(handle, severity, errc, NULL, format, ap);
212}
213
214void
215default_diag_at_handler(void *handle, enum diag_severity severity, int errc,
216 const struct floc *at, const char *format, va_list ap)
217{
218 (void)handle;
219
220 int errsv = errno;
221 char *s = NULL;
222 if (vasprintf_diag_at(&s, severity, errc, at, format, ap) >= 0) {
223 fprintf(stderr, "%s\n", s);
224 fflush(stderr);
225 }
226 free(s);
227 errno = errsv;
228
229 if (severity == DIAG_FATAL)
230 abort();
231}
232
233void
234cmd_diag_handler(void *handle, enum diag_severity severity, int errc,
235 const char *format, va_list ap)
236{
237 const char *cmd = handle;
238 if (cmd && *cmd) {
239 int errsv = errno;
240 fprintf(stderr, "%s: ", cmd);
241 fflush(stderr);
242 errno = errsv;
243 }
244
245 default_diag_handler(handle, severity, errc, format, ap);
246}
247
248void
249daemon_diag_handler(void *handle, enum diag_severity severity, int errc,
250 const char *format, va_list ap)
251{
252 daemon_diag_at_handler(handle, severity, errc, NULL, format, ap);
253}
254
255void
256daemon_diag_at_handler(void *handle, enum diag_severity severity, int errc,
257 const struct floc *at, const char *format, va_list ap)
258{
259#ifdef _WIN32
260 dialog_diag_at_handler(handle, severity, errc, at, format, ap);
261#else
262 syslog_diag_at_handler(handle, severity, errc, at, format, ap);
263#endif
264}
265
266#ifdef _WIN32
267
268void
269dialog_diag_handler(void *handle, enum diag_severity severity, int errc,
270 const char *format, va_list ap)
271{
272 dialog_diag_at_handler(handle, severity, errc, NULL, format, ap);
273}
274
275void
276dialog_diag_at_handler(void *handle, enum diag_severity severity, int errc,
277 const struct floc *at, const char *format, va_list ap)
278{
279 LPSTR pTitle = (LPSTR)(handle ? handle : "");
280
281 DWORD Style = MB_OK | MB_SETFOREGROUND | MB_TOPMOST;
282 switch (severity) {
283 case DIAG_DEBUG:
284 case DIAG_INFO: Style |= MB_ICONINFORMATION; break;
285 case DIAG_WARNING: Style |= MB_ICONWARNING; break;
286 case DIAG_ERROR:
287 case DIAG_FATAL: Style |= MB_ICONERROR; break;
288 default: break;
289 }
290
291 int errsv = errno;
292 char *pMessage = NULL;
293 if (vasprintf_diag_at(&pMessage, severity, errc, at, format, ap) >= 0) {
294 DWORD dwResponse;
295 WTSSendMessageA(WTS_CURRENT_SERVER_HANDLE,
296 WTSGetActiveConsoleSessionId(), pTitle,
297 strlen(pTitle), pMessage, strlen(pMessage),
298 Style, LELY_DIALOG_DIAG_TIMEOUT, &dwResponse,
299 FALSE);
300 }
301 free(pMessage);
302 errno = errsv;
303
304 if (severity == DIAG_FATAL)
305 abort();
306}
307
308#endif // _WIN32
309
310void
311log_diag_handler(void *handle, enum diag_severity severity, int errc,
312 const char *format, va_list ap)
313{
314 log_diag_at_handler(handle, severity, errc, NULL, format, ap);
315}
316
317void
318log_diag_at_handler(void *handle, enum diag_severity severity, int errc,
319 const struct floc *at, const char *format, va_list ap)
320{
321 int errsv = errno;
322 time_t timer;
323 if (time(&timer) != -1) {
324 struct tm *timeptr = NULL;
325#ifdef _WIN32
326 struct tm time;
327 if (localtime_s(&time, &timer))
328 timeptr = &time;
329#elif defined(_POSIX_C_SOURCE)
330 struct tm time;
331 timeptr = localtime_r(&timer, &time);
332#else
333 timeptr = localtime(&timer);
334#endif
335 if (timeptr) {
336 char buf[80];
337 // clang-format off
338 if (strftime(buf, sizeof(buf),
339 "%a, %d %b %Y %H:%M:%S %z", timeptr)
340 > 0) {
341 // clang-format on
342 fprintf(stderr, "%s: ", buf);
343 fflush(stderr);
344 }
345 }
346 }
347 errno = errsv;
348
349 default_diag_at_handler(handle, severity, errc, at, format, ap);
350}
351
352void
353syslog_diag_handler(void *handle, enum diag_severity severity, int errc,
354 const char *format, va_list ap)
355{
356 syslog_diag_at_handler(handle, severity, errc, NULL, format, ap);
357}
358
359void
360syslog_diag_at_handler(void *handle, enum diag_severity severity, int errc,
361 const struct floc *at, const char *format, va_list ap)
362{
363#if _POSIX_C_SOURCE >= 200809L && !defined(__NEWLIB__)
364 (void)handle;
365
366 int priority = LOG_USER;
367 switch (severity) {
368 case DIAG_DEBUG: priority |= LOG_DEBUG; break;
369 case DIAG_INFO: priority |= LOG_INFO; break;
370 case DIAG_WARNING: priority |= LOG_WARNING; break;
371 case DIAG_ERROR: priority |= LOG_ERR; break;
372 case DIAG_FATAL: priority |= LOG_EMERG; break;
373 }
374
375 int errsv = errno;
376 char *s = NULL;
377 if (vasprintf_diag_at(&s, DIAG_INFO, errc, at, format, ap) >= 0)
378 syslog(priority, "%s", s);
379 free(s);
380 errno = errsv;
381
382 if (severity == DIAG_FATAL)
383 abort();
384#else
385 log_diag_at_handler(handle, severity, errc, at, format, ap);
386#endif
387}
388
389int
390vsnprintf_diag(char *s, size_t n, enum diag_severity severity, int errc,
391 const char *format, va_list ap)
392{
393 return vsnprintf_diag_at(s, n, severity, errc, NULL, format, ap);
394}
395
396int
397vasprintf_diag(char **ps, enum diag_severity severity, int errc,
398 const char *format, va_list ap)
399{
400 return vasprintf_diag_at(ps, severity, errc, NULL, format, ap);
401}
402
403int
404vsnprintf_diag_at(char *s, size_t n, enum diag_severity severity, int errc,
405 const struct floc *at, const char *format, va_list ap)
406{
407 assert(format);
408
409 if (!s)
410 n = 0;
411
412 int r, t = 0;
413
414 if (at && (r = snprintf_floc(s, n, at)) != 0) {
415 if (r < 0)
416 return r;
417 t += r;
418 r = MIN((size_t)r, n);
419 s += r;
420 n -= r;
421 r = snprintf(s, n, " ");
422 if (r < 0)
423 return r;
424 t += r;
425 r = MIN((size_t)r, n);
426 s += r;
427 n -= r;
428 }
429
430 switch (severity) {
431 case DIAG_DEBUG: r = snprintf(s, n, "debug: "); break;
432 case DIAG_INFO: r = 0; break;
433 case DIAG_WARNING: r = snprintf(s, n, "warning: "); break;
434 case DIAG_ERROR: r = snprintf(s, n, "error: "); break;
435 case DIAG_FATAL: r = snprintf(s, n, "fatal: "); break;
436 default: r = 0; break;
437 }
438 if (r < 0)
439 return r;
440 t += r;
441 r = MIN((size_t)r, n);
442 s += r;
443 n -= r;
444
445 if (format && *format) {
446 r = vsnprintf(s, n, format, ap);
447 if (r < 0)
448 return r;
449 t += r;
450 r = MIN((size_t)r, n);
451 s += r;
452 n -= r;
453 if (errc) {
454 r = snprintf(s, n, ": ");
455 if (r < 0)
456 return r;
457 t += r;
458 r = MIN((size_t)r, n);
459 s += r;
460 n -= r;
461 }
462 }
463
464 if (errc) {
465 const char *errstr = errc2str(errc);
466 if (errstr) {
467 r = snprintf(s, n, "%s", errstr);
468 if (r < 0)
469 return r;
470 t += r;
471 }
472 }
473
474 return t;
475}
476
477int
478vasprintf_diag_at(char **ps, enum diag_severity severity, int errc,
479 const struct floc *at, const char *format, va_list ap)
480{
481 assert(ps);
482
483 va_list aq;
484 va_copy(aq, ap);
485 int n = vsnprintf_diag_at(NULL, 0, severity, errc, at, format, aq);
486 va_end(aq);
487 if (n < 0)
488 return n;
489
490 char *s = malloc(n + 1);
491 if (!s)
492 return -1;
493
494 n = vsnprintf_diag_at(s, n + 1, severity, errc, at, format, ap);
495 if (n < 0) {
496 int errsv = errno;
497 free(s);
498 errno = errsv;
499 return n;
500 }
501
502 *ps = s;
503 return n;
504}
505
506const char *
507cmdname(const char *path)
508{
509 assert(path);
510
511 const char *cmd = path;
512 while (*cmd)
513 cmd++;
514#ifdef _WIN32
515 while (cmd >= path && *cmd != '\\')
516#else
517 while (cmd >= path && *cmd != '/')
518#endif
519 cmd--;
520 return ++cmd;
521}
void syslog_diag_handler(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The diag() handler used for the system logging facilities.
Definition: diag.c:353
void daemon_diag_at_handler(void *handle, enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
The diag_at() handler for daemons.
Definition: diag.c:256
void diag_set_handler(diag_handler_t *handler, void *handle)
Sets the handler function for diag().
Definition: diag.c:133
int vsnprintf_diag(char *s, size_t n, enum diag_severity severity, int errc, const char *format, va_list ap)
Prints a diagnostic message to a string buffer.
Definition: diag.c:390
size_t floc_lex(struct floc *at, const char *begin, const char *end)
Increments a file location by reading characters from a memory buffer.
Definition: diag.c:54
int vasprintf_diag_at(char **ps, enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
Equivalent to vsnprintf_diag_at(), except that it allocates a string large enough to hold the output,...
Definition: diag.c:478
void cmd_diag_handler(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The diag() handler used for command-line programs.
Definition: diag.c:234
void vdiag(enum diag_severity severity, int errc, const char *format, va_list ap)
Emits a diagnostic message.
Definition: diag.c:165
const char * cmdname(const char *path)
Extracts the command name from a path.
Definition: diag.c:507
void vdiag_at(enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
Emits a diagnostic message occurring at a location in a text file.
Definition: diag.c:182
void default_diag_at_handler(void *handle, enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
The default diag_at() handler.
Definition: diag.c:215
void diag_at_set_handler(diag_at_handler_t *handler, void *handle)
Sets the handler function for diag_at().
Definition: diag.c:149
int vasprintf_diag(char **ps, enum diag_severity severity, int errc, const char *format, va_list ap)
Equivalent to vsnprintf_diag(), except that it allocates a string large enough to hold the output,...
Definition: diag.c:397
void diag_if(enum diag_severity severity, int errc, const struct floc *at, const char *format,...)
Emits a diagnostic message occurring at a location in a text file.
Definition: diag.c:190
void diag_at_get_handler(diag_at_handler_t **phandler, void **phandle)
Retrieves the handler function for diag_at().
Definition: diag.c:140
void vdiag_if(enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
Emits a diagnostic message occurring at a location in a text file.
Definition: diag.c:200
int snprintf_floc(char *s, size_t n, const struct floc *at)
Prints a file location to a string buffer.
Definition: diag.c:86
void daemon_diag_handler(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The diag() handler for daemons.
Definition: diag.c:249
void diag_at(enum diag_severity severity, int errc, const struct floc *at, const char *format,...)
Emits a diagnostic message occurring at a location in a text file.
Definition: diag.c:172
void log_diag_at_handler(void *handle, enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
The diag_at() handler used for log-files.
Definition: diag.c:318
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
void log_diag_handler(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The diag() handler for log files.
Definition: diag.c:311
int vsnprintf_diag_at(char *s, size_t n, enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
Prints a diagnostic message occurring at a location in a text file to a string buffer.
Definition: diag.c:404
void diag_get_handler(diag_handler_t **phandler, void **phandle)
Retrieves the handler function for diag().
Definition: diag.c:124
void default_diag_handler(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The default diag() handler.
Definition: diag.c:208
void syslog_diag_at_handler(void *handle, enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
The diag_at() handler used for the system logging facilities.
Definition: diag.c:360
This header file is part of the utilities library; it contains the diagnostic declarations.
void dialog_diag_at_handler(void *handle, enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
The diag_at() handler for dialog boxes.
void diag_at_handler_t(void *handle, enum diag_severity severity, int errc, const struct floc *at, const char *format, va_list ap)
The function type of a handler for diag_at().
Definition: diag.h:82
diag_severity
The severity of a diagnostic message.
Definition: diag.h:41
@ DIAG_DEBUG
A debug message.
Definition: diag.h:43
@ DIAG_WARNING
A warning.
Definition: diag.h:47
@ DIAG_INFO
An informational message.
Definition: diag.h:45
@ DIAG_ERROR
An error.
Definition: diag.h:49
@ DIAG_FATAL
A fatal error, which SHOULD result in program termination.
Definition: diag.h:51
void diag_handler_t(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The function type of a handler for diag().
Definition: diag.h:68
void dialog_diag_handler(void *handle, enum diag_severity severity, int errc, const char *format, va_list ap)
The diag() handler for dialog boxes.
const char * errc2str(int errc)
Returns a string describing a native error code.
Definition: errnum.c:973
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
This is the internal header file of the utilities library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdio....
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
This header file is part of the C11 and POSIX compatibility library; it includes <string....
A location in a text file.
Definition: diag.h:31
int line
The line number (starting from 1).
Definition: diag.h:35
int column
The column number (starting from 1).
Definition: diag.h:37
const char * filename
The name of the file.
Definition: diag.h:33