Tokenize for index_type system.
[idzebra-moved-to-github.git] / util / index_types.c
1 /* $Id: index_types.c,v 1.2 2007-10-25 19:25:00 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 #include <yaz/icu_I18N.h>
35 #include <yaz/match_glob.h>
36 #include <yaz/xmalloc.h>
37 #include <yaz/wrbuf.h>
38 #include <yaz/log.h>
39
40 struct zebra_index_types_s {
41 #if YAZ_HAVE_XML2
42     zebra_index_type_t rules;
43     xmlDocPtr doc;
44 #endif
45 };
46
47 #if YAZ_HAVE_XML2
48 struct zebra_index_type_s {
49     const xmlNode *ptr;
50     const char *id;
51     const char *locale;
52     const char *position;
53     const char *alwaysmatches;
54     const char *firstinfield;
55     int sort_flag;
56     int index_flag;
57     int staticrank_flag;
58     int simple_chain;
59 #if HAVE_ICU
60     struct icu_chain *chain;
61 #endif
62     zebra_index_type_t next;
63     WRBUF simple_buf;
64     size_t simple_off;
65 };
66
67 static void index_type_destroy(zebra_index_type_t t);
68
69 zebra_index_type_t parse_index_type(const xmlNode *ptr)
70 {
71     struct _xmlAttr *attr;
72     struct zebra_index_type_s *rule;
73     
74     rule = xmalloc(sizeof(*rule)); 
75     rule->next = 0;
76 #if HAVE_ICU
77     rule->chain = 0;
78 #endif
79     rule->ptr = ptr;
80     rule->locale = 0;
81     rule->id = 0;
82     rule->position = 0;
83     rule->alwaysmatches = 0;
84     rule->firstinfield = 0;
85     rule->sort_flag = 0;
86     rule->index_flag = 1;
87     rule->staticrank_flag = 0;
88     rule->simple_chain = 0;
89     rule->simple_buf = wrbuf_alloc();
90     for (attr = ptr->properties; attr; attr = attr->next)
91     {
92         if (attr->children && attr->children->type == XML_TEXT_NODE)
93         {
94             if (!strcmp((const char *) attr->name, "id"))
95                 rule->id = (const char *) attr->children->content;
96             else if (!strcmp((const char *) attr->name, "locale"))
97                 rule->locale = (const char *) attr->children->content;
98             else if (!strcmp((const char *) attr->name, "position"))
99                 rule->position = (const char *) attr->children->content;
100             else if (!strcmp((const char *) attr->name, "alwaysmatches"))
101                 rule->alwaysmatches = (const char *) attr->children->content;
102             else if (!strcmp((const char *) attr->name, "firstinfield"))
103                 rule->firstinfield = (const char *) attr->children->content;
104             else if (!strcmp((const char *) attr->name, "index"))
105             {
106                 const char *v = (const char *) attr->children->content;
107                 if (v)
108                     rule->index_flag = *v == '1';
109             }
110             else if (!strcmp((const char *) attr->name, "sort"))
111             {
112                 const char *v = (const char *) attr->children->content;
113                 if (v)
114                     rule->sort_flag = *v == '1';
115             }
116             else if (!strcmp((const char *) attr->name, "staticrank"))
117             {
118                 const char *v = (const char *) attr->children->content;
119                 if (v)
120                     rule->staticrank_flag = *v == '1';
121             }
122             else
123             {
124                 yaz_log(YLOG_WARN, "Unsupport attribute '%s' for indextype",
125                         attr->name);
126                 index_type_destroy(rule);
127                 return 0;
128             }
129         }
130     }
131     ptr = ptr->children;
132     while (ptr && ptr->type != XML_ELEMENT_NODE)
133         ptr = ptr->next;
134     if (!ptr)
135     {
136         yaz_log(YLOG_WARN, "Missing rules for indexrule");
137         index_type_destroy(rule);
138         rule = 0;
139     }
140     else if (!strcmp((const char *) ptr->name, "icu_chain"))
141     {
142 #if HAVE_ICU
143         UErrorCode status;
144         rule->chain = icu_chain_xml_config(ptr,
145                                            rule->locale,
146                                            rule->sort_flag,
147                                            &status);
148         if (!rule->chain)
149         {
150             index_type_destroy(rule);
151             rule = 0;
152         }
153 #else
154         yaz_log(YLOG_WARN, "ICU unsupported (must be part of YAZ)");
155         xfree(rule);
156         rule = 0;
157 #endif
158     }
159     else if (!strcmp((const char *) ptr->name, "simple"))
160     {
161         rule->simple_chain = 1;
162     }
163     else 
164     {
165         yaz_log(YLOG_WARN, "Unsupported mapping %s for indexrule",  ptr->name);
166         index_type_destroy(rule);
167         rule = 0;
168     }
169     return rule;
170 }
171 /* YAZ_HAVE_XML2 */
172 #endif
173
174 zebra_index_types_t zebra_index_types_create(const char *fname)
175 {
176     xmlDocPtr doc = xmlParseFile(fname);
177     if (!doc)
178         return 0;
179     return zebra_index_types_create_doc(doc);
180 }
181
182 zebra_index_types_t zebra_index_types_create_doc(xmlDocPtr doc)
183 {
184 #if YAZ_HAVE_XML2
185     zebra_index_types_t r = xmalloc(sizeof(*r));
186     zebra_index_type_t *rp = &r->rules;
187     const xmlNode *top = xmlDocGetRootElement(doc);
188     
189     r->doc = doc;
190     *rp = 0;
191     if (top && top->type == XML_ELEMENT_NODE
192         && !strcmp((const char *) top->name, "indextypes"))
193     {
194         const xmlNode *ptr = top->children;
195         for (; ptr; ptr = ptr->next)
196         {
197             if (ptr->type == XML_ELEMENT_NODE
198                 && !strcmp((const char *) ptr->name, "indextype"))
199             {
200                 *rp = parse_index_type(ptr);
201                 if (!*rp)
202                 {
203                     zebra_index_types_destroy(r);
204                     return 0;
205                 }
206                 rp = &(*rp)->next;
207             }
208         }
209     }
210     else
211     {
212         zebra_index_types_destroy(r);
213         r = 0;
214     }
215     return r;
216 #else
217     yaz_log(YLOG_WARN, "XML unsupported. Cannot read index rules");
218     return 0;
219 /* YAZ_HAVE_XML2 */
220 #endif
221 }
222
223 static void index_type_destroy(zebra_index_type_t t)
224 {
225     if (t)
226     {
227 #if HAVE_ICU
228         if (t->chain)
229             icu_chain_destroy(t->chain);
230 #endif
231         wrbuf_destroy(t->simple_buf);
232         xfree(t);
233     }
234 }
235
236 void zebra_index_types_destroy(zebra_index_types_t r)
237 {
238     if (r)
239     {
240 #if YAZ_HAVE_XML2
241         zebra_index_type_t rule;
242         while (r->rules)
243         {
244             rule = r->rules;
245             r->rules = rule->next;
246             index_type_destroy(rule);
247         }
248         xmlFreeDoc(r->doc);
249         
250 #endif
251         xfree(r);
252     }
253 }
254
255 zebra_index_type_t zebra_index_type_get(zebra_index_types_t types, 
256                                         const char *id)
257 {
258 #if YAZ_HAVE_XML2
259     zebra_index_type_t rule = types->rules;
260         
261     while (rule && !yaz_match_glob(rule->id, id))
262         rule = rule->next;
263     return rule;
264 #endif
265     return 0;
266 }
267
268 const char *zebra_index_type_lookup_str(zebra_index_types_t types,
269                                         const char *id)
270 {
271     zebra_index_type_t t = zebra_index_type_get(types, id);
272     if (t)
273         return t->id;
274     return 0;
275 }
276
277 int zebra_index_type_is_index(zebra_index_type_t type)
278 {
279     return type->index_flag;
280 }
281
282 int zebra_index_type_is_sort(zebra_index_type_t type)
283 {
284     return type->sort_flag;
285 }
286
287 int zebra_index_type_is_staticrank(zebra_index_type_t type)
288 {
289     return type->staticrank_flag;
290 }
291
292 #define SE_CHARS ";,.()-/?<> \r\n\t"
293
294 int tokenize_simple(zebra_index_type_t type,
295                     const char **result_buf, size_t *result_len)
296 {
297     char *buf = wrbuf_buf(type->simple_buf);
298     size_t len = wrbuf_len(type->simple_buf);
299     size_t i = type->simple_off;
300     size_t start;
301
302     while (i < len && strchr(SE_CHARS, buf[i]))
303         i++;
304     start = i;
305     while (i < len && !strchr(SE_CHARS, buf[i]))
306     {
307         if (buf[i] > 32 && buf[i] < 127)
308             buf[i] = tolower(buf[i]);
309         i++;
310     }
311
312     type->simple_off = i;
313     if (start != i)
314     {
315         *result_buf = buf + start;
316         *result_len = i - start;
317         return 1;
318     }
319     return 0;
320  }
321
322 int zebra_index_type_tokenize(zebra_index_type_t type,
323                               const char *buf, size_t len,
324                               const char **result_buf, size_t *result_len)
325 {
326     if (type->simple_chain)
327     {
328         if (buf)
329         {
330             wrbuf_rewind(type->simple_buf);
331             wrbuf_write(type->simple_buf, buf, len);
332             type->simple_off = 0;
333         }
334         return tokenize_simple(type, result_buf, result_len);
335     }
336     return 0;
337 }
338
339 /*
340  * Local variables:
341  * c-basic-offset: 4
342  * indent-tabs-mode: nil
343  * End:
344  * vim: shiftwidth=4 tabstop=8 expandtab
345  */
346