1 /***************************************************************************
2  *   Copyright (C) 2004 by TAM(Teppei Tamra)                               *
3  *   tam-t@par.odn.ne.jp                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #include "wnnconversion.h"
21 
22 #ifdef HAVE_CONFIG_H
23   #include <config.h>
24 #endif
25 
26 #ifdef HAVE_GETTEXT
27   #include <libintl.h>
28   #define _(String) dgettext(GETTEXT_PACKAGE,String)
29   #define N_(String) (String)
30 #else
31   #define _(String) (String)
32   #define N_(String) (String)
33   #define bindtextdomain(Package,Directory)
34   #define textdomain(domain)
35   #define bind_textdomain_codeset(domain,codeset)
36 #endif
37 
38 // プライグイン化のおまじないです。
39 //HonokaPluginRegister(WnnConversion);
40 
WnnConversion(ConfigPointer cfg)41 WnnConversion::WnnConversion(ConfigPointer cfg) : Convertor(cfg)
42 {
43     // とりあえず決めうちでいきます。
44     m_iconv.set_encoding ("EUC-JP");
45     pos = 0;
46     bunsetu = 0;
47     wnn = 0;
48     sType = Wnn4;
49 }
50 
51 
~WnnConversion()52 WnnConversion::~WnnConversion()
53 {
54     wnnDisconnect();
55 }
56 
57 
58     /* w_charからEUCに変換するアレ */
wstostr(unsigned char * e,w_char * u)59 void WnnConversion::wstostr(unsigned char *e,w_char *u) {
60     w_char x;
61     for(;*u;) {
62         x = *u ++;
63         if (x & 0x8000) {
64             *e ++ = x >> 8;
65             *e ++ = x;
66         } else
67         if (x & 0x80) {
68             *e ++ = 0x8e;
69             *e ++ = x & 0xff;
70         } else
71             *e++ = x;
72     }
73     *e ++ = 0;
74 }
75 
76     /* EUCからw_charに変換するナニ */
strtows(w_char * u,unsigned char * e)77 void WnnConversion::strtows(w_char *u,unsigned char *e) {
78     w_char  x;
79     for(;*e;) {
80         x = *e ++;
81         // これいらない↓
82         //if (x == 0x8e) x = 0x80 | *e ++;
83         if (x & 0x80)
84         x = ((x << 8) & 0xff00)  | *e ++;
85         *u ++ = x;
86     }
87     *u = 0;
88 }
89 
90 /*!
91     \fn WnnConversion::connect()
92  */
connect()93 bool WnnConversion::connect()
94 {
95     String host = config->read(String(HONOKA_CONFIG_JSERVER),String(HONOKA_DEFAULT_JSERVER));
96     String rc = config->read(String(HONOKA_CONFIG_WNNENVRC),String(HONOKA_DEFAULT_WNNENVRC));
97     String t = config->read(String(HONOKA_CONFIG_JSERVERTYPE),String(HONOKA_DEFAULT_JSERVERTYPE));
98 
99     if (t == "Wnn6") {
100         sType = Wnn6;
101     } else if (t == "Wnn7") {
102         sType = Wnn7;
103     } else if (t == "Wnn8") {
104         sType = Wnn8;
105     } else {
106         sType = Wnn4;
107     }
108 
109     return wnnConnect(String("scim-wnn"),host,rc,sType,0);
110 }
111 
112 /*!
113     \fn WnnConversion::disconnect()
114  */
disconnect()115 void WnnConversion::disconnect()
116 {
117     wnnDisconnect();
118 }
119 
120 
121 /*!
122     \fn WnnConversion::wnnConnect(String name,String host,String rc,JServerType type,int timeout)
123  */
wnnConnect(String name,String host,String rc,JServerType type,int timeout)124 bool WnnConversion::wnnConnect(String name,String host,String rc,JServerType type,int timeout)
125 {
126     wnn = jl_open((char *)name.c_str(),(char *)host.c_str(),(char *)rc.c_str(),wnn_error,wnn_message,timeout);
127     //wnn = jl_open_lang("test","localhost","jp_JP","/usr/lib/wnn7/ja_JP/wnnenvrc",wnn_error,wnn_message,10);
128     if (wnn == NULL) return false;
129     #ifdef HAVE_LIBWNN7
130     // 予測入力を初期化しておく。
131     jl_yosoku_init(wnn);
132     #endif
133     sType = type;
134     return true;
135 }
136 
137 /*!
138     \fn WnnConversion::wnnDisconnect()
139  */
wnnDisconnect()140 void WnnConversion::wnnDisconnect()
141 {
142     if (wnn != NULL) {
143         jl_dic_save_all(wnn);
144         #ifdef HAVE_LIBWNN7
145         jl_yosoku_free(wnn);
146         #endif
147         jl_close(wnn);
148         wnn = NULL;
149     }
150 }
151 
152 
153 
154 
155 /*!
156     \fn WnnConversion::isConnected()
157  */
isConnected()158 bool WnnConversion::isConnected()
159 {
160     if (wnn) return true;
161     else return false;
162 }
163 
164 
165 
166 
167 /*!
168     \fn WnnConversion::wnn_message (char *s)
169  */
wnn_message(char * s)170 int WnnConversion::wnn_message (char *s)
171 {
172 
173     SCIM_DEBUG_IMENGINE(1) << s << "\n";
174 }
175 
176 /*!
177     \fn WnnConversion::wnn_error (char *s)
178  */
wnn_error(char * s)179 int WnnConversion::wnn_error (char *s)
180 {
181 
182     SCIM_DEBUG_IMENGINE(1) << s << "\n";
183 }
184 
185 
186 
187 
188 /*!
189     \fn WnnConversion::reset()
190  */
reset()191 void WnnConversion::reset()
192 {
193     yomiText.clear();
194     bunList.clear();
195     yomiList.clear();
196     text.clear();
197     attr.clear();
198     pos = 0;
199     jl_kill(wnn,0,-1);
200 }
201 
202 
203 /*!
204     \fn WnnConversion::setYomiText(WideString yomi)
205  */
setYomiText(WideString yomi)206 void WnnConversion::setYomiText(WideString yomi)
207 {
208     yomiText = yomi;
209 }
210 
211 
212 
213 /*!
214     \fn WnnConversion::ren_conversion()
215  */
ren_conversion()216 int WnnConversion::ren_conversion()
217 {
218     if ((yomiText.length() > 500) || (!yomiText.length())) return -1;
219     convList.Yomi.clear();
220     convList.kouho.clear();
221     bunList.clear();
222     yomiList.clear();
223     pos = 0;
224     w_char ws[1024];
225     char c[2048];
226     String y;
227     m_iconv.convert(y,yomiText);
228     strtows(ws,(unsigned char*)y.c_str());
229     bunsetu = jl_fi_ren_conv(wnn,ws,0,-1,WNN_USE_ZENGO);
230     if (bunsetu == -1) return -1;
231     for(unsigned int i = 0;i < bunsetu;i ++) {
232         WideString w;
233         jl_get_kanji(wnn,i,i + 1,ws);
234         wstostr((unsigned char*)c,ws);
235         m_iconv.convert(w,c,strlen(c));
236         bunList.push_back(w);
237         jl_get_yomi(wnn,i,i + 1,ws);
238         wstostr((unsigned char*)c,ws);
239         m_iconv.convert(w,c,strlen(c));
240         yomiList.push_back(w);
241     }
242     createText();
243     return bunsetu;
244 }
245 
246 
247 /*!
248     \fn WnnConversion::resizeRegion(int w)
249  */
resizeRegion(int w)250 bool WnnConversion::resizeRegion(int w)
251 {
252     if (w == 0) return false;
253     if ((yomiList[pos].length() + w) <= 0)  return false;
254     if (((pos + 1) >= yomiList.size()) && (w > 0)) return false;
255 
256     w_char ws[1024];
257     char c[2048];
258     int s;
259     int h = WNN_NO_USE;
260     if (pos > 0) h = WNN_USE_MAE;
261     else if (pos < bunsetu - 1) h = WNN_USE_ATO;
262     bunsetu = jl_fi_nobi_conv(wnn,pos,yomiList[pos].length() + w,-1,h,WNN_SHO);
263     convList.kouho.clear();
264     bunList.clear();
265     yomiList.clear();
266     for(unsigned int i = 0;i < bunsetu;i ++) {
267         WideString w;
268         jl_get_kanji(wnn,i,i + 1,ws);
269         wstostr((unsigned char*)c,ws);
270         m_iconv.convert(w,c,strlen(c));
271         bunList.push_back(w);
272         jl_get_yomi(wnn,i,i + 1,ws);
273         wstostr((unsigned char*)c,ws);
274         m_iconv.convert(w,c,strlen(c));
275         yomiList.push_back(w);
276     }
277     createText();
278     return true;
279 }
280 
281 
282 /*!
283     \fn WnnConversion::createText()
284  */
createText()285 void WnnConversion::createText()
286 {
287     WideString w;
288     caretPos = 0;
289     for(unsigned int i = 0;i < bunsetu;i ++) {
290         if (pos == i) {
291             caretPos = w.length();
292             attr.clear();
293             Attribute a(w.length(),bunList[i].length(),SCIM_ATTR_DECORATE,SCIM_ATTR_DECORATE_REVERSE);
294             attr.push_back(a);
295         }
296         w = w + bunList[i];
297     }
298     text = w;
299 }
300 
301 
302 /*!
303     \fn WnnConversion::getSegmentList()
304  */
getSegmentList()305 const vector<Segment> WnnConversion::getSegmentList()
306 {
307     // getTextにかわるもの。
308     vector<Segment> result;
309     for(unsigned int i = 0;i < bunsetu;i ++) result.push_back(Segment(bunList[i],yomiList[i]));
310     return result;
311 }
312 
313 
314 /*!
315     \fn WnnConversion::setPos(int p)
316  */
setPos(int p)317 int WnnConversion::setPos(int p)
318 {
319     /*if (p >= bunsetu) p = (p % bunsetu);
320     else if (p < 0) p = bunsetu - (abs(p) % bunsetu);*/
321     if ((p < bunsetu) && (p >= 0)) pos = p;
322 
323     //pos = p;
324     createText();
325     return pos;
326 }
327 
328 
329 /*!
330     \fn WnnConversion::getPos()
331  */
getPos()332 int WnnConversion::getPos()
333 {
334     return pos;
335 }
336 
337 
338 /*!
339     \fn WnnConversion::getYosokuList(const WideString &str)
340  */
getYosokuList(const WideString & str)341 ResultList WnnConversion::getYosokuList(const WideString &str)
342 {
343     convList.Yomi = str;
344     convList.kouho.clear();
345     //convList.count = 0;
346     convList.pos = 0;
347     convList.kType = PREDICTION;
348     convList.Title = utf8_mbstowcs(String(_("yosoku lookup result")));
349     #ifdef HAVE_LIBWNN7
350     String s;
351     m_iconv.convert(s,convList.Yomi);
352     // @todo ここもmbstowcsしたほうが良いんか?
353     char c[1024];
354     strcpy(c,s.c_str());
355     if (jl_yosoku_yosoku(wnn,c) != 0) return convList;
356     //convList.count = ykYosokuKouhoNum;
357     for(unsigned int i = 0;i < ykYosokuKouhoNum;i ++) {
358         WideString w;
359         m_iconv.convert(w,ykYosokuKouho[i],strlen(ykYosokuKouho[i]));
360         convList.kouho.push_back(ResultEntry(w));
361     }
362     //jl_yosoku_free(wnn);
363     #endif
364     return convList;
365 }
366 
367 
368 /*!
369     \fn WnnConversion::getResultList(int p,ResultType kt)
370  */
getResultList(int p,ResultType kt)371 ResultList WnnConversion::getResultList(int p,ResultType kt)
372 {
373         w_char k[1024];
374         char buf[2048];
375         WideString u;
376     convList.kouho.clear();
377     convList.Yomi.clear();
378     convList.pos = 0;
379     //convList.count = 0;
380     if ((sType != Wnn8) && (sType != Wnn7) && (kt != DEFAULT)) return convList;
381 
382     if (p == -1) p = pos;
383     //if ((p >= bunsetu) || (p < 0)) p = p % bunsetu;
384     if (p >= bunsetu) return convList;
385     pos = p;
386     jl_get_yomi(wnn,pos,pos + 1,k);
387         wstostr((unsigned char*)buf,k);
388         m_iconv.convert(u,buf,strlen(buf));
389         convList.Yomi = u;
390 
391     // bunsetu connection control
392     int conn = WNN_USE_ZENGO;
393     if (bunsetu == 1) conn = WNN_NO_USE;
394     else if (pos == 0) conn = WNN_USE_ATO;
395     else if (pos == (bunsetu - 1)) conn = WNN_USE_MAE;
396     switch (kt) {
397         #ifdef HAVE_LIBWNN7
398         case SPECIAL2: {
399             convList.pos = jl_zenikeiji_dai(wnn,pos,pos + 1,conn,WNN_UNIQ);
400             convList.kType = SPECIAL2;
401             convList.Title = utf8_mbstowcs(String(_("Ikeiji lookup result")));
402             break;
403         }
404         case SPECIAL1: {
405             convList.pos = jl_zenassoc_dai(wnn,pos,pos + 1,conn,WNN_UNIQ);
406             convList.kType = SPECIAL1;
407             convList.Title = utf8_mbstowcs(String(_("association lookup result")));
408             break;
409         }
410         #endif
411         default: {
412             convList.pos = jl_zenkouho_dai(wnn,pos,pos + 1,conn,WNN_UNIQ);
413             convList.kType = DEFAULT;
414             convList.Title = utf8_mbstowcs(String(_("lookup result")));
415             break;
416         }
417     }
418 
419     // @todo be implement to ikeiji conversion using "jl_zenikeiji_dai()".
420     // @todo be implement to rensou conversion using "jl_zenassoc_dai()".
421     // @todo jl_zenkouho should change to jl_zenkouho_dai.
422     //convList.pos = jl_zenassoc_dai(wnn,pos,pos + 1,WNN_USE_ZENGO,WNN_UNIQ);
423     //convList.pos = jl_zenkouho(wnn,pos,conn,WNN_UNIQ);
424     if (convList.pos == -1) return convList;
425     int count = jl_zenkouho_suu(wnn);
426 
427     for (unsigned int i = 0;i < count; i ++) {
428         jl_get_zenkouho_kanji(wnn,i,k);
429         wstostr((unsigned char*)buf,k);
430         m_iconv.convert(u,buf,strlen(buf));
431         convList.kouho.push_back(u);
432     }
433     select(convList.pos);
434     createText();
435     return convList;
436 
437 }
438 
439 
440 /*!
441     \fn WnnConversion::select(int p)
442  */
select(int p)443 bool WnnConversion::select(int p)
444 {
445     if (p > convList.count()) p = 0;
446     convList.pos = p;
447     switch(convList.kType) {
448         case DEFAULT: {
449             jl_set_jikouho_dai(wnn,p);
450             break;
451         }
452         case PREDICTION: {
453             #ifdef HAVE_LIBWNN7
454             jl_yosoku_selected_cand(wnn,p);
455             #endif
456             return true;
457         }
458         default: {
459             break;
460         }
461     }
462 
463     bunList.at(pos) = convList.kouho.at(p).kanji;
464     createText();
465 
466     return true;
467 
468 }
469 
470 
471 
472 
473 
474 
475 /*!
476     \fn WnnConversion::updateFrequency()
477  */
updateFrequency()478 void WnnConversion::updateFrequency()
479 {
480     if (bunsetu) {
481         #ifdef HAVE_LIBWNN7
482         w_char ws[1024];
483         int c = jl_get_kanji(wnn,0,bunsetu,ws);
484         jl_yosoku_toroku(wnn,ws,c);
485         #endif
486         jl_optimize_fi(wnn,0,-1);
487         pretext = text;
488     }
489 }
490 
491 
492 
493 
getName()494 String WnnConversion::getName()
495 {
496     return String("Wnn");
497 }
498 
getPropertyName()499 String WnnConversion::getPropertyName()
500 {
501     return String(_("WnnConversion"));
502 }
503 
504 
505 
506 /*!
507     \fn WnnConversion::updateYosoku(WideString text,const WideString yomi)
508  */
updateYosoku(WideString text,const WideString yomi)509 void WnnConversion::updateYosoku(WideString text,const WideString yomi)
510 {
511     #ifdef HAVE_LIBWNN7
512     if (text == pretext) return;
513     reset();
514     setYomiText(yomi);
515     ren_conversion();
516     w_char ws[1024];
517     char c[2048];
518     String y;
519     m_iconv.convert(y,text);
520     strtows(ws,(unsigned char*)y.c_str());
521     jl_yosoku_toroku(wnn,ws,text.length());
522     reset();
523     #endif
524     return;
525 
526 }
527