X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgerror.c;h=4eed58e9b7980d32d3905fc391eb195afacf3b67;hb=2a53b4d0e2c98a14aedf31e38f0ad1fb2e8fe26f;hp=9a0729f25244caa3b2aee5e9766caba79936e3ba;hpb=a412fb16541620ed72da86daac0774afe4703d9d;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gerror.c b/glib/gerror.c index 9a0729f..4eed58e 100644 --- a/glib/gerror.c +++ b/glib/gerror.c @@ -12,52 +12,396 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library; if not, see . */ /* * Modified by the GLib Team and others 1997-2000. See the AUTHORS * file for a list of people on the GLib Team. See the ChangeLog * files for a list of changes. These files are distributed with - * GLib at ftp://ftp.gtk.org/pub/gtk/. + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +/** + * SECTION:error_reporting + * @Title: Error Reporting + * @Short_description: a system for reporting errors + * + * GLib provides a standard method of reporting errors from a called + * function to the calling code. (This is the same problem solved by + * exceptions in other languages.) It's important to understand that + * this method is both a data type (the #GError struct) and a set of + * rules. If you use #GError incorrectly, then your code will not + * properly interoperate with other code that uses #GError, and users + * of your API will probably get confused. + * + * First and foremost: #GError should only be used to report recoverable + * runtime errors, never to report programming errors. If the programmer + * has screwed up, then you should use g_warning(), g_return_if_fail(), + * g_assert(), g_error(), or some similar facility. (Incidentally, + * remember that the g_error() function should only be used for + * programming errors, it should not be used to print any error + * reportable via #GError.) + * + * Examples of recoverable runtime errors are "file not found" or + * "failed to parse input." Examples of programming errors are "NULL + * passed to strcmp()" or "attempted to free the same pointer twice." + * These two kinds of errors are fundamentally different: runtime errors + * should be handled or reported to the user, programming errors should + * be eliminated by fixing the bug in the program. This is why most + * functions in GLib and GTK+ do not use the #GError facility. + * + * Functions that can fail take a return location for a #GError as their + * last argument. For example: + * |[ + * gboolean g_file_get_contents (const gchar *filename, + * gchar **contents, + * gsize *length, + * GError **error); + * ]| + * If you pass a non-%NULL value for the `error` argument, it should + * point to a location where an error can be placed. For example: + * |[ + * gchar *contents; + * GError *err = NULL; + * + * g_file_get_contents ("foo.txt", &contents, NULL, &err); + * g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL)); + * if (err != NULL) + * { + * // Report error to user, and free error + * g_assert (contents == NULL); + * fprintf (stderr, "Unable to read file: %s\n", err->message); + * g_error_free (err); + * } + * else + * { + * // Use file contents + * g_assert (contents != NULL); + * } + * ]| + * Note that `err != NULL` in this example is a reliable indicator + * of whether g_file_get_contents() failed. Additionally, + * g_file_get_contents() returns a boolean which + * indicates whether it was successful. + * + * Because g_file_get_contents() returns %FALSE on failure, if you + * are only interested in whether it failed and don't need to display + * an error message, you can pass %NULL for the @error argument: + * |[ + * if (g_file_get_contents ("foo.txt", &contents, NULL, NULL)) // ignore errors + * // no error occurred + * ; + * else + * // error + * ; + * ]| + * + * The #GError object contains three fields: @domain indicates the module + * the error-reporting function is located in, @code indicates the specific + * error that occurred, and @message is a user-readable error message with + * as many details as possible. Several functions are provided to deal + * with an error received from a called function: g_error_matches() + * returns %TRUE if the error matches a given domain and code, + * g_propagate_error() copies an error into an error location (so the + * calling function will receive it), and g_clear_error() clears an + * error location by freeing the error and resetting the location to + * %NULL. To display an error to the user, simply display the @message, + * perhaps along with additional context known only to the calling + * function (the file being opened, or whatever - though in the + * g_file_get_contents() case, the @message already contains a filename). + * + * When implementing a function that can report errors, the basic + * tool is g_set_error(). Typically, if a fatal error occurs you + * want to g_set_error(), then return immediately. g_set_error() + * does nothing if the error location passed to it is %NULL. + * Here's an example: + * |[ + * gint + * foo_open_file (GError **error) + * { + * gint fd; + * + * fd = open ("file.txt", O_RDONLY); + * + * if (fd < 0) + * { + * g_set_error (error, + * FOO_ERROR, // error domain + * FOO_ERROR_BLAH, // error code + * "Failed to open file: %s", // error message format string + * g_strerror (errno)); + * return -1; + * } + * else + * return fd; + * } + * ]| + * + * Things are somewhat more complicated if you yourself call another + * function that can report a #GError. If the sub-function indicates + * fatal errors in some way other than reporting a #GError, such as + * by returning %TRUE on success, you can simply do the following: + * |[ + * gboolean + * my_function_that_can_fail (GError **err) + * { + * g_return_val_if_fail (err == NULL || *err == NULL, FALSE); + * + * if (!sub_function_that_can_fail (err)) + * { + * // assert that error was set by the sub-function + * g_assert (err == NULL || *err != NULL); + * return FALSE; + * } + * + * // otherwise continue, no error occurred + * g_assert (err == NULL || *err == NULL); + * } + * ]| + * + * If the sub-function does not indicate errors other than by + * reporting a #GError, you need to create a temporary #GError + * since the passed-in one may be %NULL. g_propagate_error() is + * intended for use in this case. + * |[ + * gboolean + * my_function_that_can_fail (GError **err) + * { + * GError *tmp_error; + * + * g_return_val_if_fail (err == NULL || *err == NULL, FALSE); + * + * tmp_error = NULL; + * sub_function_that_can_fail (&tmp_error); + * + * if (tmp_error != NULL) + * { + * // store tmp_error in err, if err != NULL, + * // otherwise call g_error_free() on tmp_error + * g_propagate_error (err, tmp_error); + * return FALSE; + * } + * + * // otherwise continue, no error occurred + * } + * ]| + * + * Error pileups are always a bug. For example, this code is incorrect: + * |[ + * gboolean + * my_function_that_can_fail (GError **err) + * { + * GError *tmp_error; + * + * g_return_val_if_fail (err == NULL || *err == NULL, FALSE); + * + * tmp_error = NULL; + * sub_function_that_can_fail (&tmp_error); + * other_function_that_can_fail (&tmp_error); + * + * if (tmp_error != NULL) + * { + * g_propagate_error (err, tmp_error); + * return FALSE; + * } + * } + * ]| + * @tmp_error should be checked immediately after sub_function_that_can_fail(), + * and either cleared or propagated upward. The rule is: after each error, + * you must either handle the error, or return it to the calling function. + * + * Note that passing %NULL for the error location is the equivalent + * of handling an error by always doing nothing about it. So the + * following code is fine, assuming errors in sub_function_that_can_fail() + * are not fatal to my_function_that_can_fail(): + * |[ + * gboolean + * my_function_that_can_fail (GError **err) + * { + * GError *tmp_error; + * + * g_return_val_if_fail (err == NULL || *err == NULL, FALSE); + * + * sub_function_that_can_fail (NULL); // ignore errors + * + * tmp_error = NULL; + * other_function_that_can_fail (&tmp_error); + * + * if (tmp_error != NULL) + * { + * g_propagate_error (err, tmp_error); + * return FALSE; + * } + * } + * ]| + * + * Note that passing %NULL for the error location ignores errors; + * it's equivalent to + * `try { sub_function_that_can_fail (); } catch (...) {}` + * in C++. It does not mean to leave errors unhandled; it means + * to handle them by doing nothing. + * + * Error domains and codes are conventionally named as follows: + * + * - The error domain is called __ERROR, + * for example %G_SPAWN_ERROR or %G_THREAD_ERROR: + * |[ + * #define G_SPAWN_ERROR g_spawn_error_quark () + * + * GQuark + * g_spawn_error_quark (void) + * { + * return g_quark_from_static_string ("g-spawn-error-quark"); + * } + * ]| + * + * - The quark function for the error domain is called + * __error_quark, + * for example g_spawn_error_quark() or g_thread_error_quark(). + * + * - The error codes are in an enumeration called + * Error; + * for example, #GThreadError or #GSpawnError. + * + * - Members of the error code enumeration are called + * __ERROR_, + * for example %G_SPAWN_ERROR_FORK or %G_THREAD_ERROR_AGAIN. + * + * - If there's a "generic" or "unknown" error code for unrecoverable + * errors it doesn't make sense to distinguish with specific codes, + * it should be called __ERROR_FAILED, + * for example %G_SPAWN_ERROR_FAILED. In the case of error code + * enumerations that may be extended in future releases, you should + * generally not handle this error code explicitly, but should + * instead treat any unrecognized error code as equivalent to + * FAILED. + * + * Summary of rules for use of #GError: + * + * - Do not report programming errors via #GError. + * + * - The last argument of a function that returns an error should + * be a location where a #GError can be placed (i.e. "#GError** error"). + * If #GError is used with varargs, the #GError** should be the last + * argument before the "...". + * + * - The caller may pass %NULL for the #GError** if they are not interested + * in details of the exact error that occurred. + * + * - If %NULL is passed for the #GError** argument, then errors should + * not be returned to the caller, but your function should still + * abort and return if an error occurs. That is, control flow should + * not be affected by whether the caller wants to get a #GError. + * + * - If a #GError is reported, then your function by definition had a + * fatal failure and did not complete whatever it was supposed to do. + * If the failure was not fatal, then you handled it and you should not + * report it. If it was fatal, then you must report it and discontinue + * whatever you were doing immediately. + * + * - If a #GError is reported, out parameters are not guaranteed to + * be set to any defined value. + * + * - A #GError* must be initialized to %NULL before passing its address + * to a function that can report errors. + * + * - "Piling up" errors is always a bug. That is, if you assign a + * new #GError to a #GError* that is non-%NULL, thus overwriting + * the previous error, it indicates that you should have aborted + * the operation instead of continuing. If you were able to continue, + * you should have cleared the previous error with g_clear_error(). + * g_set_error() will complain if you pile up errors. + * + * - By convention, if you return a boolean value indicating success + * then %TRUE means success and %FALSE means failure. + * Avoid creating functions which have a boolean + * return value and a GError parameter, but where the boolean does + * something other than signal whether the GError is set. Among other + * problems, it requires C callers to allocate a temporary error. Instead, + * provide a "gboolean *" out parameter. There are functions in GLib + * itself such as g_key_file_has_key() that are deprecated because of this. + * + * If %FALSE is + * returned, the error must be set to a non-%NULL value. + * One exception to this is that in situations that are + * already considered to be undefined behaviour (such as when a + * g_return_val_if_fail() check fails), the error need not be set. + * Instead of checking separately whether the error is set, callers + * should ensure that they do not provoke undefined behaviour, then + * assume that the error will be set on failure. + * + * - A %NULL return value is also frequently used to mean that an error + * occurred. You should make clear in your documentation whether %NULL + * is a valid return value in non-error cases; if %NULL is a valid value, + * then users must check whether an error was returned to see if the + * function succeeded. + * + * - When implementing a function that can report errors, you may want + * to add a check at the top of your function that the error return + * location is either %NULL or contains a %NULL error (e.g. + * `g_return_if_fail (error == NULL || *error == NULL);`). */ #include "config.h" -#include "glib.h" +#include "gerror.h" +#include "gslice.h" +#include "gstrfuncs.h" +#include "gtestutils.h" -static GError* -g_error_new_valist(GQuark domain, - gint code, - const gchar *format, - va_list args) +/** + * g_error_new_valist: + * @domain: error domain + * @code: error code + * @format: printf()-style format for error message + * @args: #va_list of parameters for the message format + * + * Creates a new #GError with the given @domain and @code, + * and a message formatted with @format. + * + * Returns: a new #GError + * + * Since: 2.22 + */ +GError* +g_error_new_valist (GQuark domain, + gint code, + const gchar *format, + va_list args) { GError *error; - - error = g_new (GError, 1); - + + /* Historically, GError allowed this (although it was never meant to work), + * and it has significant use in the wild, which g_return_val_if_fail + * would break. It should maybe g_return_val_if_fail in GLib 4. + * (GNOME#660371, GNOME#560482) + */ + g_warn_if_fail (domain != 0); + g_warn_if_fail (format != NULL); + + error = g_slice_new (GError); + error->domain = domain; error->code = code; error->message = g_strdup_vprintf (format, args); - + return error; } /** * g_error_new: - * @domain: error domain + * @domain: error domain * @code: error code * @format: printf()-style format for error message - * @Varargs: parameters for message format - * + * @...: parameters for message format + * * Creates a new #GError with the given @domain and @code, * and a message formatted with @format. - * - * Return value: a new #GError - **/ + * + * Returns: a new #GError + */ GError* g_error_new (GQuark domain, gint code, @@ -82,13 +426,13 @@ g_error_new (GQuark domain, * @domain: error domain * @code: error code * @message: error message - * - * Creates a new #GError; unlike g_error_new(), @message is not - * a printf()-style format string. Use this - * function if @message contains text you don't have control over, + * + * Creates a new #GError; unlike g_error_new(), @message is + * not a printf()-style format string. Use this function if + * @message contains text you don't have control over, * that could include printf() escape sequences. - * - * Return value: a new #GError + * + * Returns: a new #GError **/ GError* g_error_new_literal (GQuark domain, @@ -100,12 +444,12 @@ g_error_new_literal (GQuark domain, g_return_val_if_fail (message != NULL, NULL); g_return_val_if_fail (domain != 0, NULL); - err = g_new (GError, 1); + err = g_slice_new (GError); err->domain = domain; err->code = code; err->message = g_strdup (message); - + return err; } @@ -114,34 +458,36 @@ g_error_new_literal (GQuark domain, * @error: a #GError * * Frees a #GError and associated resources. - * - **/ + */ void g_error_free (GError *error) { - g_return_if_fail (error != NULL); + g_return_if_fail (error != NULL); g_free (error->message); - g_free (error); + g_slice_free (GError, error); } /** * g_error_copy: * @error: a #GError - * + * * Makes a copy of @error. - * - * Return value: a new #GError - **/ + * + * Returns: a new #GError + */ GError* g_error_copy (const GError *error) { GError *copy; - + g_return_val_if_fail (error != NULL, NULL); + /* See g_error_new_valist for why these don't return */ + g_warn_if_fail (error->domain != 0); + g_warn_if_fail (error->message != NULL); - copy = g_new (GError, 1); + copy = g_slice_new (GError); *copy = *error; @@ -152,15 +498,23 @@ g_error_copy (const GError *error) /** * g_error_matches: - * @error: a #GError + * @error: (allow-none): a #GError or %NULL * @domain: an error domain * @code: an error code - * + * * Returns %TRUE if @error matches @domain and @code, %FALSE - * otherwise. - * - * Return value: whether @error has @domain and @code - **/ + * otherwise. In particular, when @error is %NULL, %FALSE will + * be returned. + * + * If @domain contains a `FAILED` (or otherwise generic) error code, + * you should generally not check for it explicitly, but should + * instead treat any not-explicitly-recognized error code as being + * equilalent to the `FAILED` code. This way, if the domain is + * extended in the future to provide a more specific error code for + * a certain case, your code will still work. + * + * Returns: whether @error has @domain and @code + */ gboolean g_error_matches (const GError *error, GQuark domain, @@ -177,15 +531,15 @@ g_error_matches (const GError *error, /** * g_set_error: - * @err: a return location for a #GError, or %NULL + * @err: (allow-none): a return location for a #GError, or %NULL * @domain: error domain - * @code: error code + * @code: error code * @format: printf()-style format - * @Varargs: args for @format - * - * Does nothing if @err is %NULL; if @err is non-%NULL, then *@err must - * be %NULL. A new #GError is created and assigned to *@err. - **/ + * @...: args for @format + * + * Does nothing if @err is %NULL; if @err is non-%NULL, then *@err + * must be %NULL. A new #GError is created and assigned to *@err. + */ void g_set_error (GError **err, GQuark domain, @@ -194,12 +548,12 @@ g_set_error (GError **err, ...) { GError *new; - + va_list args; if (err == NULL) return; - + va_start (args, format); new = g_error_new_valist (domain, code, format, args); va_end (args); @@ -207,23 +561,60 @@ g_set_error (GError **err, if (*err == NULL) *err = new; else - g_warning (ERROR_OVERWRITTEN_WARNING, new->message); + { + g_warning (ERROR_OVERWRITTEN_WARNING, new->message); + g_error_free (new); + } +} + +/** + * g_set_error_literal: + * @err: (allow-none): a return location for a #GError, or %NULL + * @domain: error domain + * @code: error code + * @message: error message + * + * Does nothing if @err is %NULL; if @err is non-%NULL, then *@err + * must be %NULL. A new #GError is created and assigned to *@err. + * Unlike g_set_error(), @message is not a printf()-style format string. + * Use this function if @message contains text you don't have control over, + * that could include printf() escape sequences. + * + * Since: 2.18 + */ +void +g_set_error_literal (GError **err, + GQuark domain, + gint code, + const gchar *message) +{ + if (err == NULL) + return; + + if (*err == NULL) + *err = g_error_new_literal (domain, code, message); + else + g_warning (ERROR_OVERWRITTEN_WARNING, message); } /** * g_propagate_error: * @dest: error return location * @src: error to move into the return location - * - * If @dest is %NULL, free @src; otherwise, - * moves @src into *@dest. *@dest must be %NULL. - **/ -void -g_propagate_error (GError **dest, - GError *src) + * + * If @dest is %NULL, free @src; otherwise, moves @src into *@dest. + * The error variable @dest points to must be %NULL. + * + * Note that @src is no longer valid after this call. If you want + * to keep using the same GError*, you need to set it to %NULL + * after calling this function on it. + */ +void +g_propagate_error (GError **dest, + GError *src) { g_return_if_fail (src != NULL); - + if (dest == NULL) { if (src) @@ -233,7 +624,10 @@ g_propagate_error (GError **dest, else { if (*dest != NULL) - g_warning (ERROR_OVERWRITTEN_WARNING, src->message); + { + g_warning (ERROR_OVERWRITTEN_WARNING, src->message); + g_error_free (src); + } else *dest = src; } @@ -242,10 +636,10 @@ g_propagate_error (GError **dest, /** * g_clear_error: * @err: a #GError return location - * + * * If @err is %NULL, does nothing. If @err is non-%NULL, * calls g_error_free() on *@err and sets *@err to %NULL. - **/ + */ void g_clear_error (GError **err) { @@ -255,3 +649,81 @@ g_clear_error (GError **err) *err = NULL; } } + +G_GNUC_PRINTF(2, 0) +static void +g_error_add_prefix (gchar **string, + const gchar *format, + va_list ap) +{ + gchar *oldstring; + gchar *prefix; + + prefix = g_strdup_vprintf (format, ap); + oldstring = *string; + *string = g_strconcat (prefix, oldstring, NULL); + g_free (oldstring); + g_free (prefix); +} + +/** + * g_prefix_error: + * @err: (allow-none): a return location for a #GError, or %NULL + * @format: printf()-style format string + * @...: arguments to @format + * + * Formats a string according to @format and prefix it to an existing + * error message. If @err is %NULL (ie: no error variable) then do + * nothing. + * + * If *@err is %NULL (ie: an error variable is present but there is no + * error condition) then also do nothing. Whether or not it makes sense + * to take advantage of this feature is up to you. + * + * Since: 2.16 + */ +void +g_prefix_error (GError **err, + const gchar *format, + ...) +{ + if (err && *err) + { + va_list ap; + + va_start (ap, format); + g_error_add_prefix (&(*err)->message, format, ap); + va_end (ap); + } +} + +/** + * g_propagate_prefixed_error: + * @dest: error return location + * @src: error to move into the return location + * @format: printf()-style format string + * @...: arguments to @format + * + * If @dest is %NULL, free @src; otherwise, moves @src into *@dest. + * *@dest must be %NULL. After the move, add a prefix as with + * g_prefix_error(). + * + * Since: 2.16 + **/ +void +g_propagate_prefixed_error (GError **dest, + GError *src, + const gchar *format, + ...) +{ + g_propagate_error (dest, src); + + if (dest && *dest) + { + va_list ap; + + va_start (ap, format); + g_error_add_prefix (&(*dest)->message, format, ap); + va_end (ap); + } +}