From 6f03ae92415a7758fdc74f6720ec4955bc67fc0c Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 14 Aug 2020 16:05:10 +0200 Subject: Merge datatype/language into node This moves closer to the sord API, and is more convenient in most cases. --- include/serd/serd.h | 51 +++++++++++----- src/n3.c | 34 ++++++----- src/node.c | 149 ++++++++++++++++++++++++++++++++++++++++------ src/reader.c | 6 +- src/reader.h | 2 +- src/writer.c | 48 +++++++-------- test/test_node.c | 32 ++++++++++ test/test_read_chunk.c | 6 +- test/test_reader_writer.c | 58 +++++------------- 9 files changed, 258 insertions(+), 128 deletions(-) diff --git a/include/serd/serd.h b/include/serd/serd.h index 2ccedcba..d62b6e2c 100644 --- a/include/serd/serd.h +++ b/include/serd/serd.h @@ -169,8 +169,10 @@ typedef enum { /// Flags indicating certain string properties relevant to serialisation typedef enum { - SERD_HAS_NEWLINE = 1u << 0u, ///< Contains line breaks ('\\n' or '\\r') - SERD_HAS_QUOTE = 1u << 1u ///< Contains quotes ('"') + SERD_HAS_NEWLINE = 1u << 0u, ///< Contains line breaks ('\\n' or '\\r') + SERD_HAS_QUOTE = 1u << 1u, ///< Contains quotes ('"') + SERD_HAS_DATATYPE = 1u << 2u, ///< Literal node has datatype + SERD_HAS_LANGUAGE = 1u << 3u ///< Literal node has language } SerdNodeFlag; /// Bitwise OR of SerdNodeFlag values @@ -451,7 +453,21 @@ serd_new_substring(SerdNodeType type, const char* SERD_NULLABLE str, size_t len); -/// Simple wrapper for serd_new_uri() to resolve a URI node +/** + Create a new literal node from `str`. + + Either `datatype` or `lang` can be given, but not both, unless `datatype` is + rdf:langString in which case it is ignored. +*/ +SERD_API +SerdNode* SERD_ALLOCATED +serd_new_literal(const char* SERD_NONNULL str, + const char* SERD_NULLABLE datatype, + const char* SERD_NULLABLE lang); + +/** + Simple wrapper for serd_new_uri() to resolve a URI node. +*/ SERD_API SerdNode* SERD_ALLOCATED serd_new_uri_from_node(const SerdNode* SERD_NONNULL uri_node, @@ -583,6 +599,16 @@ SERD_PURE_API SerdNodeFlags serd_node_flags(const SerdNode* SERD_NONNULL node); +/// Return the datatype of a literal node, or NULL +SERD_PURE_API +const SerdNode* SERD_NULLABLE +serd_node_datatype(const SerdNode* SERD_NONNULL node); + +/// Return the language tag of a literal node, or NULL +SERD_PURE_API +const SerdNode* SERD_NULLABLE +serd_node_language(const SerdNode* SERD_NONNULL node); + /// Return true iff `a` is equal to `b` SERD_PURE_API bool @@ -626,15 +652,12 @@ typedef SerdStatus (*SerdPrefixSink)(void* SERD_NULLABLE handle, Called for every RDF statement in the serialisation. */ -typedef SerdStatus (*SerdStatementSink)( - void* SERD_NULLABLE handle, - SerdStatementFlags flags, - const SerdNode* SERD_NULLABLE graph, - const SerdNode* SERD_NONNULL subject, - const SerdNode* SERD_NONNULL predicate, - const SerdNode* SERD_NONNULL object, - const SerdNode* SERD_NULLABLE object_datatype, - const SerdNode* SERD_NULLABLE object_lang); +typedef SerdStatus (*SerdStatementSink)(void* SERD_NULLABLE handle, + SerdStatementFlags flags, + const SerdNode* SERD_NULLABLE graph, + const SerdNode* SERD_NONNULL subject, + const SerdNode* SERD_NONNULL predicate, + const SerdNode* SERD_NONNULL object); /** Sink (callback) for anonymous node end markers @@ -1017,9 +1040,7 @@ serd_writer_write_statement(SerdWriter* SERD_NONNULL writer, const SerdNode* SERD_NULLABLE graph, const SerdNode* SERD_NONNULL subject, const SerdNode* SERD_NONNULL predicate, - const SerdNode* SERD_NONNULL object, - const SerdNode* SERD_NULLABLE datatype, - const SerdNode* SERD_NULLABLE lang); + const SerdNode* SERD_NONNULL object); /** Mark the end of an anonymous node's description. diff --git a/src/n3.c b/src/n3.c index d5ee2832..fe6da47f 100644 --- a/src/n3.c +++ b/src/n3.c @@ -830,7 +830,11 @@ read_0_9(SerdReader* reader, Ref str, bool at_least_one) } static SerdStatus -read_number(SerdReader* reader, Ref* dest, Ref* datatype, bool* ate_dot) +read_number(SerdReader* reader, + Ref* dest, + Ref* datatype, + SerdNodeFlags* flags, + bool* ate_dot) { #define XSD_DECIMAL NS_XSD "decimal" #define XSD_DOUBLE NS_XSD "double" @@ -888,6 +892,10 @@ read_number(SerdReader* reader, Ref* dest, Ref* datatype, bool* ate_dot) push_node(reader, SERD_URI, XSD_INTEGER, sizeof(XSD_INTEGER) - 1); } + if (*datatype) { + *flags |= SERD_HAS_DATATYPE; + } + return SERD_SUCCESS; } @@ -922,6 +930,7 @@ read_literal(SerdReader* reader, switch (peek_byte(reader)) { case '@': eat_byte_safe(reader, '@'); + *flags |= SERD_HAS_LANGUAGE; if ((st = read_LANGTAG(reader, lang))) { *datatype = pop_node(reader, *datatype); *lang = pop_node(reader, *lang); @@ -932,6 +941,7 @@ read_literal(SerdReader* reader, case '^': eat_byte_safe(reader, '^'); eat_byte_check(reader, '^'); + *flags |= SERD_HAS_DATATYPE; if ((st = read_iri(reader, datatype, ate_dot))) { *datatype = pop_node(reader, *datatype); *lang = pop_node(reader, *lang); @@ -940,7 +950,6 @@ read_literal(SerdReader* reader, } break; } - return SERD_SUCCESS; } @@ -1067,7 +1076,7 @@ read_anon(SerdReader* reader, ReadContext ctx, bool subject, Ref* dest) SerdStatus st = SERD_SUCCESS; if (ctx.subject) { - TRY(st, emit_statement(reader, ctx, *dest, 0, 0)); + TRY(st, emit_statement(reader, ctx, *dest)); } ctx.subject = *dest; @@ -1076,21 +1085,17 @@ read_anon(SerdReader* reader, ReadContext ctx, bool subject, Ref* dest) if (!subject) { *ctx.flags |= SERD_ANON_CONT; } - bool ate_dot_in_list = false; read_predicateObjectList(reader, ctx, &ate_dot_in_list); if (ate_dot_in_list) { return r_err(reader, SERD_ERR_BAD_SYNTAX, "`.' inside blank\n"); } - read_ws_star(reader); if (reader->end_sink) { reader->end_sink(reader->handle, deref(reader, *dest)); } - *ctx.flags = old_flags; } - return (eat_byte_check(reader, ']') == ']') ? SERD_SUCCESS : SERD_ERR_BAD_SYNTAX; } @@ -1160,7 +1165,7 @@ read_object(SerdReader* reader, ReadContext* ctx, bool emit, bool* ate_dot) case '7': case '8': case '9': - ret = read_number(reader, &o, &datatype, ate_dot); + ret = read_number(reader, &o, &datatype, &flags, ate_dot); break; case '\"': case '\'': @@ -1176,6 +1181,7 @@ read_object(SerdReader* reader, ReadContext* ctx, bool emit, bool* ate_dot) node = deref(reader, o); if ((node->n_bytes == 4 && !memcmp(serd_node_string(node), "true", 4)) || (node->n_bytes == 5 && !memcmp(serd_node_string(node), "false", 5))) { + flags = flags | SERD_HAS_DATATYPE; node->type = SERD_LITERAL; datatype = push_node(reader, SERD_URI, XSD_BOOLEAN, XSD_BOOLEAN_LEN); ret = SERD_SUCCESS; @@ -1195,7 +1201,7 @@ read_object(SerdReader* reader, ReadContext* ctx, bool emit, bool* ate_dot) } if (!ret && emit && simple) { - ret = emit_statement(reader, *ctx, o, datatype, lang); + ret = emit_statement(reader, *ctx, o); } else if (!ret && !emit) { ctx->object = o; ctx->datatype = datatype; @@ -1289,14 +1295,12 @@ read_collection(SerdReader* reader, ReadContext ctx, Ref* dest) { SerdStatus st = SERD_SUCCESS; eat_byte_safe(reader, '('); - bool end = peek_delim(reader, ')'); - - *dest = end ? reader->rdf_nil : blank_id(reader); + *dest = end ? reader->rdf_nil : blank_id(reader); if (ctx.subject) { // subject predicate _:head *ctx.flags |= (end ? 0 : SERD_LIST_O_BEGIN); - TRY(st, emit_statement(reader, ctx, *dest, 0, 0)); + TRY(st, emit_statement(reader, ctx, *dest)); *ctx.flags |= SERD_LIST_CONT; } else { *ctx.flags |= (end ? 0 : SERD_LIST_S_BEGIN); @@ -1335,7 +1339,7 @@ read_collection(SerdReader* reader, ReadContext ctx, Ref* dest) // _:node rdf:rest _:rest *ctx.flags |= SERD_LIST_CONT; ctx.predicate = reader->rdf_rest; - TRY(st, emit_statement(reader, ctx, (end ? reader->rdf_nil : rest), 0, 0)); + TRY(st, emit_statement(reader, ctx, (end ? reader->rdf_nil : rest))); ctx.subject = rest; // _:node = _:rest rest = node; // _:rest = (old)_:node @@ -1710,7 +1714,7 @@ read_nquadsDoc(SerdReader* reader) } } - TRY(st, emit_statement(reader, ctx, ctx.object, ctx.datatype, ctx.lang)); + TRY(st, emit_statement(reader, ctx, ctx.object)); pop_node(reader, ctx.graph); pop_node(reader, ctx.lang); diff --git a/src/node.c b/src/node.c index b11625aa..14efddd3 100644 --- a/src/node.c +++ b/src/node.c @@ -17,10 +17,12 @@ #include "node.h" #include "base64.h" +#include "serd_internal.h" #include "string_utils.h" #include "serd/serd.h" +#include #include #include #include @@ -38,28 +40,55 @@ # endif #endif +static const size_t serd_node_align = sizeof(SerdNode); + +static size_t +serd_node_pad_size(const size_t n_bytes) +{ + const size_t pad = serd_node_align - (n_bytes + 2) % serd_node_align; + return n_bytes + 2 + pad; +} + +static const SerdNode* +serd_node_maybe_get_meta_c(const SerdNode* node) +{ + return (node->flags & (SERD_HAS_LANGUAGE | SERD_HAS_DATATYPE)) + ? (node + 1 + (serd_node_pad_size(node->n_bytes) / serd_node_align)) + : NULL; +} + +static SERD_PURE_FUNC +size_t +serd_node_total_size(const SerdNode* node) +{ + return node ? (sizeof(SerdNode) + serd_node_pad_size(node->n_bytes) + + serd_node_total_size(serd_node_maybe_get_meta_c(node))) + : 0; +} + SerdNode* serd_node_malloc(size_t n_bytes, SerdNodeFlags flags, SerdNodeType type) { - SerdNode* node = (SerdNode*)calloc(1, sizeof(SerdNode) + n_bytes + 1); - node->n_bytes = 0; - node->flags = flags; - node->type = type; + const size_t size = sizeof(SerdNode) + serd_node_pad_size(n_bytes); + SerdNode* node = (SerdNode*)calloc(1, size); + + node->n_bytes = 0; + node->flags = flags; + node->type = type; + + assert((intptr_t)node % serd_node_align == 0); return node; } void serd_node_set(SerdNode** dst, const SerdNode* src) { - if (src) { - if (!(*dst) || (*dst)->n_bytes < src->n_bytes) { - (*dst) = (SerdNode*)realloc(*dst, sizeof(SerdNode) + src->n_bytes + 1); - } - - memcpy(*dst, src, sizeof(SerdNode) + src->n_bytes + 1); - } else if (*dst) { - memset(*dst, 0, sizeof(SerdNode)); + const size_t size = serd_node_total_size(src); + if (serd_node_total_size(*dst) < size) { + (*dst) = (SerdNode*)realloc(*dst, size); } + + memcpy(*dst, src, size); } SerdNode* @@ -68,8 +97,10 @@ serd_new_string(SerdNodeType type, const char* str) SerdNodeFlags flags = 0; const size_t n_bytes = serd_strlen(str, &flags); SerdNode* node = serd_node_malloc(n_bytes, flags, type); + memcpy(serd_node_buffer(node), str, n_bytes); node->n_bytes = n_bytes; + return node; } @@ -84,6 +115,51 @@ serd_new_substring(SerdNodeType type, const char* str, const size_t len) return node; } +SerdNode* +serd_new_literal(const char* str, const char* datatype, const char* lang) +{ + if (!str || (lang && datatype && strcmp(datatype, NS_RDF "#langString"))) { + return NULL; + } + + SerdNodeFlags flags = 0; + const size_t n_bytes = serd_strlen(str, &flags); + const size_t len = serd_node_pad_size(n_bytes); + + SerdNode* node = NULL; + if (lang) { + flags |= SERD_HAS_LANGUAGE; + const size_t lang_len = strlen(lang); + const size_t total_len = len + sizeof(SerdNode) + lang_len; + node = serd_node_malloc(total_len, flags, SERD_LITERAL); + memcpy(serd_node_buffer(node), str, n_bytes); + node->n_bytes = n_bytes; + + SerdNode* lang_node = node + 1 + (len / serd_node_align); + lang_node->type = SERD_LITERAL; + lang_node->n_bytes = lang_len; + memcpy(serd_node_buffer(lang_node), lang, lang_len); + } else if (datatype) { + flags |= SERD_HAS_DATATYPE; + const size_t datatype_len = strlen(datatype); + const size_t total_len = len + sizeof(SerdNode) + datatype_len; + node = serd_node_malloc(total_len, flags, SERD_LITERAL); + memcpy(serd_node_buffer(node), str, n_bytes); + node->n_bytes = n_bytes; + + SerdNode* datatype_node = node + 1 + (len / serd_node_align); + datatype_node->type = SERD_URI; + datatype_node->n_bytes = datatype_len; + memcpy(serd_node_buffer(datatype_node), datatype, datatype_len); + } else { + node = serd_node_malloc(n_bytes, flags, SERD_LITERAL); + memcpy(serd_node_buffer(node), str, n_bytes); + node->n_bytes = n_bytes; + } + + return node; +} + SerdNode* serd_node_copy(const SerdNode* node) { @@ -91,8 +167,8 @@ serd_node_copy(const SerdNode* node) return NULL; } - const size_t size = sizeof(SerdNode) + node->n_bytes + 1; - SerdNode* copy = (SerdNode*)malloc(size); + const size_t size = serd_node_total_size(node); + SerdNode* copy = (SerdNode*)calloc(1, size + 3); memcpy(copy, node, size); return copy; } @@ -100,9 +176,16 @@ serd_node_copy(const SerdNode* node) bool serd_node_equals(const SerdNode* a, const SerdNode* b) { - return (a == b) || - (a && b && a->type == b->type && a->n_bytes == b->n_bytes && - !memcmp(serd_node_string(a), serd_node_string(b), a->n_bytes)); + if (a == b) { + return true; + } + + if (!a || !b) { + return false; + } + + const size_t a_size = serd_node_total_size(a); + return serd_node_total_size(b) == a_size && !memcmp(a, b, a_size); } static size_t @@ -416,6 +499,38 @@ serd_node_length(const SerdNode* node) return node->n_bytes; } +const SerdNode* +serd_node_datatype(const SerdNode* node) +{ + if (!node || !(node->flags & SERD_HAS_DATATYPE)) { + return NULL; + } + + const size_t len = serd_node_pad_size(node->n_bytes); + assert((intptr_t)node % serd_node_align == 0); + assert(len % serd_node_align == 0); + + const SerdNode* const datatype = node + 1 + (len / serd_node_align); + assert(datatype->type == SERD_URI || datatype->type == SERD_CURIE); + return datatype; +} + +const SerdNode* +serd_node_language(const SerdNode* node) +{ + if (!node || !(node->flags & SERD_HAS_LANGUAGE)) { + return NULL; + } + + const size_t len = serd_node_pad_size(node->n_bytes); + assert((intptr_t)node % serd_node_align == 0); + assert(len % serd_node_align == 0); + + const SerdNode* const lang = node + 1 + (len / serd_node_align); + assert(lang->type == SERD_LITERAL); + return lang; +} + SerdNodeFlags serd_node_flags(const SerdNode* node) { diff --git a/src/reader.c b/src/reader.c index 97d5dcfd..06fb25ea 100644 --- a/src/reader.c +++ b/src/reader.c @@ -139,7 +139,7 @@ pop_node(SerdReader* reader, Ref ref) } SerdStatus -emit_statement(SerdReader* reader, ReadContext ctx, Ref o, Ref d, Ref l) +emit_statement(SerdReader* reader, ReadContext ctx, Ref o) { SerdNode* graph = deref(reader, ctx.graph); if (!graph && reader->default_graph) { @@ -153,9 +153,7 @@ emit_statement(SerdReader* reader, ReadContext ctx, Ref o, Ref d, Ref l) graph, deref(reader, ctx.subject), deref(reader, ctx.predicate), - deref(reader, o), - deref(reader, d), - deref(reader, l)); + deref(reader, o)); *ctx.flags &= SERD_ANON_CONT | SERD_LIST_CONT; // Preserve only cont flags return st; diff --git a/src/reader.h b/src/reader.h index b86a7596..c598f6b3 100644 --- a/src/reader.h +++ b/src/reader.h @@ -118,7 +118,7 @@ Ref pop_node(SerdReader* reader, Ref ref); SerdStatus -emit_statement(SerdReader* reader, ReadContext ctx, Ref o, Ref d, Ref l); +emit_statement(SerdReader* reader, ReadContext ctx, Ref o); SerdStatus read_n3_statement(SerdReader* reader); diff --git a/src/writer.c b/src/writer.c index 6df55ada..5437f659 100644 --- a/src/writer.c +++ b/src/writer.c @@ -116,8 +116,6 @@ typedef enum { WRITE_STRING, WRITE_LONG_STRING } TextContext; static bool write_node(SerdWriter* writer, const SerdNode* node, - const SerdNode* datatype, - const SerdNode* lang, Field field, SerdStatementFlags flags); @@ -509,12 +507,12 @@ is_inline_start(const SerdWriter* writer, Field field, SerdStatementFlags flags) static bool write_literal(SerdWriter* writer, const SerdNode* node, - const SerdNode* datatype, - const SerdNode* lang, SerdStatementFlags flags) { - const char* node_str = serd_node_string(node); - const char* type_uri = datatype ? serd_node_string(datatype) : NULL; + const SerdNode* datatype = serd_node_datatype(node); + const SerdNode* lang = serd_node_language(node); + 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") || @@ -550,7 +548,7 @@ write_literal(SerdWriter* writer, 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); + return write_node(writer, datatype, FIELD_NONE, flags); } return true; } @@ -730,15 +728,13 @@ write_blank(SerdWriter* const writer, static bool write_node(SerdWriter* writer, const SerdNode* node, - const SerdNode* datatype, - const SerdNode* lang, Field field, SerdStatementFlags flags) { bool ret = false; switch (node->type) { case SERD_LITERAL: - ret = write_literal(writer, node, datatype, lang, flags); + ret = write_literal(writer, node, flags); break; case SERD_URI: ret = write_uri_node(writer, node, field, flags); @@ -763,7 +759,7 @@ is_resource(const SerdNode* node) static void write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred) { - write_node(writer, pred, NULL, NULL, FIELD_PREDICATE, flags); + write_node(writer, pred, FIELD_PREDICATE, flags); write_sep(writer, SEP_P_O); serd_node_set(&writer->context.predicate, pred); } @@ -772,9 +768,7 @@ static bool write_list_obj(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* predicate, - const SerdNode* object, - const SerdNode* datatype, - const SerdNode* lang) + const SerdNode* object) { if (!strcmp(serd_node_string(object), NS_RDF "nil")) { --writer->indent; @@ -784,7 +778,7 @@ write_list_obj(SerdWriter* writer, if (!strcmp(serd_node_string(predicate), NS_RDF "first")) { write_sep(writer, SEP_LIST_SEP); - write_node(writer, object, datatype, lang, FIELD_OBJECT, flags); + write_node(writer, object, FIELD_OBJECT, flags); } return false; @@ -796,9 +790,7 @@ serd_writer_write_statement(SerdWriter* writer, const SerdNode* graph, const SerdNode* subject, const SerdNode* predicate, - const SerdNode* object, - const SerdNode* datatype, - const SerdNode* lang) + const SerdNode* object) { if (!is_resource(subject) || !is_resource(predicate) || !object) { return SERD_ERR_BAD_ARG; @@ -812,14 +804,14 @@ serd_writer_write_statement(SerdWriter* writer, } while (0) if (writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS) { - TRY(write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags)); + TRY(write_node(writer, subject, FIELD_SUBJECT, flags)); sink(" ", 1, writer); - TRY(write_node(writer, predicate, NULL, NULL, FIELD_PREDICATE, flags)); + TRY(write_node(writer, predicate, FIELD_PREDICATE, flags)); sink(" ", 1, writer); - TRY(write_node(writer, object, datatype, lang, FIELD_OBJECT, flags)); + TRY(write_node(writer, object, FIELD_OBJECT, flags)); if (writer->syntax == SERD_NQUADS && graph) { sink(" ", 1, writer); - TRY(write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags)); + TRY(write_node(writer, graph, FIELD_GRAPH, flags)); } sink(" .\n", 3, writer); return SERD_SUCCESS; @@ -837,7 +829,7 @@ serd_writer_write_statement(SerdWriter* writer, reset_context(writer, true); if (graph) { - TRY(write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags)); + TRY(write_node(writer, graph, FIELD_GRAPH, flags)); ++writer->indent; write_sep(writer, SEP_GRAPH_BEGIN); serd_node_set(&writer->context.graph, graph); @@ -845,7 +837,7 @@ serd_writer_write_statement(SerdWriter* writer, } if ((flags & SERD_LIST_CONT)) { - if (write_list_obj(writer, flags, predicate, object, datatype, lang)) { + if (write_list_obj(writer, flags, predicate, object)) { // Reached end of list if (--writer->list_depth == 0 && writer->list_subj) { reset_context(writer, false); @@ -862,7 +854,7 @@ serd_writer_write_statement(SerdWriter* writer, ++writer->indent; } write_sep(writer, SEP_END_O); - write_node(writer, object, datatype, lang, FIELD_OBJECT, flags); + write_node(writer, object, FIELD_OBJECT, flags); if (!(flags & SERD_ANON_O_BEGIN)) { --writer->indent; } @@ -871,7 +863,7 @@ serd_writer_write_statement(SerdWriter* writer, 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); + write_node(writer, object, FIELD_OBJECT, flags); } } else { // No abbreviation @@ -886,7 +878,7 @@ serd_writer_write_statement(SerdWriter* writer, } if (!(flags & SERD_ANON_CONT)) { - write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags); + write_node(writer, subject, FIELD_SUBJECT, flags); ++writer->indent; write_sep(writer, SEP_S_P); } else { @@ -900,7 +892,7 @@ serd_writer_write_statement(SerdWriter* writer, write_pred(writer, flags, predicate); } - write_node(writer, object, datatype, lang, FIELD_OBJECT, flags); + write_node(writer, object, FIELD_OBJECT, flags); } if (flags & (SERD_ANON_S_BEGIN | SERD_ANON_O_BEGIN)) { diff --git a/test/test_node.c b/test/test_node.c index be3576ff..00a24b99 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -194,6 +194,37 @@ test_node_from_substring(void) serd_node_free(a_b); } +static void +test_literal(void) +{ + SerdNode* hello2 = serd_new_literal("hello\"", NULL, NULL); + assert(serd_node_length(hello2) == 6 && + serd_node_flags(hello2) == SERD_HAS_QUOTE && + !strcmp(serd_node_string(hello2), "hello\"")); + serd_node_free(hello2); + + SerdNode* hello_l = serd_new_literal("hello_l\"", NULL, "en"); + assert(serd_node_length(hello_l) == 8); + assert(!strcmp(serd_node_string(hello_l), "hello_l\"")); + assert(serd_node_flags(hello_l) == (SERD_HAS_QUOTE | SERD_HAS_LANGUAGE)); + + const SerdNode* const lang = serd_node_language(hello_l); + assert(lang); + assert(!strcmp(serd_node_string(lang), "en")); + serd_node_free(hello_l); + + SerdNode* hello_dt = + serd_new_literal("hello_dt\"", "http://example.org/Thing", NULL); + assert(serd_node_length(hello_dt) == 9); + assert(!strcmp(serd_node_string(hello_dt), "hello_dt\"")); + assert(serd_node_flags(hello_dt) == (SERD_HAS_QUOTE | SERD_HAS_DATATYPE)); + + const SerdNode* const datatype = serd_node_datatype(hello_dt); + assert(datatype); + assert(!strcmp(serd_node_string(datatype), "http://example.org/Thing")); + serd_node_free(hello_dt); +} + int main(void) { @@ -204,6 +235,7 @@ main(void) test_node_equals(); test_node_from_string(); test_node_from_substring(); + test_literal(); printf("Success\n"); return 0; diff --git a/test/test_read_chunk.c b/test/test_read_chunk.c index d97713a4..dd2961ac 100644 --- a/test/test_read_chunk.c +++ b/test/test_read_chunk.c @@ -54,9 +54,7 @@ on_statement(void* handle, const SerdNode* graph, const SerdNode* subject, const SerdNode* predicate, - const SerdNode* object, - const SerdNode* object_datatype, - const SerdNode* object_lang) + const SerdNode* object) { (void)handle; (void)flags; @@ -64,8 +62,6 @@ on_statement(void* handle, (void)subject; (void)predicate; (void)object; - (void)object_datatype; - (void)object_lang; ++n_statement; return SERD_SUCCESS; diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c index a97a44c0..d79fbbdd 100644 --- a/test/test_reader_writer.c +++ b/test/test_reader_writer.c @@ -36,16 +36,12 @@ test_sink(void* handle, const SerdNode* graph, const SerdNode* subject, const SerdNode* predicate, - const SerdNode* object, - const SerdNode* object_datatype, - const SerdNode* object_lang) + const SerdNode* object) { (void)flags; (void)subject; (void)predicate; (void)object; - (void)object_datatype; - (void)object_lang; ReaderTest* rt = (ReaderTest*)handle; ++rt->n_statements; @@ -187,57 +183,33 @@ test_writer(const char* const path) SerdNode* o = serd_new_string(SERD_LITERAL, (char*)buf); // Write 3 invalid statements (should write nothing) - const SerdNode* junk[][5] = { - {s, o, o, NULL, NULL}, {o, p, o, NULL, NULL}, {s, o, p, NULL, NULL}}; - for (size_t i = 0; i < sizeof(junk) / (sizeof(SerdNode*) * 5); ++i) { - assert(serd_writer_write_statement(writer, - 0, - NULL, - junk[i][0], - junk[i][1], - junk[i][2], - junk[i][3], - junk[i][4])); + const SerdNode* junk[][3] = {{s, o, o}, {o, p, o}, {s, o, p}}; + for (size_t i = 0; i < sizeof(junk) / (sizeof(SerdNode*) * 3); ++i) { + assert(serd_writer_write_statement( + writer, 0, NULL, junk[i][0], junk[i][1], junk[i][2])); } - SerdNode* t = serd_new_string(SERD_URI, "urn:Type"); - SerdNode* l = serd_new_string(SERD_LITERAL, "en"); - const SerdNode* good[][5] = {{s, p, o, NULL, NULL}, - {s, p, o, NULL, NULL}, - {s, p, o, t, NULL}, - {s, p, o, NULL, l}, - {s, p, o, t, l}, - {s, p, o, t, NULL}, - {s, p, o, NULL, l}, - {s, p, o, NULL, NULL}, - {s, p, o, NULL, NULL}, - {s, p, o, NULL, NULL}}; - for (size_t i = 0; i < sizeof(good) / (sizeof(SerdNode*) * 5); ++i) { - assert(!serd_writer_write_statement(writer, - 0, - NULL, - good[i][0], - good[i][1], - good[i][2], - good[i][3], - good[i][4])); + SerdNode* t = serd_new_literal((char*)buf, "urn:Type", NULL); + SerdNode* l = serd_new_literal((char*)buf, NULL, "en"); + const SerdNode* good[][3] = {{s, p, o}, {s, p, t}, {s, p, l}}; + for (size_t i = 0; i < sizeof(good) / (sizeof(SerdNode*) * 3); ++i) { + assert(!serd_writer_write_statement( + writer, 0, NULL, good[i][0], good[i][1], good[i][2])); } // Write statements with bad UTF-8 (should be replaced) const char bad_str[] = {(char)0xFF, (char)0x90, 'h', 'i', 0}; SerdNode* bad_lit = serd_new_string(SERD_LITERAL, bad_str); SerdNode* bad_uri = serd_new_string(SERD_URI, bad_str); - assert( - !serd_writer_write_statement(writer, 0, NULL, s, p, bad_lit, NULL, NULL)); - assert( - !serd_writer_write_statement(writer, 0, NULL, s, p, bad_uri, NULL, NULL)); + assert(!serd_writer_write_statement(writer, 0, NULL, s, p, bad_lit)); + assert(!serd_writer_write_statement(writer, 0, NULL, s, p, bad_uri)); serd_node_free(bad_lit); serd_node_free(bad_uri); // Write 1 valid statement serd_node_free(o); o = serd_new_string(SERD_LITERAL, "hello"); - assert(!serd_writer_write_statement(writer, 0, NULL, s, p, o, NULL, NULL)); + assert(!serd_writer_write_statement(writer, 0, NULL, s, p, o)); serd_writer_free(writer); serd_node_free(lit); @@ -297,7 +269,7 @@ test_reader(const char* path) const SerdStatus st = serd_reader_read_file(reader, path); assert(!st); - assert(rt->n_statements == 13); + assert(rt->n_statements == 6); assert(rt->graph && serd_node_string(rt->graph) && !strcmp(serd_node_string(rt->graph), "http://example.org/")); -- cgit v1.2.1