]> git.lyx.org Git - lyx.git/blobdiff - src/ispell.C
* output_plaintext.C: cosmetics in comment: line length cannot be < 0
[lyx.git] / src / ispell.C
index d9fcd9472043dc781c7e5414b8a86fb8d5d4049d..1a798cd29ec3ff32713ef3cd5180c1fffd880ccd 100644 (file)
@@ -1,50 +1,69 @@
 /**
  * \file ispell.C
- * Copyright 2002 the LyX Team
- * Read the file COPYING
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
  *
  * \author unknown
- * \author John Levon <levon@movementarian.org>
+ * \author Angus Leeming
+ * \author John Levon
+ *
+ * Full author contact details are available in file CREDITS.
  */
 
 #include <config.h>
 
-#include "LString.h"
-#include "lyxrc.h"
-#include "language.h"
+#include "ispell.h"
+
+#include "bufferparams.h"
 #include "debug.h"
 #include "encoding.h"
-#include "ispell.h"
-#include "WordLangTuple.h"
 #include "gettext.h"
+#include "language.h"
+#include "lyxrc.h"
+#include "WordLangTuple.h"
 
 #include "support/forkedcall.h"
 #include "support/lstrings.h"
+#include "support/unicode.h"
+
+// HP-UX 11.x doesn't have this header
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
 
