--- /dev/null
+/* XML resource locating rules
+ Copyright (C) 2015 Free Software Foundation, Inc.
+
+ This file was written by Daiki Ueno <ueno@gnu.org>, 2015.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "locating-rule.h"
+
+#include "basename.h"
+#include "concat-filename.h"
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#endif
+
+#if HAVE_DIRENT_H
+# define HAVE_DIR 1
+#else
+# define HAVE_DIR 0
+#endif
+
+#include <errno.h>
+#include "error.h"
+#include <fnmatch.h>
+#include "gettext.h"
+#include "hash.h"
+#include <libxml/parser.h>
+#include <libxml/uri.h>
+#include "xalloc.h"
+
+#define _(str) gettext (str)
+
+#define LOCATING_RULES_NS "https://www.gnu.org/s/gettext/ns/locating-rules/1.0"
+
+struct document_locating_rule_ty
+{
+ char *ns;
+ char *local_name;
+
+ char *target;
+};
+
+struct document_locating_rule_list_ty
+{
+ struct document_locating_rule_ty *items;
+ size_t nitems;
+ size_t nitems_max;
+};
+
+struct locating_rule_ty
+{
+ char *pattern;
+
+ struct document_locating_rule_list_ty doc_rules;
+ char *target;
+};
+
+struct locating_rule_list_ty
+{
+ char *base;
+
+ struct locating_rule_ty *items;
+ size_t nitems;
+ size_t nitems_max;
+};
+
+static char *
+get_attribute (xmlNode *node, const char *attr)
+{
+ xmlChar *value;
+ char *result;
+
+ value = xmlGetProp (node, BAD_CAST attr);
+ result = xstrdup ((const char *) value);
+ xmlFree (value);
+
+ return result;
+}
+
+static const char *
+document_locating_rule_match (struct document_locating_rule_ty *rule,
+ xmlDoc *doc)
+{
+ xmlNode *root;
+
+ root = xmlDocGetRootElement (doc);
+ if (rule->ns != NULL)
+ {
+ if (root->ns == NULL
+ || !xmlStrEqual (root->ns->href, BAD_CAST rule->ns))
+ return NULL;
+ }
+
+ if (rule->local_name != NULL)
+ {
+ if (!xmlStrEqual (root->name,
+ BAD_CAST rule->local_name))
+ return NULL;
+ }
+
+ return rule->target;
+}
+
+static const char *
+locating_rule_match (struct locating_rule_ty *rule,
+ const char *filename)
+{
+ if (fnmatch (rule->pattern, filename, FNM_PATHNAME) != 0)
+ return NULL;
+
+ if (rule->target != NULL)
+ return rule->target;
+
+ if (rule->doc_rules.nitems > 0)
+ {
+ xmlDoc *doc;
+ size_t i;
+
+ doc = xmlReadFile (filename, "utf-8",
+ XML_PARSE_NONET
+ | XML_PARSE_NOWARNING
+ | XML_PARSE_NOBLANKS
+ | XML_PARSE_NOERROR);
+ if (doc == NULL)
+ return NULL;
+
+ for (i = 0; i < rule->doc_rules.nitems; i++)
+ {
+ const char *target =
+ document_locating_rule_match (&rule->doc_rules.items[i], doc);
+ if (target)
+ return target;
+ }
+ }
+
+ return NULL;
+}
+
+char *
+locating_rule_list_locate (struct locating_rule_list_ty *rules,
+ const char *path)
+{
+ const char *target = NULL;
+ size_t i;
+
+ for (i = 0; i < rules->nitems; i++)
+ {
+ target = locating_rule_match (&rules->items[i], path);
+ if (target != NULL)
+ return xconcatenated_filename (rules->base, target, NULL);
+ }
+
+ return NULL;
+}
+
+static void
+missing_attribute (const char *element, const char *attribute)
+{
+ error (0, 0, _("\"%s\" node does not have \"%s\""), element, attribute);
+}
+
+static void
+document_locating_rule_destroy (struct document_locating_rule_ty *rule)
+{
+ free (rule->ns);
+ free (rule->local_name);
+ free (rule->target);
+}
+
+static void
+document_locating_rule_list_add (struct document_locating_rule_list_ty *rules,
+ xmlNode *node)
+{
+ struct document_locating_rule_ty rule;
+
+ if (!xmlHasProp (node, BAD_CAST "target"))
+ {
+ missing_attribute ("documentRule", "target");
+ return;
+ }
+
+ memset (&rule, 0, sizeof (struct document_locating_rule_ty));
+
+ if (xmlHasProp (node, BAD_CAST "ns"))
+ rule.ns = get_attribute (node, "ns");
+ if (xmlHasProp (node, BAD_CAST "localName"))
+ rule.local_name = get_attribute (node, "localName");
+ rule.target = get_attribute (node, "target");
+
+ if (rules->nitems == rules->nitems_max)
+ {
+ rules->nitems_max = 2 * rules->nitems_max + 1;
+ rules->items =
+ xrealloc (rules->items,
+ sizeof (struct document_locating_rule_ty)
+ * rules->nitems_max);
+ }
+ memcpy (&rules->items[rules->nitems++], &rule,
+ sizeof (struct document_locating_rule_ty));
+}
+
+static void
+locating_rule_destroy (struct locating_rule_ty *rule)
+{
+ size_t i;
+
+ for (i = 0; i < rule->doc_rules.nitems; i++)
+ document_locating_rule_destroy (&rule->doc_rules.items[i]);
+
+ free (rule->pattern);
+ free (rule->target);
+}
+
+static bool
+locating_rule_list_add_file (struct locating_rule_list_ty *rules,
+ const char *rule_file_name)
+{
+ xmlDoc *doc;
+ xmlNode *root, *node;
+
+ doc = xmlReadFile (rule_file_name, "utf-8",
+ XML_PARSE_NONET
+ | XML_PARSE_NOWARNING
+ | XML_PARSE_NOBLANKS
+ | XML_PARSE_NOERROR);
+ if (doc == NULL)
+ {
+ error (0, 0, _("cannot read XML file %s"), rule_file_name);
+ return false;
+ }
+
+ root = xmlDocGetRootElement (doc);
+ if (!(xmlStrEqual (root->name, BAD_CAST "locatingRules")
+#if 0
+ && root->ns
+ && xmlStrEqual (root->ns->href, BAD_CAST LOCATING_RULES_NS)
+#endif
+ ))
+ {
+ error (0, 0, _("the root element is not \"locatingRules\""));
+ xmlFreeDoc (doc);
+ return false;
+ }
+
+ for (node = root->children; node; node = node->next)
+ {
+ if (xmlStrEqual (node->name, BAD_CAST "locatingRule"))
+ {
+ struct locating_rule_ty rule;
+
+ if (!xmlHasProp (node, BAD_CAST "pattern"))
+ {
+ missing_attribute ("locatingRule", "pattern");
+ xmlFreeDoc (doc);
+ continue;
+ }
+
+ memset (&rule, 0, sizeof (struct locating_rule_ty));
+ rule.pattern = get_attribute (node, "pattern");
+ if (xmlHasProp (node, BAD_CAST "target"))
+ rule.target = get_attribute (node, "target");
+ else
+ {
+ xmlNode *n;
+
+ for (n = node->children; n; n = n->next)
+ {
+ if (xmlStrEqual (n->name, BAD_CAST "documentRule"))
+ document_locating_rule_list_add (&rule.doc_rules, n);
+ }
+ }
+ if (rules->nitems == rules->nitems_max)
+ {
+ rules->nitems_max = 2 * rules->nitems_max + 1;
+ rules->items =
+ xrealloc (rules->items,
+ sizeof (struct locating_rule_ty) * rules->nitems_max);
+ }
+ memcpy (&rules->items[rules->nitems++], &rule,
+ sizeof (struct locating_rule_ty));
+ }
+ }
+
+ xmlFreeDoc (doc);
+ return true;
+}
+
+static bool
+locating_rule_list_add_directory (struct locating_rule_list_ty *rules,
+ const char *directory)
+{
+#if HAVE_DIR
+ DIR *dirp;
+
+ dirp = opendir (directory);
+ if (dirp == NULL)
+ return false;
+
+ for (;;)
+ {
+ struct dirent *dp;
+
+ errno = 0;
+ dp = readdir (dirp);
+ if (dp != NULL)
+ {
+ const char *name = dp->d_name;
+ size_t namlen = strlen (name);
+
+ if (namlen > 4 && memcmp (name + namlen - 4, ".loc", 4) == 0)
+ {
+ char *locator_file_name =
+ xconcatenated_filename (directory, name, NULL);
+ locating_rule_list_add_file (rules, locator_file_name);
+ free (locator_file_name);
+ }
+ }
+ else if (errno != 0)
+ return false;
+ else
+ break;
+ }
+ if (closedir (dirp))
+ return false;
+
+#endif
+ return true;
+}
+
+struct locating_rule_list_ty *
+locating_rule_list_alloc (const char *base, const char *directory)
+{
+ struct locating_rule_list_ty *result;
+
+ xmlCheckVersion (LIBXML_VERSION);
+
+ result = XCALLOC (1, struct locating_rule_list_ty);
+ result->base = xstrdup (base);
+
+ locating_rule_list_add_directory (result, directory);
+
+ return result;
+}
+
+void
+locating_rule_list_destroy (struct locating_rule_list_ty *rules)
+{
+ free (rules->base);
+
+ while (rules->nitems-- > 0)
+ locating_rule_destroy (&rules->items[rules->nitems]);
+ free (rules->items);
+}
+
+void
+locating_rule_list_free (struct locating_rule_list_ty *rules)
+{
+ if (rules != NULL)
+ locating_rule_list_destroy (rules);
+ free (rules);
+}
+++ /dev/null
-/* XML resource locator
- Copyright (C) 2015 Free Software Foundation, Inc.
-
- This file was written by Daiki Ueno <ueno@gnu.org>, 2015.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "concat-filename.h"
-
-#if HAVE_DIRENT_H
-# include <dirent.h>
-#endif
-
-#if HAVE_DIRENT_H
-# define HAVE_DIR 1
-#else
-# define HAVE_DIR 0
-#endif
-
-#include "basename.h"
-#include <errno.h>
-#include "error.h"
-#include "gettext.h"
-#include "hash.h"
-#include <libxml/parser.h>
-#include <libxml/uri.h>
-#include "xalloc.h"
-
-#include "xlocator.h"
-
-#define _(str) gettext (str)
-
-/* The schema is the same as the one used in nXML-mode (in Emacs):
- http://www.gnu.org/software/emacs/manual/html_node/nxml-mode/Schema-locating-file-syntax-basics.html#Schema-locating-file-syntax-basics
- */
-
-#define LOCATING_RULES_NS "http://thaiopensource.com/ns/locating-rules/1.0"
-
-enum xlocator_type
-{
- XLOCATOR_URI,
- XLOCATOR_URI_PATTERN,
- XLOCATOR_NAMESPACE,
- XLOCATOR_DOCUMENT_ELEMENT
-};
-
-struct xlocator_target_ty
-{
- bool is_indirection;
- bool is_transform;
- char *uri;
-};
-
-struct xlocator_ty
-{
- enum xlocator_type type;
-
- union {
- char *uri;
- char *pattern;
- char *ns;
- struct {
- char *prefix;
- char *local_name;
- } d;
- } matcher;
-
- struct xlocator_target_ty target;
-};
-
-struct xlocator_list_ty
-{
- char *base;
-
- hash_table indirections;
-
- struct xlocator_ty *items;
- size_t nitems;
- size_t nitems_max;
-};
-
-static char *
-_xlocator_get_attribute (xmlNode *node, const char *attr)
-{
- xmlChar *value;
- char *result;
-
- value = xmlGetProp (node, BAD_CAST attr);
- result = xstrdup ((const char *) value);
- xmlFree (value);
-
- return result;
-}
-
-static bool
-_xlocator_match_pattern (const char *pattern, const char *filename,
- ptrdiff_t *start_offset, ptrdiff_t *end_offset)
-{
- const char *p = pattern, *q = filename;
- size_t length = strlen (filename);
-
- while (true)
- {
- switch (*p)
- {
- case '\0':
- return *q == '\0';
-
- case '*':
- if (*q == '\0')
- return false;
- else
- {
- const char *end = filename + length;
- while (true)
- {
- if (_xlocator_match_pattern (p + 1, end, NULL, NULL))
- {
- if (start_offset)
- *start_offset = q - filename;
- if (end_offset)
- *end_offset = end - filename;
- return true;
- }
- if (end == q + 1)
- break;
- end--;
- }
- return false;
- }
-
- default:
- if (*p == *q)
- return _xlocator_match_pattern (p + 1, q + 1, NULL, NULL);
- return false;
- }
- }
-}
-
-static bool
-xlocator_match (struct xlocator_ty *locator, const char *path,
- struct xlocator_target_ty *target,
- bool inspect_content)
-{
- switch (locator->type)
- {
- case XLOCATOR_URI:
- return strcmp (locator->matcher.uri, path) == 0;
-
- case XLOCATOR_URI_PATTERN:
- {
- char *filename = basename (path);
- /* We can't simply use fnmatch() here, since PATH is a component
- of a URI. */
- if (!target->is_transform)
- return _xlocator_match_pattern (locator->matcher.pattern, filename,
- NULL, NULL);
- else
- {
- ptrdiff_t start_offset = -1, end_offset = -1;
- char *star, *buffer, *bp;
-
- if (!_xlocator_match_pattern (locator->matcher.pattern, filename,
- &start_offset, &end_offset))
- return false;
-
- /* If fromPattern doesn't contain '*', use toPattern as it
- is as URI. */
- if (start_offset < 0 || end_offset < 0)
- return true;
-
- /* If toPattern doesn't contain '*', use the pattern as it
- is as URI. */
- star = strchr (target->uri, '*');
- if (star == NULL)
- return true;
-
- bp = buffer = XNMALLOC ((filename - path)
- + (star - target->uri)
- + (end_offset - start_offset)
- + strlen (star + 1) + 1,
- char);
- bp = stpncpy (bp, path, filename - path);
- if (star > target->uri)
- bp = stpncpy (bp, target->uri, star - target->uri);
- bp = stpncpy (bp, filename + start_offset,
- end_offset - start_offset);
- if (*star != '\0')
- bp = stpcpy (bp, star + 1);
- free (target->uri);
- target->is_transform = false;
- target->uri = buffer;
- return true;
- }
- }
-
- case XLOCATOR_NAMESPACE:
- case XLOCATOR_DOCUMENT_ELEMENT:
- if (!inspect_content)
- return false;
- else
- {
- xmlDoc *doc;
- xmlNode *root;
- bool result;
-
- doc = xmlReadFile (path, "utf-8",
- XML_PARSE_NONET
- | XML_PARSE_NOWARNING
- | XML_PARSE_NOBLANKS
- | XML_PARSE_NOERROR);
- if (doc == NULL)
- return false;
-
-
- root = xmlDocGetRootElement (doc);
- if (locator->type == XLOCATOR_NAMESPACE)
- result = root->ns != NULL
- && xmlStrEqual (root->ns->href, BAD_CAST locator->matcher.ns);
- else
- result =
- ((!locator->matcher.d.prefix
- || *locator->matcher.d.prefix == '\0'
- || !root->ns
- || xmlStrEqual (root->ns->prefix,
- BAD_CAST locator->matcher.d.prefix))
- && (!locator->matcher.d.local_name
- || xmlStrEqual (root->name,
- BAD_CAST locator->matcher.d.local_name)));
- xmlFreeDoc (doc);
- return result;
- }
-
- default:
- error (0, 0, _("unsupported locator type: %d"), locator->type);
- return false;
- }
-}
-
-static char *
-xlocator_list_resolve_target (struct xlocator_list_ty *locators,
- struct xlocator_target_ty *target)
-{
- char *target_uri = NULL;
- char *result = NULL;
-
- if (!target->is_indirection)
- target_uri = xstrdup (target->uri);
- else
- {
- void *value;
-
- if (hash_find_entry (&locators->indirections,
- target->uri, strlen (target->uri),
- &value) == 0)
- {
- struct xlocator_target_ty *next_target =
- (struct xlocator_target_ty *) value;
- target_uri = xlocator_list_resolve_target (locators, next_target);
- }
- else
- error (0, 0, _("cannot resolve \"typeId\" %s"), target->uri);
- }
-
- if (target_uri != NULL)
- {
- char *path;
- xmlChar *absolute_uri;
- xmlURI *uri;
-
- /* Use a dummy file name under the locators->base directory, so
- that xmlBuildURI() resolve a URI relative to the file, not
- the parent directory. */
- path = xconcatenated_filename (locators->base, ".", NULL);
- absolute_uri = xmlBuildURI (BAD_CAST target_uri, BAD_CAST path);
- free (path);
-
- uri = xmlParseURI ((const char *) absolute_uri);
- xmlFree (absolute_uri);
-
- if (uri != NULL)
- result = xstrdup (uri->path);
- xmlFreeURI (uri);
- }
-
- free (target_uri);
- return result;
-}
-
-char *
-xlocator_list_locate (struct xlocator_list_ty *locators,
- const char *path,
- bool inspect_content)
-{
- struct xlocator_ty *locator;
- size_t i;
-
- for (i = 0; i < locators->nitems; i++)
- {
- locator = &locators->items[i];
- if (xlocator_match (locator, path, &locator->target, inspect_content))
- break;
- }
-
- if (i == locators->nitems)
- return NULL;
-
- return xlocator_list_resolve_target (locators, &locator->target);
-}
-
-static void
-_xlocator_error_missing_attribute (const char *element, const char *attribute)
-{
- error (0, 0, _("\"%s\" node does not have \"%s\""), element, attribute);
-}
-
-static void
-_xlocator_error_missing_attributes (const char *element, ...)
-{
- va_list ap;
- char *buffer = NULL;
- size_t buflen = 0;
- size_t bufmax = 0;
-
- va_start (ap, element);
- while (true)
- {
- const char *attribute;
- size_t length;
-
- attribute = va_arg (ap, char *);
- if (!attribute)
- break;
-
- length = strlen (attribute) + 2;
- if (buflen + length + 1 >= bufmax)
- {
- bufmax = bufmax * 2 + length + 1;
- buffer = xrealloc (buffer, bufmax);
- }
- sprintf (&buffer[buflen], "%s, ", attribute);
- buflen += length;
- }
- va_end (ap);
-
- if (buflen > 0)
- buffer[buflen - 2] = '\0';
-
- error (0, 0, _("\"%s\" node must have one of: %s"),
- element, buffer);
-}
-
-static bool
-xlocator_target_init (struct xlocator_target_ty *target, xmlNode *node)
-{
- if (!(xmlHasProp (node, BAD_CAST "uri")
- || xmlHasProp (node, BAD_CAST "typeId")))
- {
- _xlocator_error_missing_attributes ((const char *) node->name,
- "uri", "typeId", NULL);
- return false;
- }
-
- if (xmlHasProp (node, BAD_CAST "uri"))
- {
- target->uri = _xlocator_get_attribute (node, "uri");
- target->is_indirection = false;
- }
- else
- {
- target->uri = _xlocator_get_attribute (node, "typeId");
- target->is_indirection = true;
- }
-
- return true;
-}
-
-static size_t
-_xlocator_count_transform_pattern (const char *pattern)
-{
- const char *p;
- size_t result;
-
- for (p = pattern, result = 0; ; p++, result++)
- {
- p = strchr (p, '*');
- if (!p)
- break;
- }
-
- return result;
-}
-
-static bool
-xlocator_init (struct xlocator_ty *locator, xmlNode *node)
-{
- memset (locator, 0, sizeof (struct xlocator_ty));
-
- if (xmlStrEqual (node->name, BAD_CAST "uri"))
- {
- if (!(xmlHasProp (node, BAD_CAST "resource")
- || xmlHasProp (node, BAD_CAST "pattern")))
- {
- _xlocator_error_missing_attributes ("uri", "resource", "pattern",
- NULL);
- return false;
- }
-
- if (xmlHasProp (node, BAD_CAST "resource"))
- {
- locator->type = XLOCATOR_URI;
- locator->matcher.uri = _xlocator_get_attribute (node, "resource");
- }
- else
- {
- locator->type = XLOCATOR_URI_PATTERN;
- locator->matcher.uri = _xlocator_get_attribute (node, "pattern");
- }
-
- return xlocator_target_init (&locator->target, node);
- }
- else if (xmlStrEqual (node->name, BAD_CAST "transformURI"))
- {
- size_t from_count, to_count;
-
- if (!xmlHasProp (node, BAD_CAST "fromPattern"))
- {
- _xlocator_error_missing_attribute ("transformURI", "fromPattern");
- return false;
- }
- if (!xmlHasProp (node, BAD_CAST "toPattern"))
- {
- _xlocator_error_missing_attribute ("transformURI", "toPattern");
- return false;
- }
-
- locator->type = XLOCATOR_URI_PATTERN;
- locator->matcher.uri = _xlocator_get_attribute (node, "fromPattern");
- locator->target.uri = _xlocator_get_attribute (node, "toPattern");
- locator->target.is_transform = true;
-
- from_count = _xlocator_count_transform_pattern (locator->matcher.uri);
- to_count = _xlocator_count_transform_pattern (locator->target.uri);
- if (from_count > 1)
- {
- error (0, 0, _("\"%s\" contains multiple wildcard characters"),
- "fromPattern");
- return false;
- }
- if (to_count > from_count)
- {
- error (0, 0, _("\"%s\" contains %zu wildcard characters,"
- " while \"%s\" contains %zu"),
- "toPattern", to_count, "fromPattern", from_count);
- return false;
- }
-
- return true;
- }
- else if (xmlStrEqual (node->name, BAD_CAST "namespace"))
- {
- if (!xmlHasProp (node, BAD_CAST "ns"))
- {
- _xlocator_error_missing_attribute ("namespace", "ns");
- return false;
- }
-
- locator->type = XLOCATOR_NAMESPACE;
- locator->matcher.ns = _xlocator_get_attribute (node, "ns");
-
- return xlocator_target_init (&locator->target, node);
- }
- else if (xmlStrEqual (node->name, BAD_CAST "documentElement"))
- {
- if (!xmlHasProp (node, BAD_CAST "prefix"))
- {
- _xlocator_error_missing_attribute ("documentElement", "prefix");
- return false;
- }
- if (!xmlHasProp (node, BAD_CAST "localName"))
- {
- _xlocator_error_missing_attribute ("documentElement", "localName");
- return false;
- }
-
- locator->type = XLOCATOR_DOCUMENT_ELEMENT;
- locator->matcher.d.prefix =
- _xlocator_get_attribute (node, "prefix");
- locator->matcher.d.local_name =
- _xlocator_get_attribute (node, "localName");
-
- return xlocator_target_init (&locator->target, node);
- }
-
- return false;
-}
-
-static void
-xlocator_destroy (struct xlocator_ty *locator)
-{
- switch (locator->type)
- {
- case XLOCATOR_URI:
- free (locator->matcher.uri);
- break;
-
- case XLOCATOR_URI_PATTERN:
- free (locator->matcher.pattern);
- break;
-
- case XLOCATOR_NAMESPACE:
- free (locator->matcher.ns);
- break;
-
- case XLOCATOR_DOCUMENT_ELEMENT:
- free (locator->matcher.d.prefix);
- free (locator->matcher.d.local_name);
- break;
- }
-
- free (locator->target.uri);
-}
-
-static bool
-xlocator_list_add_file (struct xlocator_list_ty *locators,
- const char *locator_file_name)
-{
- xmlDoc *doc;
- xmlNode *root, *node;
-
- doc = xmlReadFile (locator_file_name, "utf-8",
- XML_PARSE_NONET
- | XML_PARSE_NOWARNING
- | XML_PARSE_NOBLANKS
- | XML_PARSE_NOERROR);
- if (doc == NULL)
- return false;
-
- root = xmlDocGetRootElement (doc);
- if (!(xmlStrEqual (root->name, BAD_CAST "locatingRules")
-#if 0
- && root->ns
- && xmlStrEqual (root->ns->href, BAD_CAST LOCATING_RULES_NS)
-#endif
- ))
- {
- error (0, 0, _("the root element is not \"locatingRules\""));
- xmlFreeDoc (doc);
- return false;
- }
-
- for (node = root->children; node; node = node->next)
- {
- if (xmlStrEqual (node->name, BAD_CAST "typeId"))
- {
- struct xlocator_target_ty *target;
- char *id;
-
- if (!(xmlHasProp (node, BAD_CAST "id")
- && (xmlHasProp (node, BAD_CAST "typeId")
- || xmlHasProp (node, BAD_CAST "uri"))))
- {
- xmlFreeDoc (doc);
- return false;
- }
-
- id = _xlocator_get_attribute (node, "id");
- target = XMALLOC (struct xlocator_target_ty);
- if (xmlHasProp (node, BAD_CAST "typeId"))
- {
- target->is_indirection = true;
- target->uri = _xlocator_get_attribute (node, "typeId");
- }
- else
- {
- target->is_indirection = false;
- target->uri = _xlocator_get_attribute (node, "uri");
- }
- hash_insert_entry (&locators->indirections, id, strlen (id),
- target);
- free (id);
- }
- else
- {
- struct xlocator_ty locator;
-
- if (!xlocator_init (&locator, node))
- {
- xlocator_destroy (&locator);
- continue;
- }
-
- if (locators->nitems == locators->nitems_max)
- {
- locators->nitems_max = 2 * locators->nitems_max + 1;
- locators->items =
- xrealloc (locators->items,
- sizeof (struct xlocator_ty) * locators->nitems_max);
- }
- memcpy (&locators->items[locators->nitems++], &locator,
- sizeof (struct xlocator_ty));
- }
- }
-
- xmlFreeDoc (doc);
- return true;
-}
-
-static bool
-xlocator_list_add_directory (struct xlocator_list_ty *locators,
- const char *directory)
-{
-#if HAVE_DIR
- DIR *dirp;
-
- dirp = opendir (directory);
- if (dirp == NULL)
- return false;
-
- for (;;)
- {
- struct dirent *dp;
-
- errno = 0;
- dp = readdir (dirp);
- if (dp != NULL)
- {
- const char *name = dp->d_name;
- size_t namlen = strlen (name);
-
- if (namlen > 4 && memcmp (name + namlen - 4, ".loc", 4) == 0)
- {
- char *locator_file_name =
- xconcatenated_filename (directory, name, NULL);
- xlocator_list_add_file (locators, locator_file_name);
- free (locator_file_name);
- }
- }
- else if (errno != 0)
- return false;
- else
- break;
- }
- if (closedir (dirp))
- return false;
-
-#endif
- return true;
-}
-
-struct xlocator_list_ty *
-xlocator_list_alloc (const char *base, const char *directory)
-{
- struct xlocator_list_ty *result;
-
- xmlCheckVersion (LIBXML_VERSION);
-
- result = XCALLOC (1, struct xlocator_list_ty);
- hash_init (&result->indirections, 10);
- result->base = xstrdup (base);
-
- xlocator_list_add_directory (result, directory);
-
- return result;
-}
-
-void
-xlocator_list_destroy (struct xlocator_list_ty *locators)
-{
- void *iter;
- const void *key;
- size_t keylen;
- void *data;
-
- iter = NULL;
- while (hash_iterate (&locators->indirections, &iter, &key, &keylen, &data)
- == 0)
- {
- struct xlocator_target_ty *target = data;
- free (target->uri);
- free (target);
- }
- hash_destroy (&locators->indirections);
-
- free (locators->base);
-
- while (locators->nitems-- > 0)
- xlocator_destroy (&locators->items[locators->nitems]);
- free (locators->items);
-}
-
-void
-xlocator_list_free (struct xlocator_list_ty *locators)
-{
- if (locators != NULL)
- xlocator_list_destroy (locators);
- free (locators);
-}