summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sord/sord.h27
-rw-r--r--sord/sordmm.hpp504
-rw-r--r--src/syntax.c201
-rw-r--r--wscript3
4 files changed, 695 insertions, 40 deletions
diff --git a/sord/sord.h b/sord/sord.h
index 6b00268..f1169f9 100644
--- a/sord/sord.h
+++ b/sord/sord.h
@@ -22,9 +22,15 @@
#ifndef SORD_SORD_H
#define SORD_SORD_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <stdbool.h>
#include <stdint.h>
+#include "serd/serd.h"
+
#if defined _WIN32 || defined __CYGWIN__
#define SORD_LIB_IMPORT __declspec(dllimport)
#define SORD_LIB_EXPORT __declspec(dllexport)
@@ -330,8 +336,29 @@ sord_read_file_handle(SordModel model,
const SordNode graph,
const uint8_t* blank_prefix);
+SORD_API
+bool
+sord_write_file(SordModel model,
+ SerdEnv env,
+ const uint8_t* uri,
+ const SordNode graph,
+ const uint8_t* blank_prefix);
+
+SORD_API
+bool
+sord_write_file_handle(SordModel model,
+ SerdEnv env,
+ FILE* fd,
+ const uint8_t* base_uri,
+ const SordNode graph,
+ const uint8_t* blank_prefix);
+
/** @} */
/** @} */
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
#endif // SORD_SORD_H
diff --git a/sord/sordmm.hpp b/sord/sordmm.hpp
new file mode 100644
index 0000000..4661458
--- /dev/null
+++ b/sord/sordmm.hpp
@@ -0,0 +1,504 @@
+/* Sord, a lightweight RDF model library.
+ * Copyright 2010-2011 David Robillard <d@drobilla.net>
+ *
+ * Sord is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Sord is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file sordmm.hpp
+ * Public Sord C++ API.
+ */
+
+#ifndef SORD_SORDMM_HPP
+#define SORD_SORDMM_HPP
+
+#include <cassert>
+#include <cstring>
+#include <iostream>
+#include <set>
+#include <string>
+
+#include <boost/utility.hpp>
+#include <glibmm/ustring.h>
+
+#include "serd/serd.h"
+#include "sord/sord.h"
+
+#define SORD_NS_XSD "http://www.w3.org/2001/XMLSchema#"
+
+namespace Sord {
+
+/** C++ wrapper for a Sord object. */
+template <typename T>
+class Wrapper {
+public:
+ inline Wrapper(T c_obj = NULL) : _c_obj(c_obj) {}
+
+ inline T c_obj() { return _c_obj; }
+ inline const T c_obj() const { return _c_obj; }
+
+protected:
+ T _c_obj;
+};
+
+/** Collection of RDF namespaces with prefixes. */
+class Namespaces : public Wrapper<SerdEnv> {
+public:
+ Namespaces() : Wrapper<SerdEnv>(serd_env_new()) {}
+
+ static inline SerdNode string_to_node(SerdType type, const std::string& s) {
+ SerdNode ret = {
+ type, s.length() + 1, s.length(), (const uint8_t*)s.c_str() };
+ return ret;
+ }
+
+ inline void add(const std::string& name,
+ const std::string& uri) {
+ const SerdNode name_node = string_to_node(SERD_LITERAL, name);
+ const SerdNode uri_node = string_to_node(SERD_URI, uri);
+ serd_env_add(_c_obj, &name_node, &uri_node);
+ }
+
+ inline std::string qualify(std::string uri) const {
+ const SerdNode uri_node = string_to_node(SERD_URI, uri);
+ SerdNode prefix;
+ SerdChunk suffix;
+ if (serd_env_qualify(_c_obj, &uri_node, &prefix, &suffix)) {
+ std::string ret((const char*)prefix.buf, prefix.n_bytes - 1);
+ ret.append((const char*)suffix.buf, suffix.len);
+ return ret;
+ }
+ return uri;
+ }
+
+ inline std::string expand(const std::string& curie) const {
+ assert(curie.find(":") != std::string::npos);
+ SerdNode curie_node = string_to_node(SERD_CURIE, curie);
+ SerdChunk uri_prefix;
+ SerdChunk uri_suffix;
+ if (serd_env_expand(_c_obj, &curie_node, &uri_prefix, &uri_suffix)) {
+ std::string ret((const char*)uri_prefix.buf, uri_prefix.len);
+ ret.append((const char*)uri_suffix.buf, uri_suffix.len);
+ return ret;
+ }
+ std::cerr << "CURIE `" << curie << "' has unknown prefix." << std::endl;
+ return curie;
+ }
+};
+
+/** Sord library state. */
+class World : public boost::noncopyable, public Wrapper<SordWorld> {
+public:
+ inline World()
+ : _next_blank_id(0)
+ {
+ _c_obj = sord_world_new();
+ add_prefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+ }
+
+ inline ~World() {
+ sord_world_free(_c_obj);
+ }
+
+ inline uint64_t blank_id() { return _next_blank_id++; }
+
+ inline void add_prefix(const std::string& prefix, const std::string& uri) {
+ _prefixes.add(prefix, uri);
+ }
+
+ inline const Namespaces& prefixes() const { return _prefixes; }
+ inline SordWorld world() { return _c_obj; }
+
+private:
+ Namespaces _prefixes;
+ std::set<std::string> _blank_ids;
+ uint64_t _next_blank_id;
+};
+
+/** An RDF Node (resource, literal, etc)
+ */
+class Node : public Wrapper<SordNode> {
+public:
+ enum Type {
+ UNKNOWN = 0,
+ RESOURCE = SORD_URI,
+ BLANK = SORD_BLANK,
+ LITERAL = SORD_LITERAL
+ };
+
+ inline Node() : Wrapper<SordNode>(NULL), _world(NULL) {}
+
+ inline Node(World& world, Type t, const std::string& s);
+ inline Node(World& world);
+ inline Node(World& world, SordNode node);
+ inline Node(const Node& other);
+ inline ~Node();
+
+ inline Type type() const {
+ return _c_obj ? (Type)sord_node_get_type(_c_obj) : UNKNOWN;
+ }
+
+ inline SordNode get_node() const { return _c_obj; }
+
+ inline bool is_valid() const { return type() != UNKNOWN; }
+
+ inline bool operator<(const Node& other) const {
+ if (type() != other.type()) {
+ return type() < other.type();
+ } else {
+ return to_string() < other.to_string();
+ }
+ }
+
+ const Node& operator=(const Node& other) {
+ if (_c_obj)
+ sord_node_free(_c_obj);
+ _world = other._world;
+ _c_obj = other._c_obj ? sord_node_copy(other._c_obj) : NULL;
+ return *this;
+ }
+
+ inline bool operator==(const Node& other) const {
+ return sord_node_equals(_c_obj, other._c_obj);
+ }
+
+ inline const uint8_t* to_u_string() const;
+ inline const char* to_c_string() const;
+ inline std::string to_string() const;
+
+ inline bool is_literal_type(const char* type_uri) const;
+
+ inline bool is_resource() const { return _c_obj && type() == RESOURCE; }
+ inline bool is_blank() const { return _c_obj && type() == BLANK; }
+ inline bool is_int() const { return is_literal_type(SORD_NS_XSD "integer"); }
+ inline bool is_float() const { return is_literal_type(SORD_NS_XSD "decimal"); }
+ inline bool is_bool() const { return is_literal_type(SORD_NS_XSD "boolean"); }
+
+ inline int to_int() const;
+ inline float to_float() const;
+ inline bool to_bool() const;
+
+ inline static Node blank_id(World& world, const std::string base="b") {
+ const uint64_t num = world.blank_id();
+ std::ostringstream ss;
+ ss << base << num;
+ return Node(world, Node::BLANK, ss.str());
+ }
+
+private:
+ World* _world;
+};
+
+inline std::ostream&
+operator<<(std::ostream& os, const Node& node)
+{
+ return os << node.to_string() << std::endl;
+}
+
+class Resource : public Node {
+public:
+ inline Resource(World& world, const std::string& s) : Node(world, Node::RESOURCE, s) {}
+};
+
+class Curie : public Node {
+public:
+ inline Curie(World& world, const std::string& s)
+ : Node(world, Node::RESOURCE, world.prefixes().expand(s)) {}
+};
+
+class Literal : public Node {
+public:
+ inline Literal(World& world, const std::string& s) : Node(world, Node::LITERAL, s) {}
+};
+
+inline
+Node::Node(World& world, Type type, const std::string& s)
+ : _world(&world)
+{
+ switch (type) {
+ case RESOURCE:
+ assert(s.find(":") == std::string::npos
+ || s.substr(0, 5) == "http:"
+ || s.substr(0, 5) == "file:"
+ || s.substr(0, 4) == "urn:");
+ _c_obj = sord_new_uri(
+ world.world(), (const unsigned char*)s.c_str());
+ break;
+ case LITERAL:
+ _c_obj = sord_new_literal(
+ world.world(), NULL, (const unsigned char*)s.c_str(), NULL);
+ break;
+ case BLANK:
+ _c_obj = sord_new_blank(
+ world.world(), (const unsigned char*)s.c_str());
+ break;
+ default:
+ _c_obj = NULL;
+ }
+
+ assert(this->type() == type);
+}
+
+inline
+Node::Node(World& world)
+ : _world(&world)
+{
+ Node me = blank_id(world);
+ *this = me;
+}
+
+inline
+Node::Node(World& world, SordNode node)
+ : _world(&world)
+{
+ _c_obj = node ? sord_node_copy(node) : NULL;
+}
+
+inline
+Node::Node(const Node& other)
+ : Wrapper<SordNode>()
+ , _world(other._world)
+{
+ if (_world) {
+ _c_obj = other._c_obj ? sord_node_copy(other._c_obj) : NULL;
+ }
+
+ assert((!_c_obj && !other._c_obj) || to_string() == other.to_string());
+}
+
+inline
+Node::~Node()
+{
+ if (_world) {
+ sord_node_free(_c_obj);
+ }
+}
+
+
+inline std::string
+Node::to_string() const
+{
+ return std::string(to_c_string());
+}
+
+
+inline const char*
+Node::to_c_string() const
+{
+ return (const char*)sord_node_get_string(_c_obj);
+}
+
+inline const uint8_t*
+Node::to_u_string() const
+{
+ return sord_node_get_string(_c_obj);
+}
+
+inline bool
+Node::is_literal_type(const char* type_uri) const
+{
+ if (_c_obj && sord_node_get_type(_c_obj) == SORD_LITERAL) {
+ SordNode datatype = sord_node_get_datatype(_c_obj);
+ if (datatype && !strcmp((const char*)sord_node_get_string(datatype),
+ type_uri))
+ return true;
+ }
+ return false;
+}
+
+inline int
+Node::to_int() const
+{
+ assert(is_int());
+ std::locale c_locale("C");
+ std::stringstream ss((const char*)sord_node_get_string(_c_obj));
+ ss.imbue(c_locale);
+ int i = 0;
+ ss >> i;
+ return i;
+}
+
+inline float
+Node::to_float() const
+{
+ assert(is_float());
+ std::locale c_locale("C");
+ std::stringstream ss((const char*)sord_node_get_string(_c_obj));
+ ss.imbue(c_locale);
+ float f = 0.0f;
+ ss >> f;
+ return f;
+}
+
+inline bool
+Node::to_bool() const
+{
+ assert(is_bool());
+ return !strcmp((const char*)sord_node_get_string(_c_obj), "true");
+}
+
+struct Iter : public Wrapper<SordIter> {
+ inline Iter(World& world, SordIter c_obj)
+ : Wrapper<SordIter>(c_obj), _world(world) {}
+ inline ~Iter() { sord_iter_free(_c_obj); }
+ inline bool end() const { return sord_iter_end(_c_obj); }
+ inline bool next() const { return sord_iter_next(_c_obj); }
+ inline Iter& operator++() { assert(!end()); next(); return *this; }
+ inline Node get_subject() const {
+ SordQuad quad;
+ sord_iter_get(_c_obj, quad);
+ return Node(_world, quad[SORD_SUBJECT]);
+ }
+ inline Node get_predicate() const {
+ SordQuad quad;
+ sord_iter_get(_c_obj, quad);
+ return Node(_world, quad[SORD_PREDICATE]);
+ }
+ inline Node get_object() const {
+ SordQuad quad;
+ sord_iter_get(_c_obj, quad);
+ return Node(_world, quad[SORD_OBJECT]);
+ }
+ World& _world;
+};
+
+
+/** An RDF Model (collection of triples).
+ */
+class Model : public boost::noncopyable, public Wrapper<SordModel> {
+public:
+ inline Model(World& world, const Glib::ustring& base_uri=".");
+ inline ~Model();
+
+ inline const Node& base_uri() const { return _base; }
+
+ inline void load_file(const Glib::ustring& uri);
+
+ inline void load_string(const char* str,
+ size_t len,
+ const Glib::ustring& base_uri,
+ const std::string lang = "turtle");
+
+ inline void write_to_file_handle(FILE* fd, const char* lang);
+ inline void write_to_file(const Glib::ustring& uri, const char* lang);
+ inline char* write_to_string(const char* lang);
+
+ inline void add_statement(const Node& subject,
+ const Node& predicate,
+ const Node& object);
+
+ inline Iter find(const Node& subject,
+ const Node& predicate,
+ const Node& object);
+
+ inline World& world() const { return _world; }
+
+private:
+ World& _world;
+ Node _base;
+ SerdWriter _writer;
+ size_t _next_blank_id;
+};
+
+/** Create an empty in-memory RDF model.
+ */
+inline
+Model::Model(World& world, const Glib::ustring& base_uri)
+ : _world(world)
+ , _base(world, Node::RESOURCE, base_uri)
+ , _writer(NULL)
+{
+ // FIXME: parameters
+ _c_obj = sord_new(_world.world(), SORD_SPO|SORD_OPS, true);
+}
+
+inline void
+Model::load_string(const char* str,
+ size_t len,
+ const Glib::ustring& base_uri,
+ const std::string lang)
+{
+ // TODO
+}
+
+inline Model::~Model()
+{
+ sord_free(_c_obj);
+}
+
+inline void
+Model::load_file(const Glib::ustring& data_uri)
+{
+ // FIXME: blank prefix
+ sord_read_file(_c_obj, (const uint8_t*)data_uri.c_str(), NULL,
+ (const uint8_t*)"b");
+}
+
+inline void
+Model::write_to_file_handle(FILE* fd, const char* lang)
+{
+ sord_write_file_handle(_c_obj,
+ _world.prefixes().c_obj(),
+ fd,
+ _base.to_u_string(),
+ NULL,
+ NULL);
+}
+
+inline void
+Model::write_to_file(const Glib::ustring& uri, const char* lang)
+{
+ sord_write_file(_c_obj,
+ _world.prefixes().c_obj(),
+ (const uint8_t*)uri.c_str(),
+ NULL,
+ NULL);
+}
+
+inline char*
+Model::write_to_string(const char* lang)
+{
+ std::cerr << "TODO: serialise" << std::endl;
+ return NULL;
+}
+
+inline void
+Model::add_statement(const Node& subject,
+ const Node& predicate,
+ const Node& object)
+{
+ SordQuad quad = { subject.c_obj(),
+ predicate.c_obj(),
+ object.c_obj(),
+ NULL };
+
+ sord_add(_c_obj, quad);
+}
+
+inline Iter
+Model::find(const Node& subject,
+ const Node& predicate,
+ const Node& object)
+{
+ SordQuad quad = { subject.c_obj(),
+ predicate.c_obj(),
+ object.c_obj(),
+ NULL };
+
+ return Iter(_world, sord_find(_c_obj, quad));
+}
+
+} // namespace Sord
+
+#endif // SORD_SORDMM_HPP
+
diff --git a/src/syntax.c b/src/syntax.c
index 9f90e20..0666ecd 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -94,13 +94,18 @@ event_prefix(void* handle,
}
static inline SordNode
-sord_node_from_serd_node(ReadState* state, const SerdNode* sn)
+sord_node_from_serd_node(ReadState* state, const SerdNode* sn,
+ const SerdNode* datatype, const SerdNode* lang)
{
switch (sn->type) {
case SERD_NOTHING:
return NULL;
case SERD_LITERAL:
- return sord_new_literal(state->world, NULL, sn->buf, NULL);
+ return sord_new_literal(
+ state->world,
+ sord_node_from_serd_node(state, datatype, NULL, NULL),
+ sn->buf,
+ g_intern_string((const char*)lang->buf));
case SERD_URI: {
SerdURI abs_uri;
SerdNode abs_uri_node = serd_node_new_uri_from_node(
@@ -134,6 +139,30 @@ sord_node_from_serd_node(ReadState* state, const SerdNode* sn)
return NULL;
}
+static inline void
+sord_node_to_serd_node(const SordNode node, SerdNode* out)
+{
+ if (!node) {
+ *out = SERD_NODE_NULL;
+ return;
+ }
+ switch (node->type) {
+ case SORD_URI:
+ out->type = SERD_URI;
+ break;
+ case SORD_BLANK:
+ out->type = SERD_BLANK_ID;
+ break;
+ case SORD_LITERAL:
+ out->type = SERD_LITERAL;
+ break;
+ }
+ size_t len;
+ out->buf = sord_node_get_string_counted(node, &len);
+ out->n_bytes = len;
+ out->n_chars = len - 1; // FIXME: UTF-8
+}
+
static bool
event_statement(void* handle,
const SerdNode* graph,
@@ -146,25 +175,17 @@ event_statement(void* handle,
ReadState* const state = (ReadState*)handle;
SordQuad tup;
- tup[0] = sord_node_from_serd_node(state, subject);
- tup[1] = sord_node_from_serd_node(state, predicate);
-
- SordNode object_node = sord_node_from_serd_node(state, object);
-
- if (object_datatype) {
- object_node->datatype = sord_node_from_serd_node(state, object_datatype);
- }
- if (object_lang) {
- object_node->lang = g_intern_string((const char*)object_lang->buf);
- }
- tup[2] = object_node;
+ tup[0] = sord_node_from_serd_node(state, subject, NULL, NULL);
+ tup[1] = sord_node_from_serd_node(state, predicate, NULL, NULL);
+ tup[2] = sord_node_from_serd_node(state, object,
+ object_datatype, object_lang);
if (state->graph_uri_node) {
assert(graph->type == SERD_NOTHING);
tup[3] = state->graph_uri_node;
} else {
tup[3] = (graph && graph->buf)
- ? sord_node_from_serd_node(state, graph)
+ ? sord_node_from_serd_node(state, graph, NULL, NULL)
: NULL;
}
@@ -173,39 +194,47 @@ event_statement(void* handle,
return true;
}
-SORD_API
-bool
-sord_read_file(SordModel sord,
- const uint8_t* input,
- const SordNode graph,
- const uint8_t* blank_prefix)
+static const uint8_t*
+sord_file_uri_to_path(const uint8_t* uri)
{
const uint8_t* filename = NULL;
- if (serd_uri_string_has_scheme(input)) {
- // INPUT is an absolute URI, ensure it a file and chop scheme
- if (strncmp((const char*)input, "file:", 5)) {
- fprintf(stderr, "unsupported URI scheme `%s'\n", input);
- return 1;
- } else if (!strncmp((const char*)input, "file://", 7)) {
- filename = input + 7;
+ if (serd_uri_string_has_scheme(uri)) {
+ // Absolute URI, ensure it a file and chop scheme
+ if (strncmp((const char*)uri, "file:", 5)) {
+ fprintf(stderr, "unsupported URI scheme `%s'\n", uri);
+ return NULL;
+ } else if (!strncmp((const char*)uri, "file://", 7)) {
+ filename = uri + 7;
} else {
- filename = input + 5;
+ filename = uri + 5;
}
} else {
- filename = input;
+ filename = uri;
}
+ return filename;
+}
- FILE* in_fd = fopen((const char*)filename, "r");
- if (!in_fd) {
- fprintf(stderr, "failed to open file %s\n", filename);
- return 1;
+SORD_API
+bool
+sord_read_file(SordModel model,
+ const uint8_t* uri,
+ const SordNode graph,
+ const uint8_t* blank_prefix)
+{
+ const uint8_t* const path = sord_file_uri_to_path(uri);
+ if (!path) {
+ return false;
}
- const bool success = sord_read_file_handle(
- sord, in_fd, input, graph, blank_prefix);
+ FILE* const fd = fopen((const char*)path, "r");
+ if (!fd) {
+ fprintf(stderr, "failed to open file %s\n", path);
+ return false;
+ }
- fclose(in_fd);
- return success;
+ const bool ret = sord_read_file_handle(model, fd, uri, graph, blank_prefix);
+ fclose(fd);
+ return ret;
}
SORD_API
@@ -245,8 +274,102 @@ sord_read_file_handle(SordModel sord,
const bool success = serd_reader_read_file(state.reader, fd, base_uri_str);
serd_reader_free(state.reader);
- serd_env_free(state.env);
serd_node_free(&state.base_uri_node);
return success;
}
+
+SORD_API
+bool
+sord_write_file(SordModel model,
+ SerdEnv env,
+ const uint8_t* uri,
+ const SordNode graph,
+ const uint8_t* blank_prefix)
+{
+ const uint8_t* const path = sord_file_uri_to_path(uri);
+ if (!path) {
+ return false;
+ }
+
+ FILE* const fd = fopen((const char*)path, "w");
+ if (!fd) {
+ fprintf(stderr, "failed to open file %s\n", path);
+ return false;
+ }
+
+ const bool ret = sord_write_file_handle(model, env, fd, uri, graph, blank_prefix);
+ fclose(fd);
+ return ret;
+}
+
+static size_t
+file_sink(const void* buf, size_t len, void* stream)
+{
+ FILE* file = (FILE*)stream;
+ return fwrite(buf, 1, len, file);
+}
+
+SORD_API
+bool
+sord_write_file_handle(SordModel model,
+ SerdEnv env,
+ FILE* fd,
+ const uint8_t* base_uri_str_in,
+ const SordNode graph,
+ const uint8_t* blank_prefix)
+{
+ size_t base_uri_n_bytes = 0;
+ uint8_t* base_uri_str = copy_string(base_uri_str_in, &base_uri_n_bytes);
+ SerdURI base_uri;
+ if (!serd_uri_parse(base_uri_str, &base_uri)) {
+ fprintf(stderr, "invalid base URI `%s'\n", base_uri_str);
+ }
+
+ SerdWriter writer = serd_writer_new(SERD_TURTLE,
+ SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED,
+ env,
+ &base_uri,
+ file_sink,
+ fd);
+
+ serd_env_foreach(env,
+ (SerdPrefixSink)serd_writer_set_prefix,
+ writer);
+
+ SerdNode s_graph;
+ sord_node_to_serd_node(graph, &s_graph);
+ for (SordIter i = sord_begin(model); !sord_iter_end(i); sord_iter_next(i)) {
+ SordQuad quad;
+ sord_iter_get(i, quad);
+
+ SerdNode subject;
+ SerdNode predicate;
+ SerdNode object;
+ SerdNode datatype;
+ sord_node_to_serd_node(quad[SORD_SUBJECT], &subject);
+ sord_node_to_serd_node(quad[SORD_PREDICATE], &predicate);
+ sord_node_to_serd_node(quad[SORD_OBJECT], &object);
+
+ sord_node_to_serd_node(sord_node_get_datatype(quad[SORD_OBJECT]), &datatype);
+ const char* lang_str = sord_node_get_language(quad[SORD_OBJECT]);
+ size_t lang_len = lang_str ? strlen(lang_str) : 0;
+
+ SerdNode language = SERD_NODE_NULL;
+ if (lang_str) {
+ language.type = SERD_LITERAL;
+ language.n_bytes = lang_len + 1;
+ language.n_chars = lang_len; // FIXME: UTF-8
+ language.buf = (const uint8_t*)lang_str;
+ };
+
+ serd_writer_write_statement(writer, &s_graph,
+ &subject, &predicate, &object,
+ &datatype, &language);
+ }
+
+ serd_writer_free(writer);
+ free(base_uri_str);
+
+ return true;
+}
diff --git a/wscript b/wscript
index 9b033e1..f9641bb 100644
--- a/wscript
+++ b/wscript
@@ -61,8 +61,9 @@ def configure(conf):
print
def build(bld):
- # C Headers
+ # C/C++ Headers
bld.install_files('${INCLUDEDIR}/sord', bld.path.ant_glob('sord/*.h'))
+ bld.install_files('${INCLUDEDIR}/sord', bld.path.ant_glob('sord/*.hpp'))
# Pkgconfig file
autowaf.build_pc(bld, 'SORD', SORD_VERSION, [])