From 37251f892794e7accbabbe8a2816ad71191e2174 Mon Sep 17 00:00:00 2001
From: David Robillard <d@drobilla.net>
Date: Wed, 13 Jun 2018 21:32:11 -0400
Subject: Simplify SerdEnv API

---
 serd/serd.h       | 30 +++++----------------
 src/env.c         | 78 ++++++++++++++++++++++++++++++++++++-------------------
 src/env.h         | 28 ++++++++++++++++++--
 src/writer.c      | 11 +++++---
 tests/serd_test.c | 45 ++++++++++++++++++--------------
 5 files changed, 115 insertions(+), 77 deletions(-)

diff --git a/serd/serd.h b/serd/serd.h
index 9e1c651e..14a82389 100644
--- a/serd/serd.h
+++ b/serd/serd.h
@@ -881,17 +881,14 @@ serd_env_get_base_uri(const SerdEnv* env);
 */
 SERD_API
 SerdStatus
-serd_env_set_base_uri(SerdEnv*        env,
-                      const SerdNode* uri);
+serd_env_set_base_uri(SerdEnv* env, const SerdNode* uri);
 
 /**
    Set a namespace prefix.
 */
 SERD_API
 SerdStatus
-serd_env_set_prefix(SerdEnv*        env,
-                    const SerdNode* name,
-                    const SerdNode* uri);
+serd_env_set_prefix(SerdEnv* env, const SerdNode* name, const SerdNode* uri);
 
 /**
    Set a namespace prefix.
@@ -904,26 +901,12 @@ serd_env_set_prefix_from_strings(SerdEnv*    env,
 
 /**
    Qualify `uri` into a CURIE if possible.
-*/
-SERD_API
-bool
-serd_env_qualify(const SerdEnv*   env,
-                 const SerdNode*  uri,
-                 const SerdNode** prefix,
-                 SerdStringView*  suffix);
 
-/**
-   Expand `curie`.
-
-   Errors: SERD_ERR_BAD_ARG if `curie` is not valid, or SERD_ERR_BAD_CURIE if
-   prefix is not defined in `env`.
+   Returns null if `node` can not be qualified.
 */
 SERD_API
-SerdStatus
-serd_env_expand(const SerdEnv*  env,
-                const SerdNode* curie,
-                SerdStringView* uri_prefix,
-                SerdStringView* uri_suffix);
+SerdNode*
+serd_env_qualify(const SerdEnv* env, const SerdNode* uri);
 
 /**
    Expand `node`, which must be a CURIE or URI, to a full URI.
@@ -932,8 +915,7 @@ serd_env_expand(const SerdEnv*  env,
 */
 SERD_API
 SerdNode*