-#include <sys/select.h>
-#include <sys/time.h>
+namespace lyx {
+
+using support::bformat;
+
+using boost::shared_ptr;
 
 #ifndef CXX_GLOBAL_CSTD
 using std::strcpy;
 using std::strlen;
 using std::strpbrk;
-using std::strstr;
 #endif
 
 using std::endl;
 using std::max;
+using std::string;
+
 
 namespace {
 
-class LaunchIspell : public ForkedProcess {
+class LaunchIspell : public support::ForkedProcess {
+       typedef support::ForkedProcess ForkedProcess;
 public:
        ///
        LaunchIspell(BufferParams const & p, string const & l,
                     int * in, int * out, int * err)
                : params(p), lang(l), pipein(in), pipeout(out), pipeerr(err) {}
        ///
-       virtual ForkedProcess * clone() const {
-               return new LaunchIspell(*this);
+       virtual shared_ptr<ForkedProcess> clone() const {
+               return shared_ptr<ForkedProcess>(new LaunchIspell(*this));
        }
        ///
        int start();
@@ -63,8 +82,8 @@ private:
 
 int LaunchIspell::start()
 {
-       command_ = "ispell";
-       return runNonBlocking();
+       command_ = lyxrc.isp_command;
+       return run(DontWait);
 }
 
 
@@ -146,9 +165,9 @@ int LaunchIspell::generateChild()
        if (lyxrc.isp_use_input_encoding &&
            params.inputenc != "default") {
                string enc = (params.inputenc == "auto")
-                       ? params.language->encoding()->LatexName()
+                       ? params.language->encoding()->latexName()
                        : params.inputenc;
-               string::size_type n = enc.length();
+               size_t const n = enc.length();
                tmp = new char[3];
                string("-T").copy(tmp, 2);
                tmp[2] = '\0';
@@ -173,6 +192,29 @@ int LaunchIspell::generateChild()
 }
 
 
+string const to_iconv_encoding(docstring const & s, string const & encoding)
+{
+       if (lyxrc.isp_use_input_encoding) {
+               std::vector<char> const encoded =
+                       ucs4_to_eightbit(s.data(), s.length(), encoding);
+               return string(encoded.begin(), encoded.end());
+       }
+       // FIXME UNICODE: we don't need to convert to UTF8, but probably to the locale encoding
+       return to_utf8(s);
+}
+
+
+docstring const from_iconv_encoding(string const & s, string const & encoding)
+{
+       if (lyxrc.isp_use_input_encoding) {
+               std::vector<char_type> const ucs4 =
+                       eightbit_to_ucs4(s.data(), s.length(), encoding);
+               return docstring(ucs4.begin(), ucs4.end());
+       }
+       // FIXME UNICODE: s is not in UTF8, but probably the locale encoding
+       return from_utf8(s);
+}
+
 } // namespace anon
 
 
@@ -181,9 +223,11 @@ ISpell::ISpell(BufferParams const & params, string const & lang)
 {
        lyxerr[Debug::GUI] << "Created ispell" << endl;
 
+       encoding = params.encoding().iconvName();
+
        // static due to the setvbuf. Ugly.
        static char o_buf[BUFSIZ];
-       
+
        // We need to throw an exception not do this
        pipein[0] = pipein[1] = pipeout[0] = pipeout[1]
                = pipeerr[0] = pipeerr[1] = -1;
@@ -232,12 +276,12 @@ ISpell::ISpell(BufferParams const & params, string const & lang)
        child_.reset(li);
        if (li->start() == -1) {
                error_ = _("Could not create an ispell process.\nYou may not have "
-                       " the right languages installed.");     
+                                       "the right languages installed.");
                child_.reset(0);
                return;
        }
 
-       /* Parent process: Read ispells identification message */
+       // Parent process: Read ispells identification message
 
        bool err_read;
        bool error = select(err_read);
@@ -249,12 +293,13 @@ ISpell::ISpell(BufferParams const & params, string const & lang)
                        return;
                }
 
-               /* must have read something from stderr */
-               error_ = buf;
+               // must have read something from stderr
+               // FIXME UNICODE: buf is not in UTF8, but probably the locale encoding
+               error_ = from_utf8(buf);
        } else {
                // select returned error
-               error_ = _("The spell process returned an error.\nPerhaps "
-                               "it has been configured wrongly ?");
+               error_ = _("The ispell process returned an error.\nPerhaps "
+                          "it has been configured wrongly ?");
        }
 
        close(pipein[0]);
@@ -328,18 +373,18 @@ bool ISpell::select(bool & err_read)
 }
 
 
-string const ISpell::nextMiss()
+docstring const ISpell::nextMiss()
 {
        // Well, somebody is a sick fuck.
 
        if (str == 0 || *(e+1) == '\0')
-               return "";
+               return docstring();
        char * b = e + 2;
        e = strpbrk(b, ",\n");
        *e = '\0';
        if (b)
-               return b;
-       return "";
+               return from_iconv_encoding(b, encoding);
+       return docstring();
 }
 
 
@@ -355,26 +400,34 @@ enum ISpell::Result ISpell::check(WordLangTuple const & word)
 
        Result res;
 
-       ::fputs(word.word().c_str(), out);
+       string const encoded = to_iconv_encoding(word.word(), encoding);
+       if (encoded.empty()) {
+               error_ = bformat(
+                       _("Could not check word `%1$s' because it could not be converted to encoding `%2$s'."),
+                       word.word(), from_ascii(encoding));
+               return UNKNOWN_WORD;
+       }
+       ::fputs(encoded.c_str(), out);
        ::fputc('\n', out);
 
        bool err_read;
        bool error = select(err_read);
 
        if (error) {
-               error_ = _("Could not communicate with the spell-checker program");
-               return UNKNOWN;
+               error_ = _("Could not communicate with the ispell spellchecker process.");
+               return UNKNOWN_WORD;
        }
 
        if (err_read) {
-               error_ = buf;
-               return UNKNOWN;
+               // FIXME UNICODE: buf is not in UTF8, but probably the locale encoding
+               error_ = from_utf8(buf);
+               return UNKNOWN_WORD;
        }
 
        // I think we have to check if ispell is still alive here because
        // the signal-handler could have disabled blocking on the fd
        if (!alive())
-               return UNKNOWN;
+               return UNKNOWN_WORD;
 
        switch (*buf) {
        case '*':
@@ -384,18 +437,18 @@ enum ISpell::Result ISpell::check(WordLangTuple const & word)
                res = ROOT;
                break;
        case '-':
-               res = COMPOUNDWORD;
+               res = COMPOUND_WORD;
                break;
        case '\n':
-               res = IGNORE;
+               res = IGNORED_WORD;
                break;
        case '#': // Not found, no near misses and guesses
-               res = UNKNOWN;
+               res = UNKNOWN_WORD;
                break;
        case '?': // Not found, and no near misses, but guesses (guesses are ignored)
        case '&': // Not found, but we have near misses
        {
-               res = MISSED;
+               res = SUGGESTED_WORDS;
                char * p = strpbrk(buf, ":");
                str = new char[strlen(p) + 1];
                e   = str;
@@ -403,11 +456,11 @@ enum ISpell::Result ISpell::check(WordLangTuple const & word)
                break;
        }
        default: // This shouldn't happen, but you know Murphy
-               res = UNKNOWN;
+               res = UNKNOWN_WORD;
        }
 
        *buf = 0;
-       if (res != IGNORE) {
+       if (res != IGNORED_WORD) {
                /* wait for ispell to finish */
                while (*buf!= '\n')
                        fgets(buf, 255, in);
@@ -418,21 +471,38 @@ enum ISpell::Result ISpell::check(WordLangTuple const & word)
 
 void ISpell::insert(WordLangTuple const & word)
 {
+       string const encoded = to_iconv_encoding(word.word(), encoding);
+       if (encoded.empty()) {
+               error_ = bformat(
+                       _("Could not insert word `%1$s' because it could not be converted to encoding `%2$s'."),
+                       word.word(), from_ascii(encoding));
+               return;
+       }
        ::fputc('*', out); // Insert word in personal dictionary
-       ::fputs(word.word().c_str(), out);
+       ::fputs(encoded.c_str(), out);
        ::fputc('\n', out);
 }
 
 
 void ISpell::accept(WordLangTuple const & word)
 {
+       string const encoded = to_iconv_encoding(word.word(), encoding);
+       if (encoded.empty()) {
+               error_ = bformat(
+                       _("Could not accept word `%1$s' because it could not be converted to encoding `%2$s'."),
+                       word.word(), from_ascii(encoding));
+               return;
+       }
        ::fputc('@', out); // Accept in this session
-       ::fputs(word.word().c_str(), out);
+       ::fputs(encoded.c_str(), out);
        ::fputc('\n', out);
 }
 
 
-string const ISpell::error()
+docstring const ISpell::error()
 {
        return error_;
 }
+
+
+} // namespace lyx