X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fspellchecker.C;h=04a578affd791a636bf98aca837ba5c9bff223dd;hb=a69e7a45780e94f4330a91facfe35126c678e34e;hp=7e72553e74e5a10ed3826e9da52d154382bccbf7;hpb=0eccdd1c3613e5170deb77b22174dd0afde833e9;p=lyx.git diff --git a/src/spellchecker.C b/src/spellchecker.C index 7e72553e74..04a578affd 100644 --- a/src/spellchecker.C +++ b/src/spellchecker.C @@ -1,20 +1,23 @@ /* *This file is part of - * ====================================================== + * ====================================================== * * LyX, The Document Processor * * Copyright 1995 Matthias Ettrich * Copyright 1995-1998 The LyX Team * - *====================================================== + * ====================================================== */ #include +#ifdef __GNUG__ +#pragma implementation +#endif + #include #include -#include #include #include #include @@ -35,9 +38,15 @@ #endif #ifdef HAVE_SYS_SELECT_H +# ifdef HAVE_STRINGS_H + // is needed at least on AIX because FD_ZERO uses bzero(). +# include +# endif #include #endif +#include + #include "LString.h" #include "sp_form.h" #include "spellchecker.h" @@ -47,9 +56,12 @@ #include "BufferView.h" #include "gettext.h" #include "lyx_gui_misc.h" +#include "debug.h" +#include "support/lstrings.h" +#include "encoding.h" -extern LyXRC *lyxrc; -extern BufferView *current_view; +using std::reverse; +using std::endl; // Spellchecker status enum { @@ -61,9 +73,9 @@ enum { ISP_IGNORE }; -static bool RunSpellChecker(string const &); +static bool RunSpellChecker(BufferView * bv); -static FILE *in, *out; /* streams to communicate with ispell */ +static FILE * in, * out; /* streams to communicate with ispell */ pid_t isp_pid = -1; // pid for the `ispell' process. Also used (RO) in // lyx_cb.C @@ -86,14 +98,14 @@ struct isp_result { int flag; int count; string str; - char **misses; + char ** misses; isp_result() { flag = ISP_UNKNOWN; count = 0; - misses = (char**)0; + misses = static_cast(0); } ~isp_result() { - if (misses) delete[] misses; + delete[] misses; } }; @@ -107,68 +119,68 @@ struct isp_result { 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 @@ -212,7 +224,7 @@ 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_FULLBORDER, _("Spellchecker Options")); } } @@ -223,7 +235,7 @@ void SpellCheckerOptions() // Could also use a clean up. (Asger Alstrup) static -void create_ispell_pipe(string const & lang) +void create_ispell_pipe(BufferParams const & params, string const & lang) { static char o_buf[BUFSIZ]; // jc: it could be smaller int pipein[2], pipeout[2]; @@ -232,18 +244,20 @@ void create_ispell_pipe(string const & lang) isp_pid = -1; - if(pipe(pipein)==-1 || pipe(pipeout)==-1) { - fprintf(stderr,"LyX: Can't create pipe for spellchecker!"); + if(pipe(pipein) == -1 || pipe(pipeout) == -1) { + lyxerr << "LyX: Can't create pipe for spellchecker!" << endl; return; } - if ((out = fdopen(pipein[1], "w"))==0) { - fprintf(stderr,"LyX: Can't create stream for pipe for spellchecker!"); + if ((out = fdopen(pipein[1], "w")) == 0) { + lyxerr << "LyX: Can't create stream for pipe for spellchecker!" + << endl; return; } - if ((in = fdopen(pipeout[0], "r"))==0) { - fprintf(stderr,"LyX: Can't create stream for pipe for spellchecker!"); + if ((in = fdopen(pipeout[0], "r")) == 0) { + lyxerr <<"LyX: Can't create stream for pipe for spellchecker!" + << endl; return; } @@ -253,12 +267,13 @@ void create_ispell_pipe(string const & lang) isp_pid = fork(); - if(isp_pid==-1) { - fprintf(stderr,"LyX: Can't create child process for spellchecker!"); + if(isp_pid == -1) { + lyxerr << "LyX: Can't create child process for spellchecker!" + << endl; return; } - if(isp_pid==0) { + if(isp_pid == 0) { /* child process */ dup2(pipein[0], STDIN_FILENO); dup2(pipeout[1], STDOUT_FILENO); @@ -268,9 +283,9 @@ void create_ispell_pipe(string const & lang) close(pipeout[1]); 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'; + 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 @@ -285,7 +300,7 @@ void create_ispell_pipe(string const & lang) argv[argc++] = tmp; } - if (lyxrc->isp_accept_compound) { + if (lyxrc.isp_accept_compound) { // Consider run-together words as legal compounds tmp = new char[3]; string("-C").copy(tmp, 2); tmp[2] = '\0'; @@ -297,50 +312,54 @@ void create_ispell_pipe(string const & lang) string("-B").copy(tmp, 2); tmp[2] = '\0'; argv[argc++] = tmp; } - if (lyxrc->isp_use_esc_chars) { + 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 + "\""; + 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 tmp = new char[3]; string("-p").copy(tmp, 2); - tmp[2]='\0'; + 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'; + 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") { + if (lyxrc.isp_use_input_encoding && + params.inputenc != "default") { + string enc = (params.inputenc == "auto") + ? params.language_info->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[current_view->currentBuffer()->params.inputenc.length() + 1]; - current_view->currentBuffer()->params.inputenc.copy(tmp, current_view->currentBuffer()->params.inputenc.length()); - tmp[current_view->currentBuffer()->params.inputenc.length()] = '\0'; + tmp = new char[n + 1]; + enc.copy(tmp, n); + tmp[n] = '\0'; argv[argc++] = tmp; } argv[argc++] = 0; - execvp("ispell", (char * const *) argv); + execvp(argv[0], const_cast(argv)); // 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); } @@ -349,9 +368,6 @@ void create_ispell_pipe(string const & lang) // 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; @@ -382,17 +398,15 @@ void create_ispell_pipe(string const & lang) } 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; } } @@ -413,7 +427,7 @@ isp_result *ispell_check_word(char *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 (isp_pid == -1) return (isp_result *) 0; + if (isp_pid == -1) return 0; result = new isp_result; @@ -438,20 +452,23 @@ isp_result *ispell_check_word(char *word) { result->flag = ISP_MISSED; result->str = buf; + // nb is leaked! where should it be freed? I have to + // admit I do not understand the intent of the code :( + // (JMarc) char * nb = new char[result->str.length() + 1]; result->str.copy(nb, result->str.length()); - nb[result->str.length()]='\0'; + nb[result->str.length()]= '\0'; 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; imisses[i] = p; p = strpbrk(p, ",\n"); *p = 0; - p+=2; + p += 2; } break; } @@ -460,15 +477,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() +static inline +void ispell_terminate() { // Note: If you decide to optimize this out when it is not // needed please note that when Aspell is used this command @@ -482,15 +499,15 @@ inline void ispell_terminate() } -static -inline void ispell_terse_mode() +static inline +void ispell_terse_mode() { fputs("!\n", out); // Set terse mode (silently accept correct words) } -static -inline void ispell_insert_word(char const *word) +static inline +void ispell_insert_word(char const *word) { fputc('*', out); // Insert word in personal dictionary fputs(word, out); @@ -498,16 +515,16 @@ inline void ispell_insert_word(char const *word) } -static -inline void ispell_accept_word(char const *word) +static inline +void ispell_accept_word(char const *word) { fputc('@', out); // Accept in this session fputs(word, out); fputc('\n', out); } -static -inline void ispell_store_replacement(const char *mis, string const & cor) { +static inline +void ispell_store_replacement(char const *mis, string const & cor) { if(actual_spell_checker == ASC_ASPELL) { fputs("$$ra ", out); fputs(mis, out); @@ -518,19 +535,20 @@ inline void ispell_store_replacement(const char *mis, string const & cor) { } -void ShowSpellChecker() +void ShowSpellChecker(BufferView * bv) { - FL_OBJECT *obj; + 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 == 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, 0); + fl_set_form_atclose(fd_form_spell_check->form_spell_check, + CancelCloseBoxCB, 0); } // Clear form @@ -545,7 +563,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_FULLBORDER, _("Spellchecker")); } fl_deactivate_object(fd_form_spell_check->slider); @@ -586,7 +604,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); } @@ -597,7 +615,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); @@ -627,29 +645,27 @@ 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(string const & lang) +bool RunSpellChecker(BufferView * bv) { - isp_result *result; - char *word; - int i, oldval, clickline, newvalue; - float newval; - FL_OBJECT *obj; - unsigned int word_count = 0; + isp_result * result; + int i, newvalue; + FL_OBJECT * obj; - string tmp = (lyxrc->isp_use_alt_lang) ? lyxrc->isp_alt_lang:lang; + string tmp = (lyxrc.isp_use_alt_lang) ? lyxrc.isp_alt_lang : bv->buffer()->GetLanguage(); + bool rtl = tmp == "hebrew" || tmp == "arabic"; - oldval = 0; /* used for updating slider only when needed */ - newval = 0.0; + int oldval = 0; /* used for updating slider only when needed */ + float newval = 0.0; /* create ispell process */ - create_ispell_pipe(tmp); + create_ispell_pipe(bv->buffer()->params, tmp); if (isp_pid == -1) { fl_show_message( @@ -660,120 +676,140 @@ bool RunSpellChecker(string const & lang) "Check /usr/lib/ispell or set another\n" "dictionary in the Spellchecker Options menu."), "", ""); fclose(out); - return true; + 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==0) break; - word_count++; + char * word = bv->nextWord(newval); + if (word == 0) 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); + } + + if (word_count%1000 == 0) { + obj = fl_check_forms(); + if (obj == fd_form_spell_check->stop) { + delete[] word; + ispell_terminate(); + return true; + } + if (obj == fd_form_spell_check->done) { + delete[] word; + ispell_terminate(); + return false; + } } result = ispell_check_word(word); - if (isp_pid==-1) { + if (isp_pid == -1) { + delete result; delete[] word; break; } - obj = fl_check_forms(); - if (obj == fd_form_spell_check->stop) { - delete result; - delete[] word; - ispell_terminate(); - return true; - } - if (obj == fd_form_spell_check->done) { - delete result; - delete[] word; - ispell_terminate(); - return false; - } - switch (result->flag) { case ISP_UNKNOWN: case ISP_MISSED: - SelectLastWord(); - fl_set_object_label(fd_form_spell_check->text, 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); fl_set_input(fd_form_spell_check->input, word); fl_clear_browser(fd_form_spell_check->browser); - for (i=0; icount; i++) { - fl_add_browser_line(fd_form_spell_check->browser, result->misses[i]); + for (i = 0; i < result->count; ++i) { + if (rtl) { + string tmp = result->misses[i]; + 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, result->misses[i]); } - clickline = -1; + int clickline = -1; while (true) { obj = fl_do_forms(); - if (obj==fd_form_spell_check->insert) { + if (obj == fd_form_spell_check->insert) { ispell_insert_word(word); break; } - if (obj==fd_form_spell_check->accept) { + if (obj == fd_form_spell_check->accept) { ispell_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) { + 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)); + 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 - 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)); + 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(); return true; } - if (obj==fd_form_spell_check->done) { + if (obj == fd_form_spell_check->done) { delete result; delete[] word; ispell_terminate(); return false; } } + } default: delete result; delete[] word; } } - if(isp_pid!=-1) { + if(isp_pid!= -1) { ispell_terminate(); - string word_msg; - word_msg += int(word_count); + 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 { @@ -785,19 +821,14 @@ bool RunSpellChecker(string const & lang) } -//void sigchldhandler(int sig) -void sigchldhandler(pid_t pid, int *status) +void sigchldhandler(pid_t pid, int * status) { - //int status ; - - if (isp_pid>0) - //if (waitpid(isp_pid,&status,WNOHANG)==isp_pid) { + 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); sigchldchecker(pid, status); }