Merge icu_chain into zebramaps.
[idzebra-moved-to-github.git] / util / index_types.c
1 /* $Id: index_types.c,v 1.3 2007-10-29 08:20:16 adam Exp $
2    Copyright (C) 1995-2007
3    Index Data ApS
4
5    This file is part of the Zebra server.
6
7    Zebra is free software; you can redistribute it and/or modify it under
8    the terms of the GNU General Public License as published by the Free
9    Software Foundation; either version 2, or (at your option) any later
10    version.
11
12    Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13    WARRANTY; without even the implied warranty of MERCHANTABILITY or
14    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15    for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Zebra; see the file LICENSE.zebra.  If not, write to the
19    Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.
21 */
22
23 /** 
24     \file
25     \brief Implementation of Zebra's index types system
26 */
27
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <string.h>
32
33 #include "index_types.h"
34 #if HAVE_ICU
35 #include <yaz/icu_I18N.h>
36 #endif
37 #include <yaz/match_glob.h>
38 #include <yaz/xmalloc.h>
39 #include <yaz/wrbuf.h>
40 #include <yaz/log.h>
41
42 struct zebra_index_types_s {
43 #if YAZ_HAVE_XML2
44     zebra_index_type_t rules;
45     xmlDocPtr doc;
46 #endif
47 };
48
49 #if YAZ_HAVE_XML2
50 struct zebra_index_type_s {
51     const xmlNode *ptr;
52     const char *id;
53     const char *locale;
54     const char *position;
55     const char *alwaysmatches;
56     const char *firstinfield;
57     int sort_flag;
58     int index_flag;
59     int staticrank_flag;
60     int simple_chain;
61 #if HAVE_ICU
62     struct icu_chain *chain;
63 #endif
64     zebra_index_type_t next;
65     WRBUF simple_buf;
66     size_t simple_off;
67 };
68
69 static void index_type_destroy(zebra_index_type_t t);
70
71 zebra_index_type_t parse_index_type(const xmlNode *ptr)
72 {
73     struct _xmlAttr *attr;
74     struct zebra_index_type_s *rule;
75     
76     rule = xmalloc(sizeof(*rule)); 
77     rule->next = 0;
78 #if HAVE_ICU
79     rule->chain = 0;
80 #endif
81     rule->ptr = ptr;
82     rule->locale = 0;
83     rule->id = 0;
84     rule->position = 0;
85     rule->alwaysmatches = 0;
86     rule->firstinfield = 0;
87     rule->sort_flag = 0;
88     rule->index_flag = 1;
89     rule->staticrank_flag = 0;
90     rule->simple_chain = 0;
91     rule->simple_buf = wrbuf_alloc();
92     for (attr = ptr->properties; attr; attr = attr->next)
93     {
94         if (attr->children && attr->children->type == XML_TEXT_NODE)
95         {
96             if (!strcmp((const char *) attr->name, "id"))
97                 rule->id = (const char *) attr->children->content;
98             else if (!strcmp((const char *) attr->name, "locale"))
99                 rule->locale = (const char *) attr->children->content;
100             else if (!strcmp((const char *) attr->name, "position"))
101                 rule->position = (const char *) attr->children->content;
102             else if (!strcmp((const char *) attr->name, "alwaysmatches"))
103                 rule->alwaysmatches = (const char *) attr->children->content;
104             else if (!strcmp((const char *) attr->name, "firstinfield"))
105                 rule->firstinfield = (const char *) attr->children->content;
106             else if (!strcmp((const char *) attr->name, "index"))
107             {
108                 const char *v = (const char *) attr->children->content;
109                 if (v)
110                     rule->index_flag = *v == '1';
111             }
112             else if (!strcmp((const char *) attr->name, "sort"))
113             {
114                 const char *v = (const char *) attr->children->content;
115                 if (v)
116                     rule->sort_flag = *v == '1';
117             }
118             else if (!strcmp((const char *) attr->name, "staticrank"))
119             {
120                 const char *v = (const char *) attr->children->content;
121                 if (v)
122                     rule->staticrank_flag = *v == '1';
123             }
124             else
125             {
126                 yaz_log(YLOG_WARN, "Unsupport attribute '%s' for indextype",
127                         attr->name);
128                 index_type_destroy(rule);
129                 return 0;
130             }
131         }
132     }
133     ptr = ptr->children;
134     while (ptr && ptr->type != XML_ELEMENT_NODE)
135         ptr = ptr->next;
136     if (!ptr)
137     {
138         yaz_log(YLOG_WARN, "Missing rules for indexrule");
139         index_type_destroy(rule);
140         rule = 0;
141     }
142     else if (!strcmp((const char *) ptr->name, "icu_chain"))
143     {
144 #if HAVE_ICU
145         UErrorCode status;
146         rule->chain = icu_chain_xml_config(ptr,
147                                            rule->locale,
148                                            rule->sort_flag,
149                                            &status);
150         if (!rule->chain)
151         {
152             index_type_destroy(rule);
153             rule = 0;
154         }
155 #else
156         yaz_log(YLOG_WARN, "ICU unsupported (must be part of YAZ)");
157         xfree(rule);
158         rule = 0;
159 #endif
160     }
161     else if (!strcmp((const char *) ptr->name, "simple"))
162     {
163         rule->simple_chain = 1;
164     }
165     else 
166     {
167         yaz_log(YLOG_WARN, "Unsupported mapping %s for indexrule",  ptr->name);
168         index_type_destroy(rule);
169         rule = 0;
170     }
171     return rule;
172 }
173 /* YAZ_HAVE_XML2 */
174 #endif
175
176 zebra_index_types_t zebra_index_types_create(const char *fname)
177 {
178     xmlDocPtr doc = xmlParseFile(fname);
179     if (!doc)
180         return 0;
181     return zebra_index_types_create_doc(doc);
182 }
183
184 zebra_index_types_t zebra_index_types_create_doc(xmlDocPtr doc)
185 {
186 #if YAZ_HAVE_XML2
187     zebra_index_types_t r = xmalloc(sizeof(*r));
188     zebra_index_type_t *rp = &r->rules;
189     const xmlNode *top = xmlDocGetRootElement(doc);
190     
191     r->doc = doc;
192     *rp = 0;
193     if (top && top->type == XML_ELEMENT_NODE
194         && !strcmp((const char *) top->name, "indextypes"))
195     {
196         const xmlNode *ptr = top->children;
197         for (; ptr; ptr = ptr->next)
198         {
199             if (ptr->type == XML_ELEMENT_NODE
200                 && !strcmp((const char *) ptr->name, "indextype"))
201             {
202                 *rp = parse_index_type(ptr);
203                 if (!*rp)
204                 {
205                     zebra_index_types_destroy(r);
206                     return 0;
207                 }
208                 rp = &(*rp)->next;
209             }
210         }
211     }
212     else
213     {
214         zebra_index_types_destroy(r);
215         r = 0;
216     }
217     return r;
218 #else
219     yaz_log(YLOG_WARN, "XML unsupported. Cannot read index rules");
220     return 0;
221 /* YAZ_HAVE_XML2 */
222 #endif
223 }
224
225 static void index_type_destroy(zebra_index_type_t t)
226 {
227     if (t)
228     {
229 #if HAVE_ICU
230         if (t->chain)
231             icu_chain_destroy(t->chain);
232 #endif
233         wrbuf_destroy(t->simple_buf);
234         xfree(t);
235     }
236 }
237
238 void zebra_index_types_destroy(zebra_index_types_t r)
239 {
240     if (r)
241     {
242 #if YAZ_HAVE_XML2
243         zebra_index_type_t rule;
244         while (r->rules)
245         {
246             rule = r->rules;
247             r->rules = rule->next;
248             index_type_destroy(rule);
249         }
250         xmlFreeDoc(r->doc);
251         
252 #endif
253         xfree(r);
254     }
255 }
256
257 zebra_index_type_t zebra_index_type_get(zebra_index_types_t types, 
258                                         const char *id)
259 {
260 #if YAZ_HAVE_XML2
261     zebra_index_type_t rule = types->rules;
262         
263     while (rule && !yaz_match_glob(rule->id, id))
264         rule = rule->next;
265     return rule;
266 #endif
267     return 0;
268 }
269
270 const char *zebra_index_type_lookup_str(zebra_index_types_t types,
271                                         const char *id)
272 {
273     zebra_index_type_t t = zebra_index_type_get(types, id);
274     if (t)
275         return t->id;
276     return 0;
277 }
278
279 int zebra_index_type_is_index(zebra_index_type_t type)
280 {
281     return type->index_flag;
282 }
283
284 int zebra_index_type_is_sort(zebra_index_type_t type)
285 {
286     return type->sort_flag;
287 }
288
289 int zebra_index_type_is_staticrank(zebra_index_type_t type)
290 {
291     return type->staticrank_flag;
292 }
293
294 #define SE_CHARS ";,.()-/?<> \r\n\t"
295
296 int tokenize_simple(zebra_index_type_t type,
297                     const char **result_buf, size_t *result_len)
298 {
299     char *buf = wrbuf_buf(type->simple_buf);
300     size_t len = wrbuf_len(type->simple_buf);
301     size_t i = type->simple_off;
302     size_t start;
303
304     while (i < len && strchr(SE_CHARS, buf[i]))
305         i++;
306     start = i;
307     while (i < len && !strchr(SE_CHARS, buf[i]))
308     {
309         if (buf[i] > 32 && buf[i] < 127)
310             buf[i] = tolower(buf[i]);
311         i++;
312     }
313
314     type->simple_off = i;
315     if (start != i)
316     {
317         *result_buf = buf + start;
318         *result_len = i - start;
319         return 1;
320     }
321     return 0;
322  }
323
324 int zebra_index_type_tokenize(zebra_index_type_t type,
325                               const char *buf, size_t len,
326                               const char **result_buf, size_t *result_len)
327 {
328     if (type->simple_chain)
329     {
330         if (buf)
331         {
332             wrbuf_rewind(type->simple_buf);
333             wrbuf_write(type->simple_buf, buf, len);
334             type->simple_off = 0;
335         }
336         return tokenize_simple(type, result_buf, result_len);
337     }
338     return 0;
339 }
340
341 /*
342  * Local variables:
343  * c-basic-offset: 4
344  * indent-tabs-mode: nil
345  * End:
346  * vim: shiftwidth=4 tabstop=8 expandtab
347  */
348