Fix ispell on Windows.
[texmacs.git] / src / src / Plugins / Ispell / ispell.cpp
blob724403578bb8795d9bca258d77072f3842014a54
2 /******************************************************************************
3 * MODULE : ispell.cpp
4 * DESCRIPTION: interface with the ispell spell checker
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
12 #include "Ispell/ispell.hpp"
13 #include "file.hpp"
14 #include "resource.hpp"
15 #include "tm_link.hpp"
16 #include "convert.hpp"
18 string ispell_dictionary (string lang);
19 string ispell_extra_args (string lang);
20 string ispell_encode (string lan, string s);
21 string ispell_decode (string lan, string s);
23 /******************************************************************************
24 * The connection resource
25 ******************************************************************************/
27 RESOURCE(ispeller);
28 struct ispeller_rep: rep<ispeller> {
29 string lan; // name of the session
30 tm_link ln; // the pipe
32 public:
33 ispeller_rep (string lan);
34 string start ();
35 string retrieve ();
36 void send (string cmd);
38 RESOURCE_CODE(ispeller);
40 /******************************************************************************
41 * Routines for ispellers
42 ******************************************************************************/
44 ispeller_rep::ispeller_rep (string lan2): rep<ispeller> (lan2), lan (lan2) {}
46 string
47 ispeller_rep::start () {
48 if (is_nil (ln)) {
49 string cmd;
50 #ifdef OS_WIN32
51 string prg= "\"$TEXMACS_PATH/bin/aspell/aspell.exe\"";
52 cmd= prg * " --data-dir=.%//data --dict-dir=.%//dict -a";
53 #else
54 if (exists_in_path ("aspell")) cmd= "aspell";
55 else
56 #if defined (__MINGW__) || defined (__MINGW32__)
57 if (exists (url_system ("C:\\Program Files\\Aspell\\bin\\aspell.exe")))
58 cmd= "\"C:\\Program Files\\Aspell\\bin\\aspell.exe\"";
59 else
60 #endif
61 cmd= "ispell";
62 cmd << " -a -d " * ispell_dictionary (lan) * ispell_extra_args (lan);
63 #endif
64 ln= make_pipe_link (cmd);
66 if (ln->alive) return "ok";
67 string message= ln->start ();
68 if (DEBUG_IO) cout << "Ispell] Received " << message << "\n";
69 if (starts (message, "Error: ")) {
70 if (ln->alive) ln->stop ();
71 return message;
73 message= retrieve ();
74 if (DEBUG_IO) cout << "Ispell] Received " << message << "\n";
75 #ifdef OS_WIN32
76 if (search_forwards (message, 0, "@(#)")) return "ok";
77 #else
78 if (starts (message, "@(#)")) return "ok";
79 #endif
80 if (ln->alive) ln->stop ();
81 return "Error: no dictionary for#" * lan;
84 string
85 ispeller_rep::retrieve () {
86 string ret;
87 while ((ret != "\n") && (!ends (ret, "\n\n")) &&
88 ((!ends (ret, "\n")) || (!starts (ret, "@(#)"))))
90 ln->listen (10000);
91 string mess = ln->read (LINK_ERR);
92 string extra= ln->read (LINK_OUT);
93 if (mess != "") cerr << "TeXmacs] ispell error: " << mess << "\n";
94 if (extra == "") {
95 ln->stop ();
96 return "Error: ispell does not respond";
98 ret << extra;
100 return ispell_decode (lan, ret);
103 void
104 ispeller_rep::send (string cmd) {
105 ln->write (ispell_encode (lan, cmd) * "\n", LINK_IN);
108 /******************************************************************************
109 * Ispell dictionaries
110 ******************************************************************************/
112 static hashmap<string,string> the_dict ("");
114 static void
115 init_dictionary (string lang, string dict) {
116 if (the_dict->contains (lang)) return;
117 if (exists ("/usr/lib/ispell/" * dict * ".hash") ||
118 exists ("/usr/lib/aspell/" * dict) ||
119 exists ("/usr/lib/aspell/" * dict * ".multi"))
120 the_dict (lang)= dict;
123 string
124 ispell_dictionary (string lang) {
125 if (N(the_dict) == 0) {
126 init_dictionary ("english", "english");
127 init_dictionary ("english", "american");
128 init_dictionary ("danish", "danish");
129 init_dictionary ("danish", "dansk");
130 init_dictionary ("dutch", "dutch");
131 init_dictionary ("dutch", "nederlands");
132 init_dictionary ("french", "french");
133 init_dictionary ("french", "francais");
134 init_dictionary ("german", "german");
135 init_dictionary ("german", "deutsch");
136 init_dictionary ("german", "ngerman");
137 init_dictionary ("german", "ndeutsch");
138 init_dictionary ("german", "ogerman");
139 init_dictionary ("german", "odeutsch");
140 init_dictionary ("german", "swiss");
141 init_dictionary ("portuguese", "portuguese");
142 init_dictionary ("portuguese", "portugues");
143 init_dictionary ("portuguese", "brazilian");
144 init_dictionary ("portuguese", "brasileiro");
145 init_dictionary ("spanish", "spanish");
146 init_dictionary ("spanish", "espaƱol");
147 init_dictionary ("spanish", "espa~nol");
148 init_dictionary ("spanish", "espanol");
149 init_dictionary ("spanish", "castellano");
150 init_dictionary ("swedish", "swedish");
151 init_dictionary ("swedish", "svenska");
153 if (the_dict->contains (lang)) return the_dict [lang];
154 return lang;
157 /******************************************************************************
158 * Language dependent arguments to ispell
159 ******************************************************************************/
161 string
162 ispell_extra_args (string lan) {
163 if (lan == "german")
164 return " -T latin1";
165 else
166 return "";
169 /******************************************************************************
170 * Internationalization
171 ******************************************************************************/
173 string
174 ispell_encode (string lan, string s) {
175 if ((lan == "czech") || (lan == "hungarian") ||
176 (lan == "polish") || (lan == "slovene"))
177 return cork_to_il2 (s);
178 else if ((lan == "bulgarian") || (lan == "russian"))
179 return koi8_to_iso (s);
180 else if (lan == "ukrainian")
181 return koi8uk_to_iso (s);
182 else if (lan == "spanish")
183 return spanish_to_ispanish (s);
184 else if (lan == "german")
185 return german_to_igerman (s);
186 else return s;
189 string
190 ispell_decode (string lan, string s) {
191 if ((lan == "czech") || (lan == "hungarian") ||
192 (lan == "polish") || (lan == "slovene"))
193 return il2_to_cork (s);
194 else if ((lan == "bulgarian") || (lan == "russian"))
195 return iso_to_koi8 (s);
196 else if (lan == "ukrainian")
197 return iso_to_koi8uk (s);
198 else if (lan == "spanish")
199 return ispanish_to_spanish (s);
200 else if (lan == "german")
201 return igerman_to_german (s);
202 else return s;
205 /******************************************************************************
206 * Subroutines
207 ******************************************************************************/
209 static tree
210 parse_ispell (string s) {
211 #if defined (__MINGW__) || defined (__MINGW32__)
212 while (ends (s, "\r\n")) s= s (0, N(s)-2);
213 #else
214 while (ends (s, "\n")) s= s (0, N(s)-1);
215 #endif
216 bool flag= true;
217 int i, j;
218 tree t (TUPLE);
219 for (i=0, j=0; j<N(s); j++)
220 if (s[j]==':') flag= false;
221 else if (((s[j]==' ') && (flag || (j==i) || (s[j-1]==':'))) || (s[j]==','))
223 if (j>i) t << s (i, j);
224 i= j+1;
226 t << s (i, j);
228 if (N(t) == 0) return tree (TUPLE, "0");
229 if ((t[0] == "+") || (t[0] == "*") || (t[0] == "-")) return "ok";
230 if ((N(t)>=4) && ((t[0] == "&") || (t[0]=="?"))) {
231 tree u (TUPLE, t[2]);
232 u << A (t (4, N (t)));
233 return u;
235 return tree (TUPLE, "0");
238 static void
239 ispell_send (string lan, string s) {
240 ispeller sc= ispeller (lan);
241 if ((!is_nil (sc)) && sc->ln->alive) sc->send (s);
244 static string
245 ispell_eval (string lan, string s) {
246 ispeller sc= ispeller (lan);
247 if ((!is_nil (sc)) && sc->ln->alive) {
248 sc->send (s);
249 return sc->retrieve ();
251 return "";
254 /******************************************************************************
255 * Spell checking interface
256 ******************************************************************************/
258 string
259 ispell_start (string lan) {
260 if (DEBUG_IO) cout << "Ispell] Start " << lan << "\n";
261 ispeller sc= ispeller (lan);
262 if (is_nil (sc)) sc= tm_new<ispeller_rep> (lan);
263 return sc->start ();
266 tree
267 ispell_check (string lan, string s) {
268 if (DEBUG_IO) cout << "Ispell] Check " << s << "\n";
269 ispeller sc= ispeller (lan);
270 if (is_nil (sc) || (!sc->ln->alive)) {
271 string message= ispell_start (lan);
272 if (starts (message, "Error: ")) return message;
274 string ret_s= ispell_eval (lan, "^" * s);
275 if (starts (ret_s, "Error: ")) return ret_s;
276 return parse_ispell (ret_s);
279 void
280 ispell_accept (string lan, string s) {
281 if (DEBUG_IO) cout << "Ispell] Accept " << s << "\n";
282 ispell_send (lan, "@" * s);
285 void
286 ispell_insert (string lan, string s) {
287 if (DEBUG_IO) cout << "Ispell] Insert " << s << "\n";
288 ispell_send (lan, "*" * s);
291 void
292 ispell_done (string lan) {
293 if (DEBUG_IO) cout << "Ispell] End " << lan << "\n";
294 ispell_send (lan, "#");