aboutsummaryrefslogtreecommitdiffstats
path: root/src/writer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/writer.c')
-rw-r--r--src/writer.c229
1 files changed, 117 insertions, 112 deletions
diff --git a/src/writer.c b/src/writer.c
index 579c7f3e..abfe327b 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -15,6 +15,7 @@
*/
#include "byte_sink.h"
+#include "node.h"
#include "serd_internal.h"
#include "stack.h"
#include "string_utils.h"
@@ -39,14 +40,12 @@ typedef enum {
} Field;
typedef struct {
- SerdNode graph;
- SerdNode subject;
- SerdNode predicate;
+ SerdNode* graph;
+ SerdNode* subject;
+ SerdNode* predicate;
} WriteContext;
-static const WriteContext WRITE_CONTEXT_NULL = {{0, 0, 0, SERD_NOTHING},
- {0, 0, 0, SERD_NOTHING},
- {0, 0, 0, SERD_NOTHING}};
+static const WriteContext WRITE_CONTEXT_NULL = {NULL, NULL, NULL};
typedef enum {
SEP_NONE,
@@ -95,7 +94,7 @@ struct SerdWriterImpl {
SerdSyntax syntax;
SerdWriterFlags flags;
SerdEnv* env;
- SerdNode root_node;
+ SerdNode* root_node;
SerdURIView root_uri;
SerdURIView base_uri;
SerdStack anon_stack;
@@ -103,7 +102,7 @@ struct SerdWriterImpl {
SerdErrorFunc error_func;
void* error_handle;
WriteContext context;
- SerdNode list_subj;
+ SerdNode* list_subj;
unsigned list_depth;
unsigned indent;
char* bprefix;
@@ -150,7 +149,8 @@ w_err(SerdWriter* writer, SerdStatus st, const char* fmt, ...)
va_end(args);
}
-SERD_PURE_FUNC static WriteContext*
+SERD_PURE_FUNC
+static WriteContext*
anon_stack_top(SerdWriter* writer)
{
assert(!serd_stack_is_empty(&writer->anon_stack));
@@ -158,18 +158,19 @@ anon_stack_top(SerdWriter* writer)
sizeof(WriteContext));
}
-static void
-copy_node(SerdNode* dst, const SerdNode* src)
+static inline SerdNode*
+ctx(SerdWriter* writer, const Field field)
{
- if (src) {
- dst->buf = (char*)realloc((char*)dst->buf, src->n_bytes + 1);
- dst->n_bytes = src->n_bytes;
- dst->flags = src->flags;
- dst->type = src->type;
- memcpy((char*)dst->buf, src->buf, src->n_bytes + 1);
- } else {
- dst->type = SERD_NOTHING;
+ SerdNode* node = NULL;
+ if (field == FIELD_SUBJECT) {
+ node = writer->context.subject;
+ } else if (field == FIELD_PREDICATE) {
+ node = writer->context.predicate;
+ } else if (field == FIELD_GRAPH) {
+ node = writer->context.graph;
}
+
+ return node && node->type ? node : NULL;
}
static size_t
@@ -264,6 +265,12 @@ write_uri(SerdWriter* writer, const char* utf8, size_t n_bytes)
return len;
}
+static size_t
+write_uri_from_node(SerdWriter* writer, const SerdNode* node)
+{
+ return write_uri(writer, serd_node_string(node), node->length);
+}
+
static bool
lname_must_escape(const char c)
{
@@ -473,23 +480,26 @@ write_sep(SerdWriter* writer, const Sep sep)
static SerdStatus
reset_context(SerdWriter* writer, bool graph)
{
- if (graph) {
- writer->context.graph.type = SERD_NOTHING;
+ if (graph && writer->context.graph) {
+ memset(writer->context.graph, 0, sizeof(SerdNode));
}
-
- writer->context.subject.type = SERD_NOTHING;
- writer->context.predicate.type = SERD_NOTHING;
- writer->empty = false;
+ if (writer->context.subject) {
+ memset(writer->context.subject, 0, sizeof(SerdNode));
+ }
+ if (writer->context.predicate) {
+ memset(writer->context.predicate, 0, sizeof(SerdNode));
+ }
+ writer->empty = false;
return SERD_SUCCESS;
}
static SerdStatus
free_context(SerdWriter* writer)
{
- serd_node_free(&writer->context.graph);
- serd_node_free(&writer->context.subject);
- serd_node_free(&writer->context.predicate);
- return reset_context(writer, true);
+ serd_node_free(writer->context.graph);
+ serd_node_free(writer->context.subject);
+ serd_node_free(writer->context.predicate);
+ return SERD_SUCCESS;
}
static bool
@@ -507,23 +517,24 @@ write_literal(SerdWriter* writer,
const SerdNode* lang,
SerdStatementFlags flags)
{
- if (supports_abbrev(writer) && datatype && datatype->buf) {
- const char* type_uri = datatype->buf;
+ const char* node_str = serd_node_string(node);
+ const char* type_uri = datatype ? serd_node_string(datatype) : NULL;
+ if (supports_abbrev(writer) && type_uri) {
if (!strncmp(type_uri, NS_XSD, sizeof(NS_XSD) - 1) &&
(!strcmp(type_uri + sizeof(NS_XSD) - 1, "boolean") ||
!strcmp(type_uri + sizeof(NS_XSD) - 1, "integer"))) {
- sink(node->buf, node->n_bytes, writer);
+ sink(node_str, node->length, writer);
return true;
}
if (!strncmp(type_uri, NS_XSD, sizeof(NS_XSD) - 1) &&
!strcmp(type_uri + sizeof(NS_XSD) - 1, "decimal") &&
- strchr(node->buf, '.') && node->buf[node->n_bytes - 1] != '.') {
+ strchr(node_str, '.') && node_str[node->length - 1] != '.') {
/* xsd:decimal literals without trailing digits, e.g. "5.", can
not be written bare in Turtle. We could add a 0 which is
prettier, but changes the text and breaks round tripping.
*/
- sink(node->buf, node->n_bytes, writer);
+ sink(node_str, node->length, writer);
return true;
}
}
@@ -531,17 +542,17 @@ write_literal(SerdWriter* writer,
if (supports_abbrev(writer) &&
(node->flags & (SERD_HAS_NEWLINE | SERD_HAS_QUOTE))) {
sink("\"\"\"", 3, writer);
- write_text(writer, WRITE_LONG_STRING, node->buf, node->n_bytes);
+ write_text(writer, WRITE_LONG_STRING, node_str, node->length);
sink("\"\"\"", 3, writer);
} else {
sink("\"", 1, writer);
- write_text(writer, WRITE_STRING, node->buf, node->n_bytes);
+ write_text(writer, WRITE_STRING, node_str, node->length);
sink("\"", 1, writer);
}
- if (lang && lang->buf) {
+ if (lang && serd_node_string(lang)) {
sink("@", 1, writer);
- sink(lang->buf, lang->n_bytes, writer);
- } else if (datatype && datatype->buf) {
+ sink(serd_node_string(lang), lang->length, writer);
+ } else if (type_uri) {
sink("^^", 2, writer);
return write_node(writer, datatype, NULL, NULL, FIELD_NONE, flags);
}
@@ -567,24 +578,25 @@ write_uri_node(SerdWriter* const writer,
const SerdNode* node,
const Field field)
{
- SerdNode prefix;
- SerdStringView suffix;
+ const SerdNode* prefix = NULL;
+ SerdStringView suffix = {NULL, 0};
- const bool has_scheme = serd_uri_string_has_scheme(node->buf);
+ const char* node_str = serd_node_string(node);
+ const bool has_scheme = serd_uri_string_has_scheme(node_str);
if (supports_abbrev(writer)) {
- if (field == FIELD_PREDICATE && !strcmp(node->buf, NS_RDF "type")) {
+ if (field == FIELD_PREDICATE && !strcmp(node_str, NS_RDF "type")) {
return sink("a", 1, writer) == 1;
}
- if (!strcmp(node->buf, NS_RDF "nil")) {
+ if (!strcmp(node_str, NS_RDF "nil")) {
return sink("()", 2, writer) == 2;
}
if (has_scheme && (writer->flags & SERD_WRITE_CURIED) &&
serd_env_qualify(writer->env, node, &prefix, &suffix) &&
- is_name(prefix.buf, prefix.n_bytes) &&
+ is_name(serd_node_string(prefix), serd_node_length(prefix)) &&
is_name(suffix.buf, suffix.len)) {
- write_uri(writer, prefix.buf, prefix.n_bytes);
+ write_uri_from_node(writer, prefix);
sink(":", 1, writer);
write_uri(writer, suffix.buf, suffix.len);
return true;
@@ -592,11 +604,11 @@ write_uri_node(SerdWriter* const writer,
}
if (!has_scheme && !supports_uriref(writer) &&
- !serd_env_base_uri(writer->env, NULL)->buf) {
+ !serd_env_base_uri(writer->env, NULL)) {
w_err(writer,
SERD_ERR_BAD_ARG,
"syntax does not support URI reference <%s>\n",
- node->buf);
+ node_str);
return false;
}
@@ -606,7 +618,7 @@ write_uri_node(SerdWriter* const writer,
SerdURIView uri;
SerdURIView abs_uri;
serd_env_base_uri(writer->env, &in_base_uri);
- serd_uri_parse(node->buf, &uri);
+ serd_uri_parse(node_str, &uri);
serd_uri_resolve(&uri, &in_base_uri, &abs_uri);
bool rooted = uri_is_under(&writer->base_uri, &writer->root_uri);
SerdURIView* root = rooted ? &writer->root_uri : &writer->base_uri;
@@ -618,7 +630,7 @@ write_uri_node(SerdWriter* const writer,
&uri, &writer->base_uri, root, uri_sink, writer);
}
} else {
- write_uri(writer, node->buf, node->n_bytes);
+ write_uri_from_node(writer, node);
}
write_sep(writer, SEP_URI_END);
return true;
@@ -627,6 +639,8 @@ write_uri_node(SerdWriter* const writer,
static bool
write_curie(SerdWriter* const writer, const SerdNode* const node)
{
+ const char* node_str = serd_node_string(node);
+
SerdStringView prefix = {NULL, 0};
SerdStringView suffix = {NULL, 0};
SerdStatus st = SERD_SUCCESS;
@@ -634,7 +648,7 @@ write_curie(SerdWriter* const writer, const SerdNode* const node)
case SERD_NTRIPLES:
case SERD_NQUADS:
if ((st = serd_env_expand(writer->env, node, &prefix, &suffix))) {
- w_err(writer, st, "undefined namespace prefix `%s'\n", node->buf);
+ w_err(writer, st, "undefined namespace prefix `%s'\n", node_str);
return false;
}
write_sep(writer, SEP_URI_BEGIN);
@@ -644,7 +658,8 @@ write_curie(SerdWriter* const writer, const SerdNode* const node)
break;
case SERD_TURTLE:
case SERD_TRIG:
- write_lname(writer, node->buf, node->n_bytes);
+ write_lname(writer, node_str, node->length);
+ break;
}
return true;
@@ -656,6 +671,7 @@ write_blank(SerdWriter* const writer,
const Field field,
const SerdStatementFlags flags)
{
+ const char* node_str = serd_node_string(node);
if (supports_abbrev(writer)) {
if (is_inline_start(writer, field, flags)) {
++writer->indent;
@@ -664,7 +680,7 @@ write_blank(SerdWriter* const writer,
if (field == FIELD_SUBJECT && (flags & SERD_LIST_S_BEGIN)) {
assert(writer->list_depth == 0);
- copy_node(&writer->list_subj, node);
+ serd_node_set(&writer->list_subj, node);
++writer->list_depth;
++writer->indent;
return write_sep(writer, SEP_LIST_BEGIN);
@@ -684,12 +700,12 @@ write_blank(SerdWriter* const writer,
sink("_:", 2, writer);
if (writer->bprefix &&
- !strncmp(node->buf, writer->bprefix, writer->bprefix_len)) {
- sink(node->buf + writer->bprefix_len,
- node->n_bytes - writer->bprefix_len,
+ !strncmp(node_str, writer->bprefix, writer->bprefix_len)) {
+ sink(node_str + writer->bprefix_len,
+ node->length - writer->bprefix_len,
writer);
} else {
- sink(node->buf, node->n_bytes, writer);
+ sink(node_str, node->length, writer);
}
return true;
@@ -705,8 +721,6 @@ write_node(SerdWriter* writer,
{
bool ret = false;
switch (node->type) {
- case SERD_NOTHING:
- break;
case SERD_LITERAL:
ret = write_literal(writer, node, datatype, lang, flags);
break;
@@ -720,7 +734,6 @@ write_node(SerdWriter* writer,
ret = write_blank(writer, node, field, flags);
break;
}
-
writer->last_sep = SEP_NONE;
return ret;
}
@@ -728,7 +741,7 @@ write_node(SerdWriter* writer,
static bool
is_resource(const SerdNode* node)
{
- return node && node->buf && node->type > SERD_LITERAL;
+ return node && node->type > SERD_LITERAL;
}
static void
@@ -736,7 +749,7 @@ write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred)
{
write_node(writer, pred, NULL, NULL, FIELD_PREDICATE, flags);
write_sep(writer, SEP_P_O);
- copy_node(&writer->context.predicate, pred);
+ serd_node_set(&writer->context.predicate, pred);
}
static bool
@@ -747,13 +760,13 @@ write_list_obj(SerdWriter* writer,
const SerdNode* datatype,
const SerdNode* lang)
{
- if (!strcmp(object->buf, NS_RDF "nil")) {
+ if (!strcmp(serd_node_string(object), NS_RDF "nil")) {
--writer->indent;
write_sep(writer, SEP_LIST_END);
return true;
}
- if (!strcmp(predicate->buf, NS_RDF "first")) {
+ if (!strcmp(serd_node_string(predicate), NS_RDF "first")) {
write_sep(writer, SEP_LIST_SEP);
write_node(writer, object, datatype, lang, FIELD_OBJECT, flags);
}
@@ -771,8 +784,7 @@ serd_writer_write_statement(SerdWriter* writer,
const SerdNode* datatype,
const SerdNode* lang)
{
- if (!is_resource(subject) || !is_resource(predicate) || !object ||
- !object->buf) {
+ if (!is_resource(subject) || !is_resource(predicate) || !object) {
return SERD_ERR_BAD_ARG;
}
@@ -797,15 +809,13 @@ serd_writer_write_statement(SerdWriter* writer,
return SERD_SUCCESS;
}
- if ((graph && !serd_node_equals(graph, &writer->context.graph)) ||
- (!graph && writer->context.graph.type)) {
+ if ((graph && !serd_node_equals(graph, writer->context.graph)) ||
+ (!graph && ctx(writer, FIELD_GRAPH))) {
writer->indent = 0;
-
- if (writer->context.subject.type) {
+ if (ctx(writer, FIELD_SUBJECT)) {
write_sep(writer, SEP_END_S);
}
-
- if (writer->context.graph.type) {
+ if (ctx(writer, FIELD_GRAPH)) {
write_sep(writer, SEP_GRAPH_END);
}
@@ -814,23 +824,23 @@ serd_writer_write_statement(SerdWriter* writer,
TRY(write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags));
++writer->indent;
write_sep(writer, SEP_GRAPH_BEGIN);
- copy_node(&writer->context.graph, graph);
+ serd_node_set(&writer->context.graph, graph);
}
}
if ((flags & SERD_LIST_CONT)) {
if (write_list_obj(writer, flags, predicate, object, datatype, lang)) {
// Reached end of list
- if (--writer->list_depth == 0 && writer->list_subj.type) {
+ if (--writer->list_depth == 0 && writer->list_subj) {
reset_context(writer, false);
- serd_node_free(&writer->context.subject);
+ serd_node_free(writer->context.subject);
writer->context.subject = writer->list_subj;
- writer->list_subj = SERD_NODE_NULL;
+ writer->list_subj = NULL;
}
return SERD_SUCCESS;
}
- } else if (serd_node_equals(subject, &writer->context.subject)) {
- if (serd_node_equals(predicate, &writer->context.predicate)) {
+ } else if (serd_node_equals(subject, writer->context.subject)) {
+ if (serd_node_equals(predicate, writer->context.predicate)) {
// Abbreviate S P
if (!(flags & SERD_ANON_O_BEGIN)) {
++writer->indent;
@@ -842,14 +852,14 @@ serd_writer_write_statement(SerdWriter* writer,
}
} else {
// Abbreviate S
- Sep sep = writer->context.predicate.type ? SEP_END_P : SEP_S_P;
+ Sep sep = ctx(writer, FIELD_PREDICATE) ? SEP_END_P : SEP_S_P;
write_sep(writer, sep);
write_pred(writer, flags, predicate);
write_node(writer, object, datatype, lang, FIELD_OBJECT, flags);
}
} else {
// No abbreviation
- if (writer->context.subject.type) {
+ if (ctx(writer, FIELD_SUBJECT)) {
assert(writer->indent > 0);
--writer->indent;
if (serd_stack_is_empty(&writer->anon_stack)) {
@@ -868,7 +878,7 @@ serd_writer_write_statement(SerdWriter* writer,
}
reset_context(writer, false);
- copy_node(&writer->context.subject, subject);
+ serd_node_set(&writer->context.subject, subject);
if (!(flags & SERD_LIST_S_BEGIN)) {
write_pred(writer, flags, predicate);
@@ -882,15 +892,15 @@ serd_writer_write_statement(SerdWriter* writer,
(WriteContext*)serd_stack_push(&writer->anon_stack, sizeof(WriteContext));
*ctx = writer->context;
WriteContext new_context = {
- serd_node_copy(graph), serd_node_copy(subject), SERD_NODE_NULL};
+ serd_node_copy(graph), serd_node_copy(subject), NULL};
if ((flags & SERD_ANON_S_BEGIN)) {
new_context.predicate = serd_node_copy(predicate);
}
writer->context = new_context;
} else {
- copy_node(&writer->context.graph, graph);
- copy_node(&writer->context.subject, subject);
- copy_node(&writer->context.predicate, predicate);
+ serd_node_set(&writer->context.graph, graph);
+ serd_node_set(&writer->context.subject, subject);
+ serd_node_set(&writer->context.predicate, predicate);
}
return SERD_SUCCESS;
@@ -902,40 +912,37 @@ serd_writer_end_anon(SerdWriter* writer, const SerdNode* node)
if (writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS) {
return SERD_SUCCESS;
}
-
if (serd_stack_is_empty(&writer->anon_stack) || writer->indent == 0) {
w_err(writer, SERD_ERR_UNKNOWN, "unexpected end of anonymous node\n");
return SERD_ERR_UNKNOWN;
}
-
--writer->indent;
write_sep(writer, SEP_ANON_END);
free_context(writer);
writer->context = *anon_stack_top(writer);
serd_stack_pop(&writer->anon_stack, sizeof(WriteContext));
- const bool is_subject = serd_node_equals(node, &writer->context.subject);
+ const bool is_subject = serd_node_equals(node, writer->context.subject);
if (is_subject) {
- copy_node(&writer->context.subject, node);
- writer->context.predicate.type = SERD_NOTHING;
+ serd_node_set(&writer->context.subject, node);
+ memset(writer->context.predicate, 0, sizeof(SerdNode));
}
-
return SERD_SUCCESS;
}
SerdStatus
serd_writer_finish(SerdWriter* writer)
{
- if (writer->context.subject.type) {
+ if (ctx(writer, FIELD_SUBJECT)) {
write_sep(writer, SEP_END_S);
}
-
- if (writer->context.graph.type) {
+ if (ctx(writer, FIELD_GRAPH)) {
write_sep(writer, SEP_GRAPH_END);
}
-
serd_byte_sink_flush(&writer->byte_sink);
- writer->indent = 0;
- return free_context(writer);
+ free_context(writer);
+ writer->indent = 0;
+ writer->context = WRITE_CONTEXT_NULL;
+ return SERD_SUCCESS;
}
SerdWriter*
@@ -952,12 +959,12 @@ serd_writer_new(SerdSyntax syntax,
writer->syntax = syntax;
writer->flags = flags;
writer->env = env;
- writer->root_node = SERD_NODE_NULL;
+ writer->root_node = NULL;
writer->root_uri = SERD_URI_NULL;
writer->base_uri = base_uri ? *base_uri : SERD_URI_NULL;
writer->anon_stack = serd_stack_new(4 * sizeof(WriteContext));
writer->context = context;
- writer->list_subj = SERD_NODE_NULL;
+ writer->list_subj = NULL;
writer->empty = true;
writer->byte_sink = serd_byte_sink_new(
ssink, stream, (flags & SERD_WRITE_BULK) ? SERD_PAGE_SIZE : 1);
@@ -996,12 +1003,12 @@ serd_writer_set_base_uri(SerdWriter* writer, const SerdNode* uri)
serd_env_base_uri(writer->env, &writer->base_uri);
if (writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG) {
- if (writer->context.graph.type || writer->context.subject.type) {
+ if (ctx(writer, FIELD_GRAPH) || ctx(writer, FIELD_SUBJECT)) {
sink(" .\n\n", 4, writer);
reset_context(writer, true);
}
sink("@base <", 7, writer);
- sink(uri->buf, uri->n_bytes, writer);
+ sink(serd_node_string(uri), uri->length, writer);
sink("> .\n", 4, writer);
}
writer->indent = 0;
@@ -1013,14 +1020,13 @@ serd_writer_set_base_uri(SerdWriter* writer, const SerdNode* uri)
SerdStatus
serd_writer_set_root_uri(SerdWriter* writer, const SerdNode* uri)
{
- serd_node_free(&writer->root_node);
+ serd_node_free(writer->root_node);
+ writer->root_node = NULL;
+ writer->root_uri = SERD_URI_NULL;
- if (uri && uri->buf) {
+ if (uri) {
writer->root_node = serd_node_copy(uri);
- serd_uri_parse(uri->buf, &writer->root_uri);
- } else {
- writer->root_node = SERD_NODE_NULL;
- writer->root_uri = SERD_URI_NULL;
+ serd_uri_parse(serd_node_string(writer->root_node), &writer->root_uri);
}
return SERD_SUCCESS;
@@ -1033,20 +1039,19 @@ serd_writer_set_prefix(SerdWriter* writer,
{
if (!serd_env_set_prefix(writer->env, name, uri)) {
if (writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG) {
- if (writer->context.graph.type || writer->context.subject.type) {
+ if (ctx(writer, FIELD_GRAPH) || ctx(writer, FIELD_SUBJECT)) {
sink(" .\n\n", 4, writer);
reset_context(writer, true);
}
sink("@prefix ", 8, writer);
- sink(name->buf, name->n_bytes, writer);
+ sink(serd_node_string(name), name->length, writer);
sink(": <", 3, writer);
- write_uri(writer, uri->buf, uri->n_bytes);
+ write_uri_from_node(writer, uri);
sink("> .\n", 4, writer);
}
writer->indent = 0;
return reset_context(writer, true);
}
-
return SERD_ERR_UNKNOWN;
}
@@ -1061,7 +1066,7 @@ serd_writer_free(SerdWriter* writer)
serd_stack_free(&writer->anon_stack);
free(writer->bprefix);
serd_byte_sink_free(&writer->byte_sink);
- serd_node_free(&writer->root_node);
+ serd_node_free(writer->root_node);
free(writer);
}