Refactor zebramaps parsing
[idzebra-moved-to-github.git] / util / zebramap.c
1 /* $Id: zebramap.c,v 1.62 2007-11-05 11:27:24 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 #include <assert.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26
27 #include <charmap.h>
28 #include <attrfind.h>
29 #include <yaz/yaz-util.h>
30
31 #include <zebramap.h>
32
33 #define ZEBRA_MAP_TYPE_SORT  1
34 #define ZEBRA_MAP_TYPE_INDEX 2
35 #define ZEBRA_MAP_TYPE_STATICRANK 3
36
37 #define ZEBRA_REPLACE_ANY  300
38
39 struct zebra_map {
40     const char *id;
41     int completeness;
42     int positioned;
43     int alwaysmatches;
44     int first_in_field;
45     int type;
46     union {
47         struct {
48             int entry_size;
49         } sort;
50     } u;
51     chrmaptab maptab;
52     const char *maptab_name;
53     zebra_maps_t zebra_maps;
54     struct zebra_map *next;
55 };
56
57 struct zebra_maps_s {
58     char *tabpath;
59     char *tabroot;
60     NMEM nmem;
61     char temp_map_str[2];
62     const char *temp_map_ptr[2];
63     WRBUF wrbuf_1;
64     int no_maps;
65     zebra_map_t map_list;
66     zebra_map_t last_map;
67 };
68
69 void zebra_maps_close(zebra_maps_t zms)
70 {
71     struct zebra_map *zm = zms->map_list;
72     while (zm)
73     {
74         if (zm->maptab)
75             chrmaptab_destroy(zm->maptab);
76         zm = zm->next;
77     }
78     wrbuf_destroy(zms->wrbuf_1);
79     nmem_destroy(zms->nmem);
80     xfree(zms);
81 }
82
83 zebra_map_t zebra_add_map(zebra_maps_t zms, const char *index_type,
84                           int map_type)
85 {
86     zebra_map_t zm = (zebra_map_t) nmem_malloc(zms->nmem, sizeof(*zm));
87
88     zm->zebra_maps = zms;
89     zm->id = nmem_strdup(zms->nmem, index_type);
90     zm->maptab_name = 0;
91     zm->maptab = 0;
92     zm->type = map_type;
93     zm->completeness = 0;
94     zm->positioned = 0;
95     zm->alwaysmatches = 0;
96     zm->first_in_field = 0;
97
98     if (zms->last_map)
99         zms->last_map->next = zm;
100     else
101         zms->map_list = zm;
102     zms->last_map = zm;
103     zm->next = 0;
104
105     zms->no_maps++;
106
107     return zm;
108 }
109
110 static int parse_command(zebra_maps_t zms, int argc, char **argv,
111                          const char *fname, int lineno)
112 {
113     zebra_map_t zm = zms->last_map;
114     if (argc == 1)
115     {
116         yaz_log(YLOG_WARN, "%s:%d: Missing arguments for '%s'",
117                 fname, lineno, argv[0]);
118         return -1;
119     }
120     if (argc > 2)
121     {
122         yaz_log(YLOG_WARN, "%s:%d: Too many arguments for '%s'",
123                 fname, lineno, argv[0]);
124         return -1;
125     }
126     if (!yaz_matchstr(argv[0], "index"))
127     {
128         zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_INDEX);
129         zm->positioned = 1;
130     }
131     else if (!yaz_matchstr(argv[0], "sort"))
132     {
133         zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_SORT);
134         zm->u.sort.entry_size = 80;
135     }
136     else if (!yaz_matchstr(argv[0], "staticrank"))
137     {
138         zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_STATICRANK);
139         zm->completeness = 1;
140     }
141     else if (!zm)
142     {
143         yaz_log(YLOG_WARN, "%s:%d: Missing sort/index before '%s'",  
144                 fname, lineno, argv[0]);
145         return -1;
146     }
147     else if (!yaz_matchstr(argv[0], "charmap") && argc == 2)
148     {
149         if (zm->type != ZEBRA_MAP_TYPE_STATICRANK)
150             zm->maptab_name = nmem_strdup(zms->nmem, argv[1]);
151         else
152         {
153             yaz_log(YLOG_WARN|YLOG_FATAL, "%s:%d: charmap for "
154                     "staticrank is invalid", fname, lineno);
155             yaz_log(YLOG_LOG, "Type is %d", zm->type);
156             return -1;
157         }
158     }
159     else if (!yaz_matchstr(argv[0], "completeness") && argc == 2)
160     {
161         zm->completeness = atoi(argv[1]);
162     }
163     else if (!yaz_matchstr(argv[0], "position") && argc == 2)
164     {
165         zm->positioned = atoi(argv[1]);
166     }
167     else if (!yaz_matchstr(argv[0], "alwaysmatches") && argc == 2)
168     {
169         if (zm->type != ZEBRA_MAP_TYPE_STATICRANK)
170             zm->alwaysmatches = atoi(argv[1]);
171         else
172         {
173             yaz_log(YLOG_WARN|YLOG_FATAL, "%s:%d: alwaysmatches for "
174                     "staticrank is invalid", fname, lineno);
175             return -1;
176         }
177     }
178     else if (!yaz_matchstr(argv[0], "firstinfield") && argc == 2)
179     {
180         zm->first_in_field = atoi(argv[1]);
181     }
182     else if (!yaz_matchstr(argv[0], "entrysize") && argc == 2)
183     {
184         if (zm->type == ZEBRA_MAP_TYPE_SORT)
185             zm->u.sort.entry_size = atoi(argv[1]);
186         else
187         {
188             yaz_log(YLOG_WARN, 
189                     "%s:%d: entrysize only valid in sort section",  
190                     fname, lineno);
191             return -1;
192         }
193     }
194     else
195     {
196         yaz_log(YLOG_WARN, "%s:%d: Unrecognized directive '%s'",  
197                 fname, lineno, argv[0]);
198         return -1;
199     }
200     return 0;
201 }
202
203 ZEBRA_RES zebra_maps_read_file(zebra_maps_t zms, const char *fname)
204 {
205     FILE *f;
206     char line[512];
207     char *argv[10];
208     int argc;
209     int lineno = 0;
210     int failures = 0;
211
212     if (!(f = yaz_fopen(zms->tabpath, fname, "r", zms->tabroot)))
213     {
214         yaz_log(YLOG_ERRNO|YLOG_FATAL, "%s", fname);
215         return ZEBRA_FAIL;
216     }
217     while ((argc = readconf_line(f, &lineno, line, 512, argv, 10)))
218     {
219         int r = parse_command(zms, argc, argv, fname, lineno);
220         if (r)
221             failures++;
222     }
223     yaz_fclose(f);
224
225     if (failures)
226         return ZEBRA_FAIL;
227     return ZEBRA_OK;
228 }
229
230 zebra_maps_t zebra_maps_open(Res res, const char *base_path,
231                              const char *profile_path)
232 {
233     zebra_maps_t zms = (zebra_maps_t) xmalloc(sizeof(*zms));
234
235     zms->nmem = nmem_create();
236     zms->no_maps = 0;
237     zms->tabpath = profile_path ? nmem_strdup(zms->nmem, profile_path) : 0;
238     zms->tabroot = 0;
239     if (base_path)
240         zms->tabroot = nmem_strdup(zms->nmem, base_path);
241     zms->map_list = 0;
242     zms->last_map = 0;
243
244     zms->temp_map_str[0] = '\0';
245     zms->temp_map_str[1] = '\0';
246
247     zms->temp_map_ptr[0] = zms->temp_map_str;
248     zms->temp_map_ptr[1] = NULL;
249
250     zms->wrbuf_1 = wrbuf_alloc();
251
252     return zms;
253 }
254
255 zebra_map_t zebra_map_get(zebra_maps_t zms, const char *id)
256 {
257     zebra_map_t zm;
258     for (zm = zms->map_list; zm; zm = zm->next)
259         if (!strcmp(zm->id, id))
260             break;
261     return zm;
262 }
263
264 zebra_map_t zebra_map_get_or_add(zebra_maps_t zms, const char *id)
265 {
266     struct zebra_map *zm = zebra_map_get(zms, id);
267     if (!zm)
268     {
269         zm = zebra_add_map(zms, id, ZEBRA_MAP_TYPE_INDEX);
270         
271         /* no reason to warn if no maps are installed at ALL 
272          Note that zebra_add_maps increments no_maps .. 
273         */
274         if (zms->no_maps > 1)
275             yaz_log(YLOG_WARN, "Unknown register type: %s", id);
276         else
277             zms->no_maps = 0;
278
279         zm->maptab_name = nmem_strdup(zms->nmem, "@");
280         zm->completeness = 0;
281         zm->positioned = 1;
282     }
283     return zm;
284 }
285
286 chrmaptab zebra_charmap_get(zebra_map_t zm)
287 {
288     if (!zm->maptab)
289     {
290         if (!zm->maptab_name || !yaz_matchstr(zm->maptab_name, "@"))
291             return NULL;
292         if (!(zm->maptab = chrmaptab_create(zm->zebra_maps->tabpath,
293                                             zm->maptab_name,
294                                             zm->zebra_maps->tabroot)))
295             yaz_log(YLOG_WARN, "Failed to read character table %s",
296                     zm->maptab_name);
297         else
298             yaz_log(YLOG_DEBUG, "Read character table %s", zm->maptab_name);
299     }
300     return zm->maptab;
301 }
302
303 const char **zebra_maps_input(zebra_map_t zm,
304                               const char **from, int len, int first)
305 {
306     chrmaptab maptab = zebra_charmap_get(zm);
307     if (maptab)
308         return chr_map_input(maptab, from, len, first);
309     
310     zm->zebra_maps->temp_map_str[0] = **from;
311
312     (*from)++;
313     return zm->zebra_maps->temp_map_ptr;
314 }
315
316 const char **zebra_maps_search(zebra_map_t zm,
317                                const char **from, int len,  int *q_map_match)
318 {
319     chrmaptab maptab;
320     
321     *q_map_match = 0;
322     maptab = zebra_charmap_get(zm);
323     if (maptab)
324     {
325         const char **map;
326         map = chr_map_q_input(maptab, from, len, 0);
327         if (map && map[0])
328         {
329             *q_map_match = 1;
330             return map;
331         }
332         map = chr_map_input(maptab, from, len, 0);
333         if (map)
334             return map;
335     }
336     zm->zebra_maps->temp_map_str[0] = **from;
337
338     (*from)++;
339     return zm->zebra_maps->temp_map_ptr;
340 }
341
342 const char *zebra_maps_output(zebra_map_t zm,
343                               const char **from)
344 {
345     chrmaptab maptab = zebra_charmap_get(zm);
346     if (!maptab)
347         return 0;
348     return chr_map_output(maptab, from, 1);
349 }
350
351
352 /* ------------------------------------ */
353
354 int zebra_maps_is_complete(zebra_map_t zm)
355
356     if (zm)
357         return zm->completeness;
358     return 0;
359 }
360
361 int zebra_maps_is_positioned(zebra_map_t zm)
362 {
363     if (zm)
364         return zm->positioned;
365     return 0;
366 }
367
368 int zebra_maps_is_index(zebra_map_t zm)
369 {
370     if (zm)
371         return zm->type == ZEBRA_MAP_TYPE_INDEX;
372     return 0;
373 }
374
375 int zebra_maps_is_staticrank(zebra_map_t zm)
376 {
377     if (zm)
378         return zm->type == ZEBRA_MAP_TYPE_STATICRANK;
379     return 0;
380 }
381     
382 int zebra_maps_is_sort(zebra_map_t zm)
383 {
384     if (zm)
385         return zm->type == ZEBRA_MAP_TYPE_SORT;
386     return 0;
387 }
388
389 int zebra_maps_is_alwaysmatches(zebra_map_t zm)
390 {
391     if (zm)
392         return zm->alwaysmatches;
393     return 0;
394 }
395
396 int zebra_maps_is_first_in_field(zebra_map_t zm)
397 {
398     if (zm)
399         return zm->first_in_field;
400     return 0;
401 }
402
403 int zebra_maps_sort(zebra_maps_t zms, Z_SortAttributes *sortAttributes,
404                     int *numerical)
405 {
406     AttrType use;
407     AttrType structure;
408     int structure_value;
409     attr_init_AttrList(&use, sortAttributes->list, 1);
410     attr_init_AttrList(&structure, sortAttributes->list, 4);
411
412     *numerical = 0;
413     structure_value = attr_find(&structure, 0);
414     if (structure_value == 109)
415         *numerical = 1;
416     return attr_find(&use, NULL);
417 }
418
419 int zebra_maps_attr(zebra_maps_t zms, Z_AttributesPlusTerm *zapt,
420                     const char **index_type, char **search_type, char *rank_type,
421                     int *complete_flag, int *sort_flag)
422 {
423     AttrType completeness;
424     AttrType structure;
425     AttrType relation;
426     AttrType sort_relation;
427     AttrType weight;
428     AttrType use;
429     int completeness_value;
430     int structure_value;
431     const char *structure_str = 0;
432     int relation_value;
433     int sort_relation_value;
434     int weight_value;
435     int use_value;
436
437     attr_init_APT(&structure, zapt, 4);
438     attr_init_APT(&completeness, zapt, 6);
439     attr_init_APT(&relation, zapt, 2);
440     attr_init_APT(&sort_relation, zapt, 7);
441     attr_init_APT(&weight, zapt, 9);
442     attr_init_APT(&use, zapt, 1);
443
444     completeness_value = attr_find(&completeness, NULL);
445     structure_value = attr_find_ex(&structure, NULL, &structure_str);
446     relation_value = attr_find(&relation, NULL);
447     sort_relation_value = attr_find(&sort_relation, NULL);
448     weight_value = attr_find(&weight, NULL);
449     use_value = attr_find(&use, NULL);
450
451     if (completeness_value == 2 || completeness_value == 3)
452         *complete_flag = 1;
453     else
454         *complete_flag = 0;
455     *index_type = 0;
456
457     *sort_flag =(sort_relation_value > 0) ? 1 : 0;
458     *search_type = "phrase";
459     strcpy(rank_type, "void");
460     if (relation_value == 102)
461     {
462         if (weight_value == -1)
463             weight_value = 34;
464         sprintf(rank_type, "rank,w=%d,u=%d", weight_value, use_value);
465     }
466     if (*complete_flag)
467         *index_type = "p";
468     else
469         *index_type = "w";
470     switch (structure_value)
471     {
472     case 6:   /* word list */
473         *search_type = "and-list";
474         break;
475     case 105: /* free-form-text */
476         *search_type = "or-list";
477         break;
478     case 106: /* document-text */
479         *search_type = "or-list";
480         break;  
481     case -1:
482     case 1:   /* phrase */
483     case 2:   /* word */
484     case 108: /* string */ 
485         *search_type = "phrase";
486         break;
487     case 107: /* local-number */
488         *search_type = "local";
489         *index_type = 0;
490         break;
491     case 109: /* numeric string */
492         *index_type = "n";
493         *search_type = "numeric";
494         break;
495     case 104: /* urx */
496         *index_type = "u";
497         *search_type = "phrase";
498         break;
499     case 3:   /* key */
500         *index_type = "0";
501         *search_type = "phrase";
502         break;
503     case 4:  /* year */
504         *index_type = "y";
505         *search_type = "phrase";
506         break;
507     case 5:  /* date */
508         *index_type = "d";
509         *search_type = "phrase";
510         break;
511     case -2:
512         if (structure_str && *structure_str)
513             *index_type = structure_str;
514         else
515             return -1;
516         break;
517     default:
518         return -1;
519     }
520     return 0;
521 }
522
523 WRBUF zebra_replace(zebra_map_t zm, const char *ex_list,
524                     const char *input_str, int input_len)
525 {
526     wrbuf_rewind(zm->zebra_maps->wrbuf_1);
527     wrbuf_write(zm->zebra_maps->wrbuf_1, input_str, input_len);
528     return zm->zebra_maps->wrbuf_1;
529 }
530
531 /*
532  * Local variables:
533  * c-basic-offset: 4
534  * indent-tabs-mode: nil
535  * End:
536  * vim: shiftwidth=4 tabstop=8 expandtab
537  */
538