From 471ef4960aba6b5e1c9445229cddc0b3eb9ca148 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 29 Apr 2018 18:29:03 +0200 Subject: Simplify node construction API --- src/env.c | 82 ++++++++++++-------------------- src/env.h | 26 ++++++++++ src/node.c | 152 ++++++++++++++++++++++++++++++++++------------------------- src/serdi.c | 16 +++---- src/writer.c | 51 ++++++++++---------- 5 files changed, 177 insertions(+), 150 deletions(-) create mode 100644 src/env.h (limited to 'src') diff --git a/src/env.c b/src/env.c index eedb85fa..de10ca6b 100644 --- a/src/env.c +++ b/src/env.c @@ -14,6 +14,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "env.h" + #include "node.h" #include "serd/serd.h" @@ -36,10 +38,10 @@ struct SerdEnvImpl { }; SerdEnv* -serd_env_new(const SerdNode* base_uri) +serd_env_new(const SerdStringView base_uri) { SerdEnv* env = (SerdEnv*)calloc(1, sizeof(struct SerdEnvImpl)); - if (env && base_uri) { + if (env && base_uri.len) { serd_env_set_base_uri(env, base_uri); } @@ -62,40 +64,39 @@ serd_env_free(SerdEnv* env) free(env); } +SerdURIView +serd_env_base_uri_view(const SerdEnv* env) +{ + return env->base_uri; +} + const SerdNode* -serd_env_base_uri(const SerdEnv* env, SerdURIView* out) +serd_env_base_uri(const SerdEnv* env) { - if (out) { - *out = env->base_uri; - } return env->base_uri_node; } SerdStatus -serd_env_set_base_uri(SerdEnv* env, const SerdNode* uri) +serd_env_set_base_uri(SerdEnv* env, const SerdStringView uri) { - if (!env || (uri && uri->type != SERD_URI)) { - return SERD_ERR_BAD_ARG; - } - - if (!uri) { + if (!uri.len) { serd_node_free(env->base_uri_node); env->base_uri_node = NULL; env->base_uri = SERD_URI_NULL; return SERD_SUCCESS; } + SerdNode* const old_base_uri = env->base_uri_node; + // Resolve the new base against the current base in case it is relative const SerdURIView new_base_uri = - serd_resolve_uri(serd_parse_uri(serd_node_string(uri)), env->base_uri); - - SerdNode* const new_base_node = serd_new_parsed_uri(new_base_uri); + serd_resolve_uri(serd_parse_uri(uri.buf), env->base_uri); // Replace the current base URI - serd_node_free(env->base_uri_node); - env->base_uri_node = new_base_node; + env->base_uri_node = serd_new_parsed_uri(new_base_uri); env->base_uri = serd_node_uri_view(env->base_uri_node); + serd_node_free(old_base_uri); return SERD_SUCCESS; } @@ -115,65 +116,44 @@ serd_env_find(const SerdEnv* env, const char* name, size_t name_len) } static void -serd_env_add(SerdEnv* env, const SerdNode* name, const SerdNode* uri) +serd_env_add(SerdEnv* env, const SerdStringView name, const SerdStringView uri) { - const char* name_str = serd_node_string(name); - SerdPrefix* const prefix = serd_env_find(env, name_str, name->n_bytes); + SerdPrefix* const prefix = serd_env_find(env, name.buf, name.len); if (prefix) { - if (!serd_node_equals(prefix->uri, uri)) { - SerdNode* old_prefix_uri = prefix->uri; - prefix->uri = serd_node_copy(uri); - serd_node_free(old_prefix_uri); + if (strcmp(serd_node_string(prefix->uri), uri.buf)) { + serd_node_free(prefix->uri); + prefix->uri = serd_new_uri(uri); } } else { env->prefixes = (SerdPrefix*)realloc( env->prefixes, (++env->n_prefixes) * sizeof(SerdPrefix)); - env->prefixes[env->n_prefixes - 1].name = serd_node_copy(name); - env->prefixes[env->n_prefixes - 1].uri = serd_node_copy(uri); + env->prefixes[env->n_prefixes - 1].name = serd_new_string(name); + env->prefixes[env->n_prefixes - 1].uri = serd_new_uri(uri); } } SerdStatus -serd_env_set_prefix(SerdEnv* env, const SerdNode* name, const SerdNode* uri) +serd_env_set_prefix(SerdEnv* env, + const SerdStringView name, + const SerdStringView uri) { - if (!name || uri->type != SERD_URI) { - return SERD_ERR_BAD_ARG; - } - - if (serd_uri_string_has_scheme(serd_node_string(uri))) { + if (serd_uri_string_has_scheme(uri.buf)) { // Set prefix to absolute URI serd_env_add(env, name, uri); } else if (!env->base_uri_node) { return SERD_ERR_BAD_ARG; } else { // Resolve relative URI and create a new node and URI for it - SerdNode* const abs_uri = - serd_new_resolved_uri(serd_node_string_view(uri), env->base_uri); + SerdNode* const abs_uri = serd_new_resolved_uri(uri, env->base_uri); // Set prefix to resolved (absolute) URI - serd_env_add(env, name, abs_uri); - + serd_env_add(env, name, serd_node_string_view(abs_uri)); serd_node_free(abs_uri); } return SERD_SUCCESS; } -SerdStatus -serd_env_set_prefix_from_strings(SerdEnv* env, - const char* name, - const char* uri) -{ - SerdNode* name_node = serd_new_string(SERD_LITERAL, name); - SerdNode* uri_node = serd_new_string(SERD_URI, uri); - - const SerdStatus st = serd_env_set_prefix(env, name_node, uri_node); - - serd_node_free(name_node); - serd_node_free(uri_node); - return st; -} - bool serd_env_qualify(const SerdEnv* env, const SerdNode* uri, diff --git a/src/env.h b/src/env.h new file mode 100644 index 00000000..1c36b4ee --- /dev/null +++ b/src/env.h @@ -0,0 +1,26 @@ +/* + Copyright 2011-2020 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef SERD_ENV_H +#define SERD_ENV_H + +#include "serd/serd.h" + +SERD_CONST_FUNC +SerdURIView +serd_env_base_uri_view(const SerdEnv* env); + +#endif // SERD_ENV_H diff --git a/src/node.c b/src/node.c index 34ab3bc0..09ff2b95 100644 --- a/src/node.c +++ b/src/node.c @@ -42,6 +42,9 @@ static const size_t serd_node_align = sizeof(SerdNode); +static SerdNode* +serd_new_from_uri(const SerdURIView uri, const SerdURIView base); + static size_t serd_node_pad_size(const size_t n_bytes) { @@ -92,74 +95,94 @@ serd_node_set(SerdNode** dst, const SerdNode* src) } SerdNode* -serd_new_string(SerdNodeType type, const char* str) +serd_new_simple_node(SerdNodeType type, const SerdStringView str) { + if (type != SERD_BLANK && type != SERD_CURIE && type != SERD_URI) { + return NULL; + } + SerdNodeFlags flags = 0; - const size_t n_bytes = serd_strlen(str, &flags); + const size_t n_bytes = str.buf ? serd_strlen(str.buf, &flags) : 0; SerdNode* node = serd_node_malloc(n_bytes, flags, type); - memcpy(serd_node_buffer(node), str, n_bytes); + memcpy(serd_node_buffer(node), str.buf, n_bytes); node->n_bytes = n_bytes; - return node; } SerdNode* -serd_new_substring(SerdNodeType type, const char* str, const size_t len) +serd_new_string(const SerdStringView str) { SerdNodeFlags flags = 0; - const size_t n_bytes = serd_substrlen(str, len, &flags); - SerdNode* node = serd_node_malloc(n_bytes, flags, type); - memcpy(serd_node_buffer(node), str, n_bytes); + const size_t n_bytes = serd_substrlen(str.buf, str.len, &flags); + SerdNode* node = serd_node_malloc(n_bytes, flags, SERD_LITERAL); + + memcpy(serd_node_buffer(node), str.buf, str.len); node->n_bytes = n_bytes; + return node; } SerdNode* -serd_new_literal(const char* str, const char* datatype, const char* lang) +serd_new_literal(const SerdStringView str, + const SerdStringView datatype_uri, + const SerdStringView lang) { - if (!str || (lang && datatype && strcmp(datatype, NS_RDF "#langString"))) { + if (!str.len || (lang.len && datatype_uri.len && + strcmp(datatype_uri.buf, NS_RDF "langString"))) { return NULL; } SerdNodeFlags flags = 0; - const size_t n_bytes = serd_strlen(str, &flags); + const size_t n_bytes = serd_substrlen(str.buf, str.len, &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); + if (lang.len) { + const size_t total_len = len + sizeof(SerdNode) + lang.len; + + node = serd_node_malloc(total_len, flags | SERD_HAS_LANGUAGE, SERD_LITERAL); node->n_bytes = n_bytes; + memcpy(serd_node_buffer(node), str.buf, 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); + lang_node->n_bytes = lang.len; + memcpy(serd_node_buffer(lang_node), lang.buf, lang.len); + + } else if (datatype_uri.len) { + const size_t total_len = len + sizeof(SerdNode) + datatype_uri.len; + + node = serd_node_malloc(total_len, flags | SERD_HAS_DATATYPE, SERD_LITERAL); node->n_bytes = n_bytes; + memcpy(serd_node_buffer(node), str.buf, 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); + datatype_node->n_bytes = datatype_uri.len; + memcpy(serd_node_buffer(datatype_node), datatype_uri.buf, datatype_uri.len); + } else { node = serd_node_malloc(n_bytes, flags, SERD_LITERAL); - memcpy(serd_node_buffer(node), str, n_bytes); + memcpy(serd_node_buffer(node), str.buf, n_bytes); node->n_bytes = n_bytes; } return node; } +SerdNode* +serd_new_blank(const SerdStringView str) +{ + return serd_new_simple_node(SERD_BLANK, str); +} + +SerdNode* +serd_new_curie(const SerdStringView str) +{ + return serd_new_simple_node(SERD_CURIE, str); +} + SerdNode* serd_node_copy(const SerdNode* node) { @@ -217,13 +240,9 @@ string_sink(const void* buf, size_t len, void* stream) } SerdNode* -serd_new_uri(const char* str) +serd_new_uri(const SerdStringView str) { - const size_t n_bytes = strlen(str); - SerdNode* node = serd_node_malloc(n_bytes, 0, SERD_URI); - memcpy(serd_node_buffer(node), str, n_bytes); - node->n_bytes = n_bytes; - return node; + return serd_new_simple_node(SERD_URI, str); } SerdNode* @@ -311,50 +330,46 @@ is_uri_path_char(const char c) } SerdNode* -serd_new_file_uri(const char* path, const char* hostname, SerdURIView* out) +serd_new_file_uri(const SerdStringView path, const SerdStringView hostname) { - const size_t path_len = strlen(path); - const size_t hostname_len = hostname ? strlen(hostname) : 0; - const bool is_windows = is_windows_path(path); - size_t uri_len = 0; - char* uri = NULL; + const bool is_windows = is_windows_path(path.buf); + size_t uri_len = 0; + char* uri = NULL; - if (path[0] == '/' || is_windows) { - uri_len = strlen("file://") + hostname_len + is_windows; + if (path.buf[0] == '/' || is_windows) { + uri_len = strlen("file://") + hostname.len + is_windows; uri = (char*)calloc(uri_len + 1, 1); memcpy(uri, "file://", 7); - if (hostname) { - memcpy(uri + 7, hostname, hostname_len + 1); + if (hostname.len) { + memcpy(uri + 7, hostname.buf, hostname.len + 1); } if (is_windows) { - uri[7 + hostname_len] = '/'; + uri[7 + hostname.len] = '/'; } } SerdBuffer buffer = {uri, uri_len}; - for (size_t i = 0; i < path_len; ++i) { - if (is_windows && path[i] == '\\') { + for (size_t i = 0; i < path.len; ++i) { + if (is_windows && path.buf[i] == '\\') { serd_buffer_sink("/", 1, &buffer); - } else if (path[i] == '%') { + } else if (path.buf[i] == '%') { serd_buffer_sink("%%", 2, &buffer); - } else if (is_uri_path_char(path[i])) { - serd_buffer_sink(path + i, 1, &buffer); + } else if (is_uri_path_char(path.buf[i])) { + serd_buffer_sink(path.buf + i, 1, &buffer); } else { char escape_str[10] = {'%', 0, 0, 0, 0, 0, 0, 0, 0, 0}; - snprintf(escape_str + 1, sizeof(escape_str) - 1, "%X", (unsigned)path[i]); + snprintf( + escape_str + 1, sizeof(escape_str) - 1, "%X", (unsigned)path.buf[i]); serd_buffer_sink(escape_str, 3, &buffer); } } serd_buffer_sink_finish(&buffer); SerdNode* node = - serd_new_substring(SERD_URI, (const char*)buffer.buf, buffer.len); - if (out) { - *out = serd_parse_uri(serd_node_buffer(node)); - } + serd_new_uri(SERD_STRING_VIEW((const char*)buffer.buf, buffer.len - 1)); free(buffer.buf); return node; @@ -488,6 +503,12 @@ serd_node_length(const SerdNode* node) SerdStringView serd_node_string_view(const SerdNode* SERD_NONNULL node) { + static const SerdStringView empty_string_view = {"", 0}; + + if (!node) { + return empty_string_view; + } + const SerdStringView result = {(const char*)(node + 1), node->n_bytes}; return result; @@ -500,6 +521,15 @@ serd_node_uri_view(const SerdNode* SERD_NONNULL node) : SERD_URI_NULL; } +static const SerdNode* +serd_node_meta_node(const SerdNode* node) +{ + 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); + return node + 1 + (len / serd_node_align); +} + const SerdNode* serd_node_datatype(const SerdNode* node) { @@ -507,11 +537,7 @@ serd_node_datatype(const SerdNode* node) 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); + const SerdNode* const datatype = serd_node_meta_node(node); assert(datatype->type == SERD_URI || datatype->type == SERD_CURIE); return datatype; } @@ -523,11 +549,7 @@ serd_node_language(const SerdNode* node) 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); + const SerdNode* const lang = serd_node_meta_node(node); assert(lang->type == SERD_LITERAL); return lang; } diff --git a/src/serdi.c b/src/serdi.c index b391f549..f0cf8f4b 100644 --- a/src/serdi.c +++ b/src/serdi.c @@ -309,20 +309,18 @@ main(int argc, char** argv) const SerdWriterFlags writer_flags = choose_style(input_syntax, output_syntax, ascii, bulk_write, full_uris); - SerdURIView base_uri = SERD_URI_NULL; - SerdNode* base = NULL; + SerdNode* base = NULL; if (a < argc) { // Base URI given on command line - base_uri = serd_parse_uri(argv[a]); - base = serd_new_parsed_uri(base_uri); + base = serd_new_uri(SERD_MEASURE_STRING((const char*)argv[a])); } else if (from_file && in_fd != stdin) { // Use input file URI - base = serd_new_file_uri(input, NULL, &base_uri); + base = serd_new_file_uri(SERD_MEASURE_STRING(input), SERD_EMPTY_STRING()); } FILE* const out_fd = stdout; - SerdEnv* const env = serd_env_new(base); + SerdEnv* const env = serd_env_new(serd_node_string_view(base)); - SerdWriter* const writer = serd_writer_new( - output_syntax, writer_flags, env, &base_uri, serd_file_sink, out_fd); + SerdWriter* const writer = + serd_writer_new(output_syntax, writer_flags, env, serd_file_sink, out_fd); SerdReader* const reader = serd_reader_new(input_syntax, @@ -339,7 +337,7 @@ main(int argc, char** argv) serd_writer_set_error_sink(writer, quiet_error_sink, NULL); } - SerdNode* root = root_uri ? serd_new_string(SERD_URI, root_uri) : NULL; + SerdNode* root = serd_new_uri(SERD_MEASURE_STRING(root_uri)); serd_writer_set_root_uri(writer, root); serd_writer_chop_blank_prefix(writer, chop_prefix); serd_reader_add_blank_prefix(reader, add_prefix); diff --git a/src/writer.c b/src/writer.c index 5205c7d1..75734c0c 100644 --- a/src/writer.c +++ b/src/writer.c @@ -15,6 +15,7 @@ */ #include "byte_sink.h" +#include "env.h" #include "node.h" #include "serd_internal.h" #include "stack.h" @@ -96,7 +97,6 @@ struct SerdWriterImpl { SerdEnv* env; SerdNode* root_node; SerdURIView root_uri; - SerdURIView base_uri; SerdStack anon_stack; SerdByteSink byte_sink; SerdErrorSink error_sink; @@ -604,7 +604,7 @@ write_uri_node(SerdWriter* const writer, } if (!has_scheme && !supports_uriref(writer) && - !serd_env_base_uri(writer->env, NULL)) { + !serd_env_base_uri(writer->env)) { w_err(writer, SERD_ERR_BAD_ARG, "syntax does not support URI reference <%s>\n", @@ -613,22 +613,18 @@ write_uri_node(SerdWriter* const writer, } write_sep(writer, SEP_URI_BEGIN); - if (writer->flags & SERD_WRITE_RESOLVED) { - const SerdURIView uri = serd_parse_uri(node_str); - - SerdURIView in_base_uri; - serd_env_base_uri(writer->env, &in_base_uri); - - const SerdURIView abs_uri = serd_resolve_uri(uri, in_base_uri); - const bool rooted = uri_is_under(&in_base_uri, &writer->root_uri); - const SerdURIView* root = rooted ? &writer->root_uri : &in_base_uri; + if ((writer->flags & SERD_WRITE_RESOLVED) && serd_env_base_uri(writer->env)) { + const SerdURIView base_uri = serd_env_base_uri_view(writer->env); + SerdURIView uri = serd_parse_uri(node_str); + 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; if (writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS || - !uri_is_under(&abs_uri, root) || - !uri_is_related(&abs_uri, &in_base_uri)) { + !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, in_base_uri), uri_sink, writer); + serd_write_uri(serd_relative_uri(uri, base_uri), uri_sink, writer); } } else { write_uri_from_node(writer, node); @@ -957,12 +953,11 @@ serd_writer_finish(SerdWriter* writer) } SerdWriter* -serd_writer_new(SerdSyntax syntax, - SerdWriterFlags flags, - SerdEnv* env, - const SerdURIView* base_uri, - SerdSink ssink, - void* stream) +serd_writer_new(SerdSyntax syntax, + SerdWriterFlags flags, + SerdEnv* env, + SerdSink ssink, + void* stream) { const WriteContext context = WRITE_CONTEXT_NULL; SerdWriter* writer = (SerdWriter*)calloc(1, sizeof(SerdWriter)); @@ -972,7 +967,6 @@ serd_writer_new(SerdSyntax syntax, writer->env = env; writer->root_node = NULL; writer->root_uri = SERD_URI_NULL; - writer->base_uri = base_uri ? *base_uri : SERD_URI_NULL; writer->anon_stack = serd_stack_new(4 * sizeof(WriteContext)); writer->context = context; writer->list_subj = NULL; @@ -1010,9 +1004,11 @@ serd_writer_chop_blank_prefix(SerdWriter* writer, const char* prefix) SerdStatus serd_writer_set_base_uri(SerdWriter* writer, const SerdNode* uri) { - if (!serd_env_set_base_uri(writer->env, uri)) { - serd_env_base_uri(writer->env, &writer->base_uri); + if (uri->type != SERD_URI) { + return SERD_ERR_BAD_ARG; + } + if (!serd_env_set_base_uri(writer->env, serd_node_string_view(uri))) { if (writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG) { if (ctx(writer, FIELD_GRAPH) || ctx(writer, FIELD_SUBJECT)) { sink(" .\n\n", 4, writer); @@ -1034,7 +1030,7 @@ serd_writer_set_root_uri(SerdWriter* writer, const SerdNode* uri) serd_node_free(writer->root_node); if (uri) { writer->root_node = serd_node_copy(uri); - writer->root_uri = serd_parse_uri(serd_node_string(writer->root_node)); + writer->root_uri = serd_node_uri_view(writer->root_node); } else { writer->root_node = NULL; writer->root_uri = SERD_URI_NULL; @@ -1047,7 +1043,12 @@ serd_writer_set_prefix(SerdWriter* writer, const SerdNode* name, const SerdNode* uri) { - if (!serd_env_set_prefix(writer->env, name, uri)) { + if (name->type != SERD_LITERAL || uri->type != SERD_URI) { + return SERD_ERR_BAD_ARG; + } + + if (!serd_env_set_prefix( + writer->env, serd_node_string_view(name), serd_node_string_view(uri))) { if (writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG) { if (ctx(writer, FIELD_GRAPH) || ctx(writer, FIELD_SUBJECT)) { sink(" .\n\n", 4, writer); -- cgit v1.2.1