Fix: Destroy utf8 buffer with utf-8 buffer destroy
[yaz-moved-to-github.git] / src / stemmer.c
1
2
3 #if HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6
7 #if YAZ_HAVE_ICU
8
9 #include <yaz/yconfig.h>
10
11 #include <yaz/stemmer.h>
12
13 #include <yaz/xmalloc.h>
14
15 #include <libstemmer.h>
16
17 #include <unicode/ustring.h>  /* some more string fcns*/
18 #include <unicode/uchar.h>    /* char names           */
19
20 enum stemmer_implementation {
21     yaz_no_operation,
22     yaz_snowball
23 };
24 struct yaz_stemmer_t
25 {
26     int implementation;
27     // Required for cloning.
28     char *locale;
29     char *rule;
30     union {
31         struct sb_stemmer *sb_stemmer;
32     };
33 };
34
35 const char* yaz_stemmer_lookup_charenc(const char *charenc, const char *rule) {
36     return "UTF_8";
37 }
38
39 const char* yaz_stemmer_lookup_algorithm(const char *locale, const char *rule) {
40     return locale;
41 }
42
43 yaz_stemmer_p yaz_stemmer_snowball_create(const char *locale, const char *rule, UErrorCode *status) {
44     const char *charenc = yaz_stemmer_lookup_charenc(locale, rule);
45     const char *algorithm = yaz_stemmer_lookup_algorithm(locale,rule);
46     struct sb_stemmer *stemmer = sb_stemmer_new(algorithm, charenc);
47     yaz_stemmer_p yaz_stemmer;
48     yaz_log(YLOG_DEBUG, "create snowball stemmer: algoritm %s charenc %s ", algorithm, charenc);
49     if (stemmer == 0) {
50         *status = U_ILLEGAL_ARGUMENT_ERROR;
51         yaz_log(YLOG_DEBUG, "failed to create stemmer. Creating NOP stemmer");
52
53         return 0;
54     }
55     yaz_stemmer = xmalloc(sizeof(*yaz_stemmer));
56     yaz_stemmer->implementation = yaz_snowball;
57     yaz_stemmer->locale = xstrdup(locale);
58     yaz_stemmer->rule = xstrdup(rule);
59     yaz_stemmer->sb_stemmer = stemmer;
60     yaz_log(YLOG_DEBUG, "created snowball stemmer: algoritm %s charenc %s ", algorithm, charenc);
61     return yaz_stemmer;
62 }
63
64 yaz_stemmer_p yaz_stemmer_create(const char *locale, const char *rule, UErrorCode *status) {
65     *status = U_ZERO_ERROR;
66     // dispatch logic required if more algorithms is implemented.
67     yaz_log(YLOG_DEBUG, "create stemmer: locale %s rule %s ", locale, rule);
68     return yaz_stemmer_snowball_create(locale, rule, status);
69 }
70
71 yaz_stemmer_p yaz_stemmer_clone(yaz_stemmer_p stemmer) {
72     UErrorCode error = U_ZERO_ERROR;
73     return yaz_stemmer_create(stemmer->locale, stemmer->rule, &error);
74 }
75
76 void yaz_stemmer_stem(yaz_stemmer_p stemmer, struct icu_buf_utf16 *dst, struct icu_buf_utf16* src, UErrorCode *status)
77 {
78     switch(stemmer->implementation) {
79         case yaz_snowball: {
80             struct icu_buf_utf8 *utf8_buf = icu_buf_utf8_create(0);
81             icu_utf16_to_utf8(utf8_buf, src, status);
82             if (*status == U_ZERO_ERROR) {
83                 const sb_symbol *cstr = (const sb_symbol*) icu_buf_utf8_to_cstr(utf8_buf);
84                 const sb_symbol *sb_symbol = sb_stemmer_stem(stemmer->sb_stemmer, cstr, utf8_buf->utf8_len);
85                 if (sb_symbol == 0) {
86                     icu_buf_utf16_copy(dst, src);
87                 }
88                 else {
89                     const char *cstr = (const char *) sb_symbol;
90                     icu_utf16_from_utf8_cstr(dst, cstr , status);
91                 }
92             }
93             icu_buf_utf8_destroy(utf8_buf);
94             return ;
95             break;
96         }
97         default: {
98             // Default return the same as given.
99             icu_buf_utf16_copy(dst, src);
100         }
101     }
102 }
103
104 void yaz_stemmer_destroy(yaz_stemmer_p stemmer) {
105     switch (stemmer->implementation) {
106     case yaz_snowball:
107         sb_stemmer_delete(stemmer->sb_stemmer);
108         break;
109     }
110     xfree(stemmer->locale);
111     xfree(stemmer->rule);
112     xfree(stemmer);
113 }
114
115 #endif /* YAZ_HAVE_ICU */