1 /* This file is part of the Zebra server.
2    Copyright (C) 2004-2013 Index Data
3 
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8 
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 
18 */
19 
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
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 #if YAZ_HAVE_ICU
32 #include <yaz/icu.h>
33 #endif
34 #include <zebramap.h>
35 
36 #define ZEBRA_MAP_TYPE_SORT  1
37 #define ZEBRA_MAP_TYPE_INDEX 2
38 #define ZEBRA_MAP_TYPE_STATICRANK 3
39 
40 #define ZEBRA_REPLACE_ANY  300
41 
42 struct zebra_map {
43     const char *id;
44     int completeness;
45     int positioned;
46     int alwaysmatches;
47     int first_in_field;
48     int type;
49     int use_chain;
50     int debug;
51     union {
52         struct {
53             int entry_size;
54         } sort;
55     } u;
56     chrmaptab maptab;
57     const char *maptab_name;
58     zebra_maps_t zebra_maps;
59 #if YAZ_HAVE_XML2
60     xmlDocPtr doc;
61 #endif
62 #if YAZ_HAVE_ICU
63     struct icu_chain *icu_chain;
64 #endif
65     WRBUF input_str;
66     WRBUF print_str;
67     size_t simple_off;
68     struct zebra_map *next;
69 };
70 
71 struct zebra_maps_s {
72     char *tabpath;
73     char *tabroot;
74     NMEM nmem;
75     char temp_map_str[2];
76     const char *temp_map_ptr[2];
77     WRBUF wrbuf_1;
78     int no_files_read;
79     zebra_map_t map_list;
80     zebra_map_t last_map;
81 };
82 
zebra_maps_close(zebra_maps_t zms)83 void zebra_maps_close(zebra_maps_t zms)
84 {
85     struct zebra_map *zm = zms->map_list;
86     while (zm)
87     {
88 	if (zm->maptab)
89 	    chrmaptab_destroy(zm->maptab);
90 #if YAZ_HAVE_ICU
91         if (zm->icu_chain)
92             icu_chain_destroy(zm->icu_chain);
93 #endif
94 #if YAZ_HAVE_XML2
95         xmlFreeDoc(zm->doc);
96 #endif
97         wrbuf_destroy(zm->input_str);
98         wrbuf_destroy(zm->print_str);
99 	zm = zm->next;
100     }
101     wrbuf_destroy(zms->wrbuf_1);
102     nmem_destroy(zms->nmem);
103     xfree(zms);
104 }
105 
zebra_add_map(zebra_maps_t zms,const char * index_type,int map_type)106 zebra_map_t zebra_add_map(zebra_maps_t zms, const char *index_type,
107                           int map_type)
108 {
109     zebra_map_t zm = (zebra_map_t) nmem_malloc(zms->nmem, sizeof(*zm));
110 
111     zm->zebra_maps = zms;
112     zm->id = nmem_strdup(zms->nmem, index_type);
113     zm->maptab_name = 0;
114     zm->use_chain = 0;
115     zm->debug = 0;
116     zm->maptab = 0;
117     zm->type = map_type;
118     zm->completeness = 0;
119     zm->positioned = 0;
120     zm->alwaysmatches = 0;
121     zm->first_in_field = 0;
122 
123     if (zms->last_map)
124         zms->last_map->next = zm;
125     else
126         zms->map_list = zm;
127     zms->last_map = zm;
128     zm->next = 0;
129 #if YAZ_HAVE_ICU
130     zm->icu_chain = 0;
131 #endif
132 #if YAZ_HAVE_XML2
133     zm->doc = 0;
134 #endif
135     zm->input_str = wrbuf_alloc();
136     zm->print_str = wrbuf_alloc();
137     return zm;
138 }
139 
parse_command(zebra_maps_t zms,int argc,char ** argv,const char * fname,int lineno)140 static int parse_command(zebra_maps_t zms, int argc, char **argv,
141                          const char *fname, int lineno)
142 {
143     zebra_map_t zm = zms->last_map;
144     if (argc == 1)
145     {
146         yaz_log(YLOG_WARN, "%s:%d: Missing arguments for '%s'",
147                 fname, lineno, argv[0]);
148         return -1;
149     }
150     if (argc > 2)
151     {
152         yaz_log(YLOG_WARN, "%s:%d: Too many arguments for '%s'",
153                 fname, lineno, argv[0]);
154         return -1;
155     }
156     if (!yaz_matchstr(argv[0], "index"))
157     {
158         zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_INDEX);
159         zm->positioned = 1;
160     }
161     else if (!yaz_matchstr(argv[0], "sort"))
162     {
163         zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_SORT);
164         zm->u.sort.entry_size = 80;
165     }
166     else if (!yaz_matchstr(argv[0], "staticrank"))
167     {
168         zm = zebra_add_map(zms, argv[1], ZEBRA_MAP_TYPE_STATICRANK);
169         zm->completeness = 1;
170     }
171     else if (!zm)
172     {
173         yaz_log(YLOG_WARN, "%s:%d: Missing sort/index before '%s'",
174                 fname, lineno, argv[0]);
175         return -1;
176     }
177     else if (!yaz_matchstr(argv[0], "charmap") && argc == 2)
178     {
179         if (zm->type != ZEBRA_MAP_TYPE_STATICRANK)
180             zm->maptab_name = nmem_strdup(zms->nmem, argv[1]);
181         else
182         {
183             yaz_log(YLOG_WARN|YLOG_FATAL, "%s:%d: charmap for "
184                     "staticrank is invalid", fname, lineno);
185             yaz_log(YLOG_LOG, "Type is %d", zm->type);
186             return -1;
187         }
188     }
189     else if (!yaz_matchstr(argv[0], "completeness") && argc == 2)
190     {
191         zm->completeness = atoi(argv[1]);
192     }
193     else if (!yaz_matchstr(argv[0], "position") && argc == 2)
194     {
195         zm->positioned = atoi(argv[1]);
196     }
197     else if (!yaz_matchstr(argv[0], "alwaysmatches") && argc == 2)
198     {
199         if (zm->type != ZEBRA_MAP_TYPE_STATICRANK)
200             zm->alwaysmatches = atoi(argv[1]);
201         else
202         {
203             yaz_log(YLOG_WARN|YLOG_FATAL, "%s:%d: alwaysmatches for "
204                     "staticrank is invalid", fname, lineno);
205             return -1;
206         }
207     }
208     else if (!yaz_matchstr(argv[0], "firstinfield") && argc == 2)
209     {
210         zm->first_in_field = atoi(argv[1]);
211     }
212     else if (!yaz_matchstr(argv[0], "entrysize") && argc == 2)
213     {
214         if (zm->type == ZEBRA_MAP_TYPE_SORT)
215             zm->u.sort.entry_size = atoi(argv[1]);
216         else
217         {
218             yaz_log(YLOG_WARN,
219                     "%s:%d: entrysize only valid in sort section",
220                     fname, lineno);
221             return -1;
222         }
223     }
224     else if (!yaz_matchstr(argv[0], "simplechain"))
225     {
226         zm->use_chain = 1;
227 #if YAZ_HAVE_ICU
228         zm->icu_chain = 0;
229 #endif
230     }
231     else if (!yaz_matchstr(argv[0], "icuchain"))
232     {
233         char full_path[1024];
234         if (!yaz_filepath_resolve(argv[1], zms->tabpath, zms->tabroot,
235                                   full_path))
236         {
237             yaz_log(YLOG_WARN, "%s:%d: Could not locate icuchain config '%s'",
238                     fname, lineno, argv[1]);
239             return -1;
240         }
241 #if YAZ_HAVE_XML2
242         zm->doc = xmlParseFile(full_path);
243         if (!zm->doc)
244         {
245             yaz_log(YLOG_WARN, "%s:%d: Could not load icuchain config '%s'",
246                     fname, lineno, argv[1]);
247             return -1;
248         }
249         else
250         {
251 #if YAZ_HAVE_ICU
252             UErrorCode status;
253             xmlNode *xml_node = xmlDocGetRootElement(zm->doc);
254             zm->icu_chain =
255                 icu_chain_xml_config(xml_node,
256 /* not sure about sort for this function yet.. */
257 #if 1
258                                      1,
259 #else
260                                      zm->type == ZEBRA_MAP_TYPE_SORT,
261 #endif
262                                      &status);
263             if (!zm->icu_chain)
264             {
265                 yaz_log(YLOG_WARN, "%s:%d: Failed to load ICU chain %s",
266                         fname, lineno, argv[1]);
267             }
268             zm->use_chain = 1;
269 #else
270             yaz_log(YLOG_WARN, "%s:%d: ICU support unavailable",
271                     fname, lineno);
272             return -1;
273 #endif
274         }
275 #else
276         yaz_log(YLOG_WARN, "%s:%d: XML support unavailable",
277                 fname, lineno);
278         return -1;
279 #endif
280     }
281     else if (!yaz_matchstr(argv[0], "debug") && argc == 2)
282     {
283         zm->debug = atoi(argv[1]);
284     }
285     else
286     {
287         yaz_log(YLOG_WARN, "%s:%d: Unrecognized directive '%s'",
288                 fname, lineno, argv[0]);
289         return -1;
290     }
291     return 0;
292 }
293 
zebra_maps_read_file(zebra_maps_t zms,const char * fname)294 ZEBRA_RES zebra_maps_read_file(zebra_maps_t zms, const char *fname)
295 {
296     FILE *f;
297     char line[512];
298     char *argv[10];
299     int argc;
300     int lineno = 0;
301     int failures = 0;
302 
303     if (!(f = yaz_fopen(zms->tabpath, fname, "r", zms->tabroot)))
304     {
305 	yaz_log(YLOG_ERRNO|YLOG_FATAL, "%s", fname);
306 	return ZEBRA_FAIL;
307     }
308     while ((argc = readconf_line(f, &lineno, line, 512, argv, 10)))
309     {
310         int r = parse_command(zms, argc, argv, fname, lineno);
311         if (r)
312             failures++;
313     }
314     yaz_fclose(f);
315 
316     if (failures)
317         return ZEBRA_FAIL;
318 
319     (zms->no_files_read)++;
320     return ZEBRA_OK;
321 }
322 
zebra_maps_open(Res res,const char * base_path,const char * profile_path)323 zebra_maps_t zebra_maps_open(Res res, const char *base_path,
324                              const char *profile_path)
325 {
326     zebra_maps_t zms = (zebra_maps_t) xmalloc(sizeof(*zms));
327 
328     zms->nmem = nmem_create();
329     zms->tabpath = profile_path ? nmem_strdup(zms->nmem, profile_path) : 0;
330     zms->tabroot = 0;
331     if (base_path)
332         zms->tabroot = nmem_strdup(zms->nmem, base_path);
333     zms->map_list = 0;
334     zms->last_map = 0;
335 
336     zms->temp_map_str[0] = '\0';
337     zms->temp_map_str[1] = '\0';
338 
339     zms->temp_map_ptr[0] = zms->temp_map_str;
340     zms->temp_map_ptr[1] = NULL;
341 
342     zms->wrbuf_1 = wrbuf_alloc();
343 
344     zms->no_files_read = 0;
345     return zms;
346 }
347 
zebra_maps_define_default_sort(zebra_maps_t zms)348 void zebra_maps_define_default_sort(zebra_maps_t zms)
349 {
350     zebra_map_t zm = zebra_add_map(zms, "s", ZEBRA_MAP_TYPE_SORT);
351     zm->u.sort.entry_size = 80;
352 }
353 
zebra_map_get(zebra_maps_t zms,const char * id)354 zebra_map_t zebra_map_get(zebra_maps_t zms, const char *id)
355 {
356     zebra_map_t zm;
357     for (zm = zms->map_list; zm; zm = zm->next)
358         if (!strcmp(zm->id, id))
359             break;
360     return zm;
361 }
362 
zebra_map_get_or_add(zebra_maps_t zms,const char * id)363 zebra_map_t zebra_map_get_or_add(zebra_maps_t zms, const char *id)
364 {
365     struct zebra_map *zm = zebra_map_get(zms, id);
366     if (!zm)
367     {
368         zm = zebra_add_map(zms, id, ZEBRA_MAP_TYPE_INDEX);
369 
370 	/* no reason to warn if no maps are read from file */
371 	if (zms->no_files_read)
372 	    yaz_log(YLOG_WARN, "Unknown register type: %s", id);
373 
374 	zm->maptab_name = nmem_strdup(zms->nmem, "@");
375 	zm->completeness = 0;
376         zm->positioned = 1;
377     }
378     return zm;
379 }
380 
zebra_charmap_get(zebra_map_t zm)381 chrmaptab zebra_charmap_get(zebra_map_t zm)
382 {
383     if (!zm->maptab)
384     {
385 	if (!zm->maptab_name || !yaz_matchstr(zm->maptab_name, "@"))
386 	    return NULL;
387 	if (!(zm->maptab = chrmaptab_create(zm->zebra_maps->tabpath,
388 					    zm->maptab_name,
389 					    zm->zebra_maps->tabroot)))
390 	    yaz_log(YLOG_WARN, "Failed to read character table %s",
391 		    zm->maptab_name);
392 	else
393 	    yaz_log(YLOG_DEBUG, "Read character table %s", zm->maptab_name);
394     }
395     return zm->maptab;
396 }
397 
zebra_maps_input(zebra_map_t zm,const char ** from,int len,int first)398 const char **zebra_maps_input(zebra_map_t zm,
399 			      const char **from, int len, int first)
400 {
401     chrmaptab maptab = zebra_charmap_get(zm);
402     if (maptab)
403 	return chr_map_input(maptab, from, len, first);
404 
405     zm->zebra_maps->temp_map_str[0] = **from;
406 
407     (*from)++;
408     return zm->zebra_maps->temp_map_ptr;
409 }
410 
zebra_maps_search(zebra_map_t zm,const char ** from,int len,int * q_map_match)411 const char **zebra_maps_search(zebra_map_t zm,
412 			       const char **from, int len,  int *q_map_match)
413 {
414     chrmaptab maptab;
415 
416     *q_map_match = 0;
417     maptab = zebra_charmap_get(zm);
418     if (maptab)
419     {
420 	const char **map;
421 	map = chr_map_q_input(maptab, from, len, 0);
422 	if (map && map[0])
423 	{
424 	    *q_map_match = 1;
425 	    return map;
426 	}
427 	map = chr_map_input(maptab, from, len, 0);
428 	if (map)
429 	    return map;
430     }
431     zm->zebra_maps->temp_map_str[0] = **from;
432 
433     (*from)++;
434     return zm->zebra_maps->temp_map_ptr;
435 }
436 
zebra_maps_output(zebra_map_t zm,const char ** from)437 const char *zebra_maps_output(zebra_map_t zm,
438 			      const char **from)
439 {
440     chrmaptab maptab = zebra_charmap_get(zm);
441     if (!maptab)
442 	return 0;
443     return chr_map_output(maptab, from, 1);
444 }
445 
446 
447 /* ------------------------------------ */
448 
zebra_maps_is_complete(zebra_map_t zm)449 int zebra_maps_is_complete(zebra_map_t zm)
450 {
451     if (zm)
452 	return zm->completeness;
453     return 0;
454 }
455 
zebra_maps_is_positioned(zebra_map_t zm)456 int zebra_maps_is_positioned(zebra_map_t zm)
457 {
458     if (zm)
459 	return zm->positioned;
460     return 0;
461 }
462 
zebra_maps_is_index(zebra_map_t zm)463 int zebra_maps_is_index(zebra_map_t zm)
464 {
465     if (zm)
466 	return zm->type == ZEBRA_MAP_TYPE_INDEX;
467     return 0;
468 }
469 
zebra_maps_is_staticrank(zebra_map_t zm)470 int zebra_maps_is_staticrank(zebra_map_t zm)
471 {
472     if (zm)
473 	return zm->type == ZEBRA_MAP_TYPE_STATICRANK;
474     return 0;
475 }
476 
zebra_maps_is_sort(zebra_map_t zm)477 int zebra_maps_is_sort(zebra_map_t zm)
478 {
479     if (zm)
480 	return zm->type == ZEBRA_MAP_TYPE_SORT;
481     return 0;
482 }
483 
zebra_maps_is_alwaysmatches(zebra_map_t zm)484 int zebra_maps_is_alwaysmatches(zebra_map_t zm)
485 {
486     if (zm)
487 	return zm->alwaysmatches;
488     return 0;
489 }
490 
zebra_maps_is_first_in_field(zebra_map_t zm)491 int zebra_maps_is_first_in_field(zebra_map_t zm)
492 {
493     if (zm)
494 	return zm->first_in_field;
495     return 0;
496 }
497 
zebra_maps_sort(zebra_maps_t zms,Z_SortAttributes * sortAttributes,int * numerical)498 int zebra_maps_sort(zebra_maps_t zms, Z_SortAttributes *sortAttributes,
499 		    int *numerical)
500 {
501     AttrType use;
502     AttrType structure;
503     int structure_value;
504     attr_init_AttrList(&use, sortAttributes->list, 1);
505     attr_init_AttrList(&structure, sortAttributes->list, 4);
506 
507     *numerical = 0;
508     structure_value = attr_find(&structure, 0);
509     if (structure_value == 109)
510         *numerical = 1;
511     return attr_find(&use, NULL);
512 }
513 
zebra_maps_attr(zebra_maps_t zms,Z_AttributesPlusTerm * zapt,const char ** index_type,char ** search_type,char * rank_type,int * complete_flag,int * sort_flag)514 int zebra_maps_attr(zebra_maps_t zms, Z_AttributesPlusTerm *zapt,
515 		    const char **index_type, char **search_type, char *rank_type,
516 		    int *complete_flag, int *sort_flag)
517 {
518     AttrType completeness;
519     AttrType structure;
520     AttrType relation;
521     AttrType sort_relation;
522     AttrType weight;
523     AttrType use;
524     int completeness_value;
525     int structure_value;
526     const char *structure_str = 0;
527     int relation_value;
528     int sort_relation_value;
529     int weight_value;
530     int use_value;
531 
532     attr_init_APT(&structure, zapt, 4);
533     attr_init_APT(&completeness, zapt, 6);
534     attr_init_APT(&relation, zapt, 2);
535     attr_init_APT(&sort_relation, zapt, 7);
536     attr_init_APT(&weight, zapt, 9);
537     attr_init_APT(&use, zapt, 1);
538 
539     completeness_value = attr_find(&completeness, NULL);
540     structure_value = attr_find_ex(&structure, NULL, &structure_str);
541     relation_value = attr_find(&relation, NULL);
542     sort_relation_value = attr_find(&sort_relation, NULL);
543     weight_value = attr_find(&weight, NULL);
544     use_value = attr_find(&use, NULL);
545 
546     if (completeness_value == 2 || completeness_value == 3)
547 	*complete_flag = 1;
548     else
549 	*complete_flag = 0;
550     *index_type = 0;
551 
552     *sort_flag =(sort_relation_value > 0) ? 1 : 0;
553     *search_type = "phrase";
554     strcpy(rank_type, "void");
555     if (relation_value == 102)
556     {
557         if (weight_value == -1)
558             weight_value = 34;
559         sprintf(rank_type, "rank,w=%d,u=%d", weight_value, use_value);
560     }
561     if (*complete_flag)
562 	*index_type = "p";
563     else
564 	*index_type = "w";
565     switch (structure_value)
566     {
567     case 6:   /* word list */
568 	*search_type = "and-list";
569 	break;
570     case 105: /* free-form-text */
571 	*search_type = "or-list";
572 	break;
573     case 106: /* document-text */
574         *search_type = "or-list";
575 	break;
576     case -1:
577     case 1:   /* phrase */
578     case 2:   /* word */
579     case 108: /* string */
580 	*search_type = "phrase";
581 	break;
582     case 107: /* local-number */
583 	*search_type = "local";
584 	*index_type = 0;
585 	break;
586     case 109: /* numeric string */
587 	*index_type = "n";
588 	*search_type = "numeric";
589         break;
590     case 104: /* urx */
591 	*index_type = "u";
592 	*search_type = "phrase";
593 	break;
594     case 3:   /* key */
595         *index_type = "0";
596         *search_type = "phrase";
597         break;
598     case 4:  /* year */
599         *index_type = "y";
600         *search_type = "phrase";
601         break;
602     case 5:  /* date */
603         *index_type = "d";
604         *search_type = "phrase";
605         break;
606     case -2:
607         if (structure_str && *structure_str)
608             *index_type = structure_str;
609         else
610             return -1;
611         break;
612     default:
613 	return -1;
614     }
615     return 0;
616 }
617 
zebra_replace(zebra_map_t zm,const char * ex_list,const char * input_str,int input_len)618 WRBUF zebra_replace(zebra_map_t zm, const char *ex_list,
619 		    const char *input_str, int input_len)
620 {
621     wrbuf_rewind(zm->zebra_maps->wrbuf_1);
622     wrbuf_write(zm->zebra_maps->wrbuf_1, input_str, input_len);
623     return zm->zebra_maps->wrbuf_1;
624 }
625 
626 #define SE_CHARS ";,.()-/?<> \r\n\t"
627 
tokenize_simple(zebra_map_t zm,const char ** result_buf,size_t * result_len)628 static int tokenize_simple(zebra_map_t zm,
629                            const char **result_buf, size_t *result_len)
630 {
631     char *buf = wrbuf_buf(zm->input_str);
632     size_t len = wrbuf_len(zm->input_str);
633     size_t i = zm->simple_off;
634     size_t start;
635 
636     while (i < len && strchr(SE_CHARS, buf[i]))
637         i++;
638     start = i;
639     while (i < len && !strchr(SE_CHARS, buf[i]))
640     {
641         if (buf[i] > 32 && buf[i] < 127)
642             buf[i] = tolower(buf[i]);
643         i++;
644     }
645 
646     zm->simple_off = i;
647     if (start != i)
648     {
649         *result_buf = buf + start;
650         *result_len = i - start;
651         return 1;
652     }
653     return 0;
654  }
655 
656 
zebra_map_tokenize_next(zebra_map_t zm,const char ** result_buf,size_t * result_len,const char ** display_buf,size_t * display_len)657 int zebra_map_tokenize_next(zebra_map_t zm,
658                             const char **result_buf, size_t *result_len,
659                             const char **display_buf, size_t *display_len)
660 {
661     assert(zm->use_chain);
662 
663 #if YAZ_HAVE_ICU
664     if (!zm->icu_chain)
665         return tokenize_simple(zm, result_buf, result_len);
666     else
667     {
668         UErrorCode status;
669         while (icu_chain_next_token(zm->icu_chain, &status))
670         {
671             if (!U_SUCCESS(status))
672                 return 0;
673             *result_buf = icu_chain_token_sortkey(zm->icu_chain);
674             assert(*result_buf);
675 
676             *result_len = strlen(*result_buf);
677 
678             if (display_buf)
679             {
680                 *display_buf = icu_chain_token_display(zm->icu_chain);
681                 if (display_len)
682                     *display_len = strlen(*display_buf);
683             }
684             if (zm->debug)
685             {
686                 wrbuf_rewind(zm->print_str);
687                 wrbuf_write_escaped(zm->print_str, *result_buf, *result_len);
688                 yaz_log(YLOG_LOG, "output %s", wrbuf_cstr(zm->print_str));
689             }
690 
691             if (**result_buf != '\0')
692                 return 1;
693         }
694     }
695     return 0;
696 #else
697     return tokenize_simple(zm, result_buf, result_len);
698 #endif
699 }
700 
zebra_map_tokenize_start(zebra_map_t zm,const char * buf,size_t len)701 int zebra_map_tokenize_start(zebra_map_t zm,
702                              const char *buf, size_t len)
703 {
704 #if YAZ_HAVE_ICU
705     int ret;
706 #endif
707     assert(zm->use_chain);
708 
709     wrbuf_rewind(zm->input_str);
710     wrbuf_write(zm->input_str, buf, len);
711     zm->simple_off = 0;
712 #if YAZ_HAVE_ICU
713     if (zm->icu_chain)
714     {
715         UErrorCode status;
716         if (zm->debug)
717         {
718             wrbuf_rewind(zm->print_str);
719             wrbuf_write_escaped(zm->print_str, wrbuf_buf(zm->input_str),
720                                 wrbuf_len(zm->input_str));
721 
722             yaz_log(YLOG_LOG, "input %s",
723                     wrbuf_cstr(zm->print_str));
724         }
725         ret = icu_chain_assign_cstr(zm->icu_chain,
726                                     wrbuf_cstr(zm->input_str), &status);
727         if (!ret && !U_SUCCESS(status))
728         {
729             if (zm->debug)
730             {
731                 yaz_log(YLOG_WARN, "bad encoding for input");
732             }
733             return -1;
734         }
735     }
736 #endif
737     return 0;
738 }
739 
zebra_maps_is_icu(zebra_map_t zm)740 int zebra_maps_is_icu(zebra_map_t zm)
741 {
742     assert(zm);
743 #if YAZ_HAVE_ICU
744     return zm->use_chain;
745 #else
746     return 0;
747 #endif
748 }
749 
750 
751 /*
752  * Local variables:
753  * c-basic-offset: 4
754  * c-file-style: "Stroustrup"
755  * indent-tabs-mode: nil
756  * End:
757  * vim: shiftwidth=4 tabstop=8 expandtab
758  */
759 
760