]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
locating-rule: Rewrite from xlocator
authorDaiki Ueno <ueno@gnu.org>
Tue, 29 Sep 2015 04:56:42 +0000 (13:56 +0900)
committerDaiki Ueno <ueno@gnu.org>
Tue, 29 Sep 2015 04:57:42 +0000 (13:57 +0900)
gettext-tools/src/Makefile.am
gettext-tools/src/locating-rule.c [new file with mode: 0644]
gettext-tools/src/locating-rule.h [moved from gettext-tools/src/xlocator.h with 63% similarity]
gettext-tools/src/xgettext.c
gettext-tools/src/xlocator.c [deleted file]
gettext-tools/tests/xgettext-its-1

index b4e6ff7454038a92d8a76fedd4bdc89fd14c91df..ebbc26fe24be9751bb12dd4444db47a7617d712f 100644 (file)
@@ -40,7 +40,7 @@ read-po.h read-properties.h read-stringtable.h \
 str-list.h \
 color.h write-catalog.h write-po.h write-properties.h write-stringtable.h \
 dir-list.h file-list.h po-gram-gen.h po-gram-gen2.h cldr-plural.h \
-cldr-plural-exp.h xlocator.h its.h \
+cldr-plural-exp.h locating-rule.h its.h \
 msgl-charset.h msgl-equal.h msgl-iconv.h msgl-ascii.h msgl-cat.h msgl-header.h \
 msgl-english.h msgl-check.h msgl-fsearch.h msgfmt.h msgunfmt.h \
 plural-count.h plural-eval.h plural-distrib.h \
@@ -183,7 +183,7 @@ xgettext_SOURCES += \
   x-c.c x-po.c x-sh.c x-python.c x-lisp.c x-elisp.c x-librep.c x-scheme.c \
   x-smalltalk.c x-java.c x-csharp.c x-awk.c x-ycp.c x-tcl.c x-perl.c x-php.c \
   x-rst.c x-glade.c x-lua.c x-javascript.c x-vala.c x-gsettings.c \
-  x-desktop.c x-appdata.c xlocator.c its.c
+  x-desktop.c x-appdata.c locating-rule.c its.c
 if !WOE32DLL
 msgattrib_SOURCES = msgattrib.c
 else
diff --git a/gettext-tools/src/locating-rule.c b/gettext-tools/src/locating-rule.c
new file mode 100644 (file)
index 0000000..a487814
--- /dev/null
@@ -0,0 +1,378 @@
+/* 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);
+}
similarity index 63%
rename from gettext-tools/src/xlocator.h
rename to gettext-tools/src/locating-rule.h
index 3ef85d0682505c6c6e7cace60e4caec9b396bcff..91785f8e9d2b23c1d42dde4ce30ee6788ef48dcd 100644 (file)
@@ -1,4 +1,4 @@
-/* XML resource locator
+/* XML resource locating rules
    Copyright (C) 2015 Free Software Foundation, Inc.
 
    This file was written by Daiki Ueno <ueno@gnu.org>, 2015.
@@ -16,8 +16,8 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#ifndef _XLOCATOR_H
-#define _XLOCATOR_H
+#ifndef _LOCATING_RULE_H
+#define _LOCATING_RULE_H
 
 #include <stdbool.h>
 
 extern "C" {
 #endif
 
-typedef struct xlocator_list_ty xlocator_list_ty;
+typedef struct locating_rule_list_ty locating_rule_list_ty;
 
-/* Creates a fresh xlocator_list_ty with the base URI BASE, and loads
+/* Creates a fresh locating_rule_list_ty with the base URI BASE, and loads
    the locating rules from the files in DIRECTORY.  */
