Back to index

texmacs  1.0.7.15
ispell.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : ispell.cpp
00004 * DESCRIPTION: interface with the ispell spell checker
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "Ispell/ispell.hpp"
00013 #include "file.hpp"
00014 #include "resource.hpp"
00015 #include "tm_link.hpp"
00016 #include "convert.hpp"
00017 
00018 string ispell_dictionary (string lang);
00019 string ispell_extra_args (string lang);
00020 string ispell_encode (string lan, string s);
00021 string ispell_decode (string lan, string s);
00022 
00023 /******************************************************************************
00024 * The connection resource
00025 ******************************************************************************/
00026 
00027 RESOURCE(ispeller);
00028 struct ispeller_rep: rep<ispeller> {
00029   string  lan; // name of the session
00030   tm_link ln;  // the pipe
00031 
00032 public:
00033   ispeller_rep (string lan);
00034   string start ();
00035   string retrieve ();
00036   void   send (string cmd);
00037 };
00038 RESOURCE_CODE(ispeller);
00039 
00040 /******************************************************************************
00041 * Routines for ispellers
00042 ******************************************************************************/
00043 
00044 ispeller_rep::ispeller_rep (string lan2): rep<ispeller> (lan2), lan (lan2) {}
00045 
00046 string
00047 ispeller_rep::start () {
00048   if (is_nil (ln)) {
00049     string cmd;
00050 #ifdef OS_WIN32
00051     string prg= "\"$TEXMACS_PATH/bin/aspell/aspell.exe\"";
00052     cmd= prg * " --data-dir=.%//data --dict-dir=.%//dict -a";
00053 #else
00054     if (exists_in_path ("aspell")) cmd= "aspell";
00055     else
00056 #if defined (__MINGW__) || defined (__MINGW32__)
00057       if (exists (url_system ("C:\\Program Files\\Aspell\\bin\\aspell.exe")))
00058         cmd= "\"C:\\Program Files\\Aspell\\bin\\aspell.exe\"";
00059       else
00060 #endif
00061         cmd= "ispell";
00062     cmd << " -a -d " * ispell_dictionary (lan) * ispell_extra_args (lan);
00063 #endif
00064     ln= make_pipe_link (cmd);
00065   }
00066   if (ln->alive) return "ok";
00067   string message= ln->start ();
00068   if (DEBUG_IO) cout << "Ispell] Received " << message << "\n";
00069   if (starts (message, "Error: ")) {
00070     if (ln->alive) ln->stop ();
00071     return message;
00072   }
00073   message= retrieve ();
00074   if (DEBUG_IO) cout << "Ispell] Received " << message << "\n";
00075 #ifdef OS_WIN32
00076   if (search_forwards (message, 0, "@(#)")) return "ok";
00077 #else
00078   if (starts (message, "@(#)")) return "ok";
00079 #endif
00080   if (ln->alive) ln->stop ();
00081   return "Error: no dictionary for#" * lan;
00082 }
00083 
00084 string
00085 ispeller_rep::retrieve () {
00086   string ret;
00087 #if defined (__MINGW__) || defined (__MINGW32__)
00088   while ((ret != "\r\n") && (!ends (ret, "\r\n\r\n")) &&
00089         ((!ends (ret, "\r\n")) || (!starts (ret, "@(#)"))))
00090 #else
00091   while ((ret != "\n") && (!ends (ret, "\n\n")) &&
00092         ((!ends (ret, "\n")) || (!starts (ret, "@(#)"))))
00093 #endif
00094     {
00095       ln->listen (10000);
00096       string mess = ln->read (LINK_ERR);
00097       string extra= ln->read (LINK_OUT);
00098       if (mess  != "") cerr << "TeXmacs] ispell error: " << mess << "\n";
00099       if (extra == "") {
00100        ln->stop ();
00101        return "Error: ispell does not respond";
00102       }
00103       ret << extra;
00104     }
00105   return ispell_decode (lan, ret);
00106 }
00107 
00108 void
00109 ispeller_rep::send (string cmd) {
00110   ln->write (ispell_encode (lan, cmd) * "\n", LINK_IN);
00111 }
00112 
00113 /******************************************************************************
00114 * Ispell dictionaries
00115 ******************************************************************************/
00116 
00117 static hashmap<string,string> the_dict ("");
00118 
00119 static void
00120 init_dictionary (string lang, string dict) {
00121   if (the_dict->contains (lang)) return;
00122   if (exists ("/usr/lib/ispell/" * dict * ".hash") ||
00123       exists ("/usr/lib/aspell/" * dict) ||
00124       exists ("/usr/lib/aspell/" * dict * ".multi"))
00125     the_dict (lang)= dict;
00126 }
00127 
00128 string
00129 ispell_dictionary (string lang) {
00130   if (N(the_dict) == 0) {
00131     init_dictionary ("english", "english");
00132     init_dictionary ("english", "american");
00133     init_dictionary ("danish", "danish");
00134     init_dictionary ("danish", "dansk");
00135     init_dictionary ("dutch", "dutch");
00136     init_dictionary ("dutch", "nederlands");
00137     init_dictionary ("french", "french");
00138     init_dictionary ("french", "francais");
00139     init_dictionary ("german", "german");
00140     init_dictionary ("german", "deutsch");
00141     init_dictionary ("german", "ngerman");
00142     init_dictionary ("german", "ndeutsch");
00143     init_dictionary ("german", "ogerman");
00144     init_dictionary ("german", "odeutsch");
00145     init_dictionary ("german", "swiss");
00146     init_dictionary ("portuguese", "portuguese");
00147     init_dictionary ("portuguese", "portugues");
00148     init_dictionary ("portuguese", "brazilian");
00149     init_dictionary ("portuguese", "brasileiro");
00150     init_dictionary ("spanish", "spanish");
00151     init_dictionary ("spanish", "espaƱol");
00152     init_dictionary ("spanish", "espa~nol");
00153     init_dictionary ("spanish", "espanol");
00154     init_dictionary ("spanish", "castellano");
00155     init_dictionary ("swedish", "swedish");
00156     init_dictionary ("swedish", "svenska");
00157   }
00158   if (the_dict->contains (lang)) return the_dict [lang];
00159   return lang;
00160 }
00161 
00162 /******************************************************************************
00163 * Language dependent arguments to ispell
00164 ******************************************************************************/
00165 
00166 string
00167 ispell_extra_args (string lan) {
00168   if (lan == "german")
00169     return " -T latin1";
00170   else
00171     return "";
00172 }
00173 
00174 /******************************************************************************
00175 * Internationalization
00176 ******************************************************************************/
00177 
00178 string
00179 ispell_encode (string lan, string s) {
00180   if ((lan == "czech") || (lan == "hungarian") ||
00181       (lan == "polish") || (lan == "slovene"))
00182     return cork_to_il2 (s);
00183   else if ((lan == "bulgarian") || (lan == "russian"))
00184     return koi8_to_iso (s);
00185   else if (lan == "ukrainian")
00186     return koi8uk_to_iso (s);
00187   else if (lan == "spanish")
00188     return spanish_to_ispanish (s);
00189   else if (lan == "german")
00190     return german_to_igerman (s);
00191   else return s;
00192 }
00193 
00194 string
00195 ispell_decode (string lan, string s) {
00196   if ((lan == "czech") || (lan == "hungarian") ||
00197       (lan == "polish") || (lan == "slovene"))
00198     return il2_to_cork (s);
00199   else if ((lan == "bulgarian") || (lan == "russian"))
00200     return iso_to_koi8 (s);
00201   else if (lan == "ukrainian")
00202     return iso_to_koi8uk (s);
00203   else if (lan == "spanish")
00204     return ispanish_to_spanish (s);
00205   else if (lan == "german")
00206     return igerman_to_german (s);
00207   else return s;
00208 }
00209 
00210 /******************************************************************************
00211 * Subroutines
00212 ******************************************************************************/
00213 
00214 static tree
00215 parse_ispell (string s) {
00216 #if defined (__MINGW__) || defined (__MINGW32__)
00217   while (ends (s, "\r\n")) s= s (0, N(s)-2);
00218 #else
00219   while (ends (s, "\n")) s= s (0, N(s)-1);
00220 #endif
00221   bool flag= true;
00222   int i, j;
00223   tree t (TUPLE);
00224   for (i=0, j=0; j<N(s); j++)
00225     if (s[j]==':') flag= false;
00226     else if (((s[j]==' ') && (flag || (j==i) || (s[j-1]==':'))) || (s[j]==','))
00227       {
00228        if (j>i) t << s (i, j);
00229        i= j+1;
00230       }
00231   t << s (i, j);
00232 
00233   if (N(t) == 0) return tree (TUPLE, "0");
00234   if ((t[0] == "+") || (t[0] == "*") || (t[0] == "-")) return "ok";
00235   if ((N(t)>=4) && ((t[0] == "&") || (t[0]=="?"))) {
00236     tree u (TUPLE, t[2]);
00237     u << A (t (4, N (t)));
00238     return u;
00239   }
00240   return tree (TUPLE, "0");
00241 }
00242 
00243 static void
00244 ispell_send (string lan, string s) {
00245   ispeller sc= ispeller (lan);
00246   if ((!is_nil (sc)) && sc->ln->alive) sc->send (s);
00247 }
00248 
00249 static string
00250 ispell_eval (string lan, string s) {
00251   ispeller sc= ispeller (lan);
00252   if ((!is_nil (sc)) && sc->ln->alive) {
00253     sc->send (s);
00254     return sc->retrieve ();
00255   }
00256   return "";
00257 }
00258 
00259 /******************************************************************************
00260 * Spell checking interface
00261 ******************************************************************************/
00262 
00263 string
00264 ispell_start (string lan) {
00265   if (DEBUG_IO) cout << "Ispell] Start " << lan << "\n";
00266   ispeller sc= ispeller (lan);
00267   if (is_nil (sc)) sc= tm_new<ispeller_rep> (lan);
00268   return sc->start ();
00269 }
00270 
00271 tree
00272 ispell_check (string lan, string s) {
00273   if (DEBUG_IO) cout << "Ispell] Check " << s << "\n";
00274   ispeller sc= ispeller (lan);
00275   if (is_nil (sc) || (!sc->ln->alive)) {
00276     string message= ispell_start (lan);
00277     if (starts (message, "Error: ")) return message;
00278   }
00279   string ret_s= ispell_eval (lan, "^" * s);
00280   if (starts (ret_s, "Error: ")) return ret_s;
00281   return parse_ispell (ret_s);
00282 }
00283 
00284 void
00285 ispell_accept (string lan, string s) {
00286   if (DEBUG_IO) cout << "Ispell] Accept " << s << "\n";
00287   ispell_send (lan, "@" * s);
00288 }
00289 
00290 void
00291 ispell_insert (string lan, string s) {
00292   if (DEBUG_IO) cout << "Ispell] Insert " << s << "\n";
00293   ispell_send (lan, "*" * s);
00294 }
00295 
00296 void
00297 ispell_done (string lan) {
00298   if (DEBUG_IO) cout << "Ispell] End " << lan << "\n";
00299   ispell_send (lan, "#");
00300 }