]> git.lyx.org Git - lyx.git/blobdiff - src/spellchecker.C
Indentation change + small #ifndef NEW_INSETS fix.
[lyx.git] / src / spellchecker.C
index e74c163c2270feb5d7d7c04abac931c07eb08290..609aa93502e7406cf83ca63ca8df60e15f60a9ec 100644 (file)
@@ -1,43 +1,55 @@
 /*
  *This file is part of
- * ======================================================
+ * ====================================================== 
  * 
  *           LyX, The Document Processor
  *      
- *         Copyright (C) 1995 Matthias Ettrich
- *          Copyright (C) 1995-1998 The LyX Team
+ *         Copyright 1995 Matthias Ettrich
+ *          Copyright 1995-1998 The LyX Team
  *
- *======================================================
+ * ====================================================== 
  */
 
 #include <config.h>
 
+#ifdef __GNUG__
+#pragma implementation
+#endif
+
 #include <unistd.h>
 #include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
+#include <cstdlib>
+#include <cstring>
+#include <csignal>
 #include <sys/wait.h>
 #include <sys/types.h>
-#include <ctype.h>
+#include <cctype>
 #include FORMS_H_LOCATION
 
 #if TIME_WITH_SYS_TIME
 # include <sys/time.h>
-# include <time.h>
+# include <ctime>
 #else
 # if HAVE_SYS_TIME_H
 #  include <sys/time.h>
 # else
-#  include <time.h>
+#  include <ctime>
 # endif
 #endif
 
 #ifdef HAVE_SYS_SELECT_H
+# ifdef HAVE_STRINGS_H
+   // <strings.h> is needed at least on AIX because FD_ZERO uses bzero().
+   // BUT we cannot include both string.h and strings.h on Irix 6.5 :(
+#  ifdef _AIX
+#   include <strings.h>
+#  endif
+# endif
 #include <sys/select.h>
 #endif
 
+#include <algorithm>
+
 #include "LString.h"
 #include "sp_form.h"
 #include "spellchecker.h"
 #include "BufferView.h"
 #include "gettext.h"
 #include "lyx_gui_misc.h"
+#include "debug.h"
+#include "support/lstrings.h"
+#include "language.h"
+#include "encoding.h"
+#include "support/lstrings.h"
+
+#ifdef USE_PSPELL
+# include <pspell/pspell.h>
+#endif
 
-extern LyXRC *lyxrc;
-extern BufferView *current_view;
-
-//     $Id: spellchecker.C,v 1.1 1999/09/27 18:44:38 larsbj Exp $      
+using std::reverse;
+using std::endl;
 
