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