]> git.lyx.org Git - lyx.git/blobdiff - src/ispell.C
reverse last change
[lyx.git] / src / ispell.C
index 95dfcf2eb37169a092bfa1fc832b5a19247b5f95..9ac2625b503967d702dbc6c2c73f9a1018ee8cbc 100644 (file)
@@ -19,7 +19,7 @@
 #include <fcntl.h>
 #include <cstdio>
 
-// FIXME: do we need any of this horrible gook ? 
+// FIXME: do we need any of this horrible gook ?
 #if TIME_WITH_SYS_TIME
 # include <sys/time.h>
 # include <ctime>
 #endif
 
 #include "LString.h"
-#include "support/lstrings.h"
 #include "lyxrc.h"
 #include "language.h"
 #include "debug.h"
 #include "encoding.h"
 #include "ispell.h"
+#include "WordLangTuple.h"
+
+#include "support/forkedcall.h"
+#include "support/lstrings.h"
 
 #ifndef CXX_GLOBAL_CSTD
 using std::strcpy;
@@ -60,190 +63,246 @@ using std::strstr;
 using std::endl;
 
 namespace {
-       /// pid for the `ispell' process.
-       pid_t isp_pid = -1;
+
+/// pid for the `ispell' process.
+pid_t isp_pid = -1;
+
+class LaunchIspell : public ForkedProcess {
+public:
+       ///
+       LaunchIspell(BufferParams const & p, string const & l,
+                    int * in, int * out)
+               : params(p), lang(l), pipein(in), pipeout(out) {}
+       ///
+       virtual ForkedProcess * clone() const {
+               return new LaunchIspell(*this);
+       }
+       ///
+       int start();
+private:
+       ///
+       virtual int generateChild();
+
+       ///
+       BufferParams const & params;
+       string const & lang;
+       int * const pipein;
+       int * const pipeout;
+};
+
+
+int LaunchIspell::start()
+{
+       command_ = "ispell";
+       return runNonBlocking();
+}
+
+
+int LaunchIspell::generateChild()
+{
+       isp_pid = fork();
+
+       if (isp_pid != 0) {
+               // failed (-1) or parent process (>0)
+               return isp_pid;
+       }
+
+       // child process
+       dup2(pipein[0], STDIN_FILENO);
+       dup2(pipeout[1], STDOUT_FILENO);
+       ::close(pipein[0]);
+       ::close(pipein[1]);
+       ::close(pipeout[0]);
+       ::close(pipeout[1]);
+
+       char * argv[14];
+       int argc = 0;
+
+       char * tmp = new char[lyxrc.isp_command.length() + 1];
+       lyxrc.isp_command.copy(tmp, lyxrc.isp_command.length());
+       tmp[lyxrc.isp_command.length()] = '\0';
+       argv[argc++] = tmp;
+       tmp = new char[3];
+       string("-a").copy(tmp, 2); tmp[2] = '\0'; // pipe mode
+       argv[argc++] = tmp;
+
+       if (lang != "default") {
+               tmp = new char[3];
+               string("-d").copy(tmp, 2); tmp[2] = '\0'; // Dictionary file
+               argv[argc++] = tmp;
+               tmp = new char[lang.length() + 1];
+               lang.copy(tmp, lang.length()); tmp[lang.length()] = '\0';
+               argv[argc++] = tmp;
+       }
+
+       if (lyxrc.isp_accept_compound) {
+               // Consider run-together words as legal compounds
+               tmp = new char[3];
+               string("-C").copy(tmp, 2); tmp[2] = '\0';
+               argv[argc++] = tmp;
+       } else {
+               // Report run-together words with
+               // missing blanks as errors
+               tmp = new char[3];
+               string("-B").copy(tmp, 2); tmp[2] = '\0';
+               argv[argc++] = tmp;
+       }
+       if (lyxrc.isp_use_esc_chars) {
+               // Specify additional characters that
+               // can be part of a word
+               tmp = new char[3];
+               string("-w").copy(tmp, 2); tmp[2] = '\0';
+               argv[argc++] = tmp;
+               // Put the escape chars in ""s
+               string tms = '"' + lyxrc.isp_esc_chars + '"';
+               tmp = new char[tms.length() + 1];
+               tms.copy(tmp, tms.length()); tmp[tms.length()] = '\0';
+               argv[argc++] = tmp;
+       }
+       if (lyxrc.isp_use_pers_dict) {
+               // Specify an alternate personal dictionary
+               tmp = new char[3];
+               string("-p").copy(tmp, 2);
+               tmp[2]= '\0';
+               argv[argc++] = tmp;
+               tmp = new char[lyxrc.isp_pers_dict.length() + 1];
+               lyxrc.isp_pers_dict.copy(tmp, lyxrc.isp_pers_dict.length());
+               tmp[lyxrc.isp_pers_dict.length()] = '\0';
+               argv[argc++] = tmp;
+       }
+       if (lyxrc.isp_use_input_encoding &&
+           params.inputenc != "default") {
+               string enc = (params.inputenc == "auto")
+                       ? params.language->encoding()->LatexName()
+                       : params.inputenc;
+               string::size_type n = enc.length();
+               tmp = new char[3];
+               string("-T").copy(tmp, 2);
+               tmp[2] = '\0';
+               argv[argc++] = tmp; // Input encoding
+               tmp = new char[n + 1];
+               enc.copy(tmp, n);
+               tmp[n] = '\0';
+               argv[argc++] = tmp;
+       }
+
+       argv[argc++] = 0;
+
+       execvp(argv[0], const_cast<char * const *>(argv));
+
+       // free the memory used by string::copy in the
+       // setup of argv
+       for (int i = 0; i < argc - 1; ++i)
+               delete[] argv[i];
+
+       lyxerr << "LyX: Failed to start ispell!" << endl;
+       _exit(0);
 }
 
 
+} // namespace anon
+
+
 ISpell::ISpell(BufferParams const & params, string const & lang)
        : str(0)
 {
        static char o_buf[BUFSIZ];  // jc: it could be smaller
        int pipein[2];
        int pipeout[2];
-       char * argv[14];
-       int argc;
 
        isp_pid = -1;
 
        if (pipe(pipein) == -1 || pipe(pipeout) == -1) {
                lyxerr << "LyX: Can't create pipe for spellchecker!" << endl;
-               goto END;
+               setError();
+               return;
        }
 
        if ((out = fdopen(pipein[1], "w")) == 0) {
                lyxerr << "LyX: Can't create stream for pipe for spellchecker!"
                       << endl;
-               goto END;
+               setError();
+               return;
        }
 
        if ((in = fdopen(pipeout[0], "r")) == 0) {
                lyxerr <<"LyX: Can't create stream for pipe for spellchecker!"
                       << endl;
-               goto END;
+               setError();
+               return;
        }
 
        setvbuf(out, o_buf, _IOLBF, BUFSIZ);
 
        isp_fd = pipeout[0];
 
-       isp_pid = fork();
-
+       LaunchIspell childprocess(params, lang, pipein, pipeout);
+       isp_pid = childprocess.start();
        if (isp_pid == -1) {
                lyxerr << "LyX: Can't create child process for spellchecker!"
                       << endl;
-               goto END;
+               setError();
+               return;
        }
 
-       if (isp_pid == 0) {
-               /* child process */
-               dup2(pipein[0], STDIN_FILENO);
-               dup2(pipeout[1], STDOUT_FILENO);
-               ::close(pipein[0]);
-               ::close(pipein[1]);
+       setError();
+       /* Parent process: Read ispells identification message */
+       // Hmm...what are we using this id msg for? Nothing? (Lgb)
+       // Actually I used it to tell if it's truly Ispell or if it's
+       // aspell -- (kevinatk@home.com)
+       // But no code actually used the results for anything useful
+       // so I removed it again. Perhaps we can remove this code too.
+       // - jbl
+       char buf[2048];
+       fd_set infds;
+       struct timeval tv;
+       int retval = 0;
+       FD_ZERO(&infds);
+       FD_SET(pipeout[0], &infds);
+       tv.tv_sec = 15; // fifteen second timeout. Probably too much,
+       // but it can't really hurt.
+       tv.tv_usec = 0;
+
+       // Configure provides us with macros which are supposed to do
+       // the right typecast.
+       retval = select(SELECT_TYPE_ARG1 (pipeout[0]+1),
+                       SELECT_TYPE_ARG234 (&infds),
+                       0,
+                       0,
+                       SELECT_TYPE_ARG5 (&tv));
+
+       if (retval > 0) {
+               // Ok, do the reading. We don't have to FD_ISSET since
+               // there is only one fd in infds.
+               fgets(buf, 2048, in);
+
+               fputs("!\n", out); // Set terse mode (silently accept correct words)
+
+       } else if (retval == 0) {
+               // timeout. Give nice message to user.
+               lyxerr << "Ispell read timed out, what now?" << endl;
+               // This probably works but could need some thought
+               isp_pid = -1;
                ::close(pipeout[0]);
                ::close(pipeout[1]);
+               ::close(pipein[0]);
+               ::close(pipein[1]);
+               isp_fd = -1;
+       } else {
+               // Select returned error
+               lyxerr << "Select on ispell returned error, what now?" << endl;
+       }
+}
 
-               argc = 0;
-               char * tmp = new char[lyxrc.isp_command.length() + 1];
-               lyxrc.isp_command.copy(tmp, lyxrc.isp_command.length());
-               tmp[lyxrc.isp_command.length()] = '\0';
-               argv[argc++] = tmp;
-               tmp = new char[3];
-               string("-a").copy(tmp, 2); tmp[2] = '\0'; // pipe mode
-               argv[argc++] = tmp;
 
-               if (lang != "default") {
-                       tmp = new char[3];
-                       string("-d").copy(tmp, 2); tmp[2] = '\0'; // Dictionary file
-                       argv[argc++] = tmp;
-                       tmp = new char[lang.length() + 1];
-                       lang.copy(tmp, lang.length()); tmp[lang.length()] = '\0';
-                       argv[argc++] = tmp;
-               }
-
-               if (lyxrc.isp_accept_compound) {
-                       // Consider run-together words as legal compounds
-                       tmp = new char[3];
-                       string("-C").copy(tmp, 2); tmp[2] = '\0';
-                       argv[argc++] = tmp;
-               } else {
-                       // Report run-together words with
-                       // missing blanks as errors
-                       tmp = new char[3];
-                       string("-B").copy(tmp, 2); tmp[2] = '\0';
-                       argv[argc++] = tmp;
-               }
-               if (lyxrc.isp_use_esc_chars) {
-                       // Specify additional characters that
-                       // can be part of a word
-                       tmp = new char[3];
-                       string("-w").copy(tmp, 2); tmp[2] = '\0';
-                       argv[argc++] = tmp;
-                       // Put the escape chars in ""s
-                       string tms = "\"" + lyxrc.isp_esc_chars + "\"";
-                       tmp = new char[tms.length() + 1];
-                       tms.copy(tmp, tms.length()); tmp[tms.length()] = '\0';
-                       argv[argc++] = tmp;
-               }
-               if (lyxrc.isp_use_pers_dict) {
-                       // Specify an alternate personal dictionary
-                       tmp = new char[3];
-                       string("-p").copy(tmp, 2);
-                       tmp[2]= '\0';
-                       argv[argc++] = tmp;
-                       tmp = new char[lyxrc.isp_pers_dict.length() + 1];
-                       lyxrc.isp_pers_dict.copy(tmp, lyxrc.isp_pers_dict.length());
-                       tmp[lyxrc.isp_pers_dict.length()] = '\0';
-                       argv[argc++] = tmp;
-               }
-               if (lyxrc.isp_use_input_encoding &&
-                   params.inputenc != "default") {
-                       string enc = (params.inputenc == "auto")
-                               ? params.language->encoding()->LatexName()
-                               : params.inputenc;
-                       string::size_type n = enc.length();
-                       tmp = new char[3];
-                       string("-T").copy(tmp, 2);
-                       tmp[2] = '\0';
-                       argv[argc++] = tmp; // Input encoding
-                       tmp = new char[n + 1];
-                       enc.copy(tmp, n);
-                       tmp[n] = '\0';
-                       argv[argc++] = tmp;
-               }
-
-               argv[argc++] = 0;
-
-               execvp(argv[0], const_cast<char * const *>(argv));
-
-               // free the memory used by string::copy in the
-               // setup of argv
-               for (int i = 0; i < argc - 1; ++i)
-                       delete[] argv[i];
-
-               lyxerr << "LyX: Failed to start ispell!" << endl;
-               _exit(0);
-       }
-       {
-               /* Parent process: Read ispells identification message */
-               // Hmm...what are we using this id msg for? Nothing? (Lgb)
-               // Actually I used it to tell if it's truly Ispell or if it's
-               // aspell -- (kevinatk@home.com)
-               // But no code actually used the results for anything useful
-               // so I removed it again. Perhaps we can remove this code too. 
-               // - jbl
-               char buf[2048];
-               fd_set infds;
-               struct timeval tv;
-               int retval = 0;
-               FD_ZERO(&infds);
-               FD_SET(pipeout[0], &infds);
-               tv.tv_sec = 15; // fifteen second timeout. Probably too much,
-               // but it can't really hurt.
-               tv.tv_usec = 0;
-
-               // Configure provides us with macros which are supposed to do
-               // the right typecast.
-               retval = select(SELECT_TYPE_ARG1 (pipeout[0]+1),
-                               SELECT_TYPE_ARG234 (&infds),
-                               0,
-                               0,
-                               SELECT_TYPE_ARG5 (&tv));
-
-               if (retval > 0) {
-                       // Ok, do the reading. We don't have to FD_ISSET since
-                       // there is only one fd in infds.
-                       fgets(buf, 2048, in);
-
-                       fputs("!\n", out); // Set terse mode (silently accept correct words)
-
-               } else if (retval == 0) {
-                       // timeout. Give nice message to user.
-                       lyxerr << "Ispell read timed out, what now?" << endl;
-                       // This probably works but could need some thought
-                       isp_pid = -1;
-                       ::close(pipeout[0]);
-                       ::close(pipeout[1]);
-                       ::close(pipein[0]);
-                       ::close(pipein[1]);
-                       isp_fd = -1;
-               } else {
-                       // Select returned error
-                       lyxerr << "Select on ispell returned error, what now?" << endl;
-               }
-       }
-  END:
+ISpell::~ISpell()
+{
+       delete[] str;
+}
+
+
+void ISpell::setError()
+{
        if (isp_pid == -1) {
                error_ =
                        "\n\n"
@@ -259,25 +318,6 @@ ISpell::ISpell(BufferParams const & params, string const & lang)
 }
 
 
-ISpell::~ISpell()
-{
-       delete[] str;
-}
-
-
-/* FIXME: this is a minimalist solution until the above
- * code is able to work with forkedcall.h. We only need
- * to reap the zombies here.
- */
-void reapSpellchecker(void)
-{
-       if (isp_pid == -1)
-               return;
-
-       waitpid(isp_pid, 0, WNOHANG);
-}
-
-
 string const ISpell::nextMiss()
 {
        if (str == 0 || *(e+1) == '\0')
@@ -303,13 +343,13 @@ void ISpell::cleanUp()
 }
 
 
-enum ISpell::Result ISpell::check(string const & word)
+enum ISpell::Result ISpell::check(WordLangTuple const & word)
 {
        // FIXME Please rewrite to use string.
 
        Result res;
-       ::fputs(word.c_str(), out);
+
+       ::fputs(word.word().c_str(), out);
        ::fputc('\n', out);
 
        char buf[1024];
@@ -374,18 +414,18 @@ void ISpell::close()
 }
 
 
-void ISpell::insert(string const & word)
+void ISpell::insert(WordLangTuple const & word)
 {
        ::fputc('*', out); // Insert word in personal dictionary
-       ::fputs(word.c_str(), out);
+       ::fputs(word.word().c_str(), out);
        ::fputc('\n', out);
 }
 
 
-void ISpell::accept(string const & word)
+void ISpell::accept(WordLangTuple const & word)
 {
        ::fputc('@', out); // Accept in this session
-       ::fputs(word.c_str(), out);
+       ::fputs(word.word().c_str(), out);
        ::fputc('\n', out);
 }