From b2b4fa05b73c6eee51ee9db59726fc404198111a Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 4 Feb 2018 15:33:36 +0100 Subject: Make nodes opaque --- src/writer.c | 222 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 114 insertions(+), 108 deletions(-) (limited to 'src/writer.c') diff --git a/src/writer.c b/src/writer.c index 89600e9c..dd16e732 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 { SerdErrorSink error_sink; void* error_handle; WriteContext context; - SerdNode list_subj; + SerdNode* list_subj; unsigned list_depth; unsigned indent; char* bprefix; @@ -150,26 +149,28 @@ w_err(SerdWriter* writer, SerdStatus st, const char* fmt, ...) va_end(args); } -static inline SERD_PURE_FUNC WriteContext* - anon_stack_top(SerdWriter* writer) +static inline SERD_PURE_FUNC +WriteContext* +anon_stack_top(SerdWriter* writer) { assert(!serd_stack_is_empty(&writer->anon_stack)); return (WriteContext*)(writer->anon_stack.buf + writer->anon_stack.size - 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 inline size_t @@ -261,6 +262,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->n_bytes); +} + static bool lname_must_escape(const char c) { @@ -469,23 +476,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 @@ -503,23 +513,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->n_bytes, 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->n_bytes - 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->n_bytes, writer); return true; } } @@ -527,17 +538,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->n_bytes); 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->n_bytes); 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->n_bytes, writer); + } else if (type_uri) { sink("^^", 2, writer); return write_node(writer, datatype, NULL, NULL, FIELD_NONE, flags); } @@ -564,8 +575,8 @@ write_uri_node(SerdWriter* const writer, const Field field, const SerdStatementFlags flags) { - SerdNode prefix; - SerdStringView suffix; + const SerdNode* prefix = NULL; + SerdStringView suffix = {NULL, 0}; if (is_inline_start(writer, field, flags)) { ++writer->indent; @@ -573,20 +584,21 @@ write_uri_node(SerdWriter* const writer, sink("== ", 3, writer); } - 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(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; @@ -594,11 +606,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; } @@ -608,7 +620,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; @@ -620,7 +632,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); if (is_inline_start(writer, field, flags)) { @@ -636,6 +648,8 @@ write_curie(SerdWriter* const writer, const Field field, const SerdStatementFlags flags) { + const char* node_str = serd_node_string(node); + SerdStringView prefix = {NULL, 0}; SerdStringView suffix = {NULL, 0}; SerdStatus st = SERD_SUCCESS; @@ -643,7 +657,7 @@ write_curie(SerdWriter* const writer, 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); @@ -658,7 +672,7 @@ write_curie(SerdWriter* const writer, write_sep(writer, SEP_ANON_BEGIN); sink("== ", 3, writer); } - write_lname(writer, node->buf, node->n_bytes); + write_lname(writer, node_str, node->n_bytes); if (is_inline_start(writer, field, flags)) { sink(" ;", 2, writer); write_newline(writer); @@ -673,6 +687,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; @@ -681,7 +696,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); @@ -701,12 +716,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, + !strncmp(node_str, writer->bprefix, writer->bprefix_len)) { + sink(node_str + writer->bprefix_len, node->n_bytes - writer->bprefix_len, writer); } else { - sink(node->buf, node->n_bytes, writer); + sink(node_str, node->n_bytes, writer); } return true; @@ -745,7 +760,7 @@ write_node(SerdWriter* writer, static inline bool is_resource(const SerdNode* node) { - return node && node->buf && node->type > SERD_LITERAL; + return node && node->type > SERD_LITERAL; } static void @@ -753,7 +768,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 @@ -764,13 +779,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); } @@ -788,8 +803,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; } @@ -814,15 +828,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); } @@ -831,23 +843,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; @@ -859,14 +871,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)) { @@ -885,7 +897,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); @@ -899,15 +911,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; @@ -919,40 +931,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* @@ -969,12 +978,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); @@ -1013,12 +1022,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->n_bytes, writer); sink("> .\n", 4, writer); } writer->indent = 0; @@ -1030,16 +1039,14 @@ 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); - - if (uri && uri->buf) { + serd_node_free(writer->root_node); + if (uri) { writer->root_node = serd_node_copy(uri); - serd_uri_parse(uri->buf, &writer->root_uri); + serd_uri_parse(serd_node_string(writer->root_node), &writer->root_uri); } else { - writer->root_node = SERD_NODE_NULL; + writer->root_node = NULL; writer->root_uri = SERD_URI_NULL; } - return SERD_SUCCESS; } @@ -1050,20 +1057,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->n_bytes, 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; } @@ -1078,7 +1084,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); } -- cgit v1.2.1