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 }