-extern struct xlocator_list_ty *xlocator_list_alloc (const char *base,
+extern struct locating_rule_list_ty *locating_rule_list_alloc (const char *base,
                                                      const char *directory);
 
 /* Determines the location of resource associated with PATH, accoding
-   to the loaded locating rules.  If INSPECT_CONTENT is true, it also
-   checks the content of the file pointed by PATH.  */
-extern char *xlocator_list_locate (xlocator_list_ty *locators,
-                                   const char *path,
-                                   bool inspect_content);
+   to the loaded locating rules.  */
+extern char *locating_rule_list_locate (locating_rule_list_ty *locators,
+                                   const char *path);
 
 /* Releases memory allocated for LOCATORS.  */
-extern void xlocator_list_free (xlocator_list_ty *locators);
+extern void locating_rule_list_free (locating_rule_list_ty *locators);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif  /* _XLOCATOR_H */
+#endif  /* _LOCATING_RULE_H */
index a26a854788bf13315693e2b733779154399fdf2d..e91a835c66ea05938ce32701955f43cba76a8ce4 100644 (file)
@@ -71,8 +71,8 @@
 #include "propername.h"
 #include "sentence.h"
 #include "unistr.h"
-#include "xlocator.h"
 #include "its.h"
+#include "locating-rule.h"
 #include "gettext.h"
 
 /* A convenience macro.  I don't like writing gettext() every time.  */
@@ -208,7 +208,7 @@ const char *xgettext_current_source_encoding;
 iconv_t xgettext_current_source_iconv;
 #endif
 
-static xlocator_list_ty *its_locators;
+static locating_rule_list_ty *its_locating_rules;
 
 /* Long options.  */
 static const struct option long_options[] =
@@ -719,7 +719,7 @@ xgettext cannot work without keywords to look for"));
   if (its)
     {
       const char *gettextdatadir;
-      char *itsdir, *ruledir, *locatordir;
+      char *itsdir;
 
       /* Make it possible to override the locator file location.  This
          is necessary for running the testsuite before "make
@@ -729,13 +729,8 @@ xgettext cannot work without keywords to look for"));
         gettextdatadir = relocate (GETTEXTDATADIR);
 
       itsdir = xconcatenated_filename (gettextdatadir, "its", NULL);
-      ruledir = xconcatenated_filename (itsdir, "rules", NULL);
-      locatordir = xconcatenated_filename (itsdir, "locators", NULL);
+      its_locating_rules = locating_rule_list_alloc (itsdir, itsdir);
       free (itsdir);
-
-      its_locators = xlocator_list_alloc (ruledir, locatordir);
-      free (ruledir);
-      free (locatordir);
     }
 
   /* Determine extractor from language.  */
@@ -875,19 +870,12 @@ This version was built without iconv()."),
                 }
             }
 
-          if (language == NULL && its_locators != NULL)
+          if (language == NULL && its_locating_rules != NULL)
             {
-              bool inspect;
               char *its_filename = NULL;
 
-              /* Inspect the content, only when the file extension is
-                 ".xml".  */
-              inspect = strlen (reduced) >= 4
-                && memcmp (reduced + strlen (reduced) - 4, ".xml", 4)
-                == 0;
-
-              its_filename = xlocator_list_locate (its_locators, filename,
-                                                   inspect);
+              its_filename = locating_rule_list_locate (its_locating_rules,
+                                                        filename);
               if (its_filename != NULL)
                 {
                   its_rules = its_rule_list_alloc ();
@@ -970,8 +958,8 @@ warning: file '%s' extension '%s' is unknown; will try C"), filename, extension)
   /* Write the PO file.  */
   msgdomain_list_print (mdlp, file_name, output_syntax, force_po, do_debug);
 
-  if (its_locators)
-    xlocator_list_free (its_locators);
+  if (its_locating_rules)
+    locating_rule_list_free (its_locating_rules);
 
   exit (EXIT_SUCCESS);
 }
diff --git a/gettext-tools/src/xlocator.c b/gettext-tools/src/xlocator.c
deleted file mode 100644 (file)
index e6c331c..0000000
+++ /dev/null
@@ -1,713 +0,0 @@
-/* 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);
-}
index 605e93872c99dc0d8af6e05bec412f84972c8767..e814b8c774c669fe4fa8c66101ad4e06fde8335f 100755 (executable)
@@ -16,26 +16,26 @@ EOF
 ${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
 
 test -d its || mkdir its
-test -d its/locators || mkdir its/locators
-test -d its/rules || mkdir its/rules
 
-cat <<\EOF > its/locators/empty-1.loc
+cat <<\EOF > its/empty-1.loc
 <?xml version="1.0"?>
 <locatingRules/>
 EOF
 
 ${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
 
-cat <<\EOF > its/locators/empty-2.loc
+cat <<\EOF > its/empty-2.loc
 <?xml version="1.0"?>
-<locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0">
-  <documentElement prefix="" localName="empty" uri="empty.its"/>
+<locatingRules>
+  <locatingRule pattern="*.xml">
+    <documentRule prefix="" localName="empty" target="empty.its"/>
+  </locatingRule>
 </locatingRules>
 EOF
 
 ${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
 
-cat <<\EOF > its/rules/empty.its
+cat <<\EOF > its/empty.its
 <?xml version="1.0"?>
 <its:rules xmlns:its="http://www.w3.org/2005/11/its" version="1.0">
 </its:rules>
@@ -43,14 +43,16 @@ EOF
 
 ${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; }
 
-cat <<\EOF > its/locators/messages.loc
+cat <<\EOF > its/messages.loc
 <?xml version="1.0"?>
-<locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0">
-  <documentElement prefix="" localName="messages" uri="messages.its"/>
+<locatingRules>
+  <locatingRule pattern="*.xml">
+    <documentRule localName="messages" target="messages.its"/>
+  </locatingRule>
 </locatingRules>
 EOF
 
-cat <<\EOF > its/rules/messages.its
+cat <<\EOF > its/messages.its
 <?xml version="1.0"?>
 <its:rules xmlns:its="http://www.w3.org/2005/11/its"
            xmlns:msg="http://www.gnu.org/s/gettext/ns/messages/1.0"