Changed error handling for unknown zebra maps.
[idzebra-moved-to-github.git] / util / zebramap.c
1 /* $Id: zebramap.c,v 1.63 2007-11-05 11:36:23 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_files_read;
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     return zm;
106 }
107
108 static int parse_command(zebra_maps_t zms, int argc, char **argv,
109                          const char *fname, int lineno)
110 {
111     zebra_map_t zm = zms->last_map;
112     if (argc == 1)
113     {
114         yaz_log(YLOG_WARN, "%s:%d: Missing arguments for '%s'",
115                 fname, lineno, argv[0]);
116         return -1;
117     }
118     if (argc > 2)
119     {
120         yaz_log(YLOG_WARN, "%s:%d: Too many arguments for '%s'",
121                 fname, lineno, argv[0]);
122         return -1;
123     }
124     if (!yaz_matchstr(argv[0], "index"))
125     {
126         zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_INDEX);
127         zm->positioned = 1;
128     }
129     else if (!yaz_matchstr(argv[0], "sort"))
130     {
131         zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_SORT);
132         zm->u.sort.entry_size = 80;
133     }
134     else if (!yaz_matchstr(argv[0], "staticrank"))
135     {
136         zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_STATICRANK);
137         zm->completeness = 1;
138     }
139     else if (!zm)
140     {
141         yaz_log(YLOG_WARN, "%s:%d: Missing sort/index before '%s'",  
142                 fname, lineno, argv[0]);
143         return -1;
144     }
145     else if (!yaz_matchstr(argv[0], "charmap") && argc == 2)
146     {
147         if (zm->type != ZEBRA_MAP_TYPE_STATICRANK)
148             zm->maptab_name = nmem_strdup(zms->nmem, argv[1]);
149         else
150         {
151             yaz_log(YLOG_WARN|YLOG_FATAL, "%s:%d: charmap for "
152                     "staticrank is invalid", fname, lineno);
153             yaz_log(YLOG_LOG, "Type is %d", zm->type);
154             return -1;
155         }
156     }
157     else if (!yaz_matchstr(argv[0], "completeness") && argc == 2)
158     {
159         zm->completeness = atoi(argv[1]);
160     }
161     else if (!yaz_matchstr(argv[0], "position") && argc == 2)
162     {
163         zm->positioned = atoi(argv[1]);
164     }
165     else if (!yaz_matchstr(argv[0], "alwaysmatches") && argc == 2)
166     {
167         if (zm->type != ZEBRA_MAP_TYPE_STATICRANK)
168             zm->alwaysmatches = atoi(argv[1]);
169         else
170         {
171             yaz_log(YLOG_WARN|YLOG_FATAL, "%s:%d: alwaysmatches for "
172                     "staticrank is invalid", fname, lineno);
173             return -1;
174         }
175     }
176     else if (!yaz_matchstr(argv[0], "firstinfield") && argc == 2)
177     {
178         zm->first_in_field = atoi(argv[1]);
179     }
180     else if (!yaz_matchstr(argv[0], "entrysize") && argc == 2)
181     {
182         if (zm->type == ZEBRA_MAP_TYPE_SORT)
183             zm->u.sort.entry_size = atoi(argv[1]);
184         else
185         {
186             yaz_log(YLOG_WARN, 
187                     "%s:%d: entrysize only valid in sort section",  
188                     fname, lineno);
189             return -1;
190         }
191     }
192     else
193     {
194         yaz_log(YLOG_WARN, "%s:%d: Unrecognized directive '%s'",  
195                 fname, lineno, argv[0]);
196         return -1;
197     }
198     return 0;
199 }
200
201 ZEBRA_RES zebra_maps_read_file(zebra_maps_t zms, const char *fname)
202 {
203     FILE *f;
204     char line[512];
205     char *argv[10];
206     int argc;
207     int lineno = 0;
208     int failures = 0;
209
210     if (!(f = yaz_fopen(zms->tabpath, fname, "r", zms->tabroot)))
211     {
212         yaz_log(YLOG_ERRNO|YLOG_FATAL, "%s", fname);
213         return ZEBRA_FAIL;
214     }
215     while ((argc = readconf_line(f, &lineno, line, 512, argv, 10)))
216     {
217         int r = parse_command(zms, argc, argv, fname, lineno);
218         if (r)
219             failures++;
220     }
221     yaz_fclose(f);
222
223     if (failures)
224         return ZEBRA_FAIL;
225
226     (zms->no_files_read)++;
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->tabpath = profile_path ? nmem_strdup(zms->nmem, profile_path) : 0;
237     zms->tabroot = 0;
238     if (base_path)
239         zms->tabroot = nmem_strdup(zms->nmem, base_path);
240     zms->map_list = 0;
241     zms->last_map = 0;
242
243     zms->temp_map_str[0] = '\0';
244     zms->temp_map_str[1] = '\0';
245
246     zms->temp_map_ptr[0] = zms->temp_map_str;
247     zms->temp_map_ptr[1] = NULL;
248
249     zms->wrbuf_1 = wrbuf_alloc();
250
251     zms->no_files_read = 0;
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 read from file */
272         if (zms->no_files_read)
273             yaz_log(YLOG_WARN, "Unknown register type: %s", id);
274
275         zm->maptab_name = nmem_strdup(zms->nmem, "@");
276         zm->completeness = 0;
277         zm->positioned = 1;
278     }
279     return zm;
280 }
281
282 chrmaptab zebra_charmap_get(zebra_map_t zm)
283 {
284     if (!zm->maptab)
285     {
286         if (!zm->maptab_name || !yaz_matchstr(zm->maptab_name, "@"))
287             return NULL;
288         if (!(zm->maptab = chrmaptab_create(zm->zebra_maps->tabpath,
289                                             zm->maptab_name,
290                                             zm->zebra_maps->tabroot)))
291             yaz_log(YLOG_WARN, "Failed to read character table %s",
292                     zm->maptab_name);
293         else
294             yaz_log(YLOG_DEBUG, "Read character table %s", zm->maptab_name);
295     }
296     return zm->maptab;
297 }
298
299 const char **zebra_maps_input(zebra_map_t zm,
300                               const char **from, int len, int first)
301 {
302     chrmaptab maptab = zebra_charmap_get(zm);
303     if (maptab)
304         return chr_map_input(maptab, from, len, first);
305     
306     zm->zebra_maps->temp_map_str[0] = **from;
307
308     (*from)++;
309     return zm->zebra_maps->temp_map_ptr;
310 }
311
312 const char **zebra_maps_search(zebra_map_t zm,
313                                const char **from, int len,  int *q_map_match)
314 {
315     chrmaptab maptab;
316     
317     *q_map_match = 0;
318     maptab = zebra_charmap_get(zm);
319     if (maptab)
320     {
321         const char **map;
322         map = chr_map_q_input(maptab, from, len, 0);
323         if (map && map[0])
324         {
325             *q_map_match = 1;
326             return map;
327         }
328         map = chr_map_input(maptab, from, len, 0);
329         if (map)
330             return map;
331     }
332     zm->zebra_maps->temp_map_str[0] = **from;
333
334     (*from)++;
335     return zm->zebra_maps->temp_map_ptr;
336 }
337
338 const char *zebra_maps_output(zebra_map_t zm,
339                               const char **from)
340 {
341     chrmaptab maptab = zebra_charmap_get(zm);
342     if (!maptab)
343         return 0;
344     return chr_map_output(maptab, from, 1);
345 }
346
347
348 /* ------------------------------------ */
349
350 int zebra_maps_is_complete(zebra_map_t zm)
351
352     if (zm)
353         return zm->completeness;
354     return 0;
355 }
356
357 int zebra_maps_is_positioned(zebra_map_t zm)
358 {
359     if (zm)
360         return zm->positioned;
361     return 0;
362 }
363
364 int zebra_maps_is_index(zebra_map_t zm)
365 {
366     if (zm)
367         return zm->type == ZEBRA_MAP_TYPE_INDEX;
368     return 0;
369 }
370
371 int zebra_maps_is_staticrank(zebra_map_t zm)
372 {
373     if (zm)
374         return zm->type == ZEBRA_MAP_TYPE_STATICRANK;
375     return 0;
376 }
377     
378 int zebra_maps_is_sort(zebra_map_t zm)
379 {
380     if (zm)
381         return zm->type == ZEBRA_MAP_TYPE_SORT;
382     return 0;
383 }
384
385 int zebra_maps_is_alwaysmatches(zebra_map_t zm)
386 {
387     if (zm)
388         return zm->alwaysmatches;
389     return 0;
390 }
391
392 int zebra_maps_is_first_in_field(zebra_map_t zm)
393 {
394     if (zm)
395         return zm->first_in_field;
396     return 0;
397 }
398
399 int zebra_maps_sort(zebra_maps_t zms, Z_SortAttributes *sortAttributes,
400                     int *numerical)
401 {
402     AttrType use;
403     AttrType structure;
404     int structure_value;
405     attr_init_AttrList(&use, sortAttributes->list, 1);
406     attr_init_AttrList(&structure, sortAttributes->list, 4);
407
408     *numerical = 0;
409     structure_value = attr_find(&structure, 0);
410     if (structure_value == 109)
411         *numerical = 1;
412     return attr_find(&use, NULL);
413 }
414
415 int zebra_maps_attr(zebra_maps_t zms, Z_AttributesPlusTerm *zapt,
416                     const char **index_type, char **search_type, char *rank_type,
417                     int *complete_flag, int *sort_flag)
418 {
419     AttrType completeness;
420     AttrType structure;
421     AttrType relation;
422     AttrType sort_relation;
423     AttrType weight;
424     AttrType use;
425     int completeness_value;
426     int structure_value;
427     const char *structure_str = 0;
428     int relation_value;
429     int sort_relation_value;
430     int weight_value;
431     int use_value;
432
433     attr_init_APT(&structure, zapt, 4);
434     attr_init_APT(&completeness, zapt, 6);
435     attr_init_APT(&relation, zapt, 2);
436     attr_init_APT(&sort_relation, zapt, 7);
437     attr_init_APT(&weight, zapt, 9);
438     attr_init_APT(&use, zapt, 1);
439
440     completeness_value = attr_find(&completeness, NULL);
441     structure_value = attr_find_ex(&structure, NULL, &structure_str);
442     relation_value = attr_find(&relation, NULL);
443     sort_relation_value = attr_find(&sort_relation, NULL);
444     weight_value = attr_find(&weight, NULL);
445     use_value = attr_find(&use, NULL);
446
447     if (completeness_value == 2 || completeness_value == 3)
448         *complete_flag = 1;
449     else
450         *complete_flag = 0;
451     *index_type = 0;
452
453     *sort_flag =(sort_relation_value > 0) ? 1 : 0;
454     *search_type = "phrase";
455     strcpy(rank_type, "void");
456     if (relation_value == 102)
457     {
458         if (weight_value == -1)
459             weight_value = 34;
460         sprintf(rank_type, "rank,w=%d,u=%d", weight_value, use_value);
461     }
462     if (*complete_flag)
463         *index_type = "p";
464     else
465         *index_type = "w";
466     switch (structure_value)
467     {
468     case 6:   /* word list */
469         *search_type = "and-list";
470         break;
471     case 105: /* free-form-text */
472         *search_type = "or-list";
473         break;
474     case 106: /* document-text */
475         *search_type = "or-list";
476         break;  
477     case -1:
478     case 1:   /* phrase */
479     case 2:   /* word */
480     case 108: /* string */ 
481         *search_type = "phrase";
482         break;
483     case 107: /* local-number */
484         *search_type = "local";
485         *index_type = 0;
486         break;
487     case 109: /* numeric string */
488         *index_type = "n";
489         *search_type = "numeric";
490         break;
491     case 104: /* urx */
492         *index_type = "u";
493         *search_type = "phrase";
494         break;
495     case 3:   /* key */
496         *index_type = "0";
497         *search_type = "phrase";
498         break;
499     case 4:  /* year */
500         *index_type = "y";
501         *search_type = "phrase";
502         break;
503     case 5:  /* date */
504         *index_type = "d";
505         *search_type = "phrase";
506         break;
507     case -2:
508         if (structure_str && *structure_str)
509             *index_type = structure_str;
510         else
511             return -1;
512         break;
513     default:
514         return -1;
515     }
516     return 0;
517 }
518
519 WRBUF zebra_replace(zebra_map_t zm, const char *ex_list,
520                     const char *input_str, int input_len)
521 {
522     wrbuf_rewind(zm->zebra_maps->wrbuf_1);
523     wrbuf_write(zm->zebra_maps->wrbuf_1, input_str, input_len);
524     return zm->zebra_maps->wrbuf_1;
525 }
526
527 /*
528  * Local variables:
529  * c-basic-offset: 4
530  * indent-tabs-mode: nil
531  * End:
532  * vim: shiftwidth=4 tabstop=8 expandtab
533  */
534