Remove building with NOCRYPTO option
[minix3.git] / external / bsd / kyua-testers / dist / error.c
blob3a159c85484216b3cce41f32c5a0938233af7a49
1 // Copyright 2012 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "error.h"
31 #include <assert.h>
32 #include <err.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
39 /// Generic hook to format an error that does not have a format callback.
40 ///
41 /// \param error Error for which to generate a message.
42 /// \param output_buffer Buffer to hold the generated message.
43 /// \param output_size Length of output_buffer.
44 static int
45 generic_format_callback(const kyua_error_t error, char* const output_buffer,
46 size_t output_size)
48 assert(error != NULL);
49 return snprintf(output_buffer, output_size, "Error '%s'", error->type_name);
53 /// Initializes an error object.
54 ///
55 /// \param error Error for which to generate a message.
56 /// \param type_name Name of the error type.
57 /// \param data Opaque data that belongs to the error, for usage by
58 /// error-specific methods like format_callback.
59 /// \param data_size Size of the opaque data object.
60 /// \param format_callback Type-specific method to generate a user
61 /// representation of the error.
62 ///
63 /// \return True if the initialization succeeds; false otherwise. If
64 /// false, the error object passed in has not been modified.
65 static bool
66 error_init(kyua_error_t const error, const char* const type_name,
67 void* const data, const size_t data_size,
68 const kyua_error_format_callback format_callback)
70 assert(data != NULL || data_size == 0);
71 assert(data_size != 0 || data == NULL);
73 bool ok;
75 if (data == NULL) {
76 error->data = NULL;
77 error->needs_free = false;
78 ok = true;
79 } else {
80 void* new_data = malloc(data_size);
81 if (new_data == NULL) {
82 ok = false;
83 } else {
84 memcpy(new_data, data, data_size);
85 error->data = new_data;
86 ok = true;
90 if (ok) {
91 error->type_name = type_name;
92 error->format_callback = (format_callback == NULL) ?
93 generic_format_callback : format_callback;
96 return ok;
100 /// Allocates and initializes a new error.
102 /// \param type_name Name of the error type.
103 /// \param data Opaque data that belongs to the error, for usage by
104 /// error-specific methods like format_callback.
105 /// \param data_size Size of the opaque data object.
106 /// \param format_callback Type-specific method to generate a user
107 /// representation of the error.
109 /// \return The newly initialized error, or an out of memory error.
110 kyua_error_t
111 kyua_error_new(const char* const type_name, void* const data,
112 const size_t data_size,
113 const kyua_error_format_callback format_callback)
115 assert(data != NULL || data_size == 0);
116 assert(data_size != 0 || data == NULL);
118 kyua_error_t error = malloc(sizeof(struct kyua_error));
119 if (error == NULL)
120 error = kyua_oom_error_new();
121 else {
122 if (!error_init(error, type_name, data, data_size, format_callback)) {
123 free(error);
124 error = kyua_oom_error_new();
125 } else {
126 error->needs_free = true;
130 assert(error != NULL);
131 return error;
135 /// Releases an error.
137 /// \param error The error object to release.
138 void
139 kyua_error_free(kyua_error_t error)
141 assert(error != NULL);
143 const bool needs_free = error->needs_free;
145 if (error->data != NULL)
146 free(error->data);
147 if (needs_free)
148 free(error);
152 /// Returns the "most important" of two errors.
154 /// "Most important" is defined as: the primary error is returned if set,
155 /// otherwise the secondary error is returned.
157 /// It is the responsibility of the caller to free the *resulting* error of this
158 /// call. The original errors passed in should not be consulted any longer,
159 /// because it is impossible to know which one was chosen.
161 /// \param primary The primary error to compare.
162 /// \param [in,out] secondary The secondary error to compare. This is freed if
163 /// the primary error is set.
165 /// \return Either primary or secondary.
166 kyua_error_t
167 kyua_error_subsume(kyua_error_t primary, kyua_error_t secondary)
169 if (kyua_error_is_set(primary)) {
170 if (kyua_error_is_set(secondary))
171 kyua_error_free(secondary);
172 return primary;
173 } else {
174 return secondary;
179 /// Constructor for a no-error condition.
181 /// \return Opaque representation of a no-error condition.
182 kyua_error_t
183 kyua_error_ok(void)
185 return NULL;
189 /// Checks if the given error object represents an error or not.
191 /// \param error The error to check.
193 /// \return True if the error is set.
194 bool
195 kyua_error_is_set(const kyua_error_t error)
197 return error != NULL;
201 /// Checks if the given error object is of a specific type.
203 /// \pre The error must be set.
205 /// \param error The error to check.
206 /// \param type_name The type of the expected error.
208 /// \return True if the error is of type type_name.
209 bool
210 kyua_error_is_type(const kyua_error_t error, const char* type_name)
212 assert(error != NULL);
214 return strcmp(error->type_name, type_name) == 0;
218 /// Returns a pointer to the error-specific data.
220 /// \pre The error must be set.
222 /// \param error The error to query.
224 /// \return An opaque pointer to the error data. This should only be
225 /// dereferenced by the methods of the error class that created it.
226 const void*
227 kyua_error_data(const kyua_error_t error)
229 assert(error != NULL);
231 return error->data;
235 /// Generates a user-friendly representation of the error.
237 /// This cannot fail, but it is possible that the generated error does not
238 /// fit in the provided buffer.
240 /// \pre The error must be set.
242 /// \param error Error for which to generate a message.
243 /// \param output_buffer Buffer to hold the generated message.
244 /// \param output_size Length of output_buffer.
246 /// \return The number of bytes written to output_buffer, or a negative value if
247 /// there was an error.
249 kyua_error_format(const kyua_error_t error, char* const output_buffer,
250 const size_t output_size)
252 assert(kyua_error_is_set(error));
253 return error->format_callback(error, output_buffer, output_size);
257 /// Formats a string and appends an error code to it.
259 /// \param error Error to append to the formatted message.
260 /// \param format User-specified message, as a formatting string.
261 /// \param ap List of arguments to the format string.
262 /// \param [out] output_buffer Buffer into which to write the message.
263 /// \param output_size Length of the output_buffer.
265 /// \return The number of bytes written to output_buffer, or a negative value if
266 /// there was an error.
267 static int
268 format_user_message(const kyua_error_t error, const char* format, va_list ap,
269 char* const output_buffer, const size_t output_size)
271 assert(kyua_error_is_set(error));
273 va_list ap2;
274 va_copy(ap2, ap);
275 size_t written = vsnprintf(output_buffer, output_size, format, ap2);
276 va_end(ap2);
277 if (written >= output_size)
278 return -1;
280 written += snprintf(output_buffer + written, output_size - written, ": ");
281 if (written >= output_size)
282 return -1;
284 return kyua_error_format(error, output_buffer + written,
285 output_size - written);
289 /// Version of err(3) that works with kyua_error_t objects.
291 /// \param exit_code Error code with which to terminate the execution.
292 /// \param error Error to append to the output.
293 /// \param format User-specified message, as a formatting string.
294 /// \param ... Positional arguments to the format string.
296 /// \post Execution terminates with exit_code.
297 void
298 kyua_error_err(const int exit_code, const kyua_error_t error,
299 const char* format, ...)
301 char buffer[2048];
303 va_list ap;
304 va_start(ap, format);
305 (void)format_user_message(error, format, ap, buffer, sizeof(buffer));
306 va_end(ap);
307 kyua_error_free(error);
309 errx(exit_code, "%s", buffer);
313 /// Writes an error to a file stream.
315 /// \param stream Stream to which to write the message.
316 /// \param error Error to append to the output. This is not released.
317 /// \param format User-specified message, as a formatting string.
318 /// \param ... Positional arguments to the format string.
319 void
320 kyua_error_fprintf(FILE* stream, const kyua_error_t error,
321 const char* format, ...)
323 char buffer[2048];
325 va_list ap;
326 va_start(ap, format);
327 (void)format_user_message(error, format, ap, buffer, sizeof(buffer));
328 va_end(ap);
330 fprintf(stream, "%s", buffer);
334 /// Version of warn(3) that works with kyua_error_t objects.
336 /// \param error Error to append to the output. This is not released.
337 /// \param format User-specified message, as a formatting string.
338 /// \param ... Positional arguments to the format string.
339 void
340 kyua_error_warn(const kyua_error_t error, const char* format, ...)
342 char buffer[2048];
344 va_list ap;
345 va_start(ap, format);
346 (void)format_user_message(error, format, ap, buffer, sizeof(buffer));
347 va_end(ap);
349 warnx("%s", buffer);
353 /// Name of an generic error type.
354 const char* const kyua_generic_error_type = "generic";
357 /// Generates a user-friendly representation of the error.
359 /// \pre The error must be set.
361 /// \param error Error for which to generate a message.
362 /// \param output_buffer Buffer to hold the generated message.
363 /// \param output_size Length of output_buffer.
365 /// \return The number of bytes written to output_buffer, or a negative value if
366 /// there was an error.
367 static int
368 generic_format(const kyua_error_t error, char* const output_buffer,
369 const size_t output_size)
371 assert(kyua_error_is_type(error, kyua_generic_error_type));
373 const char* message = kyua_error_data(error);
374 return snprintf(output_buffer, output_size, "%s", message);
378 /// Constructs a new generic error.
380 /// \param message Textual description of the problem.
381 /// \param ... Positional arguments for the description.
383 /// \return The generated error.
384 kyua_error_t
385 kyua_generic_error_new(const char* message, ...)
387 char formatted[1024];
388 va_list ap;
390 va_start(ap, message);
391 (void)vsnprintf(formatted, sizeof(formatted), message, ap);
392 va_end(ap);
394 return kyua_error_new(kyua_generic_error_type, formatted, sizeof(formatted),
395 generic_format);
399 /// Name of a libc type.
400 const char* const kyua_libc_error_type = "libc";
403 /// Representation of a libc error.
404 struct libc_error_data {
405 /// Value of the errno captured during the error creation.
406 int original_errno;
408 /// Explanation of the problem that lead to the error.
409 char description[4096];
411 /// Shorthand for a libc_error_data structure.
412 typedef struct libc_error_data libc_error_data_t;
415 /// Generates a user-friendly representation of the error.
417 /// \pre The error must be set.
419 /// \param error Error for which to generate a message.
420 /// \param output_buffer Buffer to hold the generated message.
421 /// \param output_size Length of output_buffer.
423 /// \return The number of bytes written to output_buffer, or a negative value if
424 /// there was an error.
425 static int
426 libc_format(const kyua_error_t error, char* const output_buffer,
427 const size_t output_size)
429 assert(kyua_error_is_type(error, kyua_libc_error_type));
431 const libc_error_data_t* data = kyua_error_data(error);
432 return snprintf(output_buffer, output_size, "%s: %s", data->description,
433 strerror(data->original_errno));
437 /// Constructs a new libc error.
439 /// \param original_errno libc error code for this error.
440 /// \param description Textual description of the problem.
441 /// \param ... Positional arguments for the description.
443 /// \return The generated error.
444 kyua_error_t
445 kyua_libc_error_new(const int original_errno, const char* description, ...)
447 va_list ap;
449 const size_t data_size = sizeof(libc_error_data_t);
450 libc_error_data_t* data = (libc_error_data_t*)malloc(data_size);
451 if (data == NULL)
452 return kyua_oom_error_new();
454 data->original_errno = original_errno;
455 va_start(ap, description);
456 (void)vsnprintf(data->description, sizeof(data->description),
457 description, ap);
458 va_end(ap);
460 return kyua_error_new(kyua_libc_error_type, data, data_size, libc_format);
464 /// Extracts the original errno of a libc error.
466 /// \pre error must have been constructed by kyua_libc_error_new.
468 /// \param error The error object to access.
470 /// \return The libc error code.
472 kyua_libc_error_errno(const kyua_error_t error)
474 assert(kyua_error_is_type(error, kyua_libc_error_type));
476 const struct libc_error_data* data = kyua_error_data(error);
477 return data->original_errno;
481 /// Name of an OOM type.
482 const char* const kyua_oom_error_type = "oom";
485 /// Data of an out of memory error.
487 /// All error types are allocated in dynamic memory. However, doing so for
488 /// an out of memory error is not possible because, when we are out of
489 /// memory, we probably cannot allocate more memory to generate an error.
490 /// Therefore, we just keep a single static instance of the out of memory
491 /// error around all the time.
492 static struct kyua_error oom_error;
495 /// Generates a user-friendly representation of the error.
497 /// \pre The error must be set.
499 /// \param error Error for which to generate a message.
500 /// \param output_buffer Buffer to hold the generated message.
501 /// \param output_size Length of output_buffer.
503 /// \return The number of bytes written to output_buffer, or a negative value if
504 /// there was an error.
505 static int
506 oom_format(const kyua_error_t error, char* const output_buffer,
507 const size_t output_size)
509 assert(kyua_error_is_type(error, kyua_oom_error_type));
511 return snprintf(output_buffer, output_size, "Not enough memory");
515 /// Constructs a new out-of-memory error.
517 /// This will always succeed because we just return a reference to the
518 /// statically-allocated oom_error.
520 /// \return An error representing an out of memory condition.
521 kyua_error_t
522 kyua_oom_error_new(void)
524 // This is idempotent; no need to ensure that we call it only once.
525 #if defined(__minix) && !defined(NDEBUG)
526 const bool ok =
527 #endif /* defined(__minix) && !defined(NDEBUG) */
528 error_init(&oom_error, kyua_oom_error_type, NULL, 0, oom_format);
529 assert(ok);
531 return &oom_error;
535 /// Name of an usage error type.
536 const char* const kyua_usage_error_type = "usage";
539 /// Generates a user-friendly representation of the error.
541 /// \pre The error must be set.
543 /// \param error Error for which to generate a message.
544 /// \param output_buffer Buffer to hold the generated message.
545 /// \param output_size Length of output_buffer.
547 /// \return The number of bytes written to output_buffer, or a negative value if
548 /// there was an error.
549 static int
550 usage_format(const kyua_error_t error, char* const output_buffer,
551 const size_t output_size)
553 assert(kyua_error_is_type(error, kyua_usage_error_type));
555 const char* message = kyua_error_data(error);
556 return snprintf(output_buffer, output_size, "%s", message);
560 /// Constructs a new usage error.
562 /// \param message Textual description of the problem.
563 /// \param ... Positional arguments for the description.
565 /// \return The generated error.
566 kyua_error_t
567 kyua_usage_error_new(const char* message, ...)
569 char formatted[1024];
570 va_list ap;
572 va_start(ap, message);
573 (void)vsnprintf(formatted, sizeof(formatted), message, ap);
574 va_end(ap);
576 return kyua_error_new(kyua_usage_error_type, formatted, sizeof(formatted),
577 usage_format);