annotate ext/serd/src/env.c @ 226:c5cdc9e6a4bf

Add these external library files
author Chris Cannam <cannam@all-day-breakfast.com>
date Fri, 09 Jun 2017 16:41:31 +0100
parents
children
rev   line source
cannam@226 1 /*
cannam@226 2 Copyright 2011-2016 David Robillard <http://drobilla.net>
cannam@226 3
cannam@226 4 Permission to use, copy, modify, and/or distribute this software for any
cannam@226 5 purpose with or without fee is hereby granted, provided that the above
cannam@226 6 copyright notice and this permission notice appear in all copies.
cannam@226 7
cannam@226 8 THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
cannam@226 9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
cannam@226 10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
cannam@226 11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
cannam@226 12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
cannam@226 13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
cannam@226 14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
cannam@226 15 */
cannam@226 16
cannam@226 17 #include "serd_internal.h"
cannam@226 18
cannam@226 19 #include <stdlib.h>
cannam@226 20 #include <string.h>
cannam@226 21
cannam@226 22 typedef struct {
cannam@226 23 SerdNode name;
cannam@226 24 SerdNode uri;
cannam@226 25 } SerdPrefix;
cannam@226 26
cannam@226 27 struct SerdEnvImpl {
cannam@226 28 SerdPrefix* prefixes;
cannam@226 29 size_t n_prefixes;
cannam@226 30 SerdNode base_uri_node;
cannam@226 31 SerdURI base_uri;
cannam@226 32 };
cannam@226 33
cannam@226 34 SERD_API
cannam@226 35 SerdEnv*
cannam@226 36 serd_env_new(const SerdNode* base_uri)
cannam@226 37 {
cannam@226 38 SerdEnv* env = (SerdEnv*)calloc(sizeof(struct SerdEnvImpl), 1);
cannam@226 39 if (env && base_uri) {
cannam@226 40 serd_env_set_base_uri(env, base_uri);
cannam@226 41 }
cannam@226 42 return env;
cannam@226 43 }
cannam@226 44
cannam@226 45 SERD_API
cannam@226 46 void
cannam@226 47 serd_env_free(SerdEnv* env)
cannam@226 48 {
cannam@226 49 for (size_t i = 0; i < env->n_prefixes; ++i) {
cannam@226 50 serd_node_free(&env->prefixes[i].name);
cannam@226 51 serd_node_free(&env->prefixes[i].uri);
cannam@226 52 }
cannam@226 53 free(env->prefixes);
cannam@226 54 serd_node_free(&env->base_uri_node);
cannam@226 55 free(env);
cannam@226 56 }
cannam@226 57
cannam@226 58 SERD_API
cannam@226 59 const SerdNode*
cannam@226 60 serd_env_get_base_uri(const SerdEnv* env,
cannam@226 61 SerdURI* out)
cannam@226 62 {
cannam@226 63 if (out) {
cannam@226 64 *out = env->base_uri;
cannam@226 65 }
cannam@226 66 return &env->base_uri_node;
cannam@226 67 }
cannam@226 68
cannam@226 69 SERD_API
cannam@226 70 SerdStatus
cannam@226 71 serd_env_set_base_uri(SerdEnv* env,
cannam@226 72 const SerdNode* uri_node)
cannam@226 73 {
cannam@226 74 if (!env || !uri_node) {
cannam@226 75 return SERD_ERR_BAD_ARG;
cannam@226 76 }
cannam@226 77
cannam@226 78 // Resolve base URI and create a new node and URI for it
cannam@226 79 SerdURI base_uri;
cannam@226 80 SerdNode base_uri_node = serd_node_new_uri_from_node(
cannam@226 81 uri_node, &env->base_uri, &base_uri);
cannam@226 82
cannam@226 83 if (base_uri_node.buf) {
cannam@226 84 // Replace the current base URI
cannam@226 85 serd_node_free(&env->base_uri_node);
cannam@226 86 env->base_uri_node = base_uri_node;
cannam@226 87 env->base_uri = base_uri;
cannam@226 88 return SERD_SUCCESS;
cannam@226 89 }
cannam@226 90 return SERD_ERR_BAD_ARG;
cannam@226 91 }
cannam@226 92
cannam@226 93 static inline SerdPrefix*
cannam@226 94 serd_env_find(const SerdEnv* env,
cannam@226 95 const uint8_t* name,
cannam@226 96 size_t name_len)
cannam@226 97 {
cannam@226 98 for (size_t i = 0; i < env->n_prefixes; ++i) {
cannam@226 99 const SerdNode* const prefix_name = &env->prefixes[i].name;
cannam@226 100 if (prefix_name->n_bytes == name_len) {
cannam@226 101 if (!memcmp(prefix_name->buf, name, name_len)) {
cannam@226 102 return &env->prefixes[i];
cannam@226 103 }
cannam@226 104 }
cannam@226 105 }
cannam@226 106 return NULL;
cannam@226 107 }
cannam@226 108
cannam@226 109 static void
cannam@226 110 serd_env_add(SerdEnv* env,
cannam@226 111 const SerdNode* name,
cannam@226 112 const SerdNode* uri)
cannam@226 113 {
cannam@226 114 SerdPrefix* const prefix = serd_env_find(env, name->buf, name->n_bytes);
cannam@226 115 if (prefix) {
cannam@226 116 SerdNode old_prefix_uri = prefix->uri;
cannam@226 117 prefix->uri = serd_node_copy(uri);
cannam@226 118 serd_node_free(&old_prefix_uri);
cannam@226 119 } else {
cannam@226 120 env->prefixes = (SerdPrefix*)realloc(
cannam@226 121 env->prefixes, (++env->n_prefixes) * sizeof(SerdPrefix));
cannam@226 122 env->prefixes[env->n_prefixes - 1].name = serd_node_copy(name);
cannam@226 123 env->prefixes[env->n_prefixes - 1].uri = serd_node_copy(uri);
cannam@226 124 }
cannam@226 125 }
cannam@226 126
cannam@226 127 SERD_API
cannam@226 128 SerdStatus
cannam@226 129 serd_env_set_prefix(SerdEnv* env,
cannam@226 130 const SerdNode* name,
cannam@226 131 const SerdNode* uri_node)
cannam@226 132 {
cannam@226 133 if (!name->buf || uri_node->type != SERD_URI) {
cannam@226 134 return SERD_ERR_BAD_ARG;
cannam@226 135 } else if (serd_uri_string_has_scheme(uri_node->buf)) {
cannam@226 136 // Set prefix to absolute URI
cannam@226 137 serd_env_add(env, name, uri_node);
cannam@226 138 } else {
cannam@226 139 // Resolve relative URI and create a new node and URI for it
cannam@226 140 SerdURI abs_uri;
cannam@226 141 SerdNode abs_uri_node = serd_node_new_uri_from_node(
cannam@226 142 uri_node, &env->base_uri, &abs_uri);
cannam@226 143
cannam@226 144 // Set prefix to resolved (absolute) URI
cannam@226 145 serd_env_add(env, name, &abs_uri_node);
cannam@226 146 serd_node_free(&abs_uri_node);
cannam@226 147 }
cannam@226 148 return SERD_SUCCESS;
cannam@226 149 }
cannam@226 150
cannam@226 151 SERD_API
cannam@226 152 SerdStatus
cannam@226 153 serd_env_set_prefix_from_strings(SerdEnv* env,
cannam@226 154 const uint8_t* name,
cannam@226 155 const uint8_t* uri)
cannam@226 156 {
cannam@226 157 const SerdNode name_node = serd_node_from_string(SERD_LITERAL, name);
cannam@226 158 const SerdNode uri_node = serd_node_from_string(SERD_URI, uri);
cannam@226 159
cannam@226 160 return serd_env_set_prefix(env, &name_node, &uri_node);
cannam@226 161 }
cannam@226 162
cannam@226 163 static inline bool
cannam@226 164 is_nameChar(const uint8_t c)
cannam@226 165 {
cannam@226 166 return is_alpha(c) || is_digit(c) || c == '_';
cannam@226 167 }
cannam@226 168
cannam@226 169 /**
cannam@226 170 Return true iff `buf` is a valid prefixed name suffix.
cannam@226 171 TODO: This is more strict than it should be.
cannam@226 172 */
cannam@226 173 static inline bool
cannam@226 174 is_name(const uint8_t* buf, size_t len)
cannam@226 175 {
cannam@226 176 for (size_t i = 0; i < len; ++i) {
cannam@226 177 if (!is_nameChar(buf[i])) {
cannam@226 178 return false;
cannam@226 179 }
cannam@226 180 }
cannam@226 181 return true;
cannam@226 182 }
cannam@226 183
cannam@226 184 SERD_API
cannam@226 185 bool
cannam@226 186 serd_env_qualify(const SerdEnv* env,
cannam@226 187 const SerdNode* uri,
cannam@226 188 SerdNode* prefix_name,
cannam@226 189 SerdChunk* suffix)
cannam@226 190 {
cannam@226 191 for (size_t i = 0; i < env->n_prefixes; ++i) {
cannam@226 192 const SerdNode* const prefix_uri = &env->prefixes[i].uri;
cannam@226 193 if (uri->n_bytes >= prefix_uri->n_bytes) {
cannam@226 194 if (!strncmp((const char*)uri->buf,
cannam@226 195 (const char*)prefix_uri->buf,
cannam@226 196 prefix_uri->n_bytes)) {
cannam@226 197 *prefix_name = env->prefixes[i].name;
cannam@226 198 suffix->buf = uri->buf + prefix_uri->n_bytes;
cannam@226 199 suffix->len = uri->n_bytes - prefix_uri->n_bytes;
cannam@226 200 if (is_name(suffix->buf, suffix->len)) {
cannam@226 201 return true;
cannam@226 202 }
cannam@226 203 }
cannam@226 204 }
cannam@226 205 }
cannam@226 206 return false;
cannam@226 207 }
cannam@226 208
cannam@226 209 SERD_API
cannam@226 210 SerdStatus
cannam@226 211 serd_env_expand(const SerdEnv* env,
cannam@226 212 const SerdNode* qname,
cannam@226 213 SerdChunk* uri_prefix,
cannam@226 214 SerdChunk* uri_suffix)
cannam@226 215 {
cannam@226 216 const uint8_t* const colon = (const uint8_t*)memchr(
cannam@226 217 qname->buf, ':', qname->n_bytes + 1);
cannam@226 218 if (!colon) {
cannam@226 219 return SERD_ERR_BAD_ARG; // Invalid qname
cannam@226 220 }
cannam@226 221
cannam@226 222 const size_t name_len = colon - qname->buf;
cannam@226 223 const SerdPrefix* const prefix = serd_env_find(env, qname->buf, name_len);
cannam@226 224 if (prefix) {
cannam@226 225 uri_prefix->buf = prefix->uri.buf;
cannam@226 226 uri_prefix->len = prefix->uri.n_bytes;
cannam@226 227 uri_suffix->buf = colon + 1;
cannam@226 228 uri_suffix->len = qname->n_bytes - (colon - qname->buf) - 1;
cannam@226 229 return SERD_SUCCESS;
cannam@226 230 }
cannam@226 231 return SERD_ERR_NOT_FOUND;
cannam@226 232 }
cannam@226 233
cannam@226 234 SERD_API
cannam@226 235 SerdNode
cannam@226 236 serd_env_expand_node(const SerdEnv* env,
cannam@226 237 const SerdNode* node)
cannam@226 238 {
cannam@226 239 switch (node->type) {
cannam@226 240 case SERD_CURIE: {
cannam@226 241 SerdChunk prefix;
cannam@226 242 SerdChunk suffix;
cannam@226 243 if (serd_env_expand(env, node, &prefix, &suffix)) {
cannam@226 244 return SERD_NODE_NULL;
cannam@226 245 }
cannam@226 246 const size_t len = prefix.len + suffix.len;
cannam@226 247 uint8_t* buf = (uint8_t*)malloc(len + 1);
cannam@226 248 SerdNode ret = { buf, len, 0, 0, SERD_URI };
cannam@226 249 snprintf((char*)buf, len + 1, "%s%s", prefix.buf, suffix.buf);
cannam@226 250 ret.n_chars = serd_strlen(buf, NULL, NULL);
cannam@226 251 return ret;
cannam@226 252 }
cannam@226 253 case SERD_URI: {
cannam@226 254 SerdURI ignored;
cannam@226 255 return serd_node_new_uri_from_node(node, &env->base_uri, &ignored);
cannam@226 256 }
cannam@226 257 default:
cannam@226 258 return SERD_NODE_NULL;
cannam@226 259 }
cannam@226 260 }
cannam@226 261
cannam@226 262 SERD_API
cannam@226 263 void
cannam@226 264 serd_env_foreach(const SerdEnv* env,
cannam@226 265 SerdPrefixSink func,
cannam@226 266 void* handle)
cannam@226 267 {
cannam@226 268 for (size_t i = 0; i < env->n_prefixes; ++i) {
cannam@226 269 func(handle, &env->prefixes[i].name, &env->prefixes[i].uri);
cannam@226 270 }
cannam@226 271 }