Create devel package not to install header and .pc file in binary
[platform/core/uifw/anthy.git] / src-main / context.c
1 /*
2  * ÊÑ´¹¤äʸÀá¤Î¿­½Ì¤Ê¤É¤ÎÁàºî¤¬¿Ê¹ÔÃæ¤Îʸ»úÎó¤ä¸õÊä¤Ê¤É¤ò
3  * ¤Þ¤È¤á¤ÆÊÑ´¹¥³¥ó¥Æ¥­¥¹¥È¤È¸Æ¤Ö¡£
4  * Anthy¤Î¥³¥ó¥Æ¥­¥¹¥È¤ËÂФ¹¤ëÁàºî¤ÏÁ´¤Æ¤³¤³¤«¤é¸Æ¤Ð¤ì¤ë¡£
5  * ³ÆÁàºî¤ËÂФ·¤ÆÊÑ´¹¥Ñ¥¤¥×¥é¥¤¥ó¤ÎɬÍפʥ⥸¥å¡¼¥ë¤ò½ç¤Ë¸Æ¤Ó¤À¤¹¡£
6  *
7  * personality¤Î´ÉÍý¤â¤¹¤ë¡£
8  *
9  * Funded by IPA̤Ƨ¥½¥Õ¥È¥¦¥§¥¢ÁϤ»ö¶È 2001 10/29
10  * Copyright (C) 2000-2007 TABATA Yusuke
11  *
12  * $Id: context.c,v 1.26 2002/11/17 14:45:47 yusuke Exp $
13  */
14 /*
15   This library is free software; you can redistribute it and/or
16   modify it under the terms of the GNU Lesser General Public
17   License as published by the Free Software Foundation; either
18   version 2 of the License, or (at your option) any later version.
19
20   This library is distributed in the hope that it will be useful,
21   but WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23   Lesser General Public License for more details.
24
25   You should have received a copy of the GNU Lesser General Public
26   License along with this library; if not, write to the Free Software
27   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
28  */
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36
37 #include <anthy/anthy.h>
38 #include <anthy/alloc.h>
39 #include <anthy/record.h>
40 #include <anthy/ordering.h>
41 #include <anthy/splitter.h>
42 #include <anthy/xstr.h>
43 #include "main.h"
44
45 /**/
46 static allocator context_ator;
47
48 /** ¸½ºß¤Îpersonality 
49  * Ì¤ÀßÄê»þ: null
50  * Ì¤ÀßÄê¤Î¤Þ¤ÞÊÑ´¹¤ò³«»Ï¤·¤¿¾ì¹ç: "default"
51  * anonymous¤Î¾ì¹ç: ""
52  */
53 static char *current_personality;
54
55 /**/
56 #define HISTORY_FILE_LIMIT 100000
57
58 static void
59 context_dtor(void *p)
60 {
61   anthy_do_reset_context((struct anthy_context *)p);
62 }
63
64 /** ¸½ºß¤Îpersonality¤òÊÖ¤¹ */
65 static char *
66 get_personality(void)
67 {
68   if (!current_personality) {
69     current_personality = strdup("default");
70     anthy_dic_set_personality(current_personality);
71   }
72   return current_personality;
73 }
74
75 static void
76 release_segment(struct seg_ent *s)
77 {
78   if (s->cands) {
79     int i;
80     for (i = 0; i < s->nr_cands; i++) {
81       anthy_release_cand_ent(s->cands[i]);
82     }
83     free (s->cands);
84   }
85   if (s->mw_array) {
86     free(s->mw_array);
87   }
88   free(s);
89   
90 }
91
92 /** Ê¸Àá¥ê¥¹¥È¤ÎºÇ¸å¤ÎÍ×ÁǤòºï½ü¤¹¤ë */
93 static void
94 pop_back_seg_ent(struct anthy_context *c)
95 {
96   struct seg_ent *s;
97   s = c->seg_list.list_head.prev;
98   if (s == &c->seg_list.list_head) {
99     return ;
100   }
101   s->prev->next = s->next;
102   s->next->prev = s->prev;
103   release_segment(s);
104   c->seg_list.nr_segments --;
105 }
106
107
108 /** nÈÖÌܤÎʸÀá¤Îʸ»ú¤Îindex¤òµá¤á¤ë */
109 static int
110 get_nth_segment_index(struct anthy_context *c, int n)
111 {
112   int i,s;
113   for (i = 0, s = 0; i < c->str.len; i++) {
114     if (c->split_info.ce[i].seg_border) {
115       if (s == n) {
116         return i;
117       }
118       s++;
119     }
120   }
121   return -1;
122 }
123
124 /** nÈÖÌܤÎʸÀá¤ÎŤµ¤òµá¤á¤ë¡¥
125  * segment_list¤¬¹½À®¤µ¤ì¤Æ¤¤¤Ê¤¯¤Æ¤â·×»»¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ë¡¥
126  */
127 static int
128 get_nth_segment_len(struct anthy_context *c, int sindex)
129 {
130   int a,i,l;
131   a = get_nth_segment_index(c, sindex);
132   if ( a == -1){
133     return -1;
134   }
135   l = 1;
136   for (i = a+1; !c->split_info.ce[i].seg_border; i++) {
137     l++;
138   }
139   return l;
140 }
141
142 /** metaword¤ÎÇÛÎó¤òºî¤ë */
143 static void
144 make_metaword_array(struct anthy_context *ac,
145                     struct seg_ent *se)
146 {
147   int i;
148   se->mw_array = NULL;
149   for (i = se->len; i > 0; i--) {
150     int j;
151     /* ºÇ¸å¤ËÂùÅÀ¤È¤«¤¬¤Ä¤¤¤Æ¤¿¤éľÁ°¤Îʸ»ú¤´¤ÈÍ */
152     if (i < se->len &&
153         anthy_get_xchar_type(se->str.str[i]) & XCT_PART) {
154       /* FIXME ÂùÅÀ¤È¤«¤¬¤¢¤ê¤¨¤Ê¤¤Ê¤Ӥò¤·¤Æ¤¿¤é */
155       i--;
156       continue ;
157     }
158
159     se->nr_metaword = anthy_get_nr_metaword(&ac->split_info, se->from, i);
160     if (!se->nr_metaword) {
161       continue ;
162     }
163     /* metaword¤òÇÛÎó¤Ë¼è¤ê¹þ¤à */
164     se->mw_array = malloc(sizeof(struct meta_word*) * se->nr_metaword);
165     for (j = 0; j < se->nr_metaword; j++) {
166       se->mw_array[j] = anthy_get_nth_metaword(&ac->split_info, se->from, i, j);
167     }
168     return;
169   }
170 }
171
172 static struct seg_ent*
173 create_segment(struct anthy_context *ac, int from, int len,
174                struct meta_word* best_mw)
175 {
176   struct seg_ent* s;
177   s = (struct seg_ent *)malloc(sizeof(struct seg_ent));
178   s->str.str = &ac->str.str[from];
179   s->str.len = len;
180   s->from = from;
181   s->len = s->str.len;
182   s->nr_cands = 0;
183   s->cands = NULL;
184   s->best_seg_class = ac->split_info.ce[from].best_seg_class;
185   s->best_mw = best_mw;
186   make_metaword_array(ac, s);
187   return s;
188 }
189
190 /** ÊÑ´¹¥³¥ó¥Æ¥­¥¹¥È¤ËʸÀá¤òÄɲ乤ë */
191 static void
192 push_back_segment(struct anthy_context *ac, struct seg_ent *se)
193 {
194   se->next = &ac->seg_list.list_head;
195   se->prev = ac->seg_list.list_head.prev;
196   ac->seg_list.list_head.prev->next = se;
197   ac->seg_list.list_head.prev = se;
198   ac->seg_list.nr_segments ++;
199   se->committed = -1;
200 }
201
202 /** splitter¤Ë¤è¤Ã¤ÆÇÛÎóÃæ¤ËÉÕ¤±¤é¤ì¤¿Ê¸Àᶭ³¦¤Î¥Þ¡¼¥¯¤«¤é¡¢
203  * Ê¸Àá¤Î¥ê¥¹¥È¤ò¹½À®¤¹¤ë
204  */
205 static void
206 create_segment_list(struct anthy_context *ac, int from, int to)
207 {
208   int i, n;
209   struct seg_ent *s;
210   /* from ¤Î½ê¤Þ¤Ç¤Ë¤¤¤¯¤Ä¤ÎʸÀ᤬¤¢¤ë¤«Ä´¤Ù¤ë */
211   i = 0; n = 0;
212   while (i < from) {
213     i += get_nth_segment_len(ac, n);
214     n++;
215   };
216   /**/
217   for (i = from; i < to; i++) {
218     if (ac->split_info.ce[i].seg_border) {
219       int len = get_nth_segment_len(ac, n);
220       s = create_segment(ac, i, len, ac->split_info.ce[i].best_mw);
221
222       push_back_segment(ac, s);
223       n++;
224     }
225   }
226 }
227
228 /** ¥³¥ó¥Æ¥­¥¹¥È¤òºî¤ë */
229 struct anthy_context *
230 anthy_do_create_context(int encoding)
231 {
232   struct anthy_context *ac;
233   char *p = get_personality();
234
235   if (!p) {
236     return NULL;
237   }
238
239   ac = (struct anthy_context *)anthy_smalloc(context_ator);
240   ac->str.str = NULL;
241   ac->str.len = 0;
242   ac->seg_list.nr_segments = 0;
243   ac->seg_list.list_head.prev = &ac->seg_list.list_head;
244   ac->seg_list.list_head.next = &ac->seg_list.list_head;
245   ac->split_info.word_split_info = NULL;
246   ac->split_info.ce = NULL;
247   ac->ordering_info.oc = NULL;
248   ac->dic_session = NULL;
249   ac->prediction.str.str = NULL;
250   ac->prediction.str.len = 0;
251   ac->prediction.nr_prediction = 0;
252   ac->prediction.predictions = NULL;
253   ac->encoding = encoding;
254   ac->reconversion_mode = ANTHY_RECONVERT_AUTO;
255
256   return ac;
257 }
258
259 /** ¥³¥ó¥Æ¥­¥¹¥È¤Î¥¢¥í¥±¡¼¥¿¤òºî¤ë */
260 void
261 anthy_init_contexts(void)
262 {
263   context_ator = anthy_create_allocator(sizeof(struct anthy_context),
264                                         context_dtor);
265 }
266
267 void
268 anthy_quit_contexts(void)
269 {
270   anthy_free_allocator(context_ator);
271 }
272
273 static void
274 release_prediction(struct prediction_cache *pc)
275 {
276   int i;
277   if (pc->str.str) {
278     free(pc->str.str);
279     pc->str.str = NULL;
280   }
281   if (pc->predictions) {
282     for (i = 0; i < pc->nr_prediction; ++i) {
283       anthy_free_xstr(pc->predictions[i].src_str);
284       anthy_free_xstr(pc->predictions[i].str);
285     }
286     free(pc->predictions);
287     pc->predictions = NULL;
288   }
289 }
290
291 void
292 anthy_release_segment_list(struct anthy_context *ac)
293 {
294   int i, sc;
295   sc = ac->seg_list.nr_segments;
296   for (i = 0; i < sc; i++) {
297     pop_back_seg_ent(ac);
298   }
299   ac->seg_list.nr_segments = 0;
300 }
301
302 /* reset¤Ç¤Ïcontext¤Î¤¿¤á¤Ë³ÎÊݤµ¤ì¤¿¥ê¥½¡¼¥¹¤òÁ´¤Æ²òÊü¤¹¤ë */
303 void
304 anthy_do_reset_context(struct anthy_context *ac)
305 {
306   /* ¤Þ¤º¼­½ñ¥»¥Ã¥·¥ç¥ó¤ò²òÊü */
307   if (ac->dic_session) {
308     anthy_dic_release_session(ac->dic_session);
309     ac->dic_session = NULL;
310   }
311   if (!ac->str.str) {
312     /* Ê¸»úÎó¤¬ÀßÄꤵ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð²òÊü¤¹¤Ù¤­Êª¤Ï¤â¤¦Ìµ¤¤ */
313     return ;
314   }
315   free(ac->str.str);
316   ac->str.str = NULL;
317   anthy_release_split_context(&ac->split_info);
318   anthy_release_segment_list(ac);
319
320   /* Í½Â¬¤µ¤ì¤¿Ê¸»úÎó¤Î²òÊü */
321   release_prediction(&ac->prediction);
322 }
323
324 void
325 anthy_do_release_context(struct anthy_context *ac)
326 {
327   anthy_sfree(context_ator, ac);
328 }
329
330 static void
331 make_candidates(struct anthy_context *ac, int from, int from2, int is_reverse)
332 {
333   int i;
334   int len = ac->str.len;
335
336   /* Ê¸Àá¤Î¶­³¦¤òÀßÄê */
337   /* from ¤È from2¤Î´Ö¤Ë¶­³¦¤òºî¤ë¤³¤È¤ò¶Ø»ß¤¹¤ë */
338   anthy_mark_border(&ac->split_info, from, from2, len);
339   create_segment_list(ac, from, len);
340   anthy_sort_metaword(&ac->seg_list);
341
342   /* ¸õÊä¤òÎóµó */
343   for (i = 0; i < ac->seg_list.nr_segments; i++) {
344     anthy_do_make_candidates(&ac->split_info,
345                              anthy_get_nth_segment(&ac->seg_list, i),
346                              is_reverse);
347   }
348   /* ¸õÊä¤ò¥½¡¼¥È */
349   anthy_sort_candidate(&ac->seg_list, 0);
350 }
351
352 int
353 anthy_do_context_set_str(struct anthy_context *ac, xstr *s, int is_reverse)
354 {
355   int i;
356
357   /* Ê¸»úÎó¤ò¥³¥Ô¡¼(°ìʸ»úʬ;·×¤Ë¤·¤Æ0¤ò¥»¥Ã¥È) */
358   ac->str.str = (xchar *)malloc(sizeof(xchar)*(s->len+1));
359   anthy_xstrcpy(&ac->str, s);
360   ac->str.str[s->len] = 0;
361
362   /* splitter¤Î½é´ü²½*/
363   anthy_init_split_context(&ac->str, &ac->split_info, is_reverse);
364
365   /* ²ò¤Î¸õÊä¤òºîÀ® */
366   make_candidates(ac, 0, 0, is_reverse);
367   
368   /* ºÇ½é¤ËÀßÄꤷ¤¿Ê¸Àᶭ³¦¤ò³Ð¤¨¤Æ¤ª¤¯ */
369   for (i = 0; i < ac->seg_list.nr_segments; i++) {
370     struct seg_ent *s = anthy_get_nth_segment(&ac->seg_list, i);
371     ac->split_info.ce[s->from].initial_seg_len = s->len;
372   }
373
374   return 0;
375 }
376
377 void
378 anthy_do_resize_segment(struct anthy_context *ac,
379                         int nth, int resize)
380 {
381   int i;
382   int index, len, sc;
383
384   /* resize¤¬²Äǽ¤«¸¡ºº¤¹¤ë */
385   if (nth >= ac->seg_list.nr_segments) {
386     return ;
387   }
388   index = get_nth_segment_index(ac, nth);
389   len = get_nth_segment_len(ac, nth);
390   if (index + len + resize > ac->str.len) {
391     return ;
392   }
393   if (len + resize < 1) {
394     return ;
395   }
396
397   /* nth°Ê¹ß¤Îseg_ent¤ò²òÊü¤¹¤ë */
398   sc = ac->seg_list.nr_segments;
399   for (i = nth; i < sc; i++) {
400     pop_back_seg_ent(ac);
401   }
402
403   /* resize¤·¤¿seg_border¤ò¥Þ¡¼¥¯¤¹¤ë */
404   /* ¸½ºß¤Î¥Þ¡¼¥¯¤ò¾Ã¤·¤Æ¿·¤·¤¤¥Þ¡¼¥¯¤ò¤Ä¤±¤ë */
405   ac->split_info.ce[index+len].seg_border = 0;
406   ac->split_info.ce[ac->str.len].seg_border = 1;
407   for (i = index+len+resize+1; i < ac->str.len; i++) {
408     ac->split_info.ce[i].seg_border = 0;
409   }
410   ac->split_info.ce[index+len+resize].seg_border = 1;
411   for (i = index; i < ac->str.len; i++) {
412     ac->split_info.ce[i].best_mw = NULL;
413   }
414
415   /* ²ò¤Î¸õÊä¤òºîÀ® */
416   make_candidates(ac, index, index+len+resize, 0);
417 }
418
419 /*
420  * nÈÖ¤á¤ÎʸÀá¤ò¼èÆÀ¤¹¤ë¡¢Ìµ¤¤¾ì¹ç¤Ë¤ÏNULL¤òÊÖ¤¹
421  */
422 struct seg_ent *
423 anthy_get_nth_segment(struct segment_list *sl, int n)
424 {
425   int i;
426   struct seg_ent *se;
427   if (n >= sl->nr_segments ||
428       n < 0) {
429     return NULL;
430   }
431   for (i = 0, se = sl->list_head.next; i < n; i++, se = se->next);
432   return se;
433 }
434
435 int
436 anthy_do_set_prediction_str(struct anthy_context *ac, xstr* xs)
437 {
438   struct prediction_cache* prediction = &ac->prediction;
439   int nr_prediction;
440
441   /* ¤Þ¤º¼­½ñ¥»¥Ã¥·¥ç¥ó¤ò²òÊü */
442   if (ac->dic_session) {
443     anthy_dic_release_session(ac->dic_session);
444     ac->dic_session = NULL;
445   }
446   /* Í½Â¬¤µ¤ì¤¿Ê¸»úÎó¤Î²òÊü */
447   release_prediction(&ac->prediction);
448
449   /* ¼­½ñ¥»¥Ã¥·¥ç¥ó¤Î³«»Ï */
450   if (!ac->dic_session) {
451     ac->dic_session = anthy_dic_create_session();
452     if (!ac->dic_session) {
453       return -1;
454     }
455   }
456
457   prediction->str.str = (xchar*)malloc(sizeof(xchar*)*(xs->len+1));
458   anthy_xstrcpy(&prediction->str, xs);
459   prediction->str.str[xs->len]=0;
460
461   nr_prediction = anthy_traverse_record_for_prediction(xs, NULL);
462   prediction->nr_prediction = nr_prediction;
463
464   if (nr_prediction) {
465     prediction->predictions = (struct prediction_t*)malloc(sizeof(struct prediction_t) *
466                                                            nr_prediction);
467     anthy_traverse_record_for_prediction(xs, prediction->predictions);
468   }
469   return 0;
470 }
471
472 static const char *
473 get_change_state(struct anthy_context *ac)
474 {
475   int resize = 0, cand_change = 0;
476   int i;
477   for (i = 0; i < ac->seg_list.nr_segments; i++) {
478     struct seg_ent *s = anthy_get_nth_segment(&ac->seg_list, i);
479     if (ac->split_info.ce[s->from].initial_seg_len != s->len) {
480       resize = 1;
481     }
482     if (s->committed > 0) {
483       cand_change = 1;
484     }
485   }
486   /**/
487   if (resize && cand_change) {
488     return "SC";
489   }
490   if (resize) {
491     return "S";
492   }
493   if (cand_change) {
494     return "C";
495   }
496   return "-";
497 }
498
499 static void
500 write_history(FILE *fp, struct anthy_context *ac)
501 {
502   int i;
503   /* Æɤߠ*/
504   fprintf(fp, "|");
505   for (i = 0; i < ac->seg_list.nr_segments; i++) {
506     struct seg_ent *s = anthy_get_nth_segment(&ac->seg_list, i);
507     char *c = anthy_xstr_to_cstr(&s->str, ANTHY_EUC_JP_ENCODING);
508     fprintf(fp, "%s|", c);
509     free(c);
510   }
511   fprintf(fp, " |");
512   /* ·ë²Ì */
513   for (i = 0; i < ac->seg_list.nr_segments; i++) {
514     struct seg_ent *s = anthy_get_nth_segment(&ac->seg_list, i);
515     char *c;
516     /**/
517     if (s->committed < 0) {
518       fprintf(fp, "?|");
519       continue ;
520     }
521     c = anthy_xstr_to_cstr(&s->cands[s->committed]->str,
522                            ANTHY_EUC_JP_ENCODING);
523     fprintf(fp, "%s|", c);
524     free(c);
525   }
526 }
527
528 void
529 anthy_save_history(const char *fn, struct anthy_context *ac)
530 {
531   FILE *fp;
532   struct stat st;
533   if (!fn) {
534     return ;
535   }
536   fp = fopen(fn, "a");
537   if (!fp) {
538     return ;
539   }
540   if (stat(fn, &st) ||
541       st.st_size > HISTORY_FILE_LIMIT) {
542     fclose(fp);
543     return ;
544   }
545   /**/
546   fprintf(fp, "anthy-%s ", anthy_get_version_string());
547   fprintf(fp, "%s ", get_change_state(ac));
548   write_history(fp, ac);
549   fprintf(fp, "\n");
550   fclose(fp);
551   /**/
552   chmod(fn, S_IREAD | S_IWRITE);
553 }
554
555 /** ¸õÊä¤òɽ¼¨¤¹¤ë */
556 void
557 anthy_print_candidate(struct cand_ent *ce)
558 {
559   int mod = (ce->score % 1000);
560   int seg_score = 0;
561
562   if (ce->mw) {
563     seg_score = ce->mw->score;
564   }
565   anthy_putxstr(&ce->str);
566   printf(":(");
567   /*if (ce->nr_words == 1) {printf("%d,", ce->elm[0].id);    }*/
568   if (ce->flag & CEF_OCHAIRE) {
569     putchar('o');
570   }
571   if (ce->flag & CEF_SINGLEWORD) {
572     putchar('1');
573   }
574   if (ce->flag & CEF_GUESS) {
575     putchar('g');
576   }
577   if (ce->flag & (CEF_KATAKANA | CEF_HIRAGANA)) {
578     putchar('N');
579   }
580   if (ce->flag & CEF_USEDICT) {
581     putchar('U');
582   }
583   if (ce->flag & CEF_CONTEXT) {
584     putchar('C');
585   }
586   printf(",%d,", seg_score);
587
588     
589   if (ce->mw) {
590     printf("%s,%d", anthy_seg_class_sym(ce->mw->seg_class),
591            ce->mw->struct_score);
592   } else {
593     putchar('-');
594   }
595   printf(")");
596
597   if (ce->score >= 1000) {
598     printf("%d,", ce->score/1000);
599     if (mod < 100) {
600       printf("0");
601     }
602     if (mod < 10) {
603       printf("0");
604     }
605     printf("%d ", mod);
606   } else {
607     printf("%d ", ce->score);
608   }
609 }
610
611 /** Ê¸Àá¤òɽ¼¨¤¹¤ë */
612 static void
613 print_segment(struct seg_ent *e)
614 {
615   int i;
616
617   anthy_putxstr(&e->str);
618   printf("(");
619   for ( i = 0 ; i < e->nr_cands ; i++) {
620     anthy_print_candidate(e->cands[i]);
621     printf(",");
622   }
623   printf(")");
624   printf(":\n");
625 }
626
627 /** ¥³¥ó¥Æ¥­¥¹¥È¤òɽ¼¨¤¹¤ë */
628 void
629 anthy_do_print_context(struct anthy_context *ac, int encoding)
630 {
631   int i;
632   struct char_ent *ce;
633   anthy_xstr_set_print_encoding(encoding);
634
635   ce = ac->split_info.ce;
636   if (!ce) {
637     printf("(invalid)\n");
638     return ;
639   }
640   /* ³Æʸ»ú¤òɽ¼¨¤¹¤ë */
641   for (i = 0, ce = ac->split_info.ce; i < ac->str.len; i++, ce++) {
642     if (ce->seg_border) {
643       printf("|");
644     }
645     anthy_putxchar(*(ce->c));
646   }
647   printf("\n");
648   /* ³ÆʸÀá¤òɽ¼¨¤¹¤ë */
649   for (i = 0; i < ac->seg_list.nr_segments; i++) {
650     print_segment(anthy_get_nth_segment(&ac->seg_list, i));
651   }
652   printf("\n");
653 }
654
655 void
656 anthy_release_cand_ent(struct cand_ent *ce)
657 {
658   if (ce->elm) {
659     free(ce->elm);
660   }
661   if (&ce->str) {
662     anthy_free_xstr_str(&ce->str);
663   }
664   free(ce);
665 }
666
667 int
668 anthy_do_set_personality(const char *id)
669 {
670   if (current_personality) {
671     /* ¤¹¤Ç¤ËÀßÄꤵ¤ì¤Æ¤ë */
672     return -1;
673   }
674   if (!id || strchr(id, '/')) {
675     return -1;
676   }
677   current_personality = strdup(id);
678   anthy_dic_set_personality(current_personality);
679   return 0;
680 }
681
682 void
683 anthy_init_personality(void)
684 {
685   current_personality = NULL;
686 }
687
688 void
689 anthy_quit_personality(void)
690 {
691   if (current_personality) {
692     free(current_personality);
693     current_personality = NULL;
694   }
695 }