aboutsummaryrefslogtreecommitdiffstats
path: root/src/read_nquads.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/read_nquads.c')
-rw-r--r--src/read_nquads.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/read_nquads.c b/src/read_nquads.c
new file mode 100644
index 00000000..b4e200d4
--- /dev/null
+++ b/src/read_nquads.c
@@ -0,0 +1,124 @@
+// Copyright 2011-2021 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+#include "read_nquads.h"
+
+#include "caret.h"
+#include "node.h"
+#include "read_ntriples.h"
+#include "reader.h"
+#include "stack.h"
+#include "statement.h"
+#include "try.h"
+
+#include "serd/caret.h"
+#include "serd/node.h"
+#include "serd/sink.h"
+#include "serd/statement.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+
+/// [6] graphLabel
+static SerdStatus
+read_graphLabel(SerdReader* const reader, SerdNode** const dest)
+{
+ return read_nt_subject(reader, dest); // Equivalent rule
+}
+
+/// [2] statement
+static SerdStatus
+read_nquads_statement(SerdReader* const reader)
+{
+ SerdStatementFlags flags = 0;
+ ReadContext ctx = {0, 0, 0, 0, &flags};
+ SerdStatus st = SERD_SUCCESS;
+ bool ate_dot = false;
+
+ // Read subject and predicate
+ if ((st = read_nt_subject(reader, &ctx.subject)) ||
+ (st = skip_horizontal_whitespace(reader)) ||
+ (st = read_nt_predicate(reader, &ctx.predicate)) ||
+ (st = skip_horizontal_whitespace(reader))) {
+ return st;
+ }
+
+ // Preserve the caret for error reporting and read object
+ SerdCaret orig_caret = reader->source.caret;
+ if ((st = read_nt_object(reader, &ctx.object, &ate_dot)) ||
+ (st = skip_horizontal_whitespace(reader))) {
+ return st;
+ }
+
+ if (!ate_dot) {
+ if (peek_byte(reader) == '.') {
+ eat_byte(reader);
+ } else {
+ TRY(st, read_graphLabel(reader, &ctx.graph));
+ skip_horizontal_whitespace(reader);
+ TRY(st, eat_byte_check(reader, '.'));
+ }
+ }
+
+ serd_node_zero_pad(ctx.object);
+ const SerdStatement statement = {
+ {ctx.subject, ctx.predicate, ctx.object, ctx.graph}, &orig_caret};
+
+ return serd_sink_write_statement(reader->sink, *ctx.flags, &statement);
+}
+
+SerdStatus
+read_nquads_line(SerdReader* const reader)
+{
+ const size_t orig_stack_size = reader->stack.size;
+ SerdStatus st = SERD_SUCCESS;
+
+ skip_horizontal_whitespace(reader);
+
+ switch (peek_byte(reader)) {
+ case EOF:
+ return SERD_FAILURE;
+
+ case '\n':
+ case '\r':
+ return read_EOL(reader);
+
+ case '#':
+ return read_comment(reader);
+
+ default:
+ if (!(st = read_nquads_statement(reader))) {
+ skip_horizontal_whitespace(reader);
+ if (peek_byte(reader) == '#') {
+ st = read_comment(reader);
+ }
+ }
+ break;
+ }
+
+ serd_stack_pop_to(&reader->stack, orig_stack_size);
+
+ return (st || peek_byte(reader) == EOF) ? st : read_EOL(reader);
+}
+
+SerdStatus
+read_nquadsDoc(SerdReader* const reader)
+{
+ // Read the first line
+ SerdStatus st = read_nquads_line(reader);
+ if (st == SERD_FAILURE || !tolerate_status(reader, st)) {
+ return st;
+ }
+
+ // Continue reading lines for as long as possible
+ for (st = SERD_SUCCESS; !st;) {
+ st = read_nquads_line(reader);
+ if (st > SERD_FAILURE && !reader->strict && tolerate_status(reader, st)) {
+ serd_reader_skip_until_byte(reader, '\n');
+ st = SERD_SUCCESS;
+ }
+ }
+
+ // If we made it this far, we succeeded at reading at least one line
+ return st > SERD_FAILURE ? st : SERD_SUCCESS;
+}