-serd_env_expand_node(const SerdEnv*  env,
-                     const SerdNode* node);
+serd_env_expand(const SerdEnv* env, const SerdNode* node);
 
 /**
    Call `func` for each prefix defined in `env`.
diff --git a/src/env.c b/src/env.c
index 7fa43aad..6714186e 100644
--- a/src/env.c
+++ b/src/env.c
@@ -155,26 +155,11 @@ serd_env_set_prefix(SerdEnv*        env,
 	return SERD_SUCCESS;
 }
 
-SerdStatus
-serd_env_set_prefix_from_strings(SerdEnv*    env,
-                                 const char* name,
-                                 const char* uri)
-{
-	SerdNode* name_node = serd_new_string(name);
-	SerdNode* uri_node  = serd_new_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,
-                 const SerdNode** prefix,
-                 SerdStringView*  suffix)
+serd_env_qualify_in_place(const SerdEnv*   env,
+                          const SerdNode*  uri,
+                          const SerdNode** prefix,
+                          SerdStringView*  suffix)
 {
 	for (size_t i = 0; i < env->n_prefixes; ++i) {
 		const SerdNode* const prefix_uri = env->prefixes[i].uri;
@@ -194,10 +179,46 @@ serd_env_qualify(const SerdEnv*   env,
 }
 
 SerdStatus
-serd_env_expand(const SerdEnv*  env,
-                const SerdNode* curie,
-                SerdStringView* uri_prefix,
-                SerdStringView* uri_suffix)
+serd_env_set_prefix_from_strings(SerdEnv*    env,
+                                 const char* name,
+                                 const char* uri)
+{
+	SerdNode* name_node = serd_new_string(name);
+	SerdNode* uri_node  = serd_new_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;
+}
+
+SerdNode*
+serd_env_qualify(const SerdEnv* env, const SerdNode* uri)
+{
+	const SerdNode* prefix = NULL;
+	SerdStringView  suffix = {NULL, 0};
+	if (serd_env_qualify_in_place(env, uri, &prefix, &suffix)) {
+		const size_t prefix_len = serd_node_get_length(prefix);
+		const size_t n_bytes    = prefix_len + 1 + suffix.len;
+		SerdNode*    node       = serd_node_malloc(n_bytes, 0, SERD_CURIE);
+		memcpy(serd_node_buffer(node),
+		       serd_node_get_string(prefix),
+		       prefix_len);
+		serd_node_buffer(node)[prefix_len] = ':';
+		memcpy(serd_node_buffer(node) + 1 + prefix_len, suffix.buf, suffix.len);
+		node->n_bytes = n_bytes;
+		return node;
+	}
+
+	return NULL;
+}
+
+SerdStatus
+serd_env_expand_in_place(const SerdEnv*  env,
+                         const SerdNode* curie,
+                         SerdStringView* uri_prefix,
+                         SerdStringView* uri_suffix)
 {
 	const char* const str   = serd_node_get_string(curie);
 	const char* const colon = (const char*)memchr(str, ':', curie->n_bytes + 1);
@@ -218,14 +239,17 @@ serd_env_expand(const SerdEnv*  env,
 }
 
 SerdNode*
-serd_env_expand_node(const SerdEnv*  env,
-                     const SerdNode* node)
+serd_env_expand(const SerdEnv* env, const SerdNode* node)
 {
+	if (!node) {
+		return NULL;
+	}
+
 	switch (node->type) {
 	case SERD_CURIE: {
 		SerdStringView prefix;
 		SerdStringView suffix;
-		if (serd_env_expand(env, node, &prefix, &suffix)) {
+		if (serd_env_expand_in_place(env, node, &prefix, &suffix)) {
 			return NULL;
 		}
 		const size_t len = prefix.len + suffix.len;
@@ -237,7 +261,7 @@ serd_env_expand_node(const SerdEnv*  env,
 	}
 	case SERD_LITERAL:
 		if (serd_node_get_datatype(node)) {
-			SerdNode* datatype = serd_env_expand_node(
+			SerdNode* datatype = serd_env_expand(
 				env, serd_node_get_datatype(node));
 			if (datatype) {
 				SerdNode* ret = serd_new_typed_literal(
diff --git a/src/env.h b/src/env.h
index ecb6cc15..c8d17912 100644
--- a/src/env.h
+++ b/src/env.h
@@ -19,6 +19,30 @@
 
 #include "serd/serd.h"
 
-const SerdURI* serd_env_get_parsed_base_uri(const SerdEnv* env);
+#include <stdbool.h>
 
-#endif  // SERD_ENV_H
+/**
+   Qualify `uri` into a CURIE if possible.
+*/
+bool
+serd_env_qualify_in_place(const SerdEnv*   env,
+                          const SerdNode*  uri,
+                          const SerdNode** prefix,
+                          SerdStringView*  suffix);
+
+/**
+   Expand `curie`.
+
+   Errors: SERD_ERR_BAD_ARG if `curie` is not valid, or SERD_ERR_BAD_CURIE if
+   prefix is not defined in `env`.
+*/
+SerdStatus
+serd_env_expand_in_place(const SerdEnv*  env,
+                         const SerdNode* curie,
+                         SerdStringView* uri_prefix,
+                         SerdStringView* uri_suffix);
+
+const SerdURI*
+serd_env_get_parsed_base_uri(const SerdEnv* env);
+
+#endif // SERD_ENV_H
diff --git a/src/writer.c b/src/writer.c
index 692139a6..55feb3f0 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -514,7 +514,7 @@ write_uri_node(SerdWriter* const        writer,
 	} else if (supports_abbrev(writer) && !strcmp(node_str, NS_RDF "nil")) {
 		return sink("()", 2, writer) == 2;
 	} else if (has_scheme && (writer->style & SERD_STYLE_CURIED) &&
-	           serd_env_qualify(writer->env, node, &prefix, &suffix) &&
+	           serd_env_qualify_in_place(writer->env, node, &prefix, &suffix) &&
 	           is_name(suffix.buf, suffix.len)) {
 		write_uri_from_node(writer, prefix);
 		sink(":", 1, writer);
@@ -562,9 +562,12 @@ write_curie(SerdWriter* const        writer,
 	switch (writer->syntax) {
 	case SERD_NTRIPLES:
 	case SERD_NQUADS:
-		if ((st = serd_env_expand(writer->env, node, &prefix, &suffix))) {
-			serd_world_errorf(writer->world, st,
-			                  "undefined namespace prefix `%s'\n", node_str);
+		if ((st = serd_env_expand_in_place(
+			     writer->env, node, &prefix, &suffix))) {
+			serd_world_errorf(writer->world,
+			                  st,
+			                  "undefined namespace prefix `%s'\n",
+			                  node_str);
 			return false;
 		}
 		write_sep(writer, SEP_URI_BEGIN);
diff --git a/tests/serd_test.c b/tests/serd_test.c
index b8b35a0b..2fddc5bf 100644
--- a/tests/serd_test.c
+++ b/tests/serd_test.c
@@ -409,35 +409,36 @@ main(void)
 		return 1;
 	}
 
-	SerdNode* u   = serd_new_uri("http://example.org/foo");
-	SerdNode* b   = serd_new_curie("invalid");
-	SerdNode* c   = serd_new_curie("eg.2:b");
-	SerdEnv*  env = serd_env_new(NULL);
-	serd_env_set_prefix_from_strings(env, "eg.2", "http://example.org/");
+	SerdNode* eg    = serd_new_uri("http://example.org/");
+	SerdNode* foo_u = serd_new_uri("http://example.org/foo");
+	SerdNode* foo_c = serd_new_curie("eg.2:foo");
+	SerdNode* b     = serd_new_curie("invalid");
+	SerdNode* pre   = serd_new_curie("eg.2");
+	SerdEnv*  env   = serd_env_new(NULL);
+	serd_env_set_prefix(env, pre, eg);
 
 	assert(!serd_env_get_base_uri(env));
 	assert(serd_env_set_base_uri(env, NULL));
 	assert(!serd_env_get_base_uri(env));
 	assert(serd_env_set_base_uri(env, hello));
 	assert(!serd_env_get_base_uri(env));
-	serd_node_free(hello);
 
-	SerdStringView prefix;
-	SerdStringView suffix;
-	assert(serd_env_expand(env, b, &prefix, &suffix));
+	SerdNode* xnode = serd_env_expand(env, hello);
+	assert(!xnode);
 
-	assert(!serd_env_expand_node(env, b));
+	serd_node_free(hello);
 
-	SerdNode* xu = serd_env_expand_node(env, u);
+	SerdNode* xu = serd_env_expand(env, foo_c);
 	assert(!strcmp(serd_node_get_string(xu), "http://example.org/foo"));
 	serd_node_free(xu);
 
 	SerdNode* badpre = serd_new_curie("hm:what");
-	SerdNode* xbadpre = serd_env_expand_node(env, badpre);
+	SerdNode* xbadpre = serd_env_expand(env, badpre);
 	assert(!xbadpre);
+	serd_node_free(badpre);
 
-	SerdNode* xc = serd_env_expand_node(env, c);
-	assert(!strcmp(serd_node_get_string(xc), "http://example.org/b"));
+	SerdNode* xc = serd_env_expand(env, foo_c);
+	assert(serd_node_equals(xc, foo_u));
 	serd_node_free(xc);
 
 	assert(serd_env_set_prefix(env, NULL, NULL));
@@ -446,18 +447,22 @@ main(void)
 	assert(serd_env_set_prefix(env, b, lit));
 
 	int n_prefixes = 0;
-	serd_env_set_prefix_from_strings(env, "eg.2", "http://example.org/");
+	serd_env_set_prefix(env, pre, eg);
 	serd_env_foreach(env, count_prefixes, &n_prefixes);
 	assert(n_prefixes == 1);
 
 	SerdNode* shorter_uri = serd_new_uri("urn:foo");
-	const SerdNode* prefix_name;
-	assert(!serd_env_qualify(env, shorter_uri, &prefix_name, &suffix));
+	assert(!serd_env_qualify(env, shorter_uri));
 	serd_node_free(shorter_uri);
-	serd_node_free(badpre);
-	serd_node_free(c);
+
+	SerdNode* qualified = serd_env_qualify(env, foo_u);
+	assert(serd_node_equals(qualified, foo_c));
+	serd_node_free(qualified);
+	serd_node_free(foo_c);
+	serd_node_free(foo_u);
 	serd_node_free(b);
-	serd_node_free(u);
+	serd_node_free(pre);
+	serd_node_free(eg);
 
 	// Test SerdReader and SerdWriter
 
-- 
cgit v1.2.1