glibrdf.c (3764B) - raw
1
2 /*
3 * glibrdf.c
4 * Copyright 2012 Dan Callaghan <djc@djc.id.au>
5 * Licensed under GPLv3
6 */
7
8 #include <stdbool.h>
9 #include <time.h>
10 #include "glibrdf.h"
11
12 GType librdf_node_get_gtype(void) {
13 static volatile gsize _librdf_node_type_id = 0;
14 if (g_once_init_enter(&_librdf_node_type_id)) {
15 GType type_id = g_boxed_type_register_static("librdf_node",
16 (GBoxedCopyFunc) librdf_new_node_from_node,
17 (GBoxedFreeFunc) librdf_free_node);
18 g_once_init_leave(&_librdf_node_type_id, type_id);
19 }
20 return _librdf_node_type_id;
21 }
22
23 // glib should do this for me >:(
24 static GDate *parse_iso8601_date(const gchar *s) {
25 struct tm tm = {0};
26 if (*strptime(s, "%F", &tm) != '\0')
27 return NULL;
28 return g_date_new_dmy(tm.tm_mday, 1 + tm.tm_mon, 1900 + tm.tm_year);
29 }
30
31 // g_time_val_from_iso8601 doesn't preserve timezone >:(((
32 static GDateTime *parse_iso8601_datetime(const gchar *s) {
33 struct tm tm = {0};
34 // parse the date and time, timezone will be left at the end
35 const gchar *rest = strptime(s, "%FT%T", &tm);
36 GTimeZone *tz = g_time_zone_new(rest);
37 g_return_val_if_fail(tz != NULL, NULL);
38 GDateTime *result = g_date_time_new(tz,
39 1900 + tm.tm_year,
40 1 + tm.tm_mon,
41 tm.tm_mday,
42 tm.tm_hour,
43 tm.tm_min,
44 (gdouble) tm.tm_sec);
45 g_time_zone_unref(tz);
46 return result;
47 }
48
49 // XXX handle parse failures more gracefully?
50
51 static void integer(const gchar *lv, GValue *value_out) {
52 g_value_init(value_out, G_TYPE_INT64);
53 gchar *lv_unconsumed;
54 g_value_set_int64(value_out, g_ascii_strtoll(lv, &lv_unconsumed, 10));
55 g_return_if_fail(*lv_unconsumed == '\0');
56 return;
57 }
58
59 static void date(const gchar *lv, GValue *value_out) {
60 GDate *date = parse_iso8601_date(lv);
61 g_return_if_fail(date != NULL);
62 g_value_init(value_out, G_TYPE_DATE);
63 g_value_take_boxed(value_out, date);
64 return;
65 }
66
67 static void datetime(const gchar *lv, GValue *value_out) {
68 GDateTime *datetime = parse_iso8601_datetime(lv);
69 g_return_if_fail(datetime != NULL);
70 g_value_init(value_out, G_TYPE_DATE_TIME);
71 g_value_take_boxed(value_out, datetime);
72 return;
73 }
74
75 librdf_gvalue_adaptor_func librdf_default_gvalue_adaptor_map(librdf_uri *datatype_uri) {
76 const gchar *datatype_uri_string =
77 (const gchar *)librdf_uri_as_string(datatype_uri);
78 if (g_strcmp0(datatype_uri_string,
79 "http://www.w3.org/2001/XMLSchema#integer") == 0)
80 return integer;
81 if (g_strcmp0(datatype_uri_string,
82 "http://www.w3.org/TR/xmlschema-2/#date") == 0)
83 return date;
84 if (g_strcmp0(datatype_uri_string,
85 "http://www.w3.org/TR/xmlschema-2/#datetime") == 0)
86 return datetime;
87 return NULL;
88 }
89
90 void librdf_node_get_literal_gvalue(librdf_node *node,
91 librdf_gvalue_adaptor_map_func adaptor_map, GValue *value_out) {
92 g_return_if_fail(librdf_node_is_literal(node));
93 const gchar *lv = (const gchar *)librdf_node_get_literal_value(node);
94 g_return_if_fail(lv != NULL);
95 librdf_uri *datatype_uri = librdf_node_get_literal_value_datatype_uri(node);
96 if (datatype_uri == NULL) {
97 g_value_init(value_out, G_TYPE_STRING);
98 g_value_set_string(value_out, lv);
99 return;
100 }
101 if (adaptor_map == NULL)
102 adaptor_map = librdf_default_gvalue_adaptor_map;
103 librdf_gvalue_adaptor_func adaptor = adaptor_map(datatype_uri);
104 if (adaptor == NULL) {
105 g_warning("Unhandled RDF type %s", librdf_uri_as_string(datatype_uri));
106 g_value_init(value_out, G_TYPE_STRING);
107 g_value_set_string(value_out, lv);
108 }
109 adaptor(lv, value_out);
110 g_return_if_fail(G_IS_VALUE(value_out));
111 return;
112 }