mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-22 00:48:53 +02:00
Move GError docs inline and ditch template
This commit is contained in:
1
docs/reference/glib/tmpl/.gitignore
vendored
1
docs/reference/glib/tmpl/.gitignore
vendored
@@ -13,6 +13,7 @@ conversions.sgml
|
|||||||
datasets.sgml
|
datasets.sgml
|
||||||
datalist.sgml
|
datalist.sgml
|
||||||
date-time.sgml
|
date-time.sgml
|
||||||
|
error_reporting.sgml
|
||||||
ghostutils.sgml
|
ghostutils.sgml
|
||||||
gregex.sgml
|
gregex.sgml
|
||||||
gurifuncs.sgml
|
gurifuncs.sgml
|
||||||
|
@@ -1,531 +0,0 @@
|
|||||||
<!-- ##### SECTION Title ##### -->
|
|
||||||
Error Reporting
|
|
||||||
|
|
||||||
<!-- ##### SECTION Short_Description ##### -->
|
|
||||||
a system for reporting errors
|
|
||||||
|
|
||||||
<!-- ##### SECTION Long_Description ##### -->
|
|
||||||
|
|
||||||
<para>
|
|
||||||
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
|
|
||||||
<emphasis>data type</emphasis> (the #GError object) and a <emphasis>set of
|
|
||||||
rules.</emphasis> 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.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
First and foremost: <emphasis>#GError should only be used to report
|
|
||||||
recoverable runtime errors, never to report programming errors.</emphasis> 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
|
|
||||||
<emphasis>only</emphasis> be used for programming errors, it should not be used
|
|
||||||
to print any error reportable via #GError.)
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
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.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Functions that can fail take a return location for a #GError as their last argument.
|
|
||||||
For example:
|
|
||||||
<informalexample><programlisting>
|
|
||||||
gboolean g_file_get_contents (const gchar *filename,
|
|
||||||
gchar **contents,
|
|
||||||
gsize *length,
|
|
||||||
GError **error);
|
|
||||||
</programlisting></informalexample>
|
|
||||||
If you pass a non-%NULL value for the <literal>error</literal> argument, it should
|
|
||||||
point to a location where an error can be placed. For example:
|
|
||||||
<informalexample><programlisting>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
</programlisting></informalexample>
|
|
||||||
Note that <literal>err != NULL</literal> in this example is a
|
|
||||||
<emphasis>reliable</emphasis> indicator of whether
|
|
||||||
g_file_get_contents() failed. Additionally, g_file_get_contents() returns
|
|
||||||
a boolean which indicates whether it was successful.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
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 <literal>error</literal> argument:
|
|
||||||
<informalexample><programlisting>
|
|
||||||
if (g_file_get_contents ("foo.txt", &contents, NULL, NULL)) /* ignore errors */
|
|
||||||
/* no error occurred */ ;
|
|
||||||
else
|
|
||||||
/* error */ ;
|
|
||||||
</programlisting></informalexample>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The #GError object contains three fields: <literal>domain</literal> indicates
|
|
||||||
the module the error-reporting function is located in, <literal>code</literal>
|
|
||||||
indicates the specific error that occurred, and <literal>message</literal> 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 <literal>error->message</literal>, 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,
|
|
||||||
<literal>error->message</literal> already contains a filename).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
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:
|
|
||||||
<informalexample><programlisting>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
</programlisting></informalexample>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
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:
|
|
||||||
<informalexample><programlisting>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
</programlisting></informalexample>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
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.
|
|
||||||
<informalexample><programlisting>
|
|
||||||
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 */
|
|
||||||
}
|
|
||||||
</programlisting></informalexample>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Error pileups are always a bug. For example, this code is incorrect:
|
|
||||||
<informalexample><programlisting>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</programlisting></informalexample>
|
|
||||||
<literal>tmp_error</literal> should be checked immediately after
|
|
||||||
<function>sub_function_that_can_fail()</function>, and either cleared or propagated upward. The rule
|
|
||||||
is: <emphasis>after each error, you must either handle the error, or return it to the
|
|
||||||
calling function</emphasis>. 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 <function>sub_function_that_can_fail()</function> are not
|
|
||||||
fatal to <function>my_function_that_can_fail()</function>:
|
|
||||||
<informalexample><programlisting>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</programlisting></informalexample>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Note that passing %NULL for the error location <emphasis>ignores</emphasis>
|
|
||||||
errors; it's equivalent to <literal>try { sub_function_that_can_fail (); } catch
|
|
||||||
(...) {}</literal> in C++. It does <emphasis>not</emphasis> mean to leave errors
|
|
||||||
unhandled; it means to handle them by doing nothing.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Error domains and codes are conventionally named as follows:
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
The error domain is called
|
|
||||||
<literal><NAMESPACE>_<MODULE>_ERROR</literal>, for example
|
|
||||||
%G_SPAWN_ERROR or %G_THREAD_ERROR:
|
|
||||||
<informalexample><programlisting>
|
|
||||||
#define G_SPAWN_ERROR g_spawn_error_quark (<!-- -->)
|
|
||||||
|
|
||||||
GQuark
|
|
||||||
g_spawn_error_quark (void)
|
|
||||||
{
|
|
||||||
return g_quark_from_static_string ("g-spawn-error-quark");
|
|
||||||
}
|
|
||||||
</programlisting></informalexample>
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
The quark function for the error domain is called <literal><namespace>_<module>_error_quark</literal>, for example g_spawn_error_quark() or %g_thread_error_quark().
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
The error codes are in an enumeration called
|
|
||||||
<literal><Namespace><Module>Error</literal>; for example,
|
|
||||||
#GThreadError or #GSpawnError.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Members of the error code enumeration are called <literal><NAMESPACE>_<MODULE>_ERROR_<CODE></literal>, for example %G_SPAWN_ERROR_FORK or %G_THREAD_ERROR_AGAIN.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
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
|
|
||||||
<literal><NAMESPACE>_<MODULE>_ERROR_FAILED</literal>, for
|
|
||||||
example %G_SPAWN_ERROR_FAILED or %G_THREAD_ERROR_FAILED.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Summary of rules for use of #GError:
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Do not report programming errors via #GError.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
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 "...".
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
The caller may pass %NULL for the #GError** if they are not interested
|
|
||||||
in details of the exact error that occurred.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
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.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
If a #GError is reported, then your function by definition
|
|
||||||
<emphasis>had a fatal failure and did not complete whatever it was supposed
|
|
||||||
to do</emphasis>. 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.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
A #GError* must be initialized to %NULL before passing its address to
|
|
||||||
a function that can report errors.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
"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.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
By convention, if you return a boolean value indicating success
|
|
||||||
then %TRUE means success and %FALSE means failure. If %FALSE is returned,
|
|
||||||
the error <emphasis>must</emphasis> be set to a non-%NULL value.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
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.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
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. <literal>g_return_if_fail (error == NULL || *error ==
|
|
||||||
NULL);</literal>).
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<!-- ##### SECTION See_Also ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<!-- ##### SECTION Stability_Level ##### -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### SECTION Image ##### -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### STRUCT GError ##### -->
|
|
||||||
<para>
|
|
||||||
The <structname>GError</structname> structure contains
|
|
||||||
information about an error that has occurred.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@domain: error domain, e.g. #G_FILE_ERROR.
|
|
||||||
@code: error code, e.g. %G_FILE_ERROR_NOENT.
|
|
||||||
@message: human-readable informative error message.
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_error_new ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@domain:
|
|
||||||
@code:
|
|
||||||
@format:
|
|
||||||
@Varargs:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_error_new_literal ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@domain:
|
|
||||||
@code:
|
|
||||||
@message:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_error_new_valist ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@domain:
|
|
||||||
@code:
|
|
||||||
@format:
|
|
||||||
@args:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_error_free ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@error:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_error_copy ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@error:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_error_matches ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@error:
|
|
||||||
@domain:
|
|
||||||
@code:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_set_error ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@err:
|
|
||||||
@domain:
|
|
||||||
@code:
|
|
||||||
@format:
|
|
||||||
@Varargs:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_set_error_literal ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@err:
|
|
||||||
@domain:
|
|
||||||
@code:
|
|
||||||
@message:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_propagate_error ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@dest:
|
|
||||||
@src:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_clear_error ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@err: <!--
|
|
||||||
Local variables:
|
|
||||||
mode: sgml
|
|
||||||
sgml-parent-document: ("../glib-docs.sgml" "book" "refsect2" "")
|
|
||||||
End:
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_prefix_error ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@err:
|
|
||||||
@format:
|
|
||||||
@Varargs:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_propagate_prefixed_error ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@dest:
|
|
||||||
@src:
|
|
||||||
@format:
|
|
||||||
@Varargs:
|
|
||||||
|
|
||||||
|
|
324
glib/gerror.c
324
glib/gerror.c
@@ -24,6 +24,330 @@
|
|||||||
* 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 <emphasis>data type</emphasis> (the #GError
|
||||||
|
* object) and a <emphasis>set of rules.</emphasis> 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: <emphasis>#GError should only be used to report
|
||||||
|
* recoverable runtime errors, never to report programming
|
||||||
|
* errors.</emphasis> 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 <emphasis>only</emphasis> 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 <literal>error</literal>
|
||||||
|
* 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 <literal>err != NULL</literal> in this example is a
|
||||||
|
* <emphasis>reliable</emphasis> 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 <literal>error</literal>
|
||||||
|
* argument:
|
||||||
|
* |[
|
||||||
|
* if (g_file_get_contents ("foo.txt", &contents, NULL, NULL)) /* ignore errors */
|
||||||
|
* /* no error occurred */ ;
|
||||||
|
* else
|
||||||
|
* /* error */ ;
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* The #GError object contains three fields: <literal>domain</literal>
|
||||||
|
* indicates the module the error-reporting function is located in,
|
||||||
|
* <literal>code</literal> indicates the specific error that occurred,
|
||||||
|
* and <literal>message</literal> 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
|
||||||
|
* <literal>error->message</literal>, 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,
|
||||||
|
* <literal>error->message</literal> 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;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ]|
|
||||||
|
* <literal>tmp_error</literal> should be checked immediately after
|
||||||
|
* sub_function_that_can_fail(), and either cleared or propagated
|
||||||
|
* upward. The rule is: <emphasis>after each error, you must either
|
||||||
|
* handle the error, or return it to the calling function</emphasis>.
|
||||||
|
* 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
|
||||||
|
* <emphasis>ignores</emphasis> errors; it's equivalent to
|
||||||
|
* <literal>try { sub_function_that_can_fail (); } catch (...) {}</literal>
|
||||||
|
* in C++. It does <emphasis>not</emphasis> mean to leave errors
|
||||||
|
* unhandled; it means to handle them by doing nothing.
|
||||||
|
*
|
||||||
|
* Error domains and codes are conventionally named as follows:
|
||||||
|
* <itemizedlist>
|
||||||
|
* <listitem><para>
|
||||||
|
* The error domain is called
|
||||||
|
* <literal><NAMESPACE>_<MODULE>_ERROR</literal>,
|
||||||
|
* 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");
|
||||||
|
* }
|
||||||
|
* ]|
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* The quark function for the error domain is called
|
||||||
|
* <literal><namespace>_<module>_error_quark</literal>,
|
||||||
|
* for example g_spawn_error_quark() or %g_thread_error_quark().
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* The error codes are in an enumeration called
|
||||||
|
* <literal><Namespace><Module>Error</literal>;
|
||||||
|
* for example,#GThreadError or #GSpawnError.
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* Members of the error code enumeration are called
|
||||||
|
* <literal><NAMESPACE>_<MODULE>_ERROR_<CODE></literal>,
|
||||||
|
* for example %G_SPAWN_ERROR_FORK or %G_THREAD_ERROR_AGAIN.
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* 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 <literal><NAMESPACE>_<MODULE>_ERROR_FAILED</literal>,
|
||||||
|
* for example %G_SPAWN_ERROR_FAILED or %G_THREAD_ERROR_FAILED.
|
||||||
|
* </para></listitem>
|
||||||
|
* </itemizedlist>
|
||||||
|
*
|
||||||
|
* Summary of rules for use of #GError:
|
||||||
|
* <itemizedlist>
|
||||||
|
* <listitem><para>
|
||||||
|
* Do not report programming errors via #GError.
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* 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 "...".
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* The caller may pass %NULL for the #GError** if they are not interested
|
||||||
|
* in details of the exact error that occurred.
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* 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.
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* If a #GError is reported, then your function by definition
|
||||||
|
* <emphasis>had a fatal failure and did not complete whatever
|
||||||
|
* it was supposed to do</emphasis>. 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.
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* A #GError* must be initialized to %NULL before passing its address
|
||||||
|
* to a function that can report errors.
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* "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.
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* By convention, if you return a boolean value indicating success
|
||||||
|
* then %TRUE means success and %FALSE means failure. If %FALSE is
|
||||||
|
* returned, the error <emphasis>must</emphasis> be set to a non-%NULL
|
||||||
|
* value.
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* 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.
|
||||||
|
* </para></listitem>
|
||||||
|
* <listitem><para>
|
||||||
|
* 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.
|
||||||
|
* <literal>g_return_if_fail (error == NULL || *error == NULL);</literal>).
|
||||||
|
* </para></listitem>
|
||||||
|
* </itemizedlist>
|
||||||
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "gerror.h"
|
#include "gerror.h"
|
||||||
|
@@ -31,6 +31,15 @@
|
|||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GError:
|
||||||
|
* @domain: error domain, e.g. #G_FILE_ERROR
|
||||||
|
* @code: error code, e.g. %G_FILE_ERROR_NOENT
|
||||||
|
* @message: human-readable informative error message
|
||||||
|
*
|
||||||
|
* The <structname>GError</structname> structure contains
|
||||||
|
* information about an error that has occurred.
|
||||||
|
*/
|
||||||
typedef struct _GError GError;
|
typedef struct _GError GError;
|
||||||
|
|
||||||
struct _GError
|
struct _GError
|
||||||
|
Reference in New Issue
Block a user