-#if !defined(lint) && !defined(WITH_WARNINGS)
-static char vcid[] = "$Id: spellchecker.C,v 1.1 1999/09/27 18:44:38 larsbj Exp $";
-#endif /* lint */
+namespace {
 
 // Spellchecker status
 enum {
@@ -67,114 +84,160 @@ enum {
        ISP_IGNORE
 };
 
-static bool RunSpellChecker(LString const &);
+bool RunSpellChecker(BufferView * bv);
+
+#ifndef USE_PSPELL
 
-static FILE *in, *out;  /* streams to communicate with ispell */
+FILE * in;
+FILE * out;  /* streams to communicate with ispell */
 pid_t isp_pid = -1; // pid for the `ispell' process. Also used (RO) in
                     // lyx_cb.C
 
 // the true spell checker program being used
 enum ActualSpellChecker {ASC_ISPELL, ASC_ASPELL};
-static ActualSpellChecker actual_spell_checker;
+ActualSpellChecker actual_spell_checker;
 
-static int isp_fd;
+int isp_fd;
+
+#else
 
-static FD_form_spell_options *fd_form_spell_options = NULL;
-FD_form_spell_check *fd_form_spell_check = NULL;
+PspellManager * sc;
+
+#endif
+
+} // namespace anon
+
+
+// Non-static so that it can be redrawn if the xforms colors are re-mapped
+FD_form_spell_options *fd_form_spell_options = 0;
+FD_form_spell_check *fd_form_spell_check = 0;
 
-//void sigchldhandler(int sig);
 void sigchldhandler(pid_t pid, int *status);
 
-//extern void sigchldchecker(int sig);
 extern void sigchldchecker(pid_t pid, int *status);
 
+#ifndef USE_PSPELL
+
+struct isp_result {
+       int flag;
+       char * str;
+       char * b;
+       char * e;
+       const char * next_miss();
+       isp_result() {
+               flag = ISP_UNKNOWN;
+               str = 0;
+       }
+       ~isp_result() {
+               delete[] str;
+       }
+};
+
+const char * isp_result::next_miss() {
+       if (str == 0 || *(e+1) == '\0') return 0;
+       b = e + 2;
+       e = strpbrk(b, ",\n");
+       *e = '\0';
+       return b;
+}
+
+#else
+
 struct isp_result {
        int flag;
-       int count;
-       LString string;
-       char **misses;
+       PspellStringEmulation * els;
+       
+       const char * next_miss();
        isp_result() {
                flag = ISP_UNKNOWN;
-               count = 0;
-               misses = (char**)NULL;
+               els = 0;
        }
        ~isp_result() {
-               if (misses) delete[] misses;
+               delete_pspell_string_emulation(els);
        }
 };
 
+const char * isp_result::next_miss() 
+{
+       return pspell_string_emulation_next(els);
+}
+
+#endif
+
+const char * spell_error;
+
 
 /***** Spellchecker options *****/
 
 // Rewritten to use ordinary LyX xforms loop and OK, Apply and Cancel set,
-// now also LString. Amazing, eh? (Asger)
+// now also string. Amazing, eh? (Asger)
 
 // Set (sane) values in form to current spellchecker options
 void SpellOptionsUpdate() 
 {
        // Alternate language
-       if (lyxrc->isp_alt_lang.empty()) {
-               lyxrc->isp_use_alt_lang = false;
+       if (lyxrc.isp_alt_lang.empty()) {
+               lyxrc.isp_use_alt_lang = false;
        } else {
                fl_set_input(fd_form_spell_options->altlang_input,
-                            lyxrc->isp_alt_lang.c_str());
+                            lyxrc.isp_alt_lang.c_str());
        }
-       if (lyxrc->isp_use_alt_lang) {
-               fl_set_button(fd_form_spell_options->buflang,0);
-               fl_set_button(fd_form_spell_options->altlang,1);
+       if (lyxrc.isp_use_alt_lang) {
+               fl_set_button(fd_form_spell_options->buflang, 0);
+               fl_set_button(fd_form_spell_options->altlang, 1);
        } else {
-               fl_set_button(fd_form_spell_options->buflang,1);
-               fl_set_button(fd_form_spell_options->altlang,0);
+               fl_set_button(fd_form_spell_options->buflang, 1);
+               fl_set_button(fd_form_spell_options->altlang, 0);
        }  
 
        // Personal dictionary
-       if (lyxrc->isp_pers_dict.empty()) {
-               lyxrc->isp_use_pers_dict = false;
+       if (lyxrc.isp_pers_dict.empty()) {
+               lyxrc.isp_use_pers_dict = false;
        } else {
                fl_set_input(fd_form_spell_options->perdict_input,
-                            lyxrc->isp_pers_dict.c_str());
+                            lyxrc.isp_pers_dict.c_str());
        }
        fl_set_button(fd_form_spell_options->perdict,
-                     lyxrc->isp_use_pers_dict ? 1:0);
+                     lyxrc.isp_use_pers_dict ? 1:0);
 
        // Escape chars
-       if (lyxrc->isp_esc_chars.empty()) {
-               lyxrc->isp_use_esc_chars = false;
+       if (lyxrc.isp_esc_chars.empty()) {
+               lyxrc.isp_use_esc_chars = false;
        } else {
                fl_set_input(fd_form_spell_options->esc_chars_input,
-                            lyxrc->isp_esc_chars.c_str());
+                            lyxrc.isp_esc_chars.c_str());
        }
        fl_set_button(fd_form_spell_options->esc_chars,
-                     lyxrc->isp_use_esc_chars ? 1:0);
+                     lyxrc.isp_use_esc_chars ? 1:0);
 
        // Options
        fl_set_button(fd_form_spell_options->compounds,
-                     lyxrc->isp_accept_compound ? 1 : 0);
+                     lyxrc.isp_accept_compound ? 1 : 0);
        fl_set_button(fd_form_spell_options->inpenc,
-                     lyxrc->isp_use_input_encoding ? 1 : 0);
+                     lyxrc.isp_use_input_encoding ? 1 : 0);
 }
 
 // Update spellchecker options
 void SpellOptionsApplyCB(FL_OBJECT *, long)
 {
        // Build new status from form data
-       lyxrc->isp_use_alt_lang =
+       lyxrc.isp_use_alt_lang = 
                fl_get_button(fd_form_spell_options->altlang);
-       lyxrc->isp_use_pers_dict =
+       lyxrc.isp_use_pers_dict = 
                fl_get_button(fd_form_spell_options->perdict);
-       lyxrc->isp_accept_compound =
+       lyxrc.isp_accept_compound = 
                fl_get_button(fd_form_spell_options->compounds);
-       lyxrc->isp_use_esc_chars =
+       lyxrc.isp_use_esc_chars = 
                fl_get_button(fd_form_spell_options->esc_chars);
-       lyxrc->isp_use_input_encoding =
+       lyxrc.isp_use_input_encoding = 
                fl_get_button(fd_form_spell_options->inpenc);
 
        // Update strings with data from input fields
-       lyxrc->isp_alt_lang =
+       lyxrc.isp_alt_lang = 
                fl_get_input(fd_form_spell_options->altlang_input);
-       lyxrc->isp_pers_dict =
+       lyxrc.isp_pers_dict = 
                fl_get_input(fd_form_spell_options->perdict_input);
-       lyxrc->isp_esc_chars =
+       lyxrc.isp_esc_chars = 
                fl_get_input(fd_form_spell_options->esc_chars_input);
 
        // Update form
@@ -199,11 +262,11 @@ void SpellOptionsOKCB(FL_OBJECT * ob, long data)
 void SpellCheckerOptions()
 {
        // Create form if nescessary
-       if (fd_form_spell_options ==  NULL) {
+       if (fd_form_spell_options ==  0) {
                fd_form_spell_options = create_form_form_spell_options();
                // Make sure pressing the close box does not kill LyX. (RvdK)
                fl_set_form_atclose(fd_form_spell_options->form_spell_options, 
-                                   CancelCloseBoxCB, NULL);
+                                   CancelCloseBoxCB, 0);
        }
 
        // Update form to current options
@@ -218,18 +281,20 @@ void SpellCheckerOptions()
                fl_raise_form(fd_form_spell_options->form_spell_options);
        } else {
                fl_show_form(fd_form_spell_options->form_spell_options,
-                            FL_PLACE_MOUSE,FL_FULLBORDER,
+                            FL_PLACE_MOUSE | FL_FREE_SIZE, FL_TRANSIENT,
                             _("Spellchecker Options"));
        }
 }
 
