Update copyright years
[m17n/m17n-lib.git] / example / mimx-ispell.c
1 /* imx-ispell.c -- Ispell input method external module. -*- coding: euc-jp; -*-
2    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21    02111-1307, USA.  */
22
23 /***en
24     @enpage mimx-ispell external module for the input method <en, ispell>
25
26     @section mimx-ispell-description DESCRIPTION
27
28     The shared library mimx-ispell.so is an external module used by the
29     input method <en, ispell>.  It exports these functions.
30
31     <ul>
32     <li> init
33
34     Initialize this library.
35
36     <li> fini
37
38     Finalize this library.
39
40     <li> ispell_word
41
42     Check the spell of the current preedit text (English) and, if the
43     spell is incorrect,  return a list of candidates.
44
45     </ul>
46
47     This program is just for demonstrating how to write an external
48     module for an m17n input method, not for an actual use.
49
50     @section mimx-ispell-seealso See also
51     @ref mdbIM
52 */
53 /***ja
54     @japage mimx-ispell ÆþÎϥ᥽¥Ã¥É <en, ispell> Íѳ°Éô¥â¥¸¥å¡¼¥ë
55
56     @section mimx-ispell-description DESCRIPTION
57
58     ¶¦Í­¥é¥¤¥Ö¥é¥ê mimx-ispell.so ¤ÏÆþÎϥ᥽¥Ã¥É <en, ispell> ¤ËÍѤ¤¤é 
59     ¤ì¤ë³°Éô¥â¥¸¥å¡¼¥ë¤Ç¤¢¤ê¡¢°Ê²¼¤Î´Ø¿ô¤ò export ¤·¤Æ¤¤¤ë¡£
60
61     <ul>
62     <li> init
63
64     ¥é¥¤¥Ö¥é¥ê¤Î½é´ü²½¡£
65
66     <li> fini
67
68     ¥é¥¤¥Ö¥é¥ê¤Î½ªÎ»¡£ 
69
70     <li> ispell_word
71
72     ¸½ºß¤Î preedit ¥Æ¥­¥¹¥È (±Ñʸ) ¤ÎÄÖ¤òÄ´¤Ù¡¢´Ö°ã¤Ã¤Æ¤¤¤ì¤Ð¸õÊä¤Î¥ê 
73     ¥¹¥È¤òÊÖ¤¹¡£
74
75     </ul>
76
77     ¤³¤Î¥×¥í¥°¥é¥à¤Ïm17n ÆþÎϥ᥽¥Ã¥ÉÍѳ°Éô¥â¥¸¥å¡¼¥ë¤Î½ñ¤­Êý¤ò¼¨¤¹¤¿ 
78     ¤á¤Î¤â¤Î¤Ç¤¢¤ê¡¢¼ÂºÝ¤ÎÍøÍѤò°Õ¿Þ¤·¤¿¤â¤Î¤Ç¤Ï¤Ê¤¤¡£
79
80     @section mimx-ispell-seealso »²¾È
81     @ref mdbIM
82 */
83
84 #ifndef FOR_DOXYGEN
85
86 #include <stdio.h>
87 #include <string.h>
88 #include <m17n-gui.h>
89
90 #ifdef HAVE_ISPELL
91
92 static int initialized = 0;
93 static int face_available;
94 static MFace *mface_overstrike = NULL;
95
96 static MPlist *
97 add_action (MPlist *actions, MSymbol name, MSymbol key, void *val)
98 {
99   MPlist *action = mplist ();
100
101   mplist_add (action, Msymbol, name);
102   if (key != Mnil)
103     mplist_add (action, key, val);
104   mplist_add (actions, Mplist, action);
105   m17n_object_unref (action);
106   return actions;
107 }
108
109 MPlist *
110 init (MPlist *args)
111 {
112   if (! initialized++)
113     {
114       MFaceHLineProp hline;
115
116       face_available = 0;
117       if (m17n_status () == M17N_GUI_INITIALIZED)
118         {
119           face_available = 1;
120           hline.type = MFACE_HLINE_STRIKE_THROUGH;
121           hline.width = 1;
122           hline.color = msymbol ("black");
123           mface_overstrike = mface ();
124           mface_put_prop (mface_overstrike, Mhline, &hline);
125         }
126     }
127   return NULL;
128 }
129
130 MPlist *
131 fini (MPlist *args)
132 {
133   if (initialized != 0
134       && --initialized == 0
135       && face_available)
136     m17n_object_unref (mface_overstrike);
137   return NULL;
138 }
139
140 MPlist *
141 ispell_word (MPlist *args)
142 {
143   MInputContext *ic;
144   unsigned char buf[256];
145   int nbytes;
146   MPlist *actions, *candidates, *plist;
147   char command[256];
148   char **words;
149   FILE *ispell;
150   char *p = (char *) buf;
151   int i, n;
152   MSymbol init_state;
153   MSymbol select_state;
154   MText *mt;
155
156   ic = mplist_value (args);
157   args = mplist_next (args);
158   init_state = (MSymbol) mplist_value (args);
159   args = mplist_next (args);
160   select_state = (MSymbol) mplist_value (args);
161   nbytes = mconv_encode_buffer (Mcoding_us_ascii, ic->preedit, buf, 256);
162
163   actions = mplist ();
164
165   if (nbytes < 3)
166     return add_action (actions, msymbol ("shift"), Msymbol, init_state);
167
168   buf[nbytes] = '\0';
169   sprintf (command, "echo %s | ispell -a -m", (char *) buf);
170   ispell = popen (command, "r");
171   if (! ispell)
172     return add_action (actions, msymbol ("shift"), Msymbol, init_state);
173
174   /* Skip the heading line.  */
175   fgets (p, 256, ispell);
176   /* Read just 256 bytes, thus candidates listed after the first 256
177      bytes are just ignored.  */
178   fgets (p, 256, ispell);
179   pclose (ispell);
180   p[strlen (p) - 1] = '\0';
181   if (*p != '&' && *p != '#')
182     return add_action (actions, msymbol ("shift"), Msymbol, init_state);
183
184   add_action (actions, msymbol ("delete"), Msymbol,  msymbol ("@<"));
185   if (*p == '#')
186     {
187       mt = mtext_dup (ic->preedit);
188       if (face_available)
189         mtext_push_prop (mt, 0, mtext_len (mt), Mface, mface_overstrike);
190       mplist_add (actions, Mtext, mt);
191       add_action (actions, msymbol ("shift"), Msymbol, init_state);
192       m17n_object_unref (mt);
193       return actions;
194     }
195
196   p = strchr (p + 2, ' ');
197   if (sscanf (p, "%d", &n) != 1)
198     return add_action (actions, msymbol ("shift"), Msymbol, init_state);
199   words = alloca (sizeof (char *) * n);
200   p = strchr (p + 1, ' ');
201   p = strchr (p + 1, ' ');
202   for (i = 0; i < n - 1; i++)
203     {
204       words[i] = ++p;
205       p = strchr (p, ',');
206       if (! p)
207         {
208           n = i - 1;
209           break;
210         }
211       *p++ = '\0';
212     }
213   words[i] = ++p;
214   candidates = mplist ();
215   for (i = 0; i < n; i++)
216     {
217       mt = mconv_decode_buffer (Mcoding_us_ascii, (unsigned char *) words[i],
218                                 strlen (words[i]));
219       mplist_add (candidates, Mtext, mt);
220       m17n_object_unref (mt);
221     }
222   mt = mtext_dup (ic->preedit);
223   if (face_available)
224     mtext_push_prop (mt, 0, mtext_len (mt), Mface, mface_overstrike);
225   mplist_add (candidates, Mtext, mt);
226   m17n_object_unref (mt);
227   plist = mplist_add (mplist (), Mplist, candidates);
228   m17n_object_unref (candidates);
229   mplist_add (actions, Mplist, plist);
230   m17n_object_unref (plist);
231   add_action (actions, msymbol ("show"), Mnil, NULL);
232   add_action (actions, msymbol ("shift"), Msymbol, select_state);
233   return actions;
234 }
235
236 #else  /* not HAVE_ISPELL */
237
238 MPlist *ispell_word (MPlist *args) { return NULL; }
239
240 #endif /* not HAVE_ISPELL */
241 #endif /* not FOR_DOXYGEN */