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