Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Elektra error codes.
5 : *
6 : * @copyright BSD License (see doc/LICENSE.md or http://www.libelektra.org)
7 : */
8 :
9 : #include "elektra/conversion.h"
10 : #include "elektra/error.h"
11 : #include "kdberrors.h"
12 : #include "kdbhelper.h"
13 : #include "kdbprivate.h"
14 : #include <string.h>
15 :
16 : #ifdef __cplusplus
17 : extern "C" {
18 : #endif
19 :
20 : // kdbprivate.h
21 :
22 : /**
23 : * Creates a new ElektraError using the provided values.
24 : * The returned value will be allocated with elektraCalloc().
25 : *
26 : * @param code The error code of the error. Must be compile-time constant.
27 : * @param description The description of the error. Will be copied and stored in the struct.
28 : * @param module The module that raised the error. Must be compile-time constant.
29 : * @param file The file that raised the error. Must be compile-time constant.
30 : * @param line The line in which the error was raised.
31 : *
32 : * @return A newly allocated ElektraError (free with elektraErrorReset()).
33 : */
34 30 : ElektraError * elektraErrorCreate (const char * code, const char * description, const char * module, const char * file, kdb_long_t line)
35 : {
36 30 : ElektraError * const error = elektraCalloc (sizeof (struct _ElektraError));
37 30 : error->code = code;
38 30 : error->codeFromKey = NULL;
39 30 : error->description = elektraStrDup (description);
40 30 : error->module = module;
41 30 : error->file = file;
42 30 : error->line = line;
43 30 : error->warningCount = 0;
44 30 : error->warningAlloc = 0;
45 30 : error->warnings = NULL;
46 30 : error->errorKey = NULL;
47 :
48 30 : return error;
49 : }
50 :
51 : /**
52 : * Adds a warning to an existing ElektraError struct.
53 : * If you want to report a warning without an error, create a dummy error with
54 : * elektraErrorPureWarning() and then add a warning to it.
55 : *
56 : * @param error The error to which @p warning shall be added.
57 : * @param warning The warning to add. Once added it is owned by @p error.
58 : * DO NOT call elektraErrorReset() on it afterwards.
59 : */
60 0 : void elektraErrorAddWarning (ElektraError * error, ElektraError * warning)
61 : {
62 0 : if (error->warningAlloc == 0)
63 : {
64 0 : error->warningCount = 1;
65 0 : error->warningAlloc = 4;
66 0 : error->warnings = elektraCalloc (error->warningAlloc * sizeof (ElektraError *));
67 : }
68 : else
69 : {
70 0 : ++error->warningCount;
71 0 : if (error->warningCount > error->warningAlloc)
72 : {
73 0 : error->warningAlloc *= 2;
74 0 : elektraRealloc ((void **) &error->warnings, error->warningAlloc * sizeof (ElektraError *));
75 : }
76 : }
77 :
78 0 : error->warnings[error->warningCount - 1] = warning;
79 0 : }
80 :
81 : /**
82 : * Extracts the error and all warnings from the given key.
83 : * If no error exists, a pure warning error will be used.
84 : * @see elektraErrorPureWarning
85 : *
86 : * @param key The to extract error and warnings from.
87 : *
88 : * @return A newly allocated ElektraError (free with elektraErrorReset()).
89 : */
90 0 : ElektraError * elektraErrorFromKey (Key * key)
91 : {
92 0 : if (key == NULL)
93 : {
94 : return NULL;
95 : }
96 :
97 : ElektraError * error;
98 0 : if (keyGetMeta (key, "error") == NULL)
99 : {
100 0 : error = elektraErrorPureWarning ();
101 : }
102 : else
103 : {
104 0 : const Key * reasonMeta = keyGetMeta (key, "error/reason");
105 :
106 0 : const char * codeFromKey = keyString (keyGetMeta (key, "error/number"));
107 0 : const char * description = keyString (keyGetMeta (key, "error/description"));
108 0 : const char * module = keyString (keyGetMeta (key, "error/module"));
109 0 : const char * file = keyString (keyGetMeta (key, "error/file"));
110 :
111 0 : char * fullDescription =
112 0 : reasonMeta != NULL ? elektraFormat ("%s: %s", description, keyString (reasonMeta)) : elektraStrDup (description);
113 :
114 0 : kdb_long_t line = 0;
115 0 : elektraKeyToLong (key, &line);
116 0 : error = elektraErrorCreate (NULL, fullDescription, module, file, line);
117 0 : error->codeFromKey = elektraStrDup (codeFromKey);
118 0 : error->errorKey = key;
119 :
120 0 : elektraFree (fullDescription);
121 : }
122 :
123 :
124 0 : kdb_long_t warningCount = 0;
125 0 : const Key * warningsKey = keyGetMeta (key, "warnings"); // TODO: read warning count correctly
126 0 : if (warningsKey != NULL)
127 : {
128 0 : elektraKeyToLong (warningsKey, &warningCount);
129 : }
130 :
131 0 : if (warningCount > 0)
132 : {
133 0 : error->warningAlloc = 4;
134 0 : while (error->warningAlloc < warningCount)
135 : {
136 0 : error->warningAlloc *= 2;
137 : }
138 0 : error->warningCount = warningCount;
139 :
140 0 : error->warnings = elektraCalloc (error->warningAlloc * sizeof (ElektraError *));
141 :
142 0 : for (int i = 0; i < warningCount; ++i)
143 : {
144 0 : const char * codeFromKey = keyString (keyGetMeta (key, "error/number"));
145 0 : const char * description = keyString (keyGetMeta (key, "error/description"));
146 0 : const char * module = keyString (keyGetMeta (key, "error/module"));
147 0 : const char * file = keyString (keyGetMeta (key, "error/file"));
148 0 : kdb_long_t line = 0;
149 0 : elektraKeyToLong (key, &line);
150 :
151 0 : ElektraError * warning = elektraErrorCreate (NULL, description, module, file, line);
152 0 : error->codeFromKey = elektraStrDup (codeFromKey);
153 0 : error->errorKey = key;
154 :
155 0 : error->warnings[i] = warning;
156 : }
157 : }
158 : else
159 : {
160 0 : error->warningCount = 0;
161 0 : error->warnings = NULL;
162 : }
163 :
164 : return error;
165 : }
166 :
167 : /**
168 : * Creates a "Key not found" error
169 : *
170 : * @param keyname The name of the key that wasn't found.
171 : *
172 : * @return A newly allocated ElektraError (free with elektraErrorReset()).
173 : */
174 0 : ElektraError * elektraErrorKeyNotFound (const char * keyname)
175 : {
176 0 : char * description = elektraFormat ("The key '%s' could not be found.", keyname);
177 0 : ElektraError * error = elektraErrorCreate (ELEKTRA_ERROR_INTERNAL, description, "highlevel", "unknown", 0);
178 0 : elektraFree (description);
179 0 : return error;
180 : }
181 :
182 : /**
183 : * Creates a "Wrong type" error
184 : *
185 : * @param keyname The name of the key that had the wrong type.
186 : * @param expectedType The type that was expected.
187 : * @param actualType The type that was actually found.
188 : *
189 : * @return A newly allocated ElektraError (free with elektraErrorReset()).
190 : */
191 2 : ElektraError * elektraErrorWrongType (const char * keyname, KDBType expectedType, KDBType actualType)
192 : {
193 2 : char * description =
194 : elektraFormat ("The key '%s' has the wrong type (expected '%s' but got '%s').", keyname, expectedType, actualType);
195 2 : ElektraError * error = elektraErrorCreate (ELEKTRA_ERROR_VALIDATION_SEMANTIC, description, "highlevel", "unknown", 0);
196 2 : elektraFree (description);
197 2 : return error;
198 : }
199 :
200 : /**
201 : * Creates a "Null error argument" error
202 : *
203 : * @param function The name of the function that was called with a null pointer error argument.
204 : *
205 : * @return A newly allocated ElektraError (free with elektraErrorReset()).
206 : */
207 0 : ElektraError * elektraErrorNullError (const char * function)
208 : {
209 0 : char * description = elektraFormat ("The value passed to the ElektraError ** argument of %s was NULL.", function);
210 0 : ElektraError * error = elektraErrorCreate (ELEKTRA_ERROR_INTERNAL, description, "highlevel", "unknown", 0);
211 0 : elektraFree (description);
212 0 : return error;
213 : }
214 :
215 : /**
216 : * Creates a "Conversion to string failed" error
217 : *
218 : * @param sourceType The type which failed to be converted to string.
219 : * @param keyname The name of the key that couldn't be converted.
220 : *
221 : * @return A newly allocated ElektraError (free with elektraErrorReset()).
222 : */
223 0 : ElektraError * elektraErrorConversionToString (KDBType sourceType, const char * keyname)
224 : {
225 0 : char * description = elektraFormat ("The value of key '%s' with type '%s' could not be converted to string.", keyname, sourceType);
226 0 : ElektraError * error = elektraErrorCreate (ELEKTRA_ERROR_VALIDATION_SEMANTIC, description, "highlevel", "unknown", 0);
227 0 : elektraFree (description);
228 0 : return error;
229 : }
230 :
231 : /**
232 : * Creates a "Conversion from string failed" error
233 : *
234 : * @param targetType The type into which @p sourceValue couldn't be converted.
235 : * @param keyname The name of the key that couldn't be converted.
236 : * @param sourceValue The value that couldn't be converted.
237 : *
238 : * @return A newly allocated ElektraError (free with elektraErrorReset()).
239 : */
240 28 : ElektraError * elektraErrorConversionFromString (KDBType targetType, const char * keyname, const char * sourceValue)
241 : {
242 28 : char * description =
243 : elektraFormat ("The value '%s' of key '%s' could not be converted to type '%s'.", sourceValue, keyname, targetType);
244 28 : ElektraError * error = elektraErrorCreate (ELEKTRA_ERROR_VALIDATION_SEMANTIC, description, "highlevel", "unknown", 0);
245 28 : elektraFree (description);
246 28 : return error;
247 : }
248 :
249 : /**
250 : * Creates a "kdbEnsure failed" error
251 : *
252 : * This intended for the case when kdbEnsure() returns 1.
253 : *
254 : * @param reason The error/reason metadata returned by kdbEnsure().
255 : *
256 : * @return A newly allocated ElektraError (free with elektraErrorReset()).
257 : */
258 0 : ElektraError * elektraErrorEnsureFailed (const char * reason)
259 : {
260 0 : char * description = elektraFormat ("The given contract could not be ensured: %s", reason);
261 0 : ElektraError * error = elektraErrorCreate (ELEKTRA_ERROR_VALIDATION_SEMANTIC, description, "highlevel", "unknown", 0);
262 0 : elektraFree (description);
263 0 : return error;
264 : }
265 :
266 : /**
267 : * Creates a "minimal validation failed" error
268 : *
269 : * @param application parent key as passed to elektraOpen()
270 : *
271 : * @return A newly allocated ElektraError (free with elektraErrorReset()).
272 : */
273 0 : ElektraError * elektraErrorMinimalValidationFailed (const char * application)
274 : {
275 0 : char * description = elektraFormat (
276 : "The validation of your KDB has failed. Please ensure that spec%s contains the "
277 : "specification and that 'kdb spec-mount %s' was executed.",
278 : application, application);
279 0 : ElektraError * error = elektraErrorCreate (ELEKTRA_ERROR_VALIDATION_SEMANTIC, description, "highlevel", "unknown", 0);
280 0 : elektraFree (description);
281 0 : return error;
282 : }
283 :
284 : // elektra/error.h
285 :
286 : /**
287 : * \addtogroup highlevel High-level API
288 : * @{
289 : */
290 :
291 : /**
292 : * Creates a dummy ElektraError struct to store warnings in.
293 : * If elektraErrorCode() is called on the resulting struct, it will return NULL.
294 : *
295 : * @return A newly allocated ElektraError (free with elektraFree()).
296 : */
297 0 : ElektraError * elektraErrorPureWarning (void)
298 : {
299 0 : return elektraErrorCreate (NULL, "", NULL, NULL, -1);
300 : }
301 :
302 : /**
303 : * @return the error code of the given error
304 : */
305 0 : const char * elektraErrorCode (const ElektraError * error)
306 : {
307 0 : return error->errorKey == NULL ? error->code : error->codeFromKey;
308 : }
309 :
310 : /**
311 : * @return the description for the given error
312 : */
313 30 : const char * elektraErrorDescription (const ElektraError * error)
314 : {
315 30 : return error->description;
316 : }
317 :
318 : /**
319 : * Frees the memory used by the error and sets
320 : * the referenced error variable to NULL.
321 : */
322 30 : void elektraErrorReset (ElektraError ** error)
323 : {
324 30 : if (*error == NULL)
325 : {
326 : return;
327 : }
328 :
329 30 : ElektraError * actualError = *error;
330 :
331 30 : if (actualError->description != NULL)
332 : {
333 30 : elektraFree (actualError->description);
334 : }
335 :
336 30 : if (actualError->codeFromKey != NULL)
337 : {
338 0 : elektraFree (actualError->codeFromKey);
339 : }
340 :
341 30 : if (actualError->warnings != NULL)
342 : {
343 0 : for (int i = 0; i < actualError->warningCount; ++i)
344 : {
345 0 : elektraErrorReset (&actualError->warnings[i]);
346 : }
347 0 : elektraFree (actualError->warnings);
348 : }
349 :
350 30 : elektraFree (actualError);
351 30 : *error = NULL;
352 : }
353 :
354 : /**
355 : * @}
356 : */
357 :
358 : #ifdef __cplusplus
359 : };
360 : #endif
|