+namespace {
+
+#ifndef USE_PSPELL
 
 /***** Spellchecker *****/
 
 // Could also use a clean up. (Asger Alstrup)
 
-static
-void create_ispell_pipe(LString const & lang)
+void init_spell_checker(BufferParams const & params, string const & lang)
 {
        static char o_buf[BUFSIZ];  // jc: it could be smaller
        int pipein[2], pipeout[2];
@@ -238,19 +303,21 @@ void create_ispell_pipe(LString const & lang)
 
        isp_pid = -1;
 
-       if(pipe(pipein)==-1 || pipe(pipeout)==-1) {
-               fprintf(stderr,"LyX: Can't create pipe for spellchecker!");
-               return;
+       if (pipe(pipein) == -1 || pipe(pipeout) == -1) {
+               lyxerr << "LyX: Can't create pipe for spellchecker!" << endl;
+               goto END;
        }
 
-       if ((out = fdopen(pipein[1], "w"))==NULL) {
-               fprintf(stderr,"LyX: Can't create stream for pipe for spellchecker!");
-               return;
+       if ((out = fdopen(pipein[1], "w")) == 0) {
+               lyxerr << "LyX: Can't create stream for pipe for spellchecker!"
+                      << endl;
+               goto END;
        }
 
-       if ((in = fdopen(pipeout[0], "r"))==NULL) {
-               fprintf(stderr,"LyX: Can't create stream for pipe for spellchecker!");
-               return;
+       if ((in = fdopen(pipeout[0], "r")) == 0) {
+               lyxerr <<"LyX: Can't create stream for pipe for spellchecker!"
+                      << endl;
+               goto END;
        }
 
        setvbuf(out, o_buf, _IOLBF, BUFSIZ);
@@ -259,12 +326,13 @@ void create_ispell_pipe(LString const & lang)
 
        isp_pid = fork();
 
-       if(isp_pid==-1) {
-               fprintf(stderr,"LyX: Can't create child process for spellchecker!");
-               return;
+       if (isp_pid == -1) {
+               lyxerr << "LyX: Can't create child process for spellchecker!"
+                      << endl;
+               goto END;
        }
-
-       if(isp_pid==0) {        
+       
+       if (isp_pid == 0) {        
                /* child process */
                dup2(pipein[0], STDIN_FILENO);
                dup2(pipeout[1], STDOUT_FILENO);
@@ -274,62 +342,91 @@ void create_ispell_pipe(LString const & lang)
                close(pipeout[1]);
 
                argc = 0;
-               argv[argc++] = lyxrc->isp_command.copy();
-               argv[argc++] = LString("-a").copy(); // "Pipe" mode
+               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") {
-                       argv[argc++] = LString("-d").copy(); // Dictionary file
-                       argv[argc++] = lang.copy();
+                       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)
+               if (lyxrc.isp_accept_compound) {
                        // Consider run-together words as legal compounds
-                       argv[argc++] = LString("-C").copy(); 
-               else
+                       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
-                       argv[argc++] = LString("-B").copy(); 
-
-               if (lyxrc->isp_use_esc_chars) {
+                       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
-                       argv[argc++] = LString("-w").copy(); 
+                       tmp = new char[3];
+                       string("-w").copy(tmp, 2); tmp[2] = '\0';
+                       argv[argc++] = tmp; 
                        // Put the escape chars in ""s
-                       argv[argc++] = (LString("\"") + lyxrc->isp_esc_chars +
-                                       LString("\"")).copy();
+                       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) {
+               if (lyxrc.isp_use_pers_dict) {
                        // Specify an alternate personal dictionary
-                       argv[argc++] = LString("-p").copy(); 
-                       argv[argc++] = lyxrc->isp_pers_dict.copy();
+                       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 &&
-                   current_view->currentBuffer()->params.inputenc != "default") {
-                       argv[argc++] = LString("-T").copy(); // Input encoding
-                       argv[argc++] = current_view->currentBuffer()->params.inputenc.copy();
+               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++] = NULL;
+               argv[argc++] = 0;
 
-               execvp("ispell", (char * const *) argv);
+               execvp(argv[0], const_cast<char * const *>(argv));
 
-               // free the memory used by LString::copy in the
+               // free the memory used by string::copy in the
                // setup of argv
-               for (int i=0; i < argc -1; i++)
+               for (int i= 0; i < argc -1; ++i)
                        delete[] argv[i];
                
-               fprintf(stderr, "LyX: Failed to start ispell!\n");
+               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)
        char buf[2048];
-#ifdef WITH_WARNINGS
-#warning verify that this works.
-#endif
        fd_set infds;
        struct timeval tv;
        int retval = 0;
@@ -357,43 +454,65 @@ void create_ispell_pipe(LString const & lang)
                  actual_spell_checker = ASC_ASPELL;
                else
                  actual_spell_checker = ASC_ISPELL;
+
+               fputs("!\n", out); // Set terse mode (silently accept correct words)
+
                
        } else if (retval == 0) {
                // timeout. Give nice message to user.
-               fprintf(stderr, "Ispell read timed out, what now?\n");
-#ifdef WITH_WARNINGS
-#warning Is this the correct thing to do?
-#endif
+               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
-               fprintf(stderr, "Select on ispell returned error, what now?\n");
+               lyxerr << "Select on ispell returned error, what now?" << endl;
+       }
+       }
+ END:
+       if (isp_pid == -1) {
+               spell_error = 
+                       "\n\n"
+                       "The ispell-process has died for some reason. *One* possible reason\n"
+                       "could be that you do not have a dictionary file\n"
+                       "for the language of this document installed.\n"
+                       "Check /usr/lib/ispell or set another\n"
+                       "dictionary in the Spellchecker Options menu.";
+       } else {
+               spell_error = 0;
        }
 }
 
 
+bool sc_still_alive() {
+       return isp_pid != -1;
+}
+
+
+void sc_clean_up_after_error() 
+{
+       ::fclose(out);
+}
+
+
 // Send word to ispell and get reply
-static
-isp_result *ispell_check_word(char *word)
+isp_result * sc_check_word(string const & word)
 {
-       //Please rewrite to use LString.
-       isp_result *result;
-       char buf[1024], *p;
-       int count, i;
+       //Please rewrite to use string.
 
-       fputs(word, out); 
-       fputc('\n', out);
+       ::fputs(word.c_str(), out);
+       ::fputc('\n', out);
   
-       fgets(buf, 1024, in); 
+       char buf[1024];
+       ::fgets(buf, 1024, in); 
   
        /* I think we have to check if ispell is still alive here because
           the signal-handler could have disabled blocking on the fd */
-       if (isp_pid == -1) return (isp_result *) NULL;
+       if (!sc_still_alive()) return 0;
 
-       result = new isp_result;
+       isp_result * result = new isp_result;
   
        switch (*buf) {
        case '*': // Word found
@@ -415,20 +534,10 @@ isp_result *ispell_check_word(char *word)
        case '&': // Not found, but we have near misses
        {
                result->flag = ISP_MISSED;
-               result->string = buf;
-               char * nb = result->string.copy(); // This leaks.
-               p = strpbrk(nb+2, " ");
-               sscanf(p, "%d", &count); // Get near misses count
-               result->count = count;
-               if (count) result->misses = new char*[count];
-               p = strpbrk(nb, ":");
-               p +=2;
-               for (i = 0; i<count; i++) {
-                       result->misses[i] = p;
-                       p = strpbrk(p, ",\n");
-                       *p = 0;
-                       p+=2;
-               }
+               char * p = strpbrk(buf, ":");
+               result->str = new char[strlen(p) + 1];
+               result->e   = result->str;
+               strcpy(result->str, p);
                break;
        }
        default: // This shouldn't happend, but you know Murphy
@@ -436,15 +545,15 @@ isp_result *ispell_check_word(char *word)
        }
 
        *buf = 0;
-       if (result->flag!=ISP_IGNORE) {
-               while (*buf!='\n') fgets(buf, 255, in); /* wait for ispell to finish */
+       if (result->flag!= ISP_IGNORE) {
+               while (*buf!= '\n') fgets(buf, 255, in); /* wait for ispell to finish */
        }
        return result;
 }
 
 
-static
-inline void ispell_terminate()
+inline 
+void close_spell_checker()
 {
         // Note: If you decide to optimize this out when it is not 
         // needed please note that when Aspell is used this command 
@@ -458,55 +567,138 @@ inline void ispell_terminate()
 }
 
 
-static
-inline void ispell_terse_mode()
+inline 
+void sc_insert_word(string const & word)
+{
+       ::fputc('*', out); // Insert word in personal dictionary
+       ::fputs(word.c_str(), out);
+       ::fputc('\n', out);
+}
+
+
+inline 
+void sc_accept_word(string const & word) 
 {
-       fputs("!\n", out); // Set terse mode (silently accept correct words)
+       ::fputc('@', out); // Accept in this session
+       ::fputs(word.c_str(), out);
+       ::fputc('\n', out);
 }
 
 
-static
-inline void ispell_insert_word(char const *word)
+inline
+void sc_store_replacement(string const & mis, string const & cor) {
+        if (actual_spell_checker == ASC_ASPELL) {
+                ::fputs("$$ra ", out);
+                ::fputs(mis.c_str(), out);
+                ::fputc(',', out);
+                ::fputs(cor.c_str(), out);
+                ::fputc('\n', out);
+        }
+}
+
+#else
+
+PspellCanHaveError * spell_error_object;
+
+void init_spell_checker(BufferParams const &, string const & lang)
 {
-       fputc('*', out); // Insert word in personal dictionary
-       fputs(word, out);
-       fputc('\n', out);
+       PspellConfig * config = new_pspell_config();
+       string code;
+       split(lang, code, '_');
+       config->replace("language-tag", code.c_str());
+       spell_error_object = new_pspell_manager(config);
+       if (pspell_error_number(spell_error_object) != 0) {
+               spell_error = pspell_error_message(spell_error_object);
+       } else {
+               spell_error = 0;
+               sc = to_pspell_manager(spell_error_object);
+               spell_error_object = 0;
+       }
+}
+
+
+bool sc_still_alive() {
+       return true;
 }
 
 
-static
-inline void ispell_accept_word(char const *word) 
+void sc_clean_up_after_error() 
 {
-       fputc('@', out); // Accept in this session
-       fputs(word, out);
-       fputc('\n', out);
+       delete_pspell_can_have_error(spell_error_object);
 }
 
-static
-inline void ispell_store_replacement(const char *mis, LString const & cor) {
-        if(actual_spell_checker == ASC_ASPELL) {
-                fputs("$$ra ", out);
-                fputs(mis, out);
-                fputc(',', out);
-                fputs(cor.c_str(), out);
-                fputc('\n', out);
-        }
+
+
+// Send word to pspell and get reply
+isp_result * sc_check_word(string const & word)
+{
+       isp_result * result = new isp_result;
+#warning Why isnt word_ok a bool? (Lgb)
+       int word_ok = pspell_manager_check(sc, word.c_str());
+       Assert(word_ok != -1);
+
+       if (word_ok) {
+               result->flag = ISP_OK;
+       } else {
+               PspellWordList const * sugs =
+                       pspell_manager_suggest(sc, word.c_str());
+               Assert(sugs != 0);
+               result->els = pspell_word_list_elements(sugs);
+               if (pspell_word_list_empty(sugs)) 
+                       result->flag = ISP_UNKNOWN;
+               else 
+                       result->flag = ISP_MISSED;
+       }
+       return result;
+}
+
+
+inline 
+void close_spell_checker()
+{
+       pspell_manager_save_all_word_lists(sc);
+}
+
+
+inline 
+void sc_insert_word(string const & word)
+{
+       pspell_manager_add_to_personal(sc, word.c_str());
+}
+
+
+inline 
+void sc_accept_word(string const & word) 
+{
+       pspell_manager_add_to_session(sc, word.c_str());
 }
 
 
-void ShowSpellChecker()
+inline 
+void sc_store_replacement(string const & mis, string const & cor)
 {
-       FL_OBJECT *obj;
+       pspell_manager_store_replacement(sc, mis.c_str(), cor.c_str());
+}
+
+#endif
+
+} // namespace anon
+
+
+void ShowSpellChecker(BufferView * bv)
+{
+       FL_OBJECT * obj;
        int ret;
 
        // Exit if we don't have a document open
-       if (!current_view->getScreen())
+       if (!bv->available())
                return;
 
-       if (fd_form_spell_check == NULL) {
+       if (fd_form_spell_check == 0) {
                fd_form_spell_check = create_form_form_spell_check();
                // Make sure pressing the close box does not kill LyX. (RvdK)
-               fl_set_form_atclose(fd_form_spell_check->form_spell_check, IgnoreCloseBoxCB, NULL);
+               fl_set_form_atclose(fd_form_spell_check->form_spell_check, 
+                                   CancelCloseBoxCB, 0);
        }
 
        // Clear form
@@ -521,7 +713,7 @@ void ShowSpellChecker()
                fl_raise_form(fd_form_spell_check->form_spell_check);
        } else {
                fl_show_form(fd_form_spell_check->form_spell_check,
-                            FL_PLACE_MOUSE,FL_FULLBORDER,
+                            FL_PLACE_MOUSE | FL_FREE_SIZE, FL_TRANSIENT,
                             _("Spellchecker"));
        }
        fl_deactivate_object(fd_form_spell_check->slider); 
@@ -542,12 +734,12 @@ void ShowSpellChecker()
        fl_set_object_lcol(fd_form_spell_check->input, FL_INACTIVE);
        fl_set_object_lcol(fd_form_spell_check->browser, FL_INACTIVE);
 
-       while (true){
+       while (true) {
                obj = fl_do_forms();
-               if (obj == fd_form_spell_check->options){
+               if (obj == fd_form_spell_check->options) {
                        SpellCheckerOptions();
                }
-               if (obj == fd_form_spell_check->start){
+               if (obj == fd_form_spell_check->start) {
                        // activate insert, accept, and stop
                        fl_activate_object(fd_form_spell_check->insert);
                        fl_activate_object(fd_form_spell_check->accept);
@@ -562,7 +754,7 @@ void ShowSpellChecker()
                        fl_set_object_lcol(fd_form_spell_check->input, FL_BLACK);
                        fl_set_object_lcol(fd_form_spell_check->browser, FL_BLACK);
                        // activate replace only if the file is not read-only
-                       if (!current_view->currentBuffer()->isReadonly()) { 
+                       if (!bv->buffer()->isReadonly()) { 
                          fl_activate_object(fd_form_spell_check->replace);
                          fl_set_object_lcol(fd_form_spell_check->replace, FL_BLACK);
                        }
@@ -573,7 +765,7 @@ void ShowSpellChecker()
                        fl_set_object_lcol(fd_form_spell_check->options, FL_INACTIVE);
                        fl_set_object_lcol(fd_form_spell_check->start, FL_INACTIVE);
 
-                       ret = RunSpellChecker(current_view->currentBuffer()->GetLanguage());
+                       ret = RunSpellChecker(bv);
 
                        // deactivate insert, accept, replace, and stop
                        fl_deactivate_object(fd_form_spell_check->insert);
@@ -603,177 +795,204 @@ void ShowSpellChecker()
                if (obj == fd_form_spell_check->done) break;
        }
        fl_hide_form(fd_form_spell_check->form_spell_check);
-       EndOfSpellCheck();
+       bv->endOfSpellCheck();
        return;
 }
 
 
-// Perform an ispell session
-static
-bool RunSpellChecker(LString const & lang)
-{
-       isp_result *result;
-       char *word;
-       int i, oldval, clickline, newvalue;
-       float newval;
-       FL_OBJECT *obj;
-       unsigned int word_count = 0;
+// Perform a spell session
+namespace {
 
-       LString tmp = (lyxrc->isp_use_alt_lang) ? lyxrc->isp_alt_lang:lang;
+bool RunSpellChecker(BufferView * bv)
+{
+       isp_result * result;
+       int newvalue;
+       FL_OBJECT * obj;
+
+#ifndef NEW_INSETS
+       // Open all floats
+        bv->allFloats(1, 0);
+        bv->allFloats(1, 1);
+#endif
 
-       oldval = 0;  /* used for updating slider only when needed */
-       newval = 0.0;
+#ifdef USE_PSPELL
+       string tmp = (lyxrc.isp_use_alt_lang) ?
+           lyxrc.isp_alt_lang : bv->buffer()->params.language->code();
+#else
+       string tmp = (lyxrc.isp_use_alt_lang) ?
+           lyxrc.isp_alt_lang : bv->buffer()->params.language->lang();
+#endif
+       bool rtl = false;
+       if (lyxrc.isp_use_alt_lang) {
+               Language const * lang = languages.getLanguage(tmp);
+               if (lang)
+                       rtl = lang->RightToLeft();
+       } else
+           rtl = bv->buffer()->params.language->RightToLeft();
+
+       int oldval = 0;  /* used for updating slider only when needed */
+       float newval = 0.0;
    
        /* create ispell process */
-       create_ispell_pipe(tmp);
+       init_spell_checker(bv->buffer()->params, tmp);
 
-       if (isp_pid == -1) {
-               fl_show_message(
-                       _("\n\n"
-                         "The ispell-process has died for some reason. *One* possible reason\n"
-                         "could be that you do not have a dictionary file\n"
-                         "for the language of this document installed.\n"
-                         "Check /usr/lib/ispell or set another\n"
-                         "dictionary in the Spellchecker Options menu."), "", "");
-               fclose(out);
-               return true;
+       if (spell_error != 0) {
+               fl_show_message(_(spell_error), "", "");
+               sc_clean_up_after_error();
+               return false;
        }
 
-       // Put ispell in terse mode to improve speed
-       ispell_terse_mode();
+       unsigned int word_count = 0;
 
        while (true) {
-               word = NextWord(newval);
-               if (word==NULL) break;
-               word_count++;
+               string const word = bv->nextWord(newval);
+               if (word.empty()) break;
+               ++word_count;
                
                // Update slider if and only if value has changed
                newvalue = int(100.0*newval);
-               if(newvalue!=oldval) {
+               if (newvalue!= oldval) {
                        oldval = newvalue;
                        fl_set_slider_value(fd_form_spell_check->slider, oldval);
                }
 
-               result = ispell_check_word(word);
-               if (isp_pid==-1) {
-                       delete[] word;
-                       break;
+               if (word_count%1000 == 0) {
+                       obj =  fl_check_forms();
+                       if (obj == fd_form_spell_check->stop) {
+                               close_spell_checker();
+                               return true;
+                       }
+                       if (obj == fd_form_spell_check->done) {
+                               close_spell_checker();
+                               return false;
+                       }
                }
 
-               obj =  fl_check_forms();
-               if (obj == fd_form_spell_check->stop) {
+               result = sc_check_word(word);
+               if (!sc_still_alive()) {
                        delete result;
-                       delete[] word;
-                       ispell_terminate();
-                       return true;
-               }
-               if (obj == fd_form_spell_check->done) {
-                       delete result;
-                       delete[] word;
-                       ispell_terminate(); 
-                       return false;
+                       break;
                }
-    
+
                switch (result->flag) {
                case ISP_UNKNOWN:
                case ISP_MISSED:
-                       SelectLastWord();
-                       fl_set_object_label(fd_form_spell_check->text, word);
-                       fl_set_input(fd_form_spell_check->input, word);
+               {
+                       bv->selectLastWord();
+                       if (rtl) {
+                               string tmp = word;
+                               reverse(tmp.begin(),tmp.end());
+                               fl_set_object_label(fd_form_spell_check->text, tmp.c_str());
+                       } else
+                               fl_set_object_label(fd_form_spell_check->text, word.c_str());
+                       fl_set_input(fd_form_spell_check->input, word.c_str());
                        fl_clear_browser(fd_form_spell_check->browser);
-                       for (i=0; i<result->count; i++) {
-                               fl_add_browser_line(fd_form_spell_check->browser, result->misses[i]);
+                       const char * w;
+                       while ((w = result->next_miss()) != 0) {
+                               if (rtl) {
+                                       string tmp = w;
+                                       reverse(tmp.begin(),tmp.end());
+                                       fl_add_browser_line(fd_form_spell_check->browser, tmp.c_str());
+                               } else
+                                       fl_add_browser_line(fd_form_spell_check->browser, w);
                        }
 
-                       clickline = -1;
+                       int clickline = -1;
                        while (true) {
                                obj = fl_do_forms();
-                               if (obj==fd_form_spell_check->insert) {
-                                       ispell_insert_word(word);
+                               if (obj == fd_form_spell_check->insert) {
+                                       sc_insert_word(word);
                                        break;
                                }
-                               if (obj==fd_form_spell_check->accept) {
-                                       ispell_accept_word(word);
+                               if (obj == fd_form_spell_check->accept) {
+                                       sc_accept_word(word);
                                        break;
                                }
-                               if (obj==fd_form_spell_check->ignore) {
+                               if (obj == fd_form_spell_check->ignore) {
                                        break;
                                }
-                               if (obj==fd_form_spell_check->replace || 
-                                   obj==fd_form_spell_check->input) {
-                                       ispell_store_replacement(word, fl_get_input(fd_form_spell_check->input));
-                                       ReplaceWord(fl_get_input(fd_form_spell_check->input));
+                               if (obj == fd_form_spell_check->replace || 
+                                   obj == fd_form_spell_check->input) {
+                                       sc_store_replacement(word, fl_get_input(fd_form_spell_check->input));
+                                       bv->replaceWord(fl_get_input(fd_form_spell_check->input));
                                        break;
                                }
-                               if (obj==fd_form_spell_check->browser) {
+                               if (obj == fd_form_spell_check->browser) {
                                        // implements double click in the browser window.
                                        // sent to lyx@via by Mark Burton <mark@cbl.leeds.ac.uk>
-                                       if (clickline ==
+                                       if (clickline == 
                                            fl_get_browser(fd_form_spell_check->browser)) {
-                                               ispell_store_replacement(word, fl_get_input(fd_form_spell_check->input));
-                                               ReplaceWord(fl_get_input(fd_form_spell_check->input));
+                                               sc_store_replacement(word, fl_get_input(fd_form_spell_check->input));
+                                               bv->replaceWord(fl_get_input(fd_form_spell_check->input));
                                                break;
                                        }
                                        clickline = fl_get_browser(fd_form_spell_check->browser);
-                                       fl_set_input(fd_form_spell_check->input, 
-                                                    fl_get_browser_line(fd_form_spell_check->browser,
-                                                                        fl_get_browser(fd_form_spell_check->browser)));
-                                                    
+                                       /// Why not use
+                                       /// fl_set_input(fd_form_spell_check->input, result->misses[clickline-1]); ?
+                                       if (rtl) {
+                                               string tmp = fl_get_browser_line(fd_form_spell_check->browser,
+                                                                                clickline);
+                                               reverse(tmp.begin(),tmp.end());
+                                               fl_set_input(fd_form_spell_check->input, tmp.c_str());
+                                       } else
+                                               fl_set_input(fd_form_spell_check->input,
+                                                            fl_get_browser_line(fd_form_spell_check->browser,
+                                                                                clickline));
                                }
-                               if (obj==fd_form_spell_check->stop) {
+                               if (obj == fd_form_spell_check->stop) {
                                        delete result;
-                                       delete[] word;
-                                       ispell_terminate();
+                                       close_spell_checker();
                                        return true;
                                }
            
-                               if (obj==fd_form_spell_check->done) {
+                               if (obj == fd_form_spell_check->done) {
                                        delete result;
-                                       delete[] word;
-                                       ispell_terminate();
+                                       close_spell_checker();
                                        return false;
                                }
                        }
+               }
                default:
                        delete result;
-                       delete[] word;
                }
        }
    
-       if(isp_pid!=-1) {
-               ispell_terminate();
-               LString word_msg;
-               word_msg += int(word_count);
+       if (sc_still_alive()) {
+               close_spell_checker();
+               string word_msg(tostr(word_count));
                if (word_count != 1) {
                        word_msg += _(" words checked.");
                } else {
                        word_msg += _(" word checked.");
                }
-               fl_show_message("",_("Spellchecking completed!"),
+               fl_show_message("", _("Spellchecking completed!"),
                                word_msg.c_str());
                return false;
        } else {
-               fl_show_message(_("The ispell-process has died for some reason.\n"
+               fl_show_message(_("The spell checker has died for some reason.\n"
                                "Maybe it has been killed."), "", "");
-               fclose(out);
+               sc_clean_up_after_error();
                return true;
        }
 }
 
+} // namespace anon
 
-//void sigchldhandler(int sig)
-void sigchldhandler(pid_t pid, int *status)
-{ 
-       //int status ;
-
-       if (isp_pid>0)
-               //if (waitpid(isp_pid,&status,WNOHANG)==isp_pid) {
+#ifdef WITH_WARNINGS
+#warning should go somewhere more sensible
+#endif
+void sigchldhandler(pid_t pid, int * status)
+{
+#ifndef USE_PSPELL
+       if (isp_pid > 0)
                if (pid == isp_pid) {
-                       isp_pid=-1;
+                       isp_pid= -1;
                        fcntl(isp_fd, F_SETFL, O_NONBLOCK); /* set the file descriptor
                                                               to nonblocking so we can 
                                                               continue */
                }
-       //sigchldchecker(sig);
+#endif
        sigchldchecker(pid, status);
 }
+
+