summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-02-19 06:42:02 +0000
committerDavid Robillard <d@drobilla.net>2012-02-19 06:42:02 +0000
commitee1e682e0a3787a4b293e55a09d2394bd1d47252 (patch)
treef8e7e9595e47d09582fe0212f64111cfc4e1d0a5
downloadsratom-ee1e682e0a3787a4b293e55a09d2394bd1d47252.tar.gz
sratom-ee1e682e0a3787a4b293e55a09d2394bd1d47252.tar.bz2
sratom-ee1e682e0a3787a4b293e55a09d2394bd1d47252.zip
Add 'seriatom', an LV2 Atom RDF serialisation library.
git-svn-id: http://svn.drobilla.net/lad/trunk/seriatom@3989 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--seriatom.pc.in11
-rw-r--r--seriatom/seriatom.h88
-rw-r--r--src/atom_to_rdf.c173
-rw-r--r--tests/seriatom_test.c274
-rwxr-xr-xwafbin0 -> 91475 bytes
-rw-r--r--wscript181
6 files changed, 727 insertions, 0 deletions
diff --git a/seriatom.pc.in b/seriatom.pc.in
new file mode 100644
index 0000000..1e3af45
--- /dev/null
+++ b/seriatom.pc.in
@@ -0,0 +1,11 @@
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: Seriatom
+Version: @SERIATOM_VERSION@
+Description: LV2 Atom RDF serialisation library
+Requires: serd-0
+Libs: -L${libdir} -l@LIB_SERIATOM@
+Cflags: -I${includedir}/seriatom-@SERIATOM_MAJOR_VERSION@
diff --git a/seriatom/seriatom.h b/seriatom/seriatom.h
new file mode 100644
index 0000000..8381778
--- /dev/null
+++ b/seriatom/seriatom.h
@@ -0,0 +1,88 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/**
+ @file seriatom.h API for Seriatom, an LV2 Atom RDF serialisation library.
+*/
+
+#ifndef SERIATOM_SERIATOM_H
+#define SERIATOM_SERIATOM_H
+
+#include <stdint.h>
+
+#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
+#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
+#include "serd/serd.h"
+
+#ifdef SERIATOM_SHARED
+# ifdef _WIN32
+# define SERIATOM_LIB_IMPORT __declspec(dllimport)
+# define SERIATOM_LIB_EXPORT __declspec(dllexport)
+# else
+# define SERIATOM_LIB_IMPORT __attribute__((visibility("default")))
+# define SERIATOM_LIB_EXPORT __attribute__((visibility("default")))
+# endif
+# ifdef SERIATOM_INTERNAL
+# define SERIATOM_API SERIATOM_LIB_EXPORT
+# else
+# define SERIATOM_API SERIATOM_LIB_IMPORT
+# endif
+#else
+# define SERIATOM_API
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ @defgroup seriatom Seriatom
+ An LV2 Atom RDF serialisation library.
+ @{
+*/
+
+/**
+ Serialise an Atom to a SerdWriter.
+*/
+SERIATOM_API
+void
+atom_to_rdf(SerdWriter* writer,
+ LV2_URID_Unmap* unmap,
+ const SerdNode* subject,
+ const SerdNode* predicate,
+ const LV2_Atom* atom,
+ uint32_t flags);
+
+/**
+ Serialise an Atom to a Turtle string.
+ The returned string must be free()'d by the caller.
+*/
+SERIATOM_API
+char*
+atom_to_turtle(LV2_URID_Unmap* unmap,
+ const SerdNode* subject,
+ const SerdNode* predicate,
+ const LV2_Atom* atom);
+
+/**
+ @}
+*/
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SERIATOM_SERIATOM_H */
diff --git a/src/atom_to_rdf.c b/src/atom_to_rdf.c
new file mode 100644
index 0000000..f9e3895
--- /dev/null
+++ b/src/atom_to_rdf.c
@@ -0,0 +1,173 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lv2/lv2plug.in/ns/ext/atom/util.h"
+#include "seriatom/seriatom.h"
+
+#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+#define NS_XSD "http://www.w3.org/2001/XMLSchema#"
+
+#define USTR(str) ((const uint8_t*)(str))
+
+typedef struct {
+ char* buf;
+ size_t len;
+} String;
+
+static size_t
+string_sink(const void* buf, size_t len, void* stream)
+{
+ String* str = (String*)stream;
+ str->buf = realloc(str->buf, str->len + len);
+ memcpy(str->buf + str->len, buf, len);
+ str->len += len;
+ return len;
+}
+
+SERIATOM_API
+void
+atom_to_rdf(SerdWriter* writer,
+ LV2_URID_Unmap* unmap,
+ const SerdNode* subject,
+ const SerdNode* predicate,
+ const LV2_Atom* atom,
+ uint32_t flags)
+{
+ const char* const type = unmap->unmap(unmap->handle, atom->type);
+ SerdNode object = SERD_NODE_NULL;
+ SerdNode datatype = SERD_NODE_NULL;
+ SerdNode language = SERD_NODE_NULL;
+ bool new_node = false;
+ if (atom->type == 0 && atom->size == 0) {
+ object = serd_node_from_string(SERD_BLANK, USTR("null"));
+ } else if (!strcmp(type, LV2_ATOM__String)) {
+ const uint8_t* str = USTR(LV2_ATOM_BODY(atom));
+ object = serd_node_from_string(SERD_LITERAL, str);
+ } else if (!strcmp(type, LV2_ATOM__Literal)) {
+ LV2_Atom_Literal* lit = (LV2_Atom_Literal*)atom;
+ const uint8_t* str = USTR(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit));
+ object = serd_node_from_string(SERD_LITERAL, str);
+ if (lit->datatype) {
+ datatype = serd_node_from_string(
+ SERD_URI, USTR(unmap->unmap(unmap->handle, lit->datatype)));
+ } else if (lit->lang) {
+ const char* lang = unmap->unmap(unmap->handle, lit->lang);
+ const char* prefix = "http://lexvo.org/id/iso639-3/";
+ const size_t prefix_len = strlen(prefix);
+ if (lang && !strncmp(lang, prefix, prefix_len)) {
+ language = serd_node_from_string(
+ SERD_LITERAL, USTR(lang + prefix_len));
+ } else {
+ fprintf(stderr, "Unknown language URI <%s>\n", lang);
+ }
+ }
+ } else if (!strcmp(type, LV2_ATOM__URID)) {
+ const uint32_t id = *(const uint32_t*)LV2_ATOM_BODY(atom);
+ const uint8_t* str = USTR(unmap->unmap(unmap->handle, id));
+ object = serd_node_from_string(SERD_URI, str);
+ } else if (!strcmp(type, LV2_ATOM__Path)) {
+ const uint8_t* str = USTR(LV2_ATOM_BODY(atom));
+ object = serd_node_from_string(SERD_LITERAL, str);
+ datatype = serd_node_from_string(SERD_URI, USTR(LV2_ATOM__Path));
+ } else if (!strcmp(type, LV2_ATOM__URI)) {
+ const uint8_t* str = USTR(LV2_ATOM_BODY(atom));
+ object = serd_node_from_string(SERD_URI, str);
+ } else if (!strcmp(type, LV2_ATOM__Int32)) {
+ new_node = true;
+ object = serd_node_new_integer(*(int32_t*)LV2_ATOM_BODY(atom));
+ datatype = serd_node_from_string(SERD_URI, USTR(NS_XSD "int"));
+ } else if (!strcmp(type, LV2_ATOM__Int64)) {
+ new_node = true;
+ object = serd_node_new_integer(*(int64_t*)LV2_ATOM_BODY(atom));
+ datatype = serd_node_from_string(SERD_URI, USTR(NS_XSD "long"));
+ } else if (!strcmp(type, LV2_ATOM__Float)) {
+ new_node = true;
+ object = serd_node_new_decimal(*(float*)LV2_ATOM_BODY(atom), 8);
+ datatype = serd_node_from_string(SERD_URI, USTR(NS_XSD "float"));
+ } else if (!strcmp(type, LV2_ATOM__Double)) {
+ new_node = true;
+ object = serd_node_new_decimal(*(double*)LV2_ATOM_BODY(atom), 16);
+ datatype = serd_node_from_string(SERD_URI, USTR(NS_XSD "double"));
+ } else if (!strcmp(type, LV2_ATOM__Bool)) {
+ const int32_t val = *(const int32_t*)LV2_ATOM_BODY(atom);
+ datatype = serd_node_from_string(SERD_URI, USTR(NS_XSD "boolean"));
+ object = serd_node_from_string(SERD_LITERAL,
+ USTR(val ? "true" : "false"));
+ } else if (!strcmp(type, LV2_ATOM__Blank)) {
+ const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom;
+ const char* otype = unmap->unmap(unmap->handle, obj->otype);
+ SerdNode idnum = serd_node_new_integer(obj->id);
+ SerdNode id = serd_node_from_string(SERD_BLANK, idnum.buf);
+ serd_writer_write_statement(
+ writer, flags|SERD_ANON_O_BEGIN, NULL,
+ subject, predicate, &id, NULL, NULL);
+ if (otype) {
+ SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_RDF "type"));
+ SerdNode o = serd_node_from_string(SERD_URI, USTR(otype));
+ serd_writer_write_statement(writer, SERD_ANON_CONT, NULL,
+ &id, &p, &o, NULL, NULL);
+ }
+ LV2_OBJECT_FOREACH(obj, i) {
+ const LV2_Atom_Property_Body* prop = lv2_object_iter_get(i);
+ const char* const key = unmap->unmap(unmap->handle, prop->key);
+ SerdNode pred = serd_node_from_string(SERD_URI, USTR(key));
+ atom_to_rdf(writer, unmap, &id, &pred, &prop->value, SERD_ANON_CONT);
+ }
+ serd_writer_end_anon(writer, &id);
+ serd_node_free(&idnum);
+ } else {
+ object = serd_node_from_string(SERD_LITERAL, USTR("(unknown)"));
+ }
+
+ if (object.buf) {
+ serd_writer_write_statement(writer, flags, NULL,
+ subject, predicate, &object,
+ &datatype, &language);
+ }
+
+ if (new_node) {
+ serd_node_free(&object);
+ }
+}
+
+SERIATOM_API
+char*
+atom_to_turtle(LV2_URID_Unmap* unmap,
+ const SerdNode* subject,
+ const SerdNode* predicate,
+ const LV2_Atom* atom)
+{
+ SerdURI base_uri = SERD_URI_NULL;
+ SerdEnv* env = serd_env_new(NULL);
+ String str = { NULL, 0 };
+ SerdWriter* writer = serd_writer_new(
+ SERD_TURTLE,
+ SERD_STYLE_ABBREVIATED|SERD_STYLE_RESOLVED|SERD_STYLE_CURIED,
+ env, &base_uri, string_sink, &str);
+
+ serd_env_set_prefix_from_strings(env, USTR("rdf"), USTR(NS_RDF));
+ serd_env_set_prefix_from_strings(env, USTR("xsd"), USTR(NS_XSD));
+ atom_to_rdf(writer, unmap, subject, predicate, atom, 0);
+ serd_writer_finish(writer);
+ string_sink("", 1, &str);
+
+ serd_writer_free(writer);
+ serd_env_free(env);
+ return str.buf;
+}
diff --git a/tests/seriatom_test.c b/tests/seriatom_test.c
new file mode 100644
index 0000000..799c498
--- /dev/null
+++ b/tests/seriatom_test.c
@@ -0,0 +1,274 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
+#include "lv2/lv2plug.in/ns/ext/atom/util.h"
+#include "seriatom/seriatom.h"
+
+#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+
+#define USTR(s) ((const uint8_t*)(s))
+
+char** uris = NULL;
+size_t n_uris = 0;
+
+char*
+copy_string(const char* str)
+{
+ const size_t len = strlen(str);
+ char* dup = (char*)malloc(len + 1);
+ memcpy(dup, str, len + 1);
+ return dup;
+}
+
+LV2_URID
+urid_map(LV2_URID_Map_Handle handle, const char* uri)
+{
+ for (size_t i = 0; i < n_uris; ++i) {
+ if (!strcmp(uris[i], uri)) {
+ return i + 1;
+ }
+ }
+
+ uris = (char**)realloc(uris, ++n_uris * sizeof(char*));
+ uris[n_uris - 1] = copy_string(uri);
+ return n_uris;
+}
+
+const char*
+urid_unmap(LV2_URID_Unmap_Handle handle,
+ LV2_URID urid)
+{
+ if (urid <= n_uris) {
+ return uris[urid - 1];
+ }
+ return NULL;
+}
+
+int
+test_fail(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ fprintf(stderr, "error: ");
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ return 1;
+}
+
+int
+main()
+{
+ LV2_URID_Map map = { NULL, urid_map };
+ LV2_URID_Unmap unmap = { NULL, urid_unmap };
+ LV2_Atom_Forge forge;
+ lv2_atom_forge_init(&forge, &map);
+
+ LV2_URID eg_Object = urid_map(NULL, "http://example.org/Object");
+ LV2_URID eg_one = urid_map(NULL, "http://example.org/one");
+ LV2_URID eg_two = urid_map(NULL, "http://example.org/two");
+ LV2_URID eg_three = urid_map(NULL, "http://example.org/three");
+ LV2_URID eg_four = urid_map(NULL, "http://example.org/four");
+ LV2_URID eg_true = urid_map(NULL, "http://example.org/true");
+ LV2_URID eg_false = urid_map(NULL, "http://example.org/false");
+ LV2_URID eg_path = urid_map(NULL, "http://example.org/path");
+ LV2_URID eg_uri = urid_map(NULL, "http://example.org/uri");
+ LV2_URID eg_urid = urid_map(NULL, "http://example.org/urid");
+ LV2_URID eg_string = urid_map(NULL, "http://example.org/string");
+ LV2_URID eg_langlit = urid_map(NULL, "http://example.org/langlit");
+ LV2_URID eg_typelit = urid_map(NULL, "http://example.org/typelit");
+ LV2_URID eg_blank = urid_map(NULL, "http://example.org/blank");
+ LV2_URID eg_tuple = urid_map(NULL, "http://example.org/tuple");
+ LV2_URID eg_vector = urid_map(NULL, "http://example.org/vector");
+ LV2_URID eg_seq = urid_map(NULL, "http://example.org/seq");
+
+ uint8_t buf[1024];
+ lv2_atom_forge_set_buffer(&forge, buf, sizeof(buf));
+
+ LV2_Atom_Forge_Frame obj_frame;
+ LV2_Atom* obj = (LV2_Atom*)lv2_atom_forge_blank(
+ &forge, &obj_frame, 1, eg_Object);
+
+ // eg_one = (Int32)1
+ lv2_atom_forge_property_head(&forge, eg_one, 0);
+ LV2_Atom_Int32* one = lv2_atom_forge_int32(&forge, 1);
+ if (one->value != 1) {
+ return test_fail("%d != 1\n", one->value);
+ }
+
+ // eg_two = (Int64)2
+ lv2_atom_forge_property_head(&forge, eg_two, 0);
+ LV2_Atom_Int64* two = lv2_atom_forge_int64(&forge, 2);
+ if (two->value != 2) {
+ return test_fail("%ld != 2\n", two->value);
+ }
+
+ // eg_three = (Float)3.0
+ lv2_atom_forge_property_head(&forge, eg_three, 0);
+ LV2_Atom_Float* three = lv2_atom_forge_float(&forge, 3.0f);
+ if (three->value != 3) {
+ return test_fail("%f != 3\n", three->value);
+ }
+
+ // eg_four = (Double)4.0
+ lv2_atom_forge_property_head(&forge, eg_four, 0);
+ LV2_Atom_Double* four = lv2_atom_forge_double(&forge, 4.0);
+ if (four->value != 4) {
+ return test_fail("%ld != 4\n", four->value);
+ }
+
+ // eg_true = (Bool)1
+ lv2_atom_forge_property_head(&forge, eg_true, 0);
+ LV2_Atom_Bool* t = lv2_atom_forge_bool(&forge, true);
+ if (t->value != 1) {
+ return test_fail("%ld != 1 (true)\n", t->value);
+ }
+
+ // eg_false = (Bool)0
+ lv2_atom_forge_property_head(&forge, eg_false, 0);
+ LV2_Atom_Bool* f = lv2_atom_forge_bool(&forge, false);
+ if (f->value != 0) {
+ return test_fail("%ld != 0 (false)\n", f->value);
+ }
+
+ // eg_path = (Path)"/foo/bar"
+ const uint8_t* pstr = (const uint8_t*)"/foo/bar";
+ const size_t pstr_len = strlen((const char*)pstr);
+ lv2_atom_forge_property_head(&forge, eg_path, 0);
+ LV2_Atom_String* path = lv2_atom_forge_uri(&forge, pstr, pstr_len);
+ uint8_t* pbody = (uint8_t*)LV2_ATOM_BODY(path);
+ if (strcmp((const char*)pbody, (const char*)pstr)) {
+ return test_fail("%s != \"%s\"\n",
+ (const char*)pbody, (const char*)pstr);
+ }
+
+ // eg_uri = (URI)"http://example.org/value"
+ const uint8_t* ustr = (const uint8_t*)"http://example.org/value";
+ const size_t ustr_len = strlen((const char*)ustr);
+ lv2_atom_forge_property_head(&forge, eg_uri, 0);
+ LV2_Atom_String* uri = lv2_atom_forge_uri(&forge, ustr, ustr_len);
+ uint8_t* ubody = (uint8_t*)LV2_ATOM_BODY(uri);
+ if (strcmp((const char*)ubody, (const char*)ustr)) {
+ return test_fail("%s != \"%s\"\n",
+ (const char*)ubody, (const char*)ustr);
+ }
+
+ // eg_urid = (URID)"http://example.org/value"
+ LV2_URID eg_value = urid_map(NULL, "http://example.org/value");
+ lv2_atom_forge_property_head(&forge, eg_urid, 0);
+ LV2_Atom_URID* urid = lv2_atom_forge_urid(&forge, eg_value);
+ if (urid->id != eg_value) {
+ return test_fail("%u != %u\n", urid->id, eg_value);
+ }
+
+ // eg_string = (String)"hello"
+ lv2_atom_forge_property_head(&forge, eg_string, 0);
+ LV2_Atom_String* string = lv2_atom_forge_string(
+ &forge, (const uint8_t*)"hello", strlen("hello"));
+ uint8_t* sbody = (uint8_t*)LV2_ATOM_BODY(string);
+ if (strcmp((const char*)sbody, "hello")) {
+ return test_fail("%s != \"hello\"\n", (const char*)sbody);
+ }
+
+ // eg_langlit = (Literal)"bonjour"@fr
+ lv2_atom_forge_property_head(&forge, eg_langlit, 0);
+ LV2_Atom_Literal* langlit = lv2_atom_forge_literal(
+ &forge, (const uint8_t*)"bonjour", strlen("bonjour"),
+ 0, urid_map(NULL, "http://lexvo.org/id/iso639-3/fra"));
+ uint8_t* llbody = (uint8_t*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, langlit);
+ if (strcmp((const char*)llbody, "bonjour")) {
+ return test_fail("%s != \"bonjour\"\n", (const char*)llbody);
+ }
+
+ // eg_typelit = (Literal)"bonjour"@fr
+ lv2_atom_forge_property_head(&forge, eg_typelit, 0);
+ LV2_Atom_Literal* typelit = lv2_atom_forge_literal(
+ &forge, (const uint8_t*)"value", strlen("value"),
+ urid_map(NULL, "http://example.org/Type"), 0);
+ uint8_t* tlbody = (uint8_t*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, typelit);
+ if (strcmp((const char*)tlbody, "value")) {
+ return test_fail("%s != \"value\"\n", (const char*)tlbody);
+ }
+
+ // eg_blank = [ a <http://example.org/Object> ]
+ lv2_atom_forge_property_head(&forge, eg_blank, 0);
+ LV2_Atom_Forge_Frame blank_frame;
+ lv2_atom_forge_blank(&forge, &blank_frame, 2, eg_Object);
+ lv2_atom_forge_pop(&forge, &blank_frame);
+
+ // eg_tuple = "foo",true
+ lv2_atom_forge_property_head(&forge, eg_tuple, 0);
+ LV2_Atom_Forge_Frame tuple_frame;
+ LV2_Atom_Tuple* tuple = (LV2_Atom_Tuple*)lv2_atom_forge_tuple(
+ &forge, &tuple_frame);
+ LV2_Atom_String* tup0 = lv2_atom_forge_string(
+ &forge, (const uint8_t*)"foo", strlen("foo"));
+ LV2_Atom_Bool* tup1 = lv2_atom_forge_bool(&forge, true);
+ lv2_atom_forge_pop(&forge, &tuple_frame);
+ LV2_Atom_Tuple_Iter i = lv2_tuple_begin(tuple);
+ if (lv2_tuple_is_end(tuple, i)) {
+ return test_fail("Tuple iterator is empty\n");
+ }
+ LV2_Atom* tup0i = (LV2_Atom*)lv2_tuple_iter_get(i);
+ if (!lv2_atom_equals((LV2_Atom*)tup0, tup0i)) {
+ return test_fail("Corrupt tuple element 0\n");
+ }
+ i = lv2_tuple_iter_next(i);
+ if (lv2_tuple_is_end(tuple, i)) {
+ return test_fail("Premature end of tuple iterator\n");
+ }
+ LV2_Atom* tup1i = lv2_tuple_iter_get(i);
+ if (!lv2_atom_equals((LV2_Atom*)tup1, tup1i)) {
+ return test_fail("Corrupt tuple element 1\n");
+ }
+ i = lv2_tuple_iter_next(i);
+ if (!lv2_tuple_is_end(tuple, i)) {
+ return test_fail("Tuple iter is not at end\n");
+ }
+
+ // eg_vector = (Vector<Int32>)1,2,3,4
+ lv2_atom_forge_property_head(&forge, eg_vector, 0);
+ int32_t elems[] = { 1, 2, 3, 4 };
+ LV2_Atom_Vector* vector = lv2_atom_forge_vector(
+ &forge, 4, forge.Int32, sizeof(int32_t), elems);
+ void* vec_body = LV2_ATOM_CONTENTS(LV2_Atom_Vector, vector);
+ if (memcmp(elems, vec_body, sizeof(elems))) {
+ return test_fail("Corrupt vector\n");
+ }
+
+ // eg_seq = (Sequence)1, 2
+ lv2_atom_forge_property_head(&forge, eg_seq, 0);
+ LV2_Atom_Forge_Frame seq_frame;
+ lv2_atom_forge_sequence_head(&forge, &seq_frame, 0);
+ lv2_atom_forge_audio_time(&forge, 0, 0);
+ lv2_atom_forge_int32(&forge, 1);
+ lv2_atom_forge_audio_time(&forge, 1, 0);
+ lv2_atom_forge_int32(&forge, 2);
+ lv2_atom_forge_pop(&forge, &seq_frame);
+
+ lv2_atom_forge_pop(&forge, &obj_frame);
+
+ SerdNode s = serd_node_from_string(SERD_BLANK, USTR("obj"));
+ SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_RDF "value"));
+ printf("%s", atom_to_turtle(&unmap, &s, &p, obj));
+
+ printf("All tests passed.\n");
+ return 0;
+}
diff --git a/waf b/waf
new file mode 100755
index 0000000..907b984
--- /dev/null
+++ b/waf
Binary files differ
diff --git a/wscript b/wscript
new file mode 100644
index 0000000..aa3ad48
--- /dev/null
+++ b/wscript
@@ -0,0 +1,181 @@
+#!/usr/bin/env python
+import glob
+import os
+import shutil
+import subprocess
+import sys
+
+from waflib.extras import autowaf as autowaf
+import waflib.Logs as Logs, waflib.Options as Options
+
+# Version of this package (even if built as a child)
+SERIATOM_VERSION = '0.0.0'
+SERIATOM_MAJOR_VERSION = '0'
+
+# Library version (UNIX style major, minor, micro)
+# major increment <=> incompatible changes
+# minor increment <=> compatible changes (additions)
+# micro increment <=> no interface changes
+# Seriatom uses the same version number for both library and package
+SERIATOM_LIB_VERSION = SERIATOM_VERSION
+
+# Variables for 'waf dist'
+APPNAME = 'seriatom'
+VERSION = SERIATOM_VERSION
+
+# Mandatory variables
+top = '.'
+out = 'build'
+
+def options(opt):
+ opt.load('compiler_c')
+ autowaf.set_options(opt)
+ opt.add_option('--test', action='store_true', default=False, dest='build_tests',
+ help="Build unit tests")
+ opt.add_option('--static', action='store_true', default=False, dest='static',
+ help="Build static library")
+
+def configure(conf):
+ conf.load('compiler_c')
+ autowaf.configure(conf)
+ autowaf.display_header('Seriatom Configuration')
+
+ if conf.env['MSVC_COMPILER']:
+ conf.env.append_unique('CFLAGS', ['-TP', '-MD'])
+ else:
+ conf.env.append_unique('CFLAGS', '-std=c99')
+
+ conf.env['BUILD_TESTS'] = Options.options.build_tests
+ conf.env['BUILD_STATIC'] = Options.options.static
+
+ # Check for gcov library (for test coverage)
+ if conf.env['BUILD_TESTS']:
+ conf.check_cc(lib='gcov',
+ define_name='HAVE_GCOV',
+ mandatory=False)
+
+ autowaf.check_pkg(conf, 'serd-0', uselib_store='SERD',
+ atleast_version='0.8.0', mandatory=True)
+
+ autowaf.define(conf, 'SERIATOM_VERSION', SERIATOM_VERSION)
+ conf.write_config_header('seriatom_config.h', remove=False)
+
+ autowaf.display_msg(conf, "Unit tests", str(conf.env['BUILD_TESTS']))
+ print('')
+
+lib_source = [
+ 'src/atom_to_rdf.c'
+]
+
+def build(bld):
+ # C Headers
+ includedir = '${INCLUDEDIR}/seriatom-%s/seriatom' % SERIATOM_MAJOR_VERSION
+ bld.install_files(includedir, bld.path.ant_glob('seriatom/*.h'))
+
+ # Pkgconfig file
+ autowaf.build_pc(bld, 'SERIATOM', SERIATOM_VERSION, SERIATOM_MAJOR_VERSION,
+ 'SERD',
+ {'SERIATOM_MAJOR_VERSION' : SERIATOM_MAJOR_VERSION})
+
+ libflags = [ '-fvisibility=hidden' ]
+ libs = [ 'm' ]
+ if bld.env['MSVC_COMPILER']:
+ libflags = []
+ libs = []
+
+ # Shared Library
+ obj = bld(features = 'c cshlib',
+ export_includes = ['.'],
+ source = lib_source,
+ includes = ['.', './src'],
+ lib = libs,
+ name = 'libseriatom',
+ target = 'seriatom-%s' % SERIATOM_MAJOR_VERSION,
+ vnum = SERIATOM_LIB_VERSION,
+ install_path = '${LIBDIR}',
+ cflags = libflags + [ '-DSERIATOM_SHARED',
+ '-DSERIATOM_INTERNAL' ])
+ autowaf.use_lib(bld, obj, 'SERD')
+
+ # Static library
+ if bld.env['BUILD_STATIC']:
+ obj = bld(features = 'c cstlib',
+ export_includes = ['.'],
+ source = lib_source,
+ includes = ['.', './src'],
+ lib = libs,
+ name = 'libseriatom_static',
+ target = 'seriatom-%s' % SERIATOM_MAJOR_VERSION,
+ vnum = SERIATOM_LIB_VERSION,
+ install_path = '${LIBDIR}',
+ cflags = ['-DSERIATOM_INTERNAL'])
+ autowaf.use_lib(bld, obj, 'SERD')
+
+ if bld.env['BUILD_TESTS']:
+ test_libs = libs
+ test_cflags = ['']
+ if bld.is_defined('HAVE_GCOV'):
+ test_libs += ['gcov']
+ test_cflags += ['-fprofile-arcs', '-ftest-coverage']
+
+ # Static library (for unit test code coverage)
+ obj = bld(features = 'c cstlib',
+ source = lib_source,
+ includes = ['.', './src'],
+ lib = test_libs,
+ name = 'libseriatom_profiled',
+ target = 'seriatom_profiled',
+ install_path = '',
+ cflags = test_cflags + ['-DSERIATOM_INTERNAL'])
+ autowaf.use_lib(bld, obj, 'SERD')
+
+ # Unit test program
+ obj = bld(features = 'c cprogram',
+ source = 'tests/seriatom_test.c',
+ includes = ['.', './src'],
+ use = 'libseriatom_profiled',
+ lib = test_libs,
+ target = 'seriatom_test',
+ install_path = '',
+ cflags = test_cflags)
+
+ # Documentation
+ autowaf.build_dox(bld, 'SERIATOM', SERIATOM_VERSION, top, out)
+
+ bld.add_post_fun(autowaf.run_ldconfig)
+ if bld.env['DOCS']:
+ bld.add_post_fun(fix_docs)
+
+def test(ctx):
+ autowaf.pre_test(ctx, APPNAME)
+ os.environ['PATH'] = '.' + os.pathsep + os.getenv('PATH')
+ autowaf.run_tests(ctx, APPNAME, ['seriatom_test'], dirs=['./src','./tests'])
+ autowaf.post_test(ctx, APPNAME)
+
+def lint(ctx):
+ subprocess.call('cpplint.py --filter=+whitespace/comments,-whitespace/tab,-whitespace/braces,-whitespace/labels,-build/header_guard,-readability/casting,-readability/todo,-build/include src/* seriatom/*', shell=True)
+
+def build_dir(ctx, subdir):
+ if autowaf.is_child():
+ return os.path.join('build', APPNAME, subdir)
+ else:
+ return os.path.join('build', subdir)
+
+def fix_docs(ctx):
+ try:
+ top = os.getcwd()
+ os.chdir(build_dir(ctx, 'doc/html'))
+ os.system("sed -i 's/SERIATOM_API //' group__seriatom.html")
+ os.system("sed -i 's/SERIATOM_DEPRECATED //' group__seriatom.html")
+ os.remove('index.html')
+ os.symlink('group__seriatom.html',
+ 'index.html')
+ os.chdir(top)
+ os.chdir(build_dir(ctx, 'doc/man/man3'))
+ os.system("sed -i 's/SERIATOM_API //' seriatom.3")
+ os.chdir(top)
+ except:
+ Logs.error("Failed to fix up %s documentation" % APPNAME)
+
+def upload_docs(ctx):
+ os.system("rsync -ravz --delete -e ssh build/doc/html/ drobilla@drobilla.net:~/drobilla.net/docs/seriatom/")