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