Fix license
[platform/core/uifw/anthy.git] / src-splitter / compose.c
1 /*
2  * Ê¸Àá¤ËÂФ·¤Æ¸õÊä¤Î¥ê¥¹¥È¤òÀ¸À®¤¹¤ë¡£
3  * make_candidates()¤¬context´ÉÍýÉô¤«¤é¸Æ¤Ð¤ì¤ë¡£
4  *
5  * ¸õÊä¤ÎÀ¸À®¤Ï¼¡¤ÎÊýË¡¤Ç¹Ô¤¦
6  * (1)splitter¤¬³ä¤êÅö¤Æ¤¿ÉÊ»ì¤ËÂФ·¤Æproc_splitter_info()
7  *    ¤«¤é¸õÊä¤òÀ¸À®¤¹¤ë
8  * (2)¤Ò¤é¤¬¤Ê¤Î¤ß¤È¥«¥¿¥«¥Ê¤Î¤ß¤Î¸õÊä¤òÀ¸À®¤¹¤ë
9  * (3)ºÇ¸å¤Îʸ»ú¤ò½õ»ì¤È²ò¼á¤·¤Æ̵ÍýÌðÍý¸õÊä¤òÀ¸À®¤¹¤ë
10  */
11 /*
12  * Funded by IPA̤Ƨ¥½¥Õ¥È¥¦¥§¥¢ÁϤ»ö¶È 2001 9/30
13  * Copyright (C) 2000-2005 TABATA Yusuke
14  * Copyright (C) 2004-2005 YOSHIDA Yuichi
15  * Copyright (C) 2002 UGAWA Tomoharu
16  *
17  * $Id: compose.c,v 1.25 2005/08/19 04:20:25 oxy Exp $
18  */
19 /*
20   This library is free software; you can redistribute it and/or
21   modify it under the terms of the GNU Lesser General Public
22   License as published by the Free Software Foundation; either
23   version 2 of the License, or (at your option) any later version.
24
25   This library is distributed in the hope that it will be useful,
26   but WITHOUT ANY WARRANTY; without even the implied warranty of
27   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28   Lesser General Public License for more details.
29
30   You should have received a copy of the GNU Lesser General Public
31   License along with this library; if not, write to the Free Software
32   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
33  */
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <anthy/dic.h>
39 #include <anthy/splitter.h>
40 #include <anthy/segment.h>
41 #include "wordborder.h"
42
43
44 static struct cand_ent *
45 alloc_cand_ent(void)
46 {
47   struct cand_ent *ce;
48   ce = (struct cand_ent *)malloc(sizeof(struct cand_ent));
49   ce->nr_words = 0;
50   ce->elm = NULL;
51   ce->mw = NULL;
52   ce->core_elm_index = -1;
53   ce->dep_word_hash = 0;
54   return ce;
55 }
56
57 /*
58  * ¸õÊä¤òÊ£À½¤¹¤ë
59  */
60 static struct cand_ent *
61 dup_candidate(struct cand_ent *ce)
62 {
63   struct cand_ent *ce_new;
64   int i;
65   ce_new = alloc_cand_ent();
66   ce_new->nr_words = ce->nr_words;
67   ce_new->str.len = ce->str.len;
68   ce_new->str.str = anthy_xstr_dup_str(&ce->str);
69   ce_new->elm = malloc(sizeof(struct cand_elm)*ce->nr_words);
70   ce_new->flag = ce->flag;
71   ce_new->core_elm_index = ce->core_elm_index;
72   ce_new->mw = ce->mw;
73   ce_new->score = ce->score;
74   ce_new->dep_word_hash = ce->dep_word_hash;
75
76   for (i = 0 ; i < ce->nr_words ; i++) {
77     ce_new->elm[i] = ce->elm[i];
78   }
79   return ce_new;
80 }
81
82 /** Ê¸Àá¤Ë¸õÊä¤òÄɲ乤ë */
83 static void
84 push_back_candidate(struct seg_ent *seg, struct cand_ent *ce)
85 {
86   /* seg_ent¤Ë¸õÊäce¤òÄɲà*/
87   seg->nr_cands++;
88   seg->cands = (struct cand_ent **)
89     realloc(seg->cands, sizeof(struct cand_ent *) * seg->nr_cands);
90   seg->cands[seg->nr_cands - 1] = ce;
91   /**/
92   if (anthy_splitter_debug_flags() & SPLITTER_DEBUG_CAND) {
93     anthy_print_candidate(ce);
94     printf("\n");
95   }
96 }
97
98 static void
99 push_back_guessed_candidate(struct seg_ent *seg)
100 {
101   xchar xc;
102   xstr *xs;
103   struct cand_ent *ce;
104   if (seg->str.len < 2) {
105     return ;
106   }
107   /* ºÇ¸å¤Îʸ»ú¤Ï½õ»ì¤«¡© */
108   xc = seg->str.str[seg->str.len - 1];
109   if (!(anthy_get_xchar_type(xc) & XCT_DEP)) {
110     return ;
111   }
112   /* ºÇ¸å¤Îʸ»ú°Ê³°¤ò¥«¥¿¥«¥Ê¤Ë¤·¤Æ¤ß¤ë */
113   ce = alloc_cand_ent();
114   xs = anthy_xstr_hira_to_kata(&seg->str);
115   xs->str[xs->len-1] = xc;
116   ce->str.str = anthy_xstr_dup_str(xs);
117   ce->str.len = xs->len;
118   ce->flag = CEF_GUESS;
119   anthy_free_xstr(xs);
120   push_back_candidate(seg, ce);
121 }
122
123 /** ºÆµ¢¤Ç1ñ¸ì¤º¤Ä¸õÊä¤ò³äÅö¤Æ¤Æ¤¤¤¯ */
124 static int
125 enum_candidates(struct seg_ent *seg,
126                 struct cand_ent *ce,
127                 int from, int n)
128 {
129   int i, p;
130   struct cand_ent *cand;
131   int nr_cands = 0;
132   int pos;
133
134   if (n == ce->mw->nr_parts) {
135     /* ´°À®·Á */
136     /* Ê¸Àá¸åÉô¤Î²òÀϤ·¤Ê¤«¤Ã¤¿Éôʬ¤ò¸õÊäʸ»úÎó¤ËÄɲà*/
137     xstr tail;
138     tail.len = seg->len - from;
139     tail.str = &seg->str.str[from];
140     anthy_xstrcat(&ce->str, &tail);
141     if (ce->str.str && (0 < ce->str.len)) { /* ¼­½ñ¤â¤·¤¯¤Ï³Ø½¬¥Ç¡¼¥¿¤¬²õ¤ì¤Æ¤¤¤¿»þ¤ÎÂкö */
142       push_back_candidate(seg, dup_candidate(ce));
143     }
144     return 1;
145   }
146
147   p = anthy_get_nr_dic_ents(ce->elm[n].se, &ce->elm[n].str);
148
149   /* Éʻ줬³äÅö¤Æ¤é¤ì¤Æ¤¤¤ë¤Î¤Ç¡¢¤½¤ÎÉÊ»ì¤Ë¥Þ¥Ã¥Á¤¹¤ë¤â¤Î¤ò³äÅö¤Æ¤ë */
150   for (i = 0; i < p; i++) {
151     wtype_t wt;
152     if (anthy_get_nth_dic_ent_is_compound(ce->elm[n].se, i)) {
153       continue;
154     }
155     anthy_get_nth_dic_ent_wtype(ce->elm[n].se, &ce->elm[n].str, i, &wt);
156
157     ce->elm[n].wt = anthy_get_wtype_with_ct(ce->elm[n].wt, CT_NONE);
158     if (anthy_wtype_include(ce->elm[n].wt, wt)) {
159       xstr word, yomi;
160
161       yomi.len = ce->elm[n].str.len;
162       yomi.str = &seg->str.str[from];
163       cand = dup_candidate(ce);
164       anthy_get_nth_dic_ent_str(cand->elm[n].se,
165                                 &yomi, i, &word);
166       cand->elm[n].nth = i;
167       cand->elm[n].id = anthy_xstr_hash(&word);
168
169       /* Ã±¸ì¤ÎËÜÂΠ*/
170       anthy_xstrcat(&cand->str, &word);
171       free(word.str);
172       /* ¼«Ê¬¤òºÆµ¢¸Æ¤Ó½Ð¤·¤·¤Æ³¤­¤ò³ä¤êÅö¤Æ¤ë */
173       nr_cands += enum_candidates(seg, cand, 
174                                   from + yomi.len,
175                                   n+1);
176       anthy_release_cand_ent(cand);
177     }
178   }
179
180   /* ÉÊ»ìÉÔÄê¤Î¾ì¹ç¤Ë¤Ï̤ÊÑ´¹¤Ç¼¡¤Îñ¸ì¤Ø¹Ô¤¯ */
181   pos = anthy_wtype_get_pos(ce->elm[n].wt);
182   if (nr_cands == 0 || pos == POS_INVAL || pos == POS_NONE) {
183     xstr xs;
184     xs.len = ce->elm[n].str.len;
185     xs.str = &seg->str.str[from];
186     cand = dup_candidate(ce);
187     cand->elm[n].nth = -1;
188     cand->elm[n].id = -1;
189     anthy_xstrcat(&cand->str, &xs);
190     nr_cands = enum_candidates(seg,cand,
191                                from + xs.len,
192                                n + 1);
193     anthy_release_cand_ent(cand);
194     return nr_cands;
195   }
196
197   return nr_cands;
198 }
199
200 /**
201  * Ê¸ÀáÁ´ÂΤò´Þ¤à°ìñ¸ì(ñ´Á»ú¤ò´Þ¤à)¤Î¸õÊä¤òÀ¸À®¤¹¤ë
202  */
203 static void
204 push_back_singleword_candidate(struct seg_ent *seg,
205                                int is_reverse)
206 {
207   seq_ent_t se;
208   struct cand_ent *ce;
209   wtype_t wt;
210   int i, n;
211   xstr xs;
212
213   se = anthy_get_seq_ent_from_xstr(&seg->str, is_reverse);
214   n = anthy_get_nr_dic_ents(se, &seg->str);
215   /* ¼­½ñ¤Î³Æ¥¨¥ó¥È¥ê¤ËÂФ·¤Æ */
216   for (i = 0; i < n; i++) {
217     int ct;
218     if (anthy_get_nth_dic_ent_is_compound(se, i)) {
219       continue;
220     }
221     /* ÉÊ»ì¤ò¼è¤ê½Ð¤·¤Æ */
222     anthy_get_nth_dic_ent_wtype(se, &seg->str, i, &wt);
223     ct = anthy_wtype_get_ct(wt);
224     /* ½ª»ß·Á¤«³èÍѤ·¤Ê¤¤¤â¤Î¤Î¸¶·Á¤Ê¤é */
225     if (ct == CT_SYUSI || ct == CT_NONE) {
226       ce = alloc_cand_ent();
227       anthy_get_nth_dic_ent_str(se,&seg->str, i, &xs);
228       ce->str.str = xs.str;
229       ce->str.len = xs.len;
230       ce->flag = CEF_SINGLEWORD;
231       push_back_candidate(seg, ce);
232     }
233   }
234 }
235
236 static void
237 push_back_noconv_candidate(struct seg_ent *seg)
238 {
239   /* ÌµÊÑ´¹¤ÇÊÒ²¾Ì¾¤Ë¤Ê¤ë¸õÊä¤ÈÊ¿²¾Ì¾¤Î¤ß¤Ë¤Ê¤ë¸õÊä¤òÄɲà*/
240   struct cand_ent *ce;
241   xstr *xs;
242
243   /* ¤Ò¤é¤¬¤Ê¤Î¤ß */
244   ce = alloc_cand_ent();
245   ce->str.str = anthy_xstr_dup_str(&seg->str);
246   ce->str.len = seg->str.len;
247   ce->flag = CEF_HIRAGANA;
248   push_back_candidate(seg, ce);
249
250   /* ¼¡¤Ë¥«¥¿¥«¥Ê */
251   ce = alloc_cand_ent();
252   xs = anthy_xstr_hira_to_kata(&seg->str);
253   ce->str.str = anthy_xstr_dup_str(xs);
254   ce->str.len = xs->len;
255   ce->flag = CEF_KATAKANA;
256   anthy_free_xstr(xs);
257   push_back_candidate(seg, ce);
258
259   /* µ­¹æ¤Î¤ß¤ÎʸÀá */
260   xs = anthy_conv_half_wide(&seg->str);
261   if (xs) {
262     ce = alloc_cand_ent();
263     ce->str.str = anthy_xstr_dup_str(xs);
264     ce->str.len = xs->len;
265     ce->flag = CEF_NONE;
266     anthy_free_xstr(xs);
267     push_back_candidate(seg, ce);
268   }
269 }
270
271 /* word_list¤ÎÍ×ÁÇpart_info¤ÎÇÛÎ󤫤écand_elm¤ÎÇÛÎó¤òºî¤ë */
272 static void
273 make_cand_elem_from_word_list(struct seg_ent *se,
274                               struct cand_ent *ce,
275                               struct word_list *wl,
276                               int index,
277                               int is_reverse)
278 {
279   int i; 
280   int from = wl->from - se->from;
281
282   for (i = 0; i < NR_PARTS; ++i) {
283     struct part_info *part = &wl->part[i];
284     xstr core_xs;
285     if (part->len == 0) {
286       /* Ä¹¤µ¤Î̵¤¤part¤Ï̵»ë¤¹¤ë */
287       continue;
288     }
289     if (i == PART_CORE) {
290       ce->core_elm_index = i + index;
291     }
292     core_xs.str = &se->str.str[from];
293     core_xs.len = part->len;
294     if (i == PART_DEPWORD) {
295       ce->dep_word_hash = anthy_dep_word_hash(&core_xs);
296     }
297     ce->elm[i + index].se = anthy_get_seq_ent_from_xstr(&core_xs, is_reverse);
298     ce->elm[i + index].str.str = core_xs.str;
299     ce->elm[i + index].str.len = core_xs.len;
300     ce->elm[i + index].wt = part->wt;
301     ce->elm[i + index].ratio = RATIO_BASE * wl->len;
302     from += part->len;
303   }
304 }
305
306
307 /** ¤Þ¤ºwordlist¤ò»ý¤Ämetaword¤«¤émeta_word¤ò¼è¤ê½Ð¤¹ */
308 static void
309 make_candidate_from_simple_metaword(struct seg_ent *se,
310                                     struct meta_word *mw,
311                                     struct meta_word *top_mw,
312                                     int is_reverse)
313 {
314   /*
315    * ³Æñ¸ì¤ÎÉʻ줬·èÄꤵ¤ì¤¿¾õÂ֤ǥ³¥ß¥Ã¥È¤µ¤ì¤ë¡£
316    */
317   struct cand_ent *ce;
318
319   /* Ê£¿ô(1¤â´Þ¤à)¤Îñ¸ì¤Ç¹½À®¤µ¤ì¤ëʸÀá¤Ëñ¸ì¤ò³äÅö¤Æ¤Æ¤¤¤¯ */
320   ce = alloc_cand_ent();
321   ce->nr_words = mw->nr_parts;
322   ce->str.str = NULL;
323   ce->str.len = 0;
324   ce->elm = calloc(sizeof(struct cand_elm),ce->nr_words);
325   ce->mw = mw;
326   ce->score = 0;
327
328   /* ÀÜƬ¼­, ¼«Î©¸ìÉô, ÀÜÈø¼­, ÉÕ°¸ì */
329   make_cand_elem_from_word_list(se, ce, mw->wl, 0, is_reverse);
330
331   /* WRAP¤µ¤ì¤Æ¤¤¤¿¤éGUESS¤ÈƱ¤¸°·¤¤¤Ë¤·¤ÆÅÀ¿ô¤ò²¼¤²¤ë */
332   if (anthy_metaword_type_tab[top_mw->type].status != MW_STATUS_WRAPPED) {
333     ce->flag = (se->best_mw == mw) ? CEF_BEST : CEF_NONE;
334   } else {
335     ce->flag = CEF_GUESS;
336   }
337
338   enum_candidates(se, ce, 0, 0);
339   anthy_release_cand_ent(ce);
340 }
341
342 /** combined¤Êmetaword¤ÏÆó¤Ä¤Î¸ì¤ò¹çÂΤ·¤Æ°ì¤Ä¤Î¸ì¤È¤·¤Æ½Ð¤¹ */
343 static void
344 make_candidate_from_combined_metaword(struct seg_ent *se,
345                                       struct meta_word *mw,
346                                       struct meta_word *top_mw,
347                                       int is_reverse)
348 {
349   /*
350    * ³Æñ¸ì¤ÎÉʻ줬·èÄꤵ¤ì¤¿¾õÂ֤ǥ³¥ß¥Ã¥È¤µ¤ì¤ë¡£
351    */
352   struct cand_ent *ce;
353
354   /* Ê£¿ô(1¤â´Þ¤à)¤Îñ¸ì¤Ç¹½À®¤µ¤ì¤ëʸÀá¤Ëñ¸ì¤ò³äÅö¤Æ¤Æ¤¤¤¯ */
355   ce = alloc_cand_ent();
356   ce->nr_words = mw->nr_parts;
357   ce->score = 0;
358   ce->str.str = NULL;
359   ce->str.len = 0;
360   ce->elm = calloc(sizeof(struct cand_elm),ce->nr_words);
361   ce->mw = top_mw;
362
363   /* ÀÜƬ¼­, ¼«Î©¸ìÉô, ÀÜÈø¼­, ÉÕ°¸ì */
364   make_cand_elem_from_word_list(se, ce, mw->mw1->wl, 0, is_reverse);
365   if (mw->mw2) {
366     make_cand_elem_from_word_list(se, ce, mw->mw2->mw1->wl, NR_PARTS, is_reverse);
367   }
368
369   /* WRAP¤µ¤ì¤Æ¤¤¤¿¤éGUESS¤ÈƱ¤¸°·¤¤¤Ë¤·¤ÆÅÀ¿ô¤ò²¼¤²¤ë */
370   if (anthy_metaword_type_tab[top_mw->type].status != MW_STATUS_WRAPPED) {
371     ce->flag = (se->best_mw == mw) ? CEF_BEST : CEF_NONE;
372   } else {
373     ce->flag = CEF_GUESS;
374   }
375
376   enum_candidates(se, ce, 0, 0);
377   anthy_release_cand_ent(ce);
378 }
379
380
381 /** splitter¤Î¾ðÊó¤òÍøÍѤ·¤Æ¸õÊä¤òÀ¸À®¤¹¤ë
382  */
383 static void
384 proc_splitter_info(struct seg_ent *se,
385                    struct meta_word *mw,
386                    /* top¤È¤Ïtree¤Î¥È¥Ã¥× */
387                    struct meta_word *top_mw,
388                    int is_reverse)
389 {
390   enum mw_status st;
391   if (!mw) return;
392
393   /* ¤Þ¤ºwordlist¤ò»ý¤Ämetaword¤Î¾ì¹ç */
394   if (mw->wl && mw->wl->len) {
395     make_candidate_from_simple_metaword(se, mw, top_mw, is_reverse);
396     return;
397   }
398   
399   st = anthy_metaword_type_tab[mw->type].status;
400   switch (st) {
401   case MW_STATUS_WRAPPED:
402     /* wrap¤µ¤ì¤¿¤â¤Î¤Î¾ðÊó¤ò¼è¤ê½Ð¤¹ */
403     proc_splitter_info(se, mw->mw1, top_mw, is_reverse);
404     break;
405   case MW_STATUS_COMBINED:
406     make_candidate_from_combined_metaword(se, mw, top_mw, is_reverse);
407     break;
408   case MW_STATUS_COMPOUND:
409     /* Ï¢Ê¸Àá¤ÎÍÕ */
410     {
411       struct cand_ent *ce;
412       ce = alloc_cand_ent();
413       ce->str.str = anthy_xstr_dup_str(&mw->cand_hint);
414       ce->str.len = mw->cand_hint.len;
415       ce->flag = CEF_COMPOUND;
416       ce->mw = top_mw;
417       push_back_candidate(se, ce);
418     }
419     break;
420   case MW_STATUS_COMPOUND_PART:
421     /* Ï¢Ê¸Àá¤Î¸Ä¡¹¤ÎʸÀá¤ò·ë¹ç¤·¤Æ°ì¤Ä¤ÎʸÀá¤È¤·¤Æ¤ß¤¿¤â¤Î */
422     /* BREAK THROUGH */
423   case MW_STATUS_OCHAIRE:
424     {
425     /* metaword¤ò»ý¤¿¤Ê¤¤¸õÊäʸ»úÎó¤¬
426        Ä¾Àܤ˻ØÄꤵ¤ì¤¿ */
427       struct cand_ent *ce;
428       ce = alloc_cand_ent();
429       ce->str.str = anthy_xstr_dup_str(&mw->cand_hint);
430       ce->str.len = mw->cand_hint.len;
431       ce->mw = top_mw;
432       ce->flag = (st == MW_STATUS_OCHAIRE) ? CEF_OCHAIRE : CEF_COMPOUND_PART;
433
434       if (mw->len < se->len) {
435         /* metaword¤Ç¥«¥Ð¡¼¤µ¤ì¤Æ¤Ê¤¤Îΰè¤Îʸ»úÎó¤òÉÕ¤±¤ë */
436         xstr xs;
437         xs.str = &se->str.str[mw->len];
438         xs.len = se->len - mw->len;
439         anthy_xstrcat(&ce->str ,&xs);
440       }
441       push_back_candidate(se, ce);
442     }
443     break;
444   case MW_STATUS_NONE:
445     break;
446   default:
447     break;
448   }
449 }
450
451 /** context.c¤«¤é¸Æ½Ð¤µ¤ì¤ë¤â¤Ã¤È¤âÂçʪ
452  * °ì¤Ä°Ê¾å¤Î¸õÊä¤òɬ¤ºÀ¸À®¤¹¤ë
453  */
454 void
455 anthy_do_make_candidates(struct splitter_context *sc,
456                          struct seg_ent *se, int is_reverse)
457 {
458   int i;
459
460   /* metaword¤«¤é¸õÊä¤òÀ¸À®¤¹¤ë */
461   for (i = 0; i < se->nr_metaword; i++) {
462     struct meta_word *mw = se->mw_array[i];
463     if (anthy_splitter_debug_flags() & SPLITTER_DEBUG_CAND) {
464       anthy_print_metaword(sc, mw);
465     }
466     proc_splitter_info(se, mw, mw, is_reverse);
467   }
468   if (anthy_splitter_debug_flags() & SPLITTER_DEBUG_CAND) {
469     printf("#done\n");
470   }
471   /* Ã±´Á»ú¤Ê¤É¤Î¸õÊä */
472   push_back_singleword_candidate(se, is_reverse);
473
474   /* ¤Ò¤é¤¬¤Ê¡¢¥«¥¿¥«¥Ê¤Î̵ÊÑ´¹¥¨¥ó¥È¥ê¤òºî¤ë */
475   push_back_noconv_candidate(se);
476
477   /* ¸õÊ䤬Æó¤Ä¤·¤«Ìµ¤¤¤È¤­¤ÏºÇ¸å¤¬½õ»ì¤Ç»Ä¤ê¤¬Ê¿²¾Ì¾¤Î¸õÊä¤òºî¤ì¤ë¤«»î¤¹ */
478   push_back_guessed_candidate(se);
479 }