diff options
author | David Robillard <d@drobilla.net> | 2019-04-28 16:36:02 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2021-03-08 23:23:05 -0500 |
commit | 01daa5914169d57a6a6c4925d3f8d76db80a2bd8 (patch) | |
tree | 468a3371fe17adc082e93f7894147c5d67ed47fe /src/writer.c | |
parent | 36e2f27502524155e6475a75ffcab4999fce166a (diff) | |
download | serd-01daa5914169d57a6a6c4925d3f8d76db80a2bd8.tar.gz serd-01daa5914169d57a6a6c4925d3f8d76db80a2bd8.tar.bz2 serd-01daa5914169d57a6a6c4925d3f8d76db80a2bd8.zip |
Report writer errors and add strict write mode
Diffstat (limited to 'src/writer.c')
-rw-r--r-- | src/writer.c | 429 |
1 files changed, 253 insertions, 176 deletions
diff --git a/src/writer.c b/src/writer.c index 7e3033a8..3ac8f4d9 100644 --- a/src/writer.c +++ b/src/writer.c @@ -26,12 +26,26 @@ #include "serd/serd.h" #include <assert.h> +#include <errno.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#ifndef _MSC_VER +# define SERD_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define SERD_WARN_UNUSED_RESULT +#endif + +#define TRY(st, exp) \ + do { \ + if (((st) = (exp))) { \ + return (st); \ + } \ + } while (0) + typedef enum { CTX_NAMED, ///< Normal non-anonymous context CTX_BLANK, ///< Anonymous blank node @@ -134,7 +148,7 @@ serd_writer_set_prefix(SerdWriter* writer, const SerdNode* name, const SerdNode* uri); -static bool +SERD_WARN_UNUSED_RESULT static SerdStatus write_node(SerdWriter* writer, const SerdNode* node, SerdField field, @@ -221,16 +235,37 @@ ctx(SerdWriter* writer, const SerdField field) return node && node->type ? node : NULL; } -static inline size_t +SERD_WARN_UNUSED_RESULT static inline size_t sink(const void* buf, size_t len, SerdWriter* writer) { - return writer->write_func(buf, 1, len, writer->stream); + const size_t written = writer->write_func(buf, 1, len, writer->stream); + if (written != len) { + if (errno) { + serd_world_errorf(writer->world, + SERD_ERR_BAD_WRITE, + "write error (%s)\n", + strerror(errno)); + } else { + serd_world_errorf(writer->world, SERD_ERR_BAD_WRITE, "write error\n"); + } + } + + return written; +} + +SERD_WARN_UNUSED_RESULT 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 -write_character(SerdWriter* writer, const uint8_t* utf8, size_t* size) +SERD_WARN_UNUSED_RESULT static size_t +write_character(SerdWriter* writer, + const uint8_t* utf8, + size_t* size, + SerdStatus* st) { char escape[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; const uint32_t c = parse_utf8_char(utf8, size); @@ -238,6 +273,7 @@ write_character(SerdWriter* writer, const uint8_t* utf8, size_t* size) case 0: serd_world_errorf( writer->world, SERD_ERR_BAD_ARG, "invalid UTF-8 start: %X\n", utf8[0]); + *st = SERD_ERR_BAD_TEXT; return 0; case 1: snprintf(escape, sizeof(escape), "\\u%04X", utf8[0]); @@ -281,7 +317,7 @@ uri_must_escape(const char c) } static size_t -write_uri(SerdWriter* writer, const char* utf8, size_t n_bytes) +write_uri(SerdWriter* writer, const char* utf8, size_t n_bytes, SerdStatus* st) { size_t len = 0; for (size_t i = 0; i < n_bytes;) { @@ -293,15 +329,24 @@ write_uri(SerdWriter* writer, const char* utf8, size_t n_bytes) } // Bulk write all characters up to this special one - len += sink(&utf8[i], j - i, writer); + const size_t n_bulk = sink(&utf8[i], j - i, writer); + len += n_bulk; + if (n_bulk != j - i) { + return len; + } + if ((i = j) == n_bytes) { break; // Reached end } // Write UTF-8 character size_t size = 0; - len += write_character(writer, (const uint8_t*)utf8 + i, &size); + len += write_character(writer, (const uint8_t*)utf8 + i, &size, st); i += size; + if (*st && (writer->flags & SERD_WRITE_STRICT)) { + break; + } + if (size == 0) { // Corrupt input, write percent-encoded byts and scan to next start char escape[4] = {0, 0, 0, 0}; @@ -311,13 +356,23 @@ write_uri(SerdWriter* writer, const char* utf8, size_t n_bytes) } } } + return len; } -static size_t +SERD_WARN_UNUSED_RESULT static SerdStatus +ewrite_uri(SerdWriter* writer, const char* utf8, size_t n_bytes) +{ + SerdStatus st = SERD_SUCCESS; + write_uri(writer, utf8, n_bytes, &st); + + return (writer->flags & SERD_WRITE_STRICT) ? st : SERD_SUCCESS; +} + +SERD_WARN_UNUSED_RESULT static SerdStatus write_uri_from_node(SerdWriter* writer, const SerdNode* node) { - return write_uri(writer, serd_node_string(node), node->n_bytes); + return ewrite_uri(writer, serd_node_string(node), node->n_bytes); } static bool @@ -357,10 +412,10 @@ lname_must_escape(const char c) return false; } -static size_t +SERD_WARN_UNUSED_RESULT static SerdStatus write_lname(SerdWriter* writer, const char* utf8, size_t n_bytes) { - size_t len = 0; + SerdStatus st = SERD_SUCCESS; for (size_t i = 0; i < n_bytes; ++i) { size_t j = i; // Index of next character that must be escaped for (; j < n_bytes; ++j) { @@ -370,27 +425,28 @@ write_lname(SerdWriter* writer, const char* utf8, size_t n_bytes) } // Bulk write all characters up to this special one - len += sink(&utf8[i], j - i, writer); + TRY(st, esink(&utf8[i], j - i, writer)); if ((i = j) == n_bytes) { break; // Reached end } // Write escape - len += sink("\\", 1, writer); - len += sink(&utf8[i], 1, writer); + TRY(st, esink("\\", 1, writer)); + TRY(st, esink(&utf8[i], 1, writer)); } - return len; + return st; } -static size_t +SERD_WARN_UNUSED_RESULT static SerdStatus write_text(SerdWriter* writer, TextContext ctx, const char* utf8, size_t n_bytes) { - size_t len = 0; - size_t n_consecutive_quotes = 0; + size_t len = 0; + size_t n_consecutive_quotes = 0; + SerdStatus st = SERD_SUCCESS; for (size_t i = 0; i < n_bytes;) { if (utf8[i] != '"') { n_consecutive_quotes = 0; @@ -474,7 +530,10 @@ write_text(SerdWriter* writer, // Write UTF-8 character size_t size = 0; - len += write_character(writer, (const uint8_t*)utf8 + i - 1, &size); + len += write_character(writer, (const uint8_t*)utf8 + i - 1, &size, &st); + if (st && (writer->flags & SERD_WRITE_STRICT)) { + return st; + } if (size == 0) { // Corrupt input, write repacement character and scan to the next start @@ -485,41 +544,55 @@ write_text(SerdWriter* writer, i += size - 1; } } - return len; + + return (writer->flags & SERD_WRITE_STRICT) ? st : SERD_SUCCESS; } -static size_t +typedef struct { + SerdWriter* writer; + SerdStatus status; +} UriSinkContext; + +SERD_WARN_UNUSED_RESULT static size_t uri_sink(const void* buf, size_t size, size_t nmemb, void* stream) { (void)size; assert(size == 1); - return write_uri((SerdWriter*)stream, (const char*)buf, nmemb); + + UriSinkContext* const ctx = (UriSinkContext*)stream; + SerdWriter* const writer = ctx->writer; + + return write_uri(writer, (const char*)buf, nmemb, &ctx->status); } -static void +SERD_WARN_UNUSED_RESULT static SerdStatus write_newline(SerdWriter* writer, bool terse) { if (terse || (writer->flags & SERD_WRITE_TERSE)) { - sink(" ", 1, writer); - } else { - sink("\n", 1, writer); - for (int i = 0; i < writer->indent; ++i) { - sink("\t", 1, writer); - } + return esink(" ", 1, writer); + } + + SerdStatus st = SERD_SUCCESS; + TRY(st, esink("\n", 1, writer)); + for (int i = 0; i < writer->indent; ++i) { + TRY(st, esink("\t", 1, writer)); } + + return st; } -static void +SERD_WARN_UNUSED_RESULT static SerdStatus write_top_level_sep(SerdWriter* writer) { - if (!writer->empty && !(writer->flags & SERD_WRITE_TERSE)) { - write_newline(writer, false); - } + return ((!writer->empty && !(writer->flags & SERD_WRITE_TERSE)) + ? write_newline(writer, false) + : SERD_SUCCESS); } -static bool +SERD_WARN_UNUSED_RESULT static SerdStatus write_sep(SerdWriter* writer, const SerdStatementFlags flags, Sep sep) { + SerdStatus st = SERD_SUCCESS; const SepRule* rule = &rules[sep]; const bool terse = (((flags & SERD_TERSE_S) && (flags & SERD_LIST_S)) || ((flags & SERD_TERSE_O) && (flags & SERD_LIST_O))); @@ -537,19 +610,19 @@ write_sep(SerdWriter* writer, const SerdStatementFlags flags, Sep sep) // Write newline or space before separator if necessary if (rule->pre_line_after & (1u << writer->last_sep)) { - write_newline(writer, terse); + TRY(st, write_newline(writer, terse)); } else if (rule->pre_space_after & (1u << writer->last_sep)) { - sink(" ", 1, writer); + TRY(st, esink(" ", 1, writer)); } // Write actual separator string if (rule->len > 0) { - sink(rule->str, rule->len, writer); + TRY(st, esink(rule->str, rule->len, writer)); } // Write newline after separator if necessary if (rule->post_line_after & (1u << writer->last_sep)) { - write_newline(writer, terse); + TRY(st, write_newline(writer, terse)); writer->last_sep = SEP_NONE; } else { writer->last_sep = sep; @@ -559,10 +632,10 @@ write_sep(SerdWriter* writer, const SerdStatementFlags flags, Sep sep) writer->indent = 0; } - return true; + return st; } -static SerdStatus +static void reset_context(SerdWriter* writer, bool graph) { // Free any lingering contexts in case there was an error @@ -586,8 +659,6 @@ reset_context(SerdWriter* writer, bool graph) writer->empty = false; serd_stack_clear(&writer->anon_stack); - - return SERD_SUCCESS; } static bool @@ -600,7 +671,7 @@ is_inline_start(const SerdWriter* writer, (field == SERD_OBJECT && (flags & SERD_ANON_O)))); } -static bool +SERD_WARN_UNUSED_RESULT static SerdStatus write_literal(SerdWriter* writer, const SerdNode* node, SerdStatementFlags flags) @@ -614,8 +685,7 @@ write_literal(SerdWriter* writer, if (supports_abbrev(writer) && type_uri) { if (serd_node_equals(datatype, writer->world->xsd_boolean) || serd_node_equals(datatype, writer->world->xsd_integer)) { - sink(node_str, node->n_bytes, writer); - return true; + return esink(node_str, node->n_bytes, writer); } if (serd_node_equals(datatype, writer->world->xsd_decimal) && @@ -624,29 +694,29 @@ 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_str, node->n_bytes, writer); - return true; + return esink(node_str, node->n_bytes, writer); } } + SerdStatus st = SERD_SUCCESS; if (supports_abbrev(writer) && (node->flags & (SERD_HAS_NEWLINE | SERD_HAS_QUOTE))) { - sink("\"\"\"", 3, writer); - write_text(writer, WRITE_LONG_STRING, node_str, node->n_bytes); - sink("\"\"\"", 3, writer); + TRY(st, esink("\"\"\"", 3, writer)); + TRY(st, write_text(writer, WRITE_LONG_STRING, node_str, node->n_bytes)); + TRY(st, esink("\"\"\"", 3, writer)); } else { - sink("\"", 1, writer); - write_text(writer, WRITE_STRING, node_str, node->n_bytes); - sink("\"", 1, writer); + TRY(st, esink("\"", 1, writer)); + TRY(st, write_text(writer, WRITE_STRING, node_str, node->n_bytes)); + TRY(st, esink("\"", 1, writer)); } if (lang && serd_node_string(lang)) { - sink("@", 1, writer); - sink(serd_node_string(lang), lang->n_bytes, writer); + TRY(st, esink("@", 1, writer)); + TRY(st, esink(serd_node_string(lang), lang->n_bytes, writer)); } else if (type_uri) { - sink("^^", 2, writer); + TRY(st, esink("^^", 2, writer)); return write_node(writer, datatype, (SerdField)-1, flags); } - return true; + return st; } // Return true iff `buf` is a valid prefixed name prefix or suffix @@ -663,15 +733,17 @@ is_name(const char* buf, const size_t len) return true; } -static bool +SERD_WARN_UNUSED_RESULT static SerdStatus write_uri_node(SerdWriter* const writer, const SerdNode* node, const SerdField field, const SerdStatementFlags flags) { + SerdStatus st = SERD_SUCCESS; + if (is_inline_start(writer, field, flags)) { - write_sep(writer, flags, SEP_ANON_BEGIN); - sink(" == ", 4, writer); + TRY(st, write_sep(writer, flags, SEP_ANON_BEGIN)); + TRY(st, esink(" == ", 4, writer)); } const SerdNode* prefix = NULL; @@ -681,21 +753,20 @@ write_uri_node(SerdWriter* const writer, if (supports_abbrev(writer)) { if (field == SERD_PREDICATE && serd_node_equals(node, writer->world->rdf_type)) { - return sink("a", 1, writer) == 1; + return esink("a", 1, writer); } if (serd_node_equals(node, writer->world->rdf_type)) { - return sink("()", 2, writer) == 2; + return esink("()", 2, writer); } if (has_scheme && !(writer->flags & SERD_WRITE_UNQUALIFIED) && serd_env_qualify_in_place(writer->env, node, &prefix, &suffix) && is_name(serd_node_string(prefix), serd_node_length(prefix)) && is_name(suffix.buf, suffix.len)) { - write_uri_from_node(writer, prefix); - sink(":", 1, writer); - write_uri(writer, suffix.buf, suffix.len); - return true; + TRY(st, write_uri_from_node(writer, prefix)); + TRY(st, esink(":", 1, writer)); + return ewrite_uri(writer, suffix.buf, suffix.len); } } @@ -705,10 +776,10 @@ write_uri_node(SerdWriter* const writer, SERD_ERR_BAD_ARG, "syntax does not support URI reference <%s>\n", node_str); - return false; + return SERD_ERR_BAD_ARG; } - sink("<", 1, writer); + TRY(st, esink("<", 1, writer)); if (!(writer->flags & SERD_WRITE_UNRESOLVED) && serd_env_base_uri(writer->env)) { const SerdURIView base_uri = serd_env_base_uri_view(writer->env); @@ -716,26 +787,27 @@ write_uri_node(SerdWriter* const writer, SerdURIView abs_uri = serd_resolve_uri(uri, base_uri); bool rooted = uri_is_under(&base_uri, &writer->root_uri); const SerdURIView* root = rooted ? &writer->root_uri : &base_uri; + UriSinkContext ctx = {writer, SERD_SUCCESS}; + const bool write_abs = + (!supports_abbrev(writer) || !uri_is_under(&abs_uri, root)); - if (writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS || - !uri_is_under(&abs_uri, root) || !uri_is_related(&abs_uri, &base_uri)) { - serd_write_uri(abs_uri, uri_sink, writer); - } else { - serd_write_uri(serd_relative_uri(uri, base_uri), uri_sink, writer); + write_abs + ? serd_write_uri(abs_uri, uri_sink, &ctx) + : serd_write_uri(serd_relative_uri(uri, base_uri), uri_sink, &ctx); + + st = ctx.status; + if (st && (writer->flags & SERD_WRITE_STRICT)) { + return st; } } else { - write_uri_from_node(writer, node); - } - sink(">", 1, writer); - - if (is_inline_start(writer, field, flags)) { - sink(" ;", 2, writer); + TRY(st, write_uri_from_node(writer, node)); } + TRY(st, esink(">", 1, writer)); - return true; + return is_inline_start(writer, field, flags) ? esink(" ;", 2, writer) : st; } -static bool +SERD_WARN_UNUSED_RESULT static SerdStatus write_curie(SerdWriter* const writer, const SerdNode* node, const SerdField field, @@ -754,28 +826,28 @@ write_curie(SerdWriter* const writer, st, "undefined namespace prefix `%s'\n", serd_node_string(node)); - return false; + return st; } - sink("<", 1, writer); - write_uri(writer, prefix.buf, prefix.len); - write_uri(writer, suffix.buf, suffix.len); - sink(">", 1, writer); + TRY(st, esink("<", 1, writer)); + TRY(st, ewrite_uri(writer, prefix.buf, prefix.len)); + TRY(st, ewrite_uri(writer, suffix.buf, suffix.len)); + TRY(st, esink(">", 1, writer)); break; case SERD_TURTLE: case SERD_TRIG: if (is_inline_start(writer, field, flags)) { - write_sep(writer, flags, SEP_ANON_BEGIN); - sink(" == ", 4, writer); + TRY(st, write_sep(writer, flags, SEP_ANON_BEGIN)); + TRY(st, esink(" == ", 4, writer)); } - write_lname(writer, serd_node_string(node), node->n_bytes); + TRY(st, write_lname(writer, serd_node_string(node), node->n_bytes)); if (is_inline_start(writer, field, flags)) { - sink(" ;", 2, writer); + TRY(st, esink(" ;", 2, writer)); } } - return true; + return st; } -static bool +SERD_WARN_UNUSED_RESULT static SerdStatus write_blank(SerdWriter* const writer, const SerdNode* node, const SerdField field, @@ -794,25 +866,26 @@ write_blank(SerdWriter* const writer, if (field == SERD_SUBJECT && (flags & SERD_EMPTY_S)) { writer->last_sep = SEP_NONE; // Treat "[]" like a node - return sink("[]", 2, writer) == 2; + return esink("[]", 2, writer); } } - sink("_:", 2, writer); - if (writer->bprefix && + SerdStatus st = esink("_:", 2, writer); + if (!st && writer->bprefix && !strncmp(node_str, writer->bprefix, writer->bprefix_len)) { - sink(node_str + writer->bprefix_len, - node->n_bytes - writer->bprefix_len, - writer); + TRY(st, + esink(node_str + writer->bprefix_len, + node->n_bytes - writer->bprefix_len, + writer)); } else { - sink(node_str, node->n_bytes, writer); + TRY(st, esink(node_str, node->n_bytes, writer)); } writer->last_sep = SEP_NONE; - return true; + return st; } -static bool +SERD_WARN_UNUSED_RESULT static SerdStatus write_node(SerdWriter* writer, const SerdNode* node, const SerdField field, @@ -829,7 +902,7 @@ write_node(SerdWriter* writer, return write_blank(writer, node, field, flags); } - return false; + return SERD_ERR_INTERNAL; } static inline bool @@ -838,32 +911,31 @@ is_resource(const SerdNode* node) return node && node->type > SERD_LITERAL; } -static void +SERD_WARN_UNUSED_RESULT static SerdStatus write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred) { - write_node(writer, pred, SERD_PREDICATE, flags); - write_sep(writer, flags, SEP_P_O); + SerdStatus st = SERD_SUCCESS; + TRY(st, write_node(writer, pred, SERD_PREDICATE, flags)); + TRY(st, write_sep(writer, flags, SEP_P_O)); serd_node_set(&writer->context.predicate, pred); + return st; } -static bool +SERD_WARN_UNUSED_RESULT static SerdStatus write_list_obj(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* predicate, - const SerdNode* object) + const SerdNode* object, + bool* is_end) { if (serd_node_equals(object, writer->world->rdf_nil)) { - write_sep(writer, writer->context.flags, SEP_LIST_END); - return true; + *is_end = true; + return write_sep(writer, writer->context.flags, SEP_LIST_END); } - if (serd_node_equals(predicate, writer->world->rdf_first)) { - write_node(writer, object, SERD_OBJECT, flags); - } else { - write_sep(writer, writer->context.flags, SEP_LIST_SEP); - } - - return false; + return (serd_node_equals(predicate, writer->world->rdf_first) + ? write_node(writer, object, SERD_OBJECT, flags) + : write_sep(writer, writer->context.flags, SEP_LIST_SEP)); } static SerdStatus @@ -888,49 +960,44 @@ serd_writer_write_statement(SerdWriter* writer, 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, SERD_SUBJECT, flags)); - sink(" ", 1, writer); - TRY(write_node(writer, predicate, SERD_PREDICATE, flags)); - sink(" ", 1, writer); - TRY(write_node(writer, object, SERD_OBJECT, flags)); + TRY(st, write_node(writer, subject, SERD_SUBJECT, flags)); + TRY(st, esink(" ", 1, writer)); + TRY(st, write_node(writer, predicate, SERD_PREDICATE, flags)); + TRY(st, esink(" ", 1, writer)); + TRY(st, write_node(writer, object, SERD_OBJECT, flags)); if (writer->syntax == SERD_NQUADS && graph) { - sink(" ", 1, writer); - TRY(write_node(writer, graph, SERD_GRAPH, flags)); + TRY(st, esink(" ", 1, writer)); + TRY(st, write_node(writer, graph, SERD_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 && ctx(writer, SERD_GRAPH))) { if (ctx(writer, SERD_SUBJECT)) { - write_sep(writer, writer->context.flags, SEP_END_S); + TRY(st, write_sep(writer, writer->context.flags, SEP_END_S)); } if (ctx(writer, SERD_GRAPH)) { - write_sep(writer, writer->context.flags, SEP_GRAPH_END); + TRY(st, write_sep(writer, writer->context.flags, SEP_GRAPH_END)); } - write_top_level_sep(writer); + TRY(st, write_top_level_sep(writer)); reset_context(writer, true); if (graph) { - TRY(write_node(writer, graph, SERD_GRAPH, flags)); - write_sep(writer, flags, SEP_GRAPH_BEGIN); + TRY(st, write_node(writer, graph, SERD_GRAPH, flags)); + TRY(st, write_sep(writer, flags, SEP_GRAPH_BEGIN)); serd_node_set(&writer->context.graph, graph); } } if (writer->context.type == CTX_LIST) { - if (write_list_obj(writer, flags, predicate, object)) { + bool is_end = false; + TRY(st, write_list_obj(writer, flags, predicate, object, &is_end)); + if (is_end) { // Reached end of list pop_context(writer); return SERD_SUCCESS; @@ -944,8 +1011,8 @@ serd_writer_write_statement(SerdWriter* writer, writer->context.indented_object = true; } - write_sep(writer, writer->context.flags, SEP_END_O); - write_node(writer, object, SERD_OBJECT, flags); + TRY(st, write_sep(writer, writer->context.flags, SEP_END_O)); + TRY(st, write_node(writer, object, SERD_OBJECT, flags)); } else { // Abbreviate S if (writer->context.indented_object && writer->indent > 0) { @@ -953,10 +1020,10 @@ serd_writer_write_statement(SerdWriter* writer, writer->context.indented_object = false; } - Sep sep = ctx(writer, SERD_PREDICATE) ? SEP_END_P : SEP_S_P; - write_sep(writer, writer->context.flags, sep); - write_pred(writer, writer->context.flags, predicate); - write_node(writer, object, SERD_OBJECT, flags); + const Sep sep = ctx(writer, SERD_PREDICATE) ? SEP_END_P : SEP_S_P; + TRY(st, write_sep(writer, writer->context.flags, sep)); + TRY(st, write_pred(writer, writer->context.flags, predicate)); + TRY(st, write_node(writer, object, SERD_OBJECT, flags)); } } else { // No abbreviation @@ -967,30 +1034,30 @@ serd_writer_write_statement(SerdWriter* writer, if (serd_stack_is_empty(&writer->anon_stack)) { if (ctx(writer, SERD_SUBJECT)) { // Terminate last subject - write_sep(writer, writer->context.flags, SEP_END_S); + TRY(st, write_sep(writer, writer->context.flags, SEP_END_S)); } - write_top_level_sep(writer); + TRY(st, write_top_level_sep(writer)); } if (serd_stack_is_empty(&writer->anon_stack)) { - write_node(writer, subject, SERD_SUBJECT, flags); + TRY(st, write_node(writer, subject, SERD_SUBJECT, flags)); if (!(flags & (SERD_ANON_S | SERD_LIST_S))) { - write_sep(writer, writer->context.flags, SEP_S_P); + TRY(st, write_sep(writer, writer->context.flags, SEP_S_P)); } else if (flags & SERD_ANON_S) { - write_sep(writer, writer->context.flags, SEP_ANON_S_P); + TRY(st, write_sep(writer, writer->context.flags, SEP_ANON_S_P)); } } else { - write_sep(writer, writer->context.flags, SEP_ANON_S_P); + TRY(st, write_sep(writer, writer->context.flags, SEP_ANON_S_P)); } reset_context(writer, false); serd_node_set(&writer->context.subject, subject); if (!(flags & SERD_LIST_S)) { - write_pred(writer, flags, predicate); + TRY(st, write_pred(writer, flags, predicate)); } - write_node(writer, object, SERD_OBJECT, flags); + TRY(st, write_node(writer, object, SERD_OBJECT, flags)); } // Push context for list or anonymous subject if necessary @@ -1023,7 +1090,7 @@ serd_writer_write_statement(SerdWriter* writer, return st; } -static SerdStatus +SERD_WARN_UNUSED_RESULT static SerdStatus serd_writer_end_anon(SerdWriter* writer, const SerdNode* node) { if (writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS) { @@ -1037,7 +1104,7 @@ serd_writer_end_anon(SerdWriter* writer, const SerdNode* node) serd_node_string(node)); } - write_sep(writer, writer->context.flags, SEP_ANON_END); + SerdStatus st = write_sep(writer, writer->context.flags, SEP_ANON_END); pop_context(writer); if (writer->context.predicate && @@ -1046,7 +1113,7 @@ serd_writer_end_anon(SerdWriter* writer, const SerdNode* node) memset(writer->context.predicate, 0, sizeof(SerdNode)); } - return SERD_SUCCESS; + return st; } static SerdStatus @@ -1071,12 +1138,13 @@ serd_writer_on_event(SerdWriter* writer, const SerdEvent* event) SerdStatus serd_writer_finish(SerdWriter* writer) { + SerdStatus st = SERD_SUCCESS; if (ctx(writer, SERD_SUBJECT)) { - write_sep(writer, writer->context.flags, SEP_END_S); + st = write_sep(writer, writer->context.flags, SEP_END_S); } - if (ctx(writer, SERD_GRAPH)) { - write_sep(writer, writer->context.flags, SEP_GRAPH_END); + if (!st && ctx(writer, SERD_GRAPH)) { + st = write_sep(writer, writer->context.flags, SEP_GRAPH_END); } // Free any lingering contexts in case there was an error @@ -1088,7 +1156,7 @@ serd_writer_finish(SerdWriter* writer) writer->indent = 0; writer->context = WRITE_CONTEXT_NULL; writer->empty = true; - return SERD_SUCCESS; + return st; } SerdWriter* @@ -1142,20 +1210,24 @@ serd_writer_set_base_uri(SerdWriter* writer, const SerdNode* uri) return SERD_ERR_BAD_ARG; } - if (!serd_env_set_base_uri(writer->env, serd_node_string_view(uri))) { + SerdStatus st = + serd_env_set_base_uri(writer->env, serd_node_string_view(uri)); + + if (!st) { if (writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG) { if (ctx(writer, SERD_GRAPH) || ctx(writer, SERD_SUBJECT)) { - sink(" .\n\n", 4, writer); + TRY(st, esink(" .\n\n", 4, writer)); reset_context(writer, true); } - sink("@base <", 7, writer); - sink(serd_node_string(uri), uri->n_bytes, writer); - sink("> .\n", 4, writer); + TRY(st, esink("@base <", 7, writer)); + TRY(st, esink(serd_node_string(uri), uri->n_bytes, writer)); + TRY(st, esink("> .\n", 4, writer)); } writer->indent = 0; - return reset_context(writer, true); + reset_context(writer, true); } - return SERD_ERR_UNKNOWN; + + return st; } SerdStatus @@ -1181,23 +1253,28 @@ serd_writer_set_prefix(SerdWriter* writer, return SERD_ERR_BAD_ARG; } - if (!serd_env_set_prefix( - writer->env, serd_node_string_view(name), serd_node_string_view(uri))) { + SerdStatus st = serd_env_set_prefix( + writer->env, serd_node_string_view(name), serd_node_string_view(uri)); + + if (!st) { if (writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG) { if (ctx(writer, SERD_GRAPH) || ctx(writer, SERD_SUBJECT)) { - sink(" .\n\n", 4, writer); + TRY(st, esink(" .\n\n", 4, writer)); reset_context(writer, true); } - sink("@prefix ", 8, writer); - sink(serd_node_string(name), name->n_bytes, writer); - sink(": <", 3, writer); - write_uri_from_node(writer, uri); - sink("> .\n", 4, writer); + + TRY(st, esink("@prefix ", 8, writer)); + TRY(st, esink(serd_node_string(name), name->n_bytes, writer)); + TRY(st, esink(": <", 3, writer)); + TRY(st, write_uri_from_node(writer, uri)); + TRY(st, esink("> .\n", 4, writer)); } + writer->indent = 0; - return reset_context(writer, true); + reset_context(writer, true); } - return SERD_ERR_UNKNOWN; + + return st; } void |