1 /* XML resource locating rules
2 Copyright (C) 2015 Free Software Foundation, Inc.
4 This file was written by Daiki Ueno <ueno@gnu.org>, 2015.
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
24 #include "locating-rule.h"
27 #include "concat-filename.h"
28 #include "c-strcase.h"
47 #include <libxml/parser.h>
48 #include <libxml/uri.h>
51 #define _(str) gettext (str)
53 #define LOCATING_RULES_NS "https://www.gnu.org/s/gettext/ns/locating-rules/1.0"
55 struct document_locating_rule_ty
63 struct document_locating_rule_list_ty
65 struct document_locating_rule_ty *items;
70 struct locating_rule_ty
75 struct document_locating_rule_list_ty doc_rules;
79 struct locating_rule_list_ty
81 struct locating_rule_ty *items;
87 get_attribute (xmlNode *node, const char *attr)
92 value = xmlGetProp (node, BAD_CAST attr);
93 result = xstrdup ((const char *) value);
100 document_locating_rule_match (struct document_locating_rule_ty *rule,
105 root = xmlDocGetRootElement (doc);
106 if (rule->ns != NULL)
109 || !xmlStrEqual (root->ns->href, BAD_CAST rule->ns))
113 if (rule->local_name != NULL)
115 if (!xmlStrEqual (root->name,
116 BAD_CAST rule->local_name))
124 locating_rule_match (struct locating_rule_ty *rule,
125 const char *filename,
130 if (rule->name == NULL || c_strcasecmp (name, rule->name) != 0)
139 base = strrchr (filename, '/');
143 reduced = xstrdup (base);
144 /* Remove a trailing ".in" - it's a generic suffix. */
145 while (strlen (reduced) >= 3
146 && memcmp (reduced + strlen (reduced) - 3, ".in", 3) == 0)
147 reduced[strlen (reduced) - 3] = '\0';
149 err = fnmatch (rule->pattern, basename (reduced), FNM_PATHNAME);
155 /* Check documentRules. */
156 if (rule->doc_rules.nitems > 0)
162 doc = xmlReadFile (filename, NULL,
164 | XML_PARSE_NOWARNING
166 | XML_PARSE_NOERROR);
169 xmlError *err = xmlGetLastError ();
170 error (0, 0, _("cannot read %s: %s"), filename, err->message);
174 for (i = 0, target = NULL; i < rule->doc_rules.nitems; i++)
177 document_locating_rule_match (&rule->doc_rules.items[i], doc);
186 if (rule->target != NULL)
193 locating_rule_list_locate (struct locating_rule_list_ty *rules,
194 const char *filename,
197 const char *target = NULL;
200 for (i = 0; i < rules->nitems; i++)
202 if (IS_ABSOLUTE_PATH (filename))
204 target = locating_rule_match (&rules->items[i], filename, name);
214 const char *dir = dir_list_nth (j);
220 new_filename = xconcatenated_filename (dir, filename, NULL);
221 target = locating_rule_match (&rules->items[i], new_filename,
234 missing_attribute (xmlNode *node, const char *attribute)
236 error (0, 0, _("\"%s\" node does not have \"%s\""), node->name, attribute);
240 document_locating_rule_destroy (struct document_locating_rule_ty *rule)
243 free (rule->local_name);
248 document_locating_rule_list_add (struct document_locating_rule_list_ty *rules,
251 struct document_locating_rule_ty rule;
253 if (!xmlHasProp (node, BAD_CAST "target"))
255 missing_attribute (node, "target");
259 memset (&rule, 0, sizeof (struct document_locating_rule_ty));
261 if (xmlHasProp (node, BAD_CAST "ns"))
262 rule.ns = get_attribute (node, "ns");
263 if (xmlHasProp (node, BAD_CAST "localName"))
264 rule.local_name = get_attribute (node, "localName");
265 rule.target = get_attribute (node, "target");
267 if (rules->nitems == rules->nitems_max)
269 rules->nitems_max = 2 * rules->nitems_max + 1;
271 xrealloc (rules->items,
272 sizeof (struct document_locating_rule_ty)
273 * rules->nitems_max);
275 memcpy (&rules->items[rules->nitems++], &rule,
276 sizeof (struct document_locating_rule_ty));
280 locating_rule_destroy (struct locating_rule_ty *rule)
284 for (i = 0; i < rule->doc_rules.nitems; i++)
285 document_locating_rule_destroy (&rule->doc_rules.items[i]);
286 free (rule->doc_rules.items);
289 free (rule->pattern);
294 locating_rule_list_add_from_file (struct locating_rule_list_ty *rules,
295 const char *rule_file_name)
298 xmlNode *root, *node;
300 doc = xmlReadFile (rule_file_name, "utf-8",
302 | XML_PARSE_NOWARNING
304 | XML_PARSE_NOERROR);
307 error (0, 0, _("cannot read XML file %s"), rule_file_name);
311 root = xmlDocGetRootElement (doc);
312 if (!(xmlStrEqual (root->name, BAD_CAST "locatingRules")
315 && xmlStrEqual (root->ns->href, BAD_CAST LOCATING_RULES_NS)
319 error (0, 0, _("the root element is not \"locatingRules\""));
324 for (node = root->children; node; node = node->next)
326 if (xmlStrEqual (node->name, BAD_CAST "locatingRule"))
328 struct locating_rule_ty rule;
330 if (!xmlHasProp (node, BAD_CAST "pattern"))
332 missing_attribute (node, "pattern");
337 memset (&rule, 0, sizeof (struct locating_rule_ty));
338 rule.pattern = get_attribute (node, "pattern");
339 if (xmlHasProp (node, BAD_CAST "name"))
340 rule.name = get_attribute (node, "name");
341 if (xmlHasProp (node, BAD_CAST "target"))
342 rule.target = get_attribute (node, "target");
347 for (n = node->children; n; n = n->next)
349 if (xmlStrEqual (n->name, BAD_CAST "documentRule"))
350 document_locating_rule_list_add (&rule.doc_rules, n);
353 if (rules->nitems == rules->nitems_max)
355 rules->nitems_max = 2 * rules->nitems_max + 1;
357 xrealloc (rules->items,
358 sizeof (struct locating_rule_ty) * rules->nitems_max);
360 memcpy (&rules->items[rules->nitems++], &rule,
361 sizeof (struct locating_rule_ty));
370 locating_rule_list_add_from_directory (struct locating_rule_list_ty *rules,
371 const char *directory)
376 dirp = opendir (directory);
388 const char *name = dp->d_name;
389 size_t namlen = strlen (name);
391 if (namlen > 4 && memcmp (name + namlen - 4, ".loc", 4) == 0)
393 char *locator_file_name =
394 xconcatenated_filename (directory, name, NULL);
395 locating_rule_list_add_from_file (rules, locator_file_name);
396 free (locator_file_name);
411 struct locating_rule_list_ty *
412 locating_rule_list_alloc (void)
414 struct locating_rule_list_ty *result;
416 xmlCheckVersion (LIBXML_VERSION);
418 result = XCALLOC (1, struct locating_rule_list_ty);
424 locating_rule_list_destroy (struct locating_rule_list_ty *rules)
426 while (rules->nitems-- > 0)
427 locating_rule_destroy (&rules->items[rules->nitems]);
432 locating_rule_list_free (struct locating_rule_list_ty *rules)
435 locating_rule_list_destroy (rules);