aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/serd/node.h37
-rw-r--r--include/serd/sink.h15
-rw-r--r--include/serd/writer.h4
-rw-r--r--src/n3.c33
-rw-r--r--src/node.c119
-rw-r--r--src/reader.c10
-rw-r--r--src/reader.h2
-rw-r--r--src/writer.c80
-rw-r--r--test/test_node.c46
-rw-r--r--test/test_reader_writer.c58
-rw-r--r--test/test_writer.c18
11 files changed, 282 insertions, 140 deletions
diff --git a/include/serd/node.h b/include/serd/node.h
index b95891c9..4aa4ec0a 100644
--- a/include/serd/node.h
+++ b/include/serd/node.h
@@ -84,8 +84,10 @@ typedef enum {
/// Node flags, which ORed together make a #SerdNodeFlags
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
@@ -112,6 +114,17 @@ serd_new_substring(SerdNodeType type,
size_t len);
/**
+ 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);
+
+/**
Create a new URI node from a parsed URI.
*/
SERD_API SerdNode* SERD_ALLOCATED
@@ -228,6 +241,26 @@ SERD_API SerdURIView
serd_node_uri_view(const SerdNode* SERD_NONNULL node);
/**
+ Return the optional datatype of a literal node.
+
+ The datatype, if present, is always a URI, typically something like
+ <http://www.w3.org/2001/XMLSchema#boolean>.
+*/
+SERD_PURE_API const SerdNode* SERD_NULLABLE
+serd_node_datatype(const SerdNode* SERD_NONNULL node);
+
+/**
+ Return the optional language tag of a literal node.
+
+ The language tag, if present, is a well-formed BCP 47 (RFC 4647) language
+ tag like "en-ca". Note that these must be handled case-insensitively, for
+ example, the common form "en-CA" is valid, but lowercase is considered
+ canonical here.
+*/
+SERD_PURE_API const SerdNode* SERD_NULLABLE
+serd_node_language(const SerdNode* SERD_NONNULL node);
+
+/**
@}
@defgroup serd_node_operators Operators
@{
diff --git a/include/serd/sink.h b/include/serd/sink.h
index 97b47a2f..702197d5 100644
--- a/include/serd/sink.h
+++ b/include/serd/sink.h
@@ -39,15 +39,12 @@ typedef SerdStatus (*SerdPrefixFunc)(void* SERD_NULLABLE handle,
Called for every RDF statement in the serialisation.
*/
-typedef SerdStatus (*SerdStatementFunc)(
- 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 (*SerdStatementFunc)(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 function for anonymous node end markers.
diff --git a/include/serd/writer.h b/include/serd/writer.h
index 66c3d338..3327c1b9 100644
--- a/include/serd/writer.h
+++ b/include/serd/writer.h
@@ -139,9 +139,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 c0c00985..929b1a97 100644
--- a/src/n3.c
+++ b/src/n3.c
@@ -842,10 +842,11 @@ read_0_9(SerdReader* const reader, const Ref str, const bool at_least_one)
}
static SerdStatus
-read_number(SerdReader* const reader,
- Ref* const dest,
- Ref* const datatype,
- bool* const ate_dot)
+read_number(SerdReader* const reader,
+ Ref* const dest,
+ Ref* const datatype,
+ SerdNodeFlags* const flags,
+ bool* const ate_dot)
{
#define XSD_DECIMAL NS_XSD "decimal"
#define XSD_DOUBLE NS_XSD "double"
@@ -904,6 +905,10 @@ read_number(SerdReader* const reader,
push_node(reader, SERD_URI, XSD_INTEGER, sizeof(XSD_INTEGER) - 1);
}
+ if (*datatype) {
+ *flags |= SERD_HAS_DATATYPE;
+ }
+
return SERD_SUCCESS;
}
@@ -938,6 +943,7 @@ read_literal(SerdReader* const reader,
switch (peek_byte(reader)) {
case '@':
skip_byte(reader, '@');
+ *flags |= SERD_HAS_LANGUAGE;
if ((st = read_LANGTAG(reader, lang))) {
*datatype = pop_node(reader, *datatype);
*lang = pop_node(reader, *lang);
@@ -951,6 +957,7 @@ read_literal(SerdReader* const reader,
return r_err(reader, SERD_BAD_SYNTAX, "expected '^'\n");
}
+ *flags |= SERD_HAS_DATATYPE;
if ((st = read_iri(reader, datatype, ate_dot))) {
*datatype = pop_node(reader, *datatype);
*lang = pop_node(reader, *lang);
@@ -959,7 +966,6 @@ read_literal(SerdReader* const reader,
}
break;
}
-
return SERD_SUCCESS;
}
@@ -1076,7 +1082,7 @@ read_anon(SerdReader* const reader,
// Emit statement with this anonymous object first
SerdStatus st = SERD_SUCCESS;
if (ctx.subject) {
- TRY(st, emit_statement(reader, ctx, *dest, 0, 0));
+ TRY(st, emit_statement(reader, ctx, *dest));
}
// Switch the subject to the anonymous node and read its description
@@ -1086,19 +1092,16 @@ read_anon(SerdReader* const reader,
if (!subject) {
*ctx.flags |= SERD_ANON_CONT;
}
-
bool ate_dot_in_list = false;
TRY_FAILING(st, read_predicateObjectList(reader, ctx, &ate_dot_in_list));
if (ate_dot_in_list) {
return r_err(reader, SERD_BAD_SYNTAX, "'.' inside blank\n");
}
-
read_ws_star(reader);
if (reader->end_func) {
reader->end_func(reader->handle, deref(reader, *dest));
}
-
*ctx.flags = old_flags;
}
@@ -1175,7 +1178,7 @@ read_object(SerdReader* const reader,
case '7':
case '8':
case '9':
- st = read_number(reader, &o, &datatype, ate_dot);
+ st = read_number(reader, &o, &datatype, &flags, ate_dot);
break;
case '\"':
case '\'':
@@ -1191,6 +1194,7 @@ read_object(SerdReader* const reader,
node = deref(reader, o);
if ((node->length == 4 && !memcmp(serd_node_string(node), "true", 4)) ||
(node->length == 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);
st = SERD_SUCCESS;
@@ -1210,7 +1214,7 @@ read_object(SerdReader* const reader,
}
if (!st && emit && simple) {
- st = emit_statement(reader, *ctx, o, datatype, lang);
+ st = emit_statement(reader, *ctx, o);
} else if (!st && !emit) {
ctx->object = o;
ctx->datatype = datatype;
@@ -1305,6 +1309,7 @@ static SerdStatus
read_collection(SerdReader* const reader, ReadContext ctx, Ref* const dest)
{
SerdStatus st = SERD_SUCCESS;
+
skip_byte(reader, '(');
bool end = peek_delim(reader, ')');
@@ -1312,7 +1317,7 @@ read_collection(SerdReader* const reader, ReadContext ctx, Ref* const dest)
*dest = end ? reader->rdf_nil : blank_id(reader);
if (ctx.subject) { // Reading a collection object
*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_O_BEGIN;
*ctx.flags |= SERD_LIST_CONT;
} else { // Reading a collection subject
@@ -1352,7 +1357,7 @@ read_collection(SerdReader* const reader, ReadContext ctx, Ref* const 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
@@ -1745,7 +1750,7 @@ read_nquads_statement(SerdReader* const 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 de42075e..8edf7fc1 100644
--- a/src/node.c
+++ b/src/node.c
@@ -34,6 +34,8 @@
static const size_t serd_node_align = 2 * sizeof(uint64_t);
+static const SerdNodeFlags meta_mask = (SERD_HAS_DATATYPE | SERD_HAS_LANGUAGE);
+
static size_t
serd_uri_string_length(const SerdURIView* const uri)
{
@@ -69,10 +71,24 @@ serd_node_pad_size(const size_t n_bytes)
return n_bytes + 2 + pad;
}
+static const SerdNode*
+serd_node_meta_c(const SerdNode* const node)
+{
+ return node + 1 + (serd_node_pad_size(node->length) / sizeof(SerdNode));
+}
+
+static const SerdNode*
+serd_node_maybe_get_meta_c(const SerdNode* const node)
+{
+ return (node->flags & meta_mask) ? serd_node_meta_c(node) : NULL;
+}
+
static SERD_PURE_FUNC size_t
serd_node_total_size(const SerdNode* const node)
{
- return node ? (sizeof(SerdNode) + serd_node_pad_size(node->length)) : 0;
+ return node ? (sizeof(SerdNode) + serd_node_pad_size(node->length) +
+ serd_node_total_size(serd_node_maybe_get_meta_c(node)))
+ : 0;
}
SerdNode*
@@ -87,6 +103,7 @@ serd_node_malloc(const size_t length,
node->flags = flags;
node->type = type;
+ assert((uintptr_t)node % serd_node_align == 0U);
return node;
}
@@ -103,7 +120,7 @@ serd_node_set(SerdNode** const dst, const SerdNode* const src)
}
assert(*dst);
- memcpy(*dst, src, sizeof(SerdNode) + src->length + 1);
+ memcpy(*dst, src, size);
}
SerdNode*
@@ -112,8 +129,10 @@ serd_new_string(SerdNodeType type, const char* str)
SerdNodeFlags flags = 0;
const size_t length = serd_strlen(str, &flags);
SerdNode* node = serd_node_malloc(length, flags, type);
+
memcpy(serd_node_buffer(node), str, length);
node->length = length;
+
return node;
}
@@ -131,6 +150,49 @@ serd_new_substring(const SerdNodeType type,
}
SerdNode*
+serd_new_literal(const char* const str,
+ const char* const datatype,
+ const char* const lang)
+{
+ SerdNodeFlags flags = 0;
+ const size_t length = serd_strlen(str, &flags);
+ const size_t len = serd_node_pad_size(length);
+
+ 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, length);
+ node->length = length;
+
+ SerdNode* lang_node = node + 1 + (len / sizeof(SerdNode));
+ lang_node->type = SERD_LITERAL;
+ lang_node->length = 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, length);
+ node->length = length;
+
+ SerdNode* datatype_node = node + 1 + (len / sizeof(SerdNode));
+ datatype_node->type = SERD_URI;
+ datatype_node->length = datatype_len;
+ memcpy(serd_node_buffer(datatype_node), datatype, datatype_len);
+ } else {
+ node = serd_node_malloc(length, flags, SERD_LITERAL);
+ memcpy(serd_node_buffer(node), str, length);
+ node->length = length;
+ }
+
+ return node;
+}
+
+SerdNode*
serd_node_copy(const SerdNode* node)
{
if (!node) {
@@ -146,9 +208,30 @@ serd_node_copy(const SerdNode* node)
bool
serd_node_equals(const SerdNode* const a, const SerdNode* const b)
{
- return (a == b) ||
- (a && b && a->type == b->type && a->length == b->length &&
- !memcmp(serd_node_string(a), serd_node_string(b), a->length));
+ if (a == b) {
+ return true;
+ }
+
+ if (!a || !b || a->length != b->length || a->flags != b->flags ||
+ a->type != b->type) {
+ return false;
+ }
+
+ const size_t length = a->length;
+ if (!!memcmp(serd_node_string(a), serd_node_string(b), length)) {
+ return false;
+ }
+
+ const SerdNodeFlags flags = a->flags;
+ if (flags & meta_mask) {
+ const SerdNode* const am = serd_node_meta_c(a);
+ const SerdNode* const bm = serd_node_meta_c(b);
+
+ return am->length == bm->length && am->type == bm->type &&
+ !memcmp(serd_node_string(am), serd_node_string(bm), am->length);
+ }
+
+ return true;
}
SerdNode*
@@ -444,6 +527,32 @@ serd_node_uri_view(const SerdNode* const node)
: SERD_URI_NULL;
}
+const SerdNode*
+serd_node_datatype(const SerdNode* const node)
+{
+ if (!node || !(node->flags & SERD_HAS_DATATYPE)) {
+ return NULL;
+ }
+
+ const size_t len = serd_node_pad_size(node->length);
+ const SerdNode* const datatype = node + 1 + (len / sizeof(SerdNode));
+ assert(datatype->type == SERD_URI || datatype->type == SERD_CURIE);
+ return datatype;
+}
+
+const SerdNode*
+serd_node_language(const SerdNode* const node)
+{
+ if (!node || !(node->flags & SERD_HAS_LANGUAGE)) {
+ return NULL;
+ }
+
+ const size_t len = serd_node_pad_size(node->length);
+ const SerdNode* const lang = node + 1 + (len / sizeof(SerdNode));
+ assert(lang->type == SERD_LITERAL);
+ return lang;
+}
+
SerdNodeFlags
serd_node_flags(const SerdNode* const node)
{
diff --git a/src/reader.c b/src/reader.c
index 140c07ba..02738cd2 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -136,11 +136,7 @@ pop_node(SerdReader* const reader, const Ref ref)
}
SerdStatus
-emit_statement(SerdReader* const reader,
- const ReadContext ctx,
- const Ref o,
- const Ref d,
- const Ref l)
+emit_statement(SerdReader* const reader, const ReadContext ctx, const Ref o)
{
SerdNode* graph = deref(reader, ctx.graph);
if (!graph && reader->default_graph) {
@@ -154,9 +150,7 @@ emit_statement(SerdReader* const reader,
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 a528fcc8..0de1df2a 100644
--- a/src/reader.h
+++ b/src/reader.h
@@ -105,7 +105,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 a0325243..5aad6d29 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -143,8 +143,6 @@ typedef enum { RESET_GRAPH = 1U << 0U, RESET_INDENT = 1U << 1U } ResetFlag;
SERD_NODISCARD static SerdStatus
write_node(SerdWriter* writer,
const SerdNode* node,
- const SerdNode* datatype,
- const SerdNode* lang,
Field field,
SerdStatementFlags flags);
@@ -667,15 +665,15 @@ reset_context(SerdWriter* writer, const unsigned flags)
}
SERD_NODISCARD static SerdStatus
-write_literal(SerdWriter* writer,
- const SerdNode* node,
- const SerdNode* datatype,
- const SerdNode* lang,
- SerdStatementFlags flags)
+write_literal(SerdWriter* const writer,
+ const SerdNode* const node,
+ const SerdStatementFlags flags)
{
- SerdStatus st = SERD_SUCCESS;
- const char* const node_str = serd_node_string(node);
- const char* const type_uri = datatype ? serd_node_string(datatype) : NULL;
+ SerdStatus st = SERD_SUCCESS;
+ const SerdNode* const datatype = serd_node_datatype(node);
+ const SerdNode* const lang = serd_node_language(node);
+ const char* const node_str = serd_node_string(node);
+ const char* const type_uri = datatype ? serd_node_string(datatype) : NULL;
if (supports_abbrev(writer) && type_uri) {
if (!strncmp(type_uri, NS_XSD, sizeof(NS_XSD) - 1) &&
@@ -710,7 +708,7 @@ write_literal(SerdWriter* writer,
TRY(st, esink(serd_node_string(lang), lang->length, writer));
} else if (type_uri) {
TRY(st, esink("^^", 2, writer));
- return write_node(writer, datatype, NULL, NULL, FIELD_NONE, flags);
+ return write_node(writer, datatype, FIELD_NONE, flags);
}
return st;
@@ -862,18 +860,16 @@ write_blank(SerdWriter* const writer,
}
SERD_NODISCARD static SerdStatus
-write_node(SerdWriter* writer,
- const SerdNode* node,
- const SerdNode* datatype,
- const SerdNode* lang,
- Field field,
- SerdStatementFlags flags)
+write_node(SerdWriter* const writer,
+ const SerdNode* const node,
+ const Field field,
+ const SerdStatementFlags flags)
{
SerdStatus st = SERD_SUCCESS;
switch (node->type) {
case SERD_LITERAL:
- st = write_literal(writer, node, datatype, lang, flags);
+ st = write_literal(writer, node, flags);
break;
case SERD_URI:
st = write_uri_node(writer, node, field);
@@ -904,7 +900,7 @@ write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred)
{
SerdStatus st = SERD_SUCCESS;
- TRY(st, write_node(writer, pred, NULL, NULL, FIELD_PREDICATE, flags));
+ TRY(st, write_node(writer, pred, FIELD_PREDICATE, flags));
TRY(st, write_sep(writer, SEP_P_O));
serd_node_set(&writer->context.predicate, pred);
@@ -914,12 +910,10 @@ write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred)
}
SERD_NODISCARD static SerdStatus
-write_list_next(SerdWriter* writer,
- SerdStatementFlags flags,
- const SerdNode* predicate,
- const SerdNode* object,
- const SerdNode* datatype,
- const SerdNode* lang)
+write_list_next(SerdWriter* const writer,
+ const SerdStatementFlags flags,
+ const SerdNode* const predicate,
+ const SerdNode* const object)
{
SerdStatus st = SERD_SUCCESS;
@@ -929,7 +923,7 @@ write_list_next(SerdWriter* writer,
}
if (!strcmp(serd_node_string(predicate), NS_RDF "first")) {
- TRY(st, write_node(writer, object, datatype, lang, FIELD_OBJECT, flags));
+ TRY(st, write_node(writer, object, FIELD_OBJECT, flags));
} else {
TRY(st, write_sep(writer, SEP_LIST_SEP));
}
@@ -954,14 +948,12 @@ terminate_context(SerdWriter* writer)
}
SerdStatus
-serd_writer_write_statement(SerdWriter* writer,
- SerdStatementFlags flags,
- const SerdNode* graph,
- const SerdNode* subject,
- const SerdNode* predicate,
- const SerdNode* object,
- const SerdNode* datatype,
- const SerdNode* lang)
+serd_writer_write_statement(SerdWriter* const writer,
+ const SerdStatementFlags flags,
+ const SerdNode* const graph,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object)
{
SerdStatus st = SERD_SUCCESS;
@@ -971,14 +963,14 @@ serd_writer_write_statement(SerdWriter* writer,
// Simple case: write a line of NTriples or NQuads
if (writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS) {
- TRY(st, write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags));
+ TRY(st, write_node(writer, subject, FIELD_SUBJECT, flags));
TRY(st, esink(" ", 1, writer));
- TRY(st, write_node(writer, predicate, NULL, NULL, FIELD_PREDICATE, flags));
+ TRY(st, write_node(writer, predicate, FIELD_PREDICATE, flags));
TRY(st, esink(" ", 1, writer));
- TRY(st, write_node(writer, object, datatype, lang, FIELD_OBJECT, flags));
+ TRY(st, write_node(writer, object, FIELD_OBJECT, flags));
if (writer->syntax == SERD_NQUADS && graph) {
TRY(st, esink(" ", 1, writer));
- TRY(st, write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags));
+ TRY(st, write_node(writer, graph, FIELD_GRAPH, flags));
}
TRY(st, esink(" .\n", 3, writer));
return SERD_SUCCESS;
@@ -991,7 +983,7 @@ serd_writer_write_statement(SerdWriter* writer,
reset_context(writer, RESET_GRAPH | RESET_INDENT);
if (graph) {
TRY(st, write_newline(writer));
- TRY(st, write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags));
+ TRY(st, write_node(writer, graph, FIELD_GRAPH, flags));
TRY(st, write_sep(writer, SEP_GRAPH_BEGIN));
serd_node_set(&writer->context.graph, graph);
}
@@ -1004,9 +996,7 @@ serd_writer_write_statement(SerdWriter* writer,
return esink("()", 2, writer);
}
- TRY_FAILING(
- st, write_list_next(writer, flags, predicate, object, datatype, lang));
-
+ TRY_FAILING(st, write_list_next(writer, flags, predicate, object));
if (st == SERD_FAILURE) { // Reached end of list
pop_context(writer);
return SERD_SUCCESS;
@@ -1040,7 +1030,7 @@ serd_writer_write_statement(SerdWriter* writer,
TRY(st, write_pred(writer, flags, predicate));
}
- TRY(st, write_node(writer, object, datatype, lang, FIELD_OBJECT, flags));
+ TRY(st, write_node(writer, object, FIELD_OBJECT, flags));
} else {
// No abbreviation
@@ -1053,7 +1043,7 @@ serd_writer_write_statement(SerdWriter* writer,
TRY(st, write_newline(writer));
}
- TRY(st, write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags));
+ TRY(st, write_node(writer, subject, FIELD_SUBJECT, flags));
if ((flags & (SERD_ANON_S_BEGIN | SERD_LIST_S_BEGIN))) {
TRY(st, write_sep(writer, SEP_ANON_S_P));
} else {
@@ -1071,7 +1061,7 @@ serd_writer_write_statement(SerdWriter* writer,
TRY(st, write_pred(writer, flags, predicate));
}
- TRY(st, write_node(writer, object, datatype, lang, FIELD_OBJECT, flags));
+ TRY(st, write_node(writer, object, FIELD_OBJECT, flags));
}
if (flags & (SERD_ANON_S_BEGIN | SERD_LIST_S_BEGIN)) {
diff --git a/test/test_node.c b/test/test_node.c
index 11351e31..1d4d1107 100644
--- a/test/test_node.c
+++ b/test/test_node.c
@@ -196,6 +196,51 @@ test_node_from_substring(void)
serd_node_free(a_b);
}
+static void
+check_copy_equals(const SerdNode* const node)
+{
+ SerdNode* const copy = serd_node_copy(node);
+
+ assert(serd_node_equals(node, copy));
+
+ serd_node_free(copy);
+}
+
+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\""));
+ check_copy_equals(hello2);
+ 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"));
+ check_copy_equals(hello_l);
+ 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"));
+
+ check_copy_equals(hello_dt);
+ serd_node_free(hello_dt);
+}
+
int
main(void)
{
@@ -206,6 +251,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_reader_writer.c b/test/test_reader_writer.c
index 5aa2b850..245f5328 100644
--- a/test/test_reader_writer.c
+++ b/test/test_reader_writer.c
@@ -91,16 +91,12 @@ test_statement_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_statement;
@@ -471,57 +467,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);
@@ -591,7 +563,7 @@ test_reader(const char* path)
assert(!st);
assert(rt->n_base == 0);
assert(rt->n_prefix == 0);
- assert(rt->n_statement == 13);
+ assert(rt->n_statement == 6);
assert(rt->n_end == 0);
assert(rt->graph && serd_node_string(rt->graph) &&
!strcmp(serd_node_string(rt->graph), "http://example.org/"));
diff --git a/test/test_writer.c b/test/test_writer.c
index 9d004076..68d9e14e 100644
--- a/test/test_writer.c
+++ b/test/test_writer.c
@@ -31,7 +31,7 @@ test_write_long_literal(void)
SerdNode* p = serd_new_string(SERD_URI, "http://example.org/p");
SerdNode* o = serd_new_string(SERD_LITERAL, "hello \"\"\"world\"\"\"!");
- 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_node_free(o);
serd_node_free(p);
@@ -70,9 +70,7 @@ test_writer_cleanup(void)
SerdNode* p = serd_new_string(SERD_URI, "http://example.org/p");
SerdNode* o = serd_new_string(SERD_BLANK, "http://example.org/o");
- st = serd_writer_write_statement(
- writer, SERD_ANON_O_BEGIN, NULL, s, p, o, NULL, NULL);
-
+ st = serd_writer_write_statement(writer, SERD_ANON_O_BEGIN, NULL, s, p, o);
assert(!st);
// Write the start of several nested anonymous objects
@@ -83,7 +81,7 @@ test_writer_cleanup(void)
SerdNode* next_o = serd_new_string(SERD_BLANK, buf);
st = serd_writer_write_statement(
- writer, SERD_ANON_O_BEGIN, NULL, o, p, next_o, NULL, NULL);
+ writer, SERD_ANON_O_BEGIN, NULL, o, p, next_o);
serd_node_free(o);
o = next_o;
@@ -124,11 +122,11 @@ test_strict_write(void)
SerdNode* bad_lit = serd_new_string(SERD_LITERAL, (const char*)bad_str);
SerdNode* bad_uri = serd_new_string(SERD_URI, (const char*)bad_str);
- assert(serd_writer_write_statement(
- writer, 0, NULL, s, p, bad_lit, NULL, NULL) == SERD_BAD_TEXT);
+ assert(serd_writer_write_statement(writer, 0, NULL, s, p, bad_lit) ==
+ SERD_BAD_TEXT);
- assert(serd_writer_write_statement(
- writer, 0, NULL, s, p, bad_uri, NULL, NULL) == SERD_BAD_TEXT);
+ assert(serd_writer_write_statement(writer, 0, NULL, s, p, bad_uri) ==
+ SERD_BAD_TEXT);
serd_node_free(bad_uri);
serd_node_free(bad_lit);
@@ -162,7 +160,7 @@ test_write_error(void)
writer = serd_writer_new(
SERD_TURTLE, (SerdWriterFlags)0, env, NULL, error_sink, NULL);
assert(writer);
- st = serd_writer_write_statement(writer, 0U, NULL, u, u, u, NULL, NULL);
+ st = serd_writer_write_statement(writer, 0U, NULL, u, u, u);
assert(st == SERD_BAD_WRITE);
serd_writer_free(writer);