Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mcjohnalds/61e445370d123453b086c341c4747d50 to your computer and use it in GitHub Desktop.
Save mcjohnalds/61e445370d123453b086c341c4747d50 to your computer and use it in GitHub Desktop.
Here's how to do error reporting in GLib

How to do error reporting in GLib

C doesn't support exceptions but GLib has its own error reporting system. It's kind of verbose but it works ok.

Let's pretend we were making a JSON parser library, here's how the error reporting would work. (This example was actually derived from json-glib).

First we create an enum to represent different error codes.

typedef enum {
    JSON_ERROR_MISSING_COLON,
    JSON_ERROR_TRAILING_COMMA,
    ...
} JSONError;

Then we use the G_DEFINE_QUARK macro which will define a function
GQuark json_error_quark(void) that returns a constant.

We will use this constant to indicate that the error returned from a function will be from JSONError and not some other enum like GFileError.

G_DEFINE_QUARK(json-error-quark, json_error)

And then we put the constant in a #define for the sake of clarity.

#define JSON_ERROR (json_error_quark())

Now we can do our JSON parsing function.

bool json_parse(const char* path, JSON** json, GError** error) {
    ...
    if (missing_colon) {
        g_set_error(error, JSON_ERROR, JSON_ERROR_MISSING_COLON,
                    "%s:%d missing colon", path, line);
        return false;
    }

    if (trailing_comma) {
        g_set_error(error, JSON_ERROR, JSON_ERROR_TRAILING_COMMA,
                    "%s:%d trailing comma", path, line);
        return false;
    }
    ...
}

Now how do we call json_parse? Like this:

GError* error = NULL; // Note: you must always initialize a GError* to NULL
JSON* json; // Let's pretend we've defined a JSON data struct beforehand
if (!json_parse("foo.json", &json, &error)) {
    fputs(error->message, stderr);
    fputc('\n', stderr);
    g_error_free(error);
    exit(EXIT_FAILURE);
}

Or if we're lazy, like this:

JSON* json;
if (!json_parse("foo.json", &json, NULL)) {
    fputs(stderr, "couldn't pass foo.json");
    exit(EXIT_FAILURE);
}

Or if we're really lazy:

JSON* json;
json_parse("foo.json", &json, NULL); // We just assume it worked

Here's a working example, compile with

gcc `pkg-config --cflags glib-2.0` example.c `pkg-config --libs glib-2.0`

example.c

#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef enum {
    JSON_ERROR_MISSING_COLON,
    JSON_ERROR_TRAILING_COMMA,
    // ...
} JSONError;

typedef struct {
    // ...
} JSON;

G_DEFINE_QUARK(json-error-quark, json_error)
#define JSON_ERROR (json_error_quark())

bool json_parse(const char* path, JSON** json, GError** error) {
    bool missing_colon = false;
    bool trailing_comma = true;
    int line = 10;

    // ...

    if (missing_colon) {
        g_set_error(error, JSON_ERROR, JSON_ERROR_MISSING_COLON,
                    "%s:%d missing colon", path, line);
        return false;
    }

    if (trailing_comma) {
        g_set_error(error, JSON_ERROR, JSON_ERROR_TRAILING_COMMA,
                    "%s:%d trailing comma", path, line);
        return false;
    }

    // ...

    return true;
}

int main() {
    GError* error = NULL;
    JSON* json;
    if (!json_parse("foo.json", &json, &error)) {
        fputs(error->message, stderr);
        fputc('\n', stderr);
        g_error_free(error);
        exit(EXIT_FAILURE);
    }

    puts("no errors parsing foo.json");

    // ...
}

Output:

foo.json:10 trailing comma

Here's GLib's error reporting API: https://developer.gnome.org/glib/stable/glib-Error-Reporting.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment