diff --git a/glnx-errors.h b/glnx-errors.h index e26a513e39fa11f39153a2c519f13c6d41bf18eb..ecf7e85fc6681a5a08b220da8b5d1bf8bbedf232 100644 --- a/glnx-errors.h +++ b/glnx-errors.h @@ -84,6 +84,36 @@ glnx_prefix_error (GError **error, const char *fmt, ...) #define glnx_prefix_error_null(error, args...) \ ({glnx_prefix_error (error, args); NULL;}) +/** + * GLNX_AUTO_PREFIX_ERROR: + * + * An autocleanup-based macro to automatically call `g_prefix_error()` (also with a colon+space `: `) + * when it goes out of scope. This is useful when one wants error strings built up by the callee + * function, not all callers. + * + * ``` + * gboolean start_http_request (..., GError **error) + * { + * GLNX_AUTO_PREFIX_ERROR("HTTP request", error) + * + * if (!libhttp_request_start (..., error)) + * return FALSE; + * ... + * return TRUE; + * ``` + */ +typedef struct { + const char *prefix; + GError **error; +} GLnxAutoErrorPrefix; +static inline void +glnx_cleanup_auto_prefix_error (GLnxAutoErrorPrefix *prefix) +{ + g_prefix_error (prefix->error, "%s: ", prefix->prefix); +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxAutoErrorPrefix, glnx_cleanup_auto_prefix_error) +#define GLNX_AUTO_PREFIX_ERROR(text, error) g_auto(GLnxAutoErrorPrefix) _GLNX_MAKE_ANONYMOUS(_glnxautoprefixerror_) = { text, error } + /* Set @error using the value of `g_strerror (errno)`. * * This function returns %FALSE so it can be used conveniently in a single diff --git a/tests/test-libglnx-errors.c b/tests/test-libglnx-errors.c index 721818ba10341912b0ce704c743e07afa157023a..4e91e02c6e225ca8e95aaa068076de22185f4962 100644 --- a/tests/test-libglnx-errors.c +++ b/tests/test-libglnx-errors.c @@ -125,6 +125,48 @@ test_error_errno (void) g_assert_cmpint (fd, ==, -1); } +static void +test_error_auto_nothrow (GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("foo", error); + /* Side effect to avoid otherwise empty function */ + g_assert_no_error (*error); +} + +static void +test_error_auto_throw (GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("foo", error); + (void) glnx_throw (error, "oops"); +} + +static void +test_error_auto_throw_recurse (GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("foo", error); + + if (TRUE) + { + GLNX_AUTO_PREFIX_ERROR("bar", error); + (void) glnx_throw (error, "oops"); + } +} + +static void +test_error_auto (void) +{ + g_autoptr(GError) error = NULL; + test_error_auto_nothrow (&error); + g_assert_no_error (error); + test_error_auto_throw (&error); + g_assert_nonnull (error); + g_assert_cmpstr (error->message, ==, "foo: oops"); + g_clear_error (&error); + test_error_auto_throw_recurse (&error); + g_assert_nonnull (error); + g_assert_cmpstr (error->message, ==, "foo: bar: oops"); +} + int main (int argc, char **argv) { int ret; @@ -133,6 +175,7 @@ int main (int argc, char **argv) g_test_add_func ("/error-throw", test_error_throw); g_test_add_func ("/error-errno", test_error_errno); + g_test_add_func ("/error-auto", test_error_auto); ret = g_test_run();