aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2023-04-03 08:51:58 -0400
committerDavid Robillard <d@drobilla.net>2023-04-05 09:45:15 -0400
commitb8638fb5c51bcb4d51c6d13c2ee1e4734dfdd616 (patch)
tree538dc4c909648d45d91a33008b797ba0eccc2de7
parentf93c3fdd6c7d6ca61bec55d3c1ffae7e7c793913 (diff)
downloadserd-b8638fb5c51bcb4d51c6d13c2ee1e4734dfdd616.tar.gz
serd-b8638fb5c51bcb4d51c6d13c2ee1e4734dfdd616.tar.bz2
serd-b8638fb5c51bcb4d51c6d13c2ee1e4734dfdd616.zip
Improve writer error handling
-rw-r--r--NEWS5
-rw-r--r--doc/serdi.12
-rw-r--r--include/serd/serd.h1
-rw-r--r--meson.build2
-rw-r--r--src/byte_sink.h11
-rw-r--r--src/n3.c8
-rw-r--r--src/serd_config.h2
-rw-r--r--src/string.c2
-rw-r--r--src/try.h21
-rw-r--r--src/writer.c303
-rw-r--r--test/test_string.c2
11 files changed, 205 insertions, 154 deletions
diff --git a/NEWS b/NEWS
index 9b654a35..093d1ddc 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-serd (0.31.0) unstable; urgency=medium
+serd (0.31.1) unstable; urgency=medium
* Add Windows path separator support to serd_node_new_file_uri()
* Add serd_reader_skip_until_byte() to public API
@@ -17,11 +17,12 @@ serd (0.31.0) unstable; urgency=medium
* Gracefully handle bad characters in Turtle datatype syntax
* Improve TriG pretty-printing and remove trailing newlines
* Improve serdi man page
+ * Improve writer error handling
* Override pkg-config dependency within meson
* Replace duplicated dox_to_sphinx script with sphinxygen dependency
* Test header for warnings more strictly
- -- David Robillard <d@drobilla.net> Wed, 29 Mar 2023 23:55:55 +0000
+ -- David Robillard <d@drobilla.net> Mon, 03 Apr 2023 12:50:04 +0000
serd (0.30.16) stable; urgency=medium
diff --git a/doc/serdi.1 b/doc/serdi.1
index 997676a0..f3efe2d4 100644
--- a/doc/serdi.1
+++ b/doc/serdi.1
@@ -2,7 +2,7 @@
.\" # SPDX-License-Identifier: ISC
.Dd Jul 15, 2022
.Dt SERDI 1
-.Os Serd 0.31.0
+.Os Serd 0.31.1
.Sh NAME
.Nm serdi
.Nd read and write RDF syntax
diff --git a/include/serd/serd.h b/include/serd/serd.h
index e9fecd6c..ac9f2e06 100644
--- a/include/serd/serd.h
+++ b/include/serd/serd.h
@@ -120,6 +120,7 @@ typedef enum {
SERD_ERR_ID_CLASH, ///< Encountered clashing blank node IDs
SERD_ERR_BAD_CURIE, ///< Invalid CURIE (e.g. prefix does not exist)
SERD_ERR_INTERNAL, ///< Unexpected internal error (should not happen)
+ SERD_ERR_BAD_WRITE, ///< Error writing to file/stream
} SerdStatus;
/// Return a string describing a status code
diff --git a/meson.build b/meson.build
index 7fadf872..eb2547bb 100644
--- a/meson.build
+++ b/meson.build
@@ -2,7 +2,7 @@
# SPDX-License-Identifier: 0BSD OR ISC
project('serd', ['c'],
- version: '0.31.0',
+ version: '0.31.1',
license: 'ISC',
meson_version: '>= 0.56.0',
default_options: [
diff --git a/src/byte_sink.h b/src/byte_sink.h
index ed0f65b4..65b5eb12 100644
--- a/src/byte_sink.h
+++ b/src/byte_sink.h
@@ -33,13 +33,18 @@ serd_byte_sink_new(SerdSink sink, void* stream, size_t block_size)
return bsink;
}
-static inline void
+static inline SerdStatus
serd_byte_sink_flush(SerdByteSink* bsink)
{
if (bsink->block_size > 1 && bsink->size > 0) {
- bsink->sink(bsink->buf, bsink->size, bsink->stream);
- bsink->size = 0;
+ const size_t size = bsink->size;
+ const size_t n_out = bsink->sink(bsink->buf, size, bsink->stream);
+ bsink->size = 0;
+
+ return (n_out != size) ? SERD_ERR_BAD_WRITE : SERD_SUCCESS;
}
+
+ return SERD_SUCCESS;
}
static inline void
diff --git a/src/n3.c b/src/n3.c
index 48a7aba0..38505ee2 100644
--- a/src/n3.c
+++ b/src/n3.c
@@ -6,6 +6,7 @@
#include "serd_internal.h"
#include "stack.h"
#include "string_utils.h"
+#include "try.h"
#include "uri_utils.h"
#include "serd/serd.h"
@@ -27,13 +28,6 @@ _Pragma("clang diagnostic ignored \"-Wmissing-declarations\"")
# define SERD_FALLTHROUGH
#endif
-#define TRY(st, exp) \
- do { \
- if (((st) = (exp))) { \
- return (st); \
- } \
- } while (0)
-
static bool
fancy_syntax(const SerdReader* const reader)
{
diff --git a/src/serd_config.h b/src/serd_config.h
index 76733ab4..2a2c9b27 100644
--- a/src/serd_config.h
+++ b/src/serd_config.h
@@ -36,7 +36,7 @@
#define SERD_SRC_SERD_CONFIG_H
// Define version unconditionally so a warning will catch a mismatch
-#define SERD_VERSION "0.31.0"
+#define SERD_VERSION "0.31.1"
#if !defined(SERD_NO_DEFAULT_CONFIG)
diff --git a/src/string.c b/src/string.c
index 8b679bb6..07513739 100644
--- a/src/string.c
+++ b/src/string.c
@@ -37,6 +37,8 @@ serd_strerror(const SerdStatus status)
return (const uint8_t*)"Invalid CURIE";
case SERD_ERR_INTERNAL:
return (const uint8_t*)"Internal error";
+ case SERD_ERR_BAD_WRITE:
+ return (const uint8_t*)"Error writing to file/stream";
}
return (const uint8_t*)"Unknown error"; // never reached
}
diff --git a/src/try.h b/src/try.h
new file mode 100644
index 00000000..f49ae05f
--- /dev/null
+++ b/src/try.h
@@ -0,0 +1,21 @@
+// Copyright 2011-2023 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#ifndef SERD_SRC_TRY_H
+#define SERD_SRC_TRY_H
+
+#define TRY(st, exp) \
+ do { \
+ if (((st) = (exp))) { \
+ return (st); \
+ } \
+ } while (0)
+
+#define TRY_FAILING(st, exp) \
+ do { \
+ if (((st) = (exp)) > SERD_FAILURE) { \
+ return (st); \
+ } \
+ } while (0)
+
+#endif // SERD_SRC_TRY_H
diff --git a/src/writer.c b/src/writer.c
index 01b8ba47..fcd0e1dc 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -1,10 +1,12 @@
// Copyright 2011-2023 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
+#include "attributes.h"
#include "byte_sink.h"
#include "serd_internal.h"
#include "stack.h"
#include "string_utils.h"
+#include "try.h"
#include "uri_utils.h"
#include "serd/serd.h"
@@ -102,7 +104,7 @@ struct SerdWriterImpl {
typedef enum { WRITE_STRING, WRITE_LONG_STRING } TextContext;
typedef enum { RESET_GRAPH = 1U << 0U, RESET_INDENT = 1U << 1U } ResetFlag;
-static bool
+SERD_NODISCARD static SerdStatus
write_node(SerdWriter* writer,
const SerdNode* node,
const SerdNode* datatype,
@@ -130,7 +132,7 @@ deindent(SerdWriter* writer)
}
}
-static void
+static SerdStatus
w_err(SerdWriter* writer, SerdStatus st, const char* fmt, ...)
{
/* TODO: This results in errors with no file information, which is not
@@ -144,6 +146,7 @@ w_err(SerdWriter* writer, SerdStatus st, const char* fmt, ...)
const SerdError e = {st, (const uint8_t*)"", 0, 0, fmt, &args};
serd_error(writer->error_sink, writer->error_handle, &e);
va_end(args);
+ return st;
}
SERD_PURE_FUNC static WriteContext*
@@ -175,6 +178,12 @@ sink(const void* buf, size_t len, SerdWriter* writer)
return serd_byte_sink_write(buf, len, &writer->byte_sink);
}
+SERD_NODISCARD static inline SerdStatus
+esink(const void* buf, size_t len, SerdWriter* writer)
+{
+ return sink(buf, len, writer) == len ? SERD_SUCCESS : SERD_ERR_BAD_WRITE;
+}
+
// Write a single character, as an escape for single byte characters
// (Caller prints any single byte characters that don't need escaping)
static size_t
@@ -436,37 +445,42 @@ uri_sink(const void* buf, size_t len, void* stream)
return write_uri((SerdWriter*)stream, (const uint8_t*)buf, len);
}
-static void
+SERD_NODISCARD static SerdStatus
write_newline(SerdWriter* writer)
{
- sink("\n", 1, writer);
+ SerdStatus st = SERD_SUCCESS;
+
+ TRY(st, esink("\n", 1, writer));
for (unsigned i = 0; i < writer->indent; ++i) {
- sink("\t", 1, writer);
+ TRY(st, esink("\t", 1, writer));
}
+
+ return st;
}
-static bool
+SERD_NODISCARD static SerdStatus
write_sep(SerdWriter* writer, const Sep sep)
{
+ SerdStatus st = SERD_SUCCESS;
const SepRule* rule = &rules[sep];
if (rule->space_before) {
- write_newline(writer);
+ TRY(st, write_newline(writer));
}
if (rule->str) {
- sink(rule->str, rule->len, writer);
+ TRY(st, esink(rule->str, rule->len, writer));
}
if (rule->space_after_sep ||
(writer->last_sep == SEP_NODE && rule->space_after_node)) {
- write_newline(writer);
+ TRY(st, write_newline(writer));
} else if (writer->last_sep && writer->last_sep != SEP_GRAPH_BEGIN &&
rule->space_after_node) {
- sink(" ", 1, writer);
+ TRY(st, esink(" ", 1, writer));
}
writer->last_sep = sep;
- return true;
+ return st;
}
static SerdStatus
@@ -514,20 +528,21 @@ is_inline_start(const SerdWriter* writer, Field field, SerdStatementFlags flags)
(field == FIELD_OBJECT && (flags & SERD_ANON_O_BEGIN))));
}
-static bool
+SERD_NODISCARD static SerdStatus
write_literal(SerdWriter* writer,
const SerdNode* node,
const SerdNode* datatype,
const SerdNode* lang,
SerdStatementFlags flags)
{
+ SerdStatus st = SERD_SUCCESS;
+
if (supports_abbrev(writer) && datatype && datatype->buf) {
const char* type_uri = (const char*)datatype->buf;
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);
- return true;
+ return esink(node->buf, node->n_bytes, writer);
}
if (!strncmp(type_uri, NS_XSD, sizeof(NS_XSD) - 1) &&
@@ -538,29 +553,28 @@ write_literal(SerdWriter* writer,
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);
- return true;
+ return esink(node->buf, node->n_bytes, writer);
}
}
if (supports_abbrev(writer) &&
(node->flags & (SERD_HAS_NEWLINE | SERD_HAS_QUOTE))) {
- sink("\"\"\"", 3, writer);
+ TRY(st, esink("\"\"\"", 3, writer));
write_text(writer, WRITE_LONG_STRING, node->buf, node->n_bytes);
- sink("\"\"\"", 3, writer);
+ TRY(st, esink("\"\"\"", 3, writer));
} else {
- sink("\"", 1, writer);
+ TRY(st, esink("\"", 1, writer));
write_text(writer, WRITE_STRING, node->buf, node->n_bytes);
- sink("\"", 1, writer);
+ TRY(st, esink("\"", 1, writer));
}
if (lang && lang->buf) {
- sink("@", 1, writer);
- sink(lang->buf, lang->n_bytes, writer);
+ TRY(st, esink("@", 1, writer));
+ TRY(st, esink(lang->buf, lang->n_bytes, writer));
} else if (datatype && datatype->buf) {
- sink("^^", 2, writer);
+ TRY(st, esink("^^", 2, writer));
return write_node(writer, datatype, NULL, NULL, FIELD_NONE, flags);
}
- return true;
+ return SERD_SUCCESS;
}
// Return true iff `buf` is a valid prefixed name prefix or suffix
@@ -577,30 +591,31 @@ is_name(const uint8_t* buf, const size_t len)
return true;
}
-static bool
+SERD_NODISCARD static SerdStatus
write_uri_node(SerdWriter* const writer,
const SerdNode* node,
const Field field,
const SerdStatementFlags flags)
{
- SerdNode prefix;
- SerdChunk suffix;
+ SerdStatus st = SERD_SUCCESS;
+ SerdNode prefix = SERD_NODE_NULL;
+ SerdChunk suffix = {NULL, 0U};
if (is_inline_start(writer, field, flags)) {
++writer->indent;
- write_sep(writer, SEP_ANON_BEGIN);
- sink("== ", 3, writer);
+ TRY(st, write_sep(writer, SEP_ANON_BEGIN));
+ TRY(st, esink("== ", 3, writer));
}
const bool has_scheme = serd_uri_string_has_scheme(node->buf);
if (supports_abbrev(writer)) {
if (field == FIELD_PREDICATE &&
!strcmp((const char*)node->buf, NS_RDF "type")) {
- return sink("a", 1, writer) == 1;
+ return esink("a", 1, writer);
}
if (!strcmp((const char*)node->buf, NS_RDF "nil")) {
- return sink("()", 2, writer) == 2;
+ return esink("()", 2, writer);
}
if (has_scheme && (writer->style & SERD_STYLE_CURIED) &&
@@ -608,22 +623,21 @@ write_uri_node(SerdWriter* const writer,
is_name(prefix.buf, prefix.n_bytes) &&
is_name(suffix.buf, suffix.len)) {
write_uri(writer, prefix.buf, prefix.n_bytes);
- sink(":", 1, writer);
+ TRY(st, esink(":", 1, writer));
write_uri(writer, suffix.buf, suffix.len);
- return true;
+ return SERD_SUCCESS;
}
}
if (!has_scheme && !supports_uriref(writer) &&
!serd_env_get_base_uri(writer->env, NULL)->buf) {
- w_err(writer,
- SERD_ERR_BAD_ARG,
- "syntax does not support URI reference <%s>\n",
- node->buf);
- return false;
+ return w_err(writer,
+ SERD_ERR_BAD_ARG,
+ "syntax does not support URI reference <%s>\n",
+ node->buf);
}
- sink("<", 1, writer);
+ TRY(st, esink("<", 1, writer));
if (writer->style & SERD_STYLE_RESOLVED) {
SerdURI in_base_uri;
SerdURI uri;
@@ -643,17 +657,17 @@ write_uri_node(SerdWriter* const writer,
} else {
write_uri(writer, node->buf, node->n_bytes);
}
- sink(">", 1, writer);
+ TRY(st, esink(">", 1, writer));
if (is_inline_start(writer, field, flags)) {
- sink(" ;", 2, writer);
- write_newline(writer);
+ TRY(st, esink(" ;", 2, writer));
+ TRY(st, write_newline(writer));
}
- return true;
+ return SERD_SUCCESS;
}
-static bool
+SERD_NODISCARD static SerdStatus
write_curie(SerdWriter* const writer,
const SerdNode* node,
const Field field,
@@ -667,37 +681,38 @@ 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);
- return false;
+ return w_err(writer, st, "undefined namespace prefix '%s'\n", node->buf);
}
- sink("<", 1, writer);
+ TRY(st, esink("<", 1, writer));
write_uri(writer, prefix.buf, prefix.len);
write_uri(writer, suffix.buf, suffix.len);
- sink(">", 1, writer);
+ TRY(st, esink(">", 1, writer));
break;
case SERD_TURTLE:
case SERD_TRIG:
if (is_inline_start(writer, field, flags)) {
++writer->indent;
- write_sep(writer, SEP_ANON_BEGIN);
- sink("== ", 3, writer);
+ TRY(st, write_sep(writer, SEP_ANON_BEGIN));
+ TRY(st, esink("== ", 3, writer));
}
write_lname(writer, node->buf, node->n_bytes);
if (is_inline_start(writer, field, flags)) {
- sink(" ;", 2, writer);
- write_newline(writer);
+ TRY(st, esink(" ;", 2, writer));
+ TRY(st, write_newline(writer));
}
}
- return true;
+ return SERD_SUCCESS;
}
-static bool
+SERD_NODISCARD static SerdStatus
write_blank(SerdWriter* const writer,
const SerdNode* node,
const Field field,
const SerdStatementFlags flags)
{
+ SerdStatus st = SERD_SUCCESS;
+
if (supports_abbrev(writer)) {
if (is_inline_start(writer, field, flags)) {
++writer->indent;
@@ -719,25 +734,26 @@ write_blank(SerdWriter* const writer,
if ((field == FIELD_SUBJECT && (flags & SERD_EMPTY_S)) ||
(field == FIELD_OBJECT && (flags & SERD_EMPTY_O))) {
- return sink("[]", 2, writer) == 2;
+ return esink("[]", 2, writer);
}
}
- sink("_:", 2, writer);
+ TRY(st, esink("_:", 2, writer));
if (writer->bprefix && !strncmp((const char*)node->buf,
(const char*)writer->bprefix,
writer->bprefix_len)) {
- sink(node->buf + writer->bprefix_len,
- node->n_bytes - writer->bprefix_len,
- writer);
+ TRY(st,
+ esink(node->buf + writer->bprefix_len,
+ node->n_bytes - writer->bprefix_len,
+ writer));
} else {
- sink(node->buf, node->n_bytes, writer);
+ TRY(st, esink(node->buf, node->n_bytes, writer));
}
- return true;
+ return st;
}
-static bool
+SERD_NODISCARD static SerdStatus
write_node(SerdWriter* writer,
const SerdNode* node,
const SerdNode* datatype,
@@ -745,26 +761,26 @@ write_node(SerdWriter* writer,
Field field,
SerdStatementFlags flags)
{
- bool ret = false;
+ SerdStatus st = SERD_SUCCESS;
switch (node->type) {
case SERD_NOTHING:
break;
case SERD_LITERAL:
- ret = write_literal(writer, node, datatype, lang, flags);
+ st = write_literal(writer, node, datatype, lang, flags);
break;
case SERD_URI:
- ret = write_uri_node(writer, node, field, flags);
+ st = write_uri_node(writer, node, field, flags);
break;
case SERD_CURIE:
- ret = write_curie(writer, node, field, flags);
+ st = write_curie(writer, node, field, flags);
break;
case SERD_BLANK:
- ret = write_blank(writer, node, field, flags);
+ st = write_blank(writer, node, field, flags);
break;
}
writer->last_sep = SEP_NODE;
- return ret;
+ return st;
}
static bool
@@ -773,46 +789,56 @@ is_resource(const SerdNode* node)
return node && node->buf && node->type > SERD_LITERAL;
}
-static void
+SERD_NODISCARD static SerdStatus
write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred)
{
- write_node(writer, pred, NULL, NULL, FIELD_PREDICATE, flags);
- write_sep(writer, SEP_P_O);
+ SerdStatus st = SERD_SUCCESS;
+
+ TRY(st, write_node(writer, pred, NULL, NULL, FIELD_PREDICATE, flags));
+ TRY(st, write_sep(writer, SEP_P_O));
+
copy_node(&writer->context.predicate, pred);
+ return st;
}
-static bool
-write_list_obj(SerdWriter* writer,
- SerdStatementFlags flags,
- const SerdNode* predicate,
- const SerdNode* object,
- const SerdNode* datatype,
- const SerdNode* lang)
+SERD_NODISCARD static SerdStatus
+write_list_next(SerdWriter* writer,
+ SerdStatementFlags flags,
+ const SerdNode* predicate,
+ const SerdNode* object,
+ const SerdNode* datatype,
+ const SerdNode* lang)
{
+ SerdStatus st = SERD_SUCCESS;
+
if (!strcmp((const char*)object->buf, NS_RDF "nil")) {
deindent(writer);
- write_sep(writer, SEP_LIST_END);
- return true;
+ TRY(st, write_sep(writer, SEP_LIST_END));
+ return SERD_FAILURE;
}
if (!strcmp((const char*)predicate->buf, NS_RDF "first")) {
- write_sep(writer, SEP_LIST_SEP);
- write_node(writer, object, datatype, lang, FIELD_OBJECT, flags);
+ TRY(st, write_sep(writer, SEP_LIST_SEP));
+ TRY(st, write_node(writer, object, datatype, lang, FIELD_OBJECT, flags));
}
- return false;
+ return st;
}
-static void
+SERD_NODISCARD static SerdStatus
terminate_context(SerdWriter* writer)
{
+ SerdStatus st = SERD_SUCCESS;
+
if (writer->context.subject.type) {
- write_sep(writer, SEP_END_S);
+ TRY(st, write_sep(writer, SEP_END_S));
}
if (writer->context.graph.type) {
- write_sep(writer, SEP_GRAPH_END);
+ TRY(st, write_sep(writer, SEP_GRAPH_END));
}
+
+ return st;
}
SerdStatus
@@ -825,47 +851,45 @@ serd_writer_write_statement(SerdWriter* writer,
const SerdNode* datatype,
const SerdNode* lang)
{
+ SerdStatus st = SERD_SUCCESS;
+
if (!is_resource(subject) || !is_resource(predicate) || !object ||
!object->buf) {
return SERD_ERR_BAD_ARG;
}
-#define TRY(write_result) \
- do { \
- if (!(write_result)) { \
- return SERD_ERR_UNKNOWN; \
- } \
- } while (0)
-
if (writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS) {
- TRY(write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags));
- sink(" ", 1, writer);
- TRY(write_node(writer, predicate, NULL, NULL, FIELD_PREDICATE, flags));
- sink(" ", 1, writer);
- TRY(write_node(writer, object, datatype, lang, FIELD_OBJECT, flags));
+ TRY(st, write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags));
+ TRY(st, esink(" ", 1, writer));
+ TRY(st, write_node(writer, predicate, NULL, NULL, FIELD_PREDICATE, flags));
+ TRY(st, esink(" ", 1, writer));
+ TRY(st, write_node(writer, object, datatype, lang, FIELD_OBJECT, flags));
if (writer->syntax == SERD_NQUADS && graph) {
- sink(" ", 1, writer);
- TRY(write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags));
+ TRY(st, esink(" ", 1, writer));
+ TRY(st, write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags));
}
- sink(" .\n", 3, writer);
+ TRY(st, esink(" .\n", 3, writer));
return SERD_SUCCESS;
}
if ((graph && !serd_node_equals(graph, &writer->context.graph)) ||
(!graph && writer->context.graph.type)) {
- terminate_context(writer);
+ TRY(st, terminate_context(writer));
reset_context(writer, RESET_GRAPH | RESET_INDENT);
if (graph) {
- write_newline(writer);
- TRY(write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags));
+ TRY(st, write_newline(writer));
+ TRY(st, write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags));
++writer->indent;
- write_sep(writer, SEP_GRAPH_BEGIN);
+ TRY(st, write_sep(writer, SEP_GRAPH_BEGIN));
copy_node(&writer->context.graph, graph);
}
}
if ((flags & SERD_LIST_CONT)) {
- if (write_list_obj(writer, flags, predicate, object, datatype, lang)) {
+ TRY_FAILING(
+ st, write_list_next(writer, flags, predicate, object, datatype, lang));
+
+ if (st == SERD_FAILURE) {
// Reached end of list
if (--writer->list_depth == 0 && writer->list_subj.type) {
reset_context(writer, 0U);
@@ -875,44 +899,45 @@ serd_writer_write_statement(SerdWriter* writer,
}
return SERD_SUCCESS;
}
+
} 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;
}
- write_sep(writer, SEP_END_O);
- write_node(writer, object, datatype, lang, FIELD_OBJECT, flags);
+ TRY(st, write_sep(writer, SEP_END_O));
+ TRY(st, write_node(writer, object, datatype, lang, FIELD_OBJECT, flags));
if (!(flags & SERD_ANON_O_BEGIN)) {
deindent(writer);
}
} else {
// Abbreviate S
Sep sep = writer->context.predicate.type ? SEP_END_P : SEP_S_P;
- write_sep(writer, sep);
- write_pred(writer, flags, predicate);
- write_node(writer, object, datatype, lang, FIELD_OBJECT, flags);
+ TRY(st, write_sep(writer, sep));
+ TRY(st, write_pred(writer, flags, predicate));
+ TRY(st, write_node(writer, object, datatype, lang, FIELD_OBJECT, flags));
}
} else {
// No abbreviation
if (writer->context.subject.type) {
deindent(writer);
if (serd_stack_is_empty(&writer->anon_stack)) {
- write_sep(writer, SEP_END_S);
+ TRY(st, write_sep(writer, SEP_END_S));
}
}
if (!(flags & SERD_ANON_CONT)) {
if (writer->last_sep == SEP_END_S || writer->last_sep == SEP_END_DIRECT) {
- write_newline(writer);
+ TRY(st, write_newline(writer));
}
- write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags);
+ TRY(st, write_node(writer, subject, NULL, NULL, FIELD_SUBJECT, flags));
if ((flags & SERD_ANON_S_BEGIN)) {
- write_sep(writer, SEP_ANON_S_P);
+ TRY(st, write_sep(writer, SEP_ANON_S_P));
} else {
++writer->indent;
- write_sep(writer, SEP_S_P);
+ TRY(st, write_sep(writer, SEP_S_P));
}
} else {
@@ -923,10 +948,10 @@ serd_writer_write_statement(SerdWriter* writer,
copy_node(&writer->context.subject, subject);
if (!(flags & SERD_LIST_S_BEGIN)) {
- write_pred(writer, flags, predicate);
+ TRY(st, write_pred(writer, flags, predicate));
}
- write_node(writer, object, datatype, lang, FIELD_OBJECT, flags);
+ TRY(st, write_node(writer, object, datatype, lang, FIELD_OBJECT, flags));
}
if (flags & (SERD_ANON_S_BEGIN | SERD_ANON_O_BEGIN)) {
@@ -951,17 +976,19 @@ serd_writer_write_statement(SerdWriter* writer,
SerdStatus
serd_writer_end_anon(SerdWriter* writer, const SerdNode* node)
{
+ SerdStatus st = SERD_SUCCESS;
+
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;
+ return w_err(
+ writer, SERD_ERR_UNKNOWN, "unexpected end of anonymous node\n");
}
deindent(writer);
- write_sep(writer, SEP_ANON_END);
+ TRY(st, write_sep(writer, SEP_ANON_END));
free_context(&writer->context);
writer->context = *anon_stack_top(writer);
serd_stack_pop(&writer->anon_stack, sizeof(WriteContext));
@@ -971,18 +998,18 @@ serd_writer_end_anon(SerdWriter* writer, const SerdNode* node)
writer->context.predicate.type = SERD_NOTHING;
}
- return SERD_SUCCESS;
+ return st;
}
SerdStatus
serd_writer_finish(SerdWriter* writer)
{
- terminate_context(writer);
- serd_byte_sink_flush(&writer->byte_sink);
+ const SerdStatus st0 = terminate_context(writer);
+ const SerdStatus st1 = serd_byte_sink_flush(&writer->byte_sink);
free_context(&writer->context);
writer->indent = 0;
writer->context = WRITE_CONTEXT_NULL;
- return SERD_SUCCESS;
+ return st0 ? st0 : st1;
}
SerdWriter*
@@ -1038,7 +1065,7 @@ serd_writer_chop_blank_prefix(SerdWriter* writer, const uint8_t* prefix)
SerdStatus
serd_writer_set_base_uri(SerdWriter* writer, const SerdNode* uri)
{
- const SerdStatus st = serd_env_set_base_uri(writer->env, uri);
+ SerdStatus st = serd_env_set_base_uri(writer->env, uri);
if (st) {
return st;
}
@@ -1046,12 +1073,12 @@ serd_writer_set_base_uri(SerdWriter* writer, const SerdNode* uri)
serd_env_get_base_uri(writer->env, &writer->base_uri);
if (writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG) {
- terminate_context(writer);
- sink("@base <", 7, writer);
- sink(uri->buf, uri->n_bytes, writer);
- sink(">", 1, writer);
+ TRY(st, terminate_context(writer));
+ TRY(st, esink("@base <", 7, writer));
+ TRY(st, esink(uri->buf, uri->n_bytes, writer));
+ TRY(st, esink(">", 1, writer));
writer->last_sep = SEP_NODE;
- write_sep(writer, SEP_END_DIRECT);
+ TRY(st, write_sep(writer, SEP_END_DIRECT));
}
return reset_context(writer, RESET_GRAPH | RESET_INDENT);
@@ -1078,20 +1105,20 @@ serd_writer_set_prefix(SerdWriter* writer,
const SerdNode* name,
const SerdNode* uri)
{
- const SerdStatus st = serd_env_set_prefix(writer->env, name, uri);
+ SerdStatus st = serd_env_set_prefix(writer->env, name, uri);
if (st) {
return st;
}
if (writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG) {
- terminate_context(writer);
- sink("@prefix ", 8, writer);
- sink(name->buf, name->n_bytes, writer);
- sink(": <", 3, writer);
+ TRY(st, terminate_context(writer));
+ TRY(st, esink("@prefix ", 8, writer));
+ TRY(st, esink(name->buf, name->n_bytes, writer));
+ TRY(st, esink(": <", 3, writer));
write_uri(writer, uri->buf, uri->n_bytes);
- sink(">", 1, writer);
+ TRY(st, esink(">", 1, writer));
writer->last_sep = SEP_NODE;
- write_sep(writer, SEP_END_DIRECT);
+ TRY(st, write_sep(writer, SEP_END_DIRECT));
}
return reset_context(writer, RESET_GRAPH | RESET_INDENT);
diff --git a/test/test_string.c b/test/test_string.c
index 916281b3..86ccf982 100644
--- a/test/test_string.c
+++ b/test/test_string.c
@@ -31,7 +31,7 @@ test_strerror(void)
{
const uint8_t* msg = serd_strerror(SERD_SUCCESS);
assert(!strcmp((const char*)msg, "Success"));
- for (int i = SERD_FAILURE; i <= SERD_ERR_INTERNAL; ++i) {
+ for (int i = SERD_FAILURE; i <= SERD_ERR_BAD_WRITE; ++i) {
msg = serd_strerror((SerdStatus)i);
assert(strcmp((const char*)msg, "Success"));
}