xref: /vim-8.2.3635/src/spellsuggest.c (revision ed37d9b3)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * spellsuggest.c: functions for spelling suggestions
12  */
13 
14 #include "vim.h"
15 
16 #if defined(FEAT_SPELL) || defined(PROTO)
17 
18 /*
19  * Use this to adjust the score after finding suggestions, based on the
20  * suggested word sounding like the bad word.  This is much faster than doing
21  * it for every possible suggestion.
22  * Disadvantage: When "the" is typed as "hte" it sounds quite different ("@"
23  * vs "ht") and goes down in the list.
24  * Used when 'spellsuggest' is set to "best".
25  */
26 #define RESCORE(word_score, sound_score) ((3 * word_score + sound_score) / 4)
27 
28 /*
29  * Do the opposite: based on a maximum end score and a known sound score,
30  * compute the maximum word score that can be used.
31  */
32 #define MAXSCORE(word_score, sound_score) ((4 * word_score - sound_score) / 3)
33 
34 // only used for su_badflags
35 #define WF_MIXCAP   0x20	// mix of upper and lower case: macaRONI
36 
37 /*
38  * Information used when looking for suggestions.
39  */
40 typedef struct suginfo_S
41 {
42     garray_T	su_ga;		    // suggestions, contains "suggest_T"
43     int		su_maxcount;	    // max. number of suggestions displayed
44     int		su_maxscore;	    // maximum score for adding to su_ga
45     int		su_sfmaxscore;	    // idem, for when doing soundfold words
46     garray_T	su_sga;		    // like su_ga, sound-folded scoring
47     char_u	*su_badptr;	    // start of bad word in line
48     int		su_badlen;	    // length of detected bad word in line
49     int		su_badflags;	    // caps flags for bad word
50     char_u	su_badword[MAXWLEN]; // bad word truncated at su_badlen
51     char_u	su_fbadword[MAXWLEN]; // su_badword case-folded
52     char_u	su_sal_badword[MAXWLEN]; // su_badword soundfolded
53     hashtab_T	su_banned;	    // table with banned words
54     slang_T	*su_sallang;	    // default language for sound folding
55 } suginfo_T;
56 
57 // One word suggestion.  Used in "si_ga".
58 typedef struct suggest_S
59 {
60     char_u	*st_word;	// suggested word, allocated string
61     int		st_wordlen;	// STRLEN(st_word)
62     int		st_orglen;	// length of replaced text
63     int		st_score;	// lower is better
64     int		st_altscore;	// used when st_score compares equal
65     int		st_salscore;	// st_score is for soundalike
66     int		st_had_bonus;	// bonus already included in score
67     slang_T	*st_slang;	// language used for sound folding
68 } suggest_T;
69 
70 #define SUG(ga, i) (((suggest_T *)(ga).ga_data)[i])
71 
72 // TRUE if a word appears in the list of banned words.
73 #define WAS_BANNED(su, word) (!HASHITEM_EMPTY(hash_find(&su->su_banned, word)))
74 
75 // Number of suggestions kept when cleaning up.  We need to keep more than
76 // what is displayed, because when rescore_suggestions() is called the score
77 // may change and wrong suggestions may be removed later.
78 #define SUG_CLEAN_COUNT(su)    ((su)->su_maxcount < 130 ? 150 : (su)->su_maxcount + 20)
79 
80 // Threshold for sorting and cleaning up suggestions.  Don't want to keep lots
81 // of suggestions that are not going to be displayed.
82 #define SUG_MAX_COUNT(su)	(SUG_CLEAN_COUNT(su) + 50)
83 
84 // score for various changes
85 #define SCORE_SPLIT	149	// split bad word
86 #define SCORE_SPLIT_NO	249	// split bad word with NOSPLITSUGS
87 #define SCORE_ICASE	52	// slightly different case
88 #define SCORE_REGION	200	// word is for different region
89 #define SCORE_RARE	180	// rare word
90 #define SCORE_SWAP	75	// swap two characters
91 #define SCORE_SWAP3	110	// swap two characters in three
92 #define SCORE_REP	65	// REP replacement
93 #define SCORE_SUBST	93	// substitute a character
94 #define SCORE_SIMILAR	33	// substitute a similar character
95 #define SCORE_SUBCOMP	33	// substitute a composing character
96 #define SCORE_DEL	94	// delete a character
97 #define SCORE_DELDUP	66	// delete a duplicated character
98 #define SCORE_DELCOMP	28	// delete a composing character
99 #define SCORE_INS	96	// insert a character
100 #define SCORE_INSDUP	67	// insert a duplicate character
101 #define SCORE_INSCOMP	30	// insert a composing character
102 #define SCORE_NONWORD	103	// change non-word to word char
103 
104 #define SCORE_FILE	30	// suggestion from a file
105 #define SCORE_MAXINIT	350	// Initial maximum score: higher == slower.
106 				// 350 allows for about three changes.
107 
108 #define SCORE_COMMON1	30	// subtracted for words seen before
109 #define SCORE_COMMON2	40	// subtracted for words often seen
110 #define SCORE_COMMON3	50	// subtracted for words very often seen
111 #define SCORE_THRES2	10	// word count threshold for COMMON2
112 #define SCORE_THRES3	100	// word count threshold for COMMON3
113 
114 // When trying changed soundfold words it becomes slow when trying more than
115 // two changes.  With less then two changes it's slightly faster but we miss a
116 // few good suggestions.  In rare cases we need to try three of four changes.
117 #define SCORE_SFMAX1	200	// maximum score for first try
118 #define SCORE_SFMAX2	300	// maximum score for second try
119 #define SCORE_SFMAX3	400	// maximum score for third try
120 
121 #define SCORE_BIG	SCORE_INS * 3	// big difference
122 #define SCORE_MAXMAX	999999		// accept any score
123 #define SCORE_LIMITMAX	350		// for spell_edit_score_limit()
124 
125 // for spell_edit_score_limit() we need to know the minimum value of
126 // SCORE_ICASE, SCORE_SWAP, SCORE_DEL, SCORE_SIMILAR and SCORE_INS
127 #define SCORE_EDIT_MIN	SCORE_SIMILAR
128 
129 /*
130  * For finding suggestions: At each node in the tree these states are tried:
131  */
132 typedef enum
133 {
134     STATE_START = 0,	// At start of node check for NUL bytes (goodword
135 			// ends); if badword ends there is a match, otherwise
136 			// try splitting word.
137     STATE_NOPREFIX,	// try without prefix
138     STATE_SPLITUNDO,	// Undo splitting.
139     STATE_ENDNUL,	// Past NUL bytes at start of the node.
140     STATE_PLAIN,	// Use each byte of the node.
141     STATE_DEL,		// Delete a byte from the bad word.
142     STATE_INS_PREP,	// Prepare for inserting bytes.
143     STATE_INS,		// Insert a byte in the bad word.
144     STATE_SWAP,		// Swap two bytes.
145     STATE_UNSWAP,	// Undo swap two characters.
146     STATE_SWAP3,	// Swap two characters over three.
147     STATE_UNSWAP3,	// Undo Swap two characters over three.
148     STATE_UNROT3L,	// Undo rotate three characters left
149     STATE_UNROT3R,	// Undo rotate three characters right
150     STATE_REP_INI,	// Prepare for using REP items.
151     STATE_REP,		// Use matching REP items from the .aff file.
152     STATE_REP_UNDO,	// Undo a REP item replacement.
153     STATE_FINAL		// End of this node.
154 } state_T;
155 
156 /*
157  * Struct to keep the state at each level in suggest_try_change().
158  */
159 typedef struct trystate_S
160 {
161     state_T	ts_state;	// state at this level, STATE_
162     int		ts_score;	// score
163     idx_T	ts_arridx;	// index in tree array, start of node
164     short	ts_curi;	// index in list of child nodes
165     char_u	ts_fidx;	// index in fword[], case-folded bad word
166     char_u	ts_fidxtry;	// ts_fidx at which bytes may be changed
167     char_u	ts_twordlen;	// valid length of tword[]
168     char_u	ts_prefixdepth;	// stack depth for end of prefix or
169 				// PFD_PREFIXTREE or PFD_NOPREFIX
170     char_u	ts_flags;	// TSF_ flags
171     char_u	ts_tcharlen;	// number of bytes in tword character
172     char_u	ts_tcharidx;	// current byte index in tword character
173     char_u	ts_isdiff;	// DIFF_ values
174     char_u	ts_fcharstart;	// index in fword where badword char started
175     char_u	ts_prewordlen;	// length of word in "preword[]"
176     char_u	ts_splitoff;	// index in "tword" after last split
177     char_u	ts_splitfidx;	// "ts_fidx" at word split
178     char_u	ts_complen;	// nr of compound words used
179     char_u	ts_compsplit;	// index for "compflags" where word was spit
180     char_u	ts_save_badflags;   // su_badflags saved here
181     char_u	ts_delidx;	// index in fword for char that was deleted,
182 				// valid when "ts_flags" has TSF_DIDDEL
183 } trystate_T;
184 
185 // values for ts_isdiff
186 #define DIFF_NONE	0	// no different byte (yet)
187 #define DIFF_YES	1	// different byte found
188 #define DIFF_INSERT	2	// inserting character
189 
190 // values for ts_flags
191 #define TSF_PREFIXOK	1	// already checked that prefix is OK
192 #define TSF_DIDSPLIT	2	// tried split at this point
193 #define TSF_DIDDEL	4	// did a delete, "ts_delidx" has index
194 
195 // special values ts_prefixdepth
196 #define PFD_NOPREFIX	0xff	// not using prefixes
197 #define PFD_PREFIXTREE	0xfe	// walking through the prefix tree
198 #define PFD_NOTSPECIAL	0xfd	// highest value that's not special
199 
200 static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int maxcount, int banbadword, int need_cap, int interactive);
201 #ifdef FEAT_EVAL
202 static void spell_suggest_expr(suginfo_T *su, char_u *expr);
203 #endif
204 static void spell_suggest_file(suginfo_T *su, char_u *fname);
205 static void spell_suggest_intern(suginfo_T *su, int interactive);
206 static void spell_find_cleanup(suginfo_T *su);
207 static void suggest_try_special(suginfo_T *su);
208 static void suggest_try_change(suginfo_T *su);
209 static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, int soundfold);
210 static void go_deeper(trystate_T *stack, int depth, int score_add);
211 static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword);
212 static void score_comp_sal(suginfo_T *su);
213 static void score_combine(suginfo_T *su);
214 static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u *badsound);
215 static void suggest_try_soundalike_prep(void);
216 static void suggest_try_soundalike(suginfo_T *su);
217 static void suggest_try_soundalike_finish(void);
218 static void add_sound_suggest(suginfo_T *su, char_u *goodword, int score, langp_T *lp);
219 static int soundfold_find(slang_T *slang, char_u *word);
220 static int similar_chars(slang_T *slang, int c1, int c2);
221 static void add_suggestion(suginfo_T *su, garray_T *gap, char_u *goodword, int badlen, int score, int altscore, int had_bonus, slang_T *slang, int maxsf);
222 static void check_suggestions(suginfo_T *su, garray_T *gap);
223 static void add_banned(suginfo_T *su, char_u *word);
224 static void rescore_suggestions(suginfo_T *su);
225 static void rescore_one(suginfo_T *su, suggest_T *stp);
226 static int cleanup_suggestions(garray_T *gap, int maxscore, int keep);
227 static int soundalike_score(char_u *goodsound, char_u *badsound);
228 static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword);
229 static int spell_edit_score_limit(slang_T *slang, char_u *badword, char_u *goodword, int limit);
230 static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goodword, int limit);
231 
232 /*
233  * Return TRUE when the sequence of flags in "compflags" plus "flag" can
234  * possibly form a valid compounded word.  This also checks the COMPOUNDRULE
235  * lines if they don't contain wildcards.
236  */
237     static int
238 can_be_compound(
239     trystate_T	*sp,
240     slang_T	*slang,
241     char_u	*compflags,
242     int		flag)
243 {
244     // If the flag doesn't appear in sl_compstartflags or sl_compallflags
245     // then it can't possibly compound.
246     if (!byte_in_str(sp->ts_complen == sp->ts_compsplit
247 		? slang->sl_compstartflags : slang->sl_compallflags, flag))
248 	return FALSE;
249 
250     // If there are no wildcards, we can check if the flags collected so far
251     // possibly can form a match with COMPOUNDRULE patterns.  This only
252     // makes sense when we have two or more words.
253     if (slang->sl_comprules != NULL && sp->ts_complen > sp->ts_compsplit)
254     {
255 	int v;
256 
257 	compflags[sp->ts_complen] = flag;
258 	compflags[sp->ts_complen + 1] = NUL;
259 	v = match_compoundrule(slang, compflags + sp->ts_compsplit);
260 	compflags[sp->ts_complen] = NUL;
261 	return v;
262     }
263 
264     return TRUE;
265 }
266 
267 /*
268  * Adjust the score of common words.
269  */
270     static int
271 score_wordcount_adj(
272     slang_T	*slang,
273     int		score,
274     char_u	*word,
275     int		split)	    // word was split, less bonus
276 {
277     hashitem_T	*hi;
278     wordcount_T	*wc;
279     int		bonus;
280     int		newscore;
281 
282     hi = hash_find(&slang->sl_wordcount, word);
283     if (!HASHITEM_EMPTY(hi))
284     {
285 	wc = HI2WC(hi);
286 	if (wc->wc_count < SCORE_THRES2)
287 	    bonus = SCORE_COMMON1;
288 	else if (wc->wc_count < SCORE_THRES3)
289 	    bonus = SCORE_COMMON2;
290 	else
291 	    bonus = SCORE_COMMON3;
292 	if (split)
293 	    newscore = score - bonus / 2;
294 	else
295 	    newscore = score - bonus;
296 	if (newscore < 0)
297 	    return 0;
298 	return newscore;
299     }
300     return score;
301 }
302 
303 /*
304  * Like captype() but for a KEEPCAP word add ONECAP if the word starts with a
305  * capital.  So that make_case_word() can turn WOrd into Word.
306  * Add ALLCAP for "WOrD".
307  */
308     static int
309 badword_captype(char_u *word, char_u *end)
310 {
311     int		flags = captype(word, end);
312     int		c;
313     int		l, u;
314     int		first;
315     char_u	*p;
316 
317     if (flags & WF_KEEPCAP)
318     {
319 	// Count the number of UPPER and lower case letters.
320 	l = u = 0;
321 	first = FALSE;
322 	for (p = word; p < end; MB_PTR_ADV(p))
323 	{
324 	    c = PTR2CHAR(p);
325 	    if (SPELL_ISUPPER(c))
326 	    {
327 		++u;
328 		if (p == word)
329 		    first = TRUE;
330 	    }
331 	    else
332 		++l;
333 	}
334 
335 	// If there are more UPPER than lower case letters suggest an
336 	// ALLCAP word.  Otherwise, if the first letter is UPPER then
337 	// suggest ONECAP.  Exception: "ALl" most likely should be "All",
338 	// require three upper case letters.
339 	if (u > l && u > 2)
340 	    flags |= WF_ALLCAP;
341 	else if (first)
342 	    flags |= WF_ONECAP;
343 
344 	if (u >= 2 && l >= 2)	// maCARONI maCAroni
345 	    flags |= WF_MIXCAP;
346     }
347     return flags;
348 }
349 
350 /*
351  * Opposite of offset2bytes().
352  * "pp" points to the bytes and is advanced over it.
353  * Returns the offset.
354  */
355     static int
356 bytes2offset(char_u **pp)
357 {
358     char_u	*p = *pp;
359     int		nr;
360     int		c;
361 
362     c = *p++;
363     if ((c & 0x80) == 0x00)		// 1 byte
364     {
365 	nr = c - 1;
366     }
367     else if ((c & 0xc0) == 0x80)	// 2 bytes
368     {
369 	nr = (c & 0x3f) - 1;
370 	nr = nr * 255 + (*p++ - 1);
371     }
372     else if ((c & 0xe0) == 0xc0)	// 3 bytes
373     {
374 	nr = (c & 0x1f) - 1;
375 	nr = nr * 255 + (*p++ - 1);
376 	nr = nr * 255 + (*p++ - 1);
377     }
378     else				// 4 bytes
379     {
380 	nr = (c & 0x0f) - 1;
381 	nr = nr * 255 + (*p++ - 1);
382 	nr = nr * 255 + (*p++ - 1);
383 	nr = nr * 255 + (*p++ - 1);
384     }
385 
386     *pp = p;
387     return nr;
388 }
389 
390 // values for sps_flags
391 #define SPS_BEST    1
392 #define SPS_FAST    2
393 #define SPS_DOUBLE  4
394 
395 static int sps_flags = SPS_BEST;	// flags from 'spellsuggest'
396 static int sps_limit = 9999;		// max nr of suggestions given
397 
398 /*
399  * Check the 'spellsuggest' option.  Return FAIL if it's wrong.
400  * Sets "sps_flags" and "sps_limit".
401  */
402     int
403 spell_check_sps(void)
404 {
405     char_u	*p;
406     char_u	*s;
407     char_u	buf[MAXPATHL];
408     int		f;
409 
410     sps_flags = 0;
411     sps_limit = 9999;
412 
413     for (p = p_sps; *p != NUL; )
414     {
415 	copy_option_part(&p, buf, MAXPATHL, ",");
416 
417 	f = 0;
418 	if (VIM_ISDIGIT(*buf))
419 	{
420 	    s = buf;
421 	    sps_limit = getdigits(&s);
422 	    if (*s != NUL && !VIM_ISDIGIT(*s))
423 		f = -1;
424 	}
425 	else if (STRCMP(buf, "best") == 0)
426 	    f = SPS_BEST;
427 	else if (STRCMP(buf, "fast") == 0)
428 	    f = SPS_FAST;
429 	else if (STRCMP(buf, "double") == 0)
430 	    f = SPS_DOUBLE;
431 	else if (STRNCMP(buf, "expr:", 5) != 0
432 		&& STRNCMP(buf, "file:", 5) != 0)
433 	    f = -1;
434 
435 	if (f == -1 || (sps_flags != 0 && f != 0))
436 	{
437 	    sps_flags = SPS_BEST;
438 	    sps_limit = 9999;
439 	    return FAIL;
440 	}
441 	if (f != 0)
442 	    sps_flags = f;
443     }
444 
445     if (sps_flags == 0)
446 	sps_flags = SPS_BEST;
447 
448     return OK;
449 }
450 
451 /*
452  * "z=": Find badly spelled word under or after the cursor.
453  * Give suggestions for the properly spelled word.
454  * In Visual mode use the highlighted word as the bad word.
455  * When "count" is non-zero use that suggestion.
456  */
457     void
458 spell_suggest(int count)
459 {
460     char_u	*line;
461     pos_T	prev_cursor = curwin->w_cursor;
462     char_u	wcopy[MAXWLEN + 2];
463     char_u	*p;
464     int		i;
465     int		c;
466     suginfo_T	sug;
467     suggest_T	*stp;
468     int		mouse_used;
469     int		need_cap;
470     int		limit;
471     int		selected = count;
472     int		badlen = 0;
473     int		msg_scroll_save = msg_scroll;
474 
475     if (no_spell_checking(curwin))
476 	return;
477 
478     if (VIsual_active)
479     {
480 	// Use the Visually selected text as the bad word.  But reject
481 	// a multi-line selection.
482 	if (curwin->w_cursor.lnum != VIsual.lnum)
483 	{
484 	    vim_beep(BO_SPELL);
485 	    return;
486 	}
487 	badlen = (int)curwin->w_cursor.col - (int)VIsual.col;
488 	if (badlen < 0)
489 	    badlen = -badlen;
490 	else
491 	    curwin->w_cursor.col = VIsual.col;
492 	++badlen;
493 	end_visual_mode();
494     }
495     // Find the start of the badly spelled word.
496     else if (spell_move_to(curwin, FORWARD, TRUE, TRUE, NULL) == 0
497 	    || curwin->w_cursor.col > prev_cursor.col)
498     {
499 	// No bad word or it starts after the cursor: use the word under the
500 	// cursor.
501 	curwin->w_cursor = prev_cursor;
502 	line = ml_get_curline();
503 	p = line + curwin->w_cursor.col;
504 	// Backup to before start of word.
505 	while (p > line && spell_iswordp_nmw(p, curwin))
506 	    MB_PTR_BACK(line, p);
507 	// Forward to start of word.
508 	while (*p != NUL && !spell_iswordp_nmw(p, curwin))
509 	    MB_PTR_ADV(p);
510 
511 	if (!spell_iswordp_nmw(p, curwin))		// No word found.
512 	{
513 	    beep_flush();
514 	    return;
515 	}
516 	curwin->w_cursor.col = (colnr_T)(p - line);
517     }
518 
519     // Get the word and its length.
520 
521     // Figure out if the word should be capitalised.
522     need_cap = check_need_cap(curwin->w_cursor.lnum, curwin->w_cursor.col);
523 
524     // Make a copy of current line since autocommands may free the line.
525     line = vim_strsave(ml_get_curline());
526     if (line == NULL)
527 	goto skip;
528 
529     // Get the list of suggestions.  Limit to 'lines' - 2 or the number in
530     // 'spellsuggest', whatever is smaller.
531     if (sps_limit > (int)Rows - 2)
532 	limit = (int)Rows - 2;
533     else
534 	limit = sps_limit;
535     spell_find_suggest(line + curwin->w_cursor.col, badlen, &sug, limit,
536 							TRUE, need_cap, TRUE);
537 
538     if (sug.su_ga.ga_len == 0)
539 	msg(_("Sorry, no suggestions"));
540     else if (count > 0)
541     {
542 	if (count > sug.su_ga.ga_len)
543 	    smsg(_("Sorry, only %ld suggestions"), (long)sug.su_ga.ga_len);
544     }
545     else
546     {
547 #ifdef FEAT_RIGHTLEFT
548 	// When 'rightleft' is set the list is drawn right-left.
549 	cmdmsg_rl = curwin->w_p_rl;
550 	if (cmdmsg_rl)
551 	    msg_col = Columns - 1;
552 #endif
553 
554 	// List the suggestions.
555 	msg_start();
556 	msg_row = Rows - 1;	// for when 'cmdheight' > 1
557 	lines_left = Rows;	// avoid more prompt
558 	vim_snprintf((char *)IObuff, IOSIZE, _("Change \"%.*s\" to:"),
559 						sug.su_badlen, sug.su_badptr);
560 #ifdef FEAT_RIGHTLEFT
561 	if (cmdmsg_rl && STRNCMP(IObuff, "Change", 6) == 0)
562 	{
563 	    // And now the rabbit from the high hat: Avoid showing the
564 	    // untranslated message rightleft.
565 	    vim_snprintf((char *)IObuff, IOSIZE, ":ot \"%.*s\" egnahC",
566 						sug.su_badlen, sug.su_badptr);
567 	}
568 #endif
569 	msg_puts((char *)IObuff);
570 	msg_clr_eos();
571 	msg_putchar('\n');
572 
573 	msg_scroll = TRUE;
574 	for (i = 0; i < sug.su_ga.ga_len; ++i)
575 	{
576 	    stp = &SUG(sug.su_ga, i);
577 
578 	    // The suggested word may replace only part of the bad word, add
579 	    // the not replaced part.
580 	    vim_strncpy(wcopy, stp->st_word, MAXWLEN);
581 	    if (sug.su_badlen > stp->st_orglen)
582 		vim_strncpy(wcopy + stp->st_wordlen,
583 					       sug.su_badptr + stp->st_orglen,
584 					      sug.su_badlen - stp->st_orglen);
585 	    vim_snprintf((char *)IObuff, IOSIZE, "%2d", i + 1);
586 #ifdef FEAT_RIGHTLEFT
587 	    if (cmdmsg_rl)
588 		rl_mirror(IObuff);
589 #endif
590 	    msg_puts((char *)IObuff);
591 
592 	    vim_snprintf((char *)IObuff, IOSIZE, " \"%s\"", wcopy);
593 	    msg_puts((char *)IObuff);
594 
595 	    // The word may replace more than "su_badlen".
596 	    if (sug.su_badlen < stp->st_orglen)
597 	    {
598 		vim_snprintf((char *)IObuff, IOSIZE, _(" < \"%.*s\""),
599 					       stp->st_orglen, sug.su_badptr);
600 		msg_puts((char *)IObuff);
601 	    }
602 
603 	    if (p_verbose > 0)
604 	    {
605 		// Add the score.
606 		if (sps_flags & (SPS_DOUBLE | SPS_BEST))
607 		    vim_snprintf((char *)IObuff, IOSIZE, " (%s%d - %d)",
608 			stp->st_salscore ? "s " : "",
609 			stp->st_score, stp->st_altscore);
610 		else
611 		    vim_snprintf((char *)IObuff, IOSIZE, " (%d)",
612 			    stp->st_score);
613 #ifdef FEAT_RIGHTLEFT
614 		if (cmdmsg_rl)
615 		    // Mirror the numbers, but keep the leading space.
616 		    rl_mirror(IObuff + 1);
617 #endif
618 		msg_advance(30);
619 		msg_puts((char *)IObuff);
620 	    }
621 	    msg_putchar('\n');
622 	}
623 
624 #ifdef FEAT_RIGHTLEFT
625 	cmdmsg_rl = FALSE;
626 	msg_col = 0;
627 #endif
628 	// Ask for choice.
629 	selected = prompt_for_number(&mouse_used);
630 	if (mouse_used)
631 	    selected -= lines_left;
632 	lines_left = Rows;		// avoid more prompt
633 	// don't delay for 'smd' in normal_cmd()
634 	msg_scroll = msg_scroll_save;
635     }
636 
637     if (selected > 0 && selected <= sug.su_ga.ga_len && u_save_cursor() == OK)
638     {
639 	// Save the from and to text for :spellrepall.
640 	VIM_CLEAR(repl_from);
641 	VIM_CLEAR(repl_to);
642 
643 	stp = &SUG(sug.su_ga, selected - 1);
644 	if (sug.su_badlen > stp->st_orglen)
645 	{
646 	    // Replacing less than "su_badlen", append the remainder to
647 	    // repl_to.
648 	    repl_from = vim_strnsave(sug.su_badptr, sug.su_badlen);
649 	    vim_snprintf((char *)IObuff, IOSIZE, "%s%.*s", stp->st_word,
650 		    sug.su_badlen - stp->st_orglen,
651 					      sug.su_badptr + stp->st_orglen);
652 	    repl_to = vim_strsave(IObuff);
653 	}
654 	else
655 	{
656 	    // Replacing su_badlen or more, use the whole word.
657 	    repl_from = vim_strnsave(sug.su_badptr, stp->st_orglen);
658 	    repl_to = vim_strsave(stp->st_word);
659 	}
660 
661 	// Replace the word.
662 	p = alloc(STRLEN(line) - stp->st_orglen + stp->st_wordlen + 1);
663 	if (p != NULL)
664 	{
665 	    c = (int)(sug.su_badptr - line);
666 	    mch_memmove(p, line, c);
667 	    STRCPY(p + c, stp->st_word);
668 	    STRCAT(p, sug.su_badptr + stp->st_orglen);
669 	    ml_replace(curwin->w_cursor.lnum, p, FALSE);
670 	    curwin->w_cursor.col = c;
671 
672 	    // For redo we use a change-word command.
673 	    ResetRedobuff();
674 	    AppendToRedobuff((char_u *)"ciw");
675 	    AppendToRedobuffLit(p + c,
676 			    stp->st_wordlen + sug.su_badlen - stp->st_orglen);
677 	    AppendCharToRedobuff(ESC);
678 
679 	    // After this "p" may be invalid.
680 	    changed_bytes(curwin->w_cursor.lnum, c);
681 	}
682     }
683     else
684 	curwin->w_cursor = prev_cursor;
685 
686     spell_find_cleanup(&sug);
687 skip:
688     vim_free(line);
689 }
690 
691 /*
692  * Find spell suggestions for "word".  Return them in the growarray "*gap" as
693  * a list of allocated strings.
694  */
695     void
696 spell_suggest_list(
697     garray_T	*gap,
698     char_u	*word,
699     int		maxcount,	// maximum nr of suggestions
700     int		need_cap,	// 'spellcapcheck' matched
701     int		interactive)
702 {
703     suginfo_T	sug;
704     int		i;
705     suggest_T	*stp;
706     char_u	*wcopy;
707 
708     spell_find_suggest(word, 0, &sug, maxcount, FALSE, need_cap, interactive);
709 
710     // Make room in "gap".
711     ga_init2(gap, sizeof(char_u *), sug.su_ga.ga_len + 1);
712     if (ga_grow(gap, sug.su_ga.ga_len) == OK)
713     {
714 	for (i = 0; i < sug.su_ga.ga_len; ++i)
715 	{
716 	    stp = &SUG(sug.su_ga, i);
717 
718 	    // The suggested word may replace only part of "word", add the not
719 	    // replaced part.
720 	    wcopy = alloc(stp->st_wordlen
721 		      + (unsigned)STRLEN(sug.su_badptr + stp->st_orglen) + 1);
722 	    if (wcopy == NULL)
723 		break;
724 	    STRCPY(wcopy, stp->st_word);
725 	    STRCPY(wcopy + stp->st_wordlen, sug.su_badptr + stp->st_orglen);
726 	    ((char_u **)gap->ga_data)[gap->ga_len++] = wcopy;
727 	}
728     }
729 
730     spell_find_cleanup(&sug);
731 }
732 
733 /*
734  * Find spell suggestions for the word at the start of "badptr".
735  * Return the suggestions in "su->su_ga".
736  * The maximum number of suggestions is "maxcount".
737  * Note: does use info for the current window.
738  * This is based on the mechanisms of Aspell, but completely reimplemented.
739  */
740     static void
741 spell_find_suggest(
742     char_u	*badptr,
743     int		badlen,		// length of bad word or 0 if unknown
744     suginfo_T	*su,
745     int		maxcount,
746     int		banbadword,	// don't include badword in suggestions
747     int		need_cap,	// word should start with capital
748     int		interactive)
749 {
750     hlf_T	attr = HLF_COUNT;
751     char_u	buf[MAXPATHL];
752     char_u	*p;
753     int		do_combine = FALSE;
754     char_u	*sps_copy;
755 #ifdef FEAT_EVAL
756     static int	expr_busy = FALSE;
757 #endif
758     int		c;
759     int		i;
760     langp_T	*lp;
761 
762     // Set the info in "*su".
763     CLEAR_POINTER(su);
764     ga_init2(&su->su_ga, (int)sizeof(suggest_T), 10);
765     ga_init2(&su->su_sga, (int)sizeof(suggest_T), 10);
766     if (*badptr == NUL)
767 	return;
768     hash_init(&su->su_banned);
769 
770     su->su_badptr = badptr;
771     if (badlen != 0)
772 	su->su_badlen = badlen;
773     else
774 	su->su_badlen = spell_check(curwin, su->su_badptr, &attr, NULL, FALSE);
775     su->su_maxcount = maxcount;
776     su->su_maxscore = SCORE_MAXINIT;
777 
778     if (su->su_badlen >= MAXWLEN)
779 	su->su_badlen = MAXWLEN - 1;	// just in case
780     vim_strncpy(su->su_badword, su->su_badptr, su->su_badlen);
781     (void)spell_casefold(su->su_badptr, su->su_badlen,
782 						    su->su_fbadword, MAXWLEN);
783     // TODO: make this work if the case-folded text is longer than the original
784     // text. Currently an illegal byte causes wrong pointer computations.
785     su->su_fbadword[su->su_badlen] = NUL;
786 
787     // get caps flags for bad word
788     su->su_badflags = badword_captype(su->su_badptr,
789 					       su->su_badptr + su->su_badlen);
790     if (need_cap)
791 	su->su_badflags |= WF_ONECAP;
792 
793     // Find the default language for sound folding.  We simply use the first
794     // one in 'spelllang' that supports sound folding.  That's good for when
795     // using multiple files for one language, it's not that bad when mixing
796     // languages (e.g., "pl,en").
797     for (i = 0; i < curbuf->b_s.b_langp.ga_len; ++i)
798     {
799 	lp = LANGP_ENTRY(curbuf->b_s.b_langp, i);
800 	if (lp->lp_sallang != NULL)
801 	{
802 	    su->su_sallang = lp->lp_sallang;
803 	    break;
804 	}
805     }
806 
807     // Soundfold the bad word with the default sound folding, so that we don't
808     // have to do this many times.
809     if (su->su_sallang != NULL)
810 	spell_soundfold(su->su_sallang, su->su_fbadword, TRUE,
811 							  su->su_sal_badword);
812 
813     // If the word is not capitalised and spell_check() doesn't consider the
814     // word to be bad then it might need to be capitalised.  Add a suggestion
815     // for that.
816     c = PTR2CHAR(su->su_badptr);
817     if (!SPELL_ISUPPER(c) && attr == HLF_COUNT)
818     {
819 	make_case_word(su->su_badword, buf, WF_ONECAP);
820 	add_suggestion(su, &su->su_ga, buf, su->su_badlen, SCORE_ICASE,
821 					      0, TRUE, su->su_sallang, FALSE);
822     }
823 
824     // Ban the bad word itself.  It may appear in another region.
825     if (banbadword)
826 	add_banned(su, su->su_badword);
827 
828     // Make a copy of 'spellsuggest', because the expression may change it.
829     sps_copy = vim_strsave(p_sps);
830     if (sps_copy == NULL)
831 	return;
832 
833     // Loop over the items in 'spellsuggest'.
834     for (p = sps_copy; *p != NUL; )
835     {
836 	copy_option_part(&p, buf, MAXPATHL, ",");
837 
838 	if (STRNCMP(buf, "expr:", 5) == 0)
839 	{
840 #ifdef FEAT_EVAL
841 	    // Evaluate an expression.  Skip this when called recursively,
842 	    // when using spellsuggest() in the expression.
843 	    if (!expr_busy)
844 	    {
845 		expr_busy = TRUE;
846 		spell_suggest_expr(su, buf + 5);
847 		expr_busy = FALSE;
848 	    }
849 #endif
850 	}
851 	else if (STRNCMP(buf, "file:", 5) == 0)
852 	    // Use list of suggestions in a file.
853 	    spell_suggest_file(su, buf + 5);
854 	else
855 	{
856 	    // Use internal method.
857 	    spell_suggest_intern(su, interactive);
858 	    if (sps_flags & SPS_DOUBLE)
859 		do_combine = TRUE;
860 	}
861     }
862 
863     vim_free(sps_copy);
864 
865     if (do_combine)
866 	// Combine the two list of suggestions.  This must be done last,
867 	// because sorting changes the order again.
868 	score_combine(su);
869 }
870 
871 #ifdef FEAT_EVAL
872 /*
873  * Find suggestions by evaluating expression "expr".
874  */
875     static void
876 spell_suggest_expr(suginfo_T *su, char_u *expr)
877 {
878     list_T	*list;
879     listitem_T	*li;
880     int		score;
881     char_u	*p;
882 
883     // The work is split up in a few parts to avoid having to export
884     // suginfo_T.
885     // First evaluate the expression and get the resulting list.
886     list = eval_spell_expr(su->su_badword, expr);
887     if (list != NULL)
888     {
889 	// Loop over the items in the list.
890 	FOR_ALL_LIST_ITEMS(list, li)
891 	    if (li->li_tv.v_type == VAR_LIST)
892 	    {
893 		// Get the word and the score from the items.
894 		score = get_spellword(li->li_tv.vval.v_list, &p);
895 		if (score >= 0 && score <= su->su_maxscore)
896 		    add_suggestion(su, &su->su_ga, p, su->su_badlen,
897 				       score, 0, TRUE, su->su_sallang, FALSE);
898 	    }
899 	list_unref(list);
900     }
901 
902     // Remove bogus suggestions, sort and truncate at "maxcount".
903     check_suggestions(su, &su->su_ga);
904     (void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
905 }
906 #endif
907 
908 /*
909  * Find suggestions in file "fname".  Used for "file:" in 'spellsuggest'.
910  */
911     static void
912 spell_suggest_file(suginfo_T *su, char_u *fname)
913 {
914     FILE	*fd;
915     char_u	line[MAXWLEN * 2];
916     char_u	*p;
917     int		len;
918     char_u	cword[MAXWLEN];
919 
920     // Open the file.
921     fd = mch_fopen((char *)fname, "r");
922     if (fd == NULL)
923     {
924 	semsg(_(e_notopen), fname);
925 	return;
926     }
927 
928     // Read it line by line.
929     while (!vim_fgets(line, MAXWLEN * 2, fd) && !got_int)
930     {
931 	line_breakcheck();
932 
933 	p = vim_strchr(line, '/');
934 	if (p == NULL)
935 	    continue;	    // No Tab found, just skip the line.
936 	*p++ = NUL;
937 	if (STRICMP(su->su_badword, line) == 0)
938 	{
939 	    // Match!  Isolate the good word, until CR or NL.
940 	    for (len = 0; p[len] >= ' '; ++len)
941 		;
942 	    p[len] = NUL;
943 
944 	    // If the suggestion doesn't have specific case duplicate the case
945 	    // of the bad word.
946 	    if (captype(p, NULL) == 0)
947 	    {
948 		make_case_word(p, cword, su->su_badflags);
949 		p = cword;
950 	    }
951 
952 	    add_suggestion(su, &su->su_ga, p, su->su_badlen,
953 				  SCORE_FILE, 0, TRUE, su->su_sallang, FALSE);
954 	}
955     }
956 
957     fclose(fd);
958 
959     // Remove bogus suggestions, sort and truncate at "maxcount".
960     check_suggestions(su, &su->su_ga);
961     (void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
962 }
963 
964 /*
965  * Find suggestions for the internal method indicated by "sps_flags".
966  */
967     static void
968 spell_suggest_intern(suginfo_T *su, int interactive)
969 {
970     // Load the .sug file(s) that are available and not done yet.
971     suggest_load_files();
972 
973     // 1. Try special cases, such as repeating a word: "the the" -> "the".
974     //
975     // Set a maximum score to limit the combination of operations that is
976     // tried.
977     suggest_try_special(su);
978 
979     // 2. Try inserting/deleting/swapping/changing a letter, use REP entries
980     //    from the .aff file and inserting a space (split the word).
981     suggest_try_change(su);
982 
983     // For the resulting top-scorers compute the sound-a-like score.
984     if (sps_flags & SPS_DOUBLE)
985 	score_comp_sal(su);
986 
987     // 3. Try finding sound-a-like words.
988     if ((sps_flags & SPS_FAST) == 0)
989     {
990 	if (sps_flags & SPS_BEST)
991 	    // Adjust the word score for the suggestions found so far for how
992 	    // they sound like.
993 	    rescore_suggestions(su);
994 
995 	// While going through the soundfold tree "su_maxscore" is the score
996 	// for the soundfold word, limits the changes that are being tried,
997 	// and "su_sfmaxscore" the rescored score, which is set by
998 	// cleanup_suggestions().
999 	// First find words with a small edit distance, because this is much
1000 	// faster and often already finds the top-N suggestions.  If we didn't
1001 	// find many suggestions try again with a higher edit distance.
1002 	// "sl_sounddone" is used to avoid doing the same word twice.
1003 	suggest_try_soundalike_prep();
1004 	su->su_maxscore = SCORE_SFMAX1;
1005 	su->su_sfmaxscore = SCORE_MAXINIT * 3;
1006 	suggest_try_soundalike(su);
1007 	if (su->su_ga.ga_len < SUG_CLEAN_COUNT(su))
1008 	{
1009 	    // We didn't find enough matches, try again, allowing more
1010 	    // changes to the soundfold word.
1011 	    su->su_maxscore = SCORE_SFMAX2;
1012 	    suggest_try_soundalike(su);
1013 	    if (su->su_ga.ga_len < SUG_CLEAN_COUNT(su))
1014 	    {
1015 		// Still didn't find enough matches, try again, allowing even
1016 		// more changes to the soundfold word.
1017 		su->su_maxscore = SCORE_SFMAX3;
1018 		suggest_try_soundalike(su);
1019 	    }
1020 	}
1021 	su->su_maxscore = su->su_sfmaxscore;
1022 	suggest_try_soundalike_finish();
1023     }
1024 
1025     // When CTRL-C was hit while searching do show the results.  Only clear
1026     // got_int when using a command, not for spellsuggest().
1027     ui_breakcheck();
1028     if (interactive && got_int)
1029     {
1030 	(void)vgetc();
1031 	got_int = FALSE;
1032     }
1033 
1034     if ((sps_flags & SPS_DOUBLE) == 0 && su->su_ga.ga_len != 0)
1035     {
1036 	if (sps_flags & SPS_BEST)
1037 	    // Adjust the word score for how it sounds like.
1038 	    rescore_suggestions(su);
1039 
1040 	// Remove bogus suggestions, sort and truncate at "maxcount".
1041 	check_suggestions(su, &su->su_ga);
1042 	(void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
1043     }
1044 }
1045 
1046 /*
1047  * Free the info put in "*su" by spell_find_suggest().
1048  */
1049     static void
1050 spell_find_cleanup(suginfo_T *su)
1051 {
1052     int		i;
1053 
1054     // Free the suggestions.
1055     for (i = 0; i < su->su_ga.ga_len; ++i)
1056 	vim_free(SUG(su->su_ga, i).st_word);
1057     ga_clear(&su->su_ga);
1058     for (i = 0; i < su->su_sga.ga_len; ++i)
1059 	vim_free(SUG(su->su_sga, i).st_word);
1060     ga_clear(&su->su_sga);
1061 
1062     // Free the banned words.
1063     hash_clear_all(&su->su_banned, 0);
1064 }
1065 
1066 /*
1067  * Try finding suggestions by recognizing specific situations.
1068  */
1069     static void
1070 suggest_try_special(suginfo_T *su)
1071 {
1072     char_u	*p;
1073     size_t	len;
1074     int		c;
1075     char_u	word[MAXWLEN];
1076 
1077     // Recognize a word that is repeated: "the the".
1078     p = skiptowhite(su->su_fbadword);
1079     len = p - su->su_fbadword;
1080     p = skipwhite(p);
1081     if (STRLEN(p) == len && STRNCMP(su->su_fbadword, p, len) == 0)
1082     {
1083 	// Include badflags: if the badword is onecap or allcap
1084 	// use that for the goodword too: "The the" -> "The".
1085 	c = su->su_fbadword[len];
1086 	su->su_fbadword[len] = NUL;
1087 	make_case_word(su->su_fbadword, word, su->su_badflags);
1088 	su->su_fbadword[len] = c;
1089 
1090 	// Give a soundalike score of 0, compute the score as if deleting one
1091 	// character.
1092 	add_suggestion(su, &su->su_ga, word, su->su_badlen,
1093 		       RESCORE(SCORE_REP, 0), 0, TRUE, su->su_sallang, FALSE);
1094     }
1095 }
1096 
1097 /*
1098  * Change the 0 to 1 to measure how much time is spent in each state.
1099  * Output is dumped in "suggestprof".
1100  */
1101 #if 0
1102 # define SUGGEST_PROFILE
1103 proftime_T current;
1104 proftime_T total;
1105 proftime_T times[STATE_FINAL + 1];
1106 long counts[STATE_FINAL + 1];
1107 
1108     static void
1109 prof_init(void)
1110 {
1111     for (int i = 0; i <= STATE_FINAL; ++i)
1112     {
1113 	profile_zero(&times[i]);
1114 	counts[i] = 0;
1115     }
1116     profile_start(&current);
1117     profile_start(&total);
1118 }
1119 
1120 // call before changing state
1121     static void
1122 prof_store(state_T state)
1123 {
1124     profile_end(&current);
1125     profile_add(&times[state], &current);
1126     ++counts[state];
1127     profile_start(&current);
1128 }
1129 # define PROF_STORE(state) prof_store(state);
1130 
1131     static void
1132 prof_report(char *name)
1133 {
1134     FILE *fd = fopen("suggestprof", "a");
1135 
1136     profile_end(&total);
1137     fprintf(fd, "-----------------------\n");
1138     fprintf(fd, "%s: %s\n", name, profile_msg(&total));
1139     for (int i = 0; i <= STATE_FINAL; ++i)
1140 	fprintf(fd, "%d: %s (%ld)\n", i, profile_msg(&times[i]), counts[i]);
1141     fclose(fd);
1142 }
1143 #else
1144 # define PROF_STORE(state)
1145 #endif
1146 
1147 /*
1148  * Try finding suggestions by adding/removing/swapping letters.
1149  */
1150     static void
1151 suggest_try_change(suginfo_T *su)
1152 {
1153     char_u	fword[MAXWLEN];	    // copy of the bad word, case-folded
1154     int		n;
1155     char_u	*p;
1156     int		lpi;
1157     langp_T	*lp;
1158 
1159     // We make a copy of the case-folded bad word, so that we can modify it
1160     // to find matches (esp. REP items).  Append some more text, changing
1161     // chars after the bad word may help.
1162     STRCPY(fword, su->su_fbadword);
1163     n = (int)STRLEN(fword);
1164     p = su->su_badptr + su->su_badlen;
1165     (void)spell_casefold(p, (int)STRLEN(p), fword + n, MAXWLEN - n);
1166 
1167     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
1168     {
1169 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
1170 
1171 	// If reloading a spell file fails it's still in the list but
1172 	// everything has been cleared.
1173 	if (lp->lp_slang->sl_fbyts == NULL)
1174 	    continue;
1175 
1176 	// Try it for this language.  Will add possible suggestions.
1177 #ifdef SUGGEST_PROFILE
1178 	prof_init();
1179 #endif
1180 	suggest_trie_walk(su, lp, fword, FALSE);
1181 #ifdef SUGGEST_PROFILE
1182 	prof_report("try_change");
1183 #endif
1184     }
1185 }
1186 
1187 // Check the maximum score, if we go over it we won't try this change.
1188 #define TRY_DEEPER(su, stack, depth, add) \
1189 		(stack[depth].ts_score + (add) < su->su_maxscore)
1190 
1191 /*
1192  * Try finding suggestions by adding/removing/swapping letters.
1193  *
1194  * This uses a state machine.  At each node in the tree we try various
1195  * operations.  When trying if an operation works "depth" is increased and the
1196  * stack[] is used to store info.  This allows combinations, thus insert one
1197  * character, replace one and delete another.  The number of changes is
1198  * limited by su->su_maxscore.
1199  *
1200  * After implementing this I noticed an article by Kemal Oflazer that
1201  * describes something similar: "Error-tolerant Finite State Recognition with
1202  * Applications to Morphological Analysis and Spelling Correction" (1996).
1203  * The implementation in the article is simplified and requires a stack of
1204  * unknown depth.  The implementation here only needs a stack depth equal to
1205  * the length of the word.
1206  *
1207  * This is also used for the sound-folded word, "soundfold" is TRUE then.
1208  * The mechanism is the same, but we find a match with a sound-folded word
1209  * that comes from one or more original words.  Each of these words may be
1210  * added, this is done by add_sound_suggest().
1211  * Don't use:
1212  *	the prefix tree or the keep-case tree
1213  *	"su->su_badlen"
1214  *	anything to do with upper and lower case
1215  *	anything to do with word or non-word characters ("spell_iswordp()")
1216  *	banned words
1217  *	word flags (rare, region, compounding)
1218  *	word splitting for now
1219  *	"similar_chars()"
1220  *	use "slang->sl_repsal" instead of "lp->lp_replang->sl_rep"
1221  */
1222     static void
1223 suggest_trie_walk(
1224     suginfo_T	*su,
1225     langp_T	*lp,
1226     char_u	*fword,
1227     int		soundfold)
1228 {
1229     char_u	tword[MAXWLEN];	    // good word collected so far
1230     trystate_T	stack[MAXWLEN];
1231     char_u	preword[MAXWLEN * 3]; // word found with proper case;
1232 				      // concatenation of prefix compound
1233 				      // words and split word.  NUL terminated
1234 				      // when going deeper but not when coming
1235 				      // back.
1236     char_u	compflags[MAXWLEN];	// compound flags, one for each word
1237     trystate_T	*sp;
1238     int		newscore;
1239     int		score;
1240     char_u	*byts, *fbyts, *pbyts;
1241     idx_T	*idxs, *fidxs, *pidxs;
1242     int		depth;
1243     int		c, c2, c3;
1244     int		n = 0;
1245     int		flags;
1246     garray_T	*gap;
1247     idx_T	arridx;
1248     int		len;
1249     char_u	*p;
1250     fromto_T	*ftp;
1251     int		fl = 0, tl;
1252     int		repextra = 0;	    // extra bytes in fword[] from REP item
1253     slang_T	*slang = lp->lp_slang;
1254     int		fword_ends;
1255     int		goodword_ends;
1256 #ifdef DEBUG_TRIEWALK
1257     // Stores the name of the change made at each level.
1258     char_u	changename[MAXWLEN][80];
1259 #endif
1260     int		breakcheckcount = 1000;
1261     int		compound_ok;
1262 
1263     // Go through the whole case-fold tree, try changes at each node.
1264     // "tword[]" contains the word collected from nodes in the tree.
1265     // "fword[]" the word we are trying to match with (initially the bad
1266     // word).
1267     depth = 0;
1268     sp = &stack[0];
1269     CLEAR_POINTER(sp);
1270     sp->ts_curi = 1;
1271 
1272     if (soundfold)
1273     {
1274 	// Going through the soundfold tree.
1275 	byts = fbyts = slang->sl_sbyts;
1276 	idxs = fidxs = slang->sl_sidxs;
1277 	pbyts = NULL;
1278 	pidxs = NULL;
1279 	sp->ts_prefixdepth = PFD_NOPREFIX;
1280 	sp->ts_state = STATE_START;
1281     }
1282     else
1283     {
1284 	// When there are postponed prefixes we need to use these first.  At
1285 	// the end of the prefix we continue in the case-fold tree.
1286 	fbyts = slang->sl_fbyts;
1287 	fidxs = slang->sl_fidxs;
1288 	pbyts = slang->sl_pbyts;
1289 	pidxs = slang->sl_pidxs;
1290 	if (pbyts != NULL)
1291 	{
1292 	    byts = pbyts;
1293 	    idxs = pidxs;
1294 	    sp->ts_prefixdepth = PFD_PREFIXTREE;
1295 	    sp->ts_state = STATE_NOPREFIX;	// try without prefix first
1296 	}
1297 	else
1298 	{
1299 	    byts = fbyts;
1300 	    idxs = fidxs;
1301 	    sp->ts_prefixdepth = PFD_NOPREFIX;
1302 	    sp->ts_state = STATE_START;
1303 	}
1304     }
1305 
1306     // Loop to find all suggestions.  At each round we either:
1307     // - For the current state try one operation, advance "ts_curi",
1308     //   increase "depth".
1309     // - When a state is done go to the next, set "ts_state".
1310     // - When all states are tried decrease "depth".
1311     while (depth >= 0 && !got_int)
1312     {
1313 	sp = &stack[depth];
1314 	switch (sp->ts_state)
1315 	{
1316 	case STATE_START:
1317 	case STATE_NOPREFIX:
1318 	    // Start of node: Deal with NUL bytes, which means
1319 	    // tword[] may end here.
1320 	    arridx = sp->ts_arridx;	    // current node in the tree
1321 	    len = byts[arridx];		    // bytes in this node
1322 	    arridx += sp->ts_curi;	    // index of current byte
1323 
1324 	    if (sp->ts_prefixdepth == PFD_PREFIXTREE)
1325 	    {
1326 		// Skip over the NUL bytes, we use them later.
1327 		for (n = 0; n < len && byts[arridx + n] == 0; ++n)
1328 		    ;
1329 		sp->ts_curi += n;
1330 
1331 		// Always past NUL bytes now.
1332 		n = (int)sp->ts_state;
1333 		PROF_STORE(sp->ts_state)
1334 		sp->ts_state = STATE_ENDNUL;
1335 		sp->ts_save_badflags = su->su_badflags;
1336 
1337 		// At end of a prefix or at start of prefixtree: check for
1338 		// following word.
1339 		if (byts[arridx] == 0 || n == (int)STATE_NOPREFIX)
1340 		{
1341 		    // Set su->su_badflags to the caps type at this position.
1342 		    // Use the caps type until here for the prefix itself.
1343 		    if (has_mbyte)
1344 			n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
1345 		    else
1346 			n = sp->ts_fidx;
1347 		    flags = badword_captype(su->su_badptr, su->su_badptr + n);
1348 		    su->su_badflags = badword_captype(su->su_badptr + n,
1349 					       su->su_badptr + su->su_badlen);
1350 #ifdef DEBUG_TRIEWALK
1351 		    sprintf(changename[depth], "prefix");
1352 #endif
1353 		    go_deeper(stack, depth, 0);
1354 		    ++depth;
1355 		    sp = &stack[depth];
1356 		    sp->ts_prefixdepth = depth - 1;
1357 		    byts = fbyts;
1358 		    idxs = fidxs;
1359 		    sp->ts_arridx = 0;
1360 
1361 		    // Move the prefix to preword[] with the right case
1362 		    // and make find_keepcap_word() works.
1363 		    tword[sp->ts_twordlen] = NUL;
1364 		    make_case_word(tword + sp->ts_splitoff,
1365 					  preword + sp->ts_prewordlen, flags);
1366 		    sp->ts_prewordlen = (char_u)STRLEN(preword);
1367 		    sp->ts_splitoff = sp->ts_twordlen;
1368 		}
1369 		break;
1370 	    }
1371 
1372 	    if (sp->ts_curi > len || byts[arridx] != 0)
1373 	    {
1374 		// Past bytes in node and/or past NUL bytes.
1375 		PROF_STORE(sp->ts_state)
1376 		sp->ts_state = STATE_ENDNUL;
1377 		sp->ts_save_badflags = su->su_badflags;
1378 		break;
1379 	    }
1380 
1381 	    // End of word in tree.
1382 	    ++sp->ts_curi;		// eat one NUL byte
1383 
1384 	    flags = (int)idxs[arridx];
1385 
1386 	    // Skip words with the NOSUGGEST flag.
1387 	    if (flags & WF_NOSUGGEST)
1388 		break;
1389 
1390 	    fword_ends = (fword[sp->ts_fidx] == NUL
1391 			   || (soundfold
1392 			       ? VIM_ISWHITE(fword[sp->ts_fidx])
1393 			       : !spell_iswordp(fword + sp->ts_fidx, curwin)));
1394 	    tword[sp->ts_twordlen] = NUL;
1395 
1396 	    if (sp->ts_prefixdepth <= PFD_NOTSPECIAL
1397 					&& (sp->ts_flags & TSF_PREFIXOK) == 0)
1398 	    {
1399 		// There was a prefix before the word.  Check that the prefix
1400 		// can be used with this word.
1401 		// Count the length of the NULs in the prefix.  If there are
1402 		// none this must be the first try without a prefix.
1403 		n = stack[sp->ts_prefixdepth].ts_arridx;
1404 		len = pbyts[n++];
1405 		for (c = 0; c < len && pbyts[n + c] == 0; ++c)
1406 		    ;
1407 		if (c > 0)
1408 		{
1409 		    c = valid_word_prefix(c, n, flags,
1410 				       tword + sp->ts_splitoff, slang, FALSE);
1411 		    if (c == 0)
1412 			break;
1413 
1414 		    // Use the WF_RARE flag for a rare prefix.
1415 		    if (c & WF_RAREPFX)
1416 			flags |= WF_RARE;
1417 
1418 		    // Tricky: when checking for both prefix and compounding
1419 		    // we run into the prefix flag first.
1420 		    // Remember that it's OK, so that we accept the prefix
1421 		    // when arriving at a compound flag.
1422 		    sp->ts_flags |= TSF_PREFIXOK;
1423 		}
1424 	    }
1425 
1426 	    // Check NEEDCOMPOUND: can't use word without compounding.  Do try
1427 	    // appending another compound word below.
1428 	    if (sp->ts_complen == sp->ts_compsplit && fword_ends
1429 						     && (flags & WF_NEEDCOMP))
1430 		goodword_ends = FALSE;
1431 	    else
1432 		goodword_ends = TRUE;
1433 
1434 	    p = NULL;
1435 	    compound_ok = TRUE;
1436 	    if (sp->ts_complen > sp->ts_compsplit)
1437 	    {
1438 		if (slang->sl_nobreak)
1439 		{
1440 		    // There was a word before this word.  When there was no
1441 		    // change in this word (it was correct) add the first word
1442 		    // as a suggestion.  If this word was corrected too, we
1443 		    // need to check if a correct word follows.
1444 		    if (sp->ts_fidx - sp->ts_splitfidx
1445 					  == sp->ts_twordlen - sp->ts_splitoff
1446 			    && STRNCMP(fword + sp->ts_splitfidx,
1447 					tword + sp->ts_splitoff,
1448 					 sp->ts_fidx - sp->ts_splitfidx) == 0)
1449 		    {
1450 			preword[sp->ts_prewordlen] = NUL;
1451 			newscore = score_wordcount_adj(slang, sp->ts_score,
1452 						 preword + sp->ts_prewordlen,
1453 						 sp->ts_prewordlen > 0);
1454 			// Add the suggestion if the score isn't too bad.
1455 			if (newscore <= su->su_maxscore)
1456 			    add_suggestion(su, &su->su_ga, preword,
1457 				    sp->ts_splitfidx - repextra,
1458 				    newscore, 0, FALSE,
1459 				    lp->lp_sallang, FALSE);
1460 			break;
1461 		    }
1462 		}
1463 		else
1464 		{
1465 		    // There was a compound word before this word.  If this
1466 		    // word does not support compounding then give up
1467 		    // (splitting is tried for the word without compound
1468 		    // flag).
1469 		    if (((unsigned)flags >> 24) == 0
1470 			    || sp->ts_twordlen - sp->ts_splitoff
1471 						       < slang->sl_compminlen)
1472 			break;
1473 		    // For multi-byte chars check character length against
1474 		    // COMPOUNDMIN.
1475 		    if (has_mbyte
1476 			    && slang->sl_compminlen > 0
1477 			    && mb_charlen(tword + sp->ts_splitoff)
1478 						       < slang->sl_compminlen)
1479 			break;
1480 
1481 		    compflags[sp->ts_complen] = ((unsigned)flags >> 24);
1482 		    compflags[sp->ts_complen + 1] = NUL;
1483 		    vim_strncpy(preword + sp->ts_prewordlen,
1484 			    tword + sp->ts_splitoff,
1485 			    sp->ts_twordlen - sp->ts_splitoff);
1486 
1487 		    // Verify CHECKCOMPOUNDPATTERN  rules.
1488 		    if (match_checkcompoundpattern(preword,  sp->ts_prewordlen,
1489 							  &slang->sl_comppat))
1490 			compound_ok = FALSE;
1491 
1492 		    if (compound_ok)
1493 		    {
1494 			p = preword;
1495 			while (*skiptowhite(p) != NUL)
1496 			    p = skipwhite(skiptowhite(p));
1497 			if (fword_ends && !can_compound(slang, p,
1498 						compflags + sp->ts_compsplit))
1499 			    // Compound is not allowed.  But it may still be
1500 			    // possible if we add another (short) word.
1501 			    compound_ok = FALSE;
1502 		    }
1503 
1504 		    // Get pointer to last char of previous word.
1505 		    p = preword + sp->ts_prewordlen;
1506 		    MB_PTR_BACK(preword, p);
1507 		}
1508 	    }
1509 
1510 	    // Form the word with proper case in preword.
1511 	    // If there is a word from a previous split, append.
1512 	    // For the soundfold tree don't change the case, simply append.
1513 	    if (soundfold)
1514 		STRCPY(preword + sp->ts_prewordlen, tword + sp->ts_splitoff);
1515 	    else if (flags & WF_KEEPCAP)
1516 		// Must find the word in the keep-case tree.
1517 		find_keepcap_word(slang, tword + sp->ts_splitoff,
1518 						 preword + sp->ts_prewordlen);
1519 	    else
1520 	    {
1521 		// Include badflags: If the badword is onecap or allcap
1522 		// use that for the goodword too.  But if the badword is
1523 		// allcap and it's only one char long use onecap.
1524 		c = su->su_badflags;
1525 		if ((c & WF_ALLCAP)
1526 			&& su->su_badlen == (*mb_ptr2len)(su->su_badptr))
1527 		    c = WF_ONECAP;
1528 		c |= flags;
1529 
1530 		// When appending a compound word after a word character don't
1531 		// use Onecap.
1532 		if (p != NULL && spell_iswordp_nmw(p, curwin))
1533 		    c &= ~WF_ONECAP;
1534 		make_case_word(tword + sp->ts_splitoff,
1535 					      preword + sp->ts_prewordlen, c);
1536 	    }
1537 
1538 	    if (!soundfold)
1539 	    {
1540 		// Don't use a banned word.  It may appear again as a good
1541 		// word, thus remember it.
1542 		if (flags & WF_BANNED)
1543 		{
1544 		    add_banned(su, preword + sp->ts_prewordlen);
1545 		    break;
1546 		}
1547 		if ((sp->ts_complen == sp->ts_compsplit
1548 			    && WAS_BANNED(su, preword + sp->ts_prewordlen))
1549 						   || WAS_BANNED(su, preword))
1550 		{
1551 		    if (slang->sl_compprog == NULL)
1552 			break;
1553 		    // the word so far was banned but we may try compounding
1554 		    goodword_ends = FALSE;
1555 		}
1556 	    }
1557 
1558 	    newscore = 0;
1559 	    if (!soundfold)	// soundfold words don't have flags
1560 	    {
1561 		if ((flags & WF_REGION)
1562 			    && (((unsigned)flags >> 16) & lp->lp_region) == 0)
1563 		    newscore += SCORE_REGION;
1564 		if (flags & WF_RARE)
1565 		    newscore += SCORE_RARE;
1566 
1567 		if (!spell_valid_case(su->su_badflags,
1568 				  captype(preword + sp->ts_prewordlen, NULL)))
1569 		    newscore += SCORE_ICASE;
1570 	    }
1571 
1572 	    // TODO: how about splitting in the soundfold tree?
1573 	    if (fword_ends
1574 		    && goodword_ends
1575 		    && sp->ts_fidx >= sp->ts_fidxtry
1576 		    && compound_ok)
1577 	    {
1578 		// The badword also ends: add suggestions.
1579 #ifdef DEBUG_TRIEWALK
1580 		if (soundfold && STRCMP(preword, "smwrd") == 0)
1581 		{
1582 		    int	    j;
1583 
1584 		    // print the stack of changes that brought us here
1585 		    smsg("------ %s -------", fword);
1586 		    for (j = 0; j < depth; ++j)
1587 			smsg("%s", changename[j]);
1588 		}
1589 #endif
1590 		if (soundfold)
1591 		{
1592 		    // For soundfolded words we need to find the original
1593 		    // words, the edit distance and then add them.
1594 		    add_sound_suggest(su, preword, sp->ts_score, lp);
1595 		}
1596 		else if (sp->ts_fidx > 0)
1597 		{
1598 		    // Give a penalty when changing non-word char to word
1599 		    // char, e.g., "thes," -> "these".
1600 		    p = fword + sp->ts_fidx;
1601 		    MB_PTR_BACK(fword, p);
1602 		    if (!spell_iswordp(p, curwin))
1603 		    {
1604 			p = preword + STRLEN(preword);
1605 			MB_PTR_BACK(preword, p);
1606 			if (spell_iswordp(p, curwin))
1607 			    newscore += SCORE_NONWORD;
1608 		    }
1609 
1610 		    // Give a bonus to words seen before.
1611 		    score = score_wordcount_adj(slang,
1612 						sp->ts_score + newscore,
1613 						preword + sp->ts_prewordlen,
1614 						sp->ts_prewordlen > 0);
1615 
1616 		    // Add the suggestion if the score isn't too bad.
1617 		    if (score <= su->su_maxscore)
1618 		    {
1619 			add_suggestion(su, &su->su_ga, preword,
1620 				    sp->ts_fidx - repextra,
1621 				    score, 0, FALSE, lp->lp_sallang, FALSE);
1622 
1623 			if (su->su_badflags & WF_MIXCAP)
1624 			{
1625 			    // We really don't know if the word should be
1626 			    // upper or lower case, add both.
1627 			    c = captype(preword, NULL);
1628 			    if (c == 0 || c == WF_ALLCAP)
1629 			    {
1630 				make_case_word(tword + sp->ts_splitoff,
1631 					      preword + sp->ts_prewordlen,
1632 						      c == 0 ? WF_ALLCAP : 0);
1633 
1634 				add_suggestion(su, &su->su_ga, preword,
1635 					sp->ts_fidx - repextra,
1636 					score + SCORE_ICASE, 0, FALSE,
1637 					lp->lp_sallang, FALSE);
1638 			    }
1639 			}
1640 		    }
1641 		}
1642 	    }
1643 
1644 	    // Try word split and/or compounding.
1645 	    if ((sp->ts_fidx >= sp->ts_fidxtry || fword_ends)
1646 		    // Don't split halfway a character.
1647 		    && (!has_mbyte || sp->ts_tcharlen == 0))
1648 	    {
1649 		int	try_compound;
1650 		int	try_split;
1651 
1652 		// If past the end of the bad word don't try a split.
1653 		// Otherwise try changing the next word.  E.g., find
1654 		// suggestions for "the the" where the second "the" is
1655 		// different.  It's done like a split.
1656 		// TODO: word split for soundfold words
1657 		try_split = (sp->ts_fidx - repextra < su->su_badlen)
1658 								&& !soundfold;
1659 
1660 		// Get here in several situations:
1661 		// 1. The word in the tree ends:
1662 		//    If the word allows compounding try that.  Otherwise try
1663 		//    a split by inserting a space.  For both check that a
1664 		//    valid words starts at fword[sp->ts_fidx].
1665 		//    For NOBREAK do like compounding to be able to check if
1666 		//    the next word is valid.
1667 		// 2. The badword does end, but it was due to a change (e.g.,
1668 		//    a swap).  No need to split, but do check that the
1669 		//    following word is valid.
1670 		// 3. The badword and the word in the tree end.  It may still
1671 		//    be possible to compound another (short) word.
1672 		try_compound = FALSE;
1673 		if (!soundfold
1674 			&& !slang->sl_nocompoundsugs
1675 			&& slang->sl_compprog != NULL
1676 			&& ((unsigned)flags >> 24) != 0
1677 			&& sp->ts_twordlen - sp->ts_splitoff
1678 						       >= slang->sl_compminlen
1679 			&& (!has_mbyte
1680 			    || slang->sl_compminlen == 0
1681 			    || mb_charlen(tword + sp->ts_splitoff)
1682 						      >= slang->sl_compminlen)
1683 			&& (slang->sl_compsylmax < MAXWLEN
1684 			    || sp->ts_complen + 1 - sp->ts_compsplit
1685 							  < slang->sl_compmax)
1686 			&& (can_be_compound(sp, slang,
1687 					 compflags, ((unsigned)flags >> 24))))
1688 
1689 		{
1690 		    try_compound = TRUE;
1691 		    compflags[sp->ts_complen] = ((unsigned)flags >> 24);
1692 		    compflags[sp->ts_complen + 1] = NUL;
1693 		}
1694 
1695 		// For NOBREAK we never try splitting, it won't make any word
1696 		// valid.
1697 		if (slang->sl_nobreak && !slang->sl_nocompoundsugs)
1698 		    try_compound = TRUE;
1699 
1700 		// If we could add a compound word, and it's also possible to
1701 		// split at this point, do the split first and set
1702 		// TSF_DIDSPLIT to avoid doing it again.
1703 		else if (!fword_ends
1704 			&& try_compound
1705 			&& (sp->ts_flags & TSF_DIDSPLIT) == 0)
1706 		{
1707 		    try_compound = FALSE;
1708 		    sp->ts_flags |= TSF_DIDSPLIT;
1709 		    --sp->ts_curi;	    // do the same NUL again
1710 		    compflags[sp->ts_complen] = NUL;
1711 		}
1712 		else
1713 		    sp->ts_flags &= ~TSF_DIDSPLIT;
1714 
1715 		if (try_split || try_compound)
1716 		{
1717 		    if (!try_compound && (!fword_ends || !goodword_ends))
1718 		    {
1719 			// If we're going to split need to check that the
1720 			// words so far are valid for compounding.  If there
1721 			// is only one word it must not have the NEEDCOMPOUND
1722 			// flag.
1723 			if (sp->ts_complen == sp->ts_compsplit
1724 						     && (flags & WF_NEEDCOMP))
1725 			    break;
1726 			p = preword;
1727 			while (*skiptowhite(p) != NUL)
1728 			    p = skipwhite(skiptowhite(p));
1729 			if (sp->ts_complen > sp->ts_compsplit
1730 				&& !can_compound(slang, p,
1731 						compflags + sp->ts_compsplit))
1732 			    break;
1733 
1734 			if (slang->sl_nosplitsugs)
1735 			    newscore += SCORE_SPLIT_NO;
1736 			else
1737 			    newscore += SCORE_SPLIT;
1738 
1739 			// Give a bonus to words seen before.
1740 			newscore = score_wordcount_adj(slang, newscore,
1741 					   preword + sp->ts_prewordlen, TRUE);
1742 		    }
1743 
1744 		    if (TRY_DEEPER(su, stack, depth, newscore))
1745 		    {
1746 			go_deeper(stack, depth, newscore);
1747 #ifdef DEBUG_TRIEWALK
1748 			if (!try_compound && !fword_ends)
1749 			    sprintf(changename[depth], "%.*s-%s: split",
1750 				 sp->ts_twordlen, tword, fword + sp->ts_fidx);
1751 			else
1752 			    sprintf(changename[depth], "%.*s-%s: compound",
1753 				 sp->ts_twordlen, tword, fword + sp->ts_fidx);
1754 #endif
1755 			// Save things to be restored at STATE_SPLITUNDO.
1756 			sp->ts_save_badflags = su->su_badflags;
1757 			PROF_STORE(sp->ts_state)
1758 			sp->ts_state = STATE_SPLITUNDO;
1759 
1760 			++depth;
1761 			sp = &stack[depth];
1762 
1763 			// Append a space to preword when splitting.
1764 			if (!try_compound && !fword_ends)
1765 			    STRCAT(preword, " ");
1766 			sp->ts_prewordlen = (char_u)STRLEN(preword);
1767 			sp->ts_splitoff = sp->ts_twordlen;
1768 			sp->ts_splitfidx = sp->ts_fidx;
1769 
1770 			// If the badword has a non-word character at this
1771 			// position skip it.  That means replacing the
1772 			// non-word character with a space.  Always skip a
1773 			// character when the word ends.  But only when the
1774 			// good word can end.
1775 			if (((!try_compound && !spell_iswordp_nmw(fword
1776 							       + sp->ts_fidx,
1777 							       curwin))
1778 				    || fword_ends)
1779 				&& fword[sp->ts_fidx] != NUL
1780 				&& goodword_ends)
1781 			{
1782 			    int	    l;
1783 
1784 			    l = mb_ptr2len(fword + sp->ts_fidx);
1785 			    if (fword_ends)
1786 			    {
1787 				// Copy the skipped character to preword.
1788 				mch_memmove(preword + sp->ts_prewordlen,
1789 						      fword + sp->ts_fidx, l);
1790 				sp->ts_prewordlen += l;
1791 				preword[sp->ts_prewordlen] = NUL;
1792 			    }
1793 			    else
1794 				sp->ts_score -= SCORE_SPLIT - SCORE_SUBST;
1795 			    sp->ts_fidx += l;
1796 			}
1797 
1798 			// When compounding include compound flag in
1799 			// compflags[] (already set above).  When splitting we
1800 			// may start compounding over again.
1801 			if (try_compound)
1802 			    ++sp->ts_complen;
1803 			else
1804 			    sp->ts_compsplit = sp->ts_complen;
1805 			sp->ts_prefixdepth = PFD_NOPREFIX;
1806 
1807 			// set su->su_badflags to the caps type at this
1808 			// position
1809 			if (has_mbyte)
1810 			    n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
1811 			else
1812 			    n = sp->ts_fidx;
1813 			su->su_badflags = badword_captype(su->su_badptr + n,
1814 					       su->su_badptr + su->su_badlen);
1815 
1816 			// Restart at top of the tree.
1817 			sp->ts_arridx = 0;
1818 
1819 			// If there are postponed prefixes, try these too.
1820 			if (pbyts != NULL)
1821 			{
1822 			    byts = pbyts;
1823 			    idxs = pidxs;
1824 			    sp->ts_prefixdepth = PFD_PREFIXTREE;
1825 			    PROF_STORE(sp->ts_state)
1826 			    sp->ts_state = STATE_NOPREFIX;
1827 			}
1828 		    }
1829 		}
1830 	    }
1831 	    break;
1832 
1833 	case STATE_SPLITUNDO:
1834 	    // Undo the changes done for word split or compound word.
1835 	    su->su_badflags = sp->ts_save_badflags;
1836 
1837 	    // Continue looking for NUL bytes.
1838 	    PROF_STORE(sp->ts_state)
1839 	    sp->ts_state = STATE_START;
1840 
1841 	    // In case we went into the prefix tree.
1842 	    byts = fbyts;
1843 	    idxs = fidxs;
1844 	    break;
1845 
1846 	case STATE_ENDNUL:
1847 	    // Past the NUL bytes in the node.
1848 	    su->su_badflags = sp->ts_save_badflags;
1849 	    if (fword[sp->ts_fidx] == NUL && sp->ts_tcharlen == 0)
1850 	    {
1851 		// The badword ends, can't use STATE_PLAIN.
1852 		PROF_STORE(sp->ts_state)
1853 		sp->ts_state = STATE_DEL;
1854 		break;
1855 	    }
1856 	    PROF_STORE(sp->ts_state)
1857 	    sp->ts_state = STATE_PLAIN;
1858 	    // FALLTHROUGH
1859 
1860 	case STATE_PLAIN:
1861 	    // Go over all possible bytes at this node, add each to tword[]
1862 	    // and use child node.  "ts_curi" is the index.
1863 	    arridx = sp->ts_arridx;
1864 	    if (sp->ts_curi > byts[arridx])
1865 	    {
1866 		// Done all bytes at this node, do next state.  When still at
1867 		// already changed bytes skip the other tricks.
1868 		PROF_STORE(sp->ts_state)
1869 		if (sp->ts_fidx >= sp->ts_fidxtry)
1870 		    sp->ts_state = STATE_DEL;
1871 		else
1872 		    sp->ts_state = STATE_FINAL;
1873 	    }
1874 	    else
1875 	    {
1876 		arridx += sp->ts_curi++;
1877 		c = byts[arridx];
1878 
1879 		// Normal byte, go one level deeper.  If it's not equal to the
1880 		// byte in the bad word adjust the score.  But don't even try
1881 		// when the byte was already changed.  And don't try when we
1882 		// just deleted this byte, accepting it is always cheaper than
1883 		// delete + substitute.
1884 		if (c == fword[sp->ts_fidx]
1885 			|| (sp->ts_tcharlen > 0 && sp->ts_isdiff != DIFF_NONE))
1886 		    newscore = 0;
1887 		else
1888 		    newscore = SCORE_SUBST;
1889 		if ((newscore == 0
1890 			    || (sp->ts_fidx >= sp->ts_fidxtry
1891 				&& ((sp->ts_flags & TSF_DIDDEL) == 0
1892 				    || c != fword[sp->ts_delidx])))
1893 			&& TRY_DEEPER(su, stack, depth, newscore))
1894 		{
1895 		    go_deeper(stack, depth, newscore);
1896 #ifdef DEBUG_TRIEWALK
1897 		    if (newscore > 0)
1898 			sprintf(changename[depth], "%.*s-%s: subst %c to %c",
1899 				sp->ts_twordlen, tword, fword + sp->ts_fidx,
1900 				fword[sp->ts_fidx], c);
1901 		    else
1902 			sprintf(changename[depth], "%.*s-%s: accept %c",
1903 				sp->ts_twordlen, tword, fword + sp->ts_fidx,
1904 				fword[sp->ts_fidx]);
1905 #endif
1906 		    ++depth;
1907 		    sp = &stack[depth];
1908 		    ++sp->ts_fidx;
1909 		    tword[sp->ts_twordlen++] = c;
1910 		    sp->ts_arridx = idxs[arridx];
1911 		    if (newscore == SCORE_SUBST)
1912 			sp->ts_isdiff = DIFF_YES;
1913 		    if (has_mbyte)
1914 		    {
1915 			// Multi-byte characters are a bit complicated to
1916 			// handle: They differ when any of the bytes differ
1917 			// and then their length may also differ.
1918 			if (sp->ts_tcharlen == 0)
1919 			{
1920 			    // First byte.
1921 			    sp->ts_tcharidx = 0;
1922 			    sp->ts_tcharlen = MB_BYTE2LEN(c);
1923 			    sp->ts_fcharstart = sp->ts_fidx - 1;
1924 			    sp->ts_isdiff = (newscore != 0)
1925 						       ? DIFF_YES : DIFF_NONE;
1926 			}
1927 			else if (sp->ts_isdiff == DIFF_INSERT)
1928 			    // When inserting trail bytes don't advance in the
1929 			    // bad word.
1930 			    --sp->ts_fidx;
1931 			if (++sp->ts_tcharidx == sp->ts_tcharlen)
1932 			{
1933 			    // Last byte of character.
1934 			    if (sp->ts_isdiff == DIFF_YES)
1935 			    {
1936 				// Correct ts_fidx for the byte length of the
1937 				// character (we didn't check that before).
1938 				sp->ts_fidx = sp->ts_fcharstart
1939 					    + mb_ptr2len(
1940 						    fword + sp->ts_fcharstart);
1941 				// For changing a composing character adjust
1942 				// the score from SCORE_SUBST to
1943 				// SCORE_SUBCOMP.
1944 				if (enc_utf8
1945 					&& utf_iscomposing(
1946 					    utf_ptr2char(tword
1947 						+ sp->ts_twordlen
1948 							   - sp->ts_tcharlen))
1949 					&& utf_iscomposing(
1950 					    utf_ptr2char(fword
1951 							+ sp->ts_fcharstart)))
1952 				    sp->ts_score -=
1953 						  SCORE_SUBST - SCORE_SUBCOMP;
1954 
1955 				// For a similar character adjust score from
1956 				// SCORE_SUBST to SCORE_SIMILAR.
1957 				else if (!soundfold
1958 					&& slang->sl_has_map
1959 					&& similar_chars(slang,
1960 					    mb_ptr2char(tword
1961 						+ sp->ts_twordlen
1962 							   - sp->ts_tcharlen),
1963 					    mb_ptr2char(fword
1964 							+ sp->ts_fcharstart)))
1965 				    sp->ts_score -=
1966 						  SCORE_SUBST - SCORE_SIMILAR;
1967 			    }
1968 			    else if (sp->ts_isdiff == DIFF_INSERT
1969 					 && sp->ts_twordlen > sp->ts_tcharlen)
1970 			    {
1971 				p = tword + sp->ts_twordlen - sp->ts_tcharlen;
1972 				c = mb_ptr2char(p);
1973 				if (enc_utf8 && utf_iscomposing(c))
1974 				{
1975 				    // Inserting a composing char doesn't
1976 				    // count that much.
1977 				    sp->ts_score -= SCORE_INS - SCORE_INSCOMP;
1978 				}
1979 				else
1980 				{
1981 				    // If the previous character was the same,
1982 				    // thus doubling a character, give a bonus
1983 				    // to the score.  Also for the soundfold
1984 				    // tree (might seem illogical but does
1985 				    // give better scores).
1986 				    MB_PTR_BACK(tword, p);
1987 				    if (c == mb_ptr2char(p))
1988 					sp->ts_score -= SCORE_INS
1989 							       - SCORE_INSDUP;
1990 				}
1991 			    }
1992 
1993 			    // Starting a new char, reset the length.
1994 			    sp->ts_tcharlen = 0;
1995 			}
1996 		    }
1997 		    else
1998 		    {
1999 			// If we found a similar char adjust the score.
2000 			// We do this after calling go_deeper() because
2001 			// it's slow.
2002 			if (newscore != 0
2003 				&& !soundfold
2004 				&& slang->sl_has_map
2005 				&& similar_chars(slang,
2006 						   c, fword[sp->ts_fidx - 1]))
2007 			    sp->ts_score -= SCORE_SUBST - SCORE_SIMILAR;
2008 		    }
2009 		}
2010 	    }
2011 	    break;
2012 
2013 	case STATE_DEL:
2014 	    // When past the first byte of a multi-byte char don't try
2015 	    // delete/insert/swap a character.
2016 	    if (has_mbyte && sp->ts_tcharlen > 0)
2017 	    {
2018 		PROF_STORE(sp->ts_state)
2019 		sp->ts_state = STATE_FINAL;
2020 		break;
2021 	    }
2022 	    // Try skipping one character in the bad word (delete it).
2023 	    PROF_STORE(sp->ts_state)
2024 	    sp->ts_state = STATE_INS_PREP;
2025 	    sp->ts_curi = 1;
2026 	    if (soundfold && sp->ts_fidx == 0 && fword[sp->ts_fidx] == '*')
2027 		// Deleting a vowel at the start of a word counts less, see
2028 		// soundalike_score().
2029 		newscore = 2 * SCORE_DEL / 3;
2030 	    else
2031 		newscore = SCORE_DEL;
2032 	    if (fword[sp->ts_fidx] != NUL
2033 				    && TRY_DEEPER(su, stack, depth, newscore))
2034 	    {
2035 		go_deeper(stack, depth, newscore);
2036 #ifdef DEBUG_TRIEWALK
2037 		sprintf(changename[depth], "%.*s-%s: delete %c",
2038 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
2039 			fword[sp->ts_fidx]);
2040 #endif
2041 		++depth;
2042 
2043 		// Remember what character we deleted, so that we can avoid
2044 		// inserting it again.
2045 		stack[depth].ts_flags |= TSF_DIDDEL;
2046 		stack[depth].ts_delidx = sp->ts_fidx;
2047 
2048 		// Advance over the character in fword[].  Give a bonus to the
2049 		// score if the same character is following "nn" -> "n".  It's
2050 		// a bit illogical for soundfold tree but it does give better
2051 		// results.
2052 		if (has_mbyte)
2053 		{
2054 		    c = mb_ptr2char(fword + sp->ts_fidx);
2055 		    stack[depth].ts_fidx += mb_ptr2len(fword + sp->ts_fidx);
2056 		    if (enc_utf8 && utf_iscomposing(c))
2057 			stack[depth].ts_score -= SCORE_DEL - SCORE_DELCOMP;
2058 		    else if (c == mb_ptr2char(fword + stack[depth].ts_fidx))
2059 			stack[depth].ts_score -= SCORE_DEL - SCORE_DELDUP;
2060 		}
2061 		else
2062 		{
2063 		    ++stack[depth].ts_fidx;
2064 		    if (fword[sp->ts_fidx] == fword[sp->ts_fidx + 1])
2065 			stack[depth].ts_score -= SCORE_DEL - SCORE_DELDUP;
2066 		}
2067 		break;
2068 	    }
2069 	    // FALLTHROUGH
2070 
2071 	case STATE_INS_PREP:
2072 	    if (sp->ts_flags & TSF_DIDDEL)
2073 	    {
2074 		// If we just deleted a byte then inserting won't make sense,
2075 		// a substitute is always cheaper.
2076 		PROF_STORE(sp->ts_state)
2077 		sp->ts_state = STATE_SWAP;
2078 		break;
2079 	    }
2080 
2081 	    // skip over NUL bytes
2082 	    n = sp->ts_arridx;
2083 	    for (;;)
2084 	    {
2085 		if (sp->ts_curi > byts[n])
2086 		{
2087 		    // Only NUL bytes at this node, go to next state.
2088 		    PROF_STORE(sp->ts_state)
2089 		    sp->ts_state = STATE_SWAP;
2090 		    break;
2091 		}
2092 		if (byts[n + sp->ts_curi] != NUL)
2093 		{
2094 		    // Found a byte to insert.
2095 		    PROF_STORE(sp->ts_state)
2096 		    sp->ts_state = STATE_INS;
2097 		    break;
2098 		}
2099 		++sp->ts_curi;
2100 	    }
2101 	    break;
2102 
2103 	    // FALLTHROUGH
2104 
2105 	case STATE_INS:
2106 	    // Insert one byte.  Repeat this for each possible byte at this
2107 	    // node.
2108 	    n = sp->ts_arridx;
2109 	    if (sp->ts_curi > byts[n])
2110 	    {
2111 		// Done all bytes at this node, go to next state.
2112 		PROF_STORE(sp->ts_state)
2113 		sp->ts_state = STATE_SWAP;
2114 		break;
2115 	    }
2116 
2117 	    // Do one more byte at this node, but:
2118 	    // - Skip NUL bytes.
2119 	    // - Skip the byte if it's equal to the byte in the word,
2120 	    //   accepting that byte is always better.
2121 	    n += sp->ts_curi++;
2122 	    c = byts[n];
2123 	    if (soundfold && sp->ts_twordlen == 0 && c == '*')
2124 		// Inserting a vowel at the start of a word counts less,
2125 		// see soundalike_score().
2126 		newscore = 2 * SCORE_INS / 3;
2127 	    else
2128 		newscore = SCORE_INS;
2129 	    if (c != fword[sp->ts_fidx]
2130 				    && TRY_DEEPER(su, stack, depth, newscore))
2131 	    {
2132 		go_deeper(stack, depth, newscore);
2133 #ifdef DEBUG_TRIEWALK
2134 		sprintf(changename[depth], "%.*s-%s: insert %c",
2135 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
2136 			c);
2137 #endif
2138 		++depth;
2139 		sp = &stack[depth];
2140 		tword[sp->ts_twordlen++] = c;
2141 		sp->ts_arridx = idxs[n];
2142 		if (has_mbyte)
2143 		{
2144 		    fl = MB_BYTE2LEN(c);
2145 		    if (fl > 1)
2146 		    {
2147 			// There are following bytes for the same character.
2148 			// We must find all bytes before trying
2149 			// delete/insert/swap/etc.
2150 			sp->ts_tcharlen = fl;
2151 			sp->ts_tcharidx = 1;
2152 			sp->ts_isdiff = DIFF_INSERT;
2153 		    }
2154 		}
2155 		else
2156 		    fl = 1;
2157 		if (fl == 1)
2158 		{
2159 		    // If the previous character was the same, thus doubling a
2160 		    // character, give a bonus to the score.  Also for
2161 		    // soundfold words (illogical but does give a better
2162 		    // score).
2163 		    if (sp->ts_twordlen >= 2
2164 					   && tword[sp->ts_twordlen - 2] == c)
2165 			sp->ts_score -= SCORE_INS - SCORE_INSDUP;
2166 		}
2167 	    }
2168 	    break;
2169 
2170 	case STATE_SWAP:
2171 	    // Swap two bytes in the bad word: "12" -> "21".
2172 	    // We change "fword" here, it's changed back afterwards at
2173 	    // STATE_UNSWAP.
2174 	    p = fword + sp->ts_fidx;
2175 	    c = *p;
2176 	    if (c == NUL)
2177 	    {
2178 		// End of word, can't swap or replace.
2179 		PROF_STORE(sp->ts_state)
2180 		sp->ts_state = STATE_FINAL;
2181 		break;
2182 	    }
2183 
2184 	    // Don't swap if the first character is not a word character.
2185 	    // SWAP3 etc. also don't make sense then.
2186 	    if (!soundfold && !spell_iswordp(p, curwin))
2187 	    {
2188 		PROF_STORE(sp->ts_state)
2189 		sp->ts_state = STATE_REP_INI;
2190 		break;
2191 	    }
2192 
2193 	    if (has_mbyte)
2194 	    {
2195 		n = MB_CPTR2LEN(p);
2196 		c = mb_ptr2char(p);
2197 		if (p[n] == NUL)
2198 		    c2 = NUL;
2199 		else if (!soundfold && !spell_iswordp(p + n, curwin))
2200 		    c2 = c; // don't swap non-word char
2201 		else
2202 		    c2 = mb_ptr2char(p + n);
2203 	    }
2204 	    else
2205 	    {
2206 		if (p[1] == NUL)
2207 		    c2 = NUL;
2208 		else if (!soundfold && !spell_iswordp(p + 1, curwin))
2209 		    c2 = c; // don't swap non-word char
2210 		else
2211 		    c2 = p[1];
2212 	    }
2213 
2214 	    // When the second character is NUL we can't swap.
2215 	    if (c2 == NUL)
2216 	    {
2217 		PROF_STORE(sp->ts_state)
2218 		sp->ts_state = STATE_REP_INI;
2219 		break;
2220 	    }
2221 
2222 	    // When characters are identical, swap won't do anything.
2223 	    // Also get here if the second char is not a word character.
2224 	    if (c == c2)
2225 	    {
2226 		PROF_STORE(sp->ts_state)
2227 		sp->ts_state = STATE_SWAP3;
2228 		break;
2229 	    }
2230 	    if (c2 != NUL && TRY_DEEPER(su, stack, depth, SCORE_SWAP))
2231 	    {
2232 		go_deeper(stack, depth, SCORE_SWAP);
2233 #ifdef DEBUG_TRIEWALK
2234 		sprintf(changename[depth], "%.*s-%s: swap %c and %c",
2235 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
2236 			c, c2);
2237 #endif
2238 		PROF_STORE(sp->ts_state)
2239 		sp->ts_state = STATE_UNSWAP;
2240 		++depth;
2241 		if (has_mbyte)
2242 		{
2243 		    fl = mb_char2len(c2);
2244 		    mch_memmove(p, p + n, fl);
2245 		    mb_char2bytes(c, p + fl);
2246 		    stack[depth].ts_fidxtry = sp->ts_fidx + n + fl;
2247 		}
2248 		else
2249 		{
2250 		    p[0] = c2;
2251 		    p[1] = c;
2252 		    stack[depth].ts_fidxtry = sp->ts_fidx + 2;
2253 		}
2254 	    }
2255 	    else
2256 	    {
2257 		// If this swap doesn't work then SWAP3 won't either.
2258 		PROF_STORE(sp->ts_state)
2259 		sp->ts_state = STATE_REP_INI;
2260 	    }
2261 	    break;
2262 
2263 	case STATE_UNSWAP:
2264 	    // Undo the STATE_SWAP swap: "21" -> "12".
2265 	    p = fword + sp->ts_fidx;
2266 	    if (has_mbyte)
2267 	    {
2268 		n = mb_ptr2len(p);
2269 		c = mb_ptr2char(p + n);
2270 		mch_memmove(p + mb_ptr2len(p + n), p, n);
2271 		mb_char2bytes(c, p);
2272 	    }
2273 	    else
2274 	    {
2275 		c = *p;
2276 		*p = p[1];
2277 		p[1] = c;
2278 	    }
2279 	    // FALLTHROUGH
2280 
2281 	case STATE_SWAP3:
2282 	    // Swap two bytes, skipping one: "123" -> "321".  We change
2283 	    // "fword" here, it's changed back afterwards at STATE_UNSWAP3.
2284 	    p = fword + sp->ts_fidx;
2285 	    if (has_mbyte)
2286 	    {
2287 		n = MB_CPTR2LEN(p);
2288 		c = mb_ptr2char(p);
2289 		fl = MB_CPTR2LEN(p + n);
2290 		c2 = mb_ptr2char(p + n);
2291 		if (!soundfold && !spell_iswordp(p + n + fl, curwin))
2292 		    c3 = c;	// don't swap non-word char
2293 		else
2294 		    c3 = mb_ptr2char(p + n + fl);
2295 	    }
2296 	    else
2297 	    {
2298 		c = *p;
2299 		c2 = p[1];
2300 		if (!soundfold && !spell_iswordp(p + 2, curwin))
2301 		    c3 = c;	// don't swap non-word char
2302 		else
2303 		    c3 = p[2];
2304 	    }
2305 
2306 	    // When characters are identical: "121" then SWAP3 result is
2307 	    // identical, ROT3L result is same as SWAP: "211", ROT3L result is
2308 	    // same as SWAP on next char: "112".  Thus skip all swapping.
2309 	    // Also skip when c3 is NUL.
2310 	    // Also get here when the third character is not a word character.
2311 	    // Second character may any char: "a.b" -> "b.a"
2312 	    if (c == c3 || c3 == NUL)
2313 	    {
2314 		PROF_STORE(sp->ts_state)
2315 		sp->ts_state = STATE_REP_INI;
2316 		break;
2317 	    }
2318 	    if (TRY_DEEPER(su, stack, depth, SCORE_SWAP3))
2319 	    {
2320 		go_deeper(stack, depth, SCORE_SWAP3);
2321 #ifdef DEBUG_TRIEWALK
2322 		sprintf(changename[depth], "%.*s-%s: swap3 %c and %c",
2323 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
2324 			c, c3);
2325 #endif
2326 		PROF_STORE(sp->ts_state)
2327 		sp->ts_state = STATE_UNSWAP3;
2328 		++depth;
2329 		if (has_mbyte)
2330 		{
2331 		    tl = mb_char2len(c3);
2332 		    mch_memmove(p, p + n + fl, tl);
2333 		    mb_char2bytes(c2, p + tl);
2334 		    mb_char2bytes(c, p + fl + tl);
2335 		    stack[depth].ts_fidxtry = sp->ts_fidx + n + fl + tl;
2336 		}
2337 		else
2338 		{
2339 		    p[0] = p[2];
2340 		    p[2] = c;
2341 		    stack[depth].ts_fidxtry = sp->ts_fidx + 3;
2342 		}
2343 	    }
2344 	    else
2345 	    {
2346 		PROF_STORE(sp->ts_state)
2347 		sp->ts_state = STATE_REP_INI;
2348 	    }
2349 	    break;
2350 
2351 	case STATE_UNSWAP3:
2352 	    // Undo STATE_SWAP3: "321" -> "123"
2353 	    p = fword + sp->ts_fidx;
2354 	    if (has_mbyte)
2355 	    {
2356 		n = mb_ptr2len(p);
2357 		c2 = mb_ptr2char(p + n);
2358 		fl = mb_ptr2len(p + n);
2359 		c = mb_ptr2char(p + n + fl);
2360 		tl = mb_ptr2len(p + n + fl);
2361 		mch_memmove(p + fl + tl, p, n);
2362 		mb_char2bytes(c, p);
2363 		mb_char2bytes(c2, p + tl);
2364 		p = p + tl;
2365 	    }
2366 	    else
2367 	    {
2368 		c = *p;
2369 		*p = p[2];
2370 		p[2] = c;
2371 		++p;
2372 	    }
2373 
2374 	    if (!soundfold && !spell_iswordp(p, curwin))
2375 	    {
2376 		// Middle char is not a word char, skip the rotate.  First and
2377 		// third char were already checked at swap and swap3.
2378 		PROF_STORE(sp->ts_state)
2379 		sp->ts_state = STATE_REP_INI;
2380 		break;
2381 	    }
2382 
2383 	    // Rotate three characters left: "123" -> "231".  We change
2384 	    // "fword" here, it's changed back afterwards at STATE_UNROT3L.
2385 	    if (TRY_DEEPER(su, stack, depth, SCORE_SWAP3))
2386 	    {
2387 		go_deeper(stack, depth, SCORE_SWAP3);
2388 #ifdef DEBUG_TRIEWALK
2389 		p = fword + sp->ts_fidx;
2390 		sprintf(changename[depth], "%.*s-%s: rotate left %c%c%c",
2391 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
2392 			p[0], p[1], p[2]);
2393 #endif
2394 		PROF_STORE(sp->ts_state)
2395 		sp->ts_state = STATE_UNROT3L;
2396 		++depth;
2397 		p = fword + sp->ts_fidx;
2398 		if (has_mbyte)
2399 		{
2400 		    n = MB_CPTR2LEN(p);
2401 		    c = mb_ptr2char(p);
2402 		    fl = MB_CPTR2LEN(p + n);
2403 		    fl += MB_CPTR2LEN(p + n + fl);
2404 		    mch_memmove(p, p + n, fl);
2405 		    mb_char2bytes(c, p + fl);
2406 		    stack[depth].ts_fidxtry = sp->ts_fidx + n + fl;
2407 		}
2408 		else
2409 		{
2410 		    c = *p;
2411 		    *p = p[1];
2412 		    p[1] = p[2];
2413 		    p[2] = c;
2414 		    stack[depth].ts_fidxtry = sp->ts_fidx + 3;
2415 		}
2416 	    }
2417 	    else
2418 	    {
2419 		PROF_STORE(sp->ts_state)
2420 		sp->ts_state = STATE_REP_INI;
2421 	    }
2422 	    break;
2423 
2424 	case STATE_UNROT3L:
2425 	    // Undo ROT3L: "231" -> "123"
2426 	    p = fword + sp->ts_fidx;
2427 	    if (has_mbyte)
2428 	    {
2429 		n = mb_ptr2len(p);
2430 		n += mb_ptr2len(p + n);
2431 		c = mb_ptr2char(p + n);
2432 		tl = mb_ptr2len(p + n);
2433 		mch_memmove(p + tl, p, n);
2434 		mb_char2bytes(c, p);
2435 	    }
2436 	    else
2437 	    {
2438 		c = p[2];
2439 		p[2] = p[1];
2440 		p[1] = *p;
2441 		*p = c;
2442 	    }
2443 
2444 	    // Rotate three bytes right: "123" -> "312".  We change "fword"
2445 	    // here, it's changed back afterwards at STATE_UNROT3R.
2446 	    if (TRY_DEEPER(su, stack, depth, SCORE_SWAP3))
2447 	    {
2448 		go_deeper(stack, depth, SCORE_SWAP3);
2449 #ifdef DEBUG_TRIEWALK
2450 		p = fword + sp->ts_fidx;
2451 		sprintf(changename[depth], "%.*s-%s: rotate right %c%c%c",
2452 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
2453 			p[0], p[1], p[2]);
2454 #endif
2455 		PROF_STORE(sp->ts_state)
2456 		sp->ts_state = STATE_UNROT3R;
2457 		++depth;
2458 		p = fword + sp->ts_fidx;
2459 		if (has_mbyte)
2460 		{
2461 		    n = MB_CPTR2LEN(p);
2462 		    n += MB_CPTR2LEN(p + n);
2463 		    c = mb_ptr2char(p + n);
2464 		    tl = MB_CPTR2LEN(p + n);
2465 		    mch_memmove(p + tl, p, n);
2466 		    mb_char2bytes(c, p);
2467 		    stack[depth].ts_fidxtry = sp->ts_fidx + n + tl;
2468 		}
2469 		else
2470 		{
2471 		    c = p[2];
2472 		    p[2] = p[1];
2473 		    p[1] = *p;
2474 		    *p = c;
2475 		    stack[depth].ts_fidxtry = sp->ts_fidx + 3;
2476 		}
2477 	    }
2478 	    else
2479 	    {
2480 		PROF_STORE(sp->ts_state)
2481 		sp->ts_state = STATE_REP_INI;
2482 	    }
2483 	    break;
2484 
2485 	case STATE_UNROT3R:
2486 	    // Undo ROT3R: "312" -> "123"
2487 	    p = fword + sp->ts_fidx;
2488 	    if (has_mbyte)
2489 	    {
2490 		c = mb_ptr2char(p);
2491 		tl = mb_ptr2len(p);
2492 		n = mb_ptr2len(p + tl);
2493 		n += mb_ptr2len(p + tl + n);
2494 		mch_memmove(p, p + tl, n);
2495 		mb_char2bytes(c, p + n);
2496 	    }
2497 	    else
2498 	    {
2499 		c = *p;
2500 		*p = p[1];
2501 		p[1] = p[2];
2502 		p[2] = c;
2503 	    }
2504 	    // FALLTHROUGH
2505 
2506 	case STATE_REP_INI:
2507 	    // Check if matching with REP items from the .aff file would work.
2508 	    // Quickly skip if:
2509 	    // - there are no REP items and we are not in the soundfold trie
2510 	    // - the score is going to be too high anyway
2511 	    // - already applied a REP item or swapped here
2512 	    if ((lp->lp_replang == NULL && !soundfold)
2513 		    || sp->ts_score + SCORE_REP >= su->su_maxscore
2514 		    || sp->ts_fidx < sp->ts_fidxtry)
2515 	    {
2516 		PROF_STORE(sp->ts_state)
2517 		sp->ts_state = STATE_FINAL;
2518 		break;
2519 	    }
2520 
2521 	    // Use the first byte to quickly find the first entry that may
2522 	    // match.  If the index is -1 there is none.
2523 	    if (soundfold)
2524 		sp->ts_curi = slang->sl_repsal_first[fword[sp->ts_fidx]];
2525 	    else
2526 		sp->ts_curi = lp->lp_replang->sl_rep_first[fword[sp->ts_fidx]];
2527 
2528 	    if (sp->ts_curi < 0)
2529 	    {
2530 		PROF_STORE(sp->ts_state)
2531 		sp->ts_state = STATE_FINAL;
2532 		break;
2533 	    }
2534 
2535 	    PROF_STORE(sp->ts_state)
2536 	    sp->ts_state = STATE_REP;
2537 	    // FALLTHROUGH
2538 
2539 	case STATE_REP:
2540 	    // Try matching with REP items from the .aff file.  For each match
2541 	    // replace the characters and check if the resulting word is
2542 	    // valid.
2543 	    p = fword + sp->ts_fidx;
2544 
2545 	    if (soundfold)
2546 		gap = &slang->sl_repsal;
2547 	    else
2548 		gap = &lp->lp_replang->sl_rep;
2549 	    while (sp->ts_curi < gap->ga_len)
2550 	    {
2551 		ftp = (fromto_T *)gap->ga_data + sp->ts_curi++;
2552 		if (*ftp->ft_from != *p)
2553 		{
2554 		    // past possible matching entries
2555 		    sp->ts_curi = gap->ga_len;
2556 		    break;
2557 		}
2558 		if (STRNCMP(ftp->ft_from, p, STRLEN(ftp->ft_from)) == 0
2559 			&& TRY_DEEPER(su, stack, depth, SCORE_REP))
2560 		{
2561 		    go_deeper(stack, depth, SCORE_REP);
2562 #ifdef DEBUG_TRIEWALK
2563 		    sprintf(changename[depth], "%.*s-%s: replace %s with %s",
2564 			    sp->ts_twordlen, tword, fword + sp->ts_fidx,
2565 			    ftp->ft_from, ftp->ft_to);
2566 #endif
2567 		    // Need to undo this afterwards.
2568 		    PROF_STORE(sp->ts_state)
2569 		    sp->ts_state = STATE_REP_UNDO;
2570 
2571 		    // Change the "from" to the "to" string.
2572 		    ++depth;
2573 		    fl = (int)STRLEN(ftp->ft_from);
2574 		    tl = (int)STRLEN(ftp->ft_to);
2575 		    if (fl != tl)
2576 		    {
2577 			STRMOVE(p + tl, p + fl);
2578 			repextra += tl - fl;
2579 		    }
2580 		    mch_memmove(p, ftp->ft_to, tl);
2581 		    stack[depth].ts_fidxtry = sp->ts_fidx + tl;
2582 		    stack[depth].ts_tcharlen = 0;
2583 		    break;
2584 		}
2585 	    }
2586 
2587 	    if (sp->ts_curi >= gap->ga_len && sp->ts_state == STATE_REP)
2588 	    {
2589 		// No (more) matches.
2590 		PROF_STORE(sp->ts_state)
2591 		sp->ts_state = STATE_FINAL;
2592 	    }
2593 
2594 	    break;
2595 
2596 	case STATE_REP_UNDO:
2597 	    // Undo a REP replacement and continue with the next one.
2598 	    if (soundfold)
2599 		gap = &slang->sl_repsal;
2600 	    else
2601 		gap = &lp->lp_replang->sl_rep;
2602 	    ftp = (fromto_T *)gap->ga_data + sp->ts_curi - 1;
2603 	    fl = (int)STRLEN(ftp->ft_from);
2604 	    tl = (int)STRLEN(ftp->ft_to);
2605 	    p = fword + sp->ts_fidx;
2606 	    if (fl != tl)
2607 	    {
2608 		STRMOVE(p + fl, p + tl);
2609 		repextra -= tl - fl;
2610 	    }
2611 	    mch_memmove(p, ftp->ft_from, fl);
2612 	    PROF_STORE(sp->ts_state)
2613 	    sp->ts_state = STATE_REP;
2614 	    break;
2615 
2616 	default:
2617 	    // Did all possible states at this level, go up one level.
2618 	    --depth;
2619 
2620 	    if (depth >= 0 && stack[depth].ts_prefixdepth == PFD_PREFIXTREE)
2621 	    {
2622 		// Continue in or go back to the prefix tree.
2623 		byts = pbyts;
2624 		idxs = pidxs;
2625 	    }
2626 
2627 	    // Don't check for CTRL-C too often, it takes time.
2628 	    if (--breakcheckcount == 0)
2629 	    {
2630 		ui_breakcheck();
2631 		breakcheckcount = 1000;
2632 	    }
2633 	}
2634     }
2635 }
2636 
2637 
2638 /*
2639  * Go one level deeper in the tree.
2640  */
2641     static void
2642 go_deeper(trystate_T *stack, int depth, int score_add)
2643 {
2644     stack[depth + 1] = stack[depth];
2645     stack[depth + 1].ts_state = STATE_START;
2646     stack[depth + 1].ts_score = stack[depth].ts_score + score_add;
2647     stack[depth + 1].ts_curi = 1;	// start just after length byte
2648     stack[depth + 1].ts_flags = 0;
2649 }
2650 
2651 /*
2652  * "fword" is a good word with case folded.  Find the matching keep-case
2653  * words and put it in "kword".
2654  * Theoretically there could be several keep-case words that result in the
2655  * same case-folded word, but we only find one...
2656  */
2657     static void
2658 find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
2659 {
2660     char_u	uword[MAXWLEN];		// "fword" in upper-case
2661     int		depth;
2662     idx_T	tryidx;
2663 
2664     // The following arrays are used at each depth in the tree.
2665     idx_T	arridx[MAXWLEN];
2666     int		round[MAXWLEN];
2667     int		fwordidx[MAXWLEN];
2668     int		uwordidx[MAXWLEN];
2669     int		kwordlen[MAXWLEN];
2670 
2671     int		flen, ulen;
2672     int		l;
2673     int		len;
2674     int		c;
2675     idx_T	lo, hi, m;
2676     char_u	*p;
2677     char_u	*byts = slang->sl_kbyts;    // array with bytes of the words
2678     idx_T	*idxs = slang->sl_kidxs;    // array with indexes
2679 
2680     if (byts == NULL)
2681     {
2682 	// array is empty: "cannot happen"
2683 	*kword = NUL;
2684 	return;
2685     }
2686 
2687     // Make an all-cap version of "fword".
2688     allcap_copy(fword, uword);
2689 
2690     // Each character needs to be tried both case-folded and upper-case.
2691     // All this gets very complicated if we keep in mind that changing case
2692     // may change the byte length of a multi-byte character...
2693     depth = 0;
2694     arridx[0] = 0;
2695     round[0] = 0;
2696     fwordidx[0] = 0;
2697     uwordidx[0] = 0;
2698     kwordlen[0] = 0;
2699     while (depth >= 0)
2700     {
2701 	if (fword[fwordidx[depth]] == NUL)
2702 	{
2703 	    // We are at the end of "fword".  If the tree allows a word to end
2704 	    // here we have found a match.
2705 	    if (byts[arridx[depth] + 1] == 0)
2706 	    {
2707 		kword[kwordlen[depth]] = NUL;
2708 		return;
2709 	    }
2710 
2711 	    // kword is getting too long, continue one level up
2712 	    --depth;
2713 	}
2714 	else if (++round[depth] > 2)
2715 	{
2716 	    // tried both fold-case and upper-case character, continue one
2717 	    // level up
2718 	    --depth;
2719 	}
2720 	else
2721 	{
2722 	    // round[depth] == 1: Try using the folded-case character.
2723 	    // round[depth] == 2: Try using the upper-case character.
2724 	    if (has_mbyte)
2725 	    {
2726 		flen = MB_CPTR2LEN(fword + fwordidx[depth]);
2727 		ulen = MB_CPTR2LEN(uword + uwordidx[depth]);
2728 	    }
2729 	    else
2730 		ulen = flen = 1;
2731 	    if (round[depth] == 1)
2732 	    {
2733 		p = fword + fwordidx[depth];
2734 		l = flen;
2735 	    }
2736 	    else
2737 	    {
2738 		p = uword + uwordidx[depth];
2739 		l = ulen;
2740 	    }
2741 
2742 	    for (tryidx = arridx[depth]; l > 0; --l)
2743 	    {
2744 		// Perform a binary search in the list of accepted bytes.
2745 		len = byts[tryidx++];
2746 		c = *p++;
2747 		lo = tryidx;
2748 		hi = tryidx + len - 1;
2749 		while (lo < hi)
2750 		{
2751 		    m = (lo + hi) / 2;
2752 		    if (byts[m] > c)
2753 			hi = m - 1;
2754 		    else if (byts[m] < c)
2755 			lo = m + 1;
2756 		    else
2757 		    {
2758 			lo = hi = m;
2759 			break;
2760 		    }
2761 		}
2762 
2763 		// Stop if there is no matching byte.
2764 		if (hi < lo || byts[lo] != c)
2765 		    break;
2766 
2767 		// Continue at the child (if there is one).
2768 		tryidx = idxs[lo];
2769 	    }
2770 
2771 	    if (l == 0)
2772 	    {
2773 		// Found the matching char.  Copy it to "kword" and go a
2774 		// level deeper.
2775 		if (round[depth] == 1)
2776 		{
2777 		    STRNCPY(kword + kwordlen[depth], fword + fwordidx[depth],
2778 									flen);
2779 		    kwordlen[depth + 1] = kwordlen[depth] + flen;
2780 		}
2781 		else
2782 		{
2783 		    STRNCPY(kword + kwordlen[depth], uword + uwordidx[depth],
2784 									ulen);
2785 		    kwordlen[depth + 1] = kwordlen[depth] + ulen;
2786 		}
2787 		fwordidx[depth + 1] = fwordidx[depth] + flen;
2788 		uwordidx[depth + 1] = uwordidx[depth] + ulen;
2789 
2790 		++depth;
2791 		arridx[depth] = tryidx;
2792 		round[depth] = 0;
2793 	    }
2794 	}
2795     }
2796 
2797     // Didn't find it: "cannot happen".
2798     *kword = NUL;
2799 }
2800 
2801 /*
2802  * Compute the sound-a-like score for suggestions in su->su_ga and add them to
2803  * su->su_sga.
2804  */
2805     static void
2806 score_comp_sal(suginfo_T *su)
2807 {
2808     langp_T	*lp;
2809     char_u	badsound[MAXWLEN];
2810     int		i;
2811     suggest_T   *stp;
2812     suggest_T   *sstp;
2813     int		score;
2814     int		lpi;
2815 
2816     if (ga_grow(&su->su_sga, su->su_ga.ga_len) == FAIL)
2817 	return;
2818 
2819     // Use the sound-folding of the first language that supports it.
2820     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
2821     {
2822 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
2823 	if (lp->lp_slang->sl_sal.ga_len > 0)
2824 	{
2825 	    // soundfold the bad word
2826 	    spell_soundfold(lp->lp_slang, su->su_fbadword, TRUE, badsound);
2827 
2828 	    for (i = 0; i < su->su_ga.ga_len; ++i)
2829 	    {
2830 		stp = &SUG(su->su_ga, i);
2831 
2832 		// Case-fold the suggested word, sound-fold it and compute the
2833 		// sound-a-like score.
2834 		score = stp_sal_score(stp, su, lp->lp_slang, badsound);
2835 		if (score < SCORE_MAXMAX)
2836 		{
2837 		    // Add the suggestion.
2838 		    sstp = &SUG(su->su_sga, su->su_sga.ga_len);
2839 		    sstp->st_word = vim_strsave(stp->st_word);
2840 		    if (sstp->st_word != NULL)
2841 		    {
2842 			sstp->st_wordlen = stp->st_wordlen;
2843 			sstp->st_score = score;
2844 			sstp->st_altscore = 0;
2845 			sstp->st_orglen = stp->st_orglen;
2846 			++su->su_sga.ga_len;
2847 		    }
2848 		}
2849 	    }
2850 	    break;
2851 	}
2852     }
2853 }
2854 
2855 /*
2856  * Combine the list of suggestions in su->su_ga and su->su_sga.
2857  * They are entwined.
2858  */
2859     static void
2860 score_combine(suginfo_T *su)
2861 {
2862     int		i;
2863     int		j;
2864     garray_T	ga;
2865     garray_T	*gap;
2866     langp_T	*lp;
2867     suggest_T	*stp;
2868     char_u	*p;
2869     char_u	badsound[MAXWLEN];
2870     int		round;
2871     int		lpi;
2872     slang_T	*slang = NULL;
2873 
2874     // Add the alternate score to su_ga.
2875     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
2876     {
2877 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
2878 	if (lp->lp_slang->sl_sal.ga_len > 0)
2879 	{
2880 	    // soundfold the bad word
2881 	    slang = lp->lp_slang;
2882 	    spell_soundfold(slang, su->su_fbadword, TRUE, badsound);
2883 
2884 	    for (i = 0; i < su->su_ga.ga_len; ++i)
2885 	    {
2886 		stp = &SUG(su->su_ga, i);
2887 		stp->st_altscore = stp_sal_score(stp, su, slang, badsound);
2888 		if (stp->st_altscore == SCORE_MAXMAX)
2889 		    stp->st_score = (stp->st_score * 3 + SCORE_BIG) / 4;
2890 		else
2891 		    stp->st_score = (stp->st_score * 3
2892 						  + stp->st_altscore) / 4;
2893 		stp->st_salscore = FALSE;
2894 	    }
2895 	    break;
2896 	}
2897     }
2898 
2899     if (slang == NULL)	// Using "double" without sound folding.
2900     {
2901 	(void)cleanup_suggestions(&su->su_ga, su->su_maxscore,
2902 							     su->su_maxcount);
2903 	return;
2904     }
2905 
2906     // Add the alternate score to su_sga.
2907     for (i = 0; i < su->su_sga.ga_len; ++i)
2908     {
2909 	stp = &SUG(su->su_sga, i);
2910 	stp->st_altscore = spell_edit_score(slang,
2911 						su->su_badword, stp->st_word);
2912 	if (stp->st_score == SCORE_MAXMAX)
2913 	    stp->st_score = (SCORE_BIG * 7 + stp->st_altscore) / 8;
2914 	else
2915 	    stp->st_score = (stp->st_score * 7 + stp->st_altscore) / 8;
2916 	stp->st_salscore = TRUE;
2917     }
2918 
2919     // Remove bad suggestions, sort the suggestions and truncate at "maxcount"
2920     // for both lists.
2921     check_suggestions(su, &su->su_ga);
2922     (void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
2923     check_suggestions(su, &su->su_sga);
2924     (void)cleanup_suggestions(&su->su_sga, su->su_maxscore, su->su_maxcount);
2925 
2926     ga_init2(&ga, (int)sizeof(suginfo_T), 1);
2927     if (ga_grow(&ga, su->su_ga.ga_len + su->su_sga.ga_len) == FAIL)
2928 	return;
2929 
2930     stp = &SUG(ga, 0);
2931     for (i = 0; i < su->su_ga.ga_len || i < su->su_sga.ga_len; ++i)
2932     {
2933 	// round 1: get a suggestion from su_ga
2934 	// round 2: get a suggestion from su_sga
2935 	for (round = 1; round <= 2; ++round)
2936 	{
2937 	    gap = round == 1 ? &su->su_ga : &su->su_sga;
2938 	    if (i < gap->ga_len)
2939 	    {
2940 		// Don't add a word if it's already there.
2941 		p = SUG(*gap, i).st_word;
2942 		for (j = 0; j < ga.ga_len; ++j)
2943 		    if (STRCMP(stp[j].st_word, p) == 0)
2944 			break;
2945 		if (j == ga.ga_len)
2946 		    stp[ga.ga_len++] = SUG(*gap, i);
2947 		else
2948 		    vim_free(p);
2949 	    }
2950 	}
2951     }
2952 
2953     ga_clear(&su->su_ga);
2954     ga_clear(&su->su_sga);
2955 
2956     // Truncate the list to the number of suggestions that will be displayed.
2957     if (ga.ga_len > su->su_maxcount)
2958     {
2959 	for (i = su->su_maxcount; i < ga.ga_len; ++i)
2960 	    vim_free(stp[i].st_word);
2961 	ga.ga_len = su->su_maxcount;
2962     }
2963 
2964     su->su_ga = ga;
2965 }
2966 
2967 /*
2968  * For the goodword in "stp" compute the soundalike score compared to the
2969  * badword.
2970  */
2971     static int
2972 stp_sal_score(
2973     suggest_T	*stp,
2974     suginfo_T	*su,
2975     slang_T	*slang,
2976     char_u	*badsound)	// sound-folded badword
2977 {
2978     char_u	*p;
2979     char_u	*pbad;
2980     char_u	*pgood;
2981     char_u	badsound2[MAXWLEN];
2982     char_u	fword[MAXWLEN];
2983     char_u	goodsound[MAXWLEN];
2984     char_u	goodword[MAXWLEN];
2985     int		lendiff;
2986 
2987     lendiff = (int)(su->su_badlen - stp->st_orglen);
2988     if (lendiff >= 0)
2989 	pbad = badsound;
2990     else
2991     {
2992 	// soundfold the bad word with more characters following
2993 	(void)spell_casefold(su->su_badptr, stp->st_orglen, fword, MAXWLEN);
2994 
2995 	// When joining two words the sound often changes a lot.  E.g., "t he"
2996 	// sounds like "t h" while "the" sounds like "@".  Avoid that by
2997 	// removing the space.  Don't do it when the good word also contains a
2998 	// space.
2999 	if (VIM_ISWHITE(su->su_badptr[su->su_badlen])
3000 					 && *skiptowhite(stp->st_word) == NUL)
3001 	    for (p = fword; *(p = skiptowhite(p)) != NUL; )
3002 		STRMOVE(p, p + 1);
3003 
3004 	spell_soundfold(slang, fword, TRUE, badsound2);
3005 	pbad = badsound2;
3006     }
3007 
3008     if (lendiff > 0 && stp->st_wordlen + lendiff < MAXWLEN)
3009     {
3010 	// Add part of the bad word to the good word, so that we soundfold
3011 	// what replaces the bad word.
3012 	STRCPY(goodword, stp->st_word);
3013 	vim_strncpy(goodword + stp->st_wordlen,
3014 			    su->su_badptr + su->su_badlen - lendiff, lendiff);
3015 	pgood = goodword;
3016     }
3017     else
3018 	pgood = stp->st_word;
3019 
3020     // Sound-fold the word and compute the score for the difference.
3021     spell_soundfold(slang, pgood, FALSE, goodsound);
3022 
3023     return soundalike_score(goodsound, pbad);
3024 }
3025 
3026 // structure used to store soundfolded words that add_sound_suggest() has
3027 // handled already.
3028 typedef struct
3029 {
3030     short	sft_score;	// lowest score used
3031     char_u	sft_word[1];    // soundfolded word, actually longer
3032 } sftword_T;
3033 
3034 static sftword_T dumsft;
3035 #define HIKEY2SFT(p)  ((sftword_T *)(p - (dumsft.sft_word - (char_u *)&dumsft)))
3036 #define HI2SFT(hi)     HIKEY2SFT((hi)->hi_key)
3037 
3038 /*
3039  * Prepare for calling suggest_try_soundalike().
3040  */
3041     static void
3042 suggest_try_soundalike_prep(void)
3043 {
3044     langp_T	*lp;
3045     int		lpi;
3046     slang_T	*slang;
3047 
3048     // Do this for all languages that support sound folding and for which a
3049     // .sug file has been loaded.
3050     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
3051     {
3052 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
3053 	slang = lp->lp_slang;
3054 	if (slang->sl_sal.ga_len > 0 && slang->sl_sbyts != NULL)
3055 	    // prepare the hashtable used by add_sound_suggest()
3056 	    hash_init(&slang->sl_sounddone);
3057     }
3058 }
3059 
3060 /*
3061  * Find suggestions by comparing the word in a sound-a-like form.
3062  * Note: This doesn't support postponed prefixes.
3063  */
3064     static void
3065 suggest_try_soundalike(suginfo_T *su)
3066 {
3067     char_u	salword[MAXWLEN];
3068     langp_T	*lp;
3069     int		lpi;
3070     slang_T	*slang;
3071 
3072     // Do this for all languages that support sound folding and for which a
3073     // .sug file has been loaded.
3074     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
3075     {
3076 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
3077 	slang = lp->lp_slang;
3078 	if (slang->sl_sal.ga_len > 0 && slang->sl_sbyts != NULL)
3079 	{
3080 	    // soundfold the bad word
3081 	    spell_soundfold(slang, su->su_fbadword, TRUE, salword);
3082 
3083 	    // try all kinds of inserts/deletes/swaps/etc.
3084 	    // TODO: also soundfold the next words, so that we can try joining
3085 	    // and splitting
3086 #ifdef SUGGEST_PROFILE
3087 	prof_init();
3088 #endif
3089 	    suggest_trie_walk(su, lp, salword, TRUE);
3090 #ifdef SUGGEST_PROFILE
3091 	prof_report("soundalike");
3092 #endif
3093 	}
3094     }
3095 }
3096 
3097 /*
3098  * Finish up after calling suggest_try_soundalike().
3099  */
3100     static void
3101 suggest_try_soundalike_finish(void)
3102 {
3103     langp_T	*lp;
3104     int		lpi;
3105     slang_T	*slang;
3106     int		todo;
3107     hashitem_T	*hi;
3108 
3109     // Do this for all languages that support sound folding and for which a
3110     // .sug file has been loaded.
3111     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
3112     {
3113 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
3114 	slang = lp->lp_slang;
3115 	if (slang->sl_sal.ga_len > 0 && slang->sl_sbyts != NULL)
3116 	{
3117 	    // Free the info about handled words.
3118 	    todo = (int)slang->sl_sounddone.ht_used;
3119 	    for (hi = slang->sl_sounddone.ht_array; todo > 0; ++hi)
3120 		if (!HASHITEM_EMPTY(hi))
3121 		{
3122 		    vim_free(HI2SFT(hi));
3123 		    --todo;
3124 		}
3125 
3126 	    // Clear the hashtable, it may also be used by another region.
3127 	    hash_clear(&slang->sl_sounddone);
3128 	    hash_init(&slang->sl_sounddone);
3129 	}
3130     }
3131 }
3132 
3133 /*
3134  * A match with a soundfolded word is found.  Add the good word(s) that
3135  * produce this soundfolded word.
3136  */
3137     static void
3138 add_sound_suggest(
3139     suginfo_T	*su,
3140     char_u	*goodword,
3141     int		score,		// soundfold score
3142     langp_T	*lp)
3143 {
3144     slang_T	*slang = lp->lp_slang;	// language for sound folding
3145     int		sfwordnr;
3146     char_u	*nrline;
3147     int		orgnr;
3148     char_u	theword[MAXWLEN];
3149     int		i;
3150     int		wlen;
3151     char_u	*byts;
3152     idx_T	*idxs;
3153     int		n;
3154     int		wordcount;
3155     int		wc;
3156     int		goodscore;
3157     hash_T	hash;
3158     hashitem_T  *hi;
3159     sftword_T	*sft;
3160     int		bc, gc;
3161     int		limit;
3162 
3163     // It's very well possible that the same soundfold word is found several
3164     // times with different scores.  Since the following is quite slow only do
3165     // the words that have a better score than before.  Use a hashtable to
3166     // remember the words that have been done.
3167     hash = hash_hash(goodword);
3168     hi = hash_lookup(&slang->sl_sounddone, goodword, hash);
3169     if (HASHITEM_EMPTY(hi))
3170     {
3171 	sft = alloc(sizeof(sftword_T) + STRLEN(goodword));
3172 	if (sft != NULL)
3173 	{
3174 	    sft->sft_score = score;
3175 	    STRCPY(sft->sft_word, goodword);
3176 	    hash_add_item(&slang->sl_sounddone, hi, sft->sft_word, hash);
3177 	}
3178     }
3179     else
3180     {
3181 	sft = HI2SFT(hi);
3182 	if (score >= sft->sft_score)
3183 	    return;
3184 	sft->sft_score = score;
3185     }
3186 
3187     // Find the word nr in the soundfold tree.
3188     sfwordnr = soundfold_find(slang, goodword);
3189     if (sfwordnr < 0)
3190     {
3191 	internal_error("add_sound_suggest()");
3192 	return;
3193     }
3194 
3195     // go over the list of good words that produce this soundfold word
3196     nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)(sfwordnr + 1), FALSE);
3197     orgnr = 0;
3198     while (*nrline != NUL)
3199     {
3200 	// The wordnr was stored in a minimal nr of bytes as an offset to the
3201 	// previous wordnr.
3202 	orgnr += bytes2offset(&nrline);
3203 
3204 	byts = slang->sl_fbyts;
3205 	idxs = slang->sl_fidxs;
3206 
3207 	// Lookup the word "orgnr" one of the two tries.
3208 	n = 0;
3209 	wordcount = 0;
3210 	for (wlen = 0; wlen < MAXWLEN - 3; ++wlen)
3211 	{
3212 	    i = 1;
3213 	    if (wordcount == orgnr && byts[n + 1] == NUL)
3214 		break;	// found end of word
3215 
3216 	    if (byts[n + 1] == NUL)
3217 		++wordcount;
3218 
3219 	    // skip over the NUL bytes
3220 	    for ( ; byts[n + i] == NUL; ++i)
3221 		if (i > byts[n])	// safety check
3222 		{
3223 		    STRCPY(theword + wlen, "BAD");
3224 		    wlen += 3;
3225 		    goto badword;
3226 		}
3227 
3228 	    // One of the siblings must have the word.
3229 	    for ( ; i < byts[n]; ++i)
3230 	    {
3231 		wc = idxs[idxs[n + i]];	// nr of words under this byte
3232 		if (wordcount + wc > orgnr)
3233 		    break;
3234 		wordcount += wc;
3235 	    }
3236 
3237 	    theword[wlen] = byts[n + i];
3238 	    n = idxs[n + i];
3239 	}
3240 badword:
3241 	theword[wlen] = NUL;
3242 
3243 	// Go over the possible flags and regions.
3244 	for (; i <= byts[n] && byts[n + i] == NUL; ++i)
3245 	{
3246 	    char_u	cword[MAXWLEN];
3247 	    char_u	*p;
3248 	    int		flags = (int)idxs[n + i];
3249 
3250 	    // Skip words with the NOSUGGEST flag
3251 	    if (flags & WF_NOSUGGEST)
3252 		continue;
3253 
3254 	    if (flags & WF_KEEPCAP)
3255 	    {
3256 		// Must find the word in the keep-case tree.
3257 		find_keepcap_word(slang, theword, cword);
3258 		p = cword;
3259 	    }
3260 	    else
3261 	    {
3262 		flags |= su->su_badflags;
3263 		if ((flags & WF_CAPMASK) != 0)
3264 		{
3265 		    // Need to fix case according to "flags".
3266 		    make_case_word(theword, cword, flags);
3267 		    p = cword;
3268 		}
3269 		else
3270 		    p = theword;
3271 	    }
3272 
3273 	    // Add the suggestion.
3274 	    if (sps_flags & SPS_DOUBLE)
3275 	    {
3276 		// Add the suggestion if the score isn't too bad.
3277 		if (score <= su->su_maxscore)
3278 		    add_suggestion(su, &su->su_sga, p, su->su_badlen,
3279 					       score, 0, FALSE, slang, FALSE);
3280 	    }
3281 	    else
3282 	    {
3283 		// Add a penalty for words in another region.
3284 		if ((flags & WF_REGION)
3285 			    && (((unsigned)flags >> 16) & lp->lp_region) == 0)
3286 		    goodscore = SCORE_REGION;
3287 		else
3288 		    goodscore = 0;
3289 
3290 		// Add a small penalty for changing the first letter from
3291 		// lower to upper case.  Helps for "tath" -> "Kath", which is
3292 		// less common than "tath" -> "path".  Don't do it when the
3293 		// letter is the same, that has already been counted.
3294 		gc = PTR2CHAR(p);
3295 		if (SPELL_ISUPPER(gc))
3296 		{
3297 		    bc = PTR2CHAR(su->su_badword);
3298 		    if (!SPELL_ISUPPER(bc)
3299 				      && SPELL_TOFOLD(bc) != SPELL_TOFOLD(gc))
3300 			goodscore += SCORE_ICASE / 2;
3301 		}
3302 
3303 		// Compute the score for the good word.  This only does letter
3304 		// insert/delete/swap/replace.  REP items are not considered,
3305 		// which may make the score a bit higher.
3306 		// Use a limit for the score to make it work faster.  Use
3307 		// MAXSCORE(), because RESCORE() will change the score.
3308 		// If the limit is very high then the iterative method is
3309 		// inefficient, using an array is quicker.
3310 		limit = MAXSCORE(su->su_sfmaxscore - goodscore, score);
3311 		if (limit > SCORE_LIMITMAX)
3312 		    goodscore += spell_edit_score(slang, su->su_badword, p);
3313 		else
3314 		    goodscore += spell_edit_score_limit(slang, su->su_badword,
3315 								    p, limit);
3316 
3317 		// When going over the limit don't bother to do the rest.
3318 		if (goodscore < SCORE_MAXMAX)
3319 		{
3320 		    // Give a bonus to words seen before.
3321 		    goodscore = score_wordcount_adj(slang, goodscore, p, FALSE);
3322 
3323 		    // Add the suggestion if the score isn't too bad.
3324 		    goodscore = RESCORE(goodscore, score);
3325 		    if (goodscore <= su->su_sfmaxscore)
3326 			add_suggestion(su, &su->su_ga, p, su->su_badlen,
3327 					 goodscore, score, TRUE, slang, TRUE);
3328 		}
3329 	    }
3330 	}
3331 	// smsg("word %s (%d): %s (%d)", sftword, sftnr, theword, orgnr);
3332     }
3333 }
3334 
3335 /*
3336  * Find word "word" in fold-case tree for "slang" and return the word number.
3337  */
3338     static int
3339 soundfold_find(slang_T *slang, char_u *word)
3340 {
3341     idx_T	arridx = 0;
3342     int		len;
3343     int		wlen = 0;
3344     int		c;
3345     char_u	*ptr = word;
3346     char_u	*byts;
3347     idx_T	*idxs;
3348     int		wordnr = 0;
3349 
3350     byts = slang->sl_sbyts;
3351     idxs = slang->sl_sidxs;
3352 
3353     for (;;)
3354     {
3355 	// First byte is the number of possible bytes.
3356 	len = byts[arridx++];
3357 
3358 	// If the first possible byte is a zero the word could end here.
3359 	// If the word ends we found the word.  If not skip the NUL bytes.
3360 	c = ptr[wlen];
3361 	if (byts[arridx] == NUL)
3362 	{
3363 	    if (c == NUL)
3364 		break;
3365 
3366 	    // Skip over the zeros, there can be several.
3367 	    while (len > 0 && byts[arridx] == NUL)
3368 	    {
3369 		++arridx;
3370 		--len;
3371 	    }
3372 	    if (len == 0)
3373 		return -1;    // no children, word should have ended here
3374 	    ++wordnr;
3375 	}
3376 
3377 	// If the word ends we didn't find it.
3378 	if (c == NUL)
3379 	    return -1;
3380 
3381 	// Perform a binary search in the list of accepted bytes.
3382 	if (c == TAB)	    // <Tab> is handled like <Space>
3383 	    c = ' ';
3384 	while (byts[arridx] < c)
3385 	{
3386 	    // The word count is in the first idxs[] entry of the child.
3387 	    wordnr += idxs[idxs[arridx]];
3388 	    ++arridx;
3389 	    if (--len == 0)	// end of the bytes, didn't find it
3390 		return -1;
3391 	}
3392 	if (byts[arridx] != c)	// didn't find the byte
3393 	    return -1;
3394 
3395 	// Continue at the child (if there is one).
3396 	arridx = idxs[arridx];
3397 	++wlen;
3398 
3399 	// One space in the good word may stand for several spaces in the
3400 	// checked word.
3401 	if (c == ' ')
3402 	    while (ptr[wlen] == ' ' || ptr[wlen] == TAB)
3403 		++wlen;
3404     }
3405 
3406     return wordnr;
3407 }
3408 
3409 /*
3410  * Return TRUE if "c1" and "c2" are similar characters according to the MAP
3411  * lines in the .aff file.
3412  */
3413     static int
3414 similar_chars(slang_T *slang, int c1, int c2)
3415 {
3416     int		m1, m2;
3417     char_u	buf[MB_MAXBYTES + 1];
3418     hashitem_T  *hi;
3419 
3420     if (c1 >= 256)
3421     {
3422 	buf[mb_char2bytes(c1, buf)] = 0;
3423 	hi = hash_find(&slang->sl_map_hash, buf);
3424 	if (HASHITEM_EMPTY(hi))
3425 	    m1 = 0;
3426 	else
3427 	    m1 = mb_ptr2char(hi->hi_key + STRLEN(hi->hi_key) + 1);
3428     }
3429     else
3430 	m1 = slang->sl_map_array[c1];
3431     if (m1 == 0)
3432 	return FALSE;
3433 
3434 
3435     if (c2 >= 256)
3436     {
3437 	buf[mb_char2bytes(c2, buf)] = 0;
3438 	hi = hash_find(&slang->sl_map_hash, buf);
3439 	if (HASHITEM_EMPTY(hi))
3440 	    m2 = 0;
3441 	else
3442 	    m2 = mb_ptr2char(hi->hi_key + STRLEN(hi->hi_key) + 1);
3443     }
3444     else
3445 	m2 = slang->sl_map_array[c2];
3446 
3447     return m1 == m2;
3448 }
3449 
3450 /*
3451  * Add a suggestion to the list of suggestions.
3452  * For a suggestion that is already in the list the lowest score is remembered.
3453  */
3454     static void
3455 add_suggestion(
3456     suginfo_T	*su,
3457     garray_T	*gap,		// either su_ga or su_sga
3458     char_u	*goodword,
3459     int		badlenarg,	// len of bad word replaced with "goodword"
3460     int		score,
3461     int		altscore,
3462     int		had_bonus,	// value for st_had_bonus
3463     slang_T	*slang,		// language for sound folding
3464     int		maxsf)		// su_maxscore applies to soundfold score,
3465 				// su_sfmaxscore to the total score.
3466 {
3467     int		goodlen;	// len of goodword changed
3468     int		badlen;		// len of bad word changed
3469     suggest_T   *stp;
3470     suggest_T   new_sug;
3471     int		i;
3472     char_u	*pgood, *pbad;
3473 
3474     // Minimize "badlen" for consistency.  Avoids that changing "the the" to
3475     // "thee the" is added next to changing the first "the" the "thee".
3476     pgood = goodword + STRLEN(goodword);
3477     pbad = su->su_badptr + badlenarg;
3478     for (;;)
3479     {
3480 	goodlen = (int)(pgood - goodword);
3481 	badlen = (int)(pbad - su->su_badptr);
3482 	if (goodlen <= 0 || badlen <= 0)
3483 	    break;
3484 	MB_PTR_BACK(goodword, pgood);
3485 	MB_PTR_BACK(su->su_badptr, pbad);
3486 	if (has_mbyte)
3487 	{
3488 	    if (mb_ptr2char(pgood) != mb_ptr2char(pbad))
3489 		break;
3490 	}
3491 	else if (*pgood != *pbad)
3492 		break;
3493     }
3494 
3495     if (badlen == 0 && goodlen == 0)
3496 	// goodword doesn't change anything; may happen for "the the" changing
3497 	// the first "the" to itself.
3498 	return;
3499 
3500     if (gap->ga_len == 0)
3501 	i = -1;
3502     else
3503     {
3504 	// Check if the word is already there.  Also check the length that is
3505 	// being replaced "thes," -> "these" is a different suggestion from
3506 	// "thes" -> "these".
3507 	stp = &SUG(*gap, 0);
3508 	for (i = gap->ga_len; --i >= 0; ++stp)
3509 	    if (stp->st_wordlen == goodlen
3510 		    && stp->st_orglen == badlen
3511 		    && STRNCMP(stp->st_word, goodword, goodlen) == 0)
3512 	    {
3513 		// Found it.  Remember the word with the lowest score.
3514 		if (stp->st_slang == NULL)
3515 		    stp->st_slang = slang;
3516 
3517 		new_sug.st_score = score;
3518 		new_sug.st_altscore = altscore;
3519 		new_sug.st_had_bonus = had_bonus;
3520 
3521 		if (stp->st_had_bonus != had_bonus)
3522 		{
3523 		    // Only one of the two had the soundalike score computed.
3524 		    // Need to do that for the other one now, otherwise the
3525 		    // scores can't be compared.  This happens because
3526 		    // suggest_try_change() doesn't compute the soundalike
3527 		    // word to keep it fast, while some special methods set
3528 		    // the soundalike score to zero.
3529 		    if (had_bonus)
3530 			rescore_one(su, stp);
3531 		    else
3532 		    {
3533 			new_sug.st_word = stp->st_word;
3534 			new_sug.st_wordlen = stp->st_wordlen;
3535 			new_sug.st_slang = stp->st_slang;
3536 			new_sug.st_orglen = badlen;
3537 			rescore_one(su, &new_sug);
3538 		    }
3539 		}
3540 
3541 		if (stp->st_score > new_sug.st_score)
3542 		{
3543 		    stp->st_score = new_sug.st_score;
3544 		    stp->st_altscore = new_sug.st_altscore;
3545 		    stp->st_had_bonus = new_sug.st_had_bonus;
3546 		}
3547 		break;
3548 	    }
3549     }
3550 
3551     if (i < 0 && ga_grow(gap, 1) == OK)
3552     {
3553 	// Add a suggestion.
3554 	stp = &SUG(*gap, gap->ga_len);
3555 	stp->st_word = vim_strnsave(goodword, goodlen);
3556 	if (stp->st_word != NULL)
3557 	{
3558 	    stp->st_wordlen = goodlen;
3559 	    stp->st_score = score;
3560 	    stp->st_altscore = altscore;
3561 	    stp->st_had_bonus = had_bonus;
3562 	    stp->st_orglen = badlen;
3563 	    stp->st_slang = slang;
3564 	    ++gap->ga_len;
3565 
3566 	    // If we have too many suggestions now, sort the list and keep
3567 	    // the best suggestions.
3568 	    if (gap->ga_len > SUG_MAX_COUNT(su))
3569 	    {
3570 		if (maxsf)
3571 		    su->su_sfmaxscore = cleanup_suggestions(gap,
3572 				      su->su_sfmaxscore, SUG_CLEAN_COUNT(su));
3573 		else
3574 		    su->su_maxscore = cleanup_suggestions(gap,
3575 					su->su_maxscore, SUG_CLEAN_COUNT(su));
3576 	    }
3577 	}
3578     }
3579 }
3580 
3581 /*
3582  * Suggestions may in fact be flagged as errors.  Esp. for banned words and
3583  * for split words, such as "the the".  Remove these from the list here.
3584  */
3585     static void
3586 check_suggestions(
3587     suginfo_T	*su,
3588     garray_T	*gap)		    // either su_ga or su_sga
3589 {
3590     suggest_T   *stp;
3591     int		i;
3592     char_u	longword[MAXWLEN + 1];
3593     int		len;
3594     hlf_T	attr;
3595 
3596     stp = &SUG(*gap, 0);
3597     for (i = gap->ga_len - 1; i >= 0; --i)
3598     {
3599 	// Need to append what follows to check for "the the".
3600 	vim_strncpy(longword, stp[i].st_word, MAXWLEN);
3601 	len = stp[i].st_wordlen;
3602 	vim_strncpy(longword + len, su->su_badptr + stp[i].st_orglen,
3603 							       MAXWLEN - len);
3604 	attr = HLF_COUNT;
3605 	(void)spell_check(curwin, longword, &attr, NULL, FALSE);
3606 	if (attr != HLF_COUNT)
3607 	{
3608 	    // Remove this entry.
3609 	    vim_free(stp[i].st_word);
3610 	    --gap->ga_len;
3611 	    if (i < gap->ga_len)
3612 		mch_memmove(stp + i, stp + i + 1,
3613 				       sizeof(suggest_T) * (gap->ga_len - i));
3614 	}
3615     }
3616 }
3617 
3618 
3619 /*
3620  * Add a word to be banned.
3621  */
3622     static void
3623 add_banned(
3624     suginfo_T	*su,
3625     char_u	*word)
3626 {
3627     char_u	*s;
3628     hash_T	hash;
3629     hashitem_T	*hi;
3630 
3631     hash = hash_hash(word);
3632     hi = hash_lookup(&su->su_banned, word, hash);
3633     if (HASHITEM_EMPTY(hi))
3634     {
3635 	s = vim_strsave(word);
3636 	if (s != NULL)
3637 	    hash_add_item(&su->su_banned, hi, s, hash);
3638     }
3639 }
3640 
3641 /*
3642  * Recompute the score for all suggestions if sound-folding is possible.  This
3643  * is slow, thus only done for the final results.
3644  */
3645     static void
3646 rescore_suggestions(suginfo_T *su)
3647 {
3648     int		i;
3649 
3650     if (su->su_sallang != NULL)
3651 	for (i = 0; i < su->su_ga.ga_len; ++i)
3652 	    rescore_one(su, &SUG(su->su_ga, i));
3653 }
3654 
3655 /*
3656  * Recompute the score for one suggestion if sound-folding is possible.
3657  */
3658     static void
3659 rescore_one(suginfo_T *su, suggest_T *stp)
3660 {
3661     slang_T	*slang = stp->st_slang;
3662     char_u	sal_badword[MAXWLEN];
3663     char_u	*p;
3664 
3665     // Only rescore suggestions that have no sal score yet and do have a
3666     // language.
3667     if (slang != NULL && slang->sl_sal.ga_len > 0 && !stp->st_had_bonus)
3668     {
3669 	if (slang == su->su_sallang)
3670 	    p = su->su_sal_badword;
3671 	else
3672 	{
3673 	    spell_soundfold(slang, su->su_fbadword, TRUE, sal_badword);
3674 	    p = sal_badword;
3675 	}
3676 
3677 	stp->st_altscore = stp_sal_score(stp, su, slang, p);
3678 	if (stp->st_altscore == SCORE_MAXMAX)
3679 	    stp->st_altscore = SCORE_BIG;
3680 	stp->st_score = RESCORE(stp->st_score, stp->st_altscore);
3681 	stp->st_had_bonus = TRUE;
3682     }
3683 }
3684 
3685 static int sug_compare(const void *s1, const void *s2);
3686 
3687 /*
3688  * Function given to qsort() to sort the suggestions on st_score.
3689  * First on "st_score", then "st_altscore" then alphabetically.
3690  */
3691     static int
3692 sug_compare(const void *s1, const void *s2)
3693 {
3694     suggest_T	*p1 = (suggest_T *)s1;
3695     suggest_T	*p2 = (suggest_T *)s2;
3696     int		n = p1->st_score - p2->st_score;
3697 
3698     if (n == 0)
3699     {
3700 	n = p1->st_altscore - p2->st_altscore;
3701 	if (n == 0)
3702 	    n = STRICMP(p1->st_word, p2->st_word);
3703     }
3704     return n;
3705 }
3706 
3707 /*
3708  * Cleanup the suggestions:
3709  * - Sort on score.
3710  * - Remove words that won't be displayed.
3711  * Returns the maximum score in the list or "maxscore" unmodified.
3712  */
3713     static int
3714 cleanup_suggestions(
3715     garray_T	*gap,
3716     int		maxscore,
3717     int		keep)		// nr of suggestions to keep
3718 {
3719     suggest_T   *stp = &SUG(*gap, 0);
3720     int		i;
3721 
3722     if (gap->ga_len > 0)
3723     {
3724 	// Sort the list.
3725 	qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T),
3726 								  sug_compare);
3727 
3728 	// Truncate the list to the number of suggestions that will be
3729 	// displayed.
3730 	if (gap->ga_len > keep)
3731 	{
3732 	    for (i = keep; i < gap->ga_len; ++i)
3733 		vim_free(stp[i].st_word);
3734 	    gap->ga_len = keep;
3735 	    if (keep >= 1)
3736 		return stp[keep - 1].st_score;
3737 	}
3738     }
3739     return maxscore;
3740 }
3741 
3742 /*
3743  * Compute a score for two sound-a-like words.
3744  * This permits up to two inserts/deletes/swaps/etc. to keep things fast.
3745  * Instead of a generic loop we write out the code.  That keeps it fast by
3746  * avoiding checks that will not be possible.
3747  */
3748     static int
3749 soundalike_score(
3750     char_u	*goodstart,	// sound-folded good word
3751     char_u	*badstart)	// sound-folded bad word
3752 {
3753     char_u	*goodsound = goodstart;
3754     char_u	*badsound = badstart;
3755     int		goodlen;
3756     int		badlen;
3757     int		n;
3758     char_u	*pl, *ps;
3759     char_u	*pl2, *ps2;
3760     int		score = 0;
3761 
3762     // Adding/inserting "*" at the start (word starts with vowel) shouldn't be
3763     // counted so much, vowels halfway the word aren't counted at all.
3764     if ((*badsound == '*' || *goodsound == '*') && *badsound != *goodsound)
3765     {
3766 	if ((badsound[0] == NUL && goodsound[1] == NUL)
3767 	    || (goodsound[0] == NUL && badsound[1] == NUL))
3768 	    // changing word with vowel to word without a sound
3769 	    return SCORE_DEL;
3770 	if (badsound[0] == NUL || goodsound[0] == NUL)
3771 	    // more than two changes
3772 	    return SCORE_MAXMAX;
3773 
3774 	if (badsound[1] == goodsound[1]
3775 		|| (badsound[1] != NUL
3776 		    && goodsound[1] != NUL
3777 		    && badsound[2] == goodsound[2]))
3778 	{
3779 	    // handle like a substitute
3780 	}
3781 	else
3782 	{
3783 	    score = 2 * SCORE_DEL / 3;
3784 	    if (*badsound == '*')
3785 		++badsound;
3786 	    else
3787 		++goodsound;
3788 	}
3789     }
3790 
3791     goodlen = (int)STRLEN(goodsound);
3792     badlen = (int)STRLEN(badsound);
3793 
3794     // Return quickly if the lengths are too different to be fixed by two
3795     // changes.
3796     n = goodlen - badlen;
3797     if (n < -2 || n > 2)
3798 	return SCORE_MAXMAX;
3799 
3800     if (n > 0)
3801     {
3802 	pl = goodsound;	    // goodsound is longest
3803 	ps = badsound;
3804     }
3805     else
3806     {
3807 	pl = badsound;	    // badsound is longest
3808 	ps = goodsound;
3809     }
3810 
3811     // Skip over the identical part.
3812     while (*pl == *ps && *pl != NUL)
3813     {
3814 	++pl;
3815 	++ps;
3816     }
3817 
3818     switch (n)
3819     {
3820 	case -2:
3821 	case 2:
3822 	    // Must delete two characters from "pl".
3823 	    ++pl;	// first delete
3824 	    while (*pl == *ps)
3825 	    {
3826 		++pl;
3827 		++ps;
3828 	    }
3829 	    // strings must be equal after second delete
3830 	    if (STRCMP(pl + 1, ps) == 0)
3831 		return score + SCORE_DEL * 2;
3832 
3833 	    // Failed to compare.
3834 	    break;
3835 
3836 	case -1:
3837 	case 1:
3838 	    // Minimal one delete from "pl" required.
3839 
3840 	    // 1: delete
3841 	    pl2 = pl + 1;
3842 	    ps2 = ps;
3843 	    while (*pl2 == *ps2)
3844 	    {
3845 		if (*pl2 == NUL)	// reached the end
3846 		    return score + SCORE_DEL;
3847 		++pl2;
3848 		++ps2;
3849 	    }
3850 
3851 	    // 2: delete then swap, then rest must be equal
3852 	    if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
3853 					     && STRCMP(pl2 + 2, ps2 + 2) == 0)
3854 		return score + SCORE_DEL + SCORE_SWAP;
3855 
3856 	    // 3: delete then substitute, then the rest must be equal
3857 	    if (STRCMP(pl2 + 1, ps2 + 1) == 0)
3858 		return score + SCORE_DEL + SCORE_SUBST;
3859 
3860 	    // 4: first swap then delete
3861 	    if (pl[0] == ps[1] && pl[1] == ps[0])
3862 	    {
3863 		pl2 = pl + 2;	    // swap, skip two chars
3864 		ps2 = ps + 2;
3865 		while (*pl2 == *ps2)
3866 		{
3867 		    ++pl2;
3868 		    ++ps2;
3869 		}
3870 		// delete a char and then strings must be equal
3871 		if (STRCMP(pl2 + 1, ps2) == 0)
3872 		    return score + SCORE_SWAP + SCORE_DEL;
3873 	    }
3874 
3875 	    // 5: first substitute then delete
3876 	    pl2 = pl + 1;	    // substitute, skip one char
3877 	    ps2 = ps + 1;
3878 	    while (*pl2 == *ps2)
3879 	    {
3880 		++pl2;
3881 		++ps2;
3882 	    }
3883 	    // delete a char and then strings must be equal
3884 	    if (STRCMP(pl2 + 1, ps2) == 0)
3885 		return score + SCORE_SUBST + SCORE_DEL;
3886 
3887 	    // Failed to compare.
3888 	    break;
3889 
3890 	case 0:
3891 	    // Lengths are equal, thus changes must result in same length: An
3892 	    // insert is only possible in combination with a delete.
3893 	    // 1: check if for identical strings
3894 	    if (*pl == NUL)
3895 		return score;
3896 
3897 	    // 2: swap
3898 	    if (pl[0] == ps[1] && pl[1] == ps[0])
3899 	    {
3900 		pl2 = pl + 2;	    // swap, skip two chars
3901 		ps2 = ps + 2;
3902 		while (*pl2 == *ps2)
3903 		{
3904 		    if (*pl2 == NUL)	// reached the end
3905 			return score + SCORE_SWAP;
3906 		    ++pl2;
3907 		    ++ps2;
3908 		}
3909 		// 3: swap and swap again
3910 		if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
3911 					     && STRCMP(pl2 + 2, ps2 + 2) == 0)
3912 		    return score + SCORE_SWAP + SCORE_SWAP;
3913 
3914 		// 4: swap and substitute
3915 		if (STRCMP(pl2 + 1, ps2 + 1) == 0)
3916 		    return score + SCORE_SWAP + SCORE_SUBST;
3917 	    }
3918 
3919 	    // 5: substitute
3920 	    pl2 = pl + 1;
3921 	    ps2 = ps + 1;
3922 	    while (*pl2 == *ps2)
3923 	    {
3924 		if (*pl2 == NUL)	// reached the end
3925 		    return score + SCORE_SUBST;
3926 		++pl2;
3927 		++ps2;
3928 	    }
3929 
3930 	    // 6: substitute and swap
3931 	    if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
3932 					     && STRCMP(pl2 + 2, ps2 + 2) == 0)
3933 		return score + SCORE_SUBST + SCORE_SWAP;
3934 
3935 	    // 7: substitute and substitute
3936 	    if (STRCMP(pl2 + 1, ps2 + 1) == 0)
3937 		return score + SCORE_SUBST + SCORE_SUBST;
3938 
3939 	    // 8: insert then delete
3940 	    pl2 = pl;
3941 	    ps2 = ps + 1;
3942 	    while (*pl2 == *ps2)
3943 	    {
3944 		++pl2;
3945 		++ps2;
3946 	    }
3947 	    if (STRCMP(pl2 + 1, ps2) == 0)
3948 		return score + SCORE_INS + SCORE_DEL;
3949 
3950 	    // 9: delete then insert
3951 	    pl2 = pl + 1;
3952 	    ps2 = ps;
3953 	    while (*pl2 == *ps2)
3954 	    {
3955 		++pl2;
3956 		++ps2;
3957 	    }
3958 	    if (STRCMP(pl2, ps2 + 1) == 0)
3959 		return score + SCORE_INS + SCORE_DEL;
3960 
3961 	    // Failed to compare.
3962 	    break;
3963     }
3964 
3965     return SCORE_MAXMAX;
3966 }
3967 
3968 /*
3969  * Compute the "edit distance" to turn "badword" into "goodword".  The less
3970  * deletes/inserts/substitutes/swaps are required the lower the score.
3971  *
3972  * The algorithm is described by Du and Chang, 1992.
3973  * The implementation of the algorithm comes from Aspell editdist.cpp,
3974  * edit_distance().  It has been converted from C++ to C and modified to
3975  * support multi-byte characters.
3976  */
3977     static int
3978 spell_edit_score(
3979     slang_T	*slang,
3980     char_u	*badword,
3981     char_u	*goodword)
3982 {
3983     int		*cnt;
3984     int		badlen, goodlen;	// lengths including NUL
3985     int		j, i;
3986     int		t;
3987     int		bc, gc;
3988     int		pbc, pgc;
3989     char_u	*p;
3990     int		wbadword[MAXWLEN];
3991     int		wgoodword[MAXWLEN];
3992 
3993     if (has_mbyte)
3994     {
3995 	// Get the characters from the multi-byte strings and put them in an
3996 	// int array for easy access.
3997 	for (p = badword, badlen = 0; *p != NUL; )
3998 	    wbadword[badlen++] = mb_cptr2char_adv(&p);
3999 	wbadword[badlen++] = 0;
4000 	for (p = goodword, goodlen = 0; *p != NUL; )
4001 	    wgoodword[goodlen++] = mb_cptr2char_adv(&p);
4002 	wgoodword[goodlen++] = 0;
4003     }
4004     else
4005     {
4006 	badlen = (int)STRLEN(badword) + 1;
4007 	goodlen = (int)STRLEN(goodword) + 1;
4008     }
4009 
4010     // We use "cnt" as an array: CNT(badword_idx, goodword_idx).
4011 #define CNT(a, b)   cnt[(a) + (b) * (badlen + 1)]
4012     cnt = ALLOC_MULT(int, (badlen + 1) * (goodlen + 1));
4013     if (cnt == NULL)
4014 	return 0;	// out of memory
4015 
4016     CNT(0, 0) = 0;
4017     for (j = 1; j <= goodlen; ++j)
4018 	CNT(0, j) = CNT(0, j - 1) + SCORE_INS;
4019 
4020     for (i = 1; i <= badlen; ++i)
4021     {
4022 	CNT(i, 0) = CNT(i - 1, 0) + SCORE_DEL;
4023 	for (j = 1; j <= goodlen; ++j)
4024 	{
4025 	    if (has_mbyte)
4026 	    {
4027 		bc = wbadword[i - 1];
4028 		gc = wgoodword[j - 1];
4029 	    }
4030 	    else
4031 	    {
4032 		bc = badword[i - 1];
4033 		gc = goodword[j - 1];
4034 	    }
4035 	    if (bc == gc)
4036 		CNT(i, j) = CNT(i - 1, j - 1);
4037 	    else
4038 	    {
4039 		// Use a better score when there is only a case difference.
4040 		if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
4041 		    CNT(i, j) = SCORE_ICASE + CNT(i - 1, j - 1);
4042 		else
4043 		{
4044 		    // For a similar character use SCORE_SIMILAR.
4045 		    if (slang != NULL
4046 			    && slang->sl_has_map
4047 			    && similar_chars(slang, gc, bc))
4048 			CNT(i, j) = SCORE_SIMILAR + CNT(i - 1, j - 1);
4049 		    else
4050 			CNT(i, j) = SCORE_SUBST + CNT(i - 1, j - 1);
4051 		}
4052 
4053 		if (i > 1 && j > 1)
4054 		{
4055 		    if (has_mbyte)
4056 		    {
4057 			pbc = wbadword[i - 2];
4058 			pgc = wgoodword[j - 2];
4059 		    }
4060 		    else
4061 		    {
4062 			pbc = badword[i - 2];
4063 			pgc = goodword[j - 2];
4064 		    }
4065 		    if (bc == pgc && pbc == gc)
4066 		    {
4067 			t = SCORE_SWAP + CNT(i - 2, j - 2);
4068 			if (t < CNT(i, j))
4069 			    CNT(i, j) = t;
4070 		    }
4071 		}
4072 		t = SCORE_DEL + CNT(i - 1, j);
4073 		if (t < CNT(i, j))
4074 		    CNT(i, j) = t;
4075 		t = SCORE_INS + CNT(i, j - 1);
4076 		if (t < CNT(i, j))
4077 		    CNT(i, j) = t;
4078 	    }
4079 	}
4080     }
4081 
4082     i = CNT(badlen - 1, goodlen - 1);
4083     vim_free(cnt);
4084     return i;
4085 }
4086 
4087 typedef struct
4088 {
4089     int		badi;
4090     int		goodi;
4091     int		score;
4092 } limitscore_T;
4093 
4094 /*
4095  * Like spell_edit_score(), but with a limit on the score to make it faster.
4096  * May return SCORE_MAXMAX when the score is higher than "limit".
4097  *
4098  * This uses a stack for the edits still to be tried.
4099  * The idea comes from Aspell leditdist.cpp.  Rewritten in C and added support
4100  * for multi-byte characters.
4101  */
4102     static int
4103 spell_edit_score_limit(
4104     slang_T	*slang,
4105     char_u	*badword,
4106     char_u	*goodword,
4107     int		limit)
4108 {
4109     limitscore_T    stack[10];		// allow for over 3 * 2 edits
4110     int		    stackidx;
4111     int		    bi, gi;
4112     int		    bi2, gi2;
4113     int		    bc, gc;
4114     int		    score;
4115     int		    score_off;
4116     int		    minscore;
4117     int		    round;
4118 
4119     // Multi-byte characters require a bit more work, use a different function
4120     // to avoid testing "has_mbyte" quite often.
4121     if (has_mbyte)
4122 	return spell_edit_score_limit_w(slang, badword, goodword, limit);
4123 
4124     // The idea is to go from start to end over the words.  So long as
4125     // characters are equal just continue, this always gives the lowest score.
4126     // When there is a difference try several alternatives.  Each alternative
4127     // increases "score" for the edit distance.  Some of the alternatives are
4128     // pushed unto a stack and tried later, some are tried right away.  At the
4129     // end of the word the score for one alternative is known.  The lowest
4130     // possible score is stored in "minscore".
4131     stackidx = 0;
4132     bi = 0;
4133     gi = 0;
4134     score = 0;
4135     minscore = limit + 1;
4136 
4137     for (;;)
4138     {
4139 	// Skip over an equal part, score remains the same.
4140 	for (;;)
4141 	{
4142 	    bc = badword[bi];
4143 	    gc = goodword[gi];
4144 	    if (bc != gc)	// stop at a char that's different
4145 		break;
4146 	    if (bc == NUL)	// both words end
4147 	    {
4148 		if (score < minscore)
4149 		    minscore = score;
4150 		goto pop;	// do next alternative
4151 	    }
4152 	    ++bi;
4153 	    ++gi;
4154 	}
4155 
4156 	if (gc == NUL)    // goodword ends, delete badword chars
4157 	{
4158 	    do
4159 	    {
4160 		if ((score += SCORE_DEL) >= minscore)
4161 		    goto pop;	    // do next alternative
4162 	    } while (badword[++bi] != NUL);
4163 	    minscore = score;
4164 	}
4165 	else if (bc == NUL) // badword ends, insert badword chars
4166 	{
4167 	    do
4168 	    {
4169 		if ((score += SCORE_INS) >= minscore)
4170 		    goto pop;	    // do next alternative
4171 	    } while (goodword[++gi] != NUL);
4172 	    minscore = score;
4173 	}
4174 	else			// both words continue
4175 	{
4176 	    // If not close to the limit, perform a change.  Only try changes
4177 	    // that may lead to a lower score than "minscore".
4178 	    // round 0: try deleting a char from badword
4179 	    // round 1: try inserting a char in badword
4180 	    for (round = 0; round <= 1; ++round)
4181 	    {
4182 		score_off = score + (round == 0 ? SCORE_DEL : SCORE_INS);
4183 		if (score_off < minscore)
4184 		{
4185 		    if (score_off + SCORE_EDIT_MIN >= minscore)
4186 		    {
4187 			// Near the limit, rest of the words must match.  We
4188 			// can check that right now, no need to push an item
4189 			// onto the stack.
4190 			bi2 = bi + 1 - round;
4191 			gi2 = gi + round;
4192 			while (goodword[gi2] == badword[bi2])
4193 			{
4194 			    if (goodword[gi2] == NUL)
4195 			    {
4196 				minscore = score_off;
4197 				break;
4198 			    }
4199 			    ++bi2;
4200 			    ++gi2;
4201 			}
4202 		    }
4203 		    else
4204 		    {
4205 			// try deleting/inserting a character later
4206 			stack[stackidx].badi = bi + 1 - round;
4207 			stack[stackidx].goodi = gi + round;
4208 			stack[stackidx].score = score_off;
4209 			++stackidx;
4210 		    }
4211 		}
4212 	    }
4213 
4214 	    if (score + SCORE_SWAP < minscore)
4215 	    {
4216 		// If swapping two characters makes a match then the
4217 		// substitution is more expensive, thus there is no need to
4218 		// try both.
4219 		if (gc == badword[bi + 1] && bc == goodword[gi + 1])
4220 		{
4221 		    // Swap two characters, that is: skip them.
4222 		    gi += 2;
4223 		    bi += 2;
4224 		    score += SCORE_SWAP;
4225 		    continue;
4226 		}
4227 	    }
4228 
4229 	    // Substitute one character for another which is the same
4230 	    // thing as deleting a character from both goodword and badword.
4231 	    // Use a better score when there is only a case difference.
4232 	    if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
4233 		score += SCORE_ICASE;
4234 	    else
4235 	    {
4236 		// For a similar character use SCORE_SIMILAR.
4237 		if (slang != NULL
4238 			&& slang->sl_has_map
4239 			&& similar_chars(slang, gc, bc))
4240 		    score += SCORE_SIMILAR;
4241 		else
4242 		    score += SCORE_SUBST;
4243 	    }
4244 
4245 	    if (score < minscore)
4246 	    {
4247 		// Do the substitution.
4248 		++gi;
4249 		++bi;
4250 		continue;
4251 	    }
4252 	}
4253 pop:
4254 	// Get here to try the next alternative, pop it from the stack.
4255 	if (stackidx == 0)		// stack is empty, finished
4256 	    break;
4257 
4258 	// pop an item from the stack
4259 	--stackidx;
4260 	gi = stack[stackidx].goodi;
4261 	bi = stack[stackidx].badi;
4262 	score = stack[stackidx].score;
4263     }
4264 
4265     // When the score goes over "limit" it may actually be much higher.
4266     // Return a very large number to avoid going below the limit when giving a
4267     // bonus.
4268     if (minscore > limit)
4269 	return SCORE_MAXMAX;
4270     return minscore;
4271 }
4272 
4273 /*
4274  * Multi-byte version of spell_edit_score_limit().
4275  * Keep it in sync with the above!
4276  */
4277     static int
4278 spell_edit_score_limit_w(
4279     slang_T	*slang,
4280     char_u	*badword,
4281     char_u	*goodword,
4282     int		limit)
4283 {
4284     limitscore_T    stack[10];		// allow for over 3 * 2 edits
4285     int		    stackidx;
4286     int		    bi, gi;
4287     int		    bi2, gi2;
4288     int		    bc, gc;
4289     int		    score;
4290     int		    score_off;
4291     int		    minscore;
4292     int		    round;
4293     char_u	    *p;
4294     int		    wbadword[MAXWLEN];
4295     int		    wgoodword[MAXWLEN];
4296 
4297     // Get the characters from the multi-byte strings and put them in an
4298     // int array for easy access.
4299     bi = 0;
4300     for (p = badword; *p != NUL; )
4301 	wbadword[bi++] = mb_cptr2char_adv(&p);
4302     wbadword[bi++] = 0;
4303     gi = 0;
4304     for (p = goodword; *p != NUL; )
4305 	wgoodword[gi++] = mb_cptr2char_adv(&p);
4306     wgoodword[gi++] = 0;
4307 
4308     // The idea is to go from start to end over the words.  So long as
4309     // characters are equal just continue, this always gives the lowest score.
4310     // When there is a difference try several alternatives.  Each alternative
4311     // increases "score" for the edit distance.  Some of the alternatives are
4312     // pushed unto a stack and tried later, some are tried right away.  At the
4313     // end of the word the score for one alternative is known.  The lowest
4314     // possible score is stored in "minscore".
4315     stackidx = 0;
4316     bi = 0;
4317     gi = 0;
4318     score = 0;
4319     minscore = limit + 1;
4320 
4321     for (;;)
4322     {
4323 	// Skip over an equal part, score remains the same.
4324 	for (;;)
4325 	{
4326 	    bc = wbadword[bi];
4327 	    gc = wgoodword[gi];
4328 
4329 	    if (bc != gc)	// stop at a char that's different
4330 		break;
4331 	    if (bc == NUL)	// both words end
4332 	    {
4333 		if (score < minscore)
4334 		    minscore = score;
4335 		goto pop;	// do next alternative
4336 	    }
4337 	    ++bi;
4338 	    ++gi;
4339 	}
4340 
4341 	if (gc == NUL)    // goodword ends, delete badword chars
4342 	{
4343 	    do
4344 	    {
4345 		if ((score += SCORE_DEL) >= minscore)
4346 		    goto pop;	    // do next alternative
4347 	    } while (wbadword[++bi] != NUL);
4348 	    minscore = score;
4349 	}
4350 	else if (bc == NUL) // badword ends, insert badword chars
4351 	{
4352 	    do
4353 	    {
4354 		if ((score += SCORE_INS) >= minscore)
4355 		    goto pop;	    // do next alternative
4356 	    } while (wgoodword[++gi] != NUL);
4357 	    minscore = score;
4358 	}
4359 	else			// both words continue
4360 	{
4361 	    // If not close to the limit, perform a change.  Only try changes
4362 	    // that may lead to a lower score than "minscore".
4363 	    // round 0: try deleting a char from badword
4364 	    // round 1: try inserting a char in badword
4365 	    for (round = 0; round <= 1; ++round)
4366 	    {
4367 		score_off = score + (round == 0 ? SCORE_DEL : SCORE_INS);
4368 		if (score_off < minscore)
4369 		{
4370 		    if (score_off + SCORE_EDIT_MIN >= minscore)
4371 		    {
4372 			// Near the limit, rest of the words must match.  We
4373 			// can check that right now, no need to push an item
4374 			// onto the stack.
4375 			bi2 = bi + 1 - round;
4376 			gi2 = gi + round;
4377 			while (wgoodword[gi2] == wbadword[bi2])
4378 			{
4379 			    if (wgoodword[gi2] == NUL)
4380 			    {
4381 				minscore = score_off;
4382 				break;
4383 			    }
4384 			    ++bi2;
4385 			    ++gi2;
4386 			}
4387 		    }
4388 		    else
4389 		    {
4390 			// try deleting a character from badword later
4391 			stack[stackidx].badi = bi + 1 - round;
4392 			stack[stackidx].goodi = gi + round;
4393 			stack[stackidx].score = score_off;
4394 			++stackidx;
4395 		    }
4396 		}
4397 	    }
4398 
4399 	    if (score + SCORE_SWAP < minscore)
4400 	    {
4401 		// If swapping two characters makes a match then the
4402 		// substitution is more expensive, thus there is no need to
4403 		// try both.
4404 		if (gc == wbadword[bi + 1] && bc == wgoodword[gi + 1])
4405 		{
4406 		    // Swap two characters, that is: skip them.
4407 		    gi += 2;
4408 		    bi += 2;
4409 		    score += SCORE_SWAP;
4410 		    continue;
4411 		}
4412 	    }
4413 
4414 	    // Substitute one character for another which is the same
4415 	    // thing as deleting a character from both goodword and badword.
4416 	    // Use a better score when there is only a case difference.
4417 	    if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
4418 		score += SCORE_ICASE;
4419 	    else
4420 	    {
4421 		// For a similar character use SCORE_SIMILAR.
4422 		if (slang != NULL
4423 			&& slang->sl_has_map
4424 			&& similar_chars(slang, gc, bc))
4425 		    score += SCORE_SIMILAR;
4426 		else
4427 		    score += SCORE_SUBST;
4428 	    }
4429 
4430 	    if (score < minscore)
4431 	    {
4432 		// Do the substitution.
4433 		++gi;
4434 		++bi;
4435 		continue;
4436 	    }
4437 	}
4438 pop:
4439 	// Get here to try the next alternative, pop it from the stack.
4440 	if (stackidx == 0)		// stack is empty, finished
4441 	    break;
4442 
4443 	// pop an item from the stack
4444 	--stackidx;
4445 	gi = stack[stackidx].goodi;
4446 	bi = stack[stackidx].badi;
4447 	score = stack[stackidx].score;
4448     }
4449 
4450     // When the score goes over "limit" it may actually be much higher.
4451     // Return a very large number to avoid going below the limit when giving a
4452     // bonus.
4453     if (minscore > limit)
4454 	return SCORE_MAXMAX;
4455     return minscore;
4456 }
4457 #endif  // FEAT_SPELL
4458