aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2011-02-25 07:28:10 +0000
committerDavid Robillard <d@drobilla.net>2011-02-25 07:28:10 +0000
commitddd073f0a1c47e5dbba2efd04617862e49171bed (patch)
treea3059f6da6da72fb17b6e47b059fad8e8ab4008a
parent7cab293e741784109f9e0a6a3893d3c6629da999 (diff)
downloadserd-ddd073f0a1c47e5dbba2efd04617862e49171bed.tar.gz
serd-ddd073f0a1c47e5dbba2efd04617862e49171bed.tar.bz2
serd-ddd073f0a1c47e5dbba2efd04617862e49171bed.zip
Abstract common read state tracking code (SerdReadState) to make user code less tedious.
git-svn-id: http://svn.drobilla.net/serd/trunk@110 490d8e77-9747-427b-9fa3-0b8f29cee8a0
-rw-r--r--serd/serd.h63
-rw-r--r--src/reader.c102
-rw-r--r--src/serdi.c89
-rw-r--r--wscript7
4 files changed, 183 insertions, 78 deletions
diff --git a/serd/serd.h b/serd/serd.h
index 803ddea7..a56ab971 100644
--- a/serd/serd.h
+++ b/serd/serd.h
@@ -63,7 +63,7 @@ extern "C" {
*/
/**
- Namespace prefixes.
+ Environment (namespace prefixes).
A SerdEnv represents a set of namespace prefixes, and is used to resolve
CURIEs to full URIs.
@@ -79,6 +79,16 @@ typedef struct SerdEnvImpl* SerdEnv;
typedef struct SerdReaderImpl* SerdReader;
/**
+ Read state.
+
+ This represents state (context) necessary for fully resolving URIs during a
+ read (i.e. the base URI and namespace prefixes). It is implemented
+ separately from SerdReader so the reader can avoid the overhead in cases
+ where this information is unnecessary (e.g. streaming reserialisation).
+*/
+typedef struct SerdReadStateImpl* SerdReadState;
+
+/**
RDF writer.
A SerdWriter provides a number of functions to allow writing RDF syntax out
@@ -330,7 +340,7 @@ serd_node_free(SerdNode* node);
*/
/**
- Sink for base URI changes.
+ Sink (callback) for base URI changes.
Called whenever the base URI of the serialisation changes.
*/
@@ -338,7 +348,7 @@ typedef bool (*SerdBaseSink)(void* handle,
const SerdNode* uri);
/**
- Sink for namespace definitions.
+ Sink (callback) for namespace definitions.
Called whenever a prefix is defined in the serialisation.
*/
@@ -347,7 +357,7 @@ typedef bool (*SerdPrefixSink)(void* handle,
const SerdNode* uri);
/**
- Sink for statements.
+ Sink (callback) for statements.
Called for every RDF statement in the serialisation.
*/
@@ -360,7 +370,7 @@ typedef bool (*SerdStatementSink)(void* handle,
const SerdNode* object_lang);
/**
- Sink for anonymous node end markers.
+ Sink (callback) for anonymous node end markers.
This is called to indicate that the anonymous node with the given
@a value will no longer be referred to by any future statements
@@ -483,6 +493,49 @@ void
serd_reader_free(SerdReader reader);
/**
+ Create a new read state with the given initial base URI and environment.
+
+ A reference to @a env will be kept, and @a env will be modified as the
+ state is modified.
+*/
+SERD_API
+SerdReadState
+serd_read_state_new(SerdEnv env,
+ const uint8_t* base_uri_str);
+
+/**
+ Free @a state.
+*/
+SERD_API
+void
+serd_read_state_free(SerdReadState state);
+
+/**
+ Get the current base URI.
+*/
+SERD_API
+SerdNode
+serd_read_state_get_base_uri(SerdReadState state,
+ SerdURI* out);
+
+/**
+ Set the current base URI.
+*/
+SERD_API
+bool
+serd_read_state_set_base_uri(SerdReadState state,
+ const SerdNode* uri_node);
+
+/**
+ Set a namespace prefix.
+*/
+SERD_API
+bool
+serd_read_state_set_prefix(SerdReadState state,
+ const SerdNode* name,
+ const SerdNode* uri_node);
+
+/**
@}
@name SerdWriter
@{
diff --git a/src/reader.c b/src/reader.c
index e0790e39..b19ffcdc 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -41,9 +41,6 @@
#define STACK_PAGE_SIZE 4096
#define READ_BUF_LEN 4096
-#ifndef NDEBUG
-#define STACK_DEBUG 1
-#endif
typedef struct {
const uint8_t* filename;
@@ -98,12 +95,18 @@ struct SerdReaderImpl {
int32_t read_head; ///< Offset into read_buf
bool from_file; ///< True iff reading from @ref fd
bool eof;
-#ifdef STACK_DEBUG
+#ifdef SUIL_STACK_CHECK
Ref* alloc_stack; ///< Stack of push offsets
size_t n_allocs; ///< Number of stack pushes
#endif
};
+struct SerdReadStateImpl {
+ SerdEnv env;
+ SerdNode base_uri_node;
+ SerdURI base_uri;
+};
+
typedef enum {
SERD_SUCCESS = 0, ///< Completed successfully
SERD_FAILURE = 1, ///< Non-fatal failure
@@ -202,7 +205,7 @@ eat_string(SerdReader reader, const char* str, unsigned n)
}
}
-#ifdef STACK_DEBUG
+#ifdef SUIL_STACK_CHECK
static inline bool
stack_is_top_string(SerdReader reader, Ref ref)
{
@@ -229,7 +232,7 @@ push_string(SerdReader reader, const char* c_str, size_t n_bytes)
str->n_bytes = n_bytes;
str->n_chars = n_bytes - 1;
memcpy(str->buf, c_str, n_bytes);
-#ifdef STACK_DEBUG
+#ifdef SUIL_STACK_CHECK
reader->alloc_stack = realloc(reader->alloc_stack,
sizeof(uint8_t*) * (++reader->n_allocs));
reader->alloc_stack[reader->n_allocs - 1] = (mem - reader->stack.buf);
@@ -249,7 +252,7 @@ deref(SerdReader reader, const Ref ref)
static inline void
push_byte(SerdReader reader, Ref ref, const uint8_t c)
{
- #ifdef STACK_DEBUG
+ #ifdef SUIL_STACK_CHECK
assert(stack_is_top_string(reader, ref));
#endif
serd_stack_push(&reader->stack, 1);
@@ -273,7 +276,7 @@ pop_string(SerdReader reader, Ref ref)
|| ref == reader->rdf_rest.value) {
return;
}
- #ifdef STACK_DEBUG
+ #ifdef SUIL_STACK_CHECK
if (!stack_is_top_string(reader, ref)) {
fprintf(stderr, "attempt to pop non-top string %s\n",
deref(reader, ref)->buf);
@@ -1377,7 +1380,7 @@ serd_reader_new(SerdSyntax syntax,
me->read_buf = 0;
me->read_head = 0;
me->eof = false;
-#ifdef STACK_DEBUG
+#ifdef SERD_STACK_CHECK
me->alloc_stack = 0;
me->n_allocs = 0;
#endif
@@ -1401,7 +1404,7 @@ serd_reader_free(SerdReader reader)
pop_string(me, me->rdf_rest.value);
pop_string(me, me->rdf_first.value);
-#ifdef STACK_DEBUG
+#ifdef SERD_STACK_CHECK
free(me->alloc_stack);
#endif
free(me->stack.buf);
@@ -1458,3 +1461,82 @@ serd_reader_read_string(SerdReader me, const uint8_t* utf8)
me->read_buf = NULL;
return ret;
}
+
+SERD_API
+SerdReadState
+serd_read_state_new(SerdEnv env,
+ const uint8_t* base_uri_str)
+{
+ SerdReadState state = malloc(sizeof(struct SerdReadStateImpl));
+ SerdURI base_base_uri = SERD_URI_NULL;
+ state->env = env;
+ state->base_uri_node = serd_node_new_uri_from_string(
+ base_uri_str, &base_base_uri, &state->base_uri);
+ return state;
+}
+
+SERD_API
+void
+serd_read_state_free(SerdReadState state)
+{
+ serd_node_free(&state->base_uri_node);
+ free(state);
+}
+
+SERD_API
+SerdNode
+serd_read_state_get_base_uri(SerdReadState state,
+ SerdURI* out)
+{
+ *out = state->base_uri;
+ return state->base_uri_node;
+}
+
+SERD_API
+bool
+serd_read_state_set_base_uri(SerdReadState state,
+ const SerdNode* uri_node)
+{
+ // Resolve base URI and create a new node and URI for it
+ SerdURI base_uri;
+ SerdNode base_uri_node = serd_node_new_uri_from_node(
+ uri_node, &state->base_uri, &base_uri);
+
+ if (base_uri_node.buf) {
+ // Replace the current base URI
+ serd_node_free(&state->base_uri_node);
+ state->base_uri_node = base_uri_node;
+ state->base_uri = base_uri;
+ return true;
+ }
+ return false;
+}
+
+SERD_API
+bool
+serd_read_state_set_prefix(SerdReadState state,
+ const SerdNode* name,
+ const SerdNode* uri_node)
+{
+ if (serd_uri_string_has_scheme(uri_node->buf)) {
+ // Set prefix to absolute URI
+ serd_env_add(state->env, name, uri_node);
+ return true;
+ } else {
+ // Resolve relative URI and create a new node and URI for it
+ SerdURI abs_uri;
+ SerdNode abs_uri_node = serd_node_new_uri_from_node(
+ uri_node, &state->base_uri, &abs_uri);
+
+ if (!abs_uri_node.buf) {
+ return false;
+ }
+
+ // Set prefix to resolved (absolute) URI
+ serd_env_add(state->env, name, &abs_uri_node);
+ serd_node_free(&abs_uri_node);
+ return true;
+ }
+ return false;
+}
+
diff --git a/src/serdi.c b/src/serdi.c
index d97cb9f9..7eede1e6 100644
--- a/src/serdi.c
+++ b/src/serdi.c
@@ -31,38 +31,20 @@
#include "serd-config.h"
typedef struct {
- SerdWriter writer;
- SerdEnv env;
- SerdNode base_uri_node;
- SerdURI base_uri;
+ SerdEnv env;
+ SerdReadState read_state;
+ SerdWriter writer;
} State;
-static uint8_t*
-copy_string(const uint8_t* str, size_t* n_bytes)
-{
- const size_t len = strlen((const char*)str);
- uint8_t* const ret = malloc(len + 1);
- memcpy(ret, str, len + 1);
- *n_bytes = len + 1;
- return ret;
-}
-
static bool
event_base(void* handle,
const SerdNode* uri_node)
{
State* const state = (State*)handle;
- // Resolve base URI and create a new node and URI for it
- SerdURI base_uri;
- SerdNode base_uri_node = serd_node_new_uri_from_node(
- uri_node, &state->base_uri, &base_uri);
-
- if (base_uri_node.buf) {
- // Replace the current base URI
- serd_node_free(&state->base_uri_node);
- state->base_uri_node = base_uri_node;
- state->base_uri = base_uri;
+ if (serd_read_state_set_base_uri(state->read_state, uri_node)) {
+ SerdURI base_uri;
+ serd_read_state_get_base_uri(state->read_state, &base_uri);
serd_writer_set_base_uri(state->writer, &base_uri);
return true;
}
@@ -75,23 +57,8 @@ event_prefix(void* handle,
const SerdNode* uri_node)
{
State* const state = (State*)handle;
- if (serd_uri_string_has_scheme(uri_node->buf)) {
- // Set prefix to absolute URI
- serd_env_add(state->env, name, uri_node);
- } else {
- // Resolve relative URI and create a new node and URI for it
- SerdURI abs_uri;
- SerdNode abs_uri_node = serd_node_new_uri_from_node(
- uri_node, &state->base_uri, &abs_uri);
-
- if (!abs_uri_node.buf) {
- return false;
- }
-
- // Set prefix to resolved (absolute) URI
- serd_env_add(state->env, name, &abs_uri_node);
- serd_node_free(&abs_uri_node);
- }
+
+ serd_read_state_set_prefix(state->read_state, name, uri_node);
serd_writer_set_prefix(state->writer, name, uri_node);
return true;
}
@@ -218,20 +185,19 @@ main(int argc, char** argv)
}
}
- uint8_t* base_uri_str = NULL;
- size_t base_uri_n_bytes = 0;
- SerdURI base_uri;
+ const uint8_t* base_uri_str = NULL;
+ SerdURI base_uri;
if (a < argc) { // Base URI given on command line
const uint8_t* const in_base_uri = (const uint8_t*)argv[a++];
if (!serd_uri_parse((const uint8_t*)in_base_uri, &base_uri)) {
fprintf(stderr, "invalid base URI `%s'\n", argv[2]);
return 1;
}
- base_uri_str = copy_string(in_base_uri, &base_uri_n_bytes);
+ base_uri_str = in_base_uri;
} else if (from_file) { // Use input file URI
- base_uri_str = copy_string(input, &base_uri_n_bytes);
+ base_uri_str = input;
} else {
- base_uri_str = copy_string((const uint8_t*)"", &base_uri_n_bytes);
+ base_uri_str = (const uint8_t*)"";
}
if (!serd_uri_parse(base_uri_str, &base_uri)) {
@@ -241,22 +207,21 @@ main(int argc, char** argv)
FILE* out_fd = stdout;
SerdEnv env = serd_env_new();
- SerdStyle output_style = (output_syntax == SERD_NTRIPLES)
- ? SERD_STYLE_ASCII
- : SERD_STYLE_ABBREVIATED;
+ SerdStyle output_style = SERD_STYLE_RESOLVED;
+ if (output_syntax == SERD_NTRIPLES) {
+ output_style |= SERD_STYLE_ASCII;
+ } else {
+ output_style |= SERD_STYLE_ABBREVIATED;
+ }
- output_style |= SERD_STYLE_RESOLVED;
+ SerdReadState read_state = serd_read_state_new(env, base_uri_str);
- const SerdNode base_uri_node = { SERD_URI,
- base_uri_n_bytes,
- base_uri_n_bytes - 1,
- base_uri_str };
+ serd_read_state_get_base_uri(read_state, &base_uri);
- State state = {
- serd_writer_new(output_syntax, output_style,
- env, &base_uri, file_sink, out_fd),
- env, base_uri_node, base_uri
- };
+ SerdWriter writer = serd_writer_new(
+ output_syntax, output_style, env, &base_uri, file_sink, out_fd);
+
+ State state = { env, read_state, writer };
SerdReader reader = serd_reader_new(
SERD_TURTLE, &state,
@@ -274,11 +239,9 @@ main(int argc, char** argv)
serd_writer_finish(state.writer);
serd_writer_free(state.writer);
-
+ serd_read_state_free(state.read_state);
serd_env_free(state.env);
- serd_node_free(&state.base_uri_node);
-
if (success) {
return 0;
}
diff --git a/wscript b/wscript
index 007a9207..f44ba1ad 100644
--- a/wscript
+++ b/wscript
@@ -32,6 +32,8 @@ def options(opt):
help="Do not build command line utilities")
opt.add_option('--test', action='store_true', default=False, dest='build_tests',
help="Build unit tests")
+ opt.add_option('--stack-check', action='store_true', default=False, dest='stack_check',
+ help="Include runtime stack sanity checks")
def configure(conf):
conf.line_just = max(conf.line_just, 59)
@@ -44,6 +46,11 @@ def configure(conf):
conf.env['BUILD_TESTS'] = Options.options.build_tests
conf.env['BUILD_UTILS'] = not Options.options.no_utils
+ if Options.options.stack_check:
+ autowaf.define(conf, 'SERD_STACK_CHECK', SERD_VERSION)
+
+ conf.env['BUILD_TESTS'] = Options.options.build_tests
+
autowaf.define(conf, 'SERD_VERSION', SERD_VERSION)
conf.write_config_header('serd-config.h', remove=False)