xml_include fails if file is not found YAZ-668
[yaz-moved-to-github.git] / src / xml_include.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
5
6 /** \file
7     \brief XML Include (not to be confused with W3C XInclude)
8 */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <yaz/file_glob.h>
14
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <assert.h>
20 #include <yaz/wrbuf.h>
21 #include <yaz/tpath.h>
22 #include <yaz/log.h>
23 #include <yaz/xml_include.h>
24
25 #if YAZ_HAVE_XML2
26
27 #include <libxml/parser.h>
28 #include <libxml/tree.h>
29
30 struct yaz_xml_include_s {
31     const char *confdir;
32 };
33
34 typedef struct yaz_xml_include_s *yaz_xml_include_t;
35
36 static int process_config_includes(yaz_xml_include_t config, xmlNode *n);
37
38 static void conf_dir_path(yaz_xml_include_t config, WRBUF w, const char *src)
39 {
40     if (config->confdir && *config->confdir > 0 &&
41         !yaz_is_abspath(src))
42     {
43         wrbuf_printf(w, "%s/%s", config->confdir, src);
44     }
45     else
46         wrbuf_puts(w, src);
47 }
48
49 static int config_include_one(yaz_xml_include_t config, xmlNode **sib,
50                               const char *path)
51 {
52     struct stat st;
53     if (stat(path, &st) < 0)
54     {
55         yaz_log(YLOG_FATAL|YLOG_ERRNO, "stat %s", path);
56         return -1;
57     }
58     else
59     {
60         if ((st.st_mode & S_IFMT) == S_IFREG)
61         {
62             xmlDoc *doc = xmlParseFile(path);
63             if (doc)
64             {
65                 xmlNodePtr t = xmlDocGetRootElement(doc);
66                 int ret = process_config_includes(config, t);
67                 *sib = xmlAddNextSibling(*sib, xmlCopyNode(t, 1));
68                 xmlFreeDoc(doc);
69                 if (ret)
70                     return -1;
71             }
72             else
73             {
74                 yaz_log(YLOG_FATAL, "Could not parse %s", path);
75                 return -1;
76             }
77         }
78     }
79     return 0;
80 }
81
82 static int config_include_src(yaz_xml_include_t config, xmlNode **np,
83                               const char *src)
84 {
85     int ret = 0; /* return code. OK so far */
86     WRBUF w = wrbuf_alloc();
87     xmlNodePtr sib; /* our sibling that we append */
88     xmlNodePtr c; /* tmp node */
89
90     wrbuf_printf(w, " begin include src=\"%s\" ", src);
91
92     /* replace include element with a 'begin' comment */
93     sib = xmlNewComment((const xmlChar *) wrbuf_cstr(w));
94     xmlReplaceNode(*np, sib);
95
96     xmlFreeNode(*np);
97
98     wrbuf_rewind(w);
99     conf_dir_path(config, w, src);
100     {
101         int glob_ret;
102         yaz_glob_res_t glob_res;
103
104         glob_ret = yaz_file_glob(wrbuf_cstr(w), &glob_res);
105         yaz_log(YLOG_LOG, "yaz_file_glob returned w=%s %d", wrbuf_cstr(w),
106                 glob_ret);
107         if (glob_ret == 0)
108         {
109             size_t i;
110             const char *path;
111             for (i = 0; (path = yaz_file_glob_get_file(glob_res, i)); i++)
112                 ret = config_include_one(config, &sib, path);
113             yaz_file_globfree(&glob_res);
114         }
115     }
116     wrbuf_rewind(w);
117     wrbuf_printf(w, " end include src=\"%s\" ", src);
118     c = xmlNewComment((const xmlChar *) wrbuf_cstr(w));
119     sib = xmlAddNextSibling(sib, c);
120
121     *np = sib;
122     wrbuf_destroy(w);
123     return ret;
124 }
125
126 static int process_config_includes(yaz_xml_include_t config, xmlNode *n)
127 {
128     for (n = n->children; n; n = n->next)
129     {
130         if (n->type == XML_ELEMENT_NODE)
131         {
132             if (!strcmp((const char *) n->name, "include"))
133             {
134                 xmlChar *src = xmlGetProp(n, (xmlChar *) "src");
135                 if (src)
136                 {
137                     int ret = config_include_src(config, &n,
138                                                  (const char *) src);
139                     xmlFree(src);
140                     if (ret)
141                         return ret;
142
143                 }
144             }
145             else
146             {
147                 if (process_config_includes(config, n))
148                     return -1;
149             }
150         }
151     }
152     return 0;
153 }
154
155 int yaz_xml_include_simple(xmlNode *n, const char *base_path)
156 {
157     struct yaz_xml_include_s s;
158
159     s.confdir = base_path;
160     return process_config_includes(&s, n);
161 }
162
163 /* YAZ_HAVE_XML2 */
164 #endif
165
166 /*
167  * Local variables:
168  * c-basic-offset: 4
169  * c-file-style: "Stroustrup"
170  * indent-tabs-mode: nil
171  * End:
172  * vim: shiftwidth=4 tabstop=8 expandtab
173  */
174