dte test coverage


Directory: ./
File: src/error.c
Date: 2024-12-21 16:03:22
Exec Total Coverage
Lines: 44 48 91.7%
Functions: 7 7 100.0%
Branches: 11 14 78.6%

Line Branch Exec Source
1 #include <errno.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "error.h"
6 #include "command/run.h"
7 #include "config.h"
8 #include "util/log.h"
9 #include "util/xstdio.h"
10
11 typedef struct {
12 char buf[512];
13 unsigned int nr_errors;
14 bool is_error;
15 bool print_to_stderr;
16 } ErrorBuffer;
17
18 // This is not accessed from signal handlers or multiple threads and
19 // is considered an acceptable use of non-const globals:
20 // NOLINTNEXTLINE(*-avoid-non-const-global-variables)
21 static ErrorBuffer err;
22
23 95 void clear_error(void)
24 {
25 95 err.buf[0] = '\0';
26 95 }
27
28 114 bool error_msg(const char *format, ...)
29 {
30
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 13 times.
114 const char *cmd = current_command ? current_command->name : NULL;
31 114 const char *file = current_config.file;
32 114 const unsigned int line = current_config.line;
33 114 const size_t size = sizeof(err.buf);
34 114 int pos = 0;
35
36
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 if (file && cmd) {
37 pos = snprintf(err.buf, size, "%s:%u: %s: ", file, line, cmd);
38
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 113 times.
114 } else if (file) {
39 1 pos = snprintf(err.buf, size, "%s:%u: ", file, line);
40
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 12 times.
113 } else if (cmd) {
41 101 pos = snprintf(err.buf, size, "%s: ", cmd);
42 }
43
44
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if (unlikely(pos < 0)) {
45 // Note: POSIX snprintf(3) *does* set errno on failure (unlike ISO C)
46 LOG_ERRNO("snprintf");
47 pos = 0;
48 }
49
50
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 if (likely(pos < (size - 3))) {
51 114 va_list ap;
52 114 va_start(ap, format);
53 114 vsnprintf(err.buf + pos, size - pos, format, ap);
54 114 va_end(ap);
55 } else {
56 LOG_WARNING("no buffer space left for error message");
57 }
58
59 114 err.is_error = true;
60 114 err.nr_errors++;
61
62
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 110 times.
114 if (err.print_to_stderr) {
63 4 xfputs(err.buf, stderr);
64 4 xfputc('\n', stderr);
65 }
66
67 114 LOG_INFO("%s", err.buf);
68
69 // Always return false, to allow tail-calling as `return error_msg(...);`
70 // from command handlers, instead of `error_msg(...); return false;`
71 114 return false;
72 }
73
74 1 bool error_msg_errno(const char *prefix)
75 {
76 1 return error_msg("%s: %s", prefix, strerror(errno));
77 }
78
79 11 bool info_msg(const char *format, ...)
80 {
81 11 va_list ap;
82 11 va_start(ap, format);
83 11 vsnprintf(err.buf, sizeof(err.buf), format, ap);
84 11 va_end(ap);
85 11 err.is_error = false;
86 11 return true; // To allow tail-calling from command handlers
87 }
88
89 95 const char *get_msg(bool *is_error)
90 {
91 95 *is_error = err.is_error;
92 95 return err.buf;
93 }
94
95 362 unsigned int get_nr_errors(void)
96 {
97 362 return err.nr_errors;
98 }
99
100 24 void errors_to_stderr(bool enable)
101 {
102 24 err.print_to_stderr = enable;
103 24 }
104