1 #include "config.h"
2
3 #include <stdio.h>
4 #include <stdarg.h>
5 #include <string.h>
6 #include <gettext.h>
7 #include <errno.h>
8
9 #include "prelude.h"
10 #include "prelude-log.h"
11 #include "prelude-error.h"
12
13 #include "code-to-errno.h"
14 #include "code-from-errno.h"
15
16
17 #define PRELUDE_ERROR_CODE_DIM 65536
18 #define PRELUDE_ERROR_SOURCE_DIM 256
19
20 #define PRELUDE_ERROR_SOURCE_SHIFT 23
21 #define PRELUDE_ERROR_VERBOSE_SHIFT 22
22
23 #define PRELUDE_ERROR_CODE_MASK (PRELUDE_ERROR_CODE_DIM - 1)
24 #define PRELUDE_ERROR_SOURCE_MASK (PRELUDE_ERROR_SOURCE_DIM - 1)
25 #define PRELUDE_ERROR_VERBOSE_MASK (1)
26
27
28 /**
29 * prelude_error_make:
30 * @source: Error source.
31 * @code: Error code.
32 *
33 * Create a new #prelude_error_t error using @source and @code.
34 *
35 * Returns: The created #prelude_error_t integer.
36 */
prelude_error_make(prelude_error_source_t source,prelude_error_code_t code)37 prelude_error_t prelude_error_make(prelude_error_source_t source, prelude_error_code_t code)
38 {
39 return (code == PRELUDE_ERROR_NO_ERROR) ? code : -((source << PRELUDE_ERROR_SOURCE_SHIFT) | code);
40 }
41
42
43 /**
44 * prelude_error_make_from_errno:
45 * @source: Error source.
46 * @err: errno value.
47 *
48 * Create a new #prelude_error_t error using @source and @errno.
49 *
50 * Returns: The created #prelude_error_t integer.
51 */
prelude_error_make_from_errno(prelude_error_source_t source,int err)52 prelude_error_t prelude_error_make_from_errno(prelude_error_source_t source, int err)
53 {
54 prelude_error_code_t code = prelude_error_code_from_errno(err);
55 return prelude_error_make(source, code);
56 }
57
58
59
60 /**
61 * prelude_error_verbose_make_v:
62 * @source: Error source.
63 * @code: Error code.
64 * @fmt: Format string.
65 * @ap: Argument list.
66 *
67 * Create a new error using @source and @code, using the detailed error message
68 * specified within @fmt.
69 *
70 * Returns: The created #prelude_error_t integer.
71 */
prelude_error_verbose_make_v(prelude_error_source_t source,prelude_error_code_t code,const char * fmt,va_list ap)72 prelude_error_t prelude_error_verbose_make_v(prelude_error_source_t source,
73 prelude_error_code_t code, const char *fmt, va_list ap)
74 {
75 int ret;
76 prelude_string_t *str;
77
78 ret = prelude_string_new(&str);
79 if ( ret < 0 )
80 return ret;
81
82 ret = prelude_string_vprintf(str, fmt, ap);
83 if ( ret < 0 ) {
84 prelude_string_destroy(str);
85 return ret;
86 }
87
88 ret = _prelude_thread_set_error(prelude_string_get_string(str));
89 prelude_string_destroy(str);
90
91 if ( ret < 0 )
92 return ret;
93
94 ret = prelude_error_make(source, code);
95 ret = -ret;
96 ret |= (1 << PRELUDE_ERROR_VERBOSE_SHIFT);
97
98 return -ret;
99 }
100
101
102
103 /**
104 * prelude_error_verbose_make:
105 * @source: Error source.
106 * @code: Error code.
107 * @fmt: Format string.
108 * @...: Argument list.
109 *
110 * Create a new error using @source and @code, using the detailed error message
111 * specified within @fmt.
112 *
113 * Returns: The created #prelude_error_t integer.
114 */
prelude_error_verbose_make(prelude_error_source_t source,prelude_error_code_t code,const char * fmt,...)115 prelude_error_t prelude_error_verbose_make(prelude_error_source_t source,
116 prelude_error_code_t code, const char *fmt, ...)
117 {
118 int ret;
119 va_list ap;
120
121 va_start(ap, fmt);
122 ret = prelude_error_verbose_make_v(source, code, fmt, ap);
123 va_end(ap);
124
125 return ret;
126 }
127
128
129 /**
130 * prelude_error_get_code:
131 * @error: A #prelude_error_t return value.
132 *
133 * Returns: the #prelude_code_t code contained within the @prelude_error_t integer.
134 */
prelude_error_get_code(prelude_error_t error)135 prelude_error_code_t prelude_error_get_code(prelude_error_t error)
136 {
137 error = -error;
138 return (prelude_error_code_t) (error & PRELUDE_ERROR_CODE_MASK);
139 }
140
141
142 /**
143 * prelude_error_get_source:
144 * @error: A #prelude_error_t return value.
145 *
146 * Returns: the #prelude_source_t source contained within the @prelude_error_t integer.
147 */
prelude_error_get_source(prelude_error_t error)148 prelude_error_source_t prelude_error_get_source(prelude_error_t error)
149 {
150 error = -error;
151 return (prelude_error_source_t) ((error >> PRELUDE_ERROR_SOURCE_SHIFT) & PRELUDE_ERROR_SOURCE_MASK);
152 }
153
154
155 /**
156 * prelude_error_is_verbose:
157 * @error: A #prelude_error_t return value.
158 *
159 * Returns: #PRELUDE_BOOL_TRUE if there is a detailed message for this error, #PRELUDE_BOOL_FALSE otherwise.
160 */
prelude_error_is_verbose(prelude_error_t error)161 prelude_bool_t prelude_error_is_verbose(prelude_error_t error)
162 {
163 error = -error;
164 return ((error >> PRELUDE_ERROR_VERBOSE_SHIFT) & PRELUDE_ERROR_VERBOSE_MASK) ? PRELUDE_BOOL_TRUE : PRELUDE_BOOL_FALSE;
165 }
166
167
168 /**
169 * prelude_error_code_from_errno:
170 * @err: errno value.
171 *
172 * Returns: the #prelude_error_code_t value corresponding to @err.
173 */
prelude_error_code_from_errno(int err)174 prelude_error_code_t prelude_error_code_from_errno(int err)
175 {
176 int idx;
177
178 if ( ! err )
179 return PRELUDE_ERROR_NO_ERROR;
180
181 idx = errno_to_idx(err);
182 if ( idx < 0 )
183 return PRELUDE_ERROR_UNKNOWN_ERRNO;
184
185 return PRELUDE_ERROR_SYSTEM_ERROR | err_code_from_index[idx];
186 }
187
188
189 /**
190 * prelude_error_code_to_errno:
191 * @code: Error code.
192 *
193 * Returns: the errno value corresponding to @code.
194 */
prelude_error_code_to_errno(prelude_error_code_t code)195 int prelude_error_code_to_errno(prelude_error_code_t code)
196 {
197 if ( ! (code & PRELUDE_ERROR_SYSTEM_ERROR) )
198 return 0;
199
200 code &= ~PRELUDE_ERROR_SYSTEM_ERROR;
201
202 if ( code < sizeof(err_code_to_errno) / sizeof(err_code_to_errno[0]) )
203 return err_code_to_errno[code];
204 else
205 return 0;
206 }
207
208
209
210 /**
211 * prelude_perror:
212 * @error: A #prelude_error_t return value.
213 * @fmt: Format string.
214 * @...: Argument list.
215 *
216 * Print the error to stderr, or to syslog() in case stderr is unavailable.
217 */
prelude_perror(prelude_error_t error,const char * fmt,...)218 void prelude_perror(prelude_error_t error, const char *fmt, ...)
219 {
220 va_list ap;
221 char buf[1024];
222
223 va_start(ap, fmt);
224 vsnprintf(buf, sizeof(buf), fmt, ap);
225 va_end(ap);
226
227 if ( prelude_error_get_source(error) )
228 prelude_log(PRELUDE_LOG_WARN, "%s: %s: %s.\n", prelude_strsource(error), buf, prelude_strerror(error));
229 else
230 prelude_log(PRELUDE_LOG_WARN, "%s: %s.\n", buf, prelude_strerror(error));
231 }
232