summaryrefslogtreecommitdiff
path: root/pico/osdep/mswin_spell.c
diff options
context:
space:
mode:
Diffstat (limited to 'pico/osdep/mswin_spell.c')
-rw-r--r--pico/osdep/mswin_spell.c1094
1 files changed, 547 insertions, 547 deletions
diff --git a/pico/osdep/mswin_spell.c b/pico/osdep/mswin_spell.c
index 1379beb6..e921cfcd 100644
--- a/pico/osdep/mswin_spell.c
+++ b/pico/osdep/mswin_spell.c
@@ -1,547 +1,547 @@
-/*
- * ========================================================================
- * MSWIN_SPELL.C
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * ========================================================================
- */
-
-#include "../headers.h"
-
-#include "mswin_aspell.h"
-#include "mswin_spell.h"
-
-#include <windowsx.h>
-
-typedef struct WORD_INFO
-{
- ASPELLINFO *aspellinfo; // Aspell information
-
- const char *utf8_err_message; // Error message, if any
-
- char *word_utf8; // utf-8
- LPTSTR word_lptstr;
-
- int word_doto; // UCS
- LINE *word_dotp; //
- int word_size; //
-} WORD_INFO;
-
-extern HINSTANCE ghInstance;
-extern HWND ghTTYWnd;
-
-/*
- * Function prototypes
- */
-static int get_next_bad_word(WORD_INFO *word_info);
-static void free_word_info_words(WORD_INFO *word_info);
-static INT_PTR CALLBACK spell_dlg_proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
-
-/*
- * spell() - check for potentially missspelled words and offer them for
- * correction. Microsoft Windows specific version.
- */
-int
-spell(int f, int n)
-{
- int w_marko_bak;
- LINE *w_markp_bak;
- WORD_INFO word_info;
- ASPELLINFO *aspellinfo;
-
- emlwrite(_("Checking spelling..."), NULL); /* greetings! */
-
- memset(&word_info, 0, sizeof(WORD_INFO));
-
- aspellinfo = speller_init(NULL);
- if(!aspellinfo ||
- (word_info.utf8_err_message = speller_get_error_message(aspellinfo)))
- {
- if(word_info.utf8_err_message)
- emlwrite((char *)word_info.utf8_err_message, NULL); /* sad greetings! */
- else
- emlwrite(_("Spelling: initializing Aspell failed"), NULL);
-
- speller_close(aspellinfo);
- return -1;
- }
-
- // Back up current mark.
- w_marko_bak = curwp->w_marko;
- w_markp_bak = curwp->w_markp;
-
- setimark(0, 1);
- gotobob(0, 1);
-
- word_info.aspellinfo = aspellinfo;
-
- if(get_next_bad_word(&word_info))
- {
- DialogBoxParam(ghInstance, MAKEINTRESOURCE(DLG_SPELL), ghTTYWnd,
- spell_dlg_proc, (LPARAM)&word_info);
- }
-
- // Restore original mark if possible.
- if(curwp->w_markp)
- {
- // Clear any set marks.
- setmark(0, 1);
-
- if(w_markp_bak && llength(w_markp_bak))
- {
- // Make sure we don't set mark off the line.
- if(w_marko_bak >= llength(w_markp_bak))
- w_marko_bak = llength(w_markp_bak) - 1;
-
- curwp->w_marko = w_marko_bak;
- curwp->w_markp = w_markp_bak;
- }
- }
-
- if(word_info.utf8_err_message)
- emlwrite((char *)word_info.utf8_err_message, NULL);
- else
- emlwrite(_("Done checking spelling"), NULL);
-
- speller_close(aspellinfo);
- free_word_info_words(&word_info);
-
- swapimark(0, 1);
- curwp->w_flag |= WFHARD|WFMODE;
-
- update();
- return 1;
-}
-
-/*
- * handle_cb_editchange() - combobox contents have changed so enable/disable
- * the Change and Change All buttons accordingly.
- */
-static void
-handle_cb_editchange(HWND hDlg, HWND hwnd_combo)
-{
- int text_len = ComboBox_GetTextLength(hwnd_combo);
-
- Button_Enable(GetDlgItem(hDlg, ID_BUTTON_CHANGE), !!text_len);
- Button_Enable(GetDlgItem(hDlg, ID_BUTTON_CHANGEALL), !!text_len);
-}
-
-/*
- * spell_dlg_proc_set_word() - Set up the dialog to display spelling
- * information and suggestions for the current word.
- */
-static void
-spell_dlg_proc_set_word(HWND hDlg, WORD_INFO *word_info)
-{
- TCHAR dlg_title[256];
- HWND hwnd_combo = GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS);
-
- // Clear the combobox.
- ComboBox_ResetContent(hwnd_combo);
-
- // Set the dialog box title
- _sntprintf(dlg_title, ARRAYSIZE(dlg_title), TEXT("Not in Dictionary: %s"),
- word_info->word_lptstr);
- dlg_title[ARRAYSIZE(dlg_title) - 1] = 0;
- SetWindowText(hDlg, dlg_title);
-
- // Populate the combobox with suggestions
- if(speller_suggestion_init(word_info->aspellinfo, word_info->word_utf8, -1))
- {
- const char *suggestion_utf8;
-
- while(suggestion_utf8 = speller_suggestion_getnext(word_info->aspellinfo))
- {
- LPTSTR suggestion_lptstr = utf8_to_lptstr((LPSTR)suggestion_utf8);
-
- if(suggestion_lptstr)
- {
- ComboBox_AddString(hwnd_combo, suggestion_lptstr);
- fs_give((void **)&suggestion_lptstr);
- }
- }
-
- // Select the first one.
- ComboBox_SetCurSel(hwnd_combo, 0);
-
- speller_suggestion_close(word_info->aspellinfo);
- }
-
- handle_cb_editchange(hDlg, hwnd_combo);
-}
-
-/*
- * spell_dlg_next_word() - Move to the next misspelled word and display
- * the information for it. If no more bad words, kill the dialog.
- */
-static void
-spell_dlg_next_word(HWND hDlg, WORD_INFO *word_info)
-{
- if(!get_next_bad_word(word_info))
- {
- EndDialog(hDlg, 0);
- return;
- }
-
- spell_dlg_proc_set_word(hDlg, word_info);
-}
-
-/*
- * chword_n() - change the given word_len pointed to by the curwp->w_dot
- * pointers to the word in cb
- */
-static void
-chword_n(int wb_len, UCS *cb)
-{
- ldelete(wb_len, NULL); /* not saved in kill buffer */
-
- while(*cb != '\0')
- linsert(1, *cb++);
-
- curwp->w_flag |= WFEDIT;
-}
-
-/*
- * replace_all() - replace all instances of oldword with newword from
- * the current '.' on. Mark is where curwp will get restored to.
- */
-static void
-replace_all(UCS *oldword, int oldword_len, UCS *newword)
-{
- int wrap;
-
- // Mark should be at "." right now - ie the start of the word we're
- // checking. We're going to use mark below to restore curwp since
- // chword_n can potentially realloc LINES and it knows about markp.
- assert(curwp->w_markp);
- assert(curwp->w_markp == curwp->w_dotp);
- assert(curwp->w_marko == curwp->w_doto);
-
- curwp->w_bufp->b_mode |= MDEXACT; /* case sensitive */
- while(forscan(&wrap, oldword, NULL, 0, 1))
- {
- if(wrap)
- break; /* wrap NOT allowed! */
-
- /*
- * We want to minimize the number of substrings that we report
- * as matching a misspelled word...
- */
- if(lgetc(curwp->w_dotp, 0).c != '>')
- {
- LINE *lp = curwp->w_dotp; /* for convenience */
- int off = curwp->w_doto;
-
- if(off == 0 || !ucs4_isalpha(lgetc(lp, off - 1).c))
- {
- off += oldword_len;
-
- if(off == llength(lp) || !ucs4_isalpha(lgetc(lp, off).c))
- {
- // Replace this word
- chword_n(oldword_len, newword);
- }
- }
- }
-
- forwchar(0, 1); /* move on... */
-
- }
- curwp->w_bufp->b_mode ^= MDEXACT; /* case insensitive */
-
- curwp->w_dotp = curwp->w_markp;
- curwp->w_doto = curwp->w_marko;
-}
-
-/*
- * handle_button_change() - Someone pressed the Change or Change All button.
- * So deal with it.
- */
-static void
-handle_button_change(HWND hDlg, WORD_INFO *word_info, int do_replace_all)
-{
- int str_lptstr_len;
- TCHAR str_lptstr[128];
-
- // Get the length of what they want to change to.
- str_lptstr_len = ComboBox_GetText(GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS),
- str_lptstr, ARRAYSIZE(str_lptstr));
- if(str_lptstr_len)
- {
- UCS *str_ucs4;
- char *str_utf8;
-
- // Notify the speller so it'll suggest this word next time around.
- str_utf8 = lptstr_to_utf8(str_lptstr);
- if(str_utf8)
- {
- speller_replace_word(word_info->aspellinfo,
- word_info->word_utf8, -1, str_utf8, -1);
- fs_give((void **)&str_utf8);
- }
-
- str_ucs4 = lptstr_to_ucs4(str_lptstr);
- if(!str_ucs4)
- {
- // Uh oh - massive error.
- word_info->utf8_err_message = _("Spelling: lptstr_to_ucs4() failed");
- EndDialog(hDlg, -1);
- return;
- }
-
- // Move back to start of this word.
- curwp->w_doto = word_info->word_doto;
- curwp->w_dotp = word_info->word_dotp;
-
- if(do_replace_all)
- {
- int i;
- int word_size;
- UCS word[128];
-
- word_size = word_info->word_size;
- if(word_size >= ARRAYSIZE(word) - 1)
- word_size = ARRAYSIZE(word) - 1;
-
- for(i = 0; i < word_size; i++)
- word[i] = lgetc(curwp->w_dotp, curwp->w_doto + i).c;
-
- word[i] = 0;
-
- replace_all(word, word_size, str_ucs4);
-
- // Skip over the word we just inserted.
- forwchar(FALSE, (int)ucs4_strlen(str_ucs4));
- }
- else
- {
- // Swap it with the new improved version.
- chword_n(word_info->word_size, str_ucs4);
- }
- fs_give((void **)&str_ucs4);
- }
-
- update();
- spell_dlg_next_word(hDlg, word_info);
-}
-
-/*
- * center_dialog() - Center a dialog with respect to its parent.
- */
-static void
-center_dialog(HWND hDlg)
-{
- int dx;
- int dy;
- RECT rcDialog;
- RECT rcParent;
-
- GetWindowRect(GetParent(hDlg), &rcParent);
- GetWindowRect(hDlg, &rcDialog);
-
- dx = ((rcParent.right - rcParent.left) -
- (rcDialog.right - rcDialog.left)) / 2 + rcParent.left - rcDialog.left;
-
- dy = ((rcParent.bottom - rcParent.top) -
- (rcDialog.bottom - rcDialog.top)) / 2 + rcParent.top - rcDialog.top;
-
- OffsetRect(&rcDialog, dx, dy);
-
- SetWindowPos(hDlg, NULL, rcDialog.left, rcDialog.top, 0, 0,
- SWP_NOSIZE | SWP_NOZORDER);
-}
-
-/*
- * spell_dlg_on_command() - Handle the WM_COMMAND stuff for the spell dialog.
- */
-static void
-spell_dlg_on_command(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
-{
- WORD_INFO *word_info =
- (WORD_INFO *)(LONG_PTR)GetWindowLongPtr(hDlg, GWLP_USERDATA);
-
- switch(id)
- {
- case ID_COMBO_SUGGESTIONS:
- if(codeNotify == CBN_EDITCHANGE)
- handle_cb_editchange(hDlg, hwndCtl);
- break;
-
- case ID_BUTTON_CHANGE:
- handle_button_change(hDlg, word_info, 0);
- break;
-
- case ID_BUTTON_CHANGEALL:
- handle_button_change(hDlg, word_info, 1);
- break;
-
- case ID_BUTTON_IGNOREONCE:
- spell_dlg_next_word(hDlg, word_info);
- break;
-
- case ID_BUTTON_IGNOREALL:
- speller_ignore_all(word_info->aspellinfo, word_info->word_utf8, -1);
- spell_dlg_next_word(hDlg, word_info);
- break;
-
- case ID_BUTTON_ADD_TO_DICT:
- speller_add_to_dictionary(word_info->aspellinfo, word_info->word_utf8, -1);
- spell_dlg_next_word(hDlg, word_info);
- break;
-
- case ID_BUTTON_CANCEL:
- EndDialog(hDlg, 0);
- break;
- }
-}
-
-/*
- * spell_dlg_proc() - Main spell dialog proc.
- */
-static INT_PTR CALLBACK
-spell_dlg_proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- WORD_INFO *word_info;
-
- switch(message)
- {
- case WM_INITDIALOG:
- center_dialog(hDlg);
-
- // Limit how much junk they can type in.
- ComboBox_LimitText(GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS), 128);
-
- word_info = (WORD_INFO *)lParam;
- SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)word_info);
-
- spell_dlg_proc_set_word(hDlg, word_info);
- return TRUE;
-
- case WM_COMMAND:
- HANDLE_WM_COMMAND(hDlg, wParam, lParam, spell_dlg_on_command);
- return TRUE;
- }
-
- return FALSE;
-}
-
-/*
- * get_next_word() - Get the next word from dot. And skip words in
- * quoted lines.
- */
-static int
-get_next_word(WORD_INFO *word_info)
-{
- // Skip quoted lines
- while(lgetc(curwp->w_dotp, 0).c == '>')
- {
- if(curwp->w_dotp == curbp->b_linep)
- return 0;
-
- curwp->w_dotp = lforw(curwp->w_dotp);
- curwp->w_doto = 0;
- curwp->w_flag |= WFMOVE;
- }
-
- // Move to a word.
- while(inword() == FALSE)
- {
- if(forwchar(FALSE, 1) == FALSE)
- {
- // There is no next word.
- return 0;
- }
- }
-
- // If mark is currently set, clear it.
- if(curwp->w_markp)
- setmark(0, 1);
-
- // Set mark to beginning of this word.
- curwp->w_markp = curwp->w_dotp;
- curwp->w_marko = curwp->w_doto;
-
- // Get word length
- word_info->word_doto = curwp->w_doto;
- word_info->word_dotp = curwp->w_dotp;
- word_info->word_size = 0;
-
- while((inword() != FALSE) && (word_info->word_dotp == curwp->w_dotp))
- {
- word_info->word_size++;
-
- if(forwchar(FALSE, 1) == FALSE)
- break;
- }
-
- word_info->word_utf8 = ucs4_to_utf8_cpystr_n(
- (UCS *)&word_info->word_dotp->l_text[word_info->word_doto],
- word_info->word_size);
- return 1;
-}
-
-/*
- * get_next_word() - free the word_info members word_utf8 and word_lptstr.
- */
-static void
-free_word_info_words(WORD_INFO *word_info)
-{
- if(word_info->word_utf8)
- {
- fs_give((void **)&word_info->word_utf8);
- word_info->word_utf8 = NULL;
- }
-
- if(word_info->word_lptstr)
- {
- fs_give((void **)&word_info->word_lptstr);
- word_info->word_lptstr = NULL;
- }
-}
-
-/*
- * get_next_bad_word() - Search from '.' for the next word we think is
- * rotten. Mark it and highlight it.
- */
-static int
-get_next_bad_word(WORD_INFO *word_info)
-{
- free_word_info_words(word_info);
-
- while(get_next_word(word_info))
- {
- int ret;
-
- /* pass over words that contain @ */
- if(strchr(word_info->word_utf8, '@'))
- ret = 1;
- else
- ret = speller_check_word(word_info->aspellinfo, word_info->word_utf8, -1);
-
- if(ret == -1)
- {
- word_info->utf8_err_message =
- speller_get_error_message(word_info->aspellinfo);
- if(!word_info->utf8_err_message)
- word_info->utf8_err_message = _("Spelling: speller_check_word() failed");
- return 0;
- }
- else if(ret == 0)
- {
- // Highlight word.
- update();
-
- word_info->word_lptstr = utf8_to_lptstr(word_info->word_utf8);
- return 1;
- }
-
- free_word_info_words(word_info);
- }
-
- return 0;
-}
+/*
+ * ========================================================================
+ * MSWIN_SPELL.C
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * ========================================================================
+ */
+
+#include "../headers.h"
+
+#include "mswin_aspell.h"
+#include "mswin_spell.h"
+
+#include <windowsx.h>
+
+typedef struct WORD_INFO
+{
+ ASPELLINFO *aspellinfo; // Aspell information
+
+ const char *utf8_err_message; // Error message, if any
+
+ char *word_utf8; // utf-8
+ LPTSTR word_lptstr;
+
+ int word_doto; // UCS
+ LINE *word_dotp; //
+ int word_size; //
+} WORD_INFO;
+
+extern HINSTANCE ghInstance;
+extern HWND ghTTYWnd;
+
+/*
+ * Function prototypes
+ */
+static int get_next_bad_word(WORD_INFO *word_info);
+static void free_word_info_words(WORD_INFO *word_info);
+static INT_PTR CALLBACK spell_dlg_proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+
+/*
+ * spell() - check for potentially missspelled words and offer them for
+ * correction. Microsoft Windows specific version.
+ */
+int
+spell(int f, int n)
+{
+ int w_marko_bak;
+ LINE *w_markp_bak;
+ WORD_INFO word_info;
+ ASPELLINFO *aspellinfo;
+
+ emlwrite(_("Checking spelling..."), NULL); /* greetings! */
+
+ memset(&word_info, 0, sizeof(WORD_INFO));
+
+ aspellinfo = speller_init(NULL);
+ if(!aspellinfo ||
+ (word_info.utf8_err_message = speller_get_error_message(aspellinfo)))
+ {
+ if(word_info.utf8_err_message)
+ emlwrite((char *)word_info.utf8_err_message, NULL); /* sad greetings! */
+ else
+ emlwrite(_("Spelling: initializing Aspell failed"), NULL);
+
+ speller_close(aspellinfo);
+ return -1;
+ }
+
+ // Back up current mark.
+ w_marko_bak = curwp->w_marko;
+ w_markp_bak = curwp->w_markp;
+
+ setimark(0, 1);
+ gotobob(0, 1);
+
+ word_info.aspellinfo = aspellinfo;
+
+ if(get_next_bad_word(&word_info))
+ {
+ DialogBoxParam(ghInstance, MAKEINTRESOURCE(DLG_SPELL), ghTTYWnd,
+ spell_dlg_proc, (LPARAM)&word_info);
+ }
+
+ // Restore original mark if possible.
+ if(curwp->w_markp)
+ {
+ // Clear any set marks.
+ setmark(0, 1);
+
+ if(w_markp_bak && llength(w_markp_bak))
+ {
+ // Make sure we don't set mark off the line.
+ if(w_marko_bak >= llength(w_markp_bak))
+ w_marko_bak = llength(w_markp_bak) - 1;
+
+ curwp->w_marko = w_marko_bak;
+ curwp->w_markp = w_markp_bak;
+ }
+ }
+
+ if(word_info.utf8_err_message)
+ emlwrite((char *)word_info.utf8_err_message, NULL);
+ else
+ emlwrite(_("Done checking spelling"), NULL);
+
+ speller_close(aspellinfo);
+ free_word_info_words(&word_info);
+
+ swapimark(0, 1);
+ curwp->w_flag |= WFHARD|WFMODE;
+
+ update();
+ return 1;
+}
+
+/*
+ * handle_cb_editchange() - combobox contents have changed so enable/disable
+ * the Change and Change All buttons accordingly.
+ */
+static void
+handle_cb_editchange(HWND hDlg, HWND hwnd_combo)
+{
+ int text_len = ComboBox_GetTextLength(hwnd_combo);
+
+ Button_Enable(GetDlgItem(hDlg, ID_BUTTON_CHANGE), !!text_len);
+ Button_Enable(GetDlgItem(hDlg, ID_BUTTON_CHANGEALL), !!text_len);
+}
+
+/*
+ * spell_dlg_proc_set_word() - Set up the dialog to display spelling
+ * information and suggestions for the current word.
+ */
+static void
+spell_dlg_proc_set_word(HWND hDlg, WORD_INFO *word_info)
+{
+ TCHAR dlg_title[256];
+ HWND hwnd_combo = GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS);
+
+ // Clear the combobox.
+ ComboBox_ResetContent(hwnd_combo);
+
+ // Set the dialog box title
+ _sntprintf(dlg_title, ARRAYSIZE(dlg_title), TEXT("Not in Dictionary: %s"),
+ word_info->word_lptstr);
+ dlg_title[ARRAYSIZE(dlg_title) - 1] = 0;
+ SetWindowText(hDlg, dlg_title);
+
+ // Populate the combobox with suggestions
+ if(speller_suggestion_init(word_info->aspellinfo, word_info->word_utf8, -1))
+ {
+ const char *suggestion_utf8;
+
+ while(suggestion_utf8 = speller_suggestion_getnext(word_info->aspellinfo))
+ {
+ LPTSTR suggestion_lptstr = utf8_to_lptstr((LPSTR)suggestion_utf8);
+
+ if(suggestion_lptstr)
+ {
+ ComboBox_AddString(hwnd_combo, suggestion_lptstr);
+ fs_give((void **)&suggestion_lptstr);
+ }
+ }
+
+ // Select the first one.
+ ComboBox_SetCurSel(hwnd_combo, 0);
+
+ speller_suggestion_close(word_info->aspellinfo);
+ }
+
+ handle_cb_editchange(hDlg, hwnd_combo);
+}
+
+/*
+ * spell_dlg_next_word() - Move to the next misspelled word and display
+ * the information for it. If no more bad words, kill the dialog.
+ */
+static void
+spell_dlg_next_word(HWND hDlg, WORD_INFO *word_info)
+{
+ if(!get_next_bad_word(word_info))
+ {
+ EndDialog(hDlg, 0);
+ return;
+ }
+
+ spell_dlg_proc_set_word(hDlg, word_info);
+}
+
+/*
+ * chword_n() - change the given word_len pointed to by the curwp->w_dot
+ * pointers to the word in cb
+ */
+static void
+chword_n(int wb_len, UCS *cb)
+{
+ ldelete(wb_len, NULL); /* not saved in kill buffer */
+
+ while(*cb != '\0')
+ linsert(1, *cb++);
+
+ curwp->w_flag |= WFEDIT;
+}
+
+/*
+ * replace_all() - replace all instances of oldword with newword from
+ * the current '.' on. Mark is where curwp will get restored to.
+ */
+static void
+replace_all(UCS *oldword, int oldword_len, UCS *newword)
+{
+ int wrap;
+
+ // Mark should be at "." right now - ie the start of the word we're
+ // checking. We're going to use mark below to restore curwp since
+ // chword_n can potentially realloc LINES and it knows about markp.
+ assert(curwp->w_markp);
+ assert(curwp->w_markp == curwp->w_dotp);
+ assert(curwp->w_marko == curwp->w_doto);
+
+ curwp->w_bufp->b_mode |= MDEXACT; /* case sensitive */
+ while(forscan(&wrap, oldword, 0, NULL, 0, 1))
+ {
+ if(wrap)
+ break; /* wrap NOT allowed! */
+
+ /*
+ * We want to minimize the number of substrings that we report
+ * as matching a misspelled word...
+ */
+ if(lgetc(curwp->w_dotp, 0).c != '>')
+ {
+ LINE *lp = curwp->w_dotp; /* for convenience */
+ int off = curwp->w_doto;
+
+ if(off == 0 || !ucs4_isalpha(lgetc(lp, off - 1).c))
+ {
+ off += oldword_len;
+
+ if(off == llength(lp) || !ucs4_isalpha(lgetc(lp, off).c))
+ {
+ // Replace this word
+ chword_n(oldword_len, newword);
+ }
+ }
+ }
+
+ forwchar(0, 1); /* move on... */
+
+ }
+ curwp->w_bufp->b_mode ^= MDEXACT; /* case insensitive */
+
+ curwp->w_dotp = curwp->w_markp;
+ curwp->w_doto = curwp->w_marko;
+}
+
+/*
+ * handle_button_change() - Someone pressed the Change or Change All button.
+ * So deal with it.
+ */
+static void
+handle_button_change(HWND hDlg, WORD_INFO *word_info, int do_replace_all)
+{
+ int str_lptstr_len;
+ TCHAR str_lptstr[128];
+
+ // Get the length of what they want to change to.
+ str_lptstr_len = ComboBox_GetText(GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS),
+ str_lptstr, ARRAYSIZE(str_lptstr));
+ if(str_lptstr_len)
+ {
+ UCS *str_ucs4;
+ char *str_utf8;
+
+ // Notify the speller so it'll suggest this word next time around.
+ str_utf8 = lptstr_to_utf8(str_lptstr);
+ if(str_utf8)
+ {
+ speller_replace_word(word_info->aspellinfo,
+ word_info->word_utf8, -1, str_utf8, -1);
+ fs_give((void **)&str_utf8);
+ }
+
+ str_ucs4 = lptstr_to_ucs4(str_lptstr);
+ if(!str_ucs4)
+ {
+ // Uh oh - massive error.
+ word_info->utf8_err_message = _("Spelling: lptstr_to_ucs4() failed");
+ EndDialog(hDlg, -1);
+ return;
+ }
+
+ // Move back to start of this word.
+ curwp->w_doto = word_info->word_doto;
+ curwp->w_dotp = word_info->word_dotp;
+
+ if(do_replace_all)
+ {
+ int i;
+ int word_size;
+ UCS word[128];
+
+ word_size = word_info->word_size;
+ if(word_size >= ARRAYSIZE(word) - 1)
+ word_size = ARRAYSIZE(word) - 1;
+
+ for(i = 0; i < word_size; i++)
+ word[i] = lgetc(curwp->w_dotp, curwp->w_doto + i).c;
+
+ word[i] = 0;
+
+ replace_all(word, word_size, str_ucs4);
+
+ // Skip over the word we just inserted.
+ forwchar(FALSE, (int)ucs4_strlen(str_ucs4));
+ }
+ else
+ {
+ // Swap it with the new improved version.
+ chword_n(word_info->word_size, str_ucs4);
+ }
+ fs_give((void **)&str_ucs4);
+ }
+
+ update();
+ spell_dlg_next_word(hDlg, word_info);
+}
+
+/*
+ * center_dialog() - Center a dialog with respect to its parent.
+ */
+static void
+center_dialog(HWND hDlg)
+{
+ int dx;
+ int dy;
+ RECT rcDialog;
+ RECT rcParent;
+
+ GetWindowRect(GetParent(hDlg), &rcParent);
+ GetWindowRect(hDlg, &rcDialog);
+
+ dx = ((rcParent.right - rcParent.left) -
+ (rcDialog.right - rcDialog.left)) / 2 + rcParent.left - rcDialog.left;
+
+ dy = ((rcParent.bottom - rcParent.top) -
+ (rcDialog.bottom - rcDialog.top)) / 2 + rcParent.top - rcDialog.top;
+
+ OffsetRect(&rcDialog, dx, dy);
+
+ SetWindowPos(hDlg, NULL, rcDialog.left, rcDialog.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER);
+}
+
+/*
+ * spell_dlg_on_command() - Handle the WM_COMMAND stuff for the spell dialog.
+ */
+static void
+spell_dlg_on_command(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
+{
+ WORD_INFO *word_info =
+ (WORD_INFO *)(LONG_PTR)GetWindowLongPtr(hDlg, GWLP_USERDATA);
+
+ switch(id)
+ {
+ case ID_COMBO_SUGGESTIONS:
+ if(codeNotify == CBN_EDITCHANGE)
+ handle_cb_editchange(hDlg, hwndCtl);
+ break;
+
+ case ID_BUTTON_CHANGE:
+ handle_button_change(hDlg, word_info, 0);
+ break;
+
+ case ID_BUTTON_CHANGEALL:
+ handle_button_change(hDlg, word_info, 1);
+ break;
+
+ case ID_BUTTON_IGNOREONCE:
+ spell_dlg_next_word(hDlg, word_info);
+ break;
+
+ case ID_BUTTON_IGNOREALL:
+ speller_ignore_all(word_info->aspellinfo, word_info->word_utf8, -1);
+ spell_dlg_next_word(hDlg, word_info);
+ break;
+
+ case ID_BUTTON_ADD_TO_DICT:
+ speller_add_to_dictionary(word_info->aspellinfo, word_info->word_utf8, -1);
+ spell_dlg_next_word(hDlg, word_info);
+ break;
+
+ case ID_BUTTON_CANCEL:
+ EndDialog(hDlg, 0);
+ break;
+ }
+}
+
+/*
+ * spell_dlg_proc() - Main spell dialog proc.
+ */
+static INT_PTR CALLBACK
+spell_dlg_proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ WORD_INFO *word_info;
+
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ center_dialog(hDlg);
+
+ // Limit how much junk they can type in.
+ ComboBox_LimitText(GetDlgItem(hDlg, ID_COMBO_SUGGESTIONS), 128);
+
+ word_info = (WORD_INFO *)lParam;
+ SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)word_info);
+
+ spell_dlg_proc_set_word(hDlg, word_info);
+ return TRUE;
+
+ case WM_COMMAND:
+ HANDLE_WM_COMMAND(hDlg, wParam, lParam, spell_dlg_on_command);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * get_next_word() - Get the next word from dot. And skip words in
+ * quoted lines.
+ */
+static int
+get_next_word(WORD_INFO *word_info)
+{
+ // Skip quoted lines
+ while(lgetc(curwp->w_dotp, 0).c == '>')
+ {
+ if(curwp->w_dotp == curbp->b_linep)
+ return 0;
+
+ curwp->w_dotp = lforw(curwp->w_dotp);
+ curwp->w_doto = 0;
+ curwp->w_flag |= WFMOVE;
+ }
+
+ // Move to a word.
+ while(inword() == FALSE)
+ {
+ if(forwchar(FALSE, 1) == FALSE)
+ {
+ // There is no next word.
+ return 0;
+ }
+ }
+
+ // If mark is currently set, clear it.
+ if(curwp->w_markp)
+ setmark(0, 1);
+
+ // Set mark to beginning of this word.
+ curwp->w_markp = curwp->w_dotp;
+ curwp->w_marko = curwp->w_doto;
+
+ // Get word length
+ word_info->word_doto = curwp->w_doto;
+ word_info->word_dotp = curwp->w_dotp;
+ word_info->word_size = 0;
+
+ while((inword() != FALSE) && (word_info->word_dotp == curwp->w_dotp))
+ {
+ word_info->word_size++;
+
+ if(forwchar(FALSE, 1) == FALSE)
+ break;
+ }
+
+ word_info->word_utf8 = ucs4_to_utf8_cpystr_n(
+ (UCS *)&word_info->word_dotp->l_text[word_info->word_doto],
+ word_info->word_size);
+ return 1;
+}
+
+/*
+ * get_next_word() - free the word_info members word_utf8 and word_lptstr.
+ */
+static void
+free_word_info_words(WORD_INFO *word_info)
+{
+ if(word_info->word_utf8)
+ {
+ fs_give((void **)&word_info->word_utf8);
+ word_info->word_utf8 = NULL;
+ }
+
+ if(word_info->word_lptstr)
+ {
+ fs_give((void **)&word_info->word_lptstr);
+ word_info->word_lptstr = NULL;
+ }
+}
+
+/*
+ * get_next_bad_word() - Search from '.' for the next word we think is
+ * rotten. Mark it and highlight it.
+ */
+static int
+get_next_bad_word(WORD_INFO *word_info)
+{
+ free_word_info_words(word_info);
+
+ while(get_next_word(word_info))
+ {
+ int ret;
+
+ /* pass over words that contain @ */
+ if(strchr(word_info->word_utf8, '@'))
+ ret = 1;
+ else
+ ret = speller_check_word(word_info->aspellinfo, word_info->word_utf8, -1);
+
+ if(ret == -1)
+ {
+ word_info->utf8_err_message =
+ speller_get_error_message(word_info->aspellinfo);
+ if(!word_info->utf8_err_message)
+ word_info->utf8_err_message = _("Spelling: speller_check_word() failed");
+ return 0;
+ }
+ else if(ret == 0)
+ {
+ // Highlight word.
+ update();
+
+ word_info->word_lptstr = utf8_to_lptstr(word_info->word_utf8);
+ return 1;
+ }
+
+ free_word_info_words(word_info);
+ }
+
+ return 0;
+}