| /* libnih |
| * |
| * Copyright © 2009 Scott James Remnant <scott@netsplit.com>. |
| * Copyright © 2009 Canonical Ltd. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sublicense, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #ifndef NIH_ERROR_H |
| #define NIH_ERROR_H |
| |
| /** |
| * Many functions in libnih use these functions to report information about |
| * errors, those that don't use the ordinary errno mechnism which can |
| * also be reported within this framework. |
| * |
| * Errors are raised as NihError structures, kept globally. Only one error |
| * may be active at any one time, raising an error when another is already |
| * raised will result in an assertion. |
| * |
| * Errors are raised with the nih_error_raise() or nih_error_raise_printf() |
| * functions, passing the error number and a human-readable messages. |
| * |
| * System errors can be raised with nih_error_raise_system(), and both |
| * caught errors and self-allocated errors can be raised with |
| * nih_error_raise_error(). |
| * |
| * You then report the error condition through your return value, or some |
| * other stack-based method. |
| * |
| * A higher function that wishes to handle the error calls nih_error_get() |
| * to retrieve it, it's an error to do so if you do not know that an error |
| * is pending. This returns the currently raised error structure. |
| * |
| * To clear the error, it should be freed with nih_free(). To return the |
| * error from your own function, simply don't free it. |
| * |
| * Errors may be partitioned using contexts, a new context is pushed with |
| * nih_error_push_context(); any errors raised are now stored in this |
| * context and any previous raised errors are hidden from view. The context |
| * can be popped again with nih_error_pop_context() provided that any raised |
| * error has been dealt with. The previously hidden raised errors are now |
| * visible again. |
| * |
| * To raise an error from one context, into another, you can't simply call |
| * nih_error_get() before nih_error_pop_context() since the latter will |
| * assert because of the unfreed error. Instead nih_error_steal() may be |
| * used which returns the error as nih_error_get() does but also removes |
| * it from the context. |
| * |
| * nih_error_steal() may also be used to stash errors before trying an |
| * alternate code path. |
| **/ |
| |
| #include <nih/macros.h> |
| |
| #include <errno.h> |
| #include <string.h> |
| |
| |
| /** |
| * NihError: |
| * @filename: filename where the error was raised, |
| * @line: line number of @filename where the error was raised, |
| * @function: function name the error was raised within, |
| * @number: numeric identifier, |
| * @message: human-readable message. |
| * |
| * This structure represents an error, defining the error @number for |
| * programmers to capture and handle them and a human-readable @message |
| * that should be pre-translated. |
| * |
| * The structure is allocated when an error occurs, and only one structure |
| * may exist in one context at a time; when another error is raised, the |
| * existing error, if any, is freed. |
| * |
| * You may also use this structure as the header for more complicated error |
| * objects, in which case do not worry about setting @filename, @line or |
| * @function since these are set when you call nih_error_raise_error(). |
| **/ |
| typedef struct nih_error { |
| const char *filename; |
| int line; |
| const char *function; |
| |
| int number; |
| const char *message; |
| } NihError; |
| |
| |
| /** |
| * nih_error_raise: |
| * @number: numeric identifier, |
| * @message: human-readable message. |
| * |
| * Raises an error with the given details in the current error context, |
| * if an unhandled error already exists then an error message is emmitted |
| * through the logging system; you should try to avoid this. |
| * |
| * @message should be a static string, as it will not be freed when the |
| * error object is. |
| **/ |
| #define nih_error_raise(number, message) \ |
| _nih_error_raise (__FILE__, __LINE__, __FUNCTION__, number, message) |
| |
| /** |
| * nih_error_raise_printf: |
| * @number: numeric identifier, |
| * @format: format string for human-readable message. |
| * |
| * Raises an error with the given details in the current error context, |
| * if an unhandled error already exists then an error message is emmitted |
| * through the logging system; you should try to avoid this. |
| * |
| * The human-readable message for the error is parsed according to @format, |
| * and allocated as a child of the error object so that it is freed. |
| **/ |
| #define nih_error_raise_printf(number, format, ...) \ |
| _nih_error_raise_printf (__FILE__, __LINE__, __FUNCTION__, \ |
| number, format, __VA_ARGS__) |
| |
| /** |
| * nih_error_raise_system: |
| * |
| * Raises an error with details taken from the current value of errno, |
| * if an unhandled error already exists then an error message is emmitted |
| * through the logging system; you should try to avoid this. |
| **/ |
| #define nih_error_raise_system() \ |
| _nih_error_raise_system (__FILE__, __LINE__, __FUNCTION__) |
| |
| /** |
| * nih_error_raise_no_memory: |
| * |
| * Raises an ENOMEM system error, if an unhandled error already exists then |
| * an error message is emitted through the logging system; you should try |
| * to avoid this. |
| **/ |
| #define nih_error_raise_no_memory() \ |
| _nih_error_raise (__FILE__, __LINE__, __FUNCTION__, \ |
| ENOMEM, strerror (ENOMEM)) |
| |
| /** |
| * nih_error_raise_error: |
| * @error: existing object to raise. |
| * |
| * Raises the existing error object in the current error context, |
| * if an unhandled error already exists then an error message is emmitted |
| * through the logging system; you should try to avoid this. |
| * |
| * This is normally used to raise a taken error that has not been handled, |
| * or to raise a custom error object. |
| * |
| * The destructor of @error will be overwritten so that the context can |
| * be cleared when the error is freed. |
| **/ |
| #define nih_error_raise_error(error) \ |
| _nih_error_raise_error (__FILE__, __LINE__, __FUNCTION__, error) |
| |
| |
| /** |
| * nih_return_error: |
| * @retval: return value for function, |
| * @number: numeric identifier, |
| * @message: human-readable message. |
| * |
| * Raises an error with the given details in the current error context, |
| * if an unhandled error already exists then an error message is emmitted |
| * through the logging system; you should try to avoid this. |
| * |
| * Will return from the current function with @retval, which may be left |
| * empty to return from a void function. |
| **/ |
| #define nih_return_error(retval, number, message) \ |
| do { \ |
| nih_error_raise (number, message); \ |
| return retval; \ |
| } while (0) |
| |
| /** |
| * nih_return_system_error: |
| * @retval: return value for function. |
| * |
| * Raises an error with details taken from the current value of errno, |
| * if an unhandled error already exists then an error message is emmitted |
| * through the logging system; you should try to avoid this. |
| * |
| * Will return from the current function with @retval, which may be left |
| * empty to return from a void function. |
| **/ |
| #define nih_return_system_error(retval) \ |
| do { \ |
| nih_error_raise_system (); \ |
| return retval; \ |
| } while (0) |
| |
| /** |
| * nih_return_no_memory_error: |
| * @retval: return value for function. |
| * |
| * Raises an ENOMEM system error, if an unhandled error already exists then |
| * an error message is emitted through the logging system; you should try |
| * to avoid this. |
| * |
| * Will return from the current function with @retval, which may be left |
| * empty to return from a void function. |
| **/ |
| #define nih_return_no_memory_error(retval) \ |
| do { \ |
| nih_error_raise_no_memory (); \ |
| return retval; \ |
| } while (0) |
| |
| |
| /** |
| * NIH_SHOULD: |
| * @_e: C expression. |
| * |
| * Repeats the expression @_e until it either yields a true value, or |
| * raises an error other than ENOMEM. |
| * |
| * This can only be used when the expression always raises an error if |
| * it does not yield a true value. |
| * |
| * The raised error remains raised and should be dealt with following |
| * this function, thus you should store the value of the expression so you |
| * know whether or not an error occurred. |
| * |
| * Returns: value of expression @_e which will be evaluated as many times |
| * as necessary to become true. |
| **/ |
| #define NIH_SHOULD(_e) \ |
| ({ \ |
| typeof (_e) __ret; \ |
| while (! (__ret = (_e))) { \ |
| NihError *_nih_should_err; \ |
| \ |
| _nih_should_err = nih_error_get (); \ |
| if (_nih_should_err->number == ENOMEM) { \ |
| nih_free (_nih_should_err); \ |
| } else { \ |
| break; \ |
| } \ |
| } \ |
| __ret; \ |
| }) |
| |
| |
| NIH_BEGIN_EXTERN |
| |
| void nih_error_init (void); |
| |
| void _nih_error_raise (const char *filename, int line, |
| const char *function, |
| int number, const char *message); |
| void _nih_error_raise_printf (const char *filename, int line, |
| const char *function, |
| int number, const char *format, ...) |
| __attribute__ ((format (printf, 5, 6))); |
| void _nih_error_raise_system (const char *filename, int line, |
| const char *function); |
| void _nih_error_raise_error (const char *filename, int line, |
| const char *function, |
| NihError *error); |
| |
| NihError *nih_error_get (void) |
| __attribute__ ((warn_unused_result)); |
| NihError *nih_error_steal (void) |
| __attribute__ ((warn_unused_result)); |
| |
| void nih_error_push_context (void); |
| void nih_error_pop_context (void); |
| |
| NIH_END_EXTERN |
| |
| #endif /* NIH_ERROR_H */ |