1 /*
2 Copyright (C) 2003, 2004, 2008, 2011, 2012, 2015
3 Rocky Bernstein <rocky@gnu.org>
4 Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 # define __CDIO_CONFIG_H__ 1
23 #endif
24
25 #ifdef HAVE_STDLIB_H
26 #include <stdlib.h>
27 #endif
28 #ifdef HAVE_STDARG_H
29 #include <stdarg.h>
30 #endif
31 #ifdef HAVE_STDIO_H
32 #include <stdio.h>
33 #endif
34
35 #include <cdio/logging.h>
36 #include "cdio_assert.h"
37 #include "portable.h"
38 #include <assert.h>
39
40 cdio_log_level_t cdio_loglevel_default = CDIO_LOG_WARN;
41
42 extern void
cdio_default_log_handler(cdio_log_level_t level,const char message[])43 cdio_default_log_handler(cdio_log_level_t level, const char message[])
44 {
45 switch (level)
46 {
47 case CDIO_LOG_ERROR:
48 if (level >= cdio_loglevel_default) {
49 fprintf (stderr, "**ERROR: %s\n", message);
50 fflush (stderr);
51 }
52 exit (EXIT_FAILURE);
53 break;
54 case CDIO_LOG_DEBUG:
55 if (level >= cdio_loglevel_default) {
56 fprintf (stdout, "--DEBUG: %s\n", message);
57 }
58 break;
59 case CDIO_LOG_WARN:
60 if (level >= cdio_loglevel_default) {
61 fprintf (stdout, "++ WARN: %s\n", message);
62 }
63 break;
64 case CDIO_LOG_INFO:
65 if (level >= cdio_loglevel_default) {
66 fprintf (stdout, " INFO: %s\n", message);
67 }
68 break;
69 case CDIO_LOG_ASSERT:
70 if (level >= cdio_loglevel_default) {
71 fprintf (stderr, "!ASSERT: %s\n", message);
72 fflush (stderr);
73 }
74 abort ();
75 break;
76 default:
77 cdio_assert_not_reached ();
78 break;
79 }
80
81 fflush (stdout);
82 }
83
84 cdio_log_handler_t _handler = cdio_default_log_handler;
85
86 cdio_log_handler_t
cdio_log_set_handler(cdio_log_handler_t new_handler)87 cdio_log_set_handler(cdio_log_handler_t new_handler)
88 {
89 cdio_log_handler_t old_handler = _handler;
90
91 _handler = new_handler;
92
93 return old_handler;
94 }
95
96 static void
cdio_logv(cdio_log_level_t level,const char format[],va_list args)97 cdio_logv(cdio_log_level_t level, const char format[], va_list args)
98 {
99 char buf[1024] = { 0, };
100
101 /* _handler() is user defined and we want to make sure _handler()
102 doesn't call us, cdio_logv. in_recursion is used for that, however
103 it has a problem in multi-threaded programs. I'm not sure how to
104 handle multi-threading and recursion checking both. For now, we'll
105 leave in the recursion checking, at the expense of handling
106 multi-threaded log calls. To ameliorate this, we'll check the log
107 level and handle calls where there is no output, before the
108 recursion check.
109 */
110 static int in_recursion = 0;
111
112 if (level < cdio_loglevel_default) return;
113
114 if (in_recursion) {
115 /* Can't use cdio_assert_not_reached() as that may call cdio_logv */
116 assert(0);
117 }
118
119 in_recursion = 1;
120
121 vsnprintf(buf, sizeof(buf)-1, format, args);
122
123 _handler(level, buf);
124
125 in_recursion = 0;
126 }
127
128 void
cdio_log(cdio_log_level_t level,const char format[],...)129 cdio_log(cdio_log_level_t level, const char format[], ...)
130 {
131 va_list args;
132 va_start (args, format);
133 cdio_logv (level, format, args);
134 va_end (args);
135 }
136
137 #define CDIO_LOG_TEMPLATE(level, LEVEL) \
138 void \
139 cdio_ ## level (const char format[], ...) \
140 { \
141 va_list args; \
142 va_start (args, format); \
143 cdio_logv (CDIO_LOG_ ## LEVEL, format, args); \
144 va_end (args); \
145 }
146
147 CDIO_LOG_TEMPLATE(debug, DEBUG)
148 CDIO_LOG_TEMPLATE(info, INFO)
149 CDIO_LOG_TEMPLATE(warn, WARN)
150 CDIO_LOG_TEMPLATE(error, ERROR)
151
152 #undef CDIO_LOG_TEMPLATE
153
154
155 /*
156 * Local variables:
157 * c-file-style: "gnu"
158 * tab-width: 8
159 * indent-tabs-mode: nil
160 * End:
161 */
162