b96e9f0e459ddac5be0600ad5b5fe3b332b27e47
[idzebra-moved-to-github.git] / util / zebramap.c
1 /* $Id: zebramap.c,v 1.60 2007-10-30 19:17:15 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     unsigned reg_id;
41     int completeness;
42     int positioned;
43     int alwaysmatches;
44     int first_in_field;
45     int type;
46     union {
47         struct {
48             int dummy;
49         } index;
50         struct {
51             int entry_size;
52         } sort;
53     } u;
54     chrmaptab maptab;
55     const char *maptab_name;
56     zebra_maps_t zebra_maps;
57     struct zebra_map *next;
58 };
59
60 struct zebra_maps_s {
61     char *tabpath;
62     char *tabroot;
63     NMEM nmem;
64     char temp_map_str[2];
65     const char *temp_map_ptr[2];
66     struct zebra_map **lookup_array;
67     WRBUF wrbuf_1;
68     int no_maps;
69     zebra_map_t map_list;
70     zebra_map_t *last_map;
71 };
72
73 void zebra_maps_close(zebra_maps_t zms)
74 {
75     struct zebra_map *zm = zms->map_list;
76     while (zm)
77     {
78         if (zm->maptab)
79             chrmaptab_destroy(zm->maptab);
80         zm = zm->next;
81     }
82     wrbuf_destroy(zms->wrbuf_1);
83     nmem_destroy(zms->nmem);
84     xfree(zms);
85 }
86
87 zebra_map_t zebra_add_map(zebra_maps_t zms, const char *index_type,
88                           int map_type)
89 {
90     zebra_map_t zm = (zebra_map_t) nmem_malloc(zms->nmem, sizeof(*zm));
91
92     zm->zebra_maps = zms;
93     zm->reg_id = index_type[0];
94     zm->maptab_name = 0;
95     zm->maptab = 0;
96     zm->type = map_type;
97     zm->completeness = 0;
98     zm->positioned = 0;
99     zm->alwaysmatches = 0;
100     zm->first_in_field = 0;
101
102     zm->next = 0;
103     *zms->last_map = zm;
104     zms->last_map = &zm->next;
105
106     zms->no_maps++;
107
108     return zm;
109 }
110
111 ZEBRA_RES zebra_maps_read_file(zebra_maps_t zms, const char *fname)
112 {
113     FILE *f;
114     char line[512];
115     char *argv[10];
116     int argc;
117     int lineno = 0;
118     int failures = 0;
119     zebra_map_t zm = 0;
120
121     if (!(f = yaz_fopen(zms->tabpath, fname, "r", zms->tabroot)))
122     {
123         yaz_log(YLOG_ERRNO|YLOG_FATAL, "%s", fname);
124         return ZEBRA_FAIL;
125     }
126     while ((argc = readconf_line(f, &lineno, line, 512, argv, 10)))
127     {
128         if (argc == 1)
129         {
130             yaz_log(YLOG_WARN, "%s:%d: Missing arguments for '%s'",
131                     fname, lineno, argv[0]);
132             failures++;
133             break;
134         }
135         if (argc > 2)
136         {
137             yaz_log(YLOG_WARN, "%s:%d: Too many arguments for '%s'",
138                     fname, lineno, argv[0]);
139             failures++;
140             break;
141         }
142         if (!yaz_matchstr(argv[0], "index"))
143         {
144             zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_INDEX);
145             zm->positioned = 1;
146         }
147         else if (!yaz_matchstr(argv[0], "sort"))
148         {
149             zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_SORT);
150             zm->u.sort.entry_size = 80;
151         }
152         else if (!yaz_matchstr(argv[0], "staticrank"))
153         {
154             zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_STATICRANK);
155             zm->completeness = 1;
156         }
157         else if (!zm)
158         {
159             yaz_log(YLOG_WARN, "%s:%d: Missing sort/index before '%s'",  
160                     fname, lineno, argv[0]);
161             failures++;
162         }
163         else if (!yaz_matchstr(argv[0], "charmap") && argc == 2)
164         {
165             if (zm->type != ZEBRA_MAP_TYPE_STATICRANK)
166                 zm->maptab_name = nmem_strdup(zms->nmem, argv[1]);
167             else
168             {
169                 yaz_log(YLOG_WARN|YLOG_FATAL, "%s:%d: charmap for "
170                         "staticrank is invalid", fname, lineno);
171                 yaz_log(YLOG_LOG, "Type is %d", zm->type);
172                 failures++;
173             }
174         }
175         else if (!yaz_matchstr(argv[0], "completeness") && argc == 2)
176         {
177             zm->completeness = atoi(argv[1]);
178         }
179         else if (!yaz_matchstr(argv[0], "position") && argc == 2)
180         {
181             zm->positioned = atoi(argv[1]);
182         }
183         else if (!yaz_matchstr(argv[0], "alwaysmatches") && argc == 2)
184         {
185             if (zm->type != ZEBRA_MAP_TYPE_STATICRANK)
186                 zm->alwaysmatches = atoi(argv[1]);
187             else
188             {
189                 yaz_log(YLOG_WARN|YLOG_FATAL, "%s:%d: alwaysmatches for "
190                         "staticrank is invalid", fname, lineno);
191                 failures++;
192             }
193         }
194         else if (!yaz_matchstr(argv[0], "firstinfield") && argc == 2)
195         {
196             zm->first_in_field = atoi(argv[1]);
197         }
198         else if (!yaz_matchstr(argv[0], "entrysize") && argc == 2)
199         {
200             if (zm->type == ZEBRA_MAP_TYPE_SORT)
201                 zm->u.sort.entry_size = atoi(argv[1]);
202         }
203         else
204         {
205             yaz_log(YLOG_WARN, "%s:%d: Unrecognized directive '%s'",  
206                     fname, lineno, argv[0]);
207             failures++;
208         }
209     }
210     yaz_fclose(f);
211
212     for (zm = zms->map_list; zm; zm = zm->next)
213         zms->lookup_array[zm->reg_id] = zm;
214
215     if (failures)
216         return ZEBRA_FAIL;
217     return ZEBRA_OK;
218 }
219
220 zebra_maps_t zebra_maps_open(Res res, const char *base_path,
221                           const char *profile_path)
222 {
223     zebra_maps_t zms = (zebra_maps_t) xmalloc(sizeof(*zms));
224     int i;
225
226     zms->nmem = nmem_create();
227     zms->no_maps = 0;
228     zms->tabpath = profile_path ? nmem_strdup(zms->nmem, profile_path) : 0;
229     zms->tabroot = 0;
230     if (base_path)
231         zms->tabroot = nmem_strdup(zms->nmem, base_path);
232     zms->map_list = 0;
233     zms->last_map = &zms->map_list;
234
235     zms->temp_map_str[0] = '\0';
236     zms->temp_map_str[1] = '\0';
237
238     zms->temp_map_ptr[0] = zms->temp_map_str;
239     zms->temp_map_ptr[1] = NULL;
240
241     zms->lookup_array = (zebra_map_t *)
242         nmem_malloc(zms->nmem, sizeof(*zms->lookup_array)*256);
243     zms->wrbuf_1 = wrbuf_alloc();
244
245     for (i = 0; i<256; i++)
246         zms->lookup_array[i] = 0;
247     return zms;
248 }
249
250 zebra_map_t zebra_map_get(zebra_maps_t zms, unsigned reg_id)
251 {
252     assert(reg_id >= 0 && reg_id <= 255);
253     return zms->lookup_array[reg_id];
254 }
255
256 zebra_map_t zebra_map_get_or_add(zebra_maps_t zms, unsigned reg_id)
257 {
258     struct zebra_map *zm = zebra_map_get(zms, reg_id);
259     if (!zm)
260     {
261         char name[2];
262         name[0] = reg_id;
263         name[1] = '\0';
264
265         zm = zebra_add_map(zms, name, ZEBRA_MAP_TYPE_INDEX);
266         
267         /* no reason to warn if no maps are installed at ALL 
268          Note that zebra_add_maps increments no_maps .. 
269         */
270         if (zms->no_maps > 1)
271             yaz_log(YLOG_WARN, "Unknown register type: %c", reg_id);
272         else
273             zms->no_maps = 0;
274
275         zm->maptab_name = nmem_strdup(zms->nmem, "@");
276         zm->completeness = 0;
277         zm->positioned = 1;
278         zm->next = zms->map_list;
279         zms->map_list = zm->next;
280
281         zms->lookup_array[zm->reg_id & 255] = zm;
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