1 /*
2  *  $Id:$
3  *  Copyright (c) 2003,2004 Masahito Omote <omote@utyuuzin.net>
4  *                2005-2013 uim Project https://github.com/uim/uim
5  *
6  *  All rights reserved.
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions
10  *  are met:
11  *
12  *  1. Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *  2. Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *  3. Neither the name of authors nor the names of its contributors
18  *     may be used to endorse or promote products derived from this software
19  *     without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
22  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
25  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  *  SUCH DAMAGE.
32  */
33 
34 #include <config.h>
35 
36 #include <dlfcn.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <glib.h>
41 
42 #include <anthy/anthy.h>
43 #include <anthy/dicutil.h>
44 
45 #include "gettext.h"
46 #include "anthy.h"
47 #include "canna-cclass.h"
48 #include "util.h"
49 
50 static uim_dict *uim_dict_anthy_open        (const char *identifier);
51 static void      uim_dict_anthy_close       (uim_dict *dict);
52 static int       uim_dict_anthy_add_word    (uim_dict *dict, uim_word *word);
53 static int       uim_dict_anthy_change_word (uim_dict *dict, uim_word *word);
54 static int       uim_dict_anthy_remove_word (uim_dict *dict, uim_word *word);
55 static void      uim_dict_anthy_refresh     (uim_dict *dict);
56 
57 #if 0 /* should be accessed through functions */
58 static
59 #endif
60 uim_dict_class uim_dict_class_anthy = {
61   "Anthy",                    /* type */
62 
63   NULL,                       /* init */
64   NULL,                       /* exit */
65 
66   NULL,                       /* list_known_dict */
67   NULL,                       /* default_priv_dict */
68 
69   uim_dict_anthy_open,        /* open */
70 
71   NULL,                       /* is_supported */
72   NULL,                       /* load_file */
73   NULL,                       /* save_file */
74 
75   uim_dict_anthy_close,       /* close */
76 
77   uim_dict_anthy_add_word,    /* add_word */
78   uim_dict_anthy_change_word, /* change_word */
79   uim_dict_anthy_remove_word, /* remove_word */
80   uim_dict_anthy_refresh,     /* refresh */
81 };
82 
83 static const char *identifiers[] = {
84   N_("Anthy private dictionary"),
85 };
86 
87 static int
dict_anthy_init(void)88 dict_anthy_init(void)
89 {
90   anthy_dic_util_init();
91 #if LIBANTHY_UTF8_CAPABLE
92   anthy_dic_util_set_encoding(ANTHY_UTF8_ENCODING);
93 #endif
94   return 0;
95 }
96 
97 static int
dict_anthy_exit(void)98 dict_anthy_exit(void)
99 {
100   /*
101    * With anthy-7811, anthy_parse_word_lin() causes segmentation fault once
102    * anthy_dic_util_quit() and anthy_dic_util_init() have been used to restart
103    * the library.  To avoid this, we don't call anthy_dic_util_quit() even when
104    * the ref_count of uim_dict_anthy become 0.
105    */
106 #if 0
107   anthy_dic_util_quit();
108 #endif
109 
110   return 0;
111 }
112 
113 static int
dict_anthy_read_priv_dic_list(uim_word ** head)114 dict_anthy_read_priv_dic_list(uim_word **head)
115 {
116   char phon[100], desc[100], cclass_native[100];
117   int ret = 0;
118 
119   if (anthy_priv_dic_select_first_entry() == -1) {
120     *head = NULL;
121     return -1;
122   }
123 
124   while (ret == 0) {
125     if (anthy_priv_dic_get_index(phon, sizeof(phon))
126 	&& anthy_priv_dic_get_wtype(cclass_native,
127 				    sizeof(cclass_native))
128 	&& anthy_priv_dic_get_word(desc, sizeof(desc))) {
129       gint pos;
130       const char *cclass_code = NULL;
131 
132       for (pos = 0; pos < NR_POS; pos++) {
133 	cclass_code = find_desc_from_code_with_type(cclass_native, pos);
134 	if (cclass_code)
135 	  break;
136       }
137 
138 #if LIBANTHY_UTF8_CAPABLE
139       {
140 	gchar *cclass_code_utf8 = eucjp_to_utf8(cclass_code);
141 	word_append(head, WORD_TYPE_ANTHY, "UTF-8",
142 		    phon, desc, cclass_code_utf8, cclass_native,
143 		    anthy_priv_dic_get_freq(),
144 		    0, NULL);
145 	g_free(cclass_code_utf8);
146       }
147 #else /* EUC-JP */
148       word_append(head, WORD_TYPE_ANTHY, "EUC-JP",
149 		  phon, desc, cclass_code, cclass_native,
150 		  anthy_priv_dic_get_freq(),
151 		  0, NULL);
152 #endif
153     }
154     ret = anthy_priv_dic_select_next_entry();
155   }
156   return 0;
157 }
158 
159 static int
dict_anthy_add_priv_dic_with_flags(char * phon,char * desc,char * cclass_code,int freq)160 dict_anthy_add_priv_dic_with_flags(char *phon, char *desc,
161 				   char *cclass_code, int freq)
162 {
163   int status;
164 
165   if ((strlen(phon) == 0) || (strlen(desc) == 0) ||
166       (strlen(cclass_code) == 0)) {
167     return 0;
168   }
169 
170   status = anthy_priv_dic_add_entry(phon, desc, cclass_code, freq);
171 
172   switch (status) {
173   case ANTHY_DIC_UTIL_OK:
174   case ANTHY_DIC_UTIL_DUPLICATE:
175     status = 1;
176     break;
177   default:
178     status = 0;
179   }
180 
181   return status;
182 }
183 
184 static int
dict_anthy_delete_priv_dic(char * phon,char * desc,char * cclass_code)185 dict_anthy_delete_priv_dic(char *phon, char *desc, char *cclass_code)
186 {
187   int status;
188 
189   status = anthy_priv_dic_add_entry(phon, desc, cclass_code, 0);
190   return status ? 0 : 1;
191 }
192 
193 static uim_dict *
uim_dict_anthy_open(const char * identifier)194 uim_dict_anthy_open(const char *identifier)
195 {
196   uim_dict *dict;
197 
198   if (identifier == NULL)
199     return NULL;
200 
201   if (strcmp(identifier, identifiers[0]) != 0)
202     return NULL;
203 
204   if (dict_anthy_init() == -1)
205     return NULL;
206 
207   dict = malloc(sizeof(uim_dict));
208   if (dict == NULL)
209     return NULL;
210 
211   dict->funcs      = &uim_dict_class_anthy;
212   dict->identifier = strdup(identifier);
213   dict->filename   = NULL;
214 #if LIBANTHY_UTF8_CAPABLE
215   dict->charset    = strdup("UTF-8");
216 #else
217   dict->charset    = strdup("EUC-JP");
218 #endif
219   dict->ref_count  = 0; /* at this point, no window refers this */
220   dict->word_list  = NULL;
221 
222   dict_anthy_read_priv_dic_list(&dict->word_list);
223 
224   return dict;
225 }
226 
227 static void
uim_dict_anthy_close(uim_dict * dict)228 uim_dict_anthy_close(uim_dict *dict)
229 {
230   if (dict == NULL)
231     return;
232 
233   word_free_list(dict->word_list);
234 
235   free(dict->identifier);
236   free(dict->filename);
237   free(dict->charset);
238   free(dict);
239 
240   dict_anthy_exit();
241 }
242 
243 static int
uim_dict_anthy_add_word(uim_dict * dict,uim_word * word)244 uim_dict_anthy_add_word(uim_dict *dict, uim_word *word)
245 {
246   int ret;
247 
248   if (dict == NULL || word == NULL)
249     return 0;
250 
251   ret = dict_anthy_add_priv_dic_with_flags(word->phon, word->desc,
252 					   word->cclass_native, word->freq);
253 
254   return ret;
255 }
256 
257 static int
uim_dict_anthy_change_word(uim_dict * dict,uim_word * word)258 uim_dict_anthy_change_word(uim_dict *dict, uim_word *word)
259 {
260   return 0;
261 }
262 
263 static int
uim_dict_anthy_remove_word(uim_dict * dict,uim_word * word)264 uim_dict_anthy_remove_word(uim_dict *dict, uim_word *word)
265 {
266   if (dict == NULL)
267     return 0;
268 
269   return dict_anthy_delete_priv_dic(word->phon, word->desc,
270 				    word->cclass_native);
271 }
272 
273 static void
uim_dict_anthy_refresh(uim_dict * dict)274 uim_dict_anthy_refresh(uim_dict *dict)
275 {
276   if (dict == NULL)
277     return;
278 
279   dict->word_list = NULL;
280   word_free_list(dict->word_list);
281   dict_anthy_read_priv_dic_list(&dict->word_list);
282 }
283