From 43e4cba8561d332cdc0fa9d257008dc68bb65a96 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 4 Feb 2018 18:35:41 +0100 Subject: Make nodes opaque --- serd/serd.h | 58 +++----- src/env.c | 77 +++++----- src/node.c | 172 +++++++++++++---------- src/reader.c | 22 ++- src/serd_internal.h | 12 +- src/serdi.c | 13 +- src/writer.c | 149 ++++++++++---------- tests/serd_test.c | 395 ++++++++++++++++++++++++++++------------------------ 8 files changed, 484 insertions(+), 414 deletions(-) diff --git a/serd/serd.h b/serd/serd.h index ce890403..eeb5a0c0 100644 --- a/serd/serd.h +++ b/serd/serd.h @@ -214,12 +214,7 @@ typedef uint32_t SerdNodeFlags; /** A syntactic RDF node. */ -typedef struct { - const char* buf; /**< Value string */ - size_t n_bytes; /**< Size in bytes (not including null) */ - SerdNodeFlags flags; /**< Node flags (e.g. string properties) */ - SerdType type; /**< Node type */ -} SerdNode; +typedef struct SerdNodeImpl SerdNode; /** An unterminated immutable slice of a string. @@ -462,34 +457,25 @@ serd_uri_serialise_relative(const SerdURI* uri, @{ */ -static const SerdNode SERD_NODE_NULL = { NULL, 0, 0, SERD_NOTHING }; - /** - Make a (shallow) node from `str`. - - This measures, but does not copy, `str`. No memory is allocated. + Create a new node from `str`. */ SERD_API -SerdNode -serd_node_from_string(SerdType type, const char* str); +SerdNode* +serd_node_new_string(SerdType type, const char* str); /** - Make a (shallow) node from a prefix of `str`. - - This measures, but does not copy, `str`. No memory is allocated. - Note that the returned node may not be null terminated. + Create a new node from a prefix of `str`. */ SERD_API -SerdNode -serd_node_from_substring(SerdType type, const char* str, size_t len); +SerdNode* +serd_node_new_substring(SerdType type, const char* str, size_t len); /** - Make a deep copy of `node`. - - @return a node that the caller must free with serd_node_free(). + Return a deep copy of `node`. */ SERD_API -SerdNode +SerdNode* serd_node_copy(const SerdNode* node); /** @@ -503,7 +489,7 @@ serd_node_equals(const SerdNode* a, const SerdNode* b); Simple wrapper for serd_node_new_uri() to resolve a URI node. */ SERD_API -SerdNode +SerdNode* serd_node_new_uri_from_node(const SerdNode* uri_node, const SerdURI* base, SerdURI* out); @@ -512,7 +498,7 @@ serd_node_new_uri_from_node(const SerdNode* uri_node, Simple wrapper for serd_node_new_uri() to resolve a URI string. */ SERD_API -SerdNode +SerdNode* serd_node_new_uri_from_string(const char* str, const SerdURI* base, SerdURI* out); @@ -528,7 +514,7 @@ serd_node_new_uri_from_string(const char* str, If `out` is not NULL, it will be set to the parsed URI. */ SERD_API -SerdNode +SerdNode* serd_node_new_file_uri(const char* path, const char* hostname, SerdURI* out, @@ -545,7 +531,7 @@ serd_node_new_file_uri(const char* path, memory owned by the new returned node). */ SERD_API -SerdNode +SerdNode* serd_node_new_uri(const SerdURI* uri, const SerdURI* base, SerdURI* out); /** @@ -561,7 +547,7 @@ serd_node_new_uri(const SerdURI* uri, const SerdURI* base, SerdURI* out); memory owned by the new returned node). */ SERD_API -SerdNode +SerdNode* serd_node_new_relative_uri(const SerdURI* uri, const SerdURI* base, const SerdURI* root, @@ -583,14 +569,14 @@ serd_node_new_relative_uri(const SerdURI* uri, @param frac_digits The maximum number of digits after the decimal place. */ SERD_API -SerdNode +SerdNode* serd_node_new_decimal(double d, unsigned frac_digits); /** Create a new node by serialising `i` into an xsd:integer string. */ SERD_API -SerdNode +SerdNode* serd_node_new_integer(int64_t i); /** @@ -603,7 +589,7 @@ serd_node_new_integer(int64_t i); @param wrap_lines Wrap lines at 76 characters to conform to RFC 2045. */ SERD_API -SerdNode +SerdNode* serd_node_new_blob(const void* buf, size_t size, bool wrap_lines); /** @@ -759,10 +745,10 @@ serd_env_set_prefix_from_strings(SerdEnv* env, */ SERD_API bool -serd_env_qualify(const SerdEnv* env, - const SerdNode* uri, - SerdNode* prefix, - SerdSlice* suffix); +serd_env_qualify(const SerdEnv* env, + const SerdNode* uri, + const SerdNode** prefix, + SerdSlice* suffix); /** Expand `curie`. @@ -783,7 +769,7 @@ serd_env_expand(const SerdEnv* env, Returns null if `node` can not be expanded. */ SERD_API -SerdNode +SerdNode* serd_env_expand_node(const SerdEnv* env, const SerdNode* node); diff --git a/src/env.c b/src/env.c index a2772ff5..27ee48be 100644 --- a/src/env.c +++ b/src/env.c @@ -20,14 +20,14 @@ #include typedef struct { - SerdNode name; - SerdNode uri; + SerdNode* name; + SerdNode* uri; } SerdPrefix; struct SerdEnvImpl { SerdPrefix* prefixes; size_t n_prefixes; - SerdNode base_uri_node; + SerdNode* base_uri_node; SerdURI base_uri; }; @@ -45,11 +45,11 @@ void serd_env_free(SerdEnv* env) { for (size_t i = 0; i < env->n_prefixes; ++i) { - serd_node_free(&env->prefixes[i].name); - serd_node_free(&env->prefixes[i].uri); + serd_node_free(env->prefixes[i].name); + serd_node_free(env->prefixes[i].uri); } free(env->prefixes); - serd_node_free(&env->base_uri_node); + serd_node_free(env->base_uri_node); free(env); } @@ -60,7 +60,7 @@ serd_env_get_base_uri(const SerdEnv* env, if (out) { *out = env->base_uri; } - return &env->base_uri_node; + return env->base_uri_node; } SerdStatus @@ -72,13 +72,13 @@ serd_env_set_base_uri(SerdEnv* env, } // Resolve base URI and create a new node and URI for it - SerdURI base_uri; - SerdNode base_uri_node = serd_node_new_uri_from_node( + SerdURI base_uri; + SerdNode* base_uri_node = serd_node_new_uri_from_node( uri, &env->base_uri, &base_uri); - if (base_uri_node.buf) { + if (base_uri_node) { // Replace the current base URI - serd_node_free(&env->base_uri_node); + serd_node_free(env->base_uri_node); env->base_uri_node = base_uri_node; env->base_uri = base_uri; return SERD_SUCCESS; @@ -92,7 +92,7 @@ serd_env_find(const SerdEnv* env, size_t name_len) { for (size_t i = 0; i < env->n_prefixes; ++i) { - const SerdNode* const prefix_name = &env->prefixes[i].name; + const SerdNode* const prefix_name = env->prefixes[i].name; if (prefix_name->n_bytes == name_len) { if (!memcmp(serd_node_get_string(prefix_name), name, name_len)) { return &env->prefixes[i]; @@ -110,9 +110,9 @@ serd_env_add(SerdEnv* env, const char* name_str = serd_node_get_string(name); SerdPrefix* const prefix = serd_env_find(env, name_str, name->n_bytes); if (prefix) { - SerdNode old_prefix_uri = prefix->uri; + SerdNode* old_prefix_uri = prefix->uri; prefix->uri = serd_node_copy(uri); - serd_node_free(&old_prefix_uri); + serd_node_free(old_prefix_uri); } else { env->prefixes = (SerdPrefix*)realloc( env->prefixes, (++env->n_prefixes) * sizeof(SerdPrefix)); @@ -126,20 +126,20 @@ serd_env_set_prefix(SerdEnv* env, const SerdNode* name, const SerdNode* uri) { - if (!name->buf || uri->type != SERD_URI) { + if (!name || uri->type != SERD_URI) { return SERD_ERR_BAD_ARG; } else if (serd_uri_string_has_scheme(serd_node_get_string(uri))) { // Set prefix to absolute URI serd_env_add(env, name, uri); } else { // Resolve relative URI and create a new node and URI for it - SerdURI abs_uri; - SerdNode abs_uri_node = serd_node_new_uri_from_node( + SerdURI abs_uri; + SerdNode* abs_uri_node = serd_node_new_uri_from_node( uri, &env->base_uri, &abs_uri); // Set prefix to resolved (absolute) URI - serd_env_add(env, name, &abs_uri_node); - serd_node_free(&abs_uri_node); + serd_env_add(env, name, abs_uri_node); + serd_node_free(abs_uri_node); } return SERD_SUCCESS; } @@ -149,20 +149,24 @@ serd_env_set_prefix_from_strings(SerdEnv* env, const char* name, const char* uri) { - const SerdNode name_node = serd_node_from_string(SERD_LITERAL, name); - const SerdNode uri_node = serd_node_from_string(SERD_URI, uri); + SerdNode* name_node = serd_node_new_string(SERD_LITERAL, name); + SerdNode* uri_node = serd_node_new_string(SERD_URI, uri); - return serd_env_set_prefix(env, &name_node, &uri_node); + 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, - SerdNode* prefix, - SerdSlice* suffix) +serd_env_qualify(const SerdEnv* env, + const SerdNode* uri, + const SerdNode** prefix, + SerdSlice* suffix) { for (size_t i = 0; i < env->n_prefixes; ++i) { - const SerdNode* const prefix_uri = &env->prefixes[i].uri; + const SerdNode* const prefix_uri = env->prefixes[i].uri; if (uri->n_bytes >= prefix_uri->n_bytes) { const char* prefix_str = serd_node_get_string(prefix_uri); const char* uri_str = serd_node_get_string(uri); @@ -193,8 +197,8 @@ serd_env_expand(const SerdEnv* env, const size_t name_len = colon - str; const SerdPrefix* const prefix = serd_env_find(env, str, name_len); if (prefix) { - uri_prefix->buf = serd_node_get_string(&prefix->uri); - uri_prefix->len = prefix->uri.n_bytes; + uri_prefix->buf = serd_node_get_string(prefix->uri); + uri_prefix->len = prefix->uri->n_bytes; uri_suffix->buf = colon + 1; uri_suffix->len = curie->n_bytes - (colon - str) - 1; return SERD_SUCCESS; @@ -202,7 +206,7 @@ serd_env_expand(const SerdEnv* env, return SERD_ERR_BAD_CURIE; } -SerdNode +SerdNode* serd_env_expand_node(const SerdEnv* env, const SerdNode* node) { @@ -211,12 +215,13 @@ serd_env_expand_node(const SerdEnv* env, SerdSlice prefix; SerdSlice suffix; if (serd_env_expand(env, node, &prefix, &suffix)) { - return SERD_NODE_NULL; + return NULL; } const size_t len = prefix.len + suffix.len; - char* buf = (char*)malloc(len + 1); - SerdNode ret = { buf, len, 0, SERD_URI }; - snprintf((char*)buf, ret.n_bytes + 1, "%s%s", prefix.buf, suffix.buf); + SerdNode* ret = serd_node_malloc(len, 0, SERD_URI); + char* buf = serd_node_buffer(ret); + snprintf(buf, len + 1, "%s%s", prefix.buf, suffix.buf); + ret->n_bytes = len; return ret; } case SERD_URI: { @@ -224,7 +229,7 @@ serd_env_expand_node(const SerdEnv* env, return serd_node_new_uri_from_node(node, &env->base_uri, &ignored); } default: - return SERD_NODE_NULL; + return NULL; } } @@ -234,6 +239,6 @@ serd_env_foreach(const SerdEnv* env, void* handle) { for (size_t i = 0; i < env->n_prefixes; ++i) { - func(handle, &env->prefixes[i].name, &env->prefixes[i].uri); + func(handle, env->prefixes[i].name, env->prefixes[i].uri); } } diff --git a/src/node.c b/src/node.c index 8b846aab..d32a0832 100644 --- a/src/node.c +++ b/src/node.c @@ -31,61 +31,87 @@ # endif #endif +SerdNode* +serd_node_malloc(size_t n_bytes, SerdNodeFlags flags, SerdType type) +{ + SerdNode* node = (SerdNode*)calloc(1, sizeof(SerdNode) + n_bytes + 1); + node->n_bytes = 0; + node->flags = flags; + node->type = type; + return node; +} + char* serd_node_buffer(SerdNode* node) { return (char*)(node + 1); } -SerdNode -serd_node_from_string(SerdType type, const char* str) +void +serd_node_set(SerdNode** dst, const SerdNode* src) +{ + if (src) { + if (!(*dst) || (*dst)->n_bytes < src->n_bytes) { + (*dst) = (SerdNode*)realloc(*dst, sizeof(SerdNode) + src->n_bytes + 1); + } + + memcpy(*dst, src, sizeof(SerdNode) + src->n_bytes + 1); + } else if (*dst) { + (*dst)->type = SERD_NOTHING; + } +} + +SerdNode* +serd_node_new_string(SerdType type, const char* str) { if (!str) { - return SERD_NODE_NULL; + return NULL; } - uint32_t flags = 0; - const size_t n_bytes = serd_strlen(str, &flags); - const SerdNode ret = { str, n_bytes, flags, type }; - return ret; + uint32_t flags = 0; + const size_t n_bytes = serd_strlen(str, &flags); + SerdNode* node = serd_node_malloc(n_bytes, flags, type); + memcpy(serd_node_buffer(node), str, n_bytes); + node->n_bytes = n_bytes; + return node; } -SerdNode -serd_node_from_substring(SerdType type, const char* str, const size_t len) +SerdNode* +serd_node_new_substring(SerdType type, const char* str, const size_t len) { if (!str) { - return SERD_NODE_NULL; + return NULL; } - uint32_t flags = 0; - const size_t n_bytes = serd_substrlen(str, len, &flags); - const SerdNode ret = { str, n_bytes, flags, type }; - return ret; + uint32_t 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); + node->n_bytes = n_bytes; + return node; } -SerdNode +SerdNode* serd_node_copy(const SerdNode* node) { - if (!node || !node->buf) { - return SERD_NODE_NULL; + if (!node) { + return NULL; } - SerdNode copy = *node; - char* buf = (char*)malloc(copy.n_bytes + 1); - memcpy(buf, node->buf, copy.n_bytes + 1); - copy.buf = buf; + const size_t size = sizeof(SerdNode) + node->n_bytes + 1; + SerdNode* copy = (SerdNode*)malloc(size); + memcpy(copy, node, size); return copy; } bool serd_node_equals(const SerdNode* a, const SerdNode* b) { - return (a == b) - || (a->type == b->type - && a->n_bytes == b->n_bytes - && ((a->buf == b->buf) || !memcmp((const char*)a->buf, - (const char*)b->buf, - a->n_bytes + 1))); + return (a == b) || + (a && b && a->type == b->type && a->n_bytes == b->n_bytes && + !memcmp(serd_node_get_string(a), + serd_node_get_string(b), + a->n_bytes)); } static size_t @@ -114,7 +140,7 @@ string_sink(const void* buf, size_t len, void* stream) return len; } -SerdNode +SerdNode* serd_node_new_uri_from_node(const SerdNode* uri_node, const SerdURI* base, SerdURI* out) @@ -122,17 +148,17 @@ serd_node_new_uri_from_node(const SerdNode* uri_node, const char* uri_str = serd_node_get_string(uri_node); return (uri_node->type == SERD_URI && uri_str) ? serd_node_new_uri_from_string(uri_str, base, out) - : SERD_NODE_NULL; + : NULL; } -SerdNode +SerdNode* serd_node_new_uri_from_string(const char* str, const SerdURI* base, SerdURI* out) { if (!str || str[0] == '\0') { // Empty URI => Base URI, or nothing if no base is given - return base ? serd_node_new_uri(base, NULL, out) : SERD_NODE_NULL; + return base ? serd_node_new_uri(base, NULL, out) : NULL; } SerdURI uri; @@ -159,7 +185,7 @@ is_uri_path_char(const char c) } } -SerdNode +SerdNode* serd_node_new_file_uri(const char* path, const char* hostname, SerdURI* out, @@ -194,15 +220,17 @@ serd_node_new_file_uri(const char* path, } serd_buffer_sink_finish(&buffer); + SerdNode* node = serd_node_new_substring( + SERD_URI, (const char*)buffer.buf, buffer.len); if (out) { - serd_uri_parse((const char*)buffer.buf, out); + serd_uri_parse(serd_node_buffer(node), out); } - return serd_node_from_substring( - SERD_URI, (const char*)buffer.buf, buffer.len); + free(buffer.buf); + return node; } -SerdNode +SerdNode* serd_node_new_uri(const SerdURI* uri, const SerdURI* base, SerdURI* out) { SerdURI abs_uri = *uri; @@ -211,22 +239,21 @@ serd_node_new_uri(const SerdURI* uri, const SerdURI* base, SerdURI* out) } const size_t len = serd_uri_string_length(&abs_uri); - char* buf = (char*)malloc(len + 1); - SerdNode node = { buf, len, 0, SERD_URI }; - char* ptr = buf; + SerdNode* node = serd_node_malloc(len, 0, SERD_URI); + char* ptr = serd_node_buffer(node); const size_t actual_len = serd_uri_serialise(&abs_uri, string_sink, &ptr); - buf[actual_len] = '\0'; - node.n_bytes = actual_len; + serd_node_buffer(node)[actual_len] = '\0'; + node->n_bytes = actual_len; if (out) { - serd_uri_parse(buf, out); // TODO: cleverly avoid double parse + serd_uri_parse(serd_node_buffer(node), out); // TODO: avoid double parse } return node; } -SerdNode +SerdNode* serd_node_new_relative_uri(const SerdURI* uri, const SerdURI* base, const SerdURI* root, @@ -234,17 +261,16 @@ serd_node_new_relative_uri(const SerdURI* uri, { const size_t uri_len = serd_uri_string_length(uri); const size_t base_len = serd_uri_string_length(base); - char* buf = (char*)malloc(uri_len + base_len + 1); - SerdNode node = { buf, 0, 0, SERD_URI }; - char* ptr = buf; + SerdNode* node = serd_node_malloc(uri_len + base_len, 0, SERD_URI); + char* ptr = serd_node_buffer(node); const size_t actual_len = serd_uri_serialise_relative( uri, base, root, string_sink, &ptr); - buf[actual_len] = '\0'; - node.n_bytes = actual_len; + serd_node_buffer(node)[actual_len] = '\0'; + node->n_bytes = actual_len; if (out) { - serd_uri_parse(buf, out); // TODO: cleverly avoid double parse + serd_uri_parse(serd_node_buffer(node), out); // TODO: avoid double parse } return node; @@ -257,18 +283,19 @@ serd_digits(double abs) return lg < 1.0 ? 1U : (unsigned)lg; } -SerdNode +SerdNode* serd_node_new_decimal(double d, unsigned frac_digits) { if (isnan(d) || isinf(d)) { - return SERD_NODE_NULL; + return NULL; } - const double abs_d = fabs(d); - const unsigned int_digits = serd_digits(abs_d); - char* buf = (char*)calloc(int_digits + frac_digits + 3, 1); - SerdNode node = { buf, 0, 0, SERD_LITERAL }; - const double int_part = floor(abs_d); + const double abs_d = fabs(d); + const unsigned int_digits = serd_digits(abs_d); + const size_t len = int_digits + frac_digits + 3; + SerdNode* const node = serd_node_malloc(len, 0, SERD_LITERAL); + char* const buf = serd_node_buffer(node); + const double int_part = floor(abs_d); // Point s to decimal point location char* s = buf + int_digits; @@ -284,13 +311,14 @@ serd_node_new_decimal(double d, unsigned frac_digits) *t-- = '0' + (dec % 10); } while ((dec /= 10) > 0); + *s++ = '.'; // Write fractional part (right to left) double frac_part = fabs(d - int_part); if (frac_part < DBL_EPSILON) { *s++ = '0'; - node.n_bytes = (s - buf); + node->n_bytes = (s - buf); } else { uint64_t frac = frac_part * pow(10.0, (int)frac_digits) + 0.5; s += frac_digits - 1; @@ -299,7 +327,7 @@ serd_node_new_decimal(double d, unsigned frac_digits) // Skip trailing zeros for (; i < frac_digits - 1 && !(frac % 10); ++i, --s, frac /= 10) {} - node.n_bytes = (s - buf) + 1; + node->n_bytes = (s - buf) + 1; // Write digits from last trailing zero to decimal point for (; i < frac_digits; ++i) { @@ -311,13 +339,13 @@ serd_node_new_decimal(double d, unsigned frac_digits) return node; } -SerdNode +SerdNode* serd_node_new_integer(int64_t i) { int64_t abs_i = (i < 0) ? -i : i; const unsigned digits = serd_digits(abs_i); - char* buf = (char*)calloc(digits + 2, 1); - SerdNode node = { (const char*)buf, 0, 0, SERD_LITERAL }; + SerdNode* node = serd_node_malloc(digits + 2, 0, SERD_LITERAL); + char* buf = serd_node_buffer(node); // Point s to the end char* s = buf + digits - 1; @@ -326,7 +354,7 @@ serd_node_new_integer(int64_t i) ++s; } - node.n_bytes = (s - buf) + 1; + node->n_bytes = (s - buf) + 1; // Write integer part (right to left) do { @@ -357,12 +385,16 @@ encode_chunk(uint8_t out[4], const uint8_t in[3], size_t n_in) out[3] = ((n_in > 2) ? b64_map[in[2] & 0x3F] : (uint8_t)'='); } -SerdNode +SerdNode* serd_node_new_blob(const void* buf, size_t size, bool wrap_lines) { + if (!buf || !size) { + return NULL; + } + const size_t len = (size + 2) / 3 * 4 + (wrap_lines * ((size - 1) / 57)); - uint8_t* str = (uint8_t*)calloc(len + 2, 1); - SerdNode node = { (const char*)str, len, 0, SERD_LITERAL }; + SerdNode* node = serd_node_malloc(len + 1, 0, SERD_LITERAL); + uint8_t* str = (uint8_t*)serd_node_buffer(node); for (size_t i = 0, j = 0; i < size; i += 3, j += 4) { uint8_t in[4] = { 0, 0, 0, 0 }; size_t n_in = MIN(3, size - i); @@ -370,11 +402,12 @@ serd_node_new_blob(const void* buf, size_t size, bool wrap_lines) if (wrap_lines && i > 0 && (i % 57) == 0) { str[j++] = '\n'; - node.flags |= SERD_HAS_NEWLINE; + node->flags |= SERD_HAS_NEWLINE; } encode_chunk(str + j, in, n_in); } + node->n_bytes = len; return node; } @@ -387,7 +420,7 @@ serd_node_get_type(const SerdNode* node) const char* serd_node_get_string(const SerdNode* node) { - return node ? node->buf : NULL; + return node ? (const char*)(node + 1) : NULL; } size_t @@ -405,8 +438,5 @@ serd_node_get_flags(const SerdNode* node) void serd_node_free(SerdNode* node) { - if (node && node->buf) { - free((char*)node->buf); - node->buf = NULL; - } + free(node); } diff --git a/src/reader.c b/src/reader.c index 89f3cca0..c5e47bc2 100644 --- a/src/reader.c +++ b/src/reader.c @@ -40,9 +40,9 @@ void set_blank_id(SerdReader* reader, Ref ref, size_t buf_size) { SerdNode* node = deref(reader, ref); + char* buf = (char*)(node + 1); const char* prefix = reader->bprefix ? (const char*)reader->bprefix : ""; - node->n_bytes = snprintf( - (char*)node->buf, buf_size, "%sb%u", prefix, reader->next_id++); + node->n_bytes = snprintf(buf, buf_size, "%sb%u", prefix, reader->next_id++); } size_t @@ -83,7 +83,6 @@ push_node_padded(SerdReader* reader, size_t maxlen, node->n_bytes = n_bytes; node->flags = 0; node->type = type; - node->buf = NULL; char* buf = (char*)(node + 1); memcpy(buf, str, n_bytes + 1); @@ -105,12 +104,7 @@ push_node(SerdReader* reader, SerdType type, const char* str, size_t n_bytes) SerdNode* deref(SerdReader* reader, const Ref ref) { - if (ref) { - SerdNode* node = (SerdNode*)(reader->stack.buf + ref); - node->buf = (char*)node + sizeof(SerdNode); - return node; - } - return NULL; + return ref ? (SerdNode*)(reader->stack.buf + ref) : NULL; } Ref @@ -133,8 +127,8 @@ bool emit_statement(SerdReader* reader, ReadContext ctx, Ref o, Ref d, Ref l) { SerdNode* graph = deref(reader, ctx.graph); - if (!graph && reader->default_graph.buf) { - graph = &reader->default_graph; + if (!graph && reader->default_graph) { + graph = reader->default_graph; } bool ret = !reader->statement_sink || !reader->statement_sink( @@ -178,7 +172,7 @@ serd_reader_new(SerdSyntax syntax, me->prefix_sink = prefix_sink; me->statement_sink = statement_sink; me->end_sink = end_sink; - me->default_graph = SERD_NODE_NULL; + me->default_graph = NULL; me->stack = serd_stack_new(SERD_PAGE_SIZE); me->syntax = syntax; me->next_id = 1; @@ -212,7 +206,7 @@ serd_reader_free(SerdReader* reader) pop_node(reader, reader->rdf_nil); pop_node(reader, reader->rdf_rest); pop_node(reader, reader->rdf_first); - serd_node_free(&reader->default_graph); + serd_node_free(reader->default_graph); #ifdef SERD_STACK_CHECK free(reader->allocs); @@ -249,7 +243,7 @@ void serd_reader_set_default_graph(SerdReader* reader, const SerdNode* graph) { - serd_node_free(&reader->default_graph); + serd_node_free(reader->default_graph); reader->default_graph = serd_node_copy(graph); } diff --git a/src/serd_internal.h b/src/serd_internal.h index ea46567f..fde325fd 100644 --- a/src/serd_internal.h +++ b/src/serd_internal.h @@ -44,6 +44,16 @@ static const uint8_t replacement_char[] = { 0xEF, 0xBF, 0xBD }; +struct SerdNodeImpl { + size_t n_bytes; /**< Size in bytes (not including null) */ + SerdNodeFlags flags; /**< Node flags (e.g. string properties) */ + SerdType type; /**< Node type */ +}; + +static const SerdNode SERD_NODE_NULL = { 0, 0, SERD_NOTHING }; + +SerdNode* serd_node_malloc(size_t n_bytes, SerdNodeFlags flags, SerdType type); +void serd_node_set(SerdNode** dst, const SerdNode* src); char* serd_node_buffer(SerdNode* node); /* File and Buffer Utilities */ @@ -573,7 +583,7 @@ struct SerdReaderImpl { Ref rdf_first; Ref rdf_rest; Ref rdf_nil; - SerdNode default_graph; + SerdNode* default_graph; SerdByteSource source; SerdStack stack; SerdSyntax syntax; diff --git a/src/serdi.c b/src/serdi.c index 419d3d06..571e2208 100644 --- a/src/serdi.c +++ b/src/serdi.c @@ -221,8 +221,8 @@ main(int argc, char** argv) : SERD_NQUADS); } - SerdURI base_uri = SERD_URI_NULL; - SerdNode base = SERD_NODE_NULL; + SerdURI base_uri = SERD_URI_NULL; + SerdNode* base = NULL; if (a < argc) { // Base URI given on command line base = serd_node_new_uri_from_string( (const char*)argv[a], NULL, &base_uri); @@ -231,7 +231,7 @@ main(int argc, char** argv) } FILE* out_fd = stdout; - SerdEnv* env = serd_env_new(&base); + SerdEnv* env = serd_env_new(base); int output_style = 0; if (output_syntax == SERD_NTRIPLES || ascii) { @@ -270,10 +270,11 @@ main(int argc, char** argv) serd_writer_set_error_sink(writer, quiet_error_sink, NULL); } - SerdNode root = serd_node_from_string(SERD_URI, root_uri); - serd_writer_set_root_uri(writer, &root); + SerdNode* root = serd_node_new_string(SERD_URI, 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); + serd_node_free(root); SerdStatus status = SERD_SUCCESS; if (!from_file) { @@ -292,7 +293,7 @@ main(int argc, char** argv) serd_writer_finish(writer); serd_writer_free(writer); serd_env_free(env); - serd_node_free(&base); + serd_node_free(base); if (from_file) { fclose(in_fd); diff --git a/src/writer.c b/src/writer.c index 44b331de..edba0872 100644 --- a/src/writer.c +++ b/src/writer.c @@ -22,16 +22,12 @@ #include typedef struct { - SerdNode graph; - SerdNode subject; - SerdNode predicate; + SerdNode* graph; + SerdNode* subject; + SerdNode* predicate; } WriteContext; -static const WriteContext WRITE_CONTEXT_NULL = { - { 0, 0, 0, SERD_NOTHING }, - { 0, 0, 0, SERD_NOTHING }, - { 0, 0, 0, SERD_NOTHING } -}; +static const WriteContext WRITE_CONTEXT_NULL = { NULL, NULL, NULL }; typedef enum { SEP_NONE, @@ -82,7 +78,7 @@ struct SerdWriterImpl { SerdSyntax syntax; SerdStyle style; SerdEnv* env; - SerdNode root_node; + SerdNode* root_node; SerdURI root_uri; SerdURI base_uri; SerdStack anon_stack; @@ -90,7 +86,7 @@ struct SerdWriterImpl { SerdErrorSink error_sink; void* error_handle; WriteContext context; - SerdNode list_subj; + SerdNode* list_subj; unsigned list_depth; unsigned indent; char* bprefix; @@ -142,18 +138,23 @@ anon_stack_top(SerdWriter* writer) + writer->anon_stack.size - sizeof(WriteContext)); } -static void -copy_node(SerdNode* dst, const SerdNode* src) -{ - if (src) { - dst->buf = (char*)realloc((char*)dst->buf, src->n_bytes + 1); - dst->n_bytes = src->n_bytes; - dst->flags = src->flags; - dst->type = src->type; - memcpy((char*)dst->buf, src->buf, src->n_bytes + 1); - } else { - dst->type = SERD_NOTHING; +static inline SerdNode* +ctx(SerdWriter* writer, const Field field) +{ + SerdNode* node = NULL; + switch (field) { + case FIELD_SUBJECT: + node = writer->context.subject; + break; + case FIELD_PREDICATE: + node = writer->context.predicate; + break; + case FIELD_GRAPH: + node = writer->context.graph; + default: break; } + + return node && node->type ? node : NULL; } static inline size_t @@ -394,22 +395,26 @@ write_sep(SerdWriter* writer, const Sep sep) static SerdStatus reset_context(SerdWriter* writer, bool graph) { - if (graph) { - writer->context.graph.type = SERD_NOTHING; + if (graph && writer->context.graph) { + writer->context.graph->type = SERD_NOTHING; + } + if (writer->context.subject) { + writer->context.subject->type = SERD_NOTHING; + } + if (writer->context.predicate) { + writer->context.predicate->type = SERD_NOTHING; } - writer->context.subject.type = SERD_NOTHING; - writer->context.predicate.type = SERD_NOTHING; - writer->empty = false; + writer->empty = false; return SERD_SUCCESS; } static SerdStatus free_context(SerdWriter* writer) { - serd_node_free(&writer->context.graph); - serd_node_free(&writer->context.subject); - serd_node_free(&writer->context.predicate); - return reset_context(writer, true); + serd_node_free(writer->context.graph); + serd_node_free(writer->context.subject); + serd_node_free(writer->context.predicate); + return SERD_SUCCESS; } static bool @@ -488,8 +493,8 @@ write_uri_node(SerdWriter* const writer, const Field field, const SerdStatementFlags flags) { - SerdNode prefix; - SerdSlice suffix; + const SerdNode* prefix; + SerdSlice suffix; if (is_inline_start(writer, field, flags)) { ++writer->indent; @@ -507,7 +512,7 @@ write_uri_node(SerdWriter* const writer, } else if (has_scheme && (writer->style & SERD_STYLE_CURIED) && serd_env_qualify(writer->env, node, &prefix, &suffix) && is_name(suffix.buf, suffix.len)) { - write_uri_from_node(writer, &prefix); + write_uri_from_node(writer, prefix); sink(":", 1, writer); write_uri(writer, suffix.buf, suffix.len); return true; @@ -592,7 +597,7 @@ write_blank(SerdWriter* const writer, return write_sep(writer, SEP_ANON_BEGIN); } else if (field == FIELD_SUBJECT && (flags & SERD_LIST_S_BEGIN)) { assert(writer->list_depth == 0); - copy_node(&writer->list_subj, node); + serd_node_set(&writer->list_subj, node); ++writer->list_depth; ++writer->indent; return write_sep(writer, SEP_LIST_BEGIN); @@ -657,7 +662,7 @@ write_pred(SerdWriter* writer, SerdStatementFlags flags, const SerdNode* pred) { write_node(writer, pred, NULL, NULL, FIELD_PREDICATE, flags); write_sep(writer, SEP_P_O); - copy_node(&writer->context.predicate, pred); + serd_node_set(&writer->context.predicate, pred); } static bool @@ -689,9 +694,8 @@ serd_writer_write_statement(SerdWriter* writer, const SerdNode* datatype, const SerdNode* lang) { - if (!subject || !predicate || !object - || !subject->buf || !predicate->buf || !object->buf - || !is_resource(subject) || !is_resource(predicate)) { + if (!subject || !predicate || !object || + !is_resource(subject) || !is_resource(predicate)) { return SERD_ERR_BAD_ARG; } @@ -718,13 +722,13 @@ serd_writer_write_statement(SerdWriter* writer, break; } - if ((graph && !serd_node_equals(graph, &writer->context.graph)) || - (!graph && writer->context.graph.type)) { + if ((graph && !serd_node_equals(graph, writer->context.graph)) || + (!graph && ctx(writer, FIELD_GRAPH))) { writer->indent = 0; - if (writer->context.subject.type) { + if (ctx(writer, FIELD_SUBJECT)) { write_sep(writer, SEP_END_S); } - if (writer->context.graph.type) { + if (ctx(writer, FIELD_GRAPH)) { write_sep(writer, SEP_GRAPH_END); } @@ -733,23 +737,23 @@ serd_writer_write_statement(SerdWriter* writer, TRY(write_node(writer, graph, datatype, lang, FIELD_GRAPH, flags)); ++writer->indent; write_sep(writer, SEP_GRAPH_BEGIN); - copy_node(&writer->context.graph, graph); + serd_node_set(&writer->context.graph, graph); } } if ((flags & SERD_LIST_CONT)) { if (write_list_obj(writer, flags, predicate, object, datatype, lang)) { // Reached end of list - if (--writer->list_depth == 0 && writer->list_subj.type) { + if (--writer->list_depth == 0 && writer->list_subj) { reset_context(writer, false); - serd_node_free(&writer->context.subject); + serd_node_free(writer->context.subject); writer->context.subject = writer->list_subj; - writer->list_subj = SERD_NODE_NULL; + writer->list_subj = NULL; } return SERD_SUCCESS; } - } else if (serd_node_equals(subject, &writer->context.subject)) { - if (serd_node_equals(predicate, &writer->context.predicate)) { + } 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; @@ -761,14 +765,14 @@ serd_writer_write_statement(SerdWriter* writer, } } else { // Abbreviate S - Sep sep = writer->context.predicate.type ? SEP_END_P : SEP_S_P; + Sep sep = ctx(writer, FIELD_PREDICATE) ? SEP_END_P : SEP_S_P; write_sep(writer, sep); write_pred(writer, flags, predicate); write_node(writer, object, datatype, lang, FIELD_OBJECT, flags); } } else { // No abbreviation - if (writer->context.subject.type) { + if (ctx(writer, FIELD_SUBJECT)) { assert(writer->indent > 0); --writer->indent; if (serd_stack_is_empty(&writer->anon_stack)) { @@ -787,7 +791,7 @@ serd_writer_write_statement(SerdWriter* writer, } reset_context(writer, false); - copy_node(&writer->context.subject, subject); + serd_node_set(&writer->context.subject, subject); if (!(flags & SERD_LIST_S_BEGIN)) { write_pred(writer, flags, predicate); @@ -801,15 +805,15 @@ serd_writer_write_statement(SerdWriter* writer, &writer->anon_stack, sizeof(WriteContext)); *ctx = writer->context; WriteContext new_context = { - serd_node_copy(graph), serd_node_copy(subject), SERD_NODE_NULL }; + serd_node_copy(graph), serd_node_copy(subject), NULL }; if ((flags & SERD_ANON_S_BEGIN)) { new_context.predicate = serd_node_copy(predicate); } writer->context = new_context; } else { - copy_node(&writer->context.graph, graph); - copy_node(&writer->context.subject, subject); - copy_node(&writer->context.predicate, predicate); + serd_node_set(&writer->context.graph, graph); + serd_node_set(&writer->context.subject, subject); + serd_node_set(&writer->context.predicate, predicate); } return SERD_SUCCESS; @@ -832,10 +836,10 @@ serd_writer_end_anon(SerdWriter* writer, free_context(writer); writer->context = *anon_stack_top(writer); serd_stack_pop(&writer->anon_stack, sizeof(WriteContext)); - const bool is_subject = serd_node_equals(node, &writer->context.subject); + const bool is_subject = serd_node_equals(node, writer->context.subject); if (is_subject) { - copy_node(&writer->context.subject, node); - writer->context.predicate.type = SERD_NOTHING; + serd_node_set(&writer->context.subject, node); + writer->context.predicate->type = SERD_NOTHING; } return SERD_SUCCESS; } @@ -843,15 +847,17 @@ serd_writer_end_anon(SerdWriter* writer, SerdStatus serd_writer_finish(SerdWriter* writer) { - if (writer->context.subject.type) { + if (ctx(writer, FIELD_SUBJECT)) { write_sep(writer, SEP_END_S); } - if (writer->context.graph.type) { + if (ctx(writer, FIELD_GRAPH)) { write_sep(writer, SEP_GRAPH_END); } serd_byte_sink_flush(&writer->byte_sink); - writer->indent = 0; - return free_context(writer); + free_context(writer); + writer->indent = 0; + writer->context = WRITE_CONTEXT_NULL; + return SERD_SUCCESS; } SerdWriter* @@ -867,12 +873,12 @@ serd_writer_new(SerdSyntax syntax, writer->syntax = syntax; writer->style = style; writer->env = env; - writer->root_node = SERD_NODE_NULL; + 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 = SERD_NODE_NULL; + writer->list_subj = NULL; writer->empty = true; writer->byte_sink = serd_byte_sink_new( ssink, stream, (style & SERD_STYLE_BULK) ? SERD_PAGE_SIZE : 1); @@ -910,7 +916,7 @@ serd_writer_set_base_uri(SerdWriter* writer, serd_env_get_base_uri(writer->env, &writer->base_uri); if (writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG) { - if (writer->context.graph.type || writer->context.subject.type) { + if (ctx(writer, FIELD_GRAPH) || ctx(writer, FIELD_SUBJECT)) { sink(" .\n\n", 4, writer); reset_context(writer, true); } @@ -928,12 +934,13 @@ SerdStatus serd_writer_set_root_uri(SerdWriter* writer, const SerdNode* uri) { - serd_node_free(&writer->root_node); - if (uri && uri->buf) { + serd_node_free(writer->root_node); + if (uri) { writer->root_node = serd_node_copy(uri); - serd_uri_parse(serd_node_get_string(uri), &writer->root_uri); + serd_uri_parse(serd_node_get_string(writer->root_node), + &writer->root_uri); } else { - writer->root_node = SERD_NODE_NULL; + writer->root_node = NULL; writer->root_uri = SERD_URI_NULL; } return SERD_SUCCESS; @@ -946,7 +953,7 @@ serd_writer_set_prefix(SerdWriter* writer, { if (!serd_env_set_prefix(writer->env, name, uri)) { if (writer->syntax == SERD_TURTLE || writer->syntax == SERD_TRIG) { - if (writer->context.graph.type || writer->context.subject.type) { + if (ctx(writer, FIELD_GRAPH) || ctx(writer, FIELD_SUBJECT)) { sink(" .\n\n", 4, writer); reset_context(writer, true); } @@ -969,7 +976,7 @@ serd_writer_free(SerdWriter* writer) serd_stack_free(&writer->anon_stack); free(writer->bprefix); serd_byte_sink_free(&writer->byte_sink); - serd_node_free(&writer->root_node); + serd_node_free(writer->root_node); free(writer); } diff --git a/tests/serd_test.c b/tests/serd_test.c index a8d17349..1e563006 100644 --- a/tests/serd_test.c +++ b/tests/serd_test.c @@ -92,24 +92,25 @@ check_file_uri(const char* hostname, expected_path = path; } - SerdNode node = serd_node_new_file_uri(path, hostname, 0, escape); - char* out_hostname = NULL; - char* out_path = serd_file_uri_parse(node.buf, &out_hostname); - int ret = 0; - if (strcmp((const char*)node.buf, expected_uri)) { - ret = FAILF("Bad URI %s != %s\n", node.buf, expected_uri); + SerdNode* node = serd_node_new_file_uri(path, hostname, 0, escape); + const char* node_str = serd_node_get_string(node); + char* out_hostname = NULL; + char* out_path = serd_file_uri_parse(node_str, &out_hostname); + int ret = 0; + if (strcmp(node_str, expected_uri)) { + ret = FAILF("Bad URI %s != %s\n", node_str, expected_uri); } else if (!hostname && out_hostname) { ret = FAILF("hostname `%s' shouldn't exist\n", out_hostname); } else if (hostname && !out_hostname) { ret = FAILF("expected hostname `%s'\n", hostname); } else if (strcmp((const char*)out_path, (const char*)expected_path)) { ret = FAILF("path=>URI=>path failure %s => %s => %s\n", - path, node.buf, out_path); + path, node_str, out_path); } serd_free(out_path); serd_free(out_hostname); - serd_node_free(&node); + serd_node_free(node); return ret; } @@ -155,20 +156,19 @@ main(void) }; for (unsigned i = 0; i < sizeof(dbl_test_nums) / sizeof(double); ++i) { - SerdNode node = serd_node_new_decimal(dbl_test_nums[i], 8); - const bool pass = (node.buf && dbl_test_strs[i]) - ? !strcmp(node.buf, dbl_test_strs[i]) - : (node.buf == dbl_test_strs[i]); + SerdNode* node = serd_node_new_decimal(dbl_test_nums[i], 8); + const char* node_str = serd_node_get_string(node); + const bool pass = (node_str && dbl_test_strs[i]) + ? !strcmp(node_str, dbl_test_strs[i]) + : (node_str == dbl_test_strs[i]); if (!pass) { - FAILF("Serialised `%s' != %s\n", - node.buf, dbl_test_strs[i]); + FAILF("Serialised `%s' != %s\n", node_str, dbl_test_strs[i]); } - const size_t len = node.buf ? strlen(node.buf) : 0; - if (node.n_bytes != len) { - FAILF("Length %zu != %zu\n", - node.n_bytes, len); + const size_t len = node_str ? strlen(node_str) : 0; + if (serd_node_get_length(node) != len) { + FAILF("Length %zu != %zu\n", serd_node_get_length(node), len); } - serd_node_free(&node); + serd_node_free(node); } // Test serd_node_new_integer @@ -182,37 +182,35 @@ main(void) }; for (unsigned i = 0; i < sizeof(int_test_nums) / sizeof(double); ++i) { - SerdNode node = serd_node_new_integer(int_test_nums[i]); - if (strcmp((const char*)node.buf, (const char*)int_test_strs[i])) { - FAILF("Serialised `%s' != %s\n", - node.buf, int_test_strs[i]); + SerdNode* node = serd_node_new_integer(int_test_nums[i]); + const char* node_str = serd_node_get_string(node); + if (strcmp(node_str, (const char*)int_test_strs[i])) { + FAILF("Serialised `%s' != %s\n", node_str, int_test_strs[i]); } - const size_t len = strlen(node.buf); - if (node.n_bytes != len) { - FAILF("Length %zu,%zu != %zu\n", - node.n_bytes, len); + const size_t len = strlen(node_str); + if (serd_node_get_length(node) != len) { + FAILF("Length %zu,%zu != %zu\n", serd_node_get_length(node), len); } - serd_node_free(&node); + serd_node_free(node); } // Test serd_node_new_blob - for (size_t size = 0; size < 256; ++size) { + for (size_t size = 1; size < 256; ++size) { uint8_t* data = (uint8_t*)malloc(size); for (size_t i = 0; i < size; ++i) { data[i] = (uint8_t)(rand() % 256); } - SerdNode blob = serd_node_new_blob(data, size, size % 5); + size_t out_size; + SerdNode* blob = serd_node_new_blob(data, size, size % 5); + const char* blob_str = serd_node_get_string(blob); + uint8_t* out = (uint8_t*)serd_base64_decode( + blob_str, serd_node_get_length(blob), &out_size); - if (blob.n_bytes != strlen((const char*)blob.buf)) { + if (serd_node_get_length(blob) != strlen(blob_str)) { FAILF("Blob %zu bytes != length %zu\n", - blob.n_bytes, strlen((const char*)blob.buf)); - } - - size_t out_size; - uint8_t* out = (uint8_t*)serd_base64_decode( - blob.buf, blob.n_bytes, &out_size); - if (out_size != size) { + serd_node_get_length(blob), strlen(blob_str)); + } else if (out_size != size) { FAILF("Blob size %zu != %zu\n", out_size, size); } @@ -222,7 +220,7 @@ main(void) } } - serd_node_free(&blob); + serd_node_free(blob); serd_free(out); free(data); } @@ -320,170 +318,193 @@ main(void) // Test serd_node_equals const uint8_t replacement_char_str[] = { 0xEF, 0xBF, 0xBD, 0 }; - SerdNode lhs = serd_node_from_string(SERD_LITERAL, (const char*)replacement_char_str); - SerdNode rhs = serd_node_from_string(SERD_LITERAL, "123"); - if (serd_node_equals(&lhs, &rhs)) { - FAILF("%s == %s\n", lhs.buf, rhs.buf); + SerdNode* lhs = serd_node_new_string(SERD_LITERAL, (const char*)replacement_char_str); + SerdNode* rhs = serd_node_new_string(SERD_LITERAL, "123"); + if (serd_node_equals(lhs, rhs)) { + FAILF("%s == %s\n", + serd_node_get_string(lhs), serd_node_get_string(rhs)); } - SerdNode qnode = serd_node_from_string(SERD_CURIE, "foo:bar"); - if (serd_node_equals(&lhs, &qnode)) { - FAILF("%s == %s\n", lhs.buf, qnode.buf); + SerdNode* qnode = serd_node_new_string(SERD_CURIE, "foo:bar"); + if (serd_node_equals(lhs, qnode)) { + FAILF("%s == %s\n", + serd_node_get_string(lhs), serd_node_get_string(qnode)); } + serd_node_free(qnode); - if (!serd_node_equals(&lhs, &lhs)) { - FAILF("%s != %s\n", lhs.buf, lhs.buf); + if (!serd_node_equals(lhs, lhs)) { + FAILF("%s != %s\n", + serd_node_get_string(lhs), serd_node_get_string(lhs)); } - SerdNode null_copy = serd_node_copy(&SERD_NODE_NULL); - if (!serd_node_equals(&SERD_NODE_NULL, &null_copy)) { - FAIL("copy of null node != null node\n"); + if (serd_node_copy(NULL)) { + FAIL("made non-null copy of null node\n"); } - // Test serd_node_from_string + serd_node_free(lhs); + serd_node_free(rhs); + + // Test serd_node_new_string - SerdNode node = serd_node_from_string(SERD_LITERAL, "hello\""); - if (node.n_bytes != 6 || node.flags != SERD_HAS_QUOTE - || strcmp((const char*)node.buf, "hello\"")) { - FAILF("Bad node %s %zu %d %d\n", - node.buf, node.n_bytes, node.flags, node.type); + SerdNode* hello = serd_node_new_string(SERD_LITERAL, "hello\""); + if (serd_node_get_length(hello) != 6 || + serd_node_get_flags(hello) != SERD_HAS_QUOTE || + strcmp(serd_node_get_string(hello), "hello\"")) { + FAILF("Bad node %s\n", serd_node_get_string(hello)); } - node = serd_node_from_string(SERD_URI, NULL); - if (!serd_node_equals(&node, &SERD_NODE_NULL)) { - FAIL("Creating node from NULL string failed\n"); + if (serd_node_new_string(SERD_URI, NULL)) { + FAIL("Successfully created node from NULL string\n"); } - // Test serd_node_from_substring + // Test serd_node_new_substring - SerdNode empty = serd_node_from_substring(SERD_LITERAL, NULL, 32); - if (empty.buf || empty.n_bytes || empty.flags || empty.type) { + if (serd_node_new_substring(SERD_LITERAL, NULL, 32)) { FAIL("Successfully created node from NULL substring\n"); } - SerdNode a_b = serd_node_from_substring(SERD_LITERAL, "a\"bc", 3); - if (a_b.n_bytes != 3 || a_b.flags != SERD_HAS_QUOTE - || strncmp((const char*)a_b.buf, "a\"b", 3)) { - FAILF("Bad node %s %zu %d %d\n", - a_b.buf, a_b.n_bytes, a_b.flags, a_b.type); + SerdNode* a_b = serd_node_new_substring(SERD_LITERAL, "a\"bc", 3); + if (serd_node_get_length(a_b) != 3 || + serd_node_get_flags(a_b) != SERD_HAS_QUOTE || + strncmp(serd_node_get_string(a_b), "a\"b", 3)) { + FAILF("Bad node %s\n", serd_node_get_string(a_b)); } - a_b = serd_node_from_substring(SERD_LITERAL, "a\"bc", 10); - if (a_b.n_bytes != 4 || a_b.flags != SERD_HAS_QUOTE - || strncmp((const char*)a_b.buf, "a\"bc", 4)) { - FAILF("Bad node %s %zu %zu %d %d\n", - a_b.buf, a_b.n_bytes, a_b.flags, a_b.type); + serd_node_free(a_b); + a_b = serd_node_new_substring(SERD_LITERAL, "a\"bc", 10); + if (serd_node_get_length(a_b) != 4 || + serd_node_get_flags(a_b) != SERD_HAS_QUOTE || + strncmp(serd_node_get_string(a_b), "a\"bc", 4)) { + FAILF("Bad node %s\n", serd_node_get_string(a_b)); } + serd_node_free(a_b); // Test serd_node_new_uri_from_string - SerdNode nonsense = serd_node_new_uri_from_string(NULL, NULL, NULL); - if (nonsense.type != SERD_NOTHING) { + if (serd_node_new_uri_from_string(NULL, NULL, NULL)) { FAIL("Successfully created NULL URI\n"); } SerdURI base_uri; - SerdNode base = serd_node_new_uri_from_string("http://example.org/", + SerdNode* base = serd_node_new_uri_from_string("http://example.org/", NULL, &base_uri); - SerdNode nil = serd_node_new_uri_from_string(NULL, &base_uri, NULL); - SerdNode nil2 = serd_node_new_uri_from_string("", &base_uri, NULL); - if (nil.type != SERD_URI || strcmp((const char*)nil.buf, (const char*)base.buf) || - nil2.type != SERD_URI || strcmp((const char*)nil2.buf, (const char*)base.buf)) { - FAILF("URI %s != base %s\n", nil.buf, base.buf); + SerdNode* nil = serd_node_new_uri_from_string(NULL, &base_uri, NULL); + SerdNode* nil2 = serd_node_new_uri_from_string("", &base_uri, NULL); + if (serd_node_get_type(nil) != SERD_URI || + strcmp(serd_node_get_string(nil), serd_node_get_string(base)) || + serd_node_get_type(nil2) != SERD_URI || + strcmp(serd_node_get_string(nil2), serd_node_get_string(base))) { + FAILF("URI %s != base %s\n", + serd_node_get_string(nil), + serd_node_get_string(base)); } - serd_node_free(&nil); - serd_node_free(&nil2); // Test serd_node_new_relative_uri - SerdNode abs = serd_node_from_string(SERD_URI, "http://example.org/foo/bar"); - SerdURI abs_uri; - serd_uri_parse(abs.buf, &abs_uri); + SerdNode* abs = serd_node_new_string(SERD_URI, "http://example.org/foo/bar"); + SerdURI abs_uri; + serd_uri_parse(serd_node_get_string(abs), &abs_uri); - SerdURI rel_uri; - SerdNode rel = serd_node_new_relative_uri(&abs_uri, &base_uri, NULL, &rel_uri); - if (strcmp((const char*)rel.buf, "/foo/bar")) { - FAILF("Bad relative URI %s (expected '/foo/bar')\n", rel.buf); + SerdURI rel_uri; + SerdNode* rel = serd_node_new_relative_uri(&abs_uri, &base_uri, NULL, &rel_uri); + if (strcmp(serd_node_get_string(rel), "/foo/bar")) { + FAILF("Bad relative URI %s (expected '/foo/bar')\n", + serd_node_get_string(rel)); } - SerdNode up = serd_node_new_relative_uri(&base_uri, &abs_uri, NULL, NULL); - if (strcmp((const char*)up.buf, "../")) { - FAILF("Bad relative URI %s (expected '../')\n", up.buf); + SerdNode* up = serd_node_new_relative_uri(&base_uri, &abs_uri, NULL, NULL); + if (strcmp(serd_node_get_string(up), "../")) { + FAILF("Bad relative URI %s (expected '../')\n", + serd_node_get_string(up)); } - SerdNode noup = serd_node_new_relative_uri(&base_uri, &abs_uri, &abs_uri, NULL); - if (strcmp((const char*)noup.buf, "http://example.org/")) { - FAILF("Bad relative URI %s (expected 'http://example.org/')\n", noup.buf); + SerdNode* noup = serd_node_new_relative_uri(&base_uri, &abs_uri, &abs_uri, NULL); + if (strcmp(serd_node_get_string(noup), "http://example.org/")) { + FAILF("Bad relative URI %s (expected 'http://example.org/')\n", + serd_node_get_string(noup)); } - SerdNode x = serd_node_from_string(SERD_URI, "http://example.org/foo/x"); - SerdURI x_uri; - serd_uri_parse(x.buf, &x_uri); + SerdNode* x = serd_node_new_string(SERD_URI, "http://example.org/foo/x"); + SerdURI x_uri; + serd_uri_parse(serd_node_get_string(x), &x_uri); - SerdNode x_rel = serd_node_new_relative_uri(&x_uri, &abs_uri, &abs_uri, NULL); - if (strcmp((const char*)x_rel.buf, "x")) { - FAILF("Bad relative URI %s (expected 'x')\n", x_rel.buf); + SerdNode* x_rel = + serd_node_new_relative_uri(&x_uri, &abs_uri, &abs_uri, NULL); + if (strcmp(serd_node_get_string(x_rel), "x")) { + FAILF("Bad relative URI %s (expected 'x')\n", + serd_node_get_string(x_rel)); } - serd_node_free(&x_rel); - serd_node_free(&noup); - serd_node_free(&up); - serd_node_free(&rel); - serd_node_free(&base); + serd_node_free(x_rel); + serd_node_free(noup); + serd_node_free(up); + serd_node_free(abs); + serd_node_free(nil); + serd_node_free(nil2); + serd_node_free(rel); + serd_node_free(base); // Test SerdEnv - SerdNode u = serd_node_from_string(SERD_URI, "http://example.org/foo"); - SerdNode b = serd_node_from_string(SERD_CURIE, "invalid"); - SerdNode c = serd_node_from_string(SERD_CURIE, "eg.2:b"); - SerdEnv* env = serd_env_new(NULL); + SerdNode* u = serd_node_new_string(SERD_URI, "http://example.org/foo"); + SerdNode* b = serd_node_new_string(SERD_CURIE, "invalid"); + SerdNode* c = serd_node_new_string(SERD_CURIE, "eg.2:b"); + SerdEnv* env = serd_env_new(NULL); serd_env_set_prefix_from_strings(env, "eg.2", "http://example.org/"); + if (serd_env_get_base_uri(env, NULL)) { + FAIL("Unexpected initial base URI\n"); + } + if (!serd_env_set_base_uri(env, NULL)) { FAIL("Successfully set NULL base URI\n"); } - if (!serd_env_set_base_uri(env, &node)) { - FAILF("Set base URI to %s\n", node.buf); + if (!serd_env_set_base_uri(env, hello)) { + FAILF("Set base URI to %s\n", serd_node_get_string(hello)); } - if (!serd_node_equals(serd_env_get_base_uri(env, NULL), &node)) { - FAIL("Base URI mismatch\n"); + if (serd_env_get_base_uri(env, NULL)) { + FAIL("Unexpected base URI\n"); } SerdSlice prefix, suffix; - if (!serd_env_expand(env, &b, &prefix, &suffix)) { - FAILF("Expanded invalid curie %s\n", b.buf); + if (!serd_env_expand(env, b, &prefix, &suffix)) { + FAILF("Expanded invalid curie %s\n", serd_node_get_string(b)); } - SerdNode xnode = serd_env_expand_node(env, &node); - if (!serd_node_equals(&xnode, &SERD_NODE_NULL)) { - FAILF("Expanded %s to %s\n", c.buf, xnode.buf); + SerdNode* xnode = serd_env_expand_node(env, hello); + if (xnode) { + FAILF("Expanded %s\n", serd_node_get_string(c)); } + serd_node_free(hello); - SerdNode xu = serd_env_expand_node(env, &u); - if (strcmp((const char*)xu.buf, "http://example.org/foo")) { - FAILF("Expanded %s to %s\n", c.buf, xu.buf); + SerdNode* xu = serd_env_expand_node(env, u); + if (strcmp(serd_node_get_string(xu), "http://example.org/foo")) { + FAILF("Expanded %s to %s\n", + serd_node_get_string(c), serd_node_get_string(xu)); } - serd_node_free(&xu); + serd_node_free(xu); - SerdNode badpre = serd_node_from_string(SERD_CURIE, "hm:what"); - SerdNode xbadpre = serd_env_expand_node(env, &badpre); - if (!serd_node_equals(&xbadpre, &SERD_NODE_NULL)) { - FAILF("Expanded invalid curie %s\n", badpre.buf); + SerdNode* badpre = serd_node_new_string(SERD_CURIE, "hm:what"); + SerdNode* xbadpre = serd_env_expand_node(env, badpre); + if (xbadpre) { + FAILF("Expanded invalid curie %s\n", serd_node_get_string(badpre)); } + serd_node_free(badpre); - SerdNode xc = serd_env_expand_node(env, &c); - if (strcmp((const char*)xc.buf, "http://example.org/b")) { - FAILF("Expanded %s to %s\n", c.buf, xc.buf); + SerdNode* xc = serd_env_expand_node(env, c); + if (strcmp(serd_node_get_string(xc), "http://example.org/b")) { + FAILF("Expanded %s to %s\n", + serd_node_get_string(c), serd_node_get_string(xc)); } - serd_node_free(&xc); + serd_node_free(xc); - if (!serd_env_set_prefix(env, &SERD_NODE_NULL, &SERD_NODE_NULL)) { + if (!serd_env_set_prefix(env, NULL, NULL)) { FAIL("Set NULL prefix\n"); } - const SerdNode lit = serd_node_from_string(SERD_LITERAL, "hello"); - if (!serd_env_set_prefix(env, &b, &lit)) { + SerdNode* lit = serd_node_new_string(SERD_LITERAL, "hello"); + if (!serd_env_set_prefix(env, b, lit)) { FAIL("Set prefix to literal\n"); } @@ -494,11 +515,15 @@ main(void) FAILF("Bad prefix count %d\n", n_prefixes); } - SerdNode shorter_uri = serd_node_from_string(SERD_URI, "urn:foo"); - SerdNode prefix_name; - if (serd_env_qualify(env, &shorter_uri, &prefix_name, &suffix)) { - FAILF("Qualified %s\n", shorter_uri.buf); + SerdNode* shorter_uri = serd_node_new_string(SERD_URI, "urn:foo"); + const SerdNode* prefix_name; + if (serd_env_qualify(env, shorter_uri, &prefix_name, &suffix)) { + FAILF("Qualified %s\n", serd_node_get_string(shorter_uri)); } + serd_node_free(shorter_uri); + serd_node_free(u); + serd_node_free(b); + serd_node_free(c); // Test SerdReader and SerdWriter @@ -517,10 +542,11 @@ main(void) serd_writer_chop_blank_prefix(writer, "tmp"); serd_writer_chop_blank_prefix(writer, NULL); - if (!serd_writer_set_base_uri(writer, &lit)) { - FAILF("Set base URI to %s\n", lit.buf); - } else if (!serd_writer_set_prefix(writer, &lit, &lit)) { - FAILF("Set prefix %s to %s\n", lit.buf, lit.buf); + if (!serd_writer_set_base_uri(writer, lit)) { + FAILF("Set base URI to %s\n", serd_node_get_string(lit)); + } else if (!serd_writer_set_prefix(writer, lit, lit)) { + FAILF("Set prefix %s to %s\n", + serd_node_get_string(lit), serd_node_get_string(lit)); } else if (!serd_writer_end_anon(writer, NULL)) { FAIL("Ended non-existent anonymous node\n"); } else if (serd_writer_get_env(writer) != env) { @@ -528,20 +554,20 @@ main(void) } uint8_t buf[] = { 0xEF, 0xBF, 0xBD, 0 }; - SerdNode s = serd_node_from_string(SERD_URI, ""); - SerdNode p = serd_node_from_string(SERD_URI, "http://example.org/pred"); - SerdNode o = serd_node_from_string(SERD_LITERAL, (char*)buf); + SerdNode* s = serd_node_new_string(SERD_URI, ""); + SerdNode* p = serd_node_new_string(SERD_URI, "http://example.org/pred"); + SerdNode* o = serd_node_new_string(SERD_LITERAL, (char*)buf); // Write 3 invalid statements (should write nothing) - const SerdNode* junk[][5] = { { &s, &p, NULL, NULL, NULL }, - { &s, NULL, &o, NULL, NULL }, - { NULL, &p, &o, NULL, NULL }, - { &s, &p, &SERD_NODE_NULL, NULL, NULL }, - { &s, &SERD_NODE_NULL, &o, NULL, NULL }, - { &SERD_NODE_NULL, &p, &o, NULL, NULL }, - { &s, &o, &o, NULL, NULL }, - { &o, &p, &o, NULL, NULL }, - { &s, &p, &SERD_NODE_NULL, NULL, NULL }, + const SerdNode* junk[][5] = { { s, p, NULL, NULL, NULL }, + { s, NULL, o, NULL, NULL }, + { NULL, p, o, NULL, NULL }, + { s, p, NULL, NULL, NULL }, + { s, NULL, o, NULL, NULL }, + { NULL, p, o, NULL, NULL }, + { s, o, o, NULL, NULL }, + { o, p, o, NULL, NULL }, + { s, p, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL, NULL } }; for (unsigned i = 0; i < sizeof(junk) / (sizeof(SerdNode*) * 5); ++i) { if (!serd_writer_write_statement( @@ -551,18 +577,18 @@ main(void) } } - const SerdNode t = serd_node_from_string(SERD_URI, "urn:Type"); - const SerdNode l = serd_node_from_string(SERD_LITERAL, "en"); - const SerdNode* good[][5] = { { &s, &p, &o, NULL, NULL }, - { &s, &p, &o, &SERD_NODE_NULL, &SERD_NODE_NULL }, - { &s, &p, &o, &t, NULL }, - { &s, &p, &o, NULL, &l }, - { &s, &p, &o, &t, &l }, - { &s, &p, &o, &t, &SERD_NODE_NULL }, - { &s, &p, &o, &SERD_NODE_NULL, &l }, - { &s, &p, &o, NULL, &SERD_NODE_NULL }, - { &s, &p, &o, &SERD_NODE_NULL, NULL }, - { &s, &p, &o, &SERD_NODE_NULL, NULL } }; + SerdNode* t = serd_node_new_string(SERD_URI, "urn:Type"); + SerdNode* l = serd_node_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 (unsigned i = 0; i < sizeof(good) / (sizeof(SerdNode*) * 5); ++i) { if (serd_writer_write_statement( writer, 0, NULL, @@ -573,35 +599,45 @@ main(void) // Write statements with bad UTF-8 (should be replaced) const char bad_str[] = { (char)0xFF, (char)0x90, 'h', 'i', 0 }; - SerdNode bad_lit = serd_node_from_string(SERD_LITERAL, bad_str); - SerdNode bad_uri = serd_node_from_string(SERD_URI, bad_str); + SerdNode* bad_lit = serd_node_new_string(SERD_LITERAL, bad_str); + SerdNode* bad_uri = serd_node_new_string(SERD_URI, bad_str); if (serd_writer_write_statement(writer, 0, NULL, - &s, &p, &bad_lit, NULL, NULL)) { + s, p, bad_lit, NULL, NULL)) { FAIL("Failed to write junk UTF-8 literal\n"); } else if (serd_writer_write_statement(writer, 0, NULL, - &s, &p, &bad_uri, NULL, NULL)) { + s, p, bad_uri, NULL, NULL)) { FAIL("Failed to write junk UTF-8 URI\n"); } + serd_node_free(bad_uri); + serd_node_free(bad_lit); // Write 1 valid statement - o = serd_node_from_string(SERD_LITERAL, "hello"); + serd_node_free(o); + o = serd_node_new_string(SERD_LITERAL, "hello"); if (serd_writer_write_statement(writer, 0, NULL, - &s, &p, &o, NULL, NULL)) { + s, p, o, NULL, NULL)) { FAIL("Failed to write valid statement\n"); } serd_writer_free(writer); + serd_node_free(lit); + serd_node_free(s); + serd_node_free(p); + serd_node_free(o); + serd_node_free(t); + serd_node_free(l); // Test buffer sink SerdBuffer buffer = { NULL, 0 }; writer = serd_writer_new( SERD_TURTLE, (SerdStyle)0, env, NULL, serd_buffer_sink, &buffer); - o = serd_node_from_string(SERD_URI, "http://example.org/base"); - if (serd_writer_set_base_uri(writer, &o)) { + o = serd_node_new_string(SERD_URI, "http://example.org/base"); + if (serd_writer_set_base_uri(writer, o)) { FAIL("Failed to write to chunk sink\n"); } + serd_node_free(o); serd_writer_free(writer); char* out = serd_buffer_sink_finish(&buffer); @@ -625,10 +661,11 @@ main(void) FAIL("Corrupt reader handle\n"); } - SerdNode g = serd_node_from_string(SERD_URI, "http://example.org/"); - serd_reader_set_default_graph(reader, &g); + SerdNode* g = serd_node_new_string(SERD_URI, "http://example.org/"); + serd_reader_set_default_graph(reader, g); serd_reader_add_blank_prefix(reader, "tmp"); serd_reader_add_blank_prefix(reader, NULL); + serd_node_free(g); if (!serd_reader_read_file(reader, "http://notafile")) { FAIL("Apparently read an http URI\n"); @@ -643,8 +680,8 @@ main(void) FAILF("Error reading file (%s)\n", serd_strerror(st)); } else if (rt->n_statements != 13) { FAILF("Bad statement count %d\n", rt->n_statements); - } else if (!rt->graph || !rt->graph->buf || - strcmp((const char*)rt->graph->buf, "http://example.org/")) { + } else if (!rt->graph || !serd_node_get_string(rt->graph) || + strcmp(serd_node_get_string(rt->graph), "http://example.org/")) { FAILF("Bad graph %p\n", rt->graph); } -- cgit v1.2.1