xref: /vim-8.2.3635/src/spell.c (revision 94688b8a)
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  * spell.c: code for spell checking
12  *
13  * See spellfile.c for the Vim spell file format.
14  *
15  * The spell checking mechanism uses a tree (aka trie).  Each node in the tree
16  * has a list of bytes that can appear (siblings).  For each byte there is a
17  * pointer to the node with the byte that follows in the word (child).
18  *
19  * A NUL byte is used where the word may end.  The bytes are sorted, so that
20  * binary searching can be used and the NUL bytes are at the start.  The
21  * number of possible bytes is stored before the list of bytes.
22  *
23  * The tree uses two arrays: "byts" stores the characters, "idxs" stores
24  * either the next index or flags.  The tree starts at index 0.  For example,
25  * to lookup "vi" this sequence is followed:
26  *	i = 0
27  *	len = byts[i]
28  *	n = where "v" appears in byts[i + 1] to byts[i + len]
29  *	i = idxs[n]
30  *	len = byts[i]
31  *	n = where "i" appears in byts[i + 1] to byts[i + len]
32  *	i = idxs[n]
33  *	len = byts[i]
34  *	find that byts[i + 1] is 0, idxs[i + 1] has flags for "vi".
35  *
36  * There are two word trees: one with case-folded words and one with words in
37  * original case.  The second one is only used for keep-case words and is
38  * usually small.
39  *
40  * There is one additional tree for when not all prefixes are applied when
41  * generating the .spl file.  This tree stores all the possible prefixes, as
42  * if they were words.  At each word (prefix) end the prefix nr is stored, the
43  * following word must support this prefix nr.  And the condition nr is
44  * stored, used to lookup the condition that the word must match with.
45  *
46  * Thanks to Olaf Seibert for providing an example implementation of this tree
47  * and the compression mechanism.
48  * LZ trie ideas:
49  *	http://www.irb.hr/hr/home/ristov/papers/RistovLZtrieRevision1.pdf
50  * More papers: http://www-igm.univ-mlv.fr/~laporte/publi_en.html
51  *
52  * Matching involves checking the caps type: Onecap ALLCAP KeepCap.
53  *
54  * Why doesn't Vim use aspell/ispell/myspell/etc.?
55  * See ":help develop-spell".
56  */
57 
58 /*
59  * Use this to adjust the score after finding suggestions, based on the
60  * suggested word sounding like the bad word.  This is much faster than doing
61  * it for every possible suggestion.
62  * Disadvantage: When "the" is typed as "hte" it sounds quite different ("@"
63  * vs "ht") and goes down in the list.
64  * Used when 'spellsuggest' is set to "best".
65  */
66 #define RESCORE(word_score, sound_score) ((3 * word_score + sound_score) / 4)
67 
68 /*
69  * Do the opposite: based on a maximum end score and a known sound score,
70  * compute the maximum word score that can be used.
71  */
72 #define MAXSCORE(word_score, sound_score) ((4 * word_score - sound_score) / 3)
73 
74 #define IN_SPELL_C
75 #include "vim.h"
76 
77 #if defined(FEAT_SPELL) || defined(PROTO)
78 
79 #ifndef UNIX		/* it's in os_unix.h for Unix */
80 # include <time.h>	/* for time_t */
81 #endif
82 
83 /* only used for su_badflags */
84 #define WF_MIXCAP   0x20	/* mix of upper and lower case: macaRONI */
85 
86 #define WF_CAPMASK (WF_ONECAP | WF_ALLCAP | WF_KEEPCAP | WF_FIXCAP)
87 
88 #define REGION_ALL 0xff		/* word valid in all regions */
89 
90 #define VIMSUGMAGIC "VIMsug"	/* string at start of Vim .sug file */
91 #define VIMSUGMAGICL 6
92 #define VIMSUGVERSION 1
93 
94 /* Result values.  Lower number is accepted over higher one. */
95 #define SP_BANNED	-1
96 #define SP_OK		0
97 #define SP_RARE		1
98 #define SP_LOCAL	2
99 #define SP_BAD		3
100 
101 typedef struct wordcount_S
102 {
103     short_u	wc_count;	    /* nr of times word was seen */
104     char_u	wc_word[1];	    /* word, actually longer */
105 } wordcount_T;
106 
107 #define WC_KEY_OFF  offsetof(wordcount_T, wc_word)
108 #define HI2WC(hi)     ((wordcount_T *)((hi)->hi_key - WC_KEY_OFF))
109 #define MAXWORDCOUNT 0xffff
110 
111 /*
112  * Information used when looking for suggestions.
113  */
114 typedef struct suginfo_S
115 {
116     garray_T	su_ga;		    /* suggestions, contains "suggest_T" */
117     int		su_maxcount;	    /* max. number of suggestions displayed */
118     int		su_maxscore;	    /* maximum score for adding to su_ga */
119     int		su_sfmaxscore;	    /* idem, for when doing soundfold words */
120     garray_T	su_sga;		    /* like su_ga, sound-folded scoring */
121     char_u	*su_badptr;	    /* start of bad word in line */
122     int		su_badlen;	    /* length of detected bad word in line */
123     int		su_badflags;	    /* caps flags for bad word */
124     char_u	su_badword[MAXWLEN]; /* bad word truncated at su_badlen */
125     char_u	su_fbadword[MAXWLEN]; /* su_badword case-folded */
126     char_u	su_sal_badword[MAXWLEN]; /* su_badword soundfolded */
127     hashtab_T	su_banned;	    /* table with banned words */
128     slang_T	*su_sallang;	    /* default language for sound folding */
129 } suginfo_T;
130 
131 /* One word suggestion.  Used in "si_ga". */
132 typedef struct suggest_S
133 {
134     char_u	*st_word;	/* suggested word, allocated string */
135     int		st_wordlen;	/* STRLEN(st_word) */
136     int		st_orglen;	/* length of replaced text */
137     int		st_score;	/* lower is better */
138     int		st_altscore;	/* used when st_score compares equal */
139     int		st_salscore;	/* st_score is for soundalike */
140     int		st_had_bonus;	/* bonus already included in score */
141     slang_T	*st_slang;	/* language used for sound folding */
142 } suggest_T;
143 
144 #define SUG(ga, i) (((suggest_T *)(ga).ga_data)[i])
145 
146 /* TRUE if a word appears in the list of banned words.  */
147 #define WAS_BANNED(su, word) (!HASHITEM_EMPTY(hash_find(&su->su_banned, word)))
148 
149 /* Number of suggestions kept when cleaning up.  We need to keep more than
150  * what is displayed, because when rescore_suggestions() is called the score
151  * may change and wrong suggestions may be removed later. */
152 #define SUG_CLEAN_COUNT(su)    ((su)->su_maxcount < 130 ? 150 : (su)->su_maxcount + 20)
153 
154 /* Threshold for sorting and cleaning up suggestions.  Don't want to keep lots
155  * of suggestions that are not going to be displayed. */
156 #define SUG_MAX_COUNT(su)	(SUG_CLEAN_COUNT(su) + 50)
157 
158 /* score for various changes */
159 #define SCORE_SPLIT	149	/* split bad word */
160 #define SCORE_SPLIT_NO	249	/* split bad word with NOSPLITSUGS */
161 #define SCORE_ICASE	52	/* slightly different case */
162 #define SCORE_REGION	200	/* word is for different region */
163 #define SCORE_RARE	180	/* rare word */
164 #define SCORE_SWAP	75	/* swap two characters */
165 #define SCORE_SWAP3	110	/* swap two characters in three */
166 #define SCORE_REP	65	/* REP replacement */
167 #define SCORE_SUBST	93	/* substitute a character */
168 #define SCORE_SIMILAR	33	/* substitute a similar character */
169 #define SCORE_SUBCOMP	33	/* substitute a composing character */
170 #define SCORE_DEL	94	/* delete a character */
171 #define SCORE_DELDUP	66	/* delete a duplicated character */
172 #define SCORE_DELCOMP	28	/* delete a composing character */
173 #define SCORE_INS	96	/* insert a character */
174 #define SCORE_INSDUP	67	/* insert a duplicate character */
175 #define SCORE_INSCOMP	30	/* insert a composing character */
176 #define SCORE_NONWORD	103	/* change non-word to word char */
177 
178 #define SCORE_FILE	30	/* suggestion from a file */
179 #define SCORE_MAXINIT	350	/* Initial maximum score: higher == slower.
180 				 * 350 allows for about three changes. */
181 
182 #define SCORE_COMMON1	30	/* subtracted for words seen before */
183 #define SCORE_COMMON2	40	/* subtracted for words often seen */
184 #define SCORE_COMMON3	50	/* subtracted for words very often seen */
185 #define SCORE_THRES2	10	/* word count threshold for COMMON2 */
186 #define SCORE_THRES3	100	/* word count threshold for COMMON3 */
187 
188 /* When trying changed soundfold words it becomes slow when trying more than
189  * two changes.  With less then two changes it's slightly faster but we miss a
190  * few good suggestions.  In rare cases we need to try three of four changes.
191  */
192 #define SCORE_SFMAX1	200	/* maximum score for first try */
193 #define SCORE_SFMAX2	300	/* maximum score for second try */
194 #define SCORE_SFMAX3	400	/* maximum score for third try */
195 
196 #define SCORE_BIG	SCORE_INS * 3	/* big difference */
197 #define SCORE_MAXMAX	999999		/* accept any score */
198 #define SCORE_LIMITMAX	350		/* for spell_edit_score_limit() */
199 
200 /* for spell_edit_score_limit() we need to know the minimum value of
201  * SCORE_ICASE, SCORE_SWAP, SCORE_DEL, SCORE_SIMILAR and SCORE_INS */
202 #define SCORE_EDIT_MIN	SCORE_SIMILAR
203 
204 /*
205  * Structure to store info for word matching.
206  */
207 typedef struct matchinf_S
208 {
209     langp_T	*mi_lp;			/* info for language and region */
210 
211     /* pointers to original text to be checked */
212     char_u	*mi_word;		/* start of word being checked */
213     char_u	*mi_end;		/* end of matching word so far */
214     char_u	*mi_fend;		/* next char to be added to mi_fword */
215     char_u	*mi_cend;		/* char after what was used for
216 					   mi_capflags */
217 
218     /* case-folded text */
219     char_u	mi_fword[MAXWLEN + 1];	/* mi_word case-folded */
220     int		mi_fwordlen;		/* nr of valid bytes in mi_fword */
221 
222     /* for when checking word after a prefix */
223     int		mi_prefarridx;		/* index in sl_pidxs with list of
224 					   affixID/condition */
225     int		mi_prefcnt;		/* number of entries at mi_prefarridx */
226     int		mi_prefixlen;		/* byte length of prefix */
227     int		mi_cprefixlen;		/* byte length of prefix in original
228 					   case */
229 
230     /* for when checking a compound word */
231     int		mi_compoff;		/* start of following word offset */
232     char_u	mi_compflags[MAXWLEN];	/* flags for compound words used */
233     int		mi_complen;		/* nr of compound words used */
234     int		mi_compextra;		/* nr of COMPOUNDROOT words */
235 
236     /* others */
237     int		mi_result;		/* result so far: SP_BAD, SP_OK, etc. */
238     int		mi_capflags;		/* WF_ONECAP WF_ALLCAP WF_KEEPCAP */
239     win_T	*mi_win;		/* buffer being checked */
240 
241     /* for NOBREAK */
242     int		mi_result2;		/* "mi_resul" without following word */
243     char_u	*mi_end2;		/* "mi_end" without following word */
244 } matchinf_T;
245 
246 
247 static int spell_iswordp(char_u *p, win_T *wp);
248 static int spell_mb_isword_class(int cl, win_T *wp);
249 
250 /*
251  * For finding suggestions: At each node in the tree these states are tried:
252  */
253 typedef enum
254 {
255     STATE_START = 0,	/* At start of node check for NUL bytes (goodword
256 			 * ends); if badword ends there is a match, otherwise
257 			 * try splitting word. */
258     STATE_NOPREFIX,	/* try without prefix */
259     STATE_SPLITUNDO,	/* Undo splitting. */
260     STATE_ENDNUL,	/* Past NUL bytes at start of the node. */
261     STATE_PLAIN,	/* Use each byte of the node. */
262     STATE_DEL,		/* Delete a byte from the bad word. */
263     STATE_INS_PREP,	/* Prepare for inserting bytes. */
264     STATE_INS,		/* Insert a byte in the bad word. */
265     STATE_SWAP,		/* Swap two bytes. */
266     STATE_UNSWAP,	/* Undo swap two characters. */
267     STATE_SWAP3,	/* Swap two characters over three. */
268     STATE_UNSWAP3,	/* Undo Swap two characters over three. */
269     STATE_UNROT3L,	/* Undo rotate three characters left */
270     STATE_UNROT3R,	/* Undo rotate three characters right */
271     STATE_REP_INI,	/* Prepare for using REP items. */
272     STATE_REP,		/* Use matching REP items from the .aff file. */
273     STATE_REP_UNDO,	/* Undo a REP item replacement. */
274     STATE_FINAL		/* End of this node. */
275 } state_T;
276 
277 /*
278  * Struct to keep the state at each level in suggest_try_change().
279  */
280 typedef struct trystate_S
281 {
282     state_T	ts_state;	/* state at this level, STATE_ */
283     int		ts_score;	/* score */
284     idx_T	ts_arridx;	/* index in tree array, start of node */
285     short	ts_curi;	/* index in list of child nodes */
286     char_u	ts_fidx;	/* index in fword[], case-folded bad word */
287     char_u	ts_fidxtry;	/* ts_fidx at which bytes may be changed */
288     char_u	ts_twordlen;	/* valid length of tword[] */
289     char_u	ts_prefixdepth;	/* stack depth for end of prefix or
290 				 * PFD_PREFIXTREE or PFD_NOPREFIX */
291     char_u	ts_flags;	/* TSF_ flags */
292     char_u	ts_tcharlen;	/* number of bytes in tword character */
293     char_u	ts_tcharidx;	/* current byte index in tword character */
294     char_u	ts_isdiff;	/* DIFF_ values */
295     char_u	ts_fcharstart;	/* index in fword where badword char started */
296     char_u	ts_prewordlen;	/* length of word in "preword[]" */
297     char_u	ts_splitoff;	/* index in "tword" after last split */
298     char_u	ts_splitfidx;	/* "ts_fidx" at word split */
299     char_u	ts_complen;	/* nr of compound words used */
300     char_u	ts_compsplit;	/* index for "compflags" where word was spit */
301     char_u	ts_save_badflags;   /* su_badflags saved here */
302     char_u	ts_delidx;	/* index in fword for char that was deleted,
303 				   valid when "ts_flags" has TSF_DIDDEL */
304 } trystate_T;
305 
306 /* values for ts_isdiff */
307 #define DIFF_NONE	0	/* no different byte (yet) */
308 #define DIFF_YES	1	/* different byte found */
309 #define DIFF_INSERT	2	/* inserting character */
310 
311 /* values for ts_flags */
312 #define TSF_PREFIXOK	1	/* already checked that prefix is OK */
313 #define TSF_DIDSPLIT	2	/* tried split at this point */
314 #define TSF_DIDDEL	4	/* did a delete, "ts_delidx" has index */
315 
316 /* special values ts_prefixdepth */
317 #define PFD_NOPREFIX	0xff	/* not using prefixes */
318 #define PFD_PREFIXTREE	0xfe	/* walking through the prefix tree */
319 #define PFD_NOTSPECIAL	0xfd	/* highest value that's not special */
320 
321 /* mode values for find_word */
322 #define FIND_FOLDWORD	    0	/* find word case-folded */
323 #define FIND_KEEPWORD	    1	/* find keep-case word */
324 #define FIND_PREFIX	    2	/* find word after prefix */
325 #define FIND_COMPOUND	    3	/* find case-folded compound word */
326 #define FIND_KEEPCOMPOUND   4	/* find keep-case compound word */
327 
328 static void find_word(matchinf_T *mip, int mode);
329 static int match_checkcompoundpattern(char_u *ptr, int wlen, garray_T *gap);
330 static int can_compound(slang_T *slang, char_u *word, char_u *flags);
331 static int match_compoundrule(slang_T *slang, char_u *compflags);
332 static int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang, int cond_req);
333 static void find_prefix(matchinf_T *mip, int mode);
334 static int fold_more(matchinf_T *mip);
335 static int spell_valid_case(int wordflags, int treeflags);
336 static void spell_load_cb(char_u *fname, void *cookie);
337 static int count_syllables(slang_T *slang, char_u *word);
338 static void clear_midword(win_T *buf);
339 static void use_midword(slang_T *lp, win_T *buf);
340 static int find_region(char_u *rp, char_u *region);
341 static int check_need_cap(linenr_T lnum, colnr_T col);
342 static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int maxcount, int banbadword, int need_cap, int interactive);
343 #ifdef FEAT_EVAL
344 static void spell_suggest_expr(suginfo_T *su, char_u *expr);
345 #endif
346 static void spell_suggest_file(suginfo_T *su, char_u *fname);
347 static void spell_suggest_intern(suginfo_T *su, int interactive);
348 static void spell_find_cleanup(suginfo_T *su);
349 static void suggest_try_special(suginfo_T *su);
350 static void suggest_try_change(suginfo_T *su);
351 static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, int soundfold);
352 static void go_deeper(trystate_T *stack, int depth, int score_add);
353 static int nofold_len(char_u *fword, int flen, char_u *word);
354 static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword);
355 static void score_comp_sal(suginfo_T *su);
356 static void score_combine(suginfo_T *su);
357 static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u *badsound);
358 static void suggest_try_soundalike_prep(void);
359 static void suggest_try_soundalike(suginfo_T *su);
360 static void suggest_try_soundalike_finish(void);
361 static void add_sound_suggest(suginfo_T *su, char_u *goodword, int score, langp_T *lp);
362 static int soundfold_find(slang_T *slang, char_u *word);
363 static void make_case_word(char_u *fword, char_u *cword, int flags);
364 static int similar_chars(slang_T *slang, int c1, int c2);
365 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);
366 static void check_suggestions(suginfo_T *su, garray_T *gap);
367 static void add_banned(suginfo_T *su, char_u *word);
368 static void rescore_suggestions(suginfo_T *su);
369 static void rescore_one(suginfo_T *su, suggest_T *stp);
370 static int cleanup_suggestions(garray_T *gap, int maxscore, int keep);
371 static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res);
372 static void spell_soundfold_sal(slang_T *slang, char_u *inword, char_u *res);
373 static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res);
374 static int soundalike_score(char_u *goodsound, char_u *badsound);
375 static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword);
376 static int spell_edit_score_limit(slang_T *slang, char_u *badword, char_u *goodword, int limit);
377 static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goodword, int limit);
378 static void dump_word(slang_T *slang, char_u *word, char_u *pat, int *dir, int round, int flags, linenr_T lnum);
379 static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, int *dir, int round, int flags, linenr_T startlnum);
380 
381 
382 /* Remember what "z?" replaced. */
383 static char_u	*repl_from = NULL;
384 static char_u	*repl_to = NULL;
385 
386 /*
387  * Main spell-checking function.
388  * "ptr" points to a character that could be the start of a word.
389  * "*attrp" is set to the highlight index for a badly spelled word.  For a
390  * non-word or when it's OK it remains unchanged.
391  * This must only be called when 'spelllang' is not empty.
392  *
393  * "capcol" is used to check for a Capitalised word after the end of a
394  * sentence.  If it's zero then perform the check.  Return the column where to
395  * check next, or -1 when no sentence end was found.  If it's NULL then don't
396  * worry.
397  *
398  * Returns the length of the word in bytes, also when it's OK, so that the
399  * caller can skip over the word.
400  */
401     int
402 spell_check(
403     win_T	*wp,		/* current window */
404     char_u	*ptr,
405     hlf_T	*attrp,
406     int		*capcol,	/* column to check for Capital */
407     int		docount)	/* count good words */
408 {
409     matchinf_T	mi;		/* Most things are put in "mi" so that it can
410 				   be passed to functions quickly. */
411     int		nrlen = 0;	/* found a number first */
412     int		c;
413     int		wrongcaplen = 0;
414     int		lpi;
415     int		count_word = docount;
416 
417     /* A word never starts at a space or a control character.  Return quickly
418      * then, skipping over the character. */
419     if (*ptr <= ' ')
420 	return 1;
421 
422     /* Return here when loading language files failed. */
423     if (wp->w_s->b_langp.ga_len == 0)
424 	return 1;
425 
426     vim_memset(&mi, 0, sizeof(matchinf_T));
427 
428     /* A number is always OK.  Also skip hexadecimal numbers 0xFF99 and
429      * 0X99FF.  But always do check spelling to find "3GPP" and "11
430      * julifeest". */
431     if (*ptr >= '0' && *ptr <= '9')
432     {
433 	if (*ptr == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
434 	    mi.mi_end = skipbin(ptr + 2);
435 	else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
436 	    mi.mi_end = skiphex(ptr + 2);
437 	else
438 	    mi.mi_end = skipdigits(ptr);
439 	nrlen = (int)(mi.mi_end - ptr);
440     }
441 
442     /* Find the normal end of the word (until the next non-word character). */
443     mi.mi_word = ptr;
444     mi.mi_fend = ptr;
445     if (spell_iswordp(mi.mi_fend, wp))
446     {
447 	do
448 	{
449 	    MB_PTR_ADV(mi.mi_fend);
450 	} while (*mi.mi_fend != NUL && spell_iswordp(mi.mi_fend, wp));
451 
452 	if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL)
453 	{
454 	    /* Check word starting with capital letter. */
455 	    c = PTR2CHAR(ptr);
456 	    if (!SPELL_ISUPPER(c))
457 		wrongcaplen = (int)(mi.mi_fend - ptr);
458 	}
459     }
460     if (capcol != NULL)
461 	*capcol = -1;
462 
463     /* We always use the characters up to the next non-word character,
464      * also for bad words. */
465     mi.mi_end = mi.mi_fend;
466 
467     /* Check caps type later. */
468     mi.mi_capflags = 0;
469     mi.mi_cend = NULL;
470     mi.mi_win = wp;
471 
472     /* case-fold the word with one non-word character, so that we can check
473      * for the word end. */
474     if (*mi.mi_fend != NUL)
475 	MB_PTR_ADV(mi.mi_fend);
476 
477     (void)spell_casefold(ptr, (int)(mi.mi_fend - ptr), mi.mi_fword,
478 							     MAXWLEN + 1);
479     mi.mi_fwordlen = (int)STRLEN(mi.mi_fword);
480 
481     /* The word is bad unless we recognize it. */
482     mi.mi_result = SP_BAD;
483     mi.mi_result2 = SP_BAD;
484 
485     /*
486      * Loop over the languages specified in 'spelllang'.
487      * We check them all, because a word may be matched longer in another
488      * language.
489      */
490     for (lpi = 0; lpi < wp->w_s->b_langp.ga_len; ++lpi)
491     {
492 	mi.mi_lp = LANGP_ENTRY(wp->w_s->b_langp, lpi);
493 
494 	/* If reloading fails the language is still in the list but everything
495 	 * has been cleared. */
496 	if (mi.mi_lp->lp_slang->sl_fidxs == NULL)
497 	    continue;
498 
499 	/* Check for a matching word in case-folded words. */
500 	find_word(&mi, FIND_FOLDWORD);
501 
502 	/* Check for a matching word in keep-case words. */
503 	find_word(&mi, FIND_KEEPWORD);
504 
505 	/* Check for matching prefixes. */
506 	find_prefix(&mi, FIND_FOLDWORD);
507 
508 	/* For a NOBREAK language, may want to use a word without a following
509 	 * word as a backup. */
510 	if (mi.mi_lp->lp_slang->sl_nobreak && mi.mi_result == SP_BAD
511 						   && mi.mi_result2 != SP_BAD)
512 	{
513 	    mi.mi_result = mi.mi_result2;
514 	    mi.mi_end = mi.mi_end2;
515 	}
516 
517 	/* Count the word in the first language where it's found to be OK. */
518 	if (count_word && mi.mi_result == SP_OK)
519 	{
520 	    count_common_word(mi.mi_lp->lp_slang, ptr,
521 						   (int)(mi.mi_end - ptr), 1);
522 	    count_word = FALSE;
523 	}
524     }
525 
526     if (mi.mi_result != SP_OK)
527     {
528 	/* If we found a number skip over it.  Allows for "42nd".  Do flag
529 	 * rare and local words, e.g., "3GPP". */
530 	if (nrlen > 0)
531 	{
532 	    if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
533 		return nrlen;
534 	}
535 
536 	/* When we are at a non-word character there is no error, just
537 	 * skip over the character (try looking for a word after it). */
538 	else if (!spell_iswordp_nmw(ptr, wp))
539 	{
540 	    if (capcol != NULL && wp->w_s->b_cap_prog != NULL)
541 	    {
542 		regmatch_T	regmatch;
543 		int		r;
544 
545 		/* Check for end of sentence. */
546 		regmatch.regprog = wp->w_s->b_cap_prog;
547 		regmatch.rm_ic = FALSE;
548 		r = vim_regexec(&regmatch, ptr, 0);
549 		wp->w_s->b_cap_prog = regmatch.regprog;
550 		if (r)
551 		    *capcol = (int)(regmatch.endp[0] - ptr);
552 	    }
553 
554 	    if (has_mbyte)
555 		return (*mb_ptr2len)(ptr);
556 	    return 1;
557 	}
558 	else if (mi.mi_end == ptr)
559 	    /* Always include at least one character.  Required for when there
560 	     * is a mixup in "midword". */
561 	    MB_PTR_ADV(mi.mi_end);
562 	else if (mi.mi_result == SP_BAD
563 		&& LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak)
564 	{
565 	    char_u	*p, *fp;
566 	    int		save_result = mi.mi_result;
567 
568 	    /* First language in 'spelllang' is NOBREAK.  Find first position
569 	     * at which any word would be valid. */
570 	    mi.mi_lp = LANGP_ENTRY(wp->w_s->b_langp, 0);
571 	    if (mi.mi_lp->lp_slang->sl_fidxs != NULL)
572 	    {
573 		p = mi.mi_word;
574 		fp = mi.mi_fword;
575 		for (;;)
576 		{
577 		    MB_PTR_ADV(p);
578 		    MB_PTR_ADV(fp);
579 		    if (p >= mi.mi_end)
580 			break;
581 		    mi.mi_compoff = (int)(fp - mi.mi_fword);
582 		    find_word(&mi, FIND_COMPOUND);
583 		    if (mi.mi_result != SP_BAD)
584 		    {
585 			mi.mi_end = p;
586 			break;
587 		    }
588 		}
589 		mi.mi_result = save_result;
590 	    }
591 	}
592 
593 	if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
594 	    *attrp = HLF_SPB;
595 	else if (mi.mi_result == SP_RARE)
596 	    *attrp = HLF_SPR;
597 	else
598 	    *attrp = HLF_SPL;
599     }
600 
601     if (wrongcaplen > 0 && (mi.mi_result == SP_OK || mi.mi_result == SP_RARE))
602     {
603 	/* Report SpellCap only when the word isn't badly spelled. */
604 	*attrp = HLF_SPC;
605 	return wrongcaplen;
606     }
607 
608     return (int)(mi.mi_end - ptr);
609 }
610 
611 /*
612  * Check if the word at "mip->mi_word" is in the tree.
613  * When "mode" is FIND_FOLDWORD check in fold-case word tree.
614  * When "mode" is FIND_KEEPWORD check in keep-case word tree.
615  * When "mode" is FIND_PREFIX check for word after prefix in fold-case word
616  * tree.
617  *
618  * For a match mip->mi_result is updated.
619  */
620     static void
621 find_word(matchinf_T *mip, int mode)
622 {
623     idx_T	arridx = 0;
624     int		endlen[MAXWLEN];    /* length at possible word endings */
625     idx_T	endidx[MAXWLEN];    /* possible word endings */
626     int		endidxcnt = 0;
627     int		len;
628     int		wlen = 0;
629     int		flen;
630     int		c;
631     char_u	*ptr;
632     idx_T	lo, hi, m;
633     char_u	*s;
634     char_u	*p;
635     int		res = SP_BAD;
636     slang_T	*slang = mip->mi_lp->lp_slang;
637     unsigned	flags;
638     char_u	*byts;
639     idx_T	*idxs;
640     int		word_ends;
641     int		prefix_found;
642     int		nobreak_result;
643 
644     if (mode == FIND_KEEPWORD || mode == FIND_KEEPCOMPOUND)
645     {
646 	/* Check for word with matching case in keep-case tree. */
647 	ptr = mip->mi_word;
648 	flen = 9999;		    /* no case folding, always enough bytes */
649 	byts = slang->sl_kbyts;
650 	idxs = slang->sl_kidxs;
651 
652 	if (mode == FIND_KEEPCOMPOUND)
653 	    /* Skip over the previously found word(s). */
654 	    wlen += mip->mi_compoff;
655     }
656     else
657     {
658 	/* Check for case-folded in case-folded tree. */
659 	ptr = mip->mi_fword;
660 	flen = mip->mi_fwordlen;    /* available case-folded bytes */
661 	byts = slang->sl_fbyts;
662 	idxs = slang->sl_fidxs;
663 
664 	if (mode == FIND_PREFIX)
665 	{
666 	    /* Skip over the prefix. */
667 	    wlen = mip->mi_prefixlen;
668 	    flen -= mip->mi_prefixlen;
669 	}
670 	else if (mode == FIND_COMPOUND)
671 	{
672 	    /* Skip over the previously found word(s). */
673 	    wlen = mip->mi_compoff;
674 	    flen -= mip->mi_compoff;
675 	}
676 
677     }
678 
679     if (byts == NULL)
680 	return;			/* array is empty */
681 
682     /*
683      * Repeat advancing in the tree until:
684      * - there is a byte that doesn't match,
685      * - we reach the end of the tree,
686      * - or we reach the end of the line.
687      */
688     for (;;)
689     {
690 	if (flen <= 0 && *mip->mi_fend != NUL)
691 	    flen = fold_more(mip);
692 
693 	len = byts[arridx++];
694 
695 	/* If the first possible byte is a zero the word could end here.
696 	 * Remember this index, we first check for the longest word. */
697 	if (byts[arridx] == 0)
698 	{
699 	    if (endidxcnt == MAXWLEN)
700 	    {
701 		/* Must be a corrupted spell file. */
702 		emsg(_(e_format));
703 		return;
704 	    }
705 	    endlen[endidxcnt] = wlen;
706 	    endidx[endidxcnt++] = arridx++;
707 	    --len;
708 
709 	    /* Skip over the zeros, there can be several flag/region
710 	     * combinations. */
711 	    while (len > 0 && byts[arridx] == 0)
712 	    {
713 		++arridx;
714 		--len;
715 	    }
716 	    if (len == 0)
717 		break;	    /* no children, word must end here */
718 	}
719 
720 	/* Stop looking at end of the line. */
721 	if (ptr[wlen] == NUL)
722 	    break;
723 
724 	/* Perform a binary search in the list of accepted bytes. */
725 	c = ptr[wlen];
726 	if (c == TAB)	    /* <Tab> is handled like <Space> */
727 	    c = ' ';
728 	lo = arridx;
729 	hi = arridx + len - 1;
730 	while (lo < hi)
731 	{
732 	    m = (lo + hi) / 2;
733 	    if (byts[m] > c)
734 		hi = m - 1;
735 	    else if (byts[m] < c)
736 		lo = m + 1;
737 	    else
738 	    {
739 		lo = hi = m;
740 		break;
741 	    }
742 	}
743 
744 	/* Stop if there is no matching byte. */
745 	if (hi < lo || byts[lo] != c)
746 	    break;
747 
748 	/* Continue at the child (if there is one). */
749 	arridx = idxs[lo];
750 	++wlen;
751 	--flen;
752 
753 	/* One space in the good word may stand for several spaces in the
754 	 * checked word. */
755 	if (c == ' ')
756 	{
757 	    for (;;)
758 	    {
759 		if (flen <= 0 && *mip->mi_fend != NUL)
760 		    flen = fold_more(mip);
761 		if (ptr[wlen] != ' ' && ptr[wlen] != TAB)
762 		    break;
763 		++wlen;
764 		--flen;
765 	    }
766 	}
767     }
768 
769     /*
770      * Verify that one of the possible endings is valid.  Try the longest
771      * first.
772      */
773     while (endidxcnt > 0)
774     {
775 	--endidxcnt;
776 	arridx = endidx[endidxcnt];
777 	wlen = endlen[endidxcnt];
778 
779 	if ((*mb_head_off)(ptr, ptr + wlen) > 0)
780 	    continue;	    /* not at first byte of character */
781 	if (spell_iswordp(ptr + wlen, mip->mi_win))
782 	{
783 	    if (slang->sl_compprog == NULL && !slang->sl_nobreak)
784 		continue;	    /* next char is a word character */
785 	    word_ends = FALSE;
786 	}
787 	else
788 	    word_ends = TRUE;
789 	/* The prefix flag is before compound flags.  Once a valid prefix flag
790 	 * has been found we try compound flags. */
791 	prefix_found = FALSE;
792 
793 	if (mode != FIND_KEEPWORD && has_mbyte)
794 	{
795 	    /* Compute byte length in original word, length may change
796 	     * when folding case.  This can be slow, take a shortcut when the
797 	     * case-folded word is equal to the keep-case word. */
798 	    p = mip->mi_word;
799 	    if (STRNCMP(ptr, p, wlen) != 0)
800 	    {
801 		for (s = ptr; s < ptr + wlen; MB_PTR_ADV(s))
802 		    MB_PTR_ADV(p);
803 		wlen = (int)(p - mip->mi_word);
804 	    }
805 	}
806 
807 	/* Check flags and region.  For FIND_PREFIX check the condition and
808 	 * prefix ID.
809 	 * Repeat this if there are more flags/region alternatives until there
810 	 * is a match. */
811 	res = SP_BAD;
812 	for (len = byts[arridx - 1]; len > 0 && byts[arridx] == 0;
813 							      --len, ++arridx)
814 	{
815 	    flags = idxs[arridx];
816 
817 	    /* For the fold-case tree check that the case of the checked word
818 	     * matches with what the word in the tree requires.
819 	     * For keep-case tree the case is always right.  For prefixes we
820 	     * don't bother to check. */
821 	    if (mode == FIND_FOLDWORD)
822 	    {
823 		if (mip->mi_cend != mip->mi_word + wlen)
824 		{
825 		    /* mi_capflags was set for a different word length, need
826 		     * to do it again. */
827 		    mip->mi_cend = mip->mi_word + wlen;
828 		    mip->mi_capflags = captype(mip->mi_word, mip->mi_cend);
829 		}
830 
831 		if (mip->mi_capflags == WF_KEEPCAP
832 				|| !spell_valid_case(mip->mi_capflags, flags))
833 		    continue;
834 	    }
835 
836 	    /* When mode is FIND_PREFIX the word must support the prefix:
837 	     * check the prefix ID and the condition.  Do that for the list at
838 	     * mip->mi_prefarridx that find_prefix() filled. */
839 	    else if (mode == FIND_PREFIX && !prefix_found)
840 	    {
841 		c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx,
842 				    flags,
843 				    mip->mi_word + mip->mi_cprefixlen, slang,
844 				    FALSE);
845 		if (c == 0)
846 		    continue;
847 
848 		/* Use the WF_RARE flag for a rare prefix. */
849 		if (c & WF_RAREPFX)
850 		    flags |= WF_RARE;
851 		prefix_found = TRUE;
852 	    }
853 
854 	    if (slang->sl_nobreak)
855 	    {
856 		if ((mode == FIND_COMPOUND || mode == FIND_KEEPCOMPOUND)
857 			&& (flags & WF_BANNED) == 0)
858 		{
859 		    /* NOBREAK: found a valid following word.  That's all we
860 		     * need to know, so return. */
861 		    mip->mi_result = SP_OK;
862 		    break;
863 		}
864 	    }
865 
866 	    else if ((mode == FIND_COMPOUND || mode == FIND_KEEPCOMPOUND
867 								|| !word_ends))
868 	    {
869 		/* If there is no compound flag or the word is shorter than
870 		 * COMPOUNDMIN reject it quickly.
871 		 * Makes you wonder why someone puts a compound flag on a word
872 		 * that's too short...  Myspell compatibility requires this
873 		 * anyway. */
874 		if (((unsigned)flags >> 24) == 0
875 			     || wlen - mip->mi_compoff < slang->sl_compminlen)
876 		    continue;
877 		/* For multi-byte chars check character length against
878 		 * COMPOUNDMIN. */
879 		if (has_mbyte
880 			&& slang->sl_compminlen > 0
881 			&& mb_charlen_len(mip->mi_word + mip->mi_compoff,
882 				wlen - mip->mi_compoff) < slang->sl_compminlen)
883 			continue;
884 
885 		/* Limit the number of compound words to COMPOUNDWORDMAX if no
886 		 * maximum for syllables is specified. */
887 		if (!word_ends && mip->mi_complen + mip->mi_compextra + 2
888 							   > slang->sl_compmax
889 					   && slang->sl_compsylmax == MAXWLEN)
890 		    continue;
891 
892 		/* Don't allow compounding on a side where an affix was added,
893 		 * unless COMPOUNDPERMITFLAG was used. */
894 		if (mip->mi_complen > 0 && (flags & WF_NOCOMPBEF))
895 		    continue;
896 		if (!word_ends && (flags & WF_NOCOMPAFT))
897 		    continue;
898 
899 		/* Quickly check if compounding is possible with this flag. */
900 		if (!byte_in_str(mip->mi_complen == 0
901 					? slang->sl_compstartflags
902 					: slang->sl_compallflags,
903 					    ((unsigned)flags >> 24)))
904 		    continue;
905 
906 		/* If there is a match with a CHECKCOMPOUNDPATTERN rule
907 		 * discard the compound word. */
908 		if (match_checkcompoundpattern(ptr, wlen, &slang->sl_comppat))
909 		    continue;
910 
911 		if (mode == FIND_COMPOUND)
912 		{
913 		    int	    capflags;
914 
915 		    /* Need to check the caps type of the appended compound
916 		     * word. */
917 		    if (has_mbyte && STRNCMP(ptr, mip->mi_word,
918 							mip->mi_compoff) != 0)
919 		    {
920 			/* case folding may have changed the length */
921 			p = mip->mi_word;
922 			for (s = ptr; s < ptr + mip->mi_compoff; MB_PTR_ADV(s))
923 			    MB_PTR_ADV(p);
924 		    }
925 		    else
926 			p = mip->mi_word + mip->mi_compoff;
927 		    capflags = captype(p, mip->mi_word + wlen);
928 		    if (capflags == WF_KEEPCAP || (capflags == WF_ALLCAP
929 						 && (flags & WF_FIXCAP) != 0))
930 			continue;
931 
932 		    if (capflags != WF_ALLCAP)
933 		    {
934 			/* When the character before the word is a word
935 			 * character we do not accept a Onecap word.  We do
936 			 * accept a no-caps word, even when the dictionary
937 			 * word specifies ONECAP. */
938 			MB_PTR_BACK(mip->mi_word, p);
939 			if (spell_iswordp_nmw(p, mip->mi_win)
940 				? capflags == WF_ONECAP
941 				: (flags & WF_ONECAP) != 0
942 						     && capflags != WF_ONECAP)
943 			    continue;
944 		    }
945 		}
946 
947 		/* If the word ends the sequence of compound flags of the
948 		 * words must match with one of the COMPOUNDRULE items and
949 		 * the number of syllables must not be too large. */
950 		mip->mi_compflags[mip->mi_complen] = ((unsigned)flags >> 24);
951 		mip->mi_compflags[mip->mi_complen + 1] = NUL;
952 		if (word_ends)
953 		{
954 		    char_u	fword[MAXWLEN];
955 
956 		    if (slang->sl_compsylmax < MAXWLEN)
957 		    {
958 			/* "fword" is only needed for checking syllables. */
959 			if (ptr == mip->mi_word)
960 			    (void)spell_casefold(ptr, wlen, fword, MAXWLEN);
961 			else
962 			    vim_strncpy(fword, ptr, endlen[endidxcnt]);
963 		    }
964 		    if (!can_compound(slang, fword, mip->mi_compflags))
965 			continue;
966 		}
967 		else if (slang->sl_comprules != NULL
968 			     && !match_compoundrule(slang, mip->mi_compflags))
969 		    /* The compound flags collected so far do not match any
970 		     * COMPOUNDRULE, discard the compounded word. */
971 		    continue;
972 	    }
973 
974 	    /* Check NEEDCOMPOUND: can't use word without compounding. */
975 	    else if (flags & WF_NEEDCOMP)
976 		continue;
977 
978 	    nobreak_result = SP_OK;
979 
980 	    if (!word_ends)
981 	    {
982 		int	save_result = mip->mi_result;
983 		char_u	*save_end = mip->mi_end;
984 		langp_T	*save_lp = mip->mi_lp;
985 		int	lpi;
986 
987 		/* Check that a valid word follows.  If there is one and we
988 		 * are compounding, it will set "mi_result", thus we are
989 		 * always finished here.  For NOBREAK we only check that a
990 		 * valid word follows.
991 		 * Recursive! */
992 		if (slang->sl_nobreak)
993 		    mip->mi_result = SP_BAD;
994 
995 		/* Find following word in case-folded tree. */
996 		mip->mi_compoff = endlen[endidxcnt];
997 		if (has_mbyte && mode == FIND_KEEPWORD)
998 		{
999 		    /* Compute byte length in case-folded word from "wlen":
1000 		     * byte length in keep-case word.  Length may change when
1001 		     * folding case.  This can be slow, take a shortcut when
1002 		     * the case-folded word is equal to the keep-case word. */
1003 		    p = mip->mi_fword;
1004 		    if (STRNCMP(ptr, p, wlen) != 0)
1005 		    {
1006 			for (s = ptr; s < ptr + wlen; MB_PTR_ADV(s))
1007 			    MB_PTR_ADV(p);
1008 			mip->mi_compoff = (int)(p - mip->mi_fword);
1009 		    }
1010 		}
1011 #if 0 /* Disabled, see below */
1012 		c = mip->mi_compoff;
1013 #endif
1014 		++mip->mi_complen;
1015 		if (flags & WF_COMPROOT)
1016 		    ++mip->mi_compextra;
1017 
1018 		/* For NOBREAK we need to try all NOBREAK languages, at least
1019 		 * to find the ".add" file(s). */
1020 		for (lpi = 0; lpi < mip->mi_win->w_s->b_langp.ga_len; ++lpi)
1021 		{
1022 		    if (slang->sl_nobreak)
1023 		    {
1024 			mip->mi_lp = LANGP_ENTRY(mip->mi_win->w_s->b_langp, lpi);
1025 			if (mip->mi_lp->lp_slang->sl_fidxs == NULL
1026 					 || !mip->mi_lp->lp_slang->sl_nobreak)
1027 			    continue;
1028 		    }
1029 
1030 		    find_word(mip, FIND_COMPOUND);
1031 
1032 		    /* When NOBREAK any word that matches is OK.  Otherwise we
1033 		     * need to find the longest match, thus try with keep-case
1034 		     * and prefix too. */
1035 		    if (!slang->sl_nobreak || mip->mi_result == SP_BAD)
1036 		    {
1037 			/* Find following word in keep-case tree. */
1038 			mip->mi_compoff = wlen;
1039 			find_word(mip, FIND_KEEPCOMPOUND);
1040 
1041 #if 0	    /* Disabled, a prefix must not appear halfway a compound word,
1042 	       unless the COMPOUNDPERMITFLAG is used and then it can't be a
1043 	       postponed prefix. */
1044 			if (!slang->sl_nobreak || mip->mi_result == SP_BAD)
1045 			{
1046 			    /* Check for following word with prefix. */
1047 			    mip->mi_compoff = c;
1048 			    find_prefix(mip, FIND_COMPOUND);
1049 			}
1050 #endif
1051 		    }
1052 
1053 		    if (!slang->sl_nobreak)
1054 			break;
1055 		}
1056 		--mip->mi_complen;
1057 		if (flags & WF_COMPROOT)
1058 		    --mip->mi_compextra;
1059 		mip->mi_lp = save_lp;
1060 
1061 		if (slang->sl_nobreak)
1062 		{
1063 		    nobreak_result = mip->mi_result;
1064 		    mip->mi_result = save_result;
1065 		    mip->mi_end = save_end;
1066 		}
1067 		else
1068 		{
1069 		    if (mip->mi_result == SP_OK)
1070 			break;
1071 		    continue;
1072 		}
1073 	    }
1074 
1075 	    if (flags & WF_BANNED)
1076 		res = SP_BANNED;
1077 	    else if (flags & WF_REGION)
1078 	    {
1079 		/* Check region. */
1080 		if ((mip->mi_lp->lp_region & (flags >> 16)) != 0)
1081 		    res = SP_OK;
1082 		else
1083 		    res = SP_LOCAL;
1084 	    }
1085 	    else if (flags & WF_RARE)
1086 		res = SP_RARE;
1087 	    else
1088 		res = SP_OK;
1089 
1090 	    /* Always use the longest match and the best result.  For NOBREAK
1091 	     * we separately keep the longest match without a following good
1092 	     * word as a fall-back. */
1093 	    if (nobreak_result == SP_BAD)
1094 	    {
1095 		if (mip->mi_result2 > res)
1096 		{
1097 		    mip->mi_result2 = res;
1098 		    mip->mi_end2 = mip->mi_word + wlen;
1099 		}
1100 		else if (mip->mi_result2 == res
1101 					&& mip->mi_end2 < mip->mi_word + wlen)
1102 		    mip->mi_end2 = mip->mi_word + wlen;
1103 	    }
1104 	    else if (mip->mi_result > res)
1105 	    {
1106 		mip->mi_result = res;
1107 		mip->mi_end = mip->mi_word + wlen;
1108 	    }
1109 	    else if (mip->mi_result == res && mip->mi_end < mip->mi_word + wlen)
1110 		mip->mi_end = mip->mi_word + wlen;
1111 
1112 	    if (mip->mi_result == SP_OK)
1113 		break;
1114 	}
1115 
1116 	if (mip->mi_result == SP_OK)
1117 	    break;
1118     }
1119 }
1120 
1121 /*
1122  * Return TRUE if there is a match between the word ptr[wlen] and
1123  * CHECKCOMPOUNDPATTERN rules, assuming that we will concatenate with another
1124  * word.
1125  * A match means that the first part of CHECKCOMPOUNDPATTERN matches at the
1126  * end of ptr[wlen] and the second part matches after it.
1127  */
1128     static int
1129 match_checkcompoundpattern(
1130     char_u	*ptr,
1131     int		wlen,
1132     garray_T	*gap)  /* &sl_comppat */
1133 {
1134     int		i;
1135     char_u	*p;
1136     int		len;
1137 
1138     for (i = 0; i + 1 < gap->ga_len; i += 2)
1139     {
1140 	p = ((char_u **)gap->ga_data)[i + 1];
1141 	if (STRNCMP(ptr + wlen, p, STRLEN(p)) == 0)
1142 	{
1143 	    /* Second part matches at start of following compound word, now
1144 	     * check if first part matches at end of previous word. */
1145 	    p = ((char_u **)gap->ga_data)[i];
1146 	    len = (int)STRLEN(p);
1147 	    if (len <= wlen && STRNCMP(ptr + wlen - len, p, len) == 0)
1148 		return TRUE;
1149 	}
1150     }
1151     return FALSE;
1152 }
1153 
1154 /*
1155  * Return TRUE if "flags" is a valid sequence of compound flags and "word"
1156  * does not have too many syllables.
1157  */
1158     static int
1159 can_compound(slang_T *slang, char_u *word, char_u *flags)
1160 {
1161     char_u	uflags[MAXWLEN * 2];
1162     int		i;
1163     char_u	*p;
1164 
1165     if (slang->sl_compprog == NULL)
1166 	return FALSE;
1167     if (enc_utf8)
1168     {
1169 	/* Need to convert the single byte flags to utf8 characters. */
1170 	p = uflags;
1171 	for (i = 0; flags[i] != NUL; ++i)
1172 	    p += utf_char2bytes(flags[i], p);
1173 	*p = NUL;
1174 	p = uflags;
1175     }
1176     else
1177 	p = flags;
1178     if (!vim_regexec_prog(&slang->sl_compprog, FALSE, p, 0))
1179 	return FALSE;
1180 
1181     /* Count the number of syllables.  This may be slow, do it last.  If there
1182      * are too many syllables AND the number of compound words is above
1183      * COMPOUNDWORDMAX then compounding is not allowed. */
1184     if (slang->sl_compsylmax < MAXWLEN
1185 		       && count_syllables(slang, word) > slang->sl_compsylmax)
1186 	return (int)STRLEN(flags) < slang->sl_compmax;
1187     return TRUE;
1188 }
1189 
1190 /*
1191  * Return TRUE when the sequence of flags in "compflags" plus "flag" can
1192  * possibly form a valid compounded word.  This also checks the COMPOUNDRULE
1193  * lines if they don't contain wildcards.
1194  */
1195     static int
1196 can_be_compound(
1197     trystate_T	*sp,
1198     slang_T	*slang,
1199     char_u	*compflags,
1200     int		flag)
1201 {
1202     /* If the flag doesn't appear in sl_compstartflags or sl_compallflags
1203      * then it can't possibly compound. */
1204     if (!byte_in_str(sp->ts_complen == sp->ts_compsplit
1205 		? slang->sl_compstartflags : slang->sl_compallflags, flag))
1206 	return FALSE;
1207 
1208     /* If there are no wildcards, we can check if the flags collected so far
1209      * possibly can form a match with COMPOUNDRULE patterns.  This only
1210      * makes sense when we have two or more words. */
1211     if (slang->sl_comprules != NULL && sp->ts_complen > sp->ts_compsplit)
1212     {
1213 	int v;
1214 
1215 	compflags[sp->ts_complen] = flag;
1216 	compflags[sp->ts_complen + 1] = NUL;
1217 	v = match_compoundrule(slang, compflags + sp->ts_compsplit);
1218 	compflags[sp->ts_complen] = NUL;
1219 	return v;
1220     }
1221 
1222     return TRUE;
1223 }
1224 
1225 
1226 /*
1227  * Return TRUE if the compound flags in compflags[] match the start of any
1228  * compound rule.  This is used to stop trying a compound if the flags
1229  * collected so far can't possibly match any compound rule.
1230  * Caller must check that slang->sl_comprules is not NULL.
1231  */
1232     static int
1233 match_compoundrule(slang_T *slang, char_u *compflags)
1234 {
1235     char_u	*p;
1236     int		i;
1237     int		c;
1238 
1239     /* loop over all the COMPOUNDRULE entries */
1240     for (p = slang->sl_comprules; *p != NUL; ++p)
1241     {
1242 	/* loop over the flags in the compound word we have made, match
1243 	 * them against the current rule entry */
1244 	for (i = 0; ; ++i)
1245 	{
1246 	    c = compflags[i];
1247 	    if (c == NUL)
1248 		/* found a rule that matches for the flags we have so far */
1249 		return TRUE;
1250 	    if (*p == '/' || *p == NUL)
1251 		break;  /* end of rule, it's too short */
1252 	    if (*p == '[')
1253 	    {
1254 		int match = FALSE;
1255 
1256 		/* compare against all the flags in [] */
1257 		++p;
1258 		while (*p != ']' && *p != NUL)
1259 		    if (*p++ == c)
1260 			match = TRUE;
1261 		if (!match)
1262 		    break;  /* none matches */
1263 	    }
1264 	    else if (*p != c)
1265 		break;  /* flag of word doesn't match flag in pattern */
1266 	    ++p;
1267 	}
1268 
1269 	/* Skip to the next "/", where the next pattern starts. */
1270 	p = vim_strchr(p, '/');
1271 	if (p == NULL)
1272 	    break;
1273     }
1274 
1275     /* Checked all the rules and none of them match the flags, so there
1276      * can't possibly be a compound starting with these flags. */
1277     return FALSE;
1278 }
1279 
1280 /*
1281  * Return non-zero if the prefix indicated by "arridx" matches with the prefix
1282  * ID in "flags" for the word "word".
1283  * The WF_RAREPFX flag is included in the return value for a rare prefix.
1284  */
1285     static int
1286 valid_word_prefix(
1287     int		totprefcnt,	/* nr of prefix IDs */
1288     int		arridx,		/* idx in sl_pidxs[] */
1289     int		flags,
1290     char_u	*word,
1291     slang_T	*slang,
1292     int		cond_req)	/* only use prefixes with a condition */
1293 {
1294     int		prefcnt;
1295     int		pidx;
1296     regprog_T	**rp;
1297     int		prefid;
1298 
1299     prefid = (unsigned)flags >> 24;
1300     for (prefcnt = totprefcnt - 1; prefcnt >= 0; --prefcnt)
1301     {
1302 	pidx = slang->sl_pidxs[arridx + prefcnt];
1303 
1304 	/* Check the prefix ID. */
1305 	if (prefid != (pidx & 0xff))
1306 	    continue;
1307 
1308 	/* Check if the prefix doesn't combine and the word already has a
1309 	 * suffix. */
1310 	if ((flags & WF_HAS_AFF) && (pidx & WF_PFX_NC))
1311 	    continue;
1312 
1313 	/* Check the condition, if there is one.  The condition index is
1314 	 * stored in the two bytes above the prefix ID byte.  */
1315 	rp = &slang->sl_prefprog[((unsigned)pidx >> 8) & 0xffff];
1316 	if (*rp != NULL)
1317 	{
1318 	    if (!vim_regexec_prog(rp, FALSE, word, 0))
1319 		continue;
1320 	}
1321 	else if (cond_req)
1322 	    continue;
1323 
1324 	/* It's a match!  Return the WF_ flags. */
1325 	return pidx;
1326     }
1327     return 0;
1328 }
1329 
1330 /*
1331  * Check if the word at "mip->mi_word" has a matching prefix.
1332  * If it does, then check the following word.
1333  *
1334  * If "mode" is "FIND_COMPOUND" then do the same after another word, find a
1335  * prefix in a compound word.
1336  *
1337  * For a match mip->mi_result is updated.
1338  */
1339     static void
1340 find_prefix(matchinf_T *mip, int mode)
1341 {
1342     idx_T	arridx = 0;
1343     int		len;
1344     int		wlen = 0;
1345     int		flen;
1346     int		c;
1347     char_u	*ptr;
1348     idx_T	lo, hi, m;
1349     slang_T	*slang = mip->mi_lp->lp_slang;
1350     char_u	*byts;
1351     idx_T	*idxs;
1352 
1353     byts = slang->sl_pbyts;
1354     if (byts == NULL)
1355 	return;			/* array is empty */
1356 
1357     /* We use the case-folded word here, since prefixes are always
1358      * case-folded. */
1359     ptr = mip->mi_fword;
1360     flen = mip->mi_fwordlen;    /* available case-folded bytes */
1361     if (mode == FIND_COMPOUND)
1362     {
1363 	/* Skip over the previously found word(s). */
1364 	ptr += mip->mi_compoff;
1365 	flen -= mip->mi_compoff;
1366     }
1367     idxs = slang->sl_pidxs;
1368 
1369     /*
1370      * Repeat advancing in the tree until:
1371      * - there is a byte that doesn't match,
1372      * - we reach the end of the tree,
1373      * - or we reach the end of the line.
1374      */
1375     for (;;)
1376     {
1377 	if (flen == 0 && *mip->mi_fend != NUL)
1378 	    flen = fold_more(mip);
1379 
1380 	len = byts[arridx++];
1381 
1382 	/* If the first possible byte is a zero the prefix could end here.
1383 	 * Check if the following word matches and supports the prefix. */
1384 	if (byts[arridx] == 0)
1385 	{
1386 	    /* There can be several prefixes with different conditions.  We
1387 	     * try them all, since we don't know which one will give the
1388 	     * longest match.  The word is the same each time, pass the list
1389 	     * of possible prefixes to find_word(). */
1390 	    mip->mi_prefarridx = arridx;
1391 	    mip->mi_prefcnt = len;
1392 	    while (len > 0 && byts[arridx] == 0)
1393 	    {
1394 		++arridx;
1395 		--len;
1396 	    }
1397 	    mip->mi_prefcnt -= len;
1398 
1399 	    /* Find the word that comes after the prefix. */
1400 	    mip->mi_prefixlen = wlen;
1401 	    if (mode == FIND_COMPOUND)
1402 		/* Skip over the previously found word(s). */
1403 		mip->mi_prefixlen += mip->mi_compoff;
1404 
1405 	    if (has_mbyte)
1406 	    {
1407 		/* Case-folded length may differ from original length. */
1408 		mip->mi_cprefixlen = nofold_len(mip->mi_fword,
1409 					     mip->mi_prefixlen, mip->mi_word);
1410 	    }
1411 	    else
1412 		mip->mi_cprefixlen = mip->mi_prefixlen;
1413 	    find_word(mip, FIND_PREFIX);
1414 
1415 
1416 	    if (len == 0)
1417 		break;	    /* no children, word must end here */
1418 	}
1419 
1420 	/* Stop looking at end of the line. */
1421 	if (ptr[wlen] == NUL)
1422 	    break;
1423 
1424 	/* Perform a binary search in the list of accepted bytes. */
1425 	c = ptr[wlen];
1426 	lo = arridx;
1427 	hi = arridx + len - 1;
1428 	while (lo < hi)
1429 	{
1430 	    m = (lo + hi) / 2;
1431 	    if (byts[m] > c)
1432 		hi = m - 1;
1433 	    else if (byts[m] < c)
1434 		lo = m + 1;
1435 	    else
1436 	    {
1437 		lo = hi = m;
1438 		break;
1439 	    }
1440 	}
1441 
1442 	/* Stop if there is no matching byte. */
1443 	if (hi < lo || byts[lo] != c)
1444 	    break;
1445 
1446 	/* Continue at the child (if there is one). */
1447 	arridx = idxs[lo];
1448 	++wlen;
1449 	--flen;
1450     }
1451 }
1452 
1453 /*
1454  * Need to fold at least one more character.  Do until next non-word character
1455  * for efficiency.  Include the non-word character too.
1456  * Return the length of the folded chars in bytes.
1457  */
1458     static int
1459 fold_more(matchinf_T *mip)
1460 {
1461     int		flen;
1462     char_u	*p;
1463 
1464     p = mip->mi_fend;
1465     do
1466     {
1467 	MB_PTR_ADV(mip->mi_fend);
1468     } while (*mip->mi_fend != NUL && spell_iswordp(mip->mi_fend, mip->mi_win));
1469 
1470     /* Include the non-word character so that we can check for the word end. */
1471     if (*mip->mi_fend != NUL)
1472 	MB_PTR_ADV(mip->mi_fend);
1473 
1474     (void)spell_casefold(p, (int)(mip->mi_fend - p),
1475 			     mip->mi_fword + mip->mi_fwordlen,
1476 			     MAXWLEN - mip->mi_fwordlen);
1477     flen = (int)STRLEN(mip->mi_fword + mip->mi_fwordlen);
1478     mip->mi_fwordlen += flen;
1479     return flen;
1480 }
1481 
1482 /*
1483  * Check case flags for a word.  Return TRUE if the word has the requested
1484  * case.
1485  */
1486     static int
1487 spell_valid_case(
1488     int	    wordflags,	    /* flags for the checked word. */
1489     int	    treeflags)	    /* flags for the word in the spell tree */
1490 {
1491     return ((wordflags == WF_ALLCAP && (treeflags & WF_FIXCAP) == 0)
1492 	    || ((treeflags & (WF_ALLCAP | WF_KEEPCAP)) == 0
1493 		&& ((treeflags & WF_ONECAP) == 0
1494 					   || (wordflags & WF_ONECAP) != 0)));
1495 }
1496 
1497 /*
1498  * Return TRUE if spell checking is not enabled.
1499  */
1500     static int
1501 no_spell_checking(win_T *wp)
1502 {
1503     if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL
1504 					 || wp->w_s->b_langp.ga_len == 0)
1505     {
1506 	emsg(_("E756: Spell checking is not enabled"));
1507 	return TRUE;
1508     }
1509     return FALSE;
1510 }
1511 
1512 /*
1513  * Move to next spell error.
1514  * "curline" is FALSE for "[s", "]s", "[S" and "]S".
1515  * "curline" is TRUE to find word under/after cursor in the same line.
1516  * For Insert mode completion "dir" is BACKWARD and "curline" is TRUE: move
1517  * to after badly spelled word before the cursor.
1518  * Return 0 if not found, length of the badly spelled word otherwise.
1519  */
1520     int
1521 spell_move_to(
1522     win_T	*wp,
1523     int		dir,		/* FORWARD or BACKWARD */
1524     int		allwords,	/* TRUE for "[s"/"]s", FALSE for "[S"/"]S" */
1525     int		curline,
1526     hlf_T	*attrp)		/* return: attributes of bad word or NULL
1527 				   (only when "dir" is FORWARD) */
1528 {
1529     linenr_T	lnum;
1530     pos_T	found_pos;
1531     int		found_len = 0;
1532     char_u	*line;
1533     char_u	*p;
1534     char_u	*endp;
1535     hlf_T	attr;
1536     int		len;
1537 #ifdef FEAT_SYN_HL
1538     int		has_syntax = syntax_present(wp);
1539 #endif
1540     int		col;
1541     int		can_spell;
1542     char_u	*buf = NULL;
1543     int		buflen = 0;
1544     int		skip = 0;
1545     int		capcol = -1;
1546     int		found_one = FALSE;
1547     int		wrapped = FALSE;
1548 
1549     if (no_spell_checking(wp))
1550 	return 0;
1551 
1552     /*
1553      * Start looking for bad word at the start of the line, because we can't
1554      * start halfway a word, we don't know where it starts or ends.
1555      *
1556      * When searching backwards, we continue in the line to find the last
1557      * bad word (in the cursor line: before the cursor).
1558      *
1559      * We concatenate the start of the next line, so that wrapped words work
1560      * (e.g. "et<line-break>cetera").  Doesn't work when searching backwards
1561      * though...
1562      */
1563     lnum = wp->w_cursor.lnum;
1564     CLEAR_POS(&found_pos);
1565 
1566     while (!got_int)
1567     {
1568 	line = ml_get_buf(wp->w_buffer, lnum, FALSE);
1569 
1570 	len = (int)STRLEN(line);
1571 	if (buflen < len + MAXWLEN + 2)
1572 	{
1573 	    vim_free(buf);
1574 	    buflen = len + MAXWLEN + 2;
1575 	    buf = alloc(buflen);
1576 	    if (buf == NULL)
1577 		break;
1578 	}
1579 
1580 	/* In first line check first word for Capital. */
1581 	if (lnum == 1)
1582 	    capcol = 0;
1583 
1584 	/* For checking first word with a capital skip white space. */
1585 	if (capcol == 0)
1586 	    capcol = getwhitecols(line);
1587 	else if (curline && wp == curwin)
1588 	{
1589 	    /* For spellbadword(): check if first word needs a capital. */
1590 	    col = getwhitecols(line);
1591 	    if (check_need_cap(lnum, col))
1592 		capcol = col;
1593 
1594 	    /* Need to get the line again, may have looked at the previous
1595 	     * one. */
1596 	    line = ml_get_buf(wp->w_buffer, lnum, FALSE);
1597 	}
1598 
1599 	/* Copy the line into "buf" and append the start of the next line if
1600 	 * possible. */
1601 	STRCPY(buf, line);
1602 	if (lnum < wp->w_buffer->b_ml.ml_line_count)
1603 	    spell_cat_line(buf + STRLEN(buf),
1604 			  ml_get_buf(wp->w_buffer, lnum + 1, FALSE), MAXWLEN);
1605 
1606 	p = buf + skip;
1607 	endp = buf + len;
1608 	while (p < endp)
1609 	{
1610 	    /* When searching backward don't search after the cursor.  Unless
1611 	     * we wrapped around the end of the buffer. */
1612 	    if (dir == BACKWARD
1613 		    && lnum == wp->w_cursor.lnum
1614 		    && !wrapped
1615 		    && (colnr_T)(p - buf) >= wp->w_cursor.col)
1616 		break;
1617 
1618 	    /* start of word */
1619 	    attr = HLF_COUNT;
1620 	    len = spell_check(wp, p, &attr, &capcol, FALSE);
1621 
1622 	    if (attr != HLF_COUNT)
1623 	    {
1624 		/* We found a bad word.  Check the attribute. */
1625 		if (allwords || attr == HLF_SPB)
1626 		{
1627 		    /* When searching forward only accept a bad word after
1628 		     * the cursor. */
1629 		    if (dir == BACKWARD
1630 			    || lnum != wp->w_cursor.lnum
1631 			    || (lnum == wp->w_cursor.lnum
1632 				&& (wrapped
1633 				    || (colnr_T)(curline ? p - buf + len
1634 						     : p - buf)
1635 						  > wp->w_cursor.col)))
1636 		    {
1637 #ifdef FEAT_SYN_HL
1638 			if (has_syntax)
1639 			{
1640 			    col = (int)(p - buf);
1641 			    (void)syn_get_id(wp, lnum, (colnr_T)col,
1642 						    FALSE, &can_spell, FALSE);
1643 			    if (!can_spell)
1644 				attr = HLF_COUNT;
1645 			}
1646 			else
1647 #endif
1648 			    can_spell = TRUE;
1649 
1650 			if (can_spell)
1651 			{
1652 			    found_one = TRUE;
1653 			    found_pos.lnum = lnum;
1654 			    found_pos.col = (int)(p - buf);
1655 			    found_pos.coladd = 0;
1656 			    if (dir == FORWARD)
1657 			    {
1658 				/* No need to search further. */
1659 				wp->w_cursor = found_pos;
1660 				vim_free(buf);
1661 				if (attrp != NULL)
1662 				    *attrp = attr;
1663 				return len;
1664 			    }
1665 			    else if (curline)
1666 				/* Insert mode completion: put cursor after
1667 				 * the bad word. */
1668 				found_pos.col += len;
1669 			    found_len = len;
1670 			}
1671 		    }
1672 		    else
1673 			found_one = TRUE;
1674 		}
1675 	    }
1676 
1677 	    /* advance to character after the word */
1678 	    p += len;
1679 	    capcol -= len;
1680 	}
1681 
1682 	if (dir == BACKWARD && found_pos.lnum != 0)
1683 	{
1684 	    /* Use the last match in the line (before the cursor). */
1685 	    wp->w_cursor = found_pos;
1686 	    vim_free(buf);
1687 	    return found_len;
1688 	}
1689 
1690 	if (curline)
1691 	    break;	/* only check cursor line */
1692 
1693 	/* If we are back at the starting line and searched it again there
1694 	 * is no match, give up. */
1695 	if (lnum == wp->w_cursor.lnum && wrapped)
1696 	    break;
1697 
1698 	/* Advance to next line. */
1699 	if (dir == BACKWARD)
1700 	{
1701 	    if (lnum > 1)
1702 		--lnum;
1703 	    else if (!p_ws)
1704 		break;	    /* at first line and 'nowrapscan' */
1705 	    else
1706 	    {
1707 		/* Wrap around to the end of the buffer.  May search the
1708 		 * starting line again and accept the last match. */
1709 		lnum = wp->w_buffer->b_ml.ml_line_count;
1710 		wrapped = TRUE;
1711 		if (!shortmess(SHM_SEARCH))
1712 		    give_warning((char_u *)_(top_bot_msg), TRUE);
1713 	    }
1714 	    capcol = -1;
1715 	}
1716 	else
1717 	{
1718 	    if (lnum < wp->w_buffer->b_ml.ml_line_count)
1719 		++lnum;
1720 	    else if (!p_ws)
1721 		break;	    /* at first line and 'nowrapscan' */
1722 	    else
1723 	    {
1724 		/* Wrap around to the start of the buffer.  May search the
1725 		 * starting line again and accept the first match. */
1726 		lnum = 1;
1727 		wrapped = TRUE;
1728 		if (!shortmess(SHM_SEARCH))
1729 		    give_warning((char_u *)_(bot_top_msg), TRUE);
1730 	    }
1731 
1732 	    /* If we are back at the starting line and there is no match then
1733 	     * give up. */
1734 	    if (lnum == wp->w_cursor.lnum && !found_one)
1735 		break;
1736 
1737 	    /* Skip the characters at the start of the next line that were
1738 	     * included in a match crossing line boundaries. */
1739 	    if (attr == HLF_COUNT)
1740 		skip = (int)(p - endp);
1741 	    else
1742 		skip = 0;
1743 
1744 	    /* Capcol skips over the inserted space. */
1745 	    --capcol;
1746 
1747 	    /* But after empty line check first word in next line */
1748 	    if (*skipwhite(line) == NUL)
1749 		capcol = 0;
1750 	}
1751 
1752 	line_breakcheck();
1753     }
1754 
1755     vim_free(buf);
1756     return 0;
1757 }
1758 
1759 /*
1760  * For spell checking: concatenate the start of the following line "line" into
1761  * "buf", blanking-out special characters.  Copy less then "maxlen" bytes.
1762  * Keep the blanks at the start of the next line, this is used in win_line()
1763  * to skip those bytes if the word was OK.
1764  */
1765     void
1766 spell_cat_line(char_u *buf, char_u *line, int maxlen)
1767 {
1768     char_u	*p;
1769     int		n;
1770 
1771     p = skipwhite(line);
1772     while (vim_strchr((char_u *)"*#/\"\t", *p) != NULL)
1773 	p = skipwhite(p + 1);
1774 
1775     if (*p != NUL)
1776     {
1777 	/* Only worth concatenating if there is something else than spaces to
1778 	 * concatenate. */
1779 	n = (int)(p - line) + 1;
1780 	if (n < maxlen - 1)
1781 	{
1782 	    vim_memset(buf, ' ', n);
1783 	    vim_strncpy(buf +  n, p, maxlen - 1 - n);
1784 	}
1785     }
1786 }
1787 
1788 /*
1789  * Structure used for the cookie argument of do_in_runtimepath().
1790  */
1791 typedef struct spelload_S
1792 {
1793     char_u  sl_lang[MAXWLEN + 1];	/* language name */
1794     slang_T *sl_slang;			/* resulting slang_T struct */
1795     int	    sl_nobreak;			/* NOBREAK language found */
1796 } spelload_T;
1797 
1798 /*
1799  * Load word list(s) for "lang" from Vim spell file(s).
1800  * "lang" must be the language without the region: e.g., "en".
1801  */
1802     static void
1803 spell_load_lang(char_u *lang)
1804 {
1805     char_u	fname_enc[85];
1806     int		r;
1807     spelload_T	sl;
1808     int		round;
1809 
1810     /* Copy the language name to pass it to spell_load_cb() as a cookie.
1811      * It's truncated when an error is detected. */
1812     STRCPY(sl.sl_lang, lang);
1813     sl.sl_slang = NULL;
1814     sl.sl_nobreak = FALSE;
1815 
1816     /* We may retry when no spell file is found for the language, an
1817      * autocommand may load it then. */
1818     for (round = 1; round <= 2; ++round)
1819     {
1820 	/*
1821 	 * Find the first spell file for "lang" in 'runtimepath' and load it.
1822 	 */
1823 	vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5,
1824 #ifdef VMS
1825 					"spell/%s_%s.spl",
1826 #else
1827 					"spell/%s.%s.spl",
1828 #endif
1829 							   lang, spell_enc());
1830 	r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl);
1831 
1832 	if (r == FAIL && *sl.sl_lang != NUL)
1833 	{
1834 	    /* Try loading the ASCII version. */
1835 	    vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5,
1836 #ifdef VMS
1837 						  "spell/%s_ascii.spl",
1838 #else
1839 						  "spell/%s.ascii.spl",
1840 #endif
1841 									lang);
1842 	    r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl);
1843 
1844 	    if (r == FAIL && *sl.sl_lang != NUL && round == 1
1845 		    && apply_autocmds(EVENT_SPELLFILEMISSING, lang,
1846 					      curbuf->b_fname, FALSE, curbuf))
1847 		continue;
1848 	    break;
1849 	}
1850 	break;
1851     }
1852 
1853     if (r == FAIL)
1854     {
1855 	smsg(
1856 #ifdef VMS
1857 	_("Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""),
1858 #else
1859 	_("Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""),
1860 #endif
1861 						     lang, spell_enc(), lang);
1862     }
1863     else if (sl.sl_slang != NULL)
1864     {
1865 	/* At least one file was loaded, now load ALL the additions. */
1866 	STRCPY(fname_enc + STRLEN(fname_enc) - 3, "add.spl");
1867 	do_in_runtimepath(fname_enc, DIP_ALL, spell_load_cb, &sl);
1868     }
1869 }
1870 
1871 /*
1872  * Return the encoding used for spell checking: Use 'encoding', except that we
1873  * use "latin1" for "latin9".  And limit to 60 characters (just in case).
1874  */
1875     char_u *
1876 spell_enc(void)
1877 {
1878 
1879     if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0)
1880 	return p_enc;
1881     return (char_u *)"latin1";
1882 }
1883 
1884 /*
1885  * Get the name of the .spl file for the internal wordlist into
1886  * "fname[MAXPATHL]".
1887  */
1888     static void
1889 int_wordlist_spl(char_u *fname)
1890 {
1891     vim_snprintf((char *)fname, MAXPATHL, SPL_FNAME_TMPL,
1892 						  int_wordlist, spell_enc());
1893 }
1894 
1895 /*
1896  * Allocate a new slang_T for language "lang".  "lang" can be NULL.
1897  * Caller must fill "sl_next".
1898  */
1899     slang_T *
1900 slang_alloc(char_u *lang)
1901 {
1902     slang_T *lp;
1903 
1904     lp = (slang_T *)alloc_clear(sizeof(slang_T));
1905     if (lp != NULL)
1906     {
1907 	if (lang != NULL)
1908 	    lp->sl_name = vim_strsave(lang);
1909 	ga_init2(&lp->sl_rep, sizeof(fromto_T), 10);
1910 	ga_init2(&lp->sl_repsal, sizeof(fromto_T), 10);
1911 	lp->sl_compmax = MAXWLEN;
1912 	lp->sl_compsylmax = MAXWLEN;
1913 	hash_init(&lp->sl_wordcount);
1914     }
1915 
1916     return lp;
1917 }
1918 
1919 /*
1920  * Free the contents of an slang_T and the structure itself.
1921  */
1922     void
1923 slang_free(slang_T *lp)
1924 {
1925     vim_free(lp->sl_name);
1926     vim_free(lp->sl_fname);
1927     slang_clear(lp);
1928     vim_free(lp);
1929 }
1930 
1931 /*
1932  * Clear an slang_T so that the file can be reloaded.
1933  */
1934     void
1935 slang_clear(slang_T *lp)
1936 {
1937     garray_T	*gap;
1938     fromto_T	*ftp;
1939     salitem_T	*smp;
1940     int		i;
1941     int		round;
1942 
1943     VIM_CLEAR(lp->sl_fbyts);
1944     VIM_CLEAR(lp->sl_kbyts);
1945     VIM_CLEAR(lp->sl_pbyts);
1946 
1947     VIM_CLEAR(lp->sl_fidxs);
1948     VIM_CLEAR(lp->sl_kidxs);
1949     VIM_CLEAR(lp->sl_pidxs);
1950 
1951     for (round = 1; round <= 2; ++round)
1952     {
1953 	gap = round == 1 ? &lp->sl_rep : &lp->sl_repsal;
1954 	while (gap->ga_len > 0)
1955 	{
1956 	    ftp = &((fromto_T *)gap->ga_data)[--gap->ga_len];
1957 	    vim_free(ftp->ft_from);
1958 	    vim_free(ftp->ft_to);
1959 	}
1960 	ga_clear(gap);
1961     }
1962 
1963     gap = &lp->sl_sal;
1964     if (lp->sl_sofo)
1965     {
1966 	/* "ga_len" is set to 1 without adding an item for latin1 */
1967 	if (gap->ga_data != NULL)
1968 	    /* SOFOFROM and SOFOTO items: free lists of wide characters. */
1969 	    for (i = 0; i < gap->ga_len; ++i)
1970 		vim_free(((int **)gap->ga_data)[i]);
1971     }
1972     else
1973 	/* SAL items: free salitem_T items */
1974 	while (gap->ga_len > 0)
1975 	{
1976 	    smp = &((salitem_T *)gap->ga_data)[--gap->ga_len];
1977 	    vim_free(smp->sm_lead);
1978 	    /* Don't free sm_oneof and sm_rules, they point into sm_lead. */
1979 	    vim_free(smp->sm_to);
1980 	    vim_free(smp->sm_lead_w);
1981 	    vim_free(smp->sm_oneof_w);
1982 	    vim_free(smp->sm_to_w);
1983 	}
1984     ga_clear(gap);
1985 
1986     for (i = 0; i < lp->sl_prefixcnt; ++i)
1987 	vim_regfree(lp->sl_prefprog[i]);
1988     lp->sl_prefixcnt = 0;
1989     VIM_CLEAR(lp->sl_prefprog);
1990 
1991     VIM_CLEAR(lp->sl_info);
1992 
1993     VIM_CLEAR(lp->sl_midword);
1994 
1995     vim_regfree(lp->sl_compprog);
1996     lp->sl_compprog = NULL;
1997     VIM_CLEAR(lp->sl_comprules);
1998     VIM_CLEAR(lp->sl_compstartflags);
1999     VIM_CLEAR(lp->sl_compallflags);
2000 
2001     VIM_CLEAR(lp->sl_syllable);
2002     ga_clear(&lp->sl_syl_items);
2003 
2004     ga_clear_strings(&lp->sl_comppat);
2005 
2006     hash_clear_all(&lp->sl_wordcount, WC_KEY_OFF);
2007     hash_init(&lp->sl_wordcount);
2008 
2009     hash_clear_all(&lp->sl_map_hash, 0);
2010 
2011     /* Clear info from .sug file. */
2012     slang_clear_sug(lp);
2013 
2014     lp->sl_compmax = MAXWLEN;
2015     lp->sl_compminlen = 0;
2016     lp->sl_compsylmax = MAXWLEN;
2017     lp->sl_regions[0] = NUL;
2018 }
2019 
2020 /*
2021  * Clear the info from the .sug file in "lp".
2022  */
2023     void
2024 slang_clear_sug(slang_T *lp)
2025 {
2026     VIM_CLEAR(lp->sl_sbyts);
2027     VIM_CLEAR(lp->sl_sidxs);
2028     close_spellbuf(lp->sl_sugbuf);
2029     lp->sl_sugbuf = NULL;
2030     lp->sl_sugloaded = FALSE;
2031     lp->sl_sugtime = 0;
2032 }
2033 
2034 /*
2035  * Load one spell file and store the info into a slang_T.
2036  * Invoked through do_in_runtimepath().
2037  */
2038     static void
2039 spell_load_cb(char_u *fname, void *cookie)
2040 {
2041     spelload_T	*slp = (spelload_T *)cookie;
2042     slang_T	*slang;
2043 
2044     slang = spell_load_file(fname, slp->sl_lang, NULL, FALSE);
2045     if (slang != NULL)
2046     {
2047 	/* When a previously loaded file has NOBREAK also use it for the
2048 	 * ".add" files. */
2049 	if (slp->sl_nobreak && slang->sl_add)
2050 	    slang->sl_nobreak = TRUE;
2051 	else if (slang->sl_nobreak)
2052 	    slp->sl_nobreak = TRUE;
2053 
2054 	slp->sl_slang = slang;
2055     }
2056 }
2057 
2058 
2059 /*
2060  * Add a word to the hashtable of common words.
2061  * If it's already there then the counter is increased.
2062  */
2063     void
2064 count_common_word(
2065     slang_T	*lp,
2066     char_u	*word,
2067     int		len,	    /* word length, -1 for upto NUL */
2068     int		count)	    /* 1 to count once, 10 to init */
2069 {
2070     hash_T	hash;
2071     hashitem_T	*hi;
2072     wordcount_T	*wc;
2073     char_u	buf[MAXWLEN];
2074     char_u	*p;
2075 
2076     if (len == -1)
2077 	p = word;
2078     else
2079     {
2080 	vim_strncpy(buf, word, len);
2081 	p = buf;
2082     }
2083 
2084     hash = hash_hash(p);
2085     hi = hash_lookup(&lp->sl_wordcount, p, hash);
2086     if (HASHITEM_EMPTY(hi))
2087     {
2088 	wc = (wordcount_T *)alloc((unsigned)(sizeof(wordcount_T) + STRLEN(p)));
2089 	if (wc == NULL)
2090 	    return;
2091 	STRCPY(wc->wc_word, p);
2092 	wc->wc_count = count;
2093 	hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash);
2094     }
2095     else
2096     {
2097 	wc = HI2WC(hi);
2098 	if ((wc->wc_count += count) < (unsigned)count)	/* check for overflow */
2099 	    wc->wc_count = MAXWORDCOUNT;
2100     }
2101 }
2102 
2103 /*
2104  * Adjust the score of common words.
2105  */
2106     static int
2107 score_wordcount_adj(
2108     slang_T	*slang,
2109     int		score,
2110     char_u	*word,
2111     int		split)	    /* word was split, less bonus */
2112 {
2113     hashitem_T	*hi;
2114     wordcount_T	*wc;
2115     int		bonus;
2116     int		newscore;
2117 
2118     hi = hash_find(&slang->sl_wordcount, word);
2119     if (!HASHITEM_EMPTY(hi))
2120     {
2121 	wc = HI2WC(hi);
2122 	if (wc->wc_count < SCORE_THRES2)
2123 	    bonus = SCORE_COMMON1;
2124 	else if (wc->wc_count < SCORE_THRES3)
2125 	    bonus = SCORE_COMMON2;
2126 	else
2127 	    bonus = SCORE_COMMON3;
2128 	if (split)
2129 	    newscore = score - bonus / 2;
2130 	else
2131 	    newscore = score - bonus;
2132 	if (newscore < 0)
2133 	    return 0;
2134 	return newscore;
2135     }
2136     return score;
2137 }
2138 
2139 
2140 /*
2141  * Return TRUE if byte "n" appears in "str".
2142  * Like strchr() but independent of locale.
2143  */
2144     int
2145 byte_in_str(char_u *str, int n)
2146 {
2147     char_u	*p;
2148 
2149     for (p = str; *p != NUL; ++p)
2150 	if (*p == n)
2151 	    return TRUE;
2152     return FALSE;
2153 }
2154 
2155 #define SY_MAXLEN   30
2156 typedef struct syl_item_S
2157 {
2158     char_u	sy_chars[SY_MAXLEN];	    /* the sequence of chars */
2159     int		sy_len;
2160 } syl_item_T;
2161 
2162 /*
2163  * Truncate "slang->sl_syllable" at the first slash and put the following items
2164  * in "slang->sl_syl_items".
2165  */
2166     int
2167 init_syl_tab(slang_T *slang)
2168 {
2169     char_u	*p;
2170     char_u	*s;
2171     int		l;
2172     syl_item_T	*syl;
2173 
2174     ga_init2(&slang->sl_syl_items, sizeof(syl_item_T), 4);
2175     p = vim_strchr(slang->sl_syllable, '/');
2176     while (p != NULL)
2177     {
2178 	*p++ = NUL;
2179 	if (*p == NUL)	    /* trailing slash */
2180 	    break;
2181 	s = p;
2182 	p = vim_strchr(p, '/');
2183 	if (p == NULL)
2184 	    l = (int)STRLEN(s);
2185 	else
2186 	    l = (int)(p - s);
2187 	if (l >= SY_MAXLEN)
2188 	    return SP_FORMERROR;
2189 	if (ga_grow(&slang->sl_syl_items, 1) == FAIL)
2190 	    return SP_OTHERERROR;
2191 	syl = ((syl_item_T *)slang->sl_syl_items.ga_data)
2192 					       + slang->sl_syl_items.ga_len++;
2193 	vim_strncpy(syl->sy_chars, s, l);
2194 	syl->sy_len = l;
2195     }
2196     return OK;
2197 }
2198 
2199 /*
2200  * Count the number of syllables in "word".
2201  * When "word" contains spaces the syllables after the last space are counted.
2202  * Returns zero if syllables are not defines.
2203  */
2204     static int
2205 count_syllables(slang_T *slang, char_u *word)
2206 {
2207     int		cnt = 0;
2208     int		skip = FALSE;
2209     char_u	*p;
2210     int		len;
2211     int		i;
2212     syl_item_T	*syl;
2213     int		c;
2214 
2215     if (slang->sl_syllable == NULL)
2216 	return 0;
2217 
2218     for (p = word; *p != NUL; p += len)
2219     {
2220 	/* When running into a space reset counter. */
2221 	if (*p == ' ')
2222 	{
2223 	    len = 1;
2224 	    cnt = 0;
2225 	    continue;
2226 	}
2227 
2228 	/* Find longest match of syllable items. */
2229 	len = 0;
2230 	for (i = 0; i < slang->sl_syl_items.ga_len; ++i)
2231 	{
2232 	    syl = ((syl_item_T *)slang->sl_syl_items.ga_data) + i;
2233 	    if (syl->sy_len > len
2234 			       && STRNCMP(p, syl->sy_chars, syl->sy_len) == 0)
2235 		len = syl->sy_len;
2236 	}
2237 	if (len != 0)	/* found a match, count syllable  */
2238 	{
2239 	    ++cnt;
2240 	    skip = FALSE;
2241 	}
2242 	else
2243 	{
2244 	    /* No recognized syllable item, at least a syllable char then? */
2245 	    c = mb_ptr2char(p);
2246 	    len = (*mb_ptr2len)(p);
2247 	    if (vim_strchr(slang->sl_syllable, c) == NULL)
2248 		skip = FALSE;	    /* No, search for next syllable */
2249 	    else if (!skip)
2250 	    {
2251 		++cnt;		    /* Yes, count it */
2252 		skip = TRUE;	    /* don't count following syllable chars */
2253 	    }
2254 	}
2255     }
2256     return cnt;
2257 }
2258 
2259 /*
2260  * Parse 'spelllang' and set w_s->b_langp accordingly.
2261  * Returns NULL if it's OK, an error message otherwise.
2262  */
2263     char *
2264 did_set_spelllang(win_T *wp)
2265 {
2266     garray_T	ga;
2267     char_u	*splp;
2268     char_u	*region;
2269     char_u	region_cp[3];
2270     int		filename;
2271     int		region_mask;
2272     slang_T	*slang;
2273     int		c;
2274     char_u	lang[MAXWLEN + 1];
2275     char_u	spf_name[MAXPATHL];
2276     int		len;
2277     char_u	*p;
2278     int		round;
2279     char_u	*spf;
2280     char_u	*use_region = NULL;
2281     int		dont_use_region = FALSE;
2282     int		nobreak = FALSE;
2283     int		i, j;
2284     langp_T	*lp, *lp2;
2285     static int	recursive = FALSE;
2286     char	*ret_msg = NULL;
2287     char_u	*spl_copy;
2288     bufref_T	bufref;
2289 
2290     set_bufref(&bufref, wp->w_buffer);
2291 
2292     /* We don't want to do this recursively.  May happen when a language is
2293      * not available and the SpellFileMissing autocommand opens a new buffer
2294      * in which 'spell' is set. */
2295     if (recursive)
2296 	return NULL;
2297     recursive = TRUE;
2298 
2299     ga_init2(&ga, sizeof(langp_T), 2);
2300     clear_midword(wp);
2301 
2302     /* Make a copy of 'spelllang', the SpellFileMissing autocommands may change
2303      * it under our fingers. */
2304     spl_copy = vim_strsave(wp->w_s->b_p_spl);
2305     if (spl_copy == NULL)
2306 	goto theend;
2307 
2308     wp->w_s->b_cjk = 0;
2309 
2310     /* Loop over comma separated language names. */
2311     for (splp = spl_copy; *splp != NUL; )
2312     {
2313 	/* Get one language name. */
2314 	copy_option_part(&splp, lang, MAXWLEN, ",");
2315 	region = NULL;
2316 	len = (int)STRLEN(lang);
2317 
2318 	if (STRCMP(lang, "cjk") == 0)
2319 	{
2320 	    wp->w_s->b_cjk = 1;
2321 	    continue;
2322 	}
2323 
2324 	/* If the name ends in ".spl" use it as the name of the spell file.
2325 	 * If there is a region name let "region" point to it and remove it
2326 	 * from the name. */
2327 	if (len > 4 && fnamecmp(lang + len - 4, ".spl") == 0)
2328 	{
2329 	    filename = TRUE;
2330 
2331 	    /* Locate a region and remove it from the file name. */
2332 	    p = vim_strchr(gettail(lang), '_');
2333 	    if (p != NULL && ASCII_ISALPHA(p[1]) && ASCII_ISALPHA(p[2])
2334 						      && !ASCII_ISALPHA(p[3]))
2335 	    {
2336 		vim_strncpy(region_cp, p + 1, 2);
2337 		mch_memmove(p, p + 3, len - (p - lang) - 2);
2338 		region = region_cp;
2339 	    }
2340 	    else
2341 		dont_use_region = TRUE;
2342 
2343 	    /* Check if we loaded this language before. */
2344 	    for (slang = first_lang; slang != NULL; slang = slang->sl_next)
2345 		if (fullpathcmp(lang, slang->sl_fname, FALSE) == FPC_SAME)
2346 		    break;
2347 	}
2348 	else
2349 	{
2350 	    filename = FALSE;
2351 	    if (len > 3 && lang[len - 3] == '_')
2352 	    {
2353 		region = lang + len - 2;
2354 		len -= 3;
2355 		lang[len] = NUL;
2356 	    }
2357 	    else
2358 		dont_use_region = TRUE;
2359 
2360 	    /* Check if we loaded this language before. */
2361 	    for (slang = first_lang; slang != NULL; slang = slang->sl_next)
2362 		if (STRICMP(lang, slang->sl_name) == 0)
2363 		    break;
2364 	}
2365 
2366 	if (region != NULL)
2367 	{
2368 	    /* If the region differs from what was used before then don't
2369 	     * use it for 'spellfile'. */
2370 	    if (use_region != NULL && STRCMP(region, use_region) != 0)
2371 		dont_use_region = TRUE;
2372 	    use_region = region;
2373 	}
2374 
2375 	/* If not found try loading the language now. */
2376 	if (slang == NULL)
2377 	{
2378 	    if (filename)
2379 		(void)spell_load_file(lang, lang, NULL, FALSE);
2380 	    else
2381 	    {
2382 		spell_load_lang(lang);
2383 		/* SpellFileMissing autocommands may do anything, including
2384 		 * destroying the buffer we are using... */
2385 		if (!bufref_valid(&bufref))
2386 		{
2387 		    ret_msg = N_("E797: SpellFileMissing autocommand deleted buffer");
2388 		    goto theend;
2389 		}
2390 	    }
2391 	}
2392 
2393 	/*
2394 	 * Loop over the languages, there can be several files for "lang".
2395 	 */
2396 	for (slang = first_lang; slang != NULL; slang = slang->sl_next)
2397 	    if (filename ? fullpathcmp(lang, slang->sl_fname, FALSE) == FPC_SAME
2398 			 : STRICMP(lang, slang->sl_name) == 0)
2399 	    {
2400 		region_mask = REGION_ALL;
2401 		if (!filename && region != NULL)
2402 		{
2403 		    /* find region in sl_regions */
2404 		    c = find_region(slang->sl_regions, region);
2405 		    if (c == REGION_ALL)
2406 		    {
2407 			if (slang->sl_add)
2408 			{
2409 			    if (*slang->sl_regions != NUL)
2410 				/* This addition file is for other regions. */
2411 				region_mask = 0;
2412 			}
2413 			else
2414 			    /* This is probably an error.  Give a warning and
2415 			     * accept the words anyway. */
2416 			    smsg(_("Warning: region %s not supported"),
2417 								      region);
2418 		    }
2419 		    else
2420 			region_mask = 1 << c;
2421 		}
2422 
2423 		if (region_mask != 0)
2424 		{
2425 		    if (ga_grow(&ga, 1) == FAIL)
2426 		    {
2427 			ga_clear(&ga);
2428 			ret_msg = e_outofmem;
2429 			goto theend;
2430 		    }
2431 		    LANGP_ENTRY(ga, ga.ga_len)->lp_slang = slang;
2432 		    LANGP_ENTRY(ga, ga.ga_len)->lp_region = region_mask;
2433 		    ++ga.ga_len;
2434 		    use_midword(slang, wp);
2435 		    if (slang->sl_nobreak)
2436 			nobreak = TRUE;
2437 		}
2438 	    }
2439     }
2440 
2441     /* round 0: load int_wordlist, if possible.
2442      * round 1: load first name in 'spellfile'.
2443      * round 2: load second name in 'spellfile.
2444      * etc. */
2445     spf = curwin->w_s->b_p_spf;
2446     for (round = 0; round == 0 || *spf != NUL; ++round)
2447     {
2448 	if (round == 0)
2449 	{
2450 	    /* Internal wordlist, if there is one. */
2451 	    if (int_wordlist == NULL)
2452 		continue;
2453 	    int_wordlist_spl(spf_name);
2454 	}
2455 	else
2456 	{
2457 	    /* One entry in 'spellfile'. */
2458 	    copy_option_part(&spf, spf_name, MAXPATHL - 5, ",");
2459 	    STRCAT(spf_name, ".spl");
2460 
2461 	    /* If it was already found above then skip it. */
2462 	    for (c = 0; c < ga.ga_len; ++c)
2463 	    {
2464 		p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname;
2465 		if (p != NULL && fullpathcmp(spf_name, p, FALSE) == FPC_SAME)
2466 		    break;
2467 	    }
2468 	    if (c < ga.ga_len)
2469 		continue;
2470 	}
2471 
2472 	/* Check if it was loaded already. */
2473 	for (slang = first_lang; slang != NULL; slang = slang->sl_next)
2474 	    if (fullpathcmp(spf_name, slang->sl_fname, FALSE) == FPC_SAME)
2475 		break;
2476 	if (slang == NULL)
2477 	{
2478 	    /* Not loaded, try loading it now.  The language name includes the
2479 	     * region name, the region is ignored otherwise.  for int_wordlist
2480 	     * use an arbitrary name. */
2481 	    if (round == 0)
2482 		STRCPY(lang, "internal wordlist");
2483 	    else
2484 	    {
2485 		vim_strncpy(lang, gettail(spf_name), MAXWLEN);
2486 		p = vim_strchr(lang, '.');
2487 		if (p != NULL)
2488 		    *p = NUL;	/* truncate at ".encoding.add" */
2489 	    }
2490 	    slang = spell_load_file(spf_name, lang, NULL, TRUE);
2491 
2492 	    /* If one of the languages has NOBREAK we assume the addition
2493 	     * files also have this. */
2494 	    if (slang != NULL && nobreak)
2495 		slang->sl_nobreak = TRUE;
2496 	}
2497 	if (slang != NULL && ga_grow(&ga, 1) == OK)
2498 	{
2499 	    region_mask = REGION_ALL;
2500 	    if (use_region != NULL && !dont_use_region)
2501 	    {
2502 		/* find region in sl_regions */
2503 		c = find_region(slang->sl_regions, use_region);
2504 		if (c != REGION_ALL)
2505 		    region_mask = 1 << c;
2506 		else if (*slang->sl_regions != NUL)
2507 		    /* This spell file is for other regions. */
2508 		    region_mask = 0;
2509 	    }
2510 
2511 	    if (region_mask != 0)
2512 	    {
2513 		LANGP_ENTRY(ga, ga.ga_len)->lp_slang = slang;
2514 		LANGP_ENTRY(ga, ga.ga_len)->lp_sallang = NULL;
2515 		LANGP_ENTRY(ga, ga.ga_len)->lp_replang = NULL;
2516 		LANGP_ENTRY(ga, ga.ga_len)->lp_region = region_mask;
2517 		++ga.ga_len;
2518 		use_midword(slang, wp);
2519 	    }
2520 	}
2521     }
2522 
2523     /* Everything is fine, store the new b_langp value. */
2524     ga_clear(&wp->w_s->b_langp);
2525     wp->w_s->b_langp = ga;
2526 
2527     /* For each language figure out what language to use for sound folding and
2528      * REP items.  If the language doesn't support it itself use another one
2529      * with the same name.  E.g. for "en-math" use "en". */
2530     for (i = 0; i < ga.ga_len; ++i)
2531     {
2532 	lp = LANGP_ENTRY(ga, i);
2533 
2534 	/* sound folding */
2535 	if (lp->lp_slang->sl_sal.ga_len > 0)
2536 	    /* language does sound folding itself */
2537 	    lp->lp_sallang = lp->lp_slang;
2538 	else
2539 	    /* find first similar language that does sound folding */
2540 	    for (j = 0; j < ga.ga_len; ++j)
2541 	    {
2542 		lp2 = LANGP_ENTRY(ga, j);
2543 		if (lp2->lp_slang->sl_sal.ga_len > 0
2544 			&& STRNCMP(lp->lp_slang->sl_name,
2545 					      lp2->lp_slang->sl_name, 2) == 0)
2546 		{
2547 		    lp->lp_sallang = lp2->lp_slang;
2548 		    break;
2549 		}
2550 	    }
2551 
2552 	/* REP items */
2553 	if (lp->lp_slang->sl_rep.ga_len > 0)
2554 	    /* language has REP items itself */
2555 	    lp->lp_replang = lp->lp_slang;
2556 	else
2557 	    /* find first similar language that has REP items */
2558 	    for (j = 0; j < ga.ga_len; ++j)
2559 	    {
2560 		lp2 = LANGP_ENTRY(ga, j);
2561 		if (lp2->lp_slang->sl_rep.ga_len > 0
2562 			&& STRNCMP(lp->lp_slang->sl_name,
2563 					      lp2->lp_slang->sl_name, 2) == 0)
2564 		{
2565 		    lp->lp_replang = lp2->lp_slang;
2566 		    break;
2567 		}
2568 	    }
2569     }
2570 
2571 theend:
2572     vim_free(spl_copy);
2573     recursive = FALSE;
2574     redraw_win_later(wp, NOT_VALID);
2575     return ret_msg;
2576 }
2577 
2578 /*
2579  * Clear the midword characters for buffer "buf".
2580  */
2581     static void
2582 clear_midword(win_T *wp)
2583 {
2584     vim_memset(wp->w_s->b_spell_ismw, 0, 256);
2585     VIM_CLEAR(wp->w_s->b_spell_ismw_mb);
2586 }
2587 
2588 /*
2589  * Use the "sl_midword" field of language "lp" for buffer "buf".
2590  * They add up to any currently used midword characters.
2591  */
2592     static void
2593 use_midword(slang_T *lp, win_T *wp)
2594 {
2595     char_u	*p;
2596 
2597     if (lp->sl_midword == NULL)	    /* there aren't any */
2598 	return;
2599 
2600     for (p = lp->sl_midword; *p != NUL; )
2601 	if (has_mbyte)
2602 	{
2603 	    int	    c, l, n;
2604 	    char_u  *bp;
2605 
2606 	    c = mb_ptr2char(p);
2607 	    l = (*mb_ptr2len)(p);
2608 	    if (c < 256 && l <= 2)
2609 		wp->w_s->b_spell_ismw[c] = TRUE;
2610 	    else if (wp->w_s->b_spell_ismw_mb == NULL)
2611 		/* First multi-byte char in "b_spell_ismw_mb". */
2612 		wp->w_s->b_spell_ismw_mb = vim_strnsave(p, l);
2613 	    else
2614 	    {
2615 		/* Append multi-byte chars to "b_spell_ismw_mb". */
2616 		n = (int)STRLEN(wp->w_s->b_spell_ismw_mb);
2617 		bp = vim_strnsave(wp->w_s->b_spell_ismw_mb, n + l);
2618 		if (bp != NULL)
2619 		{
2620 		    vim_free(wp->w_s->b_spell_ismw_mb);
2621 		    wp->w_s->b_spell_ismw_mb = bp;
2622 		    vim_strncpy(bp + n, p, l);
2623 		}
2624 	    }
2625 	    p += l;
2626 	}
2627 	else
2628 	    wp->w_s->b_spell_ismw[*p++] = TRUE;
2629 }
2630 
2631 /*
2632  * Find the region "region[2]" in "rp" (points to "sl_regions").
2633  * Each region is simply stored as the two characters of its name.
2634  * Returns the index if found (first is 0), REGION_ALL if not found.
2635  */
2636     static int
2637 find_region(char_u *rp, char_u *region)
2638 {
2639     int		i;
2640 
2641     for (i = 0; ; i += 2)
2642     {
2643 	if (rp[i] == NUL)
2644 	    return REGION_ALL;
2645 	if (rp[i] == region[0] && rp[i + 1] == region[1])
2646 	    break;
2647     }
2648     return i / 2;
2649 }
2650 
2651 /*
2652  * Return case type of word:
2653  * w word	0
2654  * Word		WF_ONECAP
2655  * W WORD	WF_ALLCAP
2656  * WoRd	wOrd	WF_KEEPCAP
2657  */
2658     int
2659 captype(
2660     char_u	*word,
2661     char_u	*end)	    /* When NULL use up to NUL byte. */
2662 {
2663     char_u	*p;
2664     int		c;
2665     int		firstcap;
2666     int		allcap;
2667     int		past_second = FALSE;	/* past second word char */
2668 
2669     /* find first letter */
2670     for (p = word; !spell_iswordp_nmw(p, curwin); MB_PTR_ADV(p))
2671 	if (end == NULL ? *p == NUL : p >= end)
2672 	    return 0;	    /* only non-word characters, illegal word */
2673     if (has_mbyte)
2674 	c = mb_ptr2char_adv(&p);
2675     else
2676 	c = *p++;
2677     firstcap = allcap = SPELL_ISUPPER(c);
2678 
2679     /*
2680      * Need to check all letters to find a word with mixed upper/lower.
2681      * But a word with an upper char only at start is a ONECAP.
2682      */
2683     for ( ; end == NULL ? *p != NUL : p < end; MB_PTR_ADV(p))
2684 	if (spell_iswordp_nmw(p, curwin))
2685 	{
2686 	    c = PTR2CHAR(p);
2687 	    if (!SPELL_ISUPPER(c))
2688 	    {
2689 		/* UUl -> KEEPCAP */
2690 		if (past_second && allcap)
2691 		    return WF_KEEPCAP;
2692 		allcap = FALSE;
2693 	    }
2694 	    else if (!allcap)
2695 		/* UlU -> KEEPCAP */
2696 		return WF_KEEPCAP;
2697 	    past_second = TRUE;
2698 	}
2699 
2700     if (allcap)
2701 	return WF_ALLCAP;
2702     if (firstcap)
2703 	return WF_ONECAP;
2704     return 0;
2705 }
2706 
2707 /*
2708  * Like captype() but for a KEEPCAP word add ONECAP if the word starts with a
2709  * capital.  So that make_case_word() can turn WOrd into Word.
2710  * Add ALLCAP for "WOrD".
2711  */
2712     static int
2713 badword_captype(char_u *word, char_u *end)
2714 {
2715     int		flags = captype(word, end);
2716     int		c;
2717     int		l, u;
2718     int		first;
2719     char_u	*p;
2720 
2721     if (flags & WF_KEEPCAP)
2722     {
2723 	/* Count the number of UPPER and lower case letters. */
2724 	l = u = 0;
2725 	first = FALSE;
2726 	for (p = word; p < end; MB_PTR_ADV(p))
2727 	{
2728 	    c = PTR2CHAR(p);
2729 	    if (SPELL_ISUPPER(c))
2730 	    {
2731 		++u;
2732 		if (p == word)
2733 		    first = TRUE;
2734 	    }
2735 	    else
2736 		++l;
2737 	}
2738 
2739 	/* If there are more UPPER than lower case letters suggest an
2740 	 * ALLCAP word.  Otherwise, if the first letter is UPPER then
2741 	 * suggest ONECAP.  Exception: "ALl" most likely should be "All",
2742 	 * require three upper case letters. */
2743 	if (u > l && u > 2)
2744 	    flags |= WF_ALLCAP;
2745 	else if (first)
2746 	    flags |= WF_ONECAP;
2747 
2748 	if (u >= 2 && l >= 2)	/* maCARONI maCAroni */
2749 	    flags |= WF_MIXCAP;
2750     }
2751     return flags;
2752 }
2753 
2754 /*
2755  * Delete the internal wordlist and its .spl file.
2756  */
2757     void
2758 spell_delete_wordlist(void)
2759 {
2760     char_u	fname[MAXPATHL];
2761 
2762     if (int_wordlist != NULL)
2763     {
2764 	mch_remove(int_wordlist);
2765 	int_wordlist_spl(fname);
2766 	mch_remove(fname);
2767 	VIM_CLEAR(int_wordlist);
2768     }
2769 }
2770 
2771 /*
2772  * Free all languages.
2773  */
2774     void
2775 spell_free_all(void)
2776 {
2777     slang_T	*slang;
2778     buf_T	*buf;
2779 
2780     /* Go through all buffers and handle 'spelllang'. <VN> */
2781     FOR_ALL_BUFFERS(buf)
2782 	ga_clear(&buf->b_s.b_langp);
2783 
2784     while (first_lang != NULL)
2785     {
2786 	slang = first_lang;
2787 	first_lang = slang->sl_next;
2788 	slang_free(slang);
2789     }
2790 
2791     spell_delete_wordlist();
2792 
2793     VIM_CLEAR(repl_to);
2794     VIM_CLEAR(repl_from);
2795 }
2796 
2797 /*
2798  * Clear all spelling tables and reload them.
2799  * Used after 'encoding' is set and when ":mkspell" was used.
2800  */
2801     void
2802 spell_reload(void)
2803 {
2804     win_T	*wp;
2805 
2806     /* Initialize the table for spell_iswordp(). */
2807     init_spell_chartab();
2808 
2809     /* Unload all allocated memory. */
2810     spell_free_all();
2811 
2812     /* Go through all buffers and handle 'spelllang'. */
2813     FOR_ALL_WINDOWS(wp)
2814     {
2815 	/* Only load the wordlists when 'spelllang' is set and there is a
2816 	 * window for this buffer in which 'spell' is set. */
2817 	if (*wp->w_s->b_p_spl != NUL)
2818 	{
2819 		if (wp->w_p_spell)
2820 		{
2821 		    (void)did_set_spelllang(wp);
2822 		    break;
2823 		}
2824 	}
2825     }
2826 }
2827 
2828 /*
2829  * Opposite of offset2bytes().
2830  * "pp" points to the bytes and is advanced over it.
2831  * Returns the offset.
2832  */
2833     static int
2834 bytes2offset(char_u **pp)
2835 {
2836     char_u	*p = *pp;
2837     int		nr;
2838     int		c;
2839 
2840     c = *p++;
2841     if ((c & 0x80) == 0x00)		/* 1 byte */
2842     {
2843 	nr = c - 1;
2844     }
2845     else if ((c & 0xc0) == 0x80)	/* 2 bytes */
2846     {
2847 	nr = (c & 0x3f) - 1;
2848 	nr = nr * 255 + (*p++ - 1);
2849     }
2850     else if ((c & 0xe0) == 0xc0)	/* 3 bytes */
2851     {
2852 	nr = (c & 0x1f) - 1;
2853 	nr = nr * 255 + (*p++ - 1);
2854 	nr = nr * 255 + (*p++ - 1);
2855     }
2856     else				/* 4 bytes */
2857     {
2858 	nr = (c & 0x0f) - 1;
2859 	nr = nr * 255 + (*p++ - 1);
2860 	nr = nr * 255 + (*p++ - 1);
2861 	nr = nr * 255 + (*p++ - 1);
2862     }
2863 
2864     *pp = p;
2865     return nr;
2866 }
2867 
2868 
2869 /*
2870  * Open a spell buffer.  This is a nameless buffer that is not in the buffer
2871  * list and only contains text lines.  Can use a swapfile to reduce memory
2872  * use.
2873  * Most other fields are invalid!  Esp. watch out for string options being
2874  * NULL and there is no undo info.
2875  * Returns NULL when out of memory.
2876  */
2877     buf_T *
2878 open_spellbuf(void)
2879 {
2880     buf_T	*buf;
2881 
2882     buf = (buf_T *)alloc_clear(sizeof(buf_T));
2883     if (buf != NULL)
2884     {
2885 	buf->b_spell = TRUE;
2886 	buf->b_p_swf = TRUE;	/* may create a swap file */
2887 #ifdef FEAT_CRYPT
2888 	buf->b_p_key = empty_option;
2889 #endif
2890 	ml_open(buf);
2891 	ml_open_file(buf);	/* create swap file now */
2892     }
2893     return buf;
2894 }
2895 
2896 /*
2897  * Close the buffer used for spell info.
2898  */
2899     void
2900 close_spellbuf(buf_T *buf)
2901 {
2902     if (buf != NULL)
2903     {
2904 	ml_close(buf, TRUE);
2905 	vim_free(buf);
2906     }
2907 }
2908 
2909 /*
2910  * Init the chartab used for spelling for ASCII.
2911  * EBCDIC is not supported!
2912  */
2913     void
2914 clear_spell_chartab(spelltab_T *sp)
2915 {
2916     int		i;
2917 
2918     /* Init everything to FALSE. */
2919     vim_memset(sp->st_isw, FALSE, sizeof(sp->st_isw));
2920     vim_memset(sp->st_isu, FALSE, sizeof(sp->st_isu));
2921     for (i = 0; i < 256; ++i)
2922     {
2923 	sp->st_fold[i] = i;
2924 	sp->st_upper[i] = i;
2925     }
2926 
2927     /* We include digits.  A word shouldn't start with a digit, but handling
2928      * that is done separately. */
2929     for (i = '0'; i <= '9'; ++i)
2930 	sp->st_isw[i] = TRUE;
2931     for (i = 'A'; i <= 'Z'; ++i)
2932     {
2933 	sp->st_isw[i] = TRUE;
2934 	sp->st_isu[i] = TRUE;
2935 	sp->st_fold[i] = i + 0x20;
2936     }
2937     for (i = 'a'; i <= 'z'; ++i)
2938     {
2939 	sp->st_isw[i] = TRUE;
2940 	sp->st_upper[i] = i - 0x20;
2941     }
2942 }
2943 
2944 /*
2945  * Init the chartab used for spelling.  Only depends on 'encoding'.
2946  * Called once while starting up and when 'encoding' changes.
2947  * The default is to use isalpha(), but the spell file should define the word
2948  * characters to make it possible that 'encoding' differs from the current
2949  * locale.  For utf-8 we don't use isalpha() but our own functions.
2950  */
2951     void
2952 init_spell_chartab(void)
2953 {
2954     int	    i;
2955 
2956     did_set_spelltab = FALSE;
2957     clear_spell_chartab(&spelltab);
2958     if (enc_dbcs)
2959     {
2960 	/* DBCS: assume double-wide characters are word characters. */
2961 	for (i = 128; i <= 255; ++i)
2962 	    if (MB_BYTE2LEN(i) == 2)
2963 		spelltab.st_isw[i] = TRUE;
2964     }
2965     else if (enc_utf8)
2966     {
2967 	for (i = 128; i < 256; ++i)
2968 	{
2969 	    int f = utf_fold(i);
2970 	    int u = utf_toupper(i);
2971 
2972 	    spelltab.st_isu[i] = utf_isupper(i);
2973 	    spelltab.st_isw[i] = spelltab.st_isu[i] || utf_islower(i);
2974 	    /* The folded/upper-cased value is different between latin1 and
2975 	     * utf8 for 0xb5, causing E763 for no good reason.  Use the latin1
2976 	     * value for utf-8 to avoid this. */
2977 	    spelltab.st_fold[i] = (f < 256) ? f : i;
2978 	    spelltab.st_upper[i] = (u < 256) ? u : i;
2979 	}
2980     }
2981     else
2982     {
2983 	/* Rough guess: use locale-dependent library functions. */
2984 	for (i = 128; i < 256; ++i)
2985 	{
2986 	    if (MB_ISUPPER(i))
2987 	    {
2988 		spelltab.st_isw[i] = TRUE;
2989 		spelltab.st_isu[i] = TRUE;
2990 		spelltab.st_fold[i] = MB_TOLOWER(i);
2991 	    }
2992 	    else if (MB_ISLOWER(i))
2993 	    {
2994 		spelltab.st_isw[i] = TRUE;
2995 		spelltab.st_upper[i] = MB_TOUPPER(i);
2996 	    }
2997 	}
2998     }
2999 }
3000 
3001 
3002 /*
3003  * Return TRUE if "p" points to a word character.
3004  * As a special case we see "midword" characters as word character when it is
3005  * followed by a word character.  This finds they'there but not 'they there'.
3006  * Thus this only works properly when past the first character of the word.
3007  */
3008     static int
3009 spell_iswordp(
3010     char_u	*p,
3011     win_T	*wp)	    /* buffer used */
3012 {
3013     char_u	*s;
3014     int		l;
3015     int		c;
3016 
3017     if (has_mbyte)
3018     {
3019 	l = MB_PTR2LEN(p);
3020 	s = p;
3021 	if (l == 1)
3022 	{
3023 	    /* be quick for ASCII */
3024 	    if (wp->w_s->b_spell_ismw[*p])
3025 		s = p + 1;		/* skip a mid-word character */
3026 	}
3027 	else
3028 	{
3029 	    c = mb_ptr2char(p);
3030 	    if (c < 256 ? wp->w_s->b_spell_ismw[c]
3031 		    : (wp->w_s->b_spell_ismw_mb != NULL
3032 			   && vim_strchr(wp->w_s->b_spell_ismw_mb, c) != NULL))
3033 		s = p + l;
3034 	}
3035 
3036 	c = mb_ptr2char(s);
3037 	if (c > 255)
3038 	    return spell_mb_isword_class(mb_get_class(s), wp);
3039 	return spelltab.st_isw[c];
3040     }
3041 
3042     return spelltab.st_isw[wp->w_s->b_spell_ismw[*p] ? p[1] : p[0]];
3043 }
3044 
3045 /*
3046  * Return TRUE if "p" points to a word character.
3047  * Unlike spell_iswordp() this doesn't check for "midword" characters.
3048  */
3049     int
3050 spell_iswordp_nmw(char_u *p, win_T *wp)
3051 {
3052     int		c;
3053 
3054     if (has_mbyte)
3055     {
3056 	c = mb_ptr2char(p);
3057 	if (c > 255)
3058 	    return spell_mb_isword_class(mb_get_class(p), wp);
3059 	return spelltab.st_isw[c];
3060     }
3061     return spelltab.st_isw[*p];
3062 }
3063 
3064 /*
3065  * Return TRUE if word class indicates a word character.
3066  * Only for characters above 255.
3067  * Unicode subscript and superscript are not considered word characters.
3068  * See also dbcs_class() and utf_class() in mbyte.c.
3069  */
3070     static int
3071 spell_mb_isword_class(int cl, win_T *wp)
3072 {
3073     if (wp->w_s->b_cjk)
3074 	/* East Asian characters are not considered word characters. */
3075 	return cl == 2 || cl == 0x2800;
3076     return cl >= 2 && cl != 0x2070 && cl != 0x2080;
3077 }
3078 
3079 /*
3080  * Return TRUE if "p" points to a word character.
3081  * Wide version of spell_iswordp().
3082  */
3083     static int
3084 spell_iswordp_w(int *p, win_T *wp)
3085 {
3086     int		*s;
3087 
3088     if (*p < 256 ? wp->w_s->b_spell_ismw[*p]
3089 		 : (wp->w_s->b_spell_ismw_mb != NULL
3090 			     && vim_strchr(wp->w_s->b_spell_ismw_mb, *p) != NULL))
3091 	s = p + 1;
3092     else
3093 	s = p;
3094 
3095     if (*s > 255)
3096     {
3097 	if (enc_utf8)
3098 	    return spell_mb_isword_class(utf_class(*s), wp);
3099 	if (enc_dbcs)
3100 	    return spell_mb_isword_class(
3101 				dbcs_class((unsigned)*s >> 8, *s & 0xff), wp);
3102 	return 0;
3103     }
3104     return spelltab.st_isw[*s];
3105 }
3106 
3107 /*
3108  * Case-fold "str[len]" into "buf[buflen]".  The result is NUL terminated.
3109  * Uses the character definitions from the .spl file.
3110  * When using a multi-byte 'encoding' the length may change!
3111  * Returns FAIL when something wrong.
3112  */
3113     int
3114 spell_casefold(
3115     char_u	*str,
3116     int		len,
3117     char_u	*buf,
3118     int		buflen)
3119 {
3120     int		i;
3121 
3122     if (len >= buflen)
3123     {
3124 	buf[0] = NUL;
3125 	return FAIL;		/* result will not fit */
3126     }
3127 
3128     if (has_mbyte)
3129     {
3130 	int	outi = 0;
3131 	char_u	*p;
3132 	int	c;
3133 
3134 	/* Fold one character at a time. */
3135 	for (p = str; p < str + len; )
3136 	{
3137 	    if (outi + MB_MAXBYTES > buflen)
3138 	    {
3139 		buf[outi] = NUL;
3140 		return FAIL;
3141 	    }
3142 	    c = mb_cptr2char_adv(&p);
3143 	    outi += mb_char2bytes(SPELL_TOFOLD(c), buf + outi);
3144 	}
3145 	buf[outi] = NUL;
3146     }
3147     else
3148     {
3149 	/* Be quick for non-multibyte encodings. */
3150 	for (i = 0; i < len; ++i)
3151 	    buf[i] = spelltab.st_fold[str[i]];
3152 	buf[i] = NUL;
3153     }
3154 
3155     return OK;
3156 }
3157 
3158 /* values for sps_flags */
3159 #define SPS_BEST    1
3160 #define SPS_FAST    2
3161 #define SPS_DOUBLE  4
3162 
3163 static int sps_flags = SPS_BEST;	/* flags from 'spellsuggest' */
3164 static int sps_limit = 9999;		/* max nr of suggestions given */
3165 
3166 /*
3167  * Check the 'spellsuggest' option.  Return FAIL if it's wrong.
3168  * Sets "sps_flags" and "sps_limit".
3169  */
3170     int
3171 spell_check_sps(void)
3172 {
3173     char_u	*p;
3174     char_u	*s;
3175     char_u	buf[MAXPATHL];
3176     int		f;
3177 
3178     sps_flags = 0;
3179     sps_limit = 9999;
3180 
3181     for (p = p_sps; *p != NUL; )
3182     {
3183 	copy_option_part(&p, buf, MAXPATHL, ",");
3184 
3185 	f = 0;
3186 	if (VIM_ISDIGIT(*buf))
3187 	{
3188 	    s = buf;
3189 	    sps_limit = getdigits(&s);
3190 	    if (*s != NUL && !VIM_ISDIGIT(*s))
3191 		f = -1;
3192 	}
3193 	else if (STRCMP(buf, "best") == 0)
3194 	    f = SPS_BEST;
3195 	else if (STRCMP(buf, "fast") == 0)
3196 	    f = SPS_FAST;
3197 	else if (STRCMP(buf, "double") == 0)
3198 	    f = SPS_DOUBLE;
3199 	else if (STRNCMP(buf, "expr:", 5) != 0
3200 		&& STRNCMP(buf, "file:", 5) != 0)
3201 	    f = -1;
3202 
3203 	if (f == -1 || (sps_flags != 0 && f != 0))
3204 	{
3205 	    sps_flags = SPS_BEST;
3206 	    sps_limit = 9999;
3207 	    return FAIL;
3208 	}
3209 	if (f != 0)
3210 	    sps_flags = f;
3211     }
3212 
3213     if (sps_flags == 0)
3214 	sps_flags = SPS_BEST;
3215 
3216     return OK;
3217 }
3218 
3219 /*
3220  * "z=": Find badly spelled word under or after the cursor.
3221  * Give suggestions for the properly spelled word.
3222  * In Visual mode use the highlighted word as the bad word.
3223  * When "count" is non-zero use that suggestion.
3224  */
3225     void
3226 spell_suggest(int count)
3227 {
3228     char_u	*line;
3229     pos_T	prev_cursor = curwin->w_cursor;
3230     char_u	wcopy[MAXWLEN + 2];
3231     char_u	*p;
3232     int		i;
3233     int		c;
3234     suginfo_T	sug;
3235     suggest_T	*stp;
3236     int		mouse_used;
3237     int		need_cap;
3238     int		limit;
3239     int		selected = count;
3240     int		badlen = 0;
3241     int		msg_scroll_save = msg_scroll;
3242 
3243     if (no_spell_checking(curwin))
3244 	return;
3245 
3246     if (VIsual_active)
3247     {
3248 	/* Use the Visually selected text as the bad word.  But reject
3249 	 * a multi-line selection. */
3250 	if (curwin->w_cursor.lnum != VIsual.lnum)
3251 	{
3252 	    vim_beep(BO_SPELL);
3253 	    return;
3254 	}
3255 	badlen = (int)curwin->w_cursor.col - (int)VIsual.col;
3256 	if (badlen < 0)
3257 	    badlen = -badlen;
3258 	else
3259 	    curwin->w_cursor.col = VIsual.col;
3260 	++badlen;
3261 	end_visual_mode();
3262     }
3263     /* Find the start of the badly spelled word. */
3264     else if (spell_move_to(curwin, FORWARD, TRUE, TRUE, NULL) == 0
3265 	    || curwin->w_cursor.col > prev_cursor.col)
3266     {
3267 	/* No bad word or it starts after the cursor: use the word under the
3268 	 * cursor. */
3269 	curwin->w_cursor = prev_cursor;
3270 	line = ml_get_curline();
3271 	p = line + curwin->w_cursor.col;
3272 	/* Backup to before start of word. */
3273 	while (p > line && spell_iswordp_nmw(p, curwin))
3274 	    MB_PTR_BACK(line, p);
3275 	/* Forward to start of word. */
3276 	while (*p != NUL && !spell_iswordp_nmw(p, curwin))
3277 	    MB_PTR_ADV(p);
3278 
3279 	if (!spell_iswordp_nmw(p, curwin))		/* No word found. */
3280 	{
3281 	    beep_flush();
3282 	    return;
3283 	}
3284 	curwin->w_cursor.col = (colnr_T)(p - line);
3285     }
3286 
3287     /* Get the word and its length. */
3288 
3289     /* Figure out if the word should be capitalised. */
3290     need_cap = check_need_cap(curwin->w_cursor.lnum, curwin->w_cursor.col);
3291 
3292     /* Make a copy of current line since autocommands may free the line. */
3293     line = vim_strsave(ml_get_curline());
3294     if (line == NULL)
3295 	goto skip;
3296 
3297     /* Get the list of suggestions.  Limit to 'lines' - 2 or the number in
3298      * 'spellsuggest', whatever is smaller. */
3299     if (sps_limit > (int)Rows - 2)
3300 	limit = (int)Rows - 2;
3301     else
3302 	limit = sps_limit;
3303     spell_find_suggest(line + curwin->w_cursor.col, badlen, &sug, limit,
3304 							TRUE, need_cap, TRUE);
3305 
3306     if (sug.su_ga.ga_len == 0)
3307 	msg(_("Sorry, no suggestions"));
3308     else if (count > 0)
3309     {
3310 	if (count > sug.su_ga.ga_len)
3311 	    smsg(_("Sorry, only %ld suggestions"),
3312 						      (long)sug.su_ga.ga_len);
3313     }
3314     else
3315     {
3316 	VIM_CLEAR(repl_from);
3317 	VIM_CLEAR(repl_to);
3318 
3319 #ifdef FEAT_RIGHTLEFT
3320 	/* When 'rightleft' is set the list is drawn right-left. */
3321 	cmdmsg_rl = curwin->w_p_rl;
3322 	if (cmdmsg_rl)
3323 	    msg_col = Columns - 1;
3324 #endif
3325 
3326 	/* List the suggestions. */
3327 	msg_start();
3328 	msg_row = Rows - 1;	/* for when 'cmdheight' > 1 */
3329 	lines_left = Rows;	/* avoid more prompt */
3330 	vim_snprintf((char *)IObuff, IOSIZE, _("Change \"%.*s\" to:"),
3331 						sug.su_badlen, sug.su_badptr);
3332 #ifdef FEAT_RIGHTLEFT
3333 	if (cmdmsg_rl && STRNCMP(IObuff, "Change", 6) == 0)
3334 	{
3335 	    /* And now the rabbit from the high hat: Avoid showing the
3336 	     * untranslated message rightleft. */
3337 	    vim_snprintf((char *)IObuff, IOSIZE, ":ot \"%.*s\" egnahC",
3338 						sug.su_badlen, sug.su_badptr);
3339 	}
3340 #endif
3341 	msg_puts((char *)IObuff);
3342 	msg_clr_eos();
3343 	msg_putchar('\n');
3344 
3345 	msg_scroll = TRUE;
3346 	for (i = 0; i < sug.su_ga.ga_len; ++i)
3347 	{
3348 	    stp = &SUG(sug.su_ga, i);
3349 
3350 	    /* The suggested word may replace only part of the bad word, add
3351 	     * the not replaced part. */
3352 	    vim_strncpy(wcopy, stp->st_word, MAXWLEN);
3353 	    if (sug.su_badlen > stp->st_orglen)
3354 		vim_strncpy(wcopy + stp->st_wordlen,
3355 					       sug.su_badptr + stp->st_orglen,
3356 					      sug.su_badlen - stp->st_orglen);
3357 	    vim_snprintf((char *)IObuff, IOSIZE, "%2d", i + 1);
3358 #ifdef FEAT_RIGHTLEFT
3359 	    if (cmdmsg_rl)
3360 		rl_mirror(IObuff);
3361 #endif
3362 	    msg_puts((char *)IObuff);
3363 
3364 	    vim_snprintf((char *)IObuff, IOSIZE, " \"%s\"", wcopy);
3365 	    msg_puts((char *)IObuff);
3366 
3367 	    /* The word may replace more than "su_badlen". */
3368 	    if (sug.su_badlen < stp->st_orglen)
3369 	    {
3370 		vim_snprintf((char *)IObuff, IOSIZE, _(" < \"%.*s\""),
3371 					       stp->st_orglen, sug.su_badptr);
3372 		msg_puts((char *)IObuff);
3373 	    }
3374 
3375 	    if (p_verbose > 0)
3376 	    {
3377 		/* Add the score. */
3378 		if (sps_flags & (SPS_DOUBLE | SPS_BEST))
3379 		    vim_snprintf((char *)IObuff, IOSIZE, " (%s%d - %d)",
3380 			stp->st_salscore ? "s " : "",
3381 			stp->st_score, stp->st_altscore);
3382 		else
3383 		    vim_snprintf((char *)IObuff, IOSIZE, " (%d)",
3384 			    stp->st_score);
3385 #ifdef FEAT_RIGHTLEFT
3386 		if (cmdmsg_rl)
3387 		    /* Mirror the numbers, but keep the leading space. */
3388 		    rl_mirror(IObuff + 1);
3389 #endif
3390 		msg_advance(30);
3391 		msg_puts((char *)IObuff);
3392 	    }
3393 	    msg_putchar('\n');
3394 	}
3395 
3396 #ifdef FEAT_RIGHTLEFT
3397 	cmdmsg_rl = FALSE;
3398 	msg_col = 0;
3399 #endif
3400 	/* Ask for choice. */
3401 	selected = prompt_for_number(&mouse_used);
3402 	if (mouse_used)
3403 	    selected -= lines_left;
3404 	lines_left = Rows;		/* avoid more prompt */
3405 	/* don't delay for 'smd' in normal_cmd() */
3406 	msg_scroll = msg_scroll_save;
3407     }
3408 
3409     if (selected > 0 && selected <= sug.su_ga.ga_len && u_save_cursor() == OK)
3410     {
3411 	/* Save the from and to text for :spellrepall. */
3412 	stp = &SUG(sug.su_ga, selected - 1);
3413 	if (sug.su_badlen > stp->st_orglen)
3414 	{
3415 	    /* Replacing less than "su_badlen", append the remainder to
3416 	     * repl_to. */
3417 	    repl_from = vim_strnsave(sug.su_badptr, sug.su_badlen);
3418 	    vim_snprintf((char *)IObuff, IOSIZE, "%s%.*s", stp->st_word,
3419 		    sug.su_badlen - stp->st_orglen,
3420 					      sug.su_badptr + stp->st_orglen);
3421 	    repl_to = vim_strsave(IObuff);
3422 	}
3423 	else
3424 	{
3425 	    /* Replacing su_badlen or more, use the whole word. */
3426 	    repl_from = vim_strnsave(sug.su_badptr, stp->st_orglen);
3427 	    repl_to = vim_strsave(stp->st_word);
3428 	}
3429 
3430 	/* Replace the word. */
3431 	p = alloc((unsigned)STRLEN(line) - stp->st_orglen
3432 						       + stp->st_wordlen + 1);
3433 	if (p != NULL)
3434 	{
3435 	    c = (int)(sug.su_badptr - line);
3436 	    mch_memmove(p, line, c);
3437 	    STRCPY(p + c, stp->st_word);
3438 	    STRCAT(p, sug.su_badptr + stp->st_orglen);
3439 	    ml_replace(curwin->w_cursor.lnum, p, FALSE);
3440 	    curwin->w_cursor.col = c;
3441 
3442 	    /* For redo we use a change-word command. */
3443 	    ResetRedobuff();
3444 	    AppendToRedobuff((char_u *)"ciw");
3445 	    AppendToRedobuffLit(p + c,
3446 			    stp->st_wordlen + sug.su_badlen - stp->st_orglen);
3447 	    AppendCharToRedobuff(ESC);
3448 
3449 	    /* After this "p" may be invalid. */
3450 	    changed_bytes(curwin->w_cursor.lnum, c);
3451 	}
3452     }
3453     else
3454 	curwin->w_cursor = prev_cursor;
3455 
3456     spell_find_cleanup(&sug);
3457 skip:
3458     vim_free(line);
3459 }
3460 
3461 /*
3462  * Check if the word at line "lnum" column "col" is required to start with a
3463  * capital.  This uses 'spellcapcheck' of the current buffer.
3464  */
3465     static int
3466 check_need_cap(linenr_T lnum, colnr_T col)
3467 {
3468     int		need_cap = FALSE;
3469     char_u	*line;
3470     char_u	*line_copy = NULL;
3471     char_u	*p;
3472     colnr_T	endcol;
3473     regmatch_T	regmatch;
3474 
3475     if (curwin->w_s->b_cap_prog == NULL)
3476 	return FALSE;
3477 
3478     line = ml_get_curline();
3479     endcol = 0;
3480     if (getwhitecols(line) >= (int)col)
3481     {
3482 	/* At start of line, check if previous line is empty or sentence
3483 	 * ends there. */
3484 	if (lnum == 1)
3485 	    need_cap = TRUE;
3486 	else
3487 	{
3488 	    line = ml_get(lnum - 1);
3489 	    if (*skipwhite(line) == NUL)
3490 		need_cap = TRUE;
3491 	    else
3492 	    {
3493 		/* Append a space in place of the line break. */
3494 		line_copy = concat_str(line, (char_u *)" ");
3495 		line = line_copy;
3496 		endcol = (colnr_T)STRLEN(line);
3497 	    }
3498 	}
3499     }
3500     else
3501 	endcol = col;
3502 
3503     if (endcol > 0)
3504     {
3505 	/* Check if sentence ends before the bad word. */
3506 	regmatch.regprog = curwin->w_s->b_cap_prog;
3507 	regmatch.rm_ic = FALSE;
3508 	p = line + endcol;
3509 	for (;;)
3510 	{
3511 	    MB_PTR_BACK(line, p);
3512 	    if (p == line || spell_iswordp_nmw(p, curwin))
3513 		break;
3514 	    if (vim_regexec(&regmatch, p, 0)
3515 					 && regmatch.endp[0] == line + endcol)
3516 	    {
3517 		need_cap = TRUE;
3518 		break;
3519 	    }
3520 	}
3521 	curwin->w_s->b_cap_prog = regmatch.regprog;
3522     }
3523 
3524     vim_free(line_copy);
3525 
3526     return need_cap;
3527 }
3528 
3529 
3530 /*
3531  * ":spellrepall"
3532  */
3533     void
3534 ex_spellrepall(exarg_T *eap UNUSED)
3535 {
3536     pos_T	pos = curwin->w_cursor;
3537     char_u	*frompat;
3538     int		addlen;
3539     char_u	*line;
3540     char_u	*p;
3541     int		save_ws = p_ws;
3542     linenr_T	prev_lnum = 0;
3543 
3544     if (repl_from == NULL || repl_to == NULL)
3545     {
3546 	emsg(_("E752: No previous spell replacement"));
3547 	return;
3548     }
3549     addlen = (int)(STRLEN(repl_to) - STRLEN(repl_from));
3550 
3551     frompat = alloc((unsigned)STRLEN(repl_from) + 7);
3552     if (frompat == NULL)
3553 	return;
3554     sprintf((char *)frompat, "\\V\\<%s\\>", repl_from);
3555     p_ws = FALSE;
3556 
3557     sub_nsubs = 0;
3558     sub_nlines = 0;
3559     curwin->w_cursor.lnum = 0;
3560     while (!got_int)
3561     {
3562 	if (do_search(NULL, '/', frompat, 1L, SEARCH_KEEP, NULL, NULL) == 0
3563 						   || u_save_cursor() == FAIL)
3564 	    break;
3565 
3566 	/* Only replace when the right word isn't there yet.  This happens
3567 	 * when changing "etc" to "etc.". */
3568 	line = ml_get_curline();
3569 	if (addlen <= 0 || STRNCMP(line + curwin->w_cursor.col,
3570 					       repl_to, STRLEN(repl_to)) != 0)
3571 	{
3572 	    p = alloc((unsigned)STRLEN(line) + addlen + 1);
3573 	    if (p == NULL)
3574 		break;
3575 	    mch_memmove(p, line, curwin->w_cursor.col);
3576 	    STRCPY(p + curwin->w_cursor.col, repl_to);
3577 	    STRCAT(p, line + curwin->w_cursor.col + STRLEN(repl_from));
3578 	    ml_replace(curwin->w_cursor.lnum, p, FALSE);
3579 	    changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
3580 
3581 	    if (curwin->w_cursor.lnum != prev_lnum)
3582 	    {
3583 		++sub_nlines;
3584 		prev_lnum = curwin->w_cursor.lnum;
3585 	    }
3586 	    ++sub_nsubs;
3587 	}
3588 	curwin->w_cursor.col += (colnr_T)STRLEN(repl_to);
3589     }
3590 
3591     p_ws = save_ws;
3592     curwin->w_cursor = pos;
3593     vim_free(frompat);
3594 
3595     if (sub_nsubs == 0)
3596 	semsg(_("E753: Not found: %s"), repl_from);
3597     else
3598 	do_sub_msg(FALSE);
3599 }
3600 
3601 /*
3602  * Find spell suggestions for "word".  Return them in the growarray "*gap" as
3603  * a list of allocated strings.
3604  */
3605     void
3606 spell_suggest_list(
3607     garray_T	*gap,
3608     char_u	*word,
3609     int		maxcount,	/* maximum nr of suggestions */
3610     int		need_cap,	/* 'spellcapcheck' matched */
3611     int		interactive)
3612 {
3613     suginfo_T	sug;
3614     int		i;
3615     suggest_T	*stp;
3616     char_u	*wcopy;
3617 
3618     spell_find_suggest(word, 0, &sug, maxcount, FALSE, need_cap, interactive);
3619 
3620     /* Make room in "gap". */
3621     ga_init2(gap, sizeof(char_u *), sug.su_ga.ga_len + 1);
3622     if (ga_grow(gap, sug.su_ga.ga_len) == OK)
3623     {
3624 	for (i = 0; i < sug.su_ga.ga_len; ++i)
3625 	{
3626 	    stp = &SUG(sug.su_ga, i);
3627 
3628 	    /* The suggested word may replace only part of "word", add the not
3629 	     * replaced part. */
3630 	    wcopy = alloc(stp->st_wordlen
3631 		      + (unsigned)STRLEN(sug.su_badptr + stp->st_orglen) + 1);
3632 	    if (wcopy == NULL)
3633 		break;
3634 	    STRCPY(wcopy, stp->st_word);
3635 	    STRCPY(wcopy + stp->st_wordlen, sug.su_badptr + stp->st_orglen);
3636 	    ((char_u **)gap->ga_data)[gap->ga_len++] = wcopy;
3637 	}
3638     }
3639 
3640     spell_find_cleanup(&sug);
3641 }
3642 
3643 /*
3644  * Find spell suggestions for the word at the start of "badptr".
3645  * Return the suggestions in "su->su_ga".
3646  * The maximum number of suggestions is "maxcount".
3647  * Note: does use info for the current window.
3648  * This is based on the mechanisms of Aspell, but completely reimplemented.
3649  */
3650     static void
3651 spell_find_suggest(
3652     char_u	*badptr,
3653     int		badlen,		/* length of bad word or 0 if unknown */
3654     suginfo_T	*su,
3655     int		maxcount,
3656     int		banbadword,	/* don't include badword in suggestions */
3657     int		need_cap,	/* word should start with capital */
3658     int		interactive)
3659 {
3660     hlf_T	attr = HLF_COUNT;
3661     char_u	buf[MAXPATHL];
3662     char_u	*p;
3663     int		do_combine = FALSE;
3664     char_u	*sps_copy;
3665 #ifdef FEAT_EVAL
3666     static int	expr_busy = FALSE;
3667 #endif
3668     int		c;
3669     int		i;
3670     langp_T	*lp;
3671 
3672     /*
3673      * Set the info in "*su".
3674      */
3675     vim_memset(su, 0, sizeof(suginfo_T));
3676     ga_init2(&su->su_ga, (int)sizeof(suggest_T), 10);
3677     ga_init2(&su->su_sga, (int)sizeof(suggest_T), 10);
3678     if (*badptr == NUL)
3679 	return;
3680     hash_init(&su->su_banned);
3681 
3682     su->su_badptr = badptr;
3683     if (badlen != 0)
3684 	su->su_badlen = badlen;
3685     else
3686 	su->su_badlen = spell_check(curwin, su->su_badptr, &attr, NULL, FALSE);
3687     su->su_maxcount = maxcount;
3688     su->su_maxscore = SCORE_MAXINIT;
3689 
3690     if (su->su_badlen >= MAXWLEN)
3691 	su->su_badlen = MAXWLEN - 1;	/* just in case */
3692     vim_strncpy(su->su_badword, su->su_badptr, su->su_badlen);
3693     (void)spell_casefold(su->su_badptr, su->su_badlen,
3694 						    su->su_fbadword, MAXWLEN);
3695     /* TODO: make this work if the case-folded text is longer than the original
3696      * text. Currently an illegal byte causes wrong pointer computations. */
3697     su->su_fbadword[su->su_badlen] = NUL;
3698 
3699     /* get caps flags for bad word */
3700     su->su_badflags = badword_captype(su->su_badptr,
3701 					       su->su_badptr + su->su_badlen);
3702     if (need_cap)
3703 	su->su_badflags |= WF_ONECAP;
3704 
3705     /* Find the default language for sound folding.  We simply use the first
3706      * one in 'spelllang' that supports sound folding.  That's good for when
3707      * using multiple files for one language, it's not that bad when mixing
3708      * languages (e.g., "pl,en"). */
3709     for (i = 0; i < curbuf->b_s.b_langp.ga_len; ++i)
3710     {
3711 	lp = LANGP_ENTRY(curbuf->b_s.b_langp, i);
3712 	if (lp->lp_sallang != NULL)
3713 	{
3714 	    su->su_sallang = lp->lp_sallang;
3715 	    break;
3716 	}
3717     }
3718 
3719     /* Soundfold the bad word with the default sound folding, so that we don't
3720      * have to do this many times. */
3721     if (su->su_sallang != NULL)
3722 	spell_soundfold(su->su_sallang, su->su_fbadword, TRUE,
3723 							  su->su_sal_badword);
3724 
3725     /* If the word is not capitalised and spell_check() doesn't consider the
3726      * word to be bad then it might need to be capitalised.  Add a suggestion
3727      * for that. */
3728     c = PTR2CHAR(su->su_badptr);
3729     if (!SPELL_ISUPPER(c) && attr == HLF_COUNT)
3730     {
3731 	make_case_word(su->su_badword, buf, WF_ONECAP);
3732 	add_suggestion(su, &su->su_ga, buf, su->su_badlen, SCORE_ICASE,
3733 					      0, TRUE, su->su_sallang, FALSE);
3734     }
3735 
3736     /* Ban the bad word itself.  It may appear in another region. */
3737     if (banbadword)
3738 	add_banned(su, su->su_badword);
3739 
3740     /* Make a copy of 'spellsuggest', because the expression may change it. */
3741     sps_copy = vim_strsave(p_sps);
3742     if (sps_copy == NULL)
3743 	return;
3744 
3745     /* Loop over the items in 'spellsuggest'. */
3746     for (p = sps_copy; *p != NUL; )
3747     {
3748 	copy_option_part(&p, buf, MAXPATHL, ",");
3749 
3750 	if (STRNCMP(buf, "expr:", 5) == 0)
3751 	{
3752 #ifdef FEAT_EVAL
3753 	    /* Evaluate an expression.  Skip this when called recursively,
3754 	     * when using spellsuggest() in the expression. */
3755 	    if (!expr_busy)
3756 	    {
3757 		expr_busy = TRUE;
3758 		spell_suggest_expr(su, buf + 5);
3759 		expr_busy = FALSE;
3760 	    }
3761 #endif
3762 	}
3763 	else if (STRNCMP(buf, "file:", 5) == 0)
3764 	    /* Use list of suggestions in a file. */
3765 	    spell_suggest_file(su, buf + 5);
3766 	else
3767 	{
3768 	    /* Use internal method. */
3769 	    spell_suggest_intern(su, interactive);
3770 	    if (sps_flags & SPS_DOUBLE)
3771 		do_combine = TRUE;
3772 	}
3773     }
3774 
3775     vim_free(sps_copy);
3776 
3777     if (do_combine)
3778 	/* Combine the two list of suggestions.  This must be done last,
3779 	 * because sorting changes the order again. */
3780 	score_combine(su);
3781 }
3782 
3783 #ifdef FEAT_EVAL
3784 /*
3785  * Find suggestions by evaluating expression "expr".
3786  */
3787     static void
3788 spell_suggest_expr(suginfo_T *su, char_u *expr)
3789 {
3790     list_T	*list;
3791     listitem_T	*li;
3792     int		score;
3793     char_u	*p;
3794 
3795     /* The work is split up in a few parts to avoid having to export
3796      * suginfo_T.
3797      * First evaluate the expression and get the resulting list. */
3798     list = eval_spell_expr(su->su_badword, expr);
3799     if (list != NULL)
3800     {
3801 	/* Loop over the items in the list. */
3802 	for (li = list->lv_first; li != NULL; li = li->li_next)
3803 	    if (li->li_tv.v_type == VAR_LIST)
3804 	    {
3805 		/* Get the word and the score from the items. */
3806 		score = get_spellword(li->li_tv.vval.v_list, &p);
3807 		if (score >= 0 && score <= su->su_maxscore)
3808 		    add_suggestion(su, &su->su_ga, p, su->su_badlen,
3809 				       score, 0, TRUE, su->su_sallang, FALSE);
3810 	    }
3811 	list_unref(list);
3812     }
3813 
3814     /* Remove bogus suggestions, sort and truncate at "maxcount". */
3815     check_suggestions(su, &su->su_ga);
3816     (void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
3817 }
3818 #endif
3819 
3820 /*
3821  * Find suggestions in file "fname".  Used for "file:" in 'spellsuggest'.
3822  */
3823     static void
3824 spell_suggest_file(suginfo_T *su, char_u *fname)
3825 {
3826     FILE	*fd;
3827     char_u	line[MAXWLEN * 2];
3828     char_u	*p;
3829     int		len;
3830     char_u	cword[MAXWLEN];
3831 
3832     /* Open the file. */
3833     fd = mch_fopen((char *)fname, "r");
3834     if (fd == NULL)
3835     {
3836 	semsg(_(e_notopen), fname);
3837 	return;
3838     }
3839 
3840     /* Read it line by line. */
3841     while (!vim_fgets(line, MAXWLEN * 2, fd) && !got_int)
3842     {
3843 	line_breakcheck();
3844 
3845 	p = vim_strchr(line, '/');
3846 	if (p == NULL)
3847 	    continue;	    /* No Tab found, just skip the line. */
3848 	*p++ = NUL;
3849 	if (STRICMP(su->su_badword, line) == 0)
3850 	{
3851 	    /* Match!  Isolate the good word, until CR or NL. */
3852 	    for (len = 0; p[len] >= ' '; ++len)
3853 		;
3854 	    p[len] = NUL;
3855 
3856 	    /* If the suggestion doesn't have specific case duplicate the case
3857 	     * of the bad word. */
3858 	    if (captype(p, NULL) == 0)
3859 	    {
3860 		make_case_word(p, cword, su->su_badflags);
3861 		p = cword;
3862 	    }
3863 
3864 	    add_suggestion(su, &su->su_ga, p, su->su_badlen,
3865 				  SCORE_FILE, 0, TRUE, su->su_sallang, FALSE);
3866 	}
3867     }
3868 
3869     fclose(fd);
3870 
3871     /* Remove bogus suggestions, sort and truncate at "maxcount". */
3872     check_suggestions(su, &su->su_ga);
3873     (void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
3874 }
3875 
3876 /*
3877  * Find suggestions for the internal method indicated by "sps_flags".
3878  */
3879     static void
3880 spell_suggest_intern(suginfo_T *su, int interactive)
3881 {
3882     /*
3883      * Load the .sug file(s) that are available and not done yet.
3884      */
3885     suggest_load_files();
3886 
3887     /*
3888      * 1. Try special cases, such as repeating a word: "the the" -> "the".
3889      *
3890      * Set a maximum score to limit the combination of operations that is
3891      * tried.
3892      */
3893     suggest_try_special(su);
3894 
3895     /*
3896      * 2. Try inserting/deleting/swapping/changing a letter, use REP entries
3897      *    from the .aff file and inserting a space (split the word).
3898      */
3899     suggest_try_change(su);
3900 
3901     /* For the resulting top-scorers compute the sound-a-like score. */
3902     if (sps_flags & SPS_DOUBLE)
3903 	score_comp_sal(su);
3904 
3905     /*
3906      * 3. Try finding sound-a-like words.
3907      */
3908     if ((sps_flags & SPS_FAST) == 0)
3909     {
3910 	if (sps_flags & SPS_BEST)
3911 	    /* Adjust the word score for the suggestions found so far for how
3912 	     * they sounds like. */
3913 	    rescore_suggestions(su);
3914 
3915 	/*
3916 	 * While going through the soundfold tree "su_maxscore" is the score
3917 	 * for the soundfold word, limits the changes that are being tried,
3918 	 * and "su_sfmaxscore" the rescored score, which is set by
3919 	 * cleanup_suggestions().
3920 	 * First find words with a small edit distance, because this is much
3921 	 * faster and often already finds the top-N suggestions.  If we didn't
3922 	 * find many suggestions try again with a higher edit distance.
3923 	 * "sl_sounddone" is used to avoid doing the same word twice.
3924 	 */
3925 	suggest_try_soundalike_prep();
3926 	su->su_maxscore = SCORE_SFMAX1;
3927 	su->su_sfmaxscore = SCORE_MAXINIT * 3;
3928 	suggest_try_soundalike(su);
3929 	if (su->su_ga.ga_len < SUG_CLEAN_COUNT(su))
3930 	{
3931 	    /* We didn't find enough matches, try again, allowing more
3932 	     * changes to the soundfold word. */
3933 	    su->su_maxscore = SCORE_SFMAX2;
3934 	    suggest_try_soundalike(su);
3935 	    if (su->su_ga.ga_len < SUG_CLEAN_COUNT(su))
3936 	    {
3937 		/* Still didn't find enough matches, try again, allowing even
3938 		 * more changes to the soundfold word. */
3939 		su->su_maxscore = SCORE_SFMAX3;
3940 		suggest_try_soundalike(su);
3941 	    }
3942 	}
3943 	su->su_maxscore = su->su_sfmaxscore;
3944 	suggest_try_soundalike_finish();
3945     }
3946 
3947     /* When CTRL-C was hit while searching do show the results.  Only clear
3948      * got_int when using a command, not for spellsuggest(). */
3949     ui_breakcheck();
3950     if (interactive && got_int)
3951     {
3952 	(void)vgetc();
3953 	got_int = FALSE;
3954     }
3955 
3956     if ((sps_flags & SPS_DOUBLE) == 0 && su->su_ga.ga_len != 0)
3957     {
3958 	if (sps_flags & SPS_BEST)
3959 	    /* Adjust the word score for how it sounds like. */
3960 	    rescore_suggestions(su);
3961 
3962 	/* Remove bogus suggestions, sort and truncate at "maxcount". */
3963 	check_suggestions(su, &su->su_ga);
3964 	(void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
3965     }
3966 }
3967 
3968 /*
3969  * Free the info put in "*su" by spell_find_suggest().
3970  */
3971     static void
3972 spell_find_cleanup(suginfo_T *su)
3973 {
3974     int		i;
3975 
3976     /* Free the suggestions. */
3977     for (i = 0; i < su->su_ga.ga_len; ++i)
3978 	vim_free(SUG(su->su_ga, i).st_word);
3979     ga_clear(&su->su_ga);
3980     for (i = 0; i < su->su_sga.ga_len; ++i)
3981 	vim_free(SUG(su->su_sga, i).st_word);
3982     ga_clear(&su->su_sga);
3983 
3984     /* Free the banned words. */
3985     hash_clear_all(&su->su_banned, 0);
3986 }
3987 
3988 /*
3989  * Make a copy of "word", with the first letter upper or lower cased, to
3990  * "wcopy[MAXWLEN]".  "word" must not be empty.
3991  * The result is NUL terminated.
3992  */
3993     void
3994 onecap_copy(
3995     char_u	*word,
3996     char_u	*wcopy,
3997     int		upper)	    /* TRUE: first letter made upper case */
3998 {
3999     char_u	*p;
4000     int		c;
4001     int		l;
4002 
4003     p = word;
4004     if (has_mbyte)
4005 	c = mb_cptr2char_adv(&p);
4006     else
4007 	c = *p++;
4008     if (upper)
4009 	c = SPELL_TOUPPER(c);
4010     else
4011 	c = SPELL_TOFOLD(c);
4012     if (has_mbyte)
4013 	l = mb_char2bytes(c, wcopy);
4014     else
4015     {
4016 	l = 1;
4017 	wcopy[0] = c;
4018     }
4019     vim_strncpy(wcopy + l, p, MAXWLEN - l - 1);
4020 }
4021 
4022 /*
4023  * Make a copy of "word" with all the letters upper cased into
4024  * "wcopy[MAXWLEN]".  The result is NUL terminated.
4025  */
4026     static void
4027 allcap_copy(char_u *word, char_u *wcopy)
4028 {
4029     char_u	*s;
4030     char_u	*d;
4031     int		c;
4032 
4033     d = wcopy;
4034     for (s = word; *s != NUL; )
4035     {
4036 	if (has_mbyte)
4037 	    c = mb_cptr2char_adv(&s);
4038 	else
4039 	    c = *s++;
4040 
4041 	/* We only change 0xdf to SS when we are certain latin1 is used.  It
4042 	 * would cause weird errors in other 8-bit encodings. */
4043 	if (enc_latin1like && c == 0xdf)
4044 	{
4045 	    c = 'S';
4046 	    if (d - wcopy >= MAXWLEN - 1)
4047 		break;
4048 	    *d++ = c;
4049 	}
4050 	else
4051 	    c = SPELL_TOUPPER(c);
4052 
4053 	if (has_mbyte)
4054 	{
4055 	    if (d - wcopy >= MAXWLEN - MB_MAXBYTES)
4056 		break;
4057 	    d += mb_char2bytes(c, d);
4058 	}
4059 	else
4060 	{
4061 	    if (d - wcopy >= MAXWLEN - 1)
4062 		break;
4063 	    *d++ = c;
4064 	}
4065     }
4066     *d = NUL;
4067 }
4068 
4069 /*
4070  * Try finding suggestions by recognizing specific situations.
4071  */
4072     static void
4073 suggest_try_special(suginfo_T *su)
4074 {
4075     char_u	*p;
4076     size_t	len;
4077     int		c;
4078     char_u	word[MAXWLEN];
4079 
4080     /*
4081      * Recognize a word that is repeated: "the the".
4082      */
4083     p = skiptowhite(su->su_fbadword);
4084     len = p - su->su_fbadword;
4085     p = skipwhite(p);
4086     if (STRLEN(p) == len && STRNCMP(su->su_fbadword, p, len) == 0)
4087     {
4088 	/* Include badflags: if the badword is onecap or allcap
4089 	 * use that for the goodword too: "The the" -> "The". */
4090 	c = su->su_fbadword[len];
4091 	su->su_fbadword[len] = NUL;
4092 	make_case_word(su->su_fbadword, word, su->su_badflags);
4093 	su->su_fbadword[len] = c;
4094 
4095 	/* Give a soundalike score of 0, compute the score as if deleting one
4096 	 * character. */
4097 	add_suggestion(su, &su->su_ga, word, su->su_badlen,
4098 		       RESCORE(SCORE_REP, 0), 0, TRUE, su->su_sallang, FALSE);
4099     }
4100 }
4101 
4102 /*
4103  * Change the 0 to 1 to measure how much time is spent in each state.
4104  * Output is dumped in "suggestprof".
4105  */
4106 #if 0
4107 # define SUGGEST_PROFILE
4108 proftime_T current;
4109 proftime_T total;
4110 proftime_T times[STATE_FINAL + 1];
4111 long counts[STATE_FINAL + 1];
4112 
4113     static void
4114 prof_init(void)
4115 {
4116     for (int i = 0; i <= STATE_FINAL; ++i)
4117     {
4118 	profile_zero(&times[i]);
4119 	counts[i] = 0;
4120     }
4121     profile_start(&current);
4122     profile_start(&total);
4123 }
4124 
4125 /* call before changing state */
4126     static void
4127 prof_store(state_T state)
4128 {
4129     profile_end(&current);
4130     profile_add(&times[state], &current);
4131     ++counts[state];
4132     profile_start(&current);
4133 }
4134 # define PROF_STORE(state) prof_store(state);
4135 
4136     static void
4137 prof_report(char *name)
4138 {
4139     FILE *fd = fopen("suggestprof", "a");
4140 
4141     profile_end(&total);
4142     fprintf(fd, "-----------------------\n");
4143     fprintf(fd, "%s: %s\n", name, profile_msg(&total));
4144     for (int i = 0; i <= STATE_FINAL; ++i)
4145 	fprintf(fd, "%d: %s (%ld)\n", i, profile_msg(&times[i]), counts[i]);
4146     fclose(fd);
4147 }
4148 #else
4149 # define PROF_STORE(state)
4150 #endif
4151 
4152 /*
4153  * Try finding suggestions by adding/removing/swapping letters.
4154  */
4155     static void
4156 suggest_try_change(suginfo_T *su)
4157 {
4158     char_u	fword[MAXWLEN];	    /* copy of the bad word, case-folded */
4159     int		n;
4160     char_u	*p;
4161     int		lpi;
4162     langp_T	*lp;
4163 
4164     /* We make a copy of the case-folded bad word, so that we can modify it
4165      * to find matches (esp. REP items).  Append some more text, changing
4166      * chars after the bad word may help. */
4167     STRCPY(fword, su->su_fbadword);
4168     n = (int)STRLEN(fword);
4169     p = su->su_badptr + su->su_badlen;
4170     (void)spell_casefold(p, (int)STRLEN(p), fword + n, MAXWLEN - n);
4171 
4172     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
4173     {
4174 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
4175 
4176 	/* If reloading a spell file fails it's still in the list but
4177 	 * everything has been cleared. */
4178 	if (lp->lp_slang->sl_fbyts == NULL)
4179 	    continue;
4180 
4181 	/* Try it for this language.  Will add possible suggestions. */
4182 #ifdef SUGGEST_PROFILE
4183 	prof_init();
4184 #endif
4185 	suggest_trie_walk(su, lp, fword, FALSE);
4186 #ifdef SUGGEST_PROFILE
4187 	prof_report("try_change");
4188 #endif
4189     }
4190 }
4191 
4192 /* Check the maximum score, if we go over it we won't try this change. */
4193 #define TRY_DEEPER(su, stack, depth, add) \
4194 		(stack[depth].ts_score + (add) < su->su_maxscore)
4195 
4196 /*
4197  * Try finding suggestions by adding/removing/swapping letters.
4198  *
4199  * This uses a state machine.  At each node in the tree we try various
4200  * operations.  When trying if an operation works "depth" is increased and the
4201  * stack[] is used to store info.  This allows combinations, thus insert one
4202  * character, replace one and delete another.  The number of changes is
4203  * limited by su->su_maxscore.
4204  *
4205  * After implementing this I noticed an article by Kemal Oflazer that
4206  * describes something similar: "Error-tolerant Finite State Recognition with
4207  * Applications to Morphological Analysis and Spelling Correction" (1996).
4208  * The implementation in the article is simplified and requires a stack of
4209  * unknown depth.  The implementation here only needs a stack depth equal to
4210  * the length of the word.
4211  *
4212  * This is also used for the sound-folded word, "soundfold" is TRUE then.
4213  * The mechanism is the same, but we find a match with a sound-folded word
4214  * that comes from one or more original words.  Each of these words may be
4215  * added, this is done by add_sound_suggest().
4216  * Don't use:
4217  *	the prefix tree or the keep-case tree
4218  *	"su->su_badlen"
4219  *	anything to do with upper and lower case
4220  *	anything to do with word or non-word characters ("spell_iswordp()")
4221  *	banned words
4222  *	word flags (rare, region, compounding)
4223  *	word splitting for now
4224  *	"similar_chars()"
4225  *	use "slang->sl_repsal" instead of "lp->lp_replang->sl_rep"
4226  */
4227     static void
4228 suggest_trie_walk(
4229     suginfo_T	*su,
4230     langp_T	*lp,
4231     char_u	*fword,
4232     int		soundfold)
4233 {
4234     char_u	tword[MAXWLEN];	    /* good word collected so far */
4235     trystate_T	stack[MAXWLEN];
4236     char_u	preword[MAXWLEN * 3]; /* word found with proper case;
4237 				       * concatenation of prefix compound
4238 				       * words and split word.  NUL terminated
4239 				       * when going deeper but not when coming
4240 				       * back. */
4241     char_u	compflags[MAXWLEN];	/* compound flags, one for each word */
4242     trystate_T	*sp;
4243     int		newscore;
4244     int		score;
4245     char_u	*byts, *fbyts, *pbyts;
4246     idx_T	*idxs, *fidxs, *pidxs;
4247     int		depth;
4248     int		c, c2, c3;
4249     int		n = 0;
4250     int		flags;
4251     garray_T	*gap;
4252     idx_T	arridx;
4253     int		len;
4254     char_u	*p;
4255     fromto_T	*ftp;
4256     int		fl = 0, tl;
4257     int		repextra = 0;	    /* extra bytes in fword[] from REP item */
4258     slang_T	*slang = lp->lp_slang;
4259     int		fword_ends;
4260     int		goodword_ends;
4261 #ifdef DEBUG_TRIEWALK
4262     /* Stores the name of the change made at each level. */
4263     char_u	changename[MAXWLEN][80];
4264 #endif
4265     int		breakcheckcount = 1000;
4266     int		compound_ok;
4267 
4268     /*
4269      * Go through the whole case-fold tree, try changes at each node.
4270      * "tword[]" contains the word collected from nodes in the tree.
4271      * "fword[]" the word we are trying to match with (initially the bad
4272      * word).
4273      */
4274     depth = 0;
4275     sp = &stack[0];
4276     vim_memset(sp, 0, sizeof(trystate_T));
4277     sp->ts_curi = 1;
4278 
4279     if (soundfold)
4280     {
4281 	/* Going through the soundfold tree. */
4282 	byts = fbyts = slang->sl_sbyts;
4283 	idxs = fidxs = slang->sl_sidxs;
4284 	pbyts = NULL;
4285 	pidxs = NULL;
4286 	sp->ts_prefixdepth = PFD_NOPREFIX;
4287 	sp->ts_state = STATE_START;
4288     }
4289     else
4290     {
4291 	/*
4292 	 * When there are postponed prefixes we need to use these first.  At
4293 	 * the end of the prefix we continue in the case-fold tree.
4294 	 */
4295 	fbyts = slang->sl_fbyts;
4296 	fidxs = slang->sl_fidxs;
4297 	pbyts = slang->sl_pbyts;
4298 	pidxs = slang->sl_pidxs;
4299 	if (pbyts != NULL)
4300 	{
4301 	    byts = pbyts;
4302 	    idxs = pidxs;
4303 	    sp->ts_prefixdepth = PFD_PREFIXTREE;
4304 	    sp->ts_state = STATE_NOPREFIX;	/* try without prefix first */
4305 	}
4306 	else
4307 	{
4308 	    byts = fbyts;
4309 	    idxs = fidxs;
4310 	    sp->ts_prefixdepth = PFD_NOPREFIX;
4311 	    sp->ts_state = STATE_START;
4312 	}
4313     }
4314 
4315     /*
4316      * Loop to find all suggestions.  At each round we either:
4317      * - For the current state try one operation, advance "ts_curi",
4318      *   increase "depth".
4319      * - When a state is done go to the next, set "ts_state".
4320      * - When all states are tried decrease "depth".
4321      */
4322     while (depth >= 0 && !got_int)
4323     {
4324 	sp = &stack[depth];
4325 	switch (sp->ts_state)
4326 	{
4327 	case STATE_START:
4328 	case STATE_NOPREFIX:
4329 	    /*
4330 	     * Start of node: Deal with NUL bytes, which means
4331 	     * tword[] may end here.
4332 	     */
4333 	    arridx = sp->ts_arridx;	    /* current node in the tree */
4334 	    len = byts[arridx];		    /* bytes in this node */
4335 	    arridx += sp->ts_curi;	    /* index of current byte */
4336 
4337 	    if (sp->ts_prefixdepth == PFD_PREFIXTREE)
4338 	    {
4339 		/* Skip over the NUL bytes, we use them later. */
4340 		for (n = 0; n < len && byts[arridx + n] == 0; ++n)
4341 		    ;
4342 		sp->ts_curi += n;
4343 
4344 		/* Always past NUL bytes now. */
4345 		n = (int)sp->ts_state;
4346 		PROF_STORE(sp->ts_state)
4347 		sp->ts_state = STATE_ENDNUL;
4348 		sp->ts_save_badflags = su->su_badflags;
4349 
4350 		/* At end of a prefix or at start of prefixtree: check for
4351 		 * following word. */
4352 		if (byts[arridx] == 0 || n == (int)STATE_NOPREFIX)
4353 		{
4354 		    /* Set su->su_badflags to the caps type at this position.
4355 		     * Use the caps type until here for the prefix itself. */
4356 		    if (has_mbyte)
4357 			n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
4358 		    else
4359 			n = sp->ts_fidx;
4360 		    flags = badword_captype(su->su_badptr, su->su_badptr + n);
4361 		    su->su_badflags = badword_captype(su->su_badptr + n,
4362 					       su->su_badptr + su->su_badlen);
4363 #ifdef DEBUG_TRIEWALK
4364 		    sprintf(changename[depth], "prefix");
4365 #endif
4366 		    go_deeper(stack, depth, 0);
4367 		    ++depth;
4368 		    sp = &stack[depth];
4369 		    sp->ts_prefixdepth = depth - 1;
4370 		    byts = fbyts;
4371 		    idxs = fidxs;
4372 		    sp->ts_arridx = 0;
4373 
4374 		    /* Move the prefix to preword[] with the right case
4375 		     * and make find_keepcap_word() works. */
4376 		    tword[sp->ts_twordlen] = NUL;
4377 		    make_case_word(tword + sp->ts_splitoff,
4378 					  preword + sp->ts_prewordlen, flags);
4379 		    sp->ts_prewordlen = (char_u)STRLEN(preword);
4380 		    sp->ts_splitoff = sp->ts_twordlen;
4381 		}
4382 		break;
4383 	    }
4384 
4385 	    if (sp->ts_curi > len || byts[arridx] != 0)
4386 	    {
4387 		/* Past bytes in node and/or past NUL bytes. */
4388 		PROF_STORE(sp->ts_state)
4389 		sp->ts_state = STATE_ENDNUL;
4390 		sp->ts_save_badflags = su->su_badflags;
4391 		break;
4392 	    }
4393 
4394 	    /*
4395 	     * End of word in tree.
4396 	     */
4397 	    ++sp->ts_curi;		/* eat one NUL byte */
4398 
4399 	    flags = (int)idxs[arridx];
4400 
4401 	    /* Skip words with the NOSUGGEST flag. */
4402 	    if (flags & WF_NOSUGGEST)
4403 		break;
4404 
4405 	    fword_ends = (fword[sp->ts_fidx] == NUL
4406 			   || (soundfold
4407 			       ? VIM_ISWHITE(fword[sp->ts_fidx])
4408 			       : !spell_iswordp(fword + sp->ts_fidx, curwin)));
4409 	    tword[sp->ts_twordlen] = NUL;
4410 
4411 	    if (sp->ts_prefixdepth <= PFD_NOTSPECIAL
4412 					&& (sp->ts_flags & TSF_PREFIXOK) == 0)
4413 	    {
4414 		/* There was a prefix before the word.  Check that the prefix
4415 		 * can be used with this word. */
4416 		/* Count the length of the NULs in the prefix.  If there are
4417 		 * none this must be the first try without a prefix.  */
4418 		n = stack[sp->ts_prefixdepth].ts_arridx;
4419 		len = pbyts[n++];
4420 		for (c = 0; c < len && pbyts[n + c] == 0; ++c)
4421 		    ;
4422 		if (c > 0)
4423 		{
4424 		    c = valid_word_prefix(c, n, flags,
4425 				       tword + sp->ts_splitoff, slang, FALSE);
4426 		    if (c == 0)
4427 			break;
4428 
4429 		    /* Use the WF_RARE flag for a rare prefix. */
4430 		    if (c & WF_RAREPFX)
4431 			flags |= WF_RARE;
4432 
4433 		    /* Tricky: when checking for both prefix and compounding
4434 		     * we run into the prefix flag first.
4435 		     * Remember that it's OK, so that we accept the prefix
4436 		     * when arriving at a compound flag. */
4437 		    sp->ts_flags |= TSF_PREFIXOK;
4438 		}
4439 	    }
4440 
4441 	    /* Check NEEDCOMPOUND: can't use word without compounding.  Do try
4442 	     * appending another compound word below. */
4443 	    if (sp->ts_complen == sp->ts_compsplit && fword_ends
4444 						     && (flags & WF_NEEDCOMP))
4445 		goodword_ends = FALSE;
4446 	    else
4447 		goodword_ends = TRUE;
4448 
4449 	    p = NULL;
4450 	    compound_ok = TRUE;
4451 	    if (sp->ts_complen > sp->ts_compsplit)
4452 	    {
4453 		if (slang->sl_nobreak)
4454 		{
4455 		    /* There was a word before this word.  When there was no
4456 		     * change in this word (it was correct) add the first word
4457 		     * as a suggestion.  If this word was corrected too, we
4458 		     * need to check if a correct word follows. */
4459 		    if (sp->ts_fidx - sp->ts_splitfidx
4460 					  == sp->ts_twordlen - sp->ts_splitoff
4461 			    && STRNCMP(fword + sp->ts_splitfidx,
4462 					tword + sp->ts_splitoff,
4463 					 sp->ts_fidx - sp->ts_splitfidx) == 0)
4464 		    {
4465 			preword[sp->ts_prewordlen] = NUL;
4466 			newscore = score_wordcount_adj(slang, sp->ts_score,
4467 						 preword + sp->ts_prewordlen,
4468 						 sp->ts_prewordlen > 0);
4469 			/* Add the suggestion if the score isn't too bad. */
4470 			if (newscore <= su->su_maxscore)
4471 			    add_suggestion(su, &su->su_ga, preword,
4472 				    sp->ts_splitfidx - repextra,
4473 				    newscore, 0, FALSE,
4474 				    lp->lp_sallang, FALSE);
4475 			break;
4476 		    }
4477 		}
4478 		else
4479 		{
4480 		    /* There was a compound word before this word.  If this
4481 		     * word does not support compounding then give up
4482 		     * (splitting is tried for the word without compound
4483 		     * flag). */
4484 		    if (((unsigned)flags >> 24) == 0
4485 			    || sp->ts_twordlen - sp->ts_splitoff
4486 						       < slang->sl_compminlen)
4487 			break;
4488 		    /* For multi-byte chars check character length against
4489 		     * COMPOUNDMIN. */
4490 		    if (has_mbyte
4491 			    && slang->sl_compminlen > 0
4492 			    && mb_charlen(tword + sp->ts_splitoff)
4493 						       < slang->sl_compminlen)
4494 			break;
4495 
4496 		    compflags[sp->ts_complen] = ((unsigned)flags >> 24);
4497 		    compflags[sp->ts_complen + 1] = NUL;
4498 		    vim_strncpy(preword + sp->ts_prewordlen,
4499 			    tword + sp->ts_splitoff,
4500 			    sp->ts_twordlen - sp->ts_splitoff);
4501 
4502 		    /* Verify CHECKCOMPOUNDPATTERN  rules. */
4503 		    if (match_checkcompoundpattern(preword,  sp->ts_prewordlen,
4504 							  &slang->sl_comppat))
4505 			compound_ok = FALSE;
4506 
4507 		    if (compound_ok)
4508 		    {
4509 			p = preword;
4510 			while (*skiptowhite(p) != NUL)
4511 			    p = skipwhite(skiptowhite(p));
4512 			if (fword_ends && !can_compound(slang, p,
4513 						compflags + sp->ts_compsplit))
4514 			    /* Compound is not allowed.  But it may still be
4515 			     * possible if we add another (short) word. */
4516 			    compound_ok = FALSE;
4517 		    }
4518 
4519 		    /* Get pointer to last char of previous word. */
4520 		    p = preword + sp->ts_prewordlen;
4521 		    MB_PTR_BACK(preword, p);
4522 		}
4523 	    }
4524 
4525 	    /*
4526 	     * Form the word with proper case in preword.
4527 	     * If there is a word from a previous split, append.
4528 	     * For the soundfold tree don't change the case, simply append.
4529 	     */
4530 	    if (soundfold)
4531 		STRCPY(preword + sp->ts_prewordlen, tword + sp->ts_splitoff);
4532 	    else if (flags & WF_KEEPCAP)
4533 		/* Must find the word in the keep-case tree. */
4534 		find_keepcap_word(slang, tword + sp->ts_splitoff,
4535 						 preword + sp->ts_prewordlen);
4536 	    else
4537 	    {
4538 		/* Include badflags: If the badword is onecap or allcap
4539 		 * use that for the goodword too.  But if the badword is
4540 		 * allcap and it's only one char long use onecap. */
4541 		c = su->su_badflags;
4542 		if ((c & WF_ALLCAP)
4543 			&& su->su_badlen == (*mb_ptr2len)(su->su_badptr))
4544 		    c = WF_ONECAP;
4545 		c |= flags;
4546 
4547 		/* When appending a compound word after a word character don't
4548 		 * use Onecap. */
4549 		if (p != NULL && spell_iswordp_nmw(p, curwin))
4550 		    c &= ~WF_ONECAP;
4551 		make_case_word(tword + sp->ts_splitoff,
4552 					      preword + sp->ts_prewordlen, c);
4553 	    }
4554 
4555 	    if (!soundfold)
4556 	    {
4557 		/* Don't use a banned word.  It may appear again as a good
4558 		 * word, thus remember it. */
4559 		if (flags & WF_BANNED)
4560 		{
4561 		    add_banned(su, preword + sp->ts_prewordlen);
4562 		    break;
4563 		}
4564 		if ((sp->ts_complen == sp->ts_compsplit
4565 			    && WAS_BANNED(su, preword + sp->ts_prewordlen))
4566 						   || WAS_BANNED(su, preword))
4567 		{
4568 		    if (slang->sl_compprog == NULL)
4569 			break;
4570 		    /* the word so far was banned but we may try compounding */
4571 		    goodword_ends = FALSE;
4572 		}
4573 	    }
4574 
4575 	    newscore = 0;
4576 	    if (!soundfold)	/* soundfold words don't have flags */
4577 	    {
4578 		if ((flags & WF_REGION)
4579 			    && (((unsigned)flags >> 16) & lp->lp_region) == 0)
4580 		    newscore += SCORE_REGION;
4581 		if (flags & WF_RARE)
4582 		    newscore += SCORE_RARE;
4583 
4584 		if (!spell_valid_case(su->su_badflags,
4585 				  captype(preword + sp->ts_prewordlen, NULL)))
4586 		    newscore += SCORE_ICASE;
4587 	    }
4588 
4589 	    /* TODO: how about splitting in the soundfold tree? */
4590 	    if (fword_ends
4591 		    && goodword_ends
4592 		    && sp->ts_fidx >= sp->ts_fidxtry
4593 		    && compound_ok)
4594 	    {
4595 		/* The badword also ends: add suggestions. */
4596 #ifdef DEBUG_TRIEWALK
4597 		if (soundfold && STRCMP(preword, "smwrd") == 0)
4598 		{
4599 		    int	    j;
4600 
4601 		    /* print the stack of changes that brought us here */
4602 		    smsg("------ %s -------", fword);
4603 		    for (j = 0; j < depth; ++j)
4604 			smsg("%s", changename[j]);
4605 		}
4606 #endif
4607 		if (soundfold)
4608 		{
4609 		    /* For soundfolded words we need to find the original
4610 		     * words, the edit distance and then add them. */
4611 		    add_sound_suggest(su, preword, sp->ts_score, lp);
4612 		}
4613 		else if (sp->ts_fidx > 0)
4614 		{
4615 		    /* Give a penalty when changing non-word char to word
4616 		     * char, e.g., "thes," -> "these". */
4617 		    p = fword + sp->ts_fidx;
4618 		    MB_PTR_BACK(fword, p);
4619 		    if (!spell_iswordp(p, curwin))
4620 		    {
4621 			p = preword + STRLEN(preword);
4622 			MB_PTR_BACK(preword, p);
4623 			if (spell_iswordp(p, curwin))
4624 			    newscore += SCORE_NONWORD;
4625 		    }
4626 
4627 		    /* Give a bonus to words seen before. */
4628 		    score = score_wordcount_adj(slang,
4629 						sp->ts_score + newscore,
4630 						preword + sp->ts_prewordlen,
4631 						sp->ts_prewordlen > 0);
4632 
4633 		    /* Add the suggestion if the score isn't too bad. */
4634 		    if (score <= su->su_maxscore)
4635 		    {
4636 			add_suggestion(su, &su->su_ga, preword,
4637 				    sp->ts_fidx - repextra,
4638 				    score, 0, FALSE, lp->lp_sallang, FALSE);
4639 
4640 			if (su->su_badflags & WF_MIXCAP)
4641 			{
4642 			    /* We really don't know if the word should be
4643 			     * upper or lower case, add both. */
4644 			    c = captype(preword, NULL);
4645 			    if (c == 0 || c == WF_ALLCAP)
4646 			    {
4647 				make_case_word(tword + sp->ts_splitoff,
4648 					      preword + sp->ts_prewordlen,
4649 						      c == 0 ? WF_ALLCAP : 0);
4650 
4651 				add_suggestion(su, &su->su_ga, preword,
4652 					sp->ts_fidx - repextra,
4653 					score + SCORE_ICASE, 0, FALSE,
4654 					lp->lp_sallang, FALSE);
4655 			    }
4656 			}
4657 		    }
4658 		}
4659 	    }
4660 
4661 	    /*
4662 	     * Try word split and/or compounding.
4663 	     */
4664 	    if ((sp->ts_fidx >= sp->ts_fidxtry || fword_ends)
4665 		    /* Don't split halfway a character. */
4666 		    && (!has_mbyte || sp->ts_tcharlen == 0))
4667 	    {
4668 		int	try_compound;
4669 		int	try_split;
4670 
4671 		/* If past the end of the bad word don't try a split.
4672 		 * Otherwise try changing the next word.  E.g., find
4673 		 * suggestions for "the the" where the second "the" is
4674 		 * different.  It's done like a split.
4675 		 * TODO: word split for soundfold words */
4676 		try_split = (sp->ts_fidx - repextra < su->su_badlen)
4677 								&& !soundfold;
4678 
4679 		/* Get here in several situations:
4680 		 * 1. The word in the tree ends:
4681 		 *    If the word allows compounding try that.  Otherwise try
4682 		 *    a split by inserting a space.  For both check that a
4683 		 *    valid words starts at fword[sp->ts_fidx].
4684 		 *    For NOBREAK do like compounding to be able to check if
4685 		 *    the next word is valid.
4686 		 * 2. The badword does end, but it was due to a change (e.g.,
4687 		 *    a swap).  No need to split, but do check that the
4688 		 *    following word is valid.
4689 		 * 3. The badword and the word in the tree end.  It may still
4690 		 *    be possible to compound another (short) word.
4691 		 */
4692 		try_compound = FALSE;
4693 		if (!soundfold
4694 			&& !slang->sl_nocompoundsugs
4695 			&& slang->sl_compprog != NULL
4696 			&& ((unsigned)flags >> 24) != 0
4697 			&& sp->ts_twordlen - sp->ts_splitoff
4698 						       >= slang->sl_compminlen
4699 			&& (!has_mbyte
4700 			    || slang->sl_compminlen == 0
4701 			    || mb_charlen(tword + sp->ts_splitoff)
4702 						      >= slang->sl_compminlen)
4703 			&& (slang->sl_compsylmax < MAXWLEN
4704 			    || sp->ts_complen + 1 - sp->ts_compsplit
4705 							  < slang->sl_compmax)
4706 			&& (can_be_compound(sp, slang,
4707 					 compflags, ((unsigned)flags >> 24))))
4708 
4709 		{
4710 		    try_compound = TRUE;
4711 		    compflags[sp->ts_complen] = ((unsigned)flags >> 24);
4712 		    compflags[sp->ts_complen + 1] = NUL;
4713 		}
4714 
4715 		/* For NOBREAK we never try splitting, it won't make any word
4716 		 * valid. */
4717 		if (slang->sl_nobreak && !slang->sl_nocompoundsugs)
4718 		    try_compound = TRUE;
4719 
4720 		/* If we could add a compound word, and it's also possible to
4721 		 * split at this point, do the split first and set
4722 		 * TSF_DIDSPLIT to avoid doing it again. */
4723 		else if (!fword_ends
4724 			&& try_compound
4725 			&& (sp->ts_flags & TSF_DIDSPLIT) == 0)
4726 		{
4727 		    try_compound = FALSE;
4728 		    sp->ts_flags |= TSF_DIDSPLIT;
4729 		    --sp->ts_curi;	    /* do the same NUL again */
4730 		    compflags[sp->ts_complen] = NUL;
4731 		}
4732 		else
4733 		    sp->ts_flags &= ~TSF_DIDSPLIT;
4734 
4735 		if (try_split || try_compound)
4736 		{
4737 		    if (!try_compound && (!fword_ends || !goodword_ends))
4738 		    {
4739 			/* If we're going to split need to check that the
4740 			 * words so far are valid for compounding.  If there
4741 			 * is only one word it must not have the NEEDCOMPOUND
4742 			 * flag. */
4743 			if (sp->ts_complen == sp->ts_compsplit
4744 						     && (flags & WF_NEEDCOMP))
4745 			    break;
4746 			p = preword;
4747 			while (*skiptowhite(p) != NUL)
4748 			    p = skipwhite(skiptowhite(p));
4749 			if (sp->ts_complen > sp->ts_compsplit
4750 				&& !can_compound(slang, p,
4751 						compflags + sp->ts_compsplit))
4752 			    break;
4753 
4754 			if (slang->sl_nosplitsugs)
4755 			    newscore += SCORE_SPLIT_NO;
4756 			else
4757 			    newscore += SCORE_SPLIT;
4758 
4759 			/* Give a bonus to words seen before. */
4760 			newscore = score_wordcount_adj(slang, newscore,
4761 					   preword + sp->ts_prewordlen, TRUE);
4762 		    }
4763 
4764 		    if (TRY_DEEPER(su, stack, depth, newscore))
4765 		    {
4766 			go_deeper(stack, depth, newscore);
4767 #ifdef DEBUG_TRIEWALK
4768 			if (!try_compound && !fword_ends)
4769 			    sprintf(changename[depth], "%.*s-%s: split",
4770 				 sp->ts_twordlen, tword, fword + sp->ts_fidx);
4771 			else
4772 			    sprintf(changename[depth], "%.*s-%s: compound",
4773 				 sp->ts_twordlen, tword, fword + sp->ts_fidx);
4774 #endif
4775 			/* Save things to be restored at STATE_SPLITUNDO. */
4776 			sp->ts_save_badflags = su->su_badflags;
4777 			PROF_STORE(sp->ts_state)
4778 			sp->ts_state = STATE_SPLITUNDO;
4779 
4780 			++depth;
4781 			sp = &stack[depth];
4782 
4783 			/* Append a space to preword when splitting. */
4784 			if (!try_compound && !fword_ends)
4785 			    STRCAT(preword, " ");
4786 			sp->ts_prewordlen = (char_u)STRLEN(preword);
4787 			sp->ts_splitoff = sp->ts_twordlen;
4788 			sp->ts_splitfidx = sp->ts_fidx;
4789 
4790 			/* If the badword has a non-word character at this
4791 			 * position skip it.  That means replacing the
4792 			 * non-word character with a space.  Always skip a
4793 			 * character when the word ends.  But only when the
4794 			 * good word can end. */
4795 			if (((!try_compound && !spell_iswordp_nmw(fword
4796 							       + sp->ts_fidx,
4797 							       curwin))
4798 				    || fword_ends)
4799 				&& fword[sp->ts_fidx] != NUL
4800 				&& goodword_ends)
4801 			{
4802 			    int	    l;
4803 
4804 			    l = MB_PTR2LEN(fword + sp->ts_fidx);
4805 			    if (fword_ends)
4806 			    {
4807 				/* Copy the skipped character to preword. */
4808 				mch_memmove(preword + sp->ts_prewordlen,
4809 						      fword + sp->ts_fidx, l);
4810 				sp->ts_prewordlen += l;
4811 				preword[sp->ts_prewordlen] = NUL;
4812 			    }
4813 			    else
4814 				sp->ts_score -= SCORE_SPLIT - SCORE_SUBST;
4815 			    sp->ts_fidx += l;
4816 			}
4817 
4818 			/* When compounding include compound flag in
4819 			 * compflags[] (already set above).  When splitting we
4820 			 * may start compounding over again.  */
4821 			if (try_compound)
4822 			    ++sp->ts_complen;
4823 			else
4824 			    sp->ts_compsplit = sp->ts_complen;
4825 			sp->ts_prefixdepth = PFD_NOPREFIX;
4826 
4827 			/* set su->su_badflags to the caps type at this
4828 			 * position */
4829 			if (has_mbyte)
4830 			    n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
4831 			else
4832 			    n = sp->ts_fidx;
4833 			su->su_badflags = badword_captype(su->su_badptr + n,
4834 					       su->su_badptr + su->su_badlen);
4835 
4836 			/* Restart at top of the tree. */
4837 			sp->ts_arridx = 0;
4838 
4839 			/* If there are postponed prefixes, try these too. */
4840 			if (pbyts != NULL)
4841 			{
4842 			    byts = pbyts;
4843 			    idxs = pidxs;
4844 			    sp->ts_prefixdepth = PFD_PREFIXTREE;
4845 			    PROF_STORE(sp->ts_state)
4846 			    sp->ts_state = STATE_NOPREFIX;
4847 			}
4848 		    }
4849 		}
4850 	    }
4851 	    break;
4852 
4853 	case STATE_SPLITUNDO:
4854 	    /* Undo the changes done for word split or compound word. */
4855 	    su->su_badflags = sp->ts_save_badflags;
4856 
4857 	    /* Continue looking for NUL bytes. */
4858 	    PROF_STORE(sp->ts_state)
4859 	    sp->ts_state = STATE_START;
4860 
4861 	    /* In case we went into the prefix tree. */
4862 	    byts = fbyts;
4863 	    idxs = fidxs;
4864 	    break;
4865 
4866 	case STATE_ENDNUL:
4867 	    /* Past the NUL bytes in the node. */
4868 	    su->su_badflags = sp->ts_save_badflags;
4869 	    if (fword[sp->ts_fidx] == NUL && sp->ts_tcharlen == 0)
4870 	    {
4871 		/* The badword ends, can't use STATE_PLAIN. */
4872 		PROF_STORE(sp->ts_state)
4873 		sp->ts_state = STATE_DEL;
4874 		break;
4875 	    }
4876 	    PROF_STORE(sp->ts_state)
4877 	    sp->ts_state = STATE_PLAIN;
4878 	    /* FALLTHROUGH */
4879 
4880 	case STATE_PLAIN:
4881 	    /*
4882 	     * Go over all possible bytes at this node, add each to tword[]
4883 	     * and use child node.  "ts_curi" is the index.
4884 	     */
4885 	    arridx = sp->ts_arridx;
4886 	    if (sp->ts_curi > byts[arridx])
4887 	    {
4888 		/* Done all bytes at this node, do next state.  When still at
4889 		 * already changed bytes skip the other tricks. */
4890 		PROF_STORE(sp->ts_state)
4891 		if (sp->ts_fidx >= sp->ts_fidxtry)
4892 		    sp->ts_state = STATE_DEL;
4893 		else
4894 		    sp->ts_state = STATE_FINAL;
4895 	    }
4896 	    else
4897 	    {
4898 		arridx += sp->ts_curi++;
4899 		c = byts[arridx];
4900 
4901 		/* Normal byte, go one level deeper.  If it's not equal to the
4902 		 * byte in the bad word adjust the score.  But don't even try
4903 		 * when the byte was already changed.  And don't try when we
4904 		 * just deleted this byte, accepting it is always cheaper than
4905 		 * delete + substitute. */
4906 		if (c == fword[sp->ts_fidx]
4907 			|| (sp->ts_tcharlen > 0 && sp->ts_isdiff != DIFF_NONE))
4908 		    newscore = 0;
4909 		else
4910 		    newscore = SCORE_SUBST;
4911 		if ((newscore == 0
4912 			    || (sp->ts_fidx >= sp->ts_fidxtry
4913 				&& ((sp->ts_flags & TSF_DIDDEL) == 0
4914 				    || c != fword[sp->ts_delidx])))
4915 			&& TRY_DEEPER(su, stack, depth, newscore))
4916 		{
4917 		    go_deeper(stack, depth, newscore);
4918 #ifdef DEBUG_TRIEWALK
4919 		    if (newscore > 0)
4920 			sprintf(changename[depth], "%.*s-%s: subst %c to %c",
4921 				sp->ts_twordlen, tword, fword + sp->ts_fidx,
4922 				fword[sp->ts_fidx], c);
4923 		    else
4924 			sprintf(changename[depth], "%.*s-%s: accept %c",
4925 				sp->ts_twordlen, tword, fword + sp->ts_fidx,
4926 				fword[sp->ts_fidx]);
4927 #endif
4928 		    ++depth;
4929 		    sp = &stack[depth];
4930 		    ++sp->ts_fidx;
4931 		    tword[sp->ts_twordlen++] = c;
4932 		    sp->ts_arridx = idxs[arridx];
4933 		    if (newscore == SCORE_SUBST)
4934 			sp->ts_isdiff = DIFF_YES;
4935 		    if (has_mbyte)
4936 		    {
4937 			/* Multi-byte characters are a bit complicated to
4938 			 * handle: They differ when any of the bytes differ
4939 			 * and then their length may also differ. */
4940 			if (sp->ts_tcharlen == 0)
4941 			{
4942 			    /* First byte. */
4943 			    sp->ts_tcharidx = 0;
4944 			    sp->ts_tcharlen = MB_BYTE2LEN(c);
4945 			    sp->ts_fcharstart = sp->ts_fidx - 1;
4946 			    sp->ts_isdiff = (newscore != 0)
4947 						       ? DIFF_YES : DIFF_NONE;
4948 			}
4949 			else if (sp->ts_isdiff == DIFF_INSERT)
4950 			    /* When inserting trail bytes don't advance in the
4951 			     * bad word. */
4952 			    --sp->ts_fidx;
4953 			if (++sp->ts_tcharidx == sp->ts_tcharlen)
4954 			{
4955 			    /* Last byte of character. */
4956 			    if (sp->ts_isdiff == DIFF_YES)
4957 			    {
4958 				/* Correct ts_fidx for the byte length of the
4959 				 * character (we didn't check that before). */
4960 				sp->ts_fidx = sp->ts_fcharstart
4961 					    + MB_PTR2LEN(
4962 						    fword + sp->ts_fcharstart);
4963 				/* For changing a composing character adjust
4964 				 * the score from SCORE_SUBST to
4965 				 * SCORE_SUBCOMP. */
4966 				if (enc_utf8
4967 					&& utf_iscomposing(
4968 					    utf_ptr2char(tword
4969 						+ sp->ts_twordlen
4970 							   - sp->ts_tcharlen))
4971 					&& utf_iscomposing(
4972 					    utf_ptr2char(fword
4973 							+ sp->ts_fcharstart)))
4974 				    sp->ts_score -=
4975 						  SCORE_SUBST - SCORE_SUBCOMP;
4976 
4977 				/* For a similar character adjust score from
4978 				 * SCORE_SUBST to SCORE_SIMILAR. */
4979 				else if (!soundfold
4980 					&& slang->sl_has_map
4981 					&& similar_chars(slang,
4982 					    mb_ptr2char(tword
4983 						+ sp->ts_twordlen
4984 							   - sp->ts_tcharlen),
4985 					    mb_ptr2char(fword
4986 							+ sp->ts_fcharstart)))
4987 				    sp->ts_score -=
4988 						  SCORE_SUBST - SCORE_SIMILAR;
4989 			    }
4990 			    else if (sp->ts_isdiff == DIFF_INSERT
4991 					 && sp->ts_twordlen > sp->ts_tcharlen)
4992 			    {
4993 				p = tword + sp->ts_twordlen - sp->ts_tcharlen;
4994 				c = mb_ptr2char(p);
4995 				if (enc_utf8 && utf_iscomposing(c))
4996 				{
4997 				    /* Inserting a composing char doesn't
4998 				     * count that much. */
4999 				    sp->ts_score -= SCORE_INS - SCORE_INSCOMP;
5000 				}
5001 				else
5002 				{
5003 				    /* If the previous character was the same,
5004 				     * thus doubling a character, give a bonus
5005 				     * to the score.  Also for the soundfold
5006 				     * tree (might seem illogical but does
5007 				     * give better scores). */
5008 				    MB_PTR_BACK(tword, p);
5009 				    if (c == mb_ptr2char(p))
5010 					sp->ts_score -= SCORE_INS
5011 							       - SCORE_INSDUP;
5012 				}
5013 			    }
5014 
5015 			    /* Starting a new char, reset the length. */
5016 			    sp->ts_tcharlen = 0;
5017 			}
5018 		    }
5019 		    else
5020 		    {
5021 			/* If we found a similar char adjust the score.
5022 			 * We do this after calling go_deeper() because
5023 			 * it's slow. */
5024 			if (newscore != 0
5025 				&& !soundfold
5026 				&& slang->sl_has_map
5027 				&& similar_chars(slang,
5028 						   c, fword[sp->ts_fidx - 1]))
5029 			    sp->ts_score -= SCORE_SUBST - SCORE_SIMILAR;
5030 		    }
5031 		}
5032 	    }
5033 	    break;
5034 
5035 	case STATE_DEL:
5036 	    /* When past the first byte of a multi-byte char don't try
5037 	     * delete/insert/swap a character. */
5038 	    if (has_mbyte && sp->ts_tcharlen > 0)
5039 	    {
5040 		PROF_STORE(sp->ts_state)
5041 		sp->ts_state = STATE_FINAL;
5042 		break;
5043 	    }
5044 	    /*
5045 	     * Try skipping one character in the bad word (delete it).
5046 	     */
5047 	    PROF_STORE(sp->ts_state)
5048 	    sp->ts_state = STATE_INS_PREP;
5049 	    sp->ts_curi = 1;
5050 	    if (soundfold && sp->ts_fidx == 0 && fword[sp->ts_fidx] == '*')
5051 		/* Deleting a vowel at the start of a word counts less, see
5052 		 * soundalike_score(). */
5053 		newscore = 2 * SCORE_DEL / 3;
5054 	    else
5055 		newscore = SCORE_DEL;
5056 	    if (fword[sp->ts_fidx] != NUL
5057 				    && TRY_DEEPER(su, stack, depth, newscore))
5058 	    {
5059 		go_deeper(stack, depth, newscore);
5060 #ifdef DEBUG_TRIEWALK
5061 		sprintf(changename[depth], "%.*s-%s: delete %c",
5062 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
5063 			fword[sp->ts_fidx]);
5064 #endif
5065 		++depth;
5066 
5067 		/* Remember what character we deleted, so that we can avoid
5068 		 * inserting it again. */
5069 		stack[depth].ts_flags |= TSF_DIDDEL;
5070 		stack[depth].ts_delidx = sp->ts_fidx;
5071 
5072 		/* Advance over the character in fword[].  Give a bonus to the
5073 		 * score if the same character is following "nn" -> "n".  It's
5074 		 * a bit illogical for soundfold tree but it does give better
5075 		 * results. */
5076 		if (has_mbyte)
5077 		{
5078 		    c = mb_ptr2char(fword + sp->ts_fidx);
5079 		    stack[depth].ts_fidx += MB_PTR2LEN(fword + sp->ts_fidx);
5080 		    if (enc_utf8 && utf_iscomposing(c))
5081 			stack[depth].ts_score -= SCORE_DEL - SCORE_DELCOMP;
5082 		    else if (c == mb_ptr2char(fword + stack[depth].ts_fidx))
5083 			stack[depth].ts_score -= SCORE_DEL - SCORE_DELDUP;
5084 		}
5085 		else
5086 		{
5087 		    ++stack[depth].ts_fidx;
5088 		    if (fword[sp->ts_fidx] == fword[sp->ts_fidx + 1])
5089 			stack[depth].ts_score -= SCORE_DEL - SCORE_DELDUP;
5090 		}
5091 		break;
5092 	    }
5093 	    /* FALLTHROUGH */
5094 
5095 	case STATE_INS_PREP:
5096 	    if (sp->ts_flags & TSF_DIDDEL)
5097 	    {
5098 		/* If we just deleted a byte then inserting won't make sense,
5099 		 * a substitute is always cheaper. */
5100 		PROF_STORE(sp->ts_state)
5101 		sp->ts_state = STATE_SWAP;
5102 		break;
5103 	    }
5104 
5105 	    /* skip over NUL bytes */
5106 	    n = sp->ts_arridx;
5107 	    for (;;)
5108 	    {
5109 		if (sp->ts_curi > byts[n])
5110 		{
5111 		    /* Only NUL bytes at this node, go to next state. */
5112 		    PROF_STORE(sp->ts_state)
5113 		    sp->ts_state = STATE_SWAP;
5114 		    break;
5115 		}
5116 		if (byts[n + sp->ts_curi] != NUL)
5117 		{
5118 		    /* Found a byte to insert. */
5119 		    PROF_STORE(sp->ts_state)
5120 		    sp->ts_state = STATE_INS;
5121 		    break;
5122 		}
5123 		++sp->ts_curi;
5124 	    }
5125 	    break;
5126 
5127 	    /* FALLTHROUGH */
5128 
5129 	case STATE_INS:
5130 	    /* Insert one byte.  Repeat this for each possible byte at this
5131 	     * node. */
5132 	    n = sp->ts_arridx;
5133 	    if (sp->ts_curi > byts[n])
5134 	    {
5135 		/* Done all bytes at this node, go to next state. */
5136 		PROF_STORE(sp->ts_state)
5137 		sp->ts_state = STATE_SWAP;
5138 		break;
5139 	    }
5140 
5141 	    /* Do one more byte at this node, but:
5142 	     * - Skip NUL bytes.
5143 	     * - Skip the byte if it's equal to the byte in the word,
5144 	     *   accepting that byte is always better.
5145 	     */
5146 	    n += sp->ts_curi++;
5147 	    c = byts[n];
5148 	    if (soundfold && sp->ts_twordlen == 0 && c == '*')
5149 		/* Inserting a vowel at the start of a word counts less,
5150 		 * see soundalike_score(). */
5151 		newscore = 2 * SCORE_INS / 3;
5152 	    else
5153 		newscore = SCORE_INS;
5154 	    if (c != fword[sp->ts_fidx]
5155 				    && TRY_DEEPER(su, stack, depth, newscore))
5156 	    {
5157 		go_deeper(stack, depth, newscore);
5158 #ifdef DEBUG_TRIEWALK
5159 		sprintf(changename[depth], "%.*s-%s: insert %c",
5160 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
5161 			c);
5162 #endif
5163 		++depth;
5164 		sp = &stack[depth];
5165 		tword[sp->ts_twordlen++] = c;
5166 		sp->ts_arridx = idxs[n];
5167 		if (has_mbyte)
5168 		{
5169 		    fl = MB_BYTE2LEN(c);
5170 		    if (fl > 1)
5171 		    {
5172 			/* There are following bytes for the same character.
5173 			 * We must find all bytes before trying
5174 			 * delete/insert/swap/etc. */
5175 			sp->ts_tcharlen = fl;
5176 			sp->ts_tcharidx = 1;
5177 			sp->ts_isdiff = DIFF_INSERT;
5178 		    }
5179 		}
5180 		else
5181 		    fl = 1;
5182 		if (fl == 1)
5183 		{
5184 		    /* If the previous character was the same, thus doubling a
5185 		     * character, give a bonus to the score.  Also for
5186 		     * soundfold words (illogical but does give a better
5187 		     * score). */
5188 		    if (sp->ts_twordlen >= 2
5189 					   && tword[sp->ts_twordlen - 2] == c)
5190 			sp->ts_score -= SCORE_INS - SCORE_INSDUP;
5191 		}
5192 	    }
5193 	    break;
5194 
5195 	case STATE_SWAP:
5196 	    /*
5197 	     * Swap two bytes in the bad word: "12" -> "21".
5198 	     * We change "fword" here, it's changed back afterwards at
5199 	     * STATE_UNSWAP.
5200 	     */
5201 	    p = fword + sp->ts_fidx;
5202 	    c = *p;
5203 	    if (c == NUL)
5204 	    {
5205 		/* End of word, can't swap or replace. */
5206 		PROF_STORE(sp->ts_state)
5207 		sp->ts_state = STATE_FINAL;
5208 		break;
5209 	    }
5210 
5211 	    /* Don't swap if the first character is not a word character.
5212 	     * SWAP3 etc. also don't make sense then. */
5213 	    if (!soundfold && !spell_iswordp(p, curwin))
5214 	    {
5215 		PROF_STORE(sp->ts_state)
5216 		sp->ts_state = STATE_REP_INI;
5217 		break;
5218 	    }
5219 
5220 	    if (has_mbyte)
5221 	    {
5222 		n = MB_CPTR2LEN(p);
5223 		c = mb_ptr2char(p);
5224 		if (p[n] == NUL)
5225 		    c2 = NUL;
5226 		else if (!soundfold && !spell_iswordp(p + n, curwin))
5227 		    c2 = c; /* don't swap non-word char */
5228 		else
5229 		    c2 = mb_ptr2char(p + n);
5230 	    }
5231 	    else
5232 	    {
5233 		if (p[1] == NUL)
5234 		    c2 = NUL;
5235 		else if (!soundfold && !spell_iswordp(p + 1, curwin))
5236 		    c2 = c; /* don't swap non-word char */
5237 		else
5238 		    c2 = p[1];
5239 	    }
5240 
5241 	    /* When the second character is NUL we can't swap. */
5242 	    if (c2 == NUL)
5243 	    {
5244 		PROF_STORE(sp->ts_state)
5245 		sp->ts_state = STATE_REP_INI;
5246 		break;
5247 	    }
5248 
5249 	    /* When characters are identical, swap won't do anything.
5250 	     * Also get here if the second char is not a word character. */
5251 	    if (c == c2)
5252 	    {
5253 		PROF_STORE(sp->ts_state)
5254 		sp->ts_state = STATE_SWAP3;
5255 		break;
5256 	    }
5257 	    if (c2 != NUL && TRY_DEEPER(su, stack, depth, SCORE_SWAP))
5258 	    {
5259 		go_deeper(stack, depth, SCORE_SWAP);
5260 #ifdef DEBUG_TRIEWALK
5261 		sprintf(changename[depth], "%.*s-%s: swap %c and %c",
5262 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
5263 			c, c2);
5264 #endif
5265 		PROF_STORE(sp->ts_state)
5266 		sp->ts_state = STATE_UNSWAP;
5267 		++depth;
5268 		if (has_mbyte)
5269 		{
5270 		    fl = mb_char2len(c2);
5271 		    mch_memmove(p, p + n, fl);
5272 		    mb_char2bytes(c, p + fl);
5273 		    stack[depth].ts_fidxtry = sp->ts_fidx + n + fl;
5274 		}
5275 		else
5276 		{
5277 		    p[0] = c2;
5278 		    p[1] = c;
5279 		    stack[depth].ts_fidxtry = sp->ts_fidx + 2;
5280 		}
5281 	    }
5282 	    else
5283 	    {
5284 		/* If this swap doesn't work then SWAP3 won't either. */
5285 		PROF_STORE(sp->ts_state)
5286 		sp->ts_state = STATE_REP_INI;
5287 	    }
5288 	    break;
5289 
5290 	case STATE_UNSWAP:
5291 	    /* Undo the STATE_SWAP swap: "21" -> "12". */
5292 	    p = fword + sp->ts_fidx;
5293 	    if (has_mbyte)
5294 	    {
5295 		n = MB_PTR2LEN(p);
5296 		c = mb_ptr2char(p + n);
5297 		mch_memmove(p + MB_PTR2LEN(p + n), p, n);
5298 		mb_char2bytes(c, p);
5299 	    }
5300 	    else
5301 	    {
5302 		c = *p;
5303 		*p = p[1];
5304 		p[1] = c;
5305 	    }
5306 	    /* FALLTHROUGH */
5307 
5308 	case STATE_SWAP3:
5309 	    /* Swap two bytes, skipping one: "123" -> "321".  We change
5310 	     * "fword" here, it's changed back afterwards at STATE_UNSWAP3. */
5311 	    p = fword + sp->ts_fidx;
5312 	    if (has_mbyte)
5313 	    {
5314 		n = MB_CPTR2LEN(p);
5315 		c = mb_ptr2char(p);
5316 		fl = MB_CPTR2LEN(p + n);
5317 		c2 = mb_ptr2char(p + n);
5318 		if (!soundfold && !spell_iswordp(p + n + fl, curwin))
5319 		    c3 = c;	/* don't swap non-word char */
5320 		else
5321 		    c3 = mb_ptr2char(p + n + fl);
5322 	    }
5323 	    else
5324 	    {
5325 		c = *p;
5326 		c2 = p[1];
5327 		if (!soundfold && !spell_iswordp(p + 2, curwin))
5328 		    c3 = c;	/* don't swap non-word char */
5329 		else
5330 		    c3 = p[2];
5331 	    }
5332 
5333 	    /* When characters are identical: "121" then SWAP3 result is
5334 	     * identical, ROT3L result is same as SWAP: "211", ROT3L result is
5335 	     * same as SWAP on next char: "112".  Thus skip all swapping.
5336 	     * Also skip when c3 is NUL.
5337 	     * Also get here when the third character is not a word character.
5338 	     * Second character may any char: "a.b" -> "b.a" */
5339 	    if (c == c3 || c3 == NUL)
5340 	    {
5341 		PROF_STORE(sp->ts_state)
5342 		sp->ts_state = STATE_REP_INI;
5343 		break;
5344 	    }
5345 	    if (TRY_DEEPER(su, stack, depth, SCORE_SWAP3))
5346 	    {
5347 		go_deeper(stack, depth, SCORE_SWAP3);
5348 #ifdef DEBUG_TRIEWALK
5349 		sprintf(changename[depth], "%.*s-%s: swap3 %c and %c",
5350 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
5351 			c, c3);
5352 #endif
5353 		PROF_STORE(sp->ts_state)
5354 		sp->ts_state = STATE_UNSWAP3;
5355 		++depth;
5356 		if (has_mbyte)
5357 		{
5358 		    tl = mb_char2len(c3);
5359 		    mch_memmove(p, p + n + fl, tl);
5360 		    mb_char2bytes(c2, p + tl);
5361 		    mb_char2bytes(c, p + fl + tl);
5362 		    stack[depth].ts_fidxtry = sp->ts_fidx + n + fl + tl;
5363 		}
5364 		else
5365 		{
5366 		    p[0] = p[2];
5367 		    p[2] = c;
5368 		    stack[depth].ts_fidxtry = sp->ts_fidx + 3;
5369 		}
5370 	    }
5371 	    else
5372 	    {
5373 		PROF_STORE(sp->ts_state)
5374 		sp->ts_state = STATE_REP_INI;
5375 	    }
5376 	    break;
5377 
5378 	case STATE_UNSWAP3:
5379 	    /* Undo STATE_SWAP3: "321" -> "123" */
5380 	    p = fword + sp->ts_fidx;
5381 	    if (has_mbyte)
5382 	    {
5383 		n = MB_PTR2LEN(p);
5384 		c2 = mb_ptr2char(p + n);
5385 		fl = MB_PTR2LEN(p + n);
5386 		c = mb_ptr2char(p + n + fl);
5387 		tl = MB_PTR2LEN(p + n + fl);
5388 		mch_memmove(p + fl + tl, p, n);
5389 		mb_char2bytes(c, p);
5390 		mb_char2bytes(c2, p + tl);
5391 		p = p + tl;
5392 	    }
5393 	    else
5394 	    {
5395 		c = *p;
5396 		*p = p[2];
5397 		p[2] = c;
5398 		++p;
5399 	    }
5400 
5401 	    if (!soundfold && !spell_iswordp(p, curwin))
5402 	    {
5403 		/* Middle char is not a word char, skip the rotate.  First and
5404 		 * third char were already checked at swap and swap3. */
5405 		PROF_STORE(sp->ts_state)
5406 		sp->ts_state = STATE_REP_INI;
5407 		break;
5408 	    }
5409 
5410 	    /* Rotate three characters left: "123" -> "231".  We change
5411 	     * "fword" here, it's changed back afterwards at STATE_UNROT3L. */
5412 	    if (TRY_DEEPER(su, stack, depth, SCORE_SWAP3))
5413 	    {
5414 		go_deeper(stack, depth, SCORE_SWAP3);
5415 #ifdef DEBUG_TRIEWALK
5416 		p = fword + sp->ts_fidx;
5417 		sprintf(changename[depth], "%.*s-%s: rotate left %c%c%c",
5418 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
5419 			p[0], p[1], p[2]);
5420 #endif
5421 		PROF_STORE(sp->ts_state)
5422 		sp->ts_state = STATE_UNROT3L;
5423 		++depth;
5424 		p = fword + sp->ts_fidx;
5425 		if (has_mbyte)
5426 		{
5427 		    n = MB_CPTR2LEN(p);
5428 		    c = mb_ptr2char(p);
5429 		    fl = MB_CPTR2LEN(p + n);
5430 		    fl += MB_CPTR2LEN(p + n + fl);
5431 		    mch_memmove(p, p + n, fl);
5432 		    mb_char2bytes(c, p + fl);
5433 		    stack[depth].ts_fidxtry = sp->ts_fidx + n + fl;
5434 		}
5435 		else
5436 		{
5437 		    c = *p;
5438 		    *p = p[1];
5439 		    p[1] = p[2];
5440 		    p[2] = c;
5441 		    stack[depth].ts_fidxtry = sp->ts_fidx + 3;
5442 		}
5443 	    }
5444 	    else
5445 	    {
5446 		PROF_STORE(sp->ts_state)
5447 		sp->ts_state = STATE_REP_INI;
5448 	    }
5449 	    break;
5450 
5451 	case STATE_UNROT3L:
5452 	    /* Undo ROT3L: "231" -> "123" */
5453 	    p = fword + sp->ts_fidx;
5454 	    if (has_mbyte)
5455 	    {
5456 		n = MB_PTR2LEN(p);
5457 		n += MB_PTR2LEN(p + n);
5458 		c = mb_ptr2char(p + n);
5459 		tl = MB_PTR2LEN(p + n);
5460 		mch_memmove(p + tl, p, n);
5461 		mb_char2bytes(c, p);
5462 	    }
5463 	    else
5464 	    {
5465 		c = p[2];
5466 		p[2] = p[1];
5467 		p[1] = *p;
5468 		*p = c;
5469 	    }
5470 
5471 	    /* Rotate three bytes right: "123" -> "312".  We change "fword"
5472 	     * here, it's changed back afterwards at STATE_UNROT3R. */
5473 	    if (TRY_DEEPER(su, stack, depth, SCORE_SWAP3))
5474 	    {
5475 		go_deeper(stack, depth, SCORE_SWAP3);
5476 #ifdef DEBUG_TRIEWALK
5477 		p = fword + sp->ts_fidx;
5478 		sprintf(changename[depth], "%.*s-%s: rotate right %c%c%c",
5479 			sp->ts_twordlen, tword, fword + sp->ts_fidx,
5480 			p[0], p[1], p[2]);
5481 #endif
5482 		PROF_STORE(sp->ts_state)
5483 		sp->ts_state = STATE_UNROT3R;
5484 		++depth;
5485 		p = fword + sp->ts_fidx;
5486 		if (has_mbyte)
5487 		{
5488 		    n = MB_CPTR2LEN(p);
5489 		    n += MB_CPTR2LEN(p + n);
5490 		    c = mb_ptr2char(p + n);
5491 		    tl = MB_CPTR2LEN(p + n);
5492 		    mch_memmove(p + tl, p, n);
5493 		    mb_char2bytes(c, p);
5494 		    stack[depth].ts_fidxtry = sp->ts_fidx + n + tl;
5495 		}
5496 		else
5497 		{
5498 		    c = p[2];
5499 		    p[2] = p[1];
5500 		    p[1] = *p;
5501 		    *p = c;
5502 		    stack[depth].ts_fidxtry = sp->ts_fidx + 3;
5503 		}
5504 	    }
5505 	    else
5506 	    {
5507 		PROF_STORE(sp->ts_state)
5508 		sp->ts_state = STATE_REP_INI;
5509 	    }
5510 	    break;
5511 
5512 	case STATE_UNROT3R:
5513 	    /* Undo ROT3R: "312" -> "123" */
5514 	    p = fword + sp->ts_fidx;
5515 	    if (has_mbyte)
5516 	    {
5517 		c = mb_ptr2char(p);
5518 		tl = MB_PTR2LEN(p);
5519 		n = MB_PTR2LEN(p + tl);
5520 		n += MB_PTR2LEN(p + tl + n);
5521 		mch_memmove(p, p + tl, n);
5522 		mb_char2bytes(c, p + n);
5523 	    }
5524 	    else
5525 	    {
5526 		c = *p;
5527 		*p = p[1];
5528 		p[1] = p[2];
5529 		p[2] = c;
5530 	    }
5531 	    /* FALLTHROUGH */
5532 
5533 	case STATE_REP_INI:
5534 	    /* Check if matching with REP items from the .aff file would work.
5535 	     * Quickly skip if:
5536 	     * - there are no REP items and we are not in the soundfold trie
5537 	     * - the score is going to be too high anyway
5538 	     * - already applied a REP item or swapped here  */
5539 	    if ((lp->lp_replang == NULL && !soundfold)
5540 		    || sp->ts_score + SCORE_REP >= su->su_maxscore
5541 		    || sp->ts_fidx < sp->ts_fidxtry)
5542 	    {
5543 		PROF_STORE(sp->ts_state)
5544 		sp->ts_state = STATE_FINAL;
5545 		break;
5546 	    }
5547 
5548 	    /* Use the first byte to quickly find the first entry that may
5549 	     * match.  If the index is -1 there is none. */
5550 	    if (soundfold)
5551 		sp->ts_curi = slang->sl_repsal_first[fword[sp->ts_fidx]];
5552 	    else
5553 		sp->ts_curi = lp->lp_replang->sl_rep_first[fword[sp->ts_fidx]];
5554 
5555 	    if (sp->ts_curi < 0)
5556 	    {
5557 		PROF_STORE(sp->ts_state)
5558 		sp->ts_state = STATE_FINAL;
5559 		break;
5560 	    }
5561 
5562 	    PROF_STORE(sp->ts_state)
5563 	    sp->ts_state = STATE_REP;
5564 	    /* FALLTHROUGH */
5565 
5566 	case STATE_REP:
5567 	    /* Try matching with REP items from the .aff file.  For each match
5568 	     * replace the characters and check if the resulting word is
5569 	     * valid. */
5570 	    p = fword + sp->ts_fidx;
5571 
5572 	    if (soundfold)
5573 		gap = &slang->sl_repsal;
5574 	    else
5575 		gap = &lp->lp_replang->sl_rep;
5576 	    while (sp->ts_curi < gap->ga_len)
5577 	    {
5578 		ftp = (fromto_T *)gap->ga_data + sp->ts_curi++;
5579 		if (*ftp->ft_from != *p)
5580 		{
5581 		    /* past possible matching entries */
5582 		    sp->ts_curi = gap->ga_len;
5583 		    break;
5584 		}
5585 		if (STRNCMP(ftp->ft_from, p, STRLEN(ftp->ft_from)) == 0
5586 			&& TRY_DEEPER(su, stack, depth, SCORE_REP))
5587 		{
5588 		    go_deeper(stack, depth, SCORE_REP);
5589 #ifdef DEBUG_TRIEWALK
5590 		    sprintf(changename[depth], "%.*s-%s: replace %s with %s",
5591 			    sp->ts_twordlen, tword, fword + sp->ts_fidx,
5592 			    ftp->ft_from, ftp->ft_to);
5593 #endif
5594 		    /* Need to undo this afterwards. */
5595 		    PROF_STORE(sp->ts_state)
5596 		    sp->ts_state = STATE_REP_UNDO;
5597 
5598 		    /* Change the "from" to the "to" string. */
5599 		    ++depth;
5600 		    fl = (int)STRLEN(ftp->ft_from);
5601 		    tl = (int)STRLEN(ftp->ft_to);
5602 		    if (fl != tl)
5603 		    {
5604 			STRMOVE(p + tl, p + fl);
5605 			repextra += tl - fl;
5606 		    }
5607 		    mch_memmove(p, ftp->ft_to, tl);
5608 		    stack[depth].ts_fidxtry = sp->ts_fidx + tl;
5609 		    stack[depth].ts_tcharlen = 0;
5610 		    break;
5611 		}
5612 	    }
5613 
5614 	    if (sp->ts_curi >= gap->ga_len && sp->ts_state == STATE_REP)
5615 	    {
5616 		/* No (more) matches. */
5617 		PROF_STORE(sp->ts_state)
5618 		sp->ts_state = STATE_FINAL;
5619 	    }
5620 
5621 	    break;
5622 
5623 	case STATE_REP_UNDO:
5624 	    /* Undo a REP replacement and continue with the next one. */
5625 	    if (soundfold)
5626 		gap = &slang->sl_repsal;
5627 	    else
5628 		gap = &lp->lp_replang->sl_rep;
5629 	    ftp = (fromto_T *)gap->ga_data + sp->ts_curi - 1;
5630 	    fl = (int)STRLEN(ftp->ft_from);
5631 	    tl = (int)STRLEN(ftp->ft_to);
5632 	    p = fword + sp->ts_fidx;
5633 	    if (fl != tl)
5634 	    {
5635 		STRMOVE(p + fl, p + tl);
5636 		repextra -= tl - fl;
5637 	    }
5638 	    mch_memmove(p, ftp->ft_from, fl);
5639 	    PROF_STORE(sp->ts_state)
5640 	    sp->ts_state = STATE_REP;
5641 	    break;
5642 
5643 	default:
5644 	    /* Did all possible states at this level, go up one level. */
5645 	    --depth;
5646 
5647 	    if (depth >= 0 && stack[depth].ts_prefixdepth == PFD_PREFIXTREE)
5648 	    {
5649 		/* Continue in or go back to the prefix tree. */
5650 		byts = pbyts;
5651 		idxs = pidxs;
5652 	    }
5653 
5654 	    /* Don't check for CTRL-C too often, it takes time. */
5655 	    if (--breakcheckcount == 0)
5656 	    {
5657 		ui_breakcheck();
5658 		breakcheckcount = 1000;
5659 	    }
5660 	}
5661     }
5662 }
5663 
5664 
5665 /*
5666  * Go one level deeper in the tree.
5667  */
5668     static void
5669 go_deeper(trystate_T *stack, int depth, int score_add)
5670 {
5671     stack[depth + 1] = stack[depth];
5672     stack[depth + 1].ts_state = STATE_START;
5673     stack[depth + 1].ts_score = stack[depth].ts_score + score_add;
5674     stack[depth + 1].ts_curi = 1;	/* start just after length byte */
5675     stack[depth + 1].ts_flags = 0;
5676 }
5677 
5678 /*
5679  * Case-folding may change the number of bytes: Count nr of chars in
5680  * fword[flen] and return the byte length of that many chars in "word".
5681  */
5682     static int
5683 nofold_len(char_u *fword, int flen, char_u *word)
5684 {
5685     char_u	*p;
5686     int		i = 0;
5687 
5688     for (p = fword; p < fword + flen; MB_PTR_ADV(p))
5689 	++i;
5690     for (p = word; i > 0; MB_PTR_ADV(p))
5691 	--i;
5692     return (int)(p - word);
5693 }
5694 
5695 /*
5696  * "fword" is a good word with case folded.  Find the matching keep-case
5697  * words and put it in "kword".
5698  * Theoretically there could be several keep-case words that result in the
5699  * same case-folded word, but we only find one...
5700  */
5701     static void
5702 find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
5703 {
5704     char_u	uword[MAXWLEN];		/* "fword" in upper-case */
5705     int		depth;
5706     idx_T	tryidx;
5707 
5708     /* The following arrays are used at each depth in the tree. */
5709     idx_T	arridx[MAXWLEN];
5710     int		round[MAXWLEN];
5711     int		fwordidx[MAXWLEN];
5712     int		uwordidx[MAXWLEN];
5713     int		kwordlen[MAXWLEN];
5714 
5715     int		flen, ulen;
5716     int		l;
5717     int		len;
5718     int		c;
5719     idx_T	lo, hi, m;
5720     char_u	*p;
5721     char_u	*byts = slang->sl_kbyts;    /* array with bytes of the words */
5722     idx_T	*idxs = slang->sl_kidxs;    /* array with indexes */
5723 
5724     if (byts == NULL)
5725     {
5726 	/* array is empty: "cannot happen" */
5727 	*kword = NUL;
5728 	return;
5729     }
5730 
5731     /* Make an all-cap version of "fword". */
5732     allcap_copy(fword, uword);
5733 
5734     /*
5735      * Each character needs to be tried both case-folded and upper-case.
5736      * All this gets very complicated if we keep in mind that changing case
5737      * may change the byte length of a multi-byte character...
5738      */
5739     depth = 0;
5740     arridx[0] = 0;
5741     round[0] = 0;
5742     fwordidx[0] = 0;
5743     uwordidx[0] = 0;
5744     kwordlen[0] = 0;
5745     while (depth >= 0)
5746     {
5747 	if (fword[fwordidx[depth]] == NUL)
5748 	{
5749 	    /* We are at the end of "fword".  If the tree allows a word to end
5750 	     * here we have found a match. */
5751 	    if (byts[arridx[depth] + 1] == 0)
5752 	    {
5753 		kword[kwordlen[depth]] = NUL;
5754 		return;
5755 	    }
5756 
5757 	    /* kword is getting too long, continue one level up */
5758 	    --depth;
5759 	}
5760 	else if (++round[depth] > 2)
5761 	{
5762 	    /* tried both fold-case and upper-case character, continue one
5763 	     * level up */
5764 	    --depth;
5765 	}
5766 	else
5767 	{
5768 	    /*
5769 	     * round[depth] == 1: Try using the folded-case character.
5770 	     * round[depth] == 2: Try using the upper-case character.
5771 	     */
5772 	    if (has_mbyte)
5773 	    {
5774 		flen = MB_CPTR2LEN(fword + fwordidx[depth]);
5775 		ulen = MB_CPTR2LEN(uword + uwordidx[depth]);
5776 	    }
5777 	    else
5778 		ulen = flen = 1;
5779 	    if (round[depth] == 1)
5780 	    {
5781 		p = fword + fwordidx[depth];
5782 		l = flen;
5783 	    }
5784 	    else
5785 	    {
5786 		p = uword + uwordidx[depth];
5787 		l = ulen;
5788 	    }
5789 
5790 	    for (tryidx = arridx[depth]; l > 0; --l)
5791 	    {
5792 		/* Perform a binary search in the list of accepted bytes. */
5793 		len = byts[tryidx++];
5794 		c = *p++;
5795 		lo = tryidx;
5796 		hi = tryidx + len - 1;
5797 		while (lo < hi)
5798 		{
5799 		    m = (lo + hi) / 2;
5800 		    if (byts[m] > c)
5801 			hi = m - 1;
5802 		    else if (byts[m] < c)
5803 			lo = m + 1;
5804 		    else
5805 		    {
5806 			lo = hi = m;
5807 			break;
5808 		    }
5809 		}
5810 
5811 		/* Stop if there is no matching byte. */
5812 		if (hi < lo || byts[lo] != c)
5813 		    break;
5814 
5815 		/* Continue at the child (if there is one). */
5816 		tryidx = idxs[lo];
5817 	    }
5818 
5819 	    if (l == 0)
5820 	    {
5821 		/*
5822 		 * Found the matching char.  Copy it to "kword" and go a
5823 		 * level deeper.
5824 		 */
5825 		if (round[depth] == 1)
5826 		{
5827 		    STRNCPY(kword + kwordlen[depth], fword + fwordidx[depth],
5828 									flen);
5829 		    kwordlen[depth + 1] = kwordlen[depth] + flen;
5830 		}
5831 		else
5832 		{
5833 		    STRNCPY(kword + kwordlen[depth], uword + uwordidx[depth],
5834 									ulen);
5835 		    kwordlen[depth + 1] = kwordlen[depth] + ulen;
5836 		}
5837 		fwordidx[depth + 1] = fwordidx[depth] + flen;
5838 		uwordidx[depth + 1] = uwordidx[depth] + ulen;
5839 
5840 		++depth;
5841 		arridx[depth] = tryidx;
5842 		round[depth] = 0;
5843 	    }
5844 	}
5845     }
5846 
5847     /* Didn't find it: "cannot happen". */
5848     *kword = NUL;
5849 }
5850 
5851 /*
5852  * Compute the sound-a-like score for suggestions in su->su_ga and add them to
5853  * su->su_sga.
5854  */
5855     static void
5856 score_comp_sal(suginfo_T *su)
5857 {
5858     langp_T	*lp;
5859     char_u	badsound[MAXWLEN];
5860     int		i;
5861     suggest_T   *stp;
5862     suggest_T   *sstp;
5863     int		score;
5864     int		lpi;
5865 
5866     if (ga_grow(&su->su_sga, su->su_ga.ga_len) == FAIL)
5867 	return;
5868 
5869     /*	Use the sound-folding of the first language that supports it. */
5870     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
5871     {
5872 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
5873 	if (lp->lp_slang->sl_sal.ga_len > 0)
5874 	{
5875 	    /* soundfold the bad word */
5876 	    spell_soundfold(lp->lp_slang, su->su_fbadword, TRUE, badsound);
5877 
5878 	    for (i = 0; i < su->su_ga.ga_len; ++i)
5879 	    {
5880 		stp = &SUG(su->su_ga, i);
5881 
5882 		/* Case-fold the suggested word, sound-fold it and compute the
5883 		 * sound-a-like score. */
5884 		score = stp_sal_score(stp, su, lp->lp_slang, badsound);
5885 		if (score < SCORE_MAXMAX)
5886 		{
5887 		    /* Add the suggestion. */
5888 		    sstp = &SUG(su->su_sga, su->su_sga.ga_len);
5889 		    sstp->st_word = vim_strsave(stp->st_word);
5890 		    if (sstp->st_word != NULL)
5891 		    {
5892 			sstp->st_wordlen = stp->st_wordlen;
5893 			sstp->st_score = score;
5894 			sstp->st_altscore = 0;
5895 			sstp->st_orglen = stp->st_orglen;
5896 			++su->su_sga.ga_len;
5897 		    }
5898 		}
5899 	    }
5900 	    break;
5901 	}
5902     }
5903 }
5904 
5905 /*
5906  * Combine the list of suggestions in su->su_ga and su->su_sga.
5907  * They are entwined.
5908  */
5909     static void
5910 score_combine(suginfo_T *su)
5911 {
5912     int		i;
5913     int		j;
5914     garray_T	ga;
5915     garray_T	*gap;
5916     langp_T	*lp;
5917     suggest_T	*stp;
5918     char_u	*p;
5919     char_u	badsound[MAXWLEN];
5920     int		round;
5921     int		lpi;
5922     slang_T	*slang = NULL;
5923 
5924     /* Add the alternate score to su_ga. */
5925     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
5926     {
5927 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
5928 	if (lp->lp_slang->sl_sal.ga_len > 0)
5929 	{
5930 	    /* soundfold the bad word */
5931 	    slang = lp->lp_slang;
5932 	    spell_soundfold(slang, su->su_fbadword, TRUE, badsound);
5933 
5934 	    for (i = 0; i < su->su_ga.ga_len; ++i)
5935 	    {
5936 		stp = &SUG(su->su_ga, i);
5937 		stp->st_altscore = stp_sal_score(stp, su, slang, badsound);
5938 		if (stp->st_altscore == SCORE_MAXMAX)
5939 		    stp->st_score = (stp->st_score * 3 + SCORE_BIG) / 4;
5940 		else
5941 		    stp->st_score = (stp->st_score * 3
5942 						  + stp->st_altscore) / 4;
5943 		stp->st_salscore = FALSE;
5944 	    }
5945 	    break;
5946 	}
5947     }
5948 
5949     if (slang == NULL)	/* Using "double" without sound folding. */
5950     {
5951 	(void)cleanup_suggestions(&su->su_ga, su->su_maxscore,
5952 							     su->su_maxcount);
5953 	return;
5954     }
5955 
5956     /* Add the alternate score to su_sga. */
5957     for (i = 0; i < su->su_sga.ga_len; ++i)
5958     {
5959 	stp = &SUG(su->su_sga, i);
5960 	stp->st_altscore = spell_edit_score(slang,
5961 						su->su_badword, stp->st_word);
5962 	if (stp->st_score == SCORE_MAXMAX)
5963 	    stp->st_score = (SCORE_BIG * 7 + stp->st_altscore) / 8;
5964 	else
5965 	    stp->st_score = (stp->st_score * 7 + stp->st_altscore) / 8;
5966 	stp->st_salscore = TRUE;
5967     }
5968 
5969     /* Remove bad suggestions, sort the suggestions and truncate at "maxcount"
5970      * for both lists. */
5971     check_suggestions(su, &su->su_ga);
5972     (void)cleanup_suggestions(&su->su_ga, su->su_maxscore, su->su_maxcount);
5973     check_suggestions(su, &su->su_sga);
5974     (void)cleanup_suggestions(&su->su_sga, su->su_maxscore, su->su_maxcount);
5975 
5976     ga_init2(&ga, (int)sizeof(suginfo_T), 1);
5977     if (ga_grow(&ga, su->su_ga.ga_len + su->su_sga.ga_len) == FAIL)
5978 	return;
5979 
5980     stp = &SUG(ga, 0);
5981     for (i = 0; i < su->su_ga.ga_len || i < su->su_sga.ga_len; ++i)
5982     {
5983 	/* round 1: get a suggestion from su_ga
5984 	 * round 2: get a suggestion from su_sga */
5985 	for (round = 1; round <= 2; ++round)
5986 	{
5987 	    gap = round == 1 ? &su->su_ga : &su->su_sga;
5988 	    if (i < gap->ga_len)
5989 	    {
5990 		/* Don't add a word if it's already there. */
5991 		p = SUG(*gap, i).st_word;
5992 		for (j = 0; j < ga.ga_len; ++j)
5993 		    if (STRCMP(stp[j].st_word, p) == 0)
5994 			break;
5995 		if (j == ga.ga_len)
5996 		    stp[ga.ga_len++] = SUG(*gap, i);
5997 		else
5998 		    vim_free(p);
5999 	    }
6000 	}
6001     }
6002 
6003     ga_clear(&su->su_ga);
6004     ga_clear(&su->su_sga);
6005 
6006     /* Truncate the list to the number of suggestions that will be displayed. */
6007     if (ga.ga_len > su->su_maxcount)
6008     {
6009 	for (i = su->su_maxcount; i < ga.ga_len; ++i)
6010 	    vim_free(stp[i].st_word);
6011 	ga.ga_len = su->su_maxcount;
6012     }
6013 
6014     su->su_ga = ga;
6015 }
6016 
6017 /*
6018  * For the goodword in "stp" compute the soundalike score compared to the
6019  * badword.
6020  */
6021     static int
6022 stp_sal_score(
6023     suggest_T	*stp,
6024     suginfo_T	*su,
6025     slang_T	*slang,
6026     char_u	*badsound)	/* sound-folded badword */
6027 {
6028     char_u	*p;
6029     char_u	*pbad;
6030     char_u	*pgood;
6031     char_u	badsound2[MAXWLEN];
6032     char_u	fword[MAXWLEN];
6033     char_u	goodsound[MAXWLEN];
6034     char_u	goodword[MAXWLEN];
6035     int		lendiff;
6036 
6037     lendiff = (int)(su->su_badlen - stp->st_orglen);
6038     if (lendiff >= 0)
6039 	pbad = badsound;
6040     else
6041     {
6042 	/* soundfold the bad word with more characters following */
6043 	(void)spell_casefold(su->su_badptr, stp->st_orglen, fword, MAXWLEN);
6044 
6045 	/* When joining two words the sound often changes a lot.  E.g., "t he"
6046 	 * sounds like "t h" while "the" sounds like "@".  Avoid that by
6047 	 * removing the space.  Don't do it when the good word also contains a
6048 	 * space. */
6049 	if (VIM_ISWHITE(su->su_badptr[su->su_badlen])
6050 					 && *skiptowhite(stp->st_word) == NUL)
6051 	    for (p = fword; *(p = skiptowhite(p)) != NUL; )
6052 		STRMOVE(p, p + 1);
6053 
6054 	spell_soundfold(slang, fword, TRUE, badsound2);
6055 	pbad = badsound2;
6056     }
6057 
6058     if (lendiff > 0 && stp->st_wordlen + lendiff < MAXWLEN)
6059     {
6060 	/* Add part of the bad word to the good word, so that we soundfold
6061 	 * what replaces the bad word. */
6062 	STRCPY(goodword, stp->st_word);
6063 	vim_strncpy(goodword + stp->st_wordlen,
6064 			    su->su_badptr + su->su_badlen - lendiff, lendiff);
6065 	pgood = goodword;
6066     }
6067     else
6068 	pgood = stp->st_word;
6069 
6070     /* Sound-fold the word and compute the score for the difference. */
6071     spell_soundfold(slang, pgood, FALSE, goodsound);
6072 
6073     return soundalike_score(goodsound, pbad);
6074 }
6075 
6076 /* structure used to store soundfolded words that add_sound_suggest() has
6077  * handled already. */
6078 typedef struct
6079 {
6080     short	sft_score;	/* lowest score used */
6081     char_u	sft_word[1];    /* soundfolded word, actually longer */
6082 } sftword_T;
6083 
6084 static sftword_T dumsft;
6085 #define HIKEY2SFT(p)  ((sftword_T *)(p - (dumsft.sft_word - (char_u *)&dumsft)))
6086 #define HI2SFT(hi)     HIKEY2SFT((hi)->hi_key)
6087 
6088 /*
6089  * Prepare for calling suggest_try_soundalike().
6090  */
6091     static void
6092 suggest_try_soundalike_prep(void)
6093 {
6094     langp_T	*lp;
6095     int		lpi;
6096     slang_T	*slang;
6097 
6098     /* Do this for all languages that support sound folding and for which a
6099      * .sug file has been loaded. */
6100     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
6101     {
6102 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
6103 	slang = lp->lp_slang;
6104 	if (slang->sl_sal.ga_len > 0 && slang->sl_sbyts != NULL)
6105 	    /* prepare the hashtable used by add_sound_suggest() */
6106 	    hash_init(&slang->sl_sounddone);
6107     }
6108 }
6109 
6110 /*
6111  * Find suggestions by comparing the word in a sound-a-like form.
6112  * Note: This doesn't support postponed prefixes.
6113  */
6114     static void
6115 suggest_try_soundalike(suginfo_T *su)
6116 {
6117     char_u	salword[MAXWLEN];
6118     langp_T	*lp;
6119     int		lpi;
6120     slang_T	*slang;
6121 
6122     /* Do this for all languages that support sound folding and for which a
6123      * .sug file has been loaded. */
6124     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
6125     {
6126 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
6127 	slang = lp->lp_slang;
6128 	if (slang->sl_sal.ga_len > 0 && slang->sl_sbyts != NULL)
6129 	{
6130 	    /* soundfold the bad word */
6131 	    spell_soundfold(slang, su->su_fbadword, TRUE, salword);
6132 
6133 	    /* try all kinds of inserts/deletes/swaps/etc. */
6134 	    /* TODO: also soundfold the next words, so that we can try joining
6135 	     * and splitting */
6136 #ifdef SUGGEST_PROFILE
6137 	prof_init();
6138 #endif
6139 	    suggest_trie_walk(su, lp, salword, TRUE);
6140 #ifdef SUGGEST_PROFILE
6141 	prof_report("soundalike");
6142 #endif
6143 	}
6144     }
6145 }
6146 
6147 /*
6148  * Finish up after calling suggest_try_soundalike().
6149  */
6150     static void
6151 suggest_try_soundalike_finish(void)
6152 {
6153     langp_T	*lp;
6154     int		lpi;
6155     slang_T	*slang;
6156     int		todo;
6157     hashitem_T	*hi;
6158 
6159     /* Do this for all languages that support sound folding and for which a
6160      * .sug file has been loaded. */
6161     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
6162     {
6163 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
6164 	slang = lp->lp_slang;
6165 	if (slang->sl_sal.ga_len > 0 && slang->sl_sbyts != NULL)
6166 	{
6167 	    /* Free the info about handled words. */
6168 	    todo = (int)slang->sl_sounddone.ht_used;
6169 	    for (hi = slang->sl_sounddone.ht_array; todo > 0; ++hi)
6170 		if (!HASHITEM_EMPTY(hi))
6171 		{
6172 		    vim_free(HI2SFT(hi));
6173 		    --todo;
6174 		}
6175 
6176 	    /* Clear the hashtable, it may also be used by another region. */
6177 	    hash_clear(&slang->sl_sounddone);
6178 	    hash_init(&slang->sl_sounddone);
6179 	}
6180     }
6181 }
6182 
6183 /*
6184  * A match with a soundfolded word is found.  Add the good word(s) that
6185  * produce this soundfolded word.
6186  */
6187     static void
6188 add_sound_suggest(
6189     suginfo_T	*su,
6190     char_u	*goodword,
6191     int		score,		/* soundfold score  */
6192     langp_T	*lp)
6193 {
6194     slang_T	*slang = lp->lp_slang;	/* language for sound folding */
6195     int		sfwordnr;
6196     char_u	*nrline;
6197     int		orgnr;
6198     char_u	theword[MAXWLEN];
6199     int		i;
6200     int		wlen;
6201     char_u	*byts;
6202     idx_T	*idxs;
6203     int		n;
6204     int		wordcount;
6205     int		wc;
6206     int		goodscore;
6207     hash_T	hash;
6208     hashitem_T  *hi;
6209     sftword_T	*sft;
6210     int		bc, gc;
6211     int		limit;
6212 
6213     /*
6214      * It's very well possible that the same soundfold word is found several
6215      * times with different scores.  Since the following is quite slow only do
6216      * the words that have a better score than before.  Use a hashtable to
6217      * remember the words that have been done.
6218      */
6219     hash = hash_hash(goodword);
6220     hi = hash_lookup(&slang->sl_sounddone, goodword, hash);
6221     if (HASHITEM_EMPTY(hi))
6222     {
6223 	sft = (sftword_T *)alloc((unsigned)(sizeof(sftword_T)
6224 							 + STRLEN(goodword)));
6225 	if (sft != NULL)
6226 	{
6227 	    sft->sft_score = score;
6228 	    STRCPY(sft->sft_word, goodword);
6229 	    hash_add_item(&slang->sl_sounddone, hi, sft->sft_word, hash);
6230 	}
6231     }
6232     else
6233     {
6234 	sft = HI2SFT(hi);
6235 	if (score >= sft->sft_score)
6236 	    return;
6237 	sft->sft_score = score;
6238     }
6239 
6240     /*
6241      * Find the word nr in the soundfold tree.
6242      */
6243     sfwordnr = soundfold_find(slang, goodword);
6244     if (sfwordnr < 0)
6245     {
6246 	internal_error("add_sound_suggest()");
6247 	return;
6248     }
6249 
6250     /*
6251      * go over the list of good words that produce this soundfold word
6252      */
6253     nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)(sfwordnr + 1), FALSE);
6254     orgnr = 0;
6255     while (*nrline != NUL)
6256     {
6257 	/* The wordnr was stored in a minimal nr of bytes as an offset to the
6258 	 * previous wordnr. */
6259 	orgnr += bytes2offset(&nrline);
6260 
6261 	byts = slang->sl_fbyts;
6262 	idxs = slang->sl_fidxs;
6263 
6264 	/* Lookup the word "orgnr" one of the two tries. */
6265 	n = 0;
6266 	wordcount = 0;
6267 	for (wlen = 0; wlen < MAXWLEN - 3; ++wlen)
6268 	{
6269 	    i = 1;
6270 	    if (wordcount == orgnr && byts[n + 1] == NUL)
6271 		break;	/* found end of word */
6272 
6273 	    if (byts[n + 1] == NUL)
6274 		++wordcount;
6275 
6276 	    /* skip over the NUL bytes */
6277 	    for ( ; byts[n + i] == NUL; ++i)
6278 		if (i > byts[n])	/* safety check */
6279 		{
6280 		    STRCPY(theword + wlen, "BAD");
6281 		    wlen += 3;
6282 		    goto badword;
6283 		}
6284 
6285 	    /* One of the siblings must have the word. */
6286 	    for ( ; i < byts[n]; ++i)
6287 	    {
6288 		wc = idxs[idxs[n + i]];	/* nr of words under this byte */
6289 		if (wordcount + wc > orgnr)
6290 		    break;
6291 		wordcount += wc;
6292 	    }
6293 
6294 	    theword[wlen] = byts[n + i];
6295 	    n = idxs[n + i];
6296 	}
6297 badword:
6298 	theword[wlen] = NUL;
6299 
6300 	/* Go over the possible flags and regions. */
6301 	for (; i <= byts[n] && byts[n + i] == NUL; ++i)
6302 	{
6303 	    char_u	cword[MAXWLEN];
6304 	    char_u	*p;
6305 	    int		flags = (int)idxs[n + i];
6306 
6307 	    /* Skip words with the NOSUGGEST flag */
6308 	    if (flags & WF_NOSUGGEST)
6309 		continue;
6310 
6311 	    if (flags & WF_KEEPCAP)
6312 	    {
6313 		/* Must find the word in the keep-case tree. */
6314 		find_keepcap_word(slang, theword, cword);
6315 		p = cword;
6316 	    }
6317 	    else
6318 	    {
6319 		flags |= su->su_badflags;
6320 		if ((flags & WF_CAPMASK) != 0)
6321 		{
6322 		    /* Need to fix case according to "flags". */
6323 		    make_case_word(theword, cword, flags);
6324 		    p = cword;
6325 		}
6326 		else
6327 		    p = theword;
6328 	    }
6329 
6330 	    /* Add the suggestion. */
6331 	    if (sps_flags & SPS_DOUBLE)
6332 	    {
6333 		/* Add the suggestion if the score isn't too bad. */
6334 		if (score <= su->su_maxscore)
6335 		    add_suggestion(su, &su->su_sga, p, su->su_badlen,
6336 					       score, 0, FALSE, slang, FALSE);
6337 	    }
6338 	    else
6339 	    {
6340 		/* Add a penalty for words in another region. */
6341 		if ((flags & WF_REGION)
6342 			    && (((unsigned)flags >> 16) & lp->lp_region) == 0)
6343 		    goodscore = SCORE_REGION;
6344 		else
6345 		    goodscore = 0;
6346 
6347 		/* Add a small penalty for changing the first letter from
6348 		 * lower to upper case.  Helps for "tath" -> "Kath", which is
6349 		 * less common than "tath" -> "path".  Don't do it when the
6350 		 * letter is the same, that has already been counted. */
6351 		gc = PTR2CHAR(p);
6352 		if (SPELL_ISUPPER(gc))
6353 		{
6354 		    bc = PTR2CHAR(su->su_badword);
6355 		    if (!SPELL_ISUPPER(bc)
6356 				      && SPELL_TOFOLD(bc) != SPELL_TOFOLD(gc))
6357 			goodscore += SCORE_ICASE / 2;
6358 		}
6359 
6360 		/* Compute the score for the good word.  This only does letter
6361 		 * insert/delete/swap/replace.  REP items are not considered,
6362 		 * which may make the score a bit higher.
6363 		 * Use a limit for the score to make it work faster.  Use
6364 		 * MAXSCORE(), because RESCORE() will change the score.
6365 		 * If the limit is very high then the iterative method is
6366 		 * inefficient, using an array is quicker. */
6367 		limit = MAXSCORE(su->su_sfmaxscore - goodscore, score);
6368 		if (limit > SCORE_LIMITMAX)
6369 		    goodscore += spell_edit_score(slang, su->su_badword, p);
6370 		else
6371 		    goodscore += spell_edit_score_limit(slang, su->su_badword,
6372 								    p, limit);
6373 
6374 		/* When going over the limit don't bother to do the rest. */
6375 		if (goodscore < SCORE_MAXMAX)
6376 		{
6377 		    /* Give a bonus to words seen before. */
6378 		    goodscore = score_wordcount_adj(slang, goodscore, p, FALSE);
6379 
6380 		    /* Add the suggestion if the score isn't too bad. */
6381 		    goodscore = RESCORE(goodscore, score);
6382 		    if (goodscore <= su->su_sfmaxscore)
6383 			add_suggestion(su, &su->su_ga, p, su->su_badlen,
6384 					 goodscore, score, TRUE, slang, TRUE);
6385 		}
6386 	    }
6387 	}
6388 	/* smsg("word %s (%d): %s (%d)", sftword, sftnr, theword, orgnr); */
6389     }
6390 }
6391 
6392 /*
6393  * Find word "word" in fold-case tree for "slang" and return the word number.
6394  */
6395     static int
6396 soundfold_find(slang_T *slang, char_u *word)
6397 {
6398     idx_T	arridx = 0;
6399     int		len;
6400     int		wlen = 0;
6401     int		c;
6402     char_u	*ptr = word;
6403     char_u	*byts;
6404     idx_T	*idxs;
6405     int		wordnr = 0;
6406 
6407     byts = slang->sl_sbyts;
6408     idxs = slang->sl_sidxs;
6409 
6410     for (;;)
6411     {
6412 	/* First byte is the number of possible bytes. */
6413 	len = byts[arridx++];
6414 
6415 	/* If the first possible byte is a zero the word could end here.
6416 	 * If the word ends we found the word.  If not skip the NUL bytes. */
6417 	c = ptr[wlen];
6418 	if (byts[arridx] == NUL)
6419 	{
6420 	    if (c == NUL)
6421 		break;
6422 
6423 	    /* Skip over the zeros, there can be several. */
6424 	    while (len > 0 && byts[arridx] == NUL)
6425 	    {
6426 		++arridx;
6427 		--len;
6428 	    }
6429 	    if (len == 0)
6430 		return -1;    /* no children, word should have ended here */
6431 	    ++wordnr;
6432 	}
6433 
6434 	/* If the word ends we didn't find it. */
6435 	if (c == NUL)
6436 	    return -1;
6437 
6438 	/* Perform a binary search in the list of accepted bytes. */
6439 	if (c == TAB)	    /* <Tab> is handled like <Space> */
6440 	    c = ' ';
6441 	while (byts[arridx] < c)
6442 	{
6443 	    /* The word count is in the first idxs[] entry of the child. */
6444 	    wordnr += idxs[idxs[arridx]];
6445 	    ++arridx;
6446 	    if (--len == 0)	/* end of the bytes, didn't find it */
6447 		return -1;
6448 	}
6449 	if (byts[arridx] != c)	/* didn't find the byte */
6450 	    return -1;
6451 
6452 	/* Continue at the child (if there is one). */
6453 	arridx = idxs[arridx];
6454 	++wlen;
6455 
6456 	/* One space in the good word may stand for several spaces in the
6457 	 * checked word. */
6458 	if (c == ' ')
6459 	    while (ptr[wlen] == ' ' || ptr[wlen] == TAB)
6460 		++wlen;
6461     }
6462 
6463     return wordnr;
6464 }
6465 
6466 /*
6467  * Copy "fword" to "cword", fixing case according to "flags".
6468  */
6469     static void
6470 make_case_word(char_u *fword, char_u *cword, int flags)
6471 {
6472     if (flags & WF_ALLCAP)
6473 	/* Make it all upper-case */
6474 	allcap_copy(fword, cword);
6475     else if (flags & WF_ONECAP)
6476 	/* Make the first letter upper-case */
6477 	onecap_copy(fword, cword, TRUE);
6478     else
6479 	/* Use goodword as-is. */
6480 	STRCPY(cword, fword);
6481 }
6482 
6483 
6484 /*
6485  * Return TRUE if "c1" and "c2" are similar characters according to the MAP
6486  * lines in the .aff file.
6487  */
6488     static int
6489 similar_chars(slang_T *slang, int c1, int c2)
6490 {
6491     int		m1, m2;
6492     char_u	buf[MB_MAXBYTES + 1];
6493     hashitem_T  *hi;
6494 
6495     if (c1 >= 256)
6496     {
6497 	buf[mb_char2bytes(c1, buf)] = 0;
6498 	hi = hash_find(&slang->sl_map_hash, buf);
6499 	if (HASHITEM_EMPTY(hi))
6500 	    m1 = 0;
6501 	else
6502 	    m1 = mb_ptr2char(hi->hi_key + STRLEN(hi->hi_key) + 1);
6503     }
6504     else
6505 	m1 = slang->sl_map_array[c1];
6506     if (m1 == 0)
6507 	return FALSE;
6508 
6509 
6510     if (c2 >= 256)
6511     {
6512 	buf[mb_char2bytes(c2, buf)] = 0;
6513 	hi = hash_find(&slang->sl_map_hash, buf);
6514 	if (HASHITEM_EMPTY(hi))
6515 	    m2 = 0;
6516 	else
6517 	    m2 = mb_ptr2char(hi->hi_key + STRLEN(hi->hi_key) + 1);
6518     }
6519     else
6520 	m2 = slang->sl_map_array[c2];
6521 
6522     return m1 == m2;
6523 }
6524 
6525 /*
6526  * Add a suggestion to the list of suggestions.
6527  * For a suggestion that is already in the list the lowest score is remembered.
6528  */
6529     static void
6530 add_suggestion(
6531     suginfo_T	*su,
6532     garray_T	*gap,		/* either su_ga or su_sga */
6533     char_u	*goodword,
6534     int		badlenarg,	/* len of bad word replaced with "goodword" */
6535     int		score,
6536     int		altscore,
6537     int		had_bonus,	/* value for st_had_bonus */
6538     slang_T	*slang,		/* language for sound folding */
6539     int		maxsf)		/* su_maxscore applies to soundfold score,
6540 				   su_sfmaxscore to the total score. */
6541 {
6542     int		goodlen;	/* len of goodword changed */
6543     int		badlen;		/* len of bad word changed */
6544     suggest_T   *stp;
6545     suggest_T   new_sug;
6546     int		i;
6547     char_u	*pgood, *pbad;
6548 
6549     /* Minimize "badlen" for consistency.  Avoids that changing "the the" to
6550      * "thee the" is added next to changing the first "the" the "thee".  */
6551     pgood = goodword + STRLEN(goodword);
6552     pbad = su->su_badptr + badlenarg;
6553     for (;;)
6554     {
6555 	goodlen = (int)(pgood - goodword);
6556 	badlen = (int)(pbad - su->su_badptr);
6557 	if (goodlen <= 0 || badlen <= 0)
6558 	    break;
6559 	MB_PTR_BACK(goodword, pgood);
6560 	MB_PTR_BACK(su->su_badptr, pbad);
6561 	if (has_mbyte)
6562 	{
6563 	    if (mb_ptr2char(pgood) != mb_ptr2char(pbad))
6564 		break;
6565 	}
6566 	else if (*pgood != *pbad)
6567 		break;
6568     }
6569 
6570     if (badlen == 0 && goodlen == 0)
6571 	/* goodword doesn't change anything; may happen for "the the" changing
6572 	 * the first "the" to itself. */
6573 	return;
6574 
6575     if (gap->ga_len == 0)
6576 	i = -1;
6577     else
6578     {
6579 	/* Check if the word is already there.  Also check the length that is
6580 	 * being replaced "thes," -> "these" is a different suggestion from
6581 	 * "thes" -> "these". */
6582 	stp = &SUG(*gap, 0);
6583 	for (i = gap->ga_len; --i >= 0; ++stp)
6584 	    if (stp->st_wordlen == goodlen
6585 		    && stp->st_orglen == badlen
6586 		    && STRNCMP(stp->st_word, goodword, goodlen) == 0)
6587 	    {
6588 		/*
6589 		 * Found it.  Remember the word with the lowest score.
6590 		 */
6591 		if (stp->st_slang == NULL)
6592 		    stp->st_slang = slang;
6593 
6594 		new_sug.st_score = score;
6595 		new_sug.st_altscore = altscore;
6596 		new_sug.st_had_bonus = had_bonus;
6597 
6598 		if (stp->st_had_bonus != had_bonus)
6599 		{
6600 		    /* Only one of the two had the soundalike score computed.
6601 		     * Need to do that for the other one now, otherwise the
6602 		     * scores can't be compared.  This happens because
6603 		     * suggest_try_change() doesn't compute the soundalike
6604 		     * word to keep it fast, while some special methods set
6605 		     * the soundalike score to zero. */
6606 		    if (had_bonus)
6607 			rescore_one(su, stp);
6608 		    else
6609 		    {
6610 			new_sug.st_word = stp->st_word;
6611 			new_sug.st_wordlen = stp->st_wordlen;
6612 			new_sug.st_slang = stp->st_slang;
6613 			new_sug.st_orglen = badlen;
6614 			rescore_one(su, &new_sug);
6615 		    }
6616 		}
6617 
6618 		if (stp->st_score > new_sug.st_score)
6619 		{
6620 		    stp->st_score = new_sug.st_score;
6621 		    stp->st_altscore = new_sug.st_altscore;
6622 		    stp->st_had_bonus = new_sug.st_had_bonus;
6623 		}
6624 		break;
6625 	    }
6626     }
6627 
6628     if (i < 0 && ga_grow(gap, 1) == OK)
6629     {
6630 	/* Add a suggestion. */
6631 	stp = &SUG(*gap, gap->ga_len);
6632 	stp->st_word = vim_strnsave(goodword, goodlen);
6633 	if (stp->st_word != NULL)
6634 	{
6635 	    stp->st_wordlen = goodlen;
6636 	    stp->st_score = score;
6637 	    stp->st_altscore = altscore;
6638 	    stp->st_had_bonus = had_bonus;
6639 	    stp->st_orglen = badlen;
6640 	    stp->st_slang = slang;
6641 	    ++gap->ga_len;
6642 
6643 	    /* If we have too many suggestions now, sort the list and keep
6644 	     * the best suggestions. */
6645 	    if (gap->ga_len > SUG_MAX_COUNT(su))
6646 	    {
6647 		if (maxsf)
6648 		    su->su_sfmaxscore = cleanup_suggestions(gap,
6649 				      su->su_sfmaxscore, SUG_CLEAN_COUNT(su));
6650 		else
6651 		    su->su_maxscore = cleanup_suggestions(gap,
6652 					su->su_maxscore, SUG_CLEAN_COUNT(su));
6653 	    }
6654 	}
6655     }
6656 }
6657 
6658 /*
6659  * Suggestions may in fact be flagged as errors.  Esp. for banned words and
6660  * for split words, such as "the the".  Remove these from the list here.
6661  */
6662     static void
6663 check_suggestions(
6664     suginfo_T	*su,
6665     garray_T	*gap)		    /* either su_ga or su_sga */
6666 {
6667     suggest_T   *stp;
6668     int		i;
6669     char_u	longword[MAXWLEN + 1];
6670     int		len;
6671     hlf_T	attr;
6672 
6673     stp = &SUG(*gap, 0);
6674     for (i = gap->ga_len - 1; i >= 0; --i)
6675     {
6676 	/* Need to append what follows to check for "the the". */
6677 	vim_strncpy(longword, stp[i].st_word, MAXWLEN);
6678 	len = stp[i].st_wordlen;
6679 	vim_strncpy(longword + len, su->su_badptr + stp[i].st_orglen,
6680 							       MAXWLEN - len);
6681 	attr = HLF_COUNT;
6682 	(void)spell_check(curwin, longword, &attr, NULL, FALSE);
6683 	if (attr != HLF_COUNT)
6684 	{
6685 	    /* Remove this entry. */
6686 	    vim_free(stp[i].st_word);
6687 	    --gap->ga_len;
6688 	    if (i < gap->ga_len)
6689 		mch_memmove(stp + i, stp + i + 1,
6690 				       sizeof(suggest_T) * (gap->ga_len - i));
6691 	}
6692     }
6693 }
6694 
6695 
6696 /*
6697  * Add a word to be banned.
6698  */
6699     static void
6700 add_banned(
6701     suginfo_T	*su,
6702     char_u	*word)
6703 {
6704     char_u	*s;
6705     hash_T	hash;
6706     hashitem_T	*hi;
6707 
6708     hash = hash_hash(word);
6709     hi = hash_lookup(&su->su_banned, word, hash);
6710     if (HASHITEM_EMPTY(hi))
6711     {
6712 	s = vim_strsave(word);
6713 	if (s != NULL)
6714 	    hash_add_item(&su->su_banned, hi, s, hash);
6715     }
6716 }
6717 
6718 /*
6719  * Recompute the score for all suggestions if sound-folding is possible.  This
6720  * is slow, thus only done for the final results.
6721  */
6722     static void
6723 rescore_suggestions(suginfo_T *su)
6724 {
6725     int		i;
6726 
6727     if (su->su_sallang != NULL)
6728 	for (i = 0; i < su->su_ga.ga_len; ++i)
6729 	    rescore_one(su, &SUG(su->su_ga, i));
6730 }
6731 
6732 /*
6733  * Recompute the score for one suggestion if sound-folding is possible.
6734  */
6735     static void
6736 rescore_one(suginfo_T *su, suggest_T *stp)
6737 {
6738     slang_T	*slang = stp->st_slang;
6739     char_u	sal_badword[MAXWLEN];
6740     char_u	*p;
6741 
6742     /* Only rescore suggestions that have no sal score yet and do have a
6743      * language. */
6744     if (slang != NULL && slang->sl_sal.ga_len > 0 && !stp->st_had_bonus)
6745     {
6746 	if (slang == su->su_sallang)
6747 	    p = su->su_sal_badword;
6748 	else
6749 	{
6750 	    spell_soundfold(slang, su->su_fbadword, TRUE, sal_badword);
6751 	    p = sal_badword;
6752 	}
6753 
6754 	stp->st_altscore = stp_sal_score(stp, su, slang, p);
6755 	if (stp->st_altscore == SCORE_MAXMAX)
6756 	    stp->st_altscore = SCORE_BIG;
6757 	stp->st_score = RESCORE(stp->st_score, stp->st_altscore);
6758 	stp->st_had_bonus = TRUE;
6759     }
6760 }
6761 
6762 static int
6763 #ifdef __BORLANDC__
6764 _RTLENTRYF
6765 #endif
6766 sug_compare(const void *s1, const void *s2);
6767 
6768 /*
6769  * Function given to qsort() to sort the suggestions on st_score.
6770  * First on "st_score", then "st_altscore" then alphabetically.
6771  */
6772     static int
6773 #ifdef __BORLANDC__
6774 _RTLENTRYF
6775 #endif
6776 sug_compare(const void *s1, const void *s2)
6777 {
6778     suggest_T	*p1 = (suggest_T *)s1;
6779     suggest_T	*p2 = (suggest_T *)s2;
6780     int		n = p1->st_score - p2->st_score;
6781 
6782     if (n == 0)
6783     {
6784 	n = p1->st_altscore - p2->st_altscore;
6785 	if (n == 0)
6786 	    n = STRICMP(p1->st_word, p2->st_word);
6787     }
6788     return n;
6789 }
6790 
6791 /*
6792  * Cleanup the suggestions:
6793  * - Sort on score.
6794  * - Remove words that won't be displayed.
6795  * Returns the maximum score in the list or "maxscore" unmodified.
6796  */
6797     static int
6798 cleanup_suggestions(
6799     garray_T	*gap,
6800     int		maxscore,
6801     int		keep)		/* nr of suggestions to keep */
6802 {
6803     suggest_T   *stp = &SUG(*gap, 0);
6804     int		i;
6805 
6806     /* Sort the list. */
6807     qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare);
6808 
6809     /* Truncate the list to the number of suggestions that will be displayed. */
6810     if (gap->ga_len > keep)
6811     {
6812 	for (i = keep; i < gap->ga_len; ++i)
6813 	    vim_free(stp[i].st_word);
6814 	gap->ga_len = keep;
6815 	return stp[keep - 1].st_score;
6816     }
6817     return maxscore;
6818 }
6819 
6820 #if defined(FEAT_EVAL) || defined(PROTO)
6821 /*
6822  * Soundfold a string, for soundfold().
6823  * Result is in allocated memory, NULL for an error.
6824  */
6825     char_u *
6826 eval_soundfold(char_u *word)
6827 {
6828     langp_T	*lp;
6829     char_u	sound[MAXWLEN];
6830     int		lpi;
6831 
6832     if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
6833 	/* Use the sound-folding of the first language that supports it. */
6834 	for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
6835 	{
6836 	    lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
6837 	    if (lp->lp_slang->sl_sal.ga_len > 0)
6838 	    {
6839 		/* soundfold the word */
6840 		spell_soundfold(lp->lp_slang, word, FALSE, sound);
6841 		return vim_strsave(sound);
6842 	    }
6843 	}
6844 
6845     /* No language with sound folding, return word as-is. */
6846     return vim_strsave(word);
6847 }
6848 #endif
6849 
6850 /*
6851  * Turn "inword" into its sound-a-like equivalent in "res[MAXWLEN]".
6852  *
6853  * There are many ways to turn a word into a sound-a-like representation.  The
6854  * oldest is Soundex (1918!).   A nice overview can be found in "Approximate
6855  * swedish name matching - survey and test of different algorithms" by Klas
6856  * Erikson.
6857  *
6858  * We support two methods:
6859  * 1. SOFOFROM/SOFOTO do a simple character mapping.
6860  * 2. SAL items define a more advanced sound-folding (and much slower).
6861  */
6862     void
6863 spell_soundfold(
6864     slang_T	*slang,
6865     char_u	*inword,
6866     int		folded,	    /* "inword" is already case-folded */
6867     char_u	*res)
6868 {
6869     char_u	fword[MAXWLEN];
6870     char_u	*word;
6871 
6872     if (slang->sl_sofo)
6873 	/* SOFOFROM and SOFOTO used */
6874 	spell_soundfold_sofo(slang, inword, res);
6875     else
6876     {
6877 	/* SAL items used.  Requires the word to be case-folded. */
6878 	if (folded)
6879 	    word = inword;
6880 	else
6881 	{
6882 	    (void)spell_casefold(inword, (int)STRLEN(inword), fword, MAXWLEN);
6883 	    word = fword;
6884 	}
6885 
6886 	if (has_mbyte)
6887 	    spell_soundfold_wsal(slang, word, res);
6888 	else
6889 	    spell_soundfold_sal(slang, word, res);
6890     }
6891 }
6892 
6893 /*
6894  * Perform sound folding of "inword" into "res" according to SOFOFROM and
6895  * SOFOTO lines.
6896  */
6897     static void
6898 spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res)
6899 {
6900     char_u	*s;
6901     int		ri = 0;
6902     int		c;
6903 
6904     if (has_mbyte)
6905     {
6906 	int	prevc = 0;
6907 	int	*ip;
6908 
6909 	/* The sl_sal_first[] table contains the translation for chars up to
6910 	 * 255, sl_sal the rest. */
6911 	for (s = inword; *s != NUL; )
6912 	{
6913 	    c = mb_cptr2char_adv(&s);
6914 	    if (enc_utf8 ? utf_class(c) == 0 : VIM_ISWHITE(c))
6915 		c = ' ';
6916 	    else if (c < 256)
6917 		c = slang->sl_sal_first[c];
6918 	    else
6919 	    {
6920 		ip = ((int **)slang->sl_sal.ga_data)[c & 0xff];
6921 		if (ip == NULL)		/* empty list, can't match */
6922 		    c = NUL;
6923 		else
6924 		    for (;;)		/* find "c" in the list */
6925 		    {
6926 			if (*ip == 0)	/* not found */
6927 			{
6928 			    c = NUL;
6929 			    break;
6930 			}
6931 			if (*ip == c)	/* match! */
6932 			{
6933 			    c = ip[1];
6934 			    break;
6935 			}
6936 			ip += 2;
6937 		    }
6938 	    }
6939 
6940 	    if (c != NUL && c != prevc)
6941 	    {
6942 		ri += mb_char2bytes(c, res + ri);
6943 		if (ri + MB_MAXBYTES > MAXWLEN)
6944 		    break;
6945 		prevc = c;
6946 	    }
6947 	}
6948     }
6949     else
6950     {
6951 	/* The sl_sal_first[] table contains the translation. */
6952 	for (s = inword; (c = *s) != NUL; ++s)
6953 	{
6954 	    if (VIM_ISWHITE(c))
6955 		c = ' ';
6956 	    else
6957 		c = slang->sl_sal_first[c];
6958 	    if (c != NUL && (ri == 0 || res[ri - 1] != c))
6959 		res[ri++] = c;
6960 	}
6961     }
6962 
6963     res[ri] = NUL;
6964 }
6965 
6966     static void
6967 spell_soundfold_sal(slang_T *slang, char_u *inword, char_u *res)
6968 {
6969     salitem_T	*smp;
6970     char_u	word[MAXWLEN];
6971     char_u	*s = inword;
6972     char_u	*t;
6973     char_u	*pf;
6974     int		i, j, z;
6975     int		reslen;
6976     int		n, k = 0;
6977     int		z0;
6978     int		k0;
6979     int		n0;
6980     int		c;
6981     int		pri;
6982     int		p0 = -333;
6983     int		c0;
6984 
6985     /* Remove accents, if wanted.  We actually remove all non-word characters.
6986      * But keep white space.  We need a copy, the word may be changed here. */
6987     if (slang->sl_rem_accents)
6988     {
6989 	t = word;
6990 	while (*s != NUL)
6991 	{
6992 	    if (VIM_ISWHITE(*s))
6993 	    {
6994 		*t++ = ' ';
6995 		s = skipwhite(s);
6996 	    }
6997 	    else
6998 	    {
6999 		if (spell_iswordp_nmw(s, curwin))
7000 		    *t++ = *s;
7001 		++s;
7002 	    }
7003 	}
7004 	*t = NUL;
7005     }
7006     else
7007 	vim_strncpy(word, s, MAXWLEN - 1);
7008 
7009     smp = (salitem_T *)slang->sl_sal.ga_data;
7010 
7011     /*
7012      * This comes from Aspell phonet.cpp.  Converted from C++ to C.
7013      * Changed to keep spaces.
7014      */
7015     i = reslen = z = 0;
7016     while ((c = word[i]) != NUL)
7017     {
7018 	/* Start with the first rule that has the character in the word. */
7019 	n = slang->sl_sal_first[c];
7020 	z0 = 0;
7021 
7022 	if (n >= 0)
7023 	{
7024 	    /* check all rules for the same letter */
7025 	    for (; (s = smp[n].sm_lead)[0] == c; ++n)
7026 	    {
7027 		/* Quickly skip entries that don't match the word.  Most
7028 		 * entries are less then three chars, optimize for that. */
7029 		k = smp[n].sm_leadlen;
7030 		if (k > 1)
7031 		{
7032 		    if (word[i + 1] != s[1])
7033 			continue;
7034 		    if (k > 2)
7035 		    {
7036 			for (j = 2; j < k; ++j)
7037 			    if (word[i + j] != s[j])
7038 				break;
7039 			if (j < k)
7040 			    continue;
7041 		    }
7042 		}
7043 
7044 		if ((pf = smp[n].sm_oneof) != NULL)
7045 		{
7046 		    /* Check for match with one of the chars in "sm_oneof". */
7047 		    while (*pf != NUL && *pf != word[i + k])
7048 			++pf;
7049 		    if (*pf == NUL)
7050 			continue;
7051 		    ++k;
7052 		}
7053 		s = smp[n].sm_rules;
7054 		pri = 5;    /* default priority */
7055 
7056 		p0 = *s;
7057 		k0 = k;
7058 		while (*s == '-' && k > 1)
7059 		{
7060 		    k--;
7061 		    s++;
7062 		}
7063 		if (*s == '<')
7064 		    s++;
7065 		if (VIM_ISDIGIT(*s))
7066 		{
7067 		    /* determine priority */
7068 		    pri = *s - '0';
7069 		    s++;
7070 		}
7071 		if (*s == '^' && *(s + 1) == '^')
7072 		    s++;
7073 
7074 		if (*s == NUL
7075 			|| (*s == '^'
7076 			    && (i == 0 || !(word[i - 1] == ' '
7077 				      || spell_iswordp(word + i - 1, curwin)))
7078 			    && (*(s + 1) != '$'
7079 				|| (!spell_iswordp(word + i + k0, curwin))))
7080 			|| (*s == '$' && i > 0
7081 			    && spell_iswordp(word + i - 1, curwin)
7082 			    && (!spell_iswordp(word + i + k0, curwin))))
7083 		{
7084 		    /* search for followup rules, if:    */
7085 		    /* followup and k > 1  and  NO '-' in searchstring */
7086 		    c0 = word[i + k - 1];
7087 		    n0 = slang->sl_sal_first[c0];
7088 
7089 		    if (slang->sl_followup && k > 1 && n0 >= 0
7090 					   && p0 != '-' && word[i + k] != NUL)
7091 		    {
7092 			/* test follow-up rule for "word[i + k]" */
7093 			for ( ; (s = smp[n0].sm_lead)[0] == c0; ++n0)
7094 			{
7095 			    /* Quickly skip entries that don't match the word.
7096 			     * */
7097 			    k0 = smp[n0].sm_leadlen;
7098 			    if (k0 > 1)
7099 			    {
7100 				if (word[i + k] != s[1])
7101 				    continue;
7102 				if (k0 > 2)
7103 				{
7104 				    pf = word + i + k + 1;
7105 				    for (j = 2; j < k0; ++j)
7106 					if (*pf++ != s[j])
7107 					    break;
7108 				    if (j < k0)
7109 					continue;
7110 				}
7111 			    }
7112 			    k0 += k - 1;
7113 
7114 			    if ((pf = smp[n0].sm_oneof) != NULL)
7115 			    {
7116 				/* Check for match with one of the chars in
7117 				 * "sm_oneof". */
7118 				while (*pf != NUL && *pf != word[i + k0])
7119 				    ++pf;
7120 				if (*pf == NUL)
7121 				    continue;
7122 				++k0;
7123 			    }
7124 
7125 			    p0 = 5;
7126 			    s = smp[n0].sm_rules;
7127 			    while (*s == '-')
7128 			    {
7129 				/* "k0" gets NOT reduced because
7130 				 * "if (k0 == k)" */
7131 				s++;
7132 			    }
7133 			    if (*s == '<')
7134 				s++;
7135 			    if (VIM_ISDIGIT(*s))
7136 			    {
7137 				p0 = *s - '0';
7138 				s++;
7139 			    }
7140 
7141 			    if (*s == NUL
7142 				    /* *s == '^' cuts */
7143 				    || (*s == '$'
7144 					    && !spell_iswordp(word + i + k0,
7145 								     curwin)))
7146 			    {
7147 				if (k0 == k)
7148 				    /* this is just a piece of the string */
7149 				    continue;
7150 
7151 				if (p0 < pri)
7152 				    /* priority too low */
7153 				    continue;
7154 				/* rule fits; stop search */
7155 				break;
7156 			    }
7157 			}
7158 
7159 			if (p0 >= pri && smp[n0].sm_lead[0] == c0)
7160 			    continue;
7161 		    }
7162 
7163 		    /* replace string */
7164 		    s = smp[n].sm_to;
7165 		    if (s == NULL)
7166 			s = (char_u *)"";
7167 		    pf = smp[n].sm_rules;
7168 		    p0 = (vim_strchr(pf, '<') != NULL) ? 1 : 0;
7169 		    if (p0 == 1 && z == 0)
7170 		    {
7171 			/* rule with '<' is used */
7172 			if (reslen > 0 && *s != NUL && (res[reslen - 1] == c
7173 						    || res[reslen - 1] == *s))
7174 			    reslen--;
7175 			z0 = 1;
7176 			z = 1;
7177 			k0 = 0;
7178 			while (*s != NUL && word[i + k0] != NUL)
7179 			{
7180 			    word[i + k0] = *s;
7181 			    k0++;
7182 			    s++;
7183 			}
7184 			if (k > k0)
7185 			    STRMOVE(word + i + k0, word + i + k);
7186 
7187 			/* new "actual letter" */
7188 			c = word[i];
7189 		    }
7190 		    else
7191 		    {
7192 			/* no '<' rule used */
7193 			i += k - 1;
7194 			z = 0;
7195 			while (*s != NUL && s[1] != NUL && reslen < MAXWLEN)
7196 			{
7197 			    if (reslen == 0 || res[reslen - 1] != *s)
7198 				res[reslen++] = *s;
7199 			    s++;
7200 			}
7201 			/* new "actual letter" */
7202 			c = *s;
7203 			if (strstr((char *)pf, "^^") != NULL)
7204 			{
7205 			    if (c != NUL)
7206 				res[reslen++] = c;
7207 			    STRMOVE(word, word + i + 1);
7208 			    i = 0;
7209 			    z0 = 1;
7210 			}
7211 		    }
7212 		    break;
7213 		}
7214 	    }
7215 	}
7216 	else if (VIM_ISWHITE(c))
7217 	{
7218 	    c = ' ';
7219 	    k = 1;
7220 	}
7221 
7222 	if (z0 == 0)
7223 	{
7224 	    if (k && !p0 && reslen < MAXWLEN && c != NUL
7225 		    && (!slang->sl_collapse || reslen == 0
7226 						     || res[reslen - 1] != c))
7227 		/* condense only double letters */
7228 		res[reslen++] = c;
7229 
7230 	    i++;
7231 	    z = 0;
7232 	    k = 0;
7233 	}
7234     }
7235 
7236     res[reslen] = NUL;
7237 }
7238 
7239 /*
7240  * Turn "inword" into its sound-a-like equivalent in "res[MAXWLEN]".
7241  * Multi-byte version of spell_soundfold().
7242  */
7243     static void
7244 spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
7245 {
7246     salitem_T	*smp = (salitem_T *)slang->sl_sal.ga_data;
7247     int		word[MAXWLEN];
7248     int		wres[MAXWLEN];
7249     int		l;
7250     char_u	*s;
7251     int		*ws;
7252     char_u	*t;
7253     int		*pf;
7254     int		i, j, z;
7255     int		reslen;
7256     int		n, k = 0;
7257     int		z0;
7258     int		k0;
7259     int		n0;
7260     int		c;
7261     int		pri;
7262     int		p0 = -333;
7263     int		c0;
7264     int		did_white = FALSE;
7265     int		wordlen;
7266 
7267 
7268     /*
7269      * Convert the multi-byte string to a wide-character string.
7270      * Remove accents, if wanted.  We actually remove all non-word characters.
7271      * But keep white space.
7272      */
7273     wordlen = 0;
7274     for (s = inword; *s != NUL; )
7275     {
7276 	t = s;
7277 	c = mb_cptr2char_adv(&s);
7278 	if (slang->sl_rem_accents)
7279 	{
7280 	    if (enc_utf8 ? utf_class(c) == 0 : VIM_ISWHITE(c))
7281 	    {
7282 		if (did_white)
7283 		    continue;
7284 		c = ' ';
7285 		did_white = TRUE;
7286 	    }
7287 	    else
7288 	    {
7289 		did_white = FALSE;
7290 		if (!spell_iswordp_nmw(t, curwin))
7291 		    continue;
7292 	    }
7293 	}
7294 	word[wordlen++] = c;
7295     }
7296     word[wordlen] = NUL;
7297 
7298     /*
7299      * This algorithm comes from Aspell phonet.cpp.
7300      * Converted from C++ to C.  Added support for multi-byte chars.
7301      * Changed to keep spaces.
7302      */
7303     i = reslen = z = 0;
7304     while ((c = word[i]) != NUL)
7305     {
7306 	/* Start with the first rule that has the character in the word. */
7307 	n = slang->sl_sal_first[c & 0xff];
7308 	z0 = 0;
7309 
7310 	if (n >= 0)
7311 	{
7312 	    /* Check all rules for the same index byte.
7313 	     * If c is 0x300 need extra check for the end of the array, as
7314 	     * (c & 0xff) is NUL. */
7315 	    for (; ((ws = smp[n].sm_lead_w)[0] & 0xff) == (c & 0xff)
7316 							 && ws[0] != NUL; ++n)
7317 	    {
7318 		/* Quickly skip entries that don't match the word.  Most
7319 		 * entries are less then three chars, optimize for that. */
7320 		if (c != ws[0])
7321 		    continue;
7322 		k = smp[n].sm_leadlen;
7323 		if (k > 1)
7324 		{
7325 		    if (word[i + 1] != ws[1])
7326 			continue;
7327 		    if (k > 2)
7328 		    {
7329 			for (j = 2; j < k; ++j)
7330 			    if (word[i + j] != ws[j])
7331 				break;
7332 			if (j < k)
7333 			    continue;
7334 		    }
7335 		}
7336 
7337 		if ((pf = smp[n].sm_oneof_w) != NULL)
7338 		{
7339 		    /* Check for match with one of the chars in "sm_oneof". */
7340 		    while (*pf != NUL && *pf != word[i + k])
7341 			++pf;
7342 		    if (*pf == NUL)
7343 			continue;
7344 		    ++k;
7345 		}
7346 		s = smp[n].sm_rules;
7347 		pri = 5;    /* default priority */
7348 
7349 		p0 = *s;
7350 		k0 = k;
7351 		while (*s == '-' && k > 1)
7352 		{
7353 		    k--;
7354 		    s++;
7355 		}
7356 		if (*s == '<')
7357 		    s++;
7358 		if (VIM_ISDIGIT(*s))
7359 		{
7360 		    /* determine priority */
7361 		    pri = *s - '0';
7362 		    s++;
7363 		}
7364 		if (*s == '^' && *(s + 1) == '^')
7365 		    s++;
7366 
7367 		if (*s == NUL
7368 			|| (*s == '^'
7369 			    && (i == 0 || !(word[i - 1] == ' '
7370 				    || spell_iswordp_w(word + i - 1, curwin)))
7371 			    && (*(s + 1) != '$'
7372 				|| (!spell_iswordp_w(word + i + k0, curwin))))
7373 			|| (*s == '$' && i > 0
7374 			    && spell_iswordp_w(word + i - 1, curwin)
7375 			    && (!spell_iswordp_w(word + i + k0, curwin))))
7376 		{
7377 		    /* search for followup rules, if:    */
7378 		    /* followup and k > 1  and  NO '-' in searchstring */
7379 		    c0 = word[i + k - 1];
7380 		    n0 = slang->sl_sal_first[c0 & 0xff];
7381 
7382 		    if (slang->sl_followup && k > 1 && n0 >= 0
7383 					   && p0 != '-' && word[i + k] != NUL)
7384 		    {
7385 			/* Test follow-up rule for "word[i + k]"; loop over
7386 			 * all entries with the same index byte. */
7387 			for ( ; ((ws = smp[n0].sm_lead_w)[0] & 0xff)
7388 							 == (c0 & 0xff); ++n0)
7389 			{
7390 			    /* Quickly skip entries that don't match the word.
7391 			     */
7392 			    if (c0 != ws[0])
7393 				continue;
7394 			    k0 = smp[n0].sm_leadlen;
7395 			    if (k0 > 1)
7396 			    {
7397 				if (word[i + k] != ws[1])
7398 				    continue;
7399 				if (k0 > 2)
7400 				{
7401 				    pf = word + i + k + 1;
7402 				    for (j = 2; j < k0; ++j)
7403 					if (*pf++ != ws[j])
7404 					    break;
7405 				    if (j < k0)
7406 					continue;
7407 				}
7408 			    }
7409 			    k0 += k - 1;
7410 
7411 			    if ((pf = smp[n0].sm_oneof_w) != NULL)
7412 			    {
7413 				/* Check for match with one of the chars in
7414 				 * "sm_oneof". */
7415 				while (*pf != NUL && *pf != word[i + k0])
7416 				    ++pf;
7417 				if (*pf == NUL)
7418 				    continue;
7419 				++k0;
7420 			    }
7421 
7422 			    p0 = 5;
7423 			    s = smp[n0].sm_rules;
7424 			    while (*s == '-')
7425 			    {
7426 				/* "k0" gets NOT reduced because
7427 				 * "if (k0 == k)" */
7428 				s++;
7429 			    }
7430 			    if (*s == '<')
7431 				s++;
7432 			    if (VIM_ISDIGIT(*s))
7433 			    {
7434 				p0 = *s - '0';
7435 				s++;
7436 			    }
7437 
7438 			    if (*s == NUL
7439 				    /* *s == '^' cuts */
7440 				    || (*s == '$'
7441 					 && !spell_iswordp_w(word + i + k0,
7442 								     curwin)))
7443 			    {
7444 				if (k0 == k)
7445 				    /* this is just a piece of the string */
7446 				    continue;
7447 
7448 				if (p0 < pri)
7449 				    /* priority too low */
7450 				    continue;
7451 				/* rule fits; stop search */
7452 				break;
7453 			    }
7454 			}
7455 
7456 			if (p0 >= pri && (smp[n0].sm_lead_w[0] & 0xff)
7457 							       == (c0 & 0xff))
7458 			    continue;
7459 		    }
7460 
7461 		    /* replace string */
7462 		    ws = smp[n].sm_to_w;
7463 		    s = smp[n].sm_rules;
7464 		    p0 = (vim_strchr(s, '<') != NULL) ? 1 : 0;
7465 		    if (p0 == 1 && z == 0)
7466 		    {
7467 			/* rule with '<' is used */
7468 			if (reslen > 0 && ws != NULL && *ws != NUL
7469 				&& (wres[reslen - 1] == c
7470 						    || wres[reslen - 1] == *ws))
7471 			    reslen--;
7472 			z0 = 1;
7473 			z = 1;
7474 			k0 = 0;
7475 			if (ws != NULL)
7476 			    while (*ws != NUL && word[i + k0] != NUL)
7477 			    {
7478 				word[i + k0] = *ws;
7479 				k0++;
7480 				ws++;
7481 			    }
7482 			if (k > k0)
7483 			    mch_memmove(word + i + k0, word + i + k,
7484 				    sizeof(int) * (wordlen - (i + k) + 1));
7485 
7486 			/* new "actual letter" */
7487 			c = word[i];
7488 		    }
7489 		    else
7490 		    {
7491 			/* no '<' rule used */
7492 			i += k - 1;
7493 			z = 0;
7494 			if (ws != NULL)
7495 			    while (*ws != NUL && ws[1] != NUL
7496 							  && reslen < MAXWLEN)
7497 			    {
7498 				if (reslen == 0 || wres[reslen - 1] != *ws)
7499 				    wres[reslen++] = *ws;
7500 				ws++;
7501 			    }
7502 			/* new "actual letter" */
7503 			if (ws == NULL)
7504 			    c = NUL;
7505 			else
7506 			    c = *ws;
7507 			if (strstr((char *)s, "^^") != NULL)
7508 			{
7509 			    if (c != NUL)
7510 				wres[reslen++] = c;
7511 			    mch_memmove(word, word + i + 1,
7512 				       sizeof(int) * (wordlen - (i + 1) + 1));
7513 			    i = 0;
7514 			    z0 = 1;
7515 			}
7516 		    }
7517 		    break;
7518 		}
7519 	    }
7520 	}
7521 	else if (VIM_ISWHITE(c))
7522 	{
7523 	    c = ' ';
7524 	    k = 1;
7525 	}
7526 
7527 	if (z0 == 0)
7528 	{
7529 	    if (k && !p0 && reslen < MAXWLEN && c != NUL
7530 		    && (!slang->sl_collapse || reslen == 0
7531 						     || wres[reslen - 1] != c))
7532 		/* condense only double letters */
7533 		wres[reslen++] = c;
7534 
7535 	    i++;
7536 	    z = 0;
7537 	    k = 0;
7538 	}
7539     }
7540 
7541     /* Convert wide characters in "wres" to a multi-byte string in "res". */
7542     l = 0;
7543     for (n = 0; n < reslen; ++n)
7544     {
7545 	l += mb_char2bytes(wres[n], res + l);
7546 	if (l + MB_MAXBYTES > MAXWLEN)
7547 	    break;
7548     }
7549     res[l] = NUL;
7550 }
7551 
7552 /*
7553  * Compute a score for two sound-a-like words.
7554  * This permits up to two inserts/deletes/swaps/etc. to keep things fast.
7555  * Instead of a generic loop we write out the code.  That keeps it fast by
7556  * avoiding checks that will not be possible.
7557  */
7558     static int
7559 soundalike_score(
7560     char_u	*goodstart,	/* sound-folded good word */
7561     char_u	*badstart)	/* sound-folded bad word */
7562 {
7563     char_u	*goodsound = goodstart;
7564     char_u	*badsound = badstart;
7565     int		goodlen;
7566     int		badlen;
7567     int		n;
7568     char_u	*pl, *ps;
7569     char_u	*pl2, *ps2;
7570     int		score = 0;
7571 
7572     /* Adding/inserting "*" at the start (word starts with vowel) shouldn't be
7573      * counted so much, vowels halfway the word aren't counted at all. */
7574     if ((*badsound == '*' || *goodsound == '*') && *badsound != *goodsound)
7575     {
7576 	if ((badsound[0] == NUL && goodsound[1] == NUL)
7577 	    || (goodsound[0] == NUL && badsound[1] == NUL))
7578 	    /* changing word with vowel to word without a sound */
7579 	    return SCORE_DEL;
7580 	if (badsound[0] == NUL || goodsound[0] == NUL)
7581 	    /* more than two changes */
7582 	    return SCORE_MAXMAX;
7583 
7584 	if (badsound[1] == goodsound[1]
7585 		|| (badsound[1] != NUL
7586 		    && goodsound[1] != NUL
7587 		    && badsound[2] == goodsound[2]))
7588 	{
7589 	    /* handle like a substitute */
7590 	}
7591 	else
7592 	{
7593 	    score = 2 * SCORE_DEL / 3;
7594 	    if (*badsound == '*')
7595 		++badsound;
7596 	    else
7597 		++goodsound;
7598 	}
7599     }
7600 
7601     goodlen = (int)STRLEN(goodsound);
7602     badlen = (int)STRLEN(badsound);
7603 
7604     /* Return quickly if the lengths are too different to be fixed by two
7605      * changes. */
7606     n = goodlen - badlen;
7607     if (n < -2 || n > 2)
7608 	return SCORE_MAXMAX;
7609 
7610     if (n > 0)
7611     {
7612 	pl = goodsound;	    /* goodsound is longest */
7613 	ps = badsound;
7614     }
7615     else
7616     {
7617 	pl = badsound;	    /* badsound is longest */
7618 	ps = goodsound;
7619     }
7620 
7621     /* Skip over the identical part. */
7622     while (*pl == *ps && *pl != NUL)
7623     {
7624 	++pl;
7625 	++ps;
7626     }
7627 
7628     switch (n)
7629     {
7630 	case -2:
7631 	case 2:
7632 	    /*
7633 	     * Must delete two characters from "pl".
7634 	     */
7635 	    ++pl;	/* first delete */
7636 	    while (*pl == *ps)
7637 	    {
7638 		++pl;
7639 		++ps;
7640 	    }
7641 	    /* strings must be equal after second delete */
7642 	    if (STRCMP(pl + 1, ps) == 0)
7643 		return score + SCORE_DEL * 2;
7644 
7645 	    /* Failed to compare. */
7646 	    break;
7647 
7648 	case -1:
7649 	case 1:
7650 	    /*
7651 	     * Minimal one delete from "pl" required.
7652 	     */
7653 
7654 	    /* 1: delete */
7655 	    pl2 = pl + 1;
7656 	    ps2 = ps;
7657 	    while (*pl2 == *ps2)
7658 	    {
7659 		if (*pl2 == NUL)	/* reached the end */
7660 		    return score + SCORE_DEL;
7661 		++pl2;
7662 		++ps2;
7663 	    }
7664 
7665 	    /* 2: delete then swap, then rest must be equal */
7666 	    if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
7667 					     && STRCMP(pl2 + 2, ps2 + 2) == 0)
7668 		return score + SCORE_DEL + SCORE_SWAP;
7669 
7670 	    /* 3: delete then substitute, then the rest must be equal */
7671 	    if (STRCMP(pl2 + 1, ps2 + 1) == 0)
7672 		return score + SCORE_DEL + SCORE_SUBST;
7673 
7674 	    /* 4: first swap then delete */
7675 	    if (pl[0] == ps[1] && pl[1] == ps[0])
7676 	    {
7677 		pl2 = pl + 2;	    /* swap, skip two chars */
7678 		ps2 = ps + 2;
7679 		while (*pl2 == *ps2)
7680 		{
7681 		    ++pl2;
7682 		    ++ps2;
7683 		}
7684 		/* delete a char and then strings must be equal */
7685 		if (STRCMP(pl2 + 1, ps2) == 0)
7686 		    return score + SCORE_SWAP + SCORE_DEL;
7687 	    }
7688 
7689 	    /* 5: first substitute then delete */
7690 	    pl2 = pl + 1;	    /* substitute, skip one char */
7691 	    ps2 = ps + 1;
7692 	    while (*pl2 == *ps2)
7693 	    {
7694 		++pl2;
7695 		++ps2;
7696 	    }
7697 	    /* delete a char and then strings must be equal */
7698 	    if (STRCMP(pl2 + 1, ps2) == 0)
7699 		return score + SCORE_SUBST + SCORE_DEL;
7700 
7701 	    /* Failed to compare. */
7702 	    break;
7703 
7704 	case 0:
7705 	    /*
7706 	     * Lengths are equal, thus changes must result in same length: An
7707 	     * insert is only possible in combination with a delete.
7708 	     * 1: check if for identical strings
7709 	     */
7710 	    if (*pl == NUL)
7711 		return score;
7712 
7713 	    /* 2: swap */
7714 	    if (pl[0] == ps[1] && pl[1] == ps[0])
7715 	    {
7716 		pl2 = pl + 2;	    /* swap, skip two chars */
7717 		ps2 = ps + 2;
7718 		while (*pl2 == *ps2)
7719 		{
7720 		    if (*pl2 == NUL)	/* reached the end */
7721 			return score + SCORE_SWAP;
7722 		    ++pl2;
7723 		    ++ps2;
7724 		}
7725 		/* 3: swap and swap again */
7726 		if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
7727 					     && STRCMP(pl2 + 2, ps2 + 2) == 0)
7728 		    return score + SCORE_SWAP + SCORE_SWAP;
7729 
7730 		/* 4: swap and substitute */
7731 		if (STRCMP(pl2 + 1, ps2 + 1) == 0)
7732 		    return score + SCORE_SWAP + SCORE_SUBST;
7733 	    }
7734 
7735 	    /* 5: substitute */
7736 	    pl2 = pl + 1;
7737 	    ps2 = ps + 1;
7738 	    while (*pl2 == *ps2)
7739 	    {
7740 		if (*pl2 == NUL)	/* reached the end */
7741 		    return score + SCORE_SUBST;
7742 		++pl2;
7743 		++ps2;
7744 	    }
7745 
7746 	    /* 6: substitute and swap */
7747 	    if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
7748 					     && STRCMP(pl2 + 2, ps2 + 2) == 0)
7749 		return score + SCORE_SUBST + SCORE_SWAP;
7750 
7751 	    /* 7: substitute and substitute */
7752 	    if (STRCMP(pl2 + 1, ps2 + 1) == 0)
7753 		return score + SCORE_SUBST + SCORE_SUBST;
7754 
7755 	    /* 8: insert then delete */
7756 	    pl2 = pl;
7757 	    ps2 = ps + 1;
7758 	    while (*pl2 == *ps2)
7759 	    {
7760 		++pl2;
7761 		++ps2;
7762 	    }
7763 	    if (STRCMP(pl2 + 1, ps2) == 0)
7764 		return score + SCORE_INS + SCORE_DEL;
7765 
7766 	    /* 9: delete then insert */
7767 	    pl2 = pl + 1;
7768 	    ps2 = ps;
7769 	    while (*pl2 == *ps2)
7770 	    {
7771 		++pl2;
7772 		++ps2;
7773 	    }
7774 	    if (STRCMP(pl2, ps2 + 1) == 0)
7775 		return score + SCORE_INS + SCORE_DEL;
7776 
7777 	    /* Failed to compare. */
7778 	    break;
7779     }
7780 
7781     return SCORE_MAXMAX;
7782 }
7783 
7784 /*
7785  * Compute the "edit distance" to turn "badword" into "goodword".  The less
7786  * deletes/inserts/substitutes/swaps are required the lower the score.
7787  *
7788  * The algorithm is described by Du and Chang, 1992.
7789  * The implementation of the algorithm comes from Aspell editdist.cpp,
7790  * edit_distance().  It has been converted from C++ to C and modified to
7791  * support multi-byte characters.
7792  */
7793     static int
7794 spell_edit_score(
7795     slang_T	*slang,
7796     char_u	*badword,
7797     char_u	*goodword)
7798 {
7799     int		*cnt;
7800     int		badlen, goodlen;	/* lengths including NUL */
7801     int		j, i;
7802     int		t;
7803     int		bc, gc;
7804     int		pbc, pgc;
7805     char_u	*p;
7806     int		wbadword[MAXWLEN];
7807     int		wgoodword[MAXWLEN];
7808 
7809     if (has_mbyte)
7810     {
7811 	/* Get the characters from the multi-byte strings and put them in an
7812 	 * int array for easy access. */
7813 	for (p = badword, badlen = 0; *p != NUL; )
7814 	    wbadword[badlen++] = mb_cptr2char_adv(&p);
7815 	wbadword[badlen++] = 0;
7816 	for (p = goodword, goodlen = 0; *p != NUL; )
7817 	    wgoodword[goodlen++] = mb_cptr2char_adv(&p);
7818 	wgoodword[goodlen++] = 0;
7819     }
7820     else
7821     {
7822 	badlen = (int)STRLEN(badword) + 1;
7823 	goodlen = (int)STRLEN(goodword) + 1;
7824     }
7825 
7826     /* We use "cnt" as an array: CNT(badword_idx, goodword_idx). */
7827 #define CNT(a, b)   cnt[(a) + (b) * (badlen + 1)]
7828     cnt = (int *)lalloc((long_u)(sizeof(int) * (badlen + 1) * (goodlen + 1)),
7829 									TRUE);
7830     if (cnt == NULL)
7831 	return 0;	/* out of memory */
7832 
7833     CNT(0, 0) = 0;
7834     for (j = 1; j <= goodlen; ++j)
7835 	CNT(0, j) = CNT(0, j - 1) + SCORE_INS;
7836 
7837     for (i = 1; i <= badlen; ++i)
7838     {
7839 	CNT(i, 0) = CNT(i - 1, 0) + SCORE_DEL;
7840 	for (j = 1; j <= goodlen; ++j)
7841 	{
7842 	    if (has_mbyte)
7843 	    {
7844 		bc = wbadword[i - 1];
7845 		gc = wgoodword[j - 1];
7846 	    }
7847 	    else
7848 	    {
7849 		bc = badword[i - 1];
7850 		gc = goodword[j - 1];
7851 	    }
7852 	    if (bc == gc)
7853 		CNT(i, j) = CNT(i - 1, j - 1);
7854 	    else
7855 	    {
7856 		/* Use a better score when there is only a case difference. */
7857 		if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
7858 		    CNT(i, j) = SCORE_ICASE + CNT(i - 1, j - 1);
7859 		else
7860 		{
7861 		    /* For a similar character use SCORE_SIMILAR. */
7862 		    if (slang != NULL
7863 			    && slang->sl_has_map
7864 			    && similar_chars(slang, gc, bc))
7865 			CNT(i, j) = SCORE_SIMILAR + CNT(i - 1, j - 1);
7866 		    else
7867 			CNT(i, j) = SCORE_SUBST + CNT(i - 1, j - 1);
7868 		}
7869 
7870 		if (i > 1 && j > 1)
7871 		{
7872 		    if (has_mbyte)
7873 		    {
7874 			pbc = wbadword[i - 2];
7875 			pgc = wgoodword[j - 2];
7876 		    }
7877 		    else
7878 		    {
7879 			pbc = badword[i - 2];
7880 			pgc = goodword[j - 2];
7881 		    }
7882 		    if (bc == pgc && pbc == gc)
7883 		    {
7884 			t = SCORE_SWAP + CNT(i - 2, j - 2);
7885 			if (t < CNT(i, j))
7886 			    CNT(i, j) = t;
7887 		    }
7888 		}
7889 		t = SCORE_DEL + CNT(i - 1, j);
7890 		if (t < CNT(i, j))
7891 		    CNT(i, j) = t;
7892 		t = SCORE_INS + CNT(i, j - 1);
7893 		if (t < CNT(i, j))
7894 		    CNT(i, j) = t;
7895 	    }
7896 	}
7897     }
7898 
7899     i = CNT(badlen - 1, goodlen - 1);
7900     vim_free(cnt);
7901     return i;
7902 }
7903 
7904 typedef struct
7905 {
7906     int		badi;
7907     int		goodi;
7908     int		score;
7909 } limitscore_T;
7910 
7911 /*
7912  * Like spell_edit_score(), but with a limit on the score to make it faster.
7913  * May return SCORE_MAXMAX when the score is higher than "limit".
7914  *
7915  * This uses a stack for the edits still to be tried.
7916  * The idea comes from Aspell leditdist.cpp.  Rewritten in C and added support
7917  * for multi-byte characters.
7918  */
7919     static int
7920 spell_edit_score_limit(
7921     slang_T	*slang,
7922     char_u	*badword,
7923     char_u	*goodword,
7924     int		limit)
7925 {
7926     limitscore_T    stack[10];		/* allow for over 3 * 2 edits */
7927     int		    stackidx;
7928     int		    bi, gi;
7929     int		    bi2, gi2;
7930     int		    bc, gc;
7931     int		    score;
7932     int		    score_off;
7933     int		    minscore;
7934     int		    round;
7935 
7936     /* Multi-byte characters require a bit more work, use a different function
7937      * to avoid testing "has_mbyte" quite often. */
7938     if (has_mbyte)
7939 	return spell_edit_score_limit_w(slang, badword, goodword, limit);
7940 
7941     /*
7942      * The idea is to go from start to end over the words.  So long as
7943      * characters are equal just continue, this always gives the lowest score.
7944      * When there is a difference try several alternatives.  Each alternative
7945      * increases "score" for the edit distance.  Some of the alternatives are
7946      * pushed unto a stack and tried later, some are tried right away.  At the
7947      * end of the word the score for one alternative is known.  The lowest
7948      * possible score is stored in "minscore".
7949      */
7950     stackidx = 0;
7951     bi = 0;
7952     gi = 0;
7953     score = 0;
7954     minscore = limit + 1;
7955 
7956     for (;;)
7957     {
7958 	/* Skip over an equal part, score remains the same. */
7959 	for (;;)
7960 	{
7961 	    bc = badword[bi];
7962 	    gc = goodword[gi];
7963 	    if (bc != gc)	/* stop at a char that's different */
7964 		break;
7965 	    if (bc == NUL)	/* both words end */
7966 	    {
7967 		if (score < minscore)
7968 		    minscore = score;
7969 		goto pop;	/* do next alternative */
7970 	    }
7971 	    ++bi;
7972 	    ++gi;
7973 	}
7974 
7975 	if (gc == NUL)    /* goodword ends, delete badword chars */
7976 	{
7977 	    do
7978 	    {
7979 		if ((score += SCORE_DEL) >= minscore)
7980 		    goto pop;	    /* do next alternative */
7981 	    } while (badword[++bi] != NUL);
7982 	    minscore = score;
7983 	}
7984 	else if (bc == NUL) /* badword ends, insert badword chars */
7985 	{
7986 	    do
7987 	    {
7988 		if ((score += SCORE_INS) >= minscore)
7989 		    goto pop;	    /* do next alternative */
7990 	    } while (goodword[++gi] != NUL);
7991 	    minscore = score;
7992 	}
7993 	else			/* both words continue */
7994 	{
7995 	    /* If not close to the limit, perform a change.  Only try changes
7996 	     * that may lead to a lower score than "minscore".
7997 	     * round 0: try deleting a char from badword
7998 	     * round 1: try inserting a char in badword */
7999 	    for (round = 0; round <= 1; ++round)
8000 	    {
8001 		score_off = score + (round == 0 ? SCORE_DEL : SCORE_INS);
8002 		if (score_off < minscore)
8003 		{
8004 		    if (score_off + SCORE_EDIT_MIN >= minscore)
8005 		    {
8006 			/* Near the limit, rest of the words must match.  We
8007 			 * can check that right now, no need to push an item
8008 			 * onto the stack. */
8009 			bi2 = bi + 1 - round;
8010 			gi2 = gi + round;
8011 			while (goodword[gi2] == badword[bi2])
8012 			{
8013 			    if (goodword[gi2] == NUL)
8014 			    {
8015 				minscore = score_off;
8016 				break;
8017 			    }
8018 			    ++bi2;
8019 			    ++gi2;
8020 			}
8021 		    }
8022 		    else
8023 		    {
8024 			/* try deleting/inserting a character later */
8025 			stack[stackidx].badi = bi + 1 - round;
8026 			stack[stackidx].goodi = gi + round;
8027 			stack[stackidx].score = score_off;
8028 			++stackidx;
8029 		    }
8030 		}
8031 	    }
8032 
8033 	    if (score + SCORE_SWAP < minscore)
8034 	    {
8035 		/* If swapping two characters makes a match then the
8036 		 * substitution is more expensive, thus there is no need to
8037 		 * try both. */
8038 		if (gc == badword[bi + 1] && bc == goodword[gi + 1])
8039 		{
8040 		    /* Swap two characters, that is: skip them. */
8041 		    gi += 2;
8042 		    bi += 2;
8043 		    score += SCORE_SWAP;
8044 		    continue;
8045 		}
8046 	    }
8047 
8048 	    /* Substitute one character for another which is the same
8049 	     * thing as deleting a character from both goodword and badword.
8050 	     * Use a better score when there is only a case difference. */
8051 	    if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
8052 		score += SCORE_ICASE;
8053 	    else
8054 	    {
8055 		/* For a similar character use SCORE_SIMILAR. */
8056 		if (slang != NULL
8057 			&& slang->sl_has_map
8058 			&& similar_chars(slang, gc, bc))
8059 		    score += SCORE_SIMILAR;
8060 		else
8061 		    score += SCORE_SUBST;
8062 	    }
8063 
8064 	    if (score < minscore)
8065 	    {
8066 		/* Do the substitution. */
8067 		++gi;
8068 		++bi;
8069 		continue;
8070 	    }
8071 	}
8072 pop:
8073 	/*
8074 	 * Get here to try the next alternative, pop it from the stack.
8075 	 */
8076 	if (stackidx == 0)		/* stack is empty, finished */
8077 	    break;
8078 
8079 	/* pop an item from the stack */
8080 	--stackidx;
8081 	gi = stack[stackidx].goodi;
8082 	bi = stack[stackidx].badi;
8083 	score = stack[stackidx].score;
8084     }
8085 
8086     /* When the score goes over "limit" it may actually be much higher.
8087      * Return a very large number to avoid going below the limit when giving a
8088      * bonus. */
8089     if (minscore > limit)
8090 	return SCORE_MAXMAX;
8091     return minscore;
8092 }
8093 
8094 /*
8095  * Multi-byte version of spell_edit_score_limit().
8096  * Keep it in sync with the above!
8097  */
8098     static int
8099 spell_edit_score_limit_w(
8100     slang_T	*slang,
8101     char_u	*badword,
8102     char_u	*goodword,
8103     int		limit)
8104 {
8105     limitscore_T    stack[10];		/* allow for over 3 * 2 edits */
8106     int		    stackidx;
8107     int		    bi, gi;
8108     int		    bi2, gi2;
8109     int		    bc, gc;
8110     int		    score;
8111     int		    score_off;
8112     int		    minscore;
8113     int		    round;
8114     char_u	    *p;
8115     int		    wbadword[MAXWLEN];
8116     int		    wgoodword[MAXWLEN];
8117 
8118     /* Get the characters from the multi-byte strings and put them in an
8119      * int array for easy access. */
8120     bi = 0;
8121     for (p = badword; *p != NUL; )
8122 	wbadword[bi++] = mb_cptr2char_adv(&p);
8123     wbadword[bi++] = 0;
8124     gi = 0;
8125     for (p = goodword; *p != NUL; )
8126 	wgoodword[gi++] = mb_cptr2char_adv(&p);
8127     wgoodword[gi++] = 0;
8128 
8129     /*
8130      * The idea is to go from start to end over the words.  So long as
8131      * characters are equal just continue, this always gives the lowest score.
8132      * When there is a difference try several alternatives.  Each alternative
8133      * increases "score" for the edit distance.  Some of the alternatives are
8134      * pushed unto a stack and tried later, some are tried right away.  At the
8135      * end of the word the score for one alternative is known.  The lowest
8136      * possible score is stored in "minscore".
8137      */
8138     stackidx = 0;
8139     bi = 0;
8140     gi = 0;
8141     score = 0;
8142     minscore = limit + 1;
8143 
8144     for (;;)
8145     {
8146 	/* Skip over an equal part, score remains the same. */
8147 	for (;;)
8148 	{
8149 	    bc = wbadword[bi];
8150 	    gc = wgoodword[gi];
8151 
8152 	    if (bc != gc)	/* stop at a char that's different */
8153 		break;
8154 	    if (bc == NUL)	/* both words end */
8155 	    {
8156 		if (score < minscore)
8157 		    minscore = score;
8158 		goto pop;	/* do next alternative */
8159 	    }
8160 	    ++bi;
8161 	    ++gi;
8162 	}
8163 
8164 	if (gc == NUL)    /* goodword ends, delete badword chars */
8165 	{
8166 	    do
8167 	    {
8168 		if ((score += SCORE_DEL) >= minscore)
8169 		    goto pop;	    /* do next alternative */
8170 	    } while (wbadword[++bi] != NUL);
8171 	    minscore = score;
8172 	}
8173 	else if (bc == NUL) /* badword ends, insert badword chars */
8174 	{
8175 	    do
8176 	    {
8177 		if ((score += SCORE_INS) >= minscore)
8178 		    goto pop;	    /* do next alternative */
8179 	    } while (wgoodword[++gi] != NUL);
8180 	    minscore = score;
8181 	}
8182 	else			/* both words continue */
8183 	{
8184 	    /* If not close to the limit, perform a change.  Only try changes
8185 	     * that may lead to a lower score than "minscore".
8186 	     * round 0: try deleting a char from badword
8187 	     * round 1: try inserting a char in badword */
8188 	    for (round = 0; round <= 1; ++round)
8189 	    {
8190 		score_off = score + (round == 0 ? SCORE_DEL : SCORE_INS);
8191 		if (score_off < minscore)
8192 		{
8193 		    if (score_off + SCORE_EDIT_MIN >= minscore)
8194 		    {
8195 			/* Near the limit, rest of the words must match.  We
8196 			 * can check that right now, no need to push an item
8197 			 * onto the stack. */
8198 			bi2 = bi + 1 - round;
8199 			gi2 = gi + round;
8200 			while (wgoodword[gi2] == wbadword[bi2])
8201 			{
8202 			    if (wgoodword[gi2] == NUL)
8203 			    {
8204 				minscore = score_off;
8205 				break;
8206 			    }
8207 			    ++bi2;
8208 			    ++gi2;
8209 			}
8210 		    }
8211 		    else
8212 		    {
8213 			/* try deleting a character from badword later */
8214 			stack[stackidx].badi = bi + 1 - round;
8215 			stack[stackidx].goodi = gi + round;
8216 			stack[stackidx].score = score_off;
8217 			++stackidx;
8218 		    }
8219 		}
8220 	    }
8221 
8222 	    if (score + SCORE_SWAP < minscore)
8223 	    {
8224 		/* If swapping two characters makes a match then the
8225 		 * substitution is more expensive, thus there is no need to
8226 		 * try both. */
8227 		if (gc == wbadword[bi + 1] && bc == wgoodword[gi + 1])
8228 		{
8229 		    /* Swap two characters, that is: skip them. */
8230 		    gi += 2;
8231 		    bi += 2;
8232 		    score += SCORE_SWAP;
8233 		    continue;
8234 		}
8235 	    }
8236 
8237 	    /* Substitute one character for another which is the same
8238 	     * thing as deleting a character from both goodword and badword.
8239 	     * Use a better score when there is only a case difference. */
8240 	    if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
8241 		score += SCORE_ICASE;
8242 	    else
8243 	    {
8244 		/* For a similar character use SCORE_SIMILAR. */
8245 		if (slang != NULL
8246 			&& slang->sl_has_map
8247 			&& similar_chars(slang, gc, bc))
8248 		    score += SCORE_SIMILAR;
8249 		else
8250 		    score += SCORE_SUBST;
8251 	    }
8252 
8253 	    if (score < minscore)
8254 	    {
8255 		/* Do the substitution. */
8256 		++gi;
8257 		++bi;
8258 		continue;
8259 	    }
8260 	}
8261 pop:
8262 	/*
8263 	 * Get here to try the next alternative, pop it from the stack.
8264 	 */
8265 	if (stackidx == 0)		/* stack is empty, finished */
8266 	    break;
8267 
8268 	/* pop an item from the stack */
8269 	--stackidx;
8270 	gi = stack[stackidx].goodi;
8271 	bi = stack[stackidx].badi;
8272 	score = stack[stackidx].score;
8273     }
8274 
8275     /* When the score goes over "limit" it may actually be much higher.
8276      * Return a very large number to avoid going below the limit when giving a
8277      * bonus. */
8278     if (minscore > limit)
8279 	return SCORE_MAXMAX;
8280     return minscore;
8281 }
8282 
8283 /*
8284  * ":spellinfo"
8285  */
8286     void
8287 ex_spellinfo(exarg_T *eap UNUSED)
8288 {
8289     int		lpi;
8290     langp_T	*lp;
8291     char_u	*p;
8292 
8293     if (no_spell_checking(curwin))
8294 	return;
8295 
8296     msg_start();
8297     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len && !got_int; ++lpi)
8298     {
8299 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
8300 	msg_puts("file: ");
8301 	msg_puts((char *)lp->lp_slang->sl_fname);
8302 	msg_putchar('\n');
8303 	p = lp->lp_slang->sl_info;
8304 	if (p != NULL)
8305 	{
8306 	    msg_puts((char *)p);
8307 	    msg_putchar('\n');
8308 	}
8309     }
8310     msg_end();
8311 }
8312 
8313 #define DUMPFLAG_KEEPCASE   1	/* round 2: keep-case tree */
8314 #define DUMPFLAG_COUNT	    2	/* include word count */
8315 #define DUMPFLAG_ICASE	    4	/* ignore case when finding matches */
8316 #define DUMPFLAG_ONECAP	    8	/* pattern starts with capital */
8317 #define DUMPFLAG_ALLCAP	    16	/* pattern is all capitals */
8318 
8319 /*
8320  * ":spelldump"
8321  */
8322     void
8323 ex_spelldump(exarg_T *eap)
8324 {
8325     char_u  *spl;
8326     long    dummy;
8327 
8328     if (no_spell_checking(curwin))
8329 	return;
8330     get_option_value((char_u*)"spl", &dummy, &spl, OPT_LOCAL);
8331 
8332     /* Create a new empty buffer in a new window. */
8333     do_cmdline_cmd((char_u *)"new");
8334 
8335     /* enable spelling locally in the new window */
8336     set_option_value((char_u*)"spell", TRUE, (char_u*)"", OPT_LOCAL);
8337     set_option_value((char_u*)"spl",  dummy, spl, OPT_LOCAL);
8338     vim_free(spl);
8339 
8340     if (!BUFEMPTY())
8341 	return;
8342 
8343     spell_dump_compl(NULL, 0, NULL, eap->forceit ? DUMPFLAG_COUNT : 0);
8344 
8345     /* Delete the empty line that we started with. */
8346     if (curbuf->b_ml.ml_line_count > 1)
8347 	ml_delete(curbuf->b_ml.ml_line_count, FALSE);
8348 
8349     redraw_later(NOT_VALID);
8350 }
8351 
8352 /*
8353  * Go through all possible words and:
8354  * 1. When "pat" is NULL: dump a list of all words in the current buffer.
8355  *	"ic" and "dir" are not used.
8356  * 2. When "pat" is not NULL: add matching words to insert mode completion.
8357  */
8358     void
8359 spell_dump_compl(
8360     char_u	*pat,	    /* leading part of the word */
8361     int		ic,	    /* ignore case */
8362     int		*dir,	    /* direction for adding matches */
8363     int		dumpflags_arg)	/* DUMPFLAG_* */
8364 {
8365     langp_T	*lp;
8366     slang_T	*slang;
8367     idx_T	arridx[MAXWLEN];
8368     int		curi[MAXWLEN];
8369     char_u	word[MAXWLEN];
8370     int		c;
8371     char_u	*byts;
8372     idx_T	*idxs;
8373     linenr_T	lnum = 0;
8374     int		round;
8375     int		depth;
8376     int		n;
8377     int		flags;
8378     char_u	*region_names = NULL;	    /* region names being used */
8379     int		do_region = TRUE;	    /* dump region names and numbers */
8380     char_u	*p;
8381     int		lpi;
8382     int		dumpflags = dumpflags_arg;
8383     int		patlen;
8384 
8385     /* When ignoring case or when the pattern starts with capital pass this on
8386      * to dump_word(). */
8387     if (pat != NULL)
8388     {
8389 	if (ic)
8390 	    dumpflags |= DUMPFLAG_ICASE;
8391 	else
8392 	{
8393 	    n = captype(pat, NULL);
8394 	    if (n == WF_ONECAP)
8395 		dumpflags |= DUMPFLAG_ONECAP;
8396 	    else if (n == WF_ALLCAP && (int)STRLEN(pat) > mb_ptr2len(pat))
8397 		dumpflags |= DUMPFLAG_ALLCAP;
8398 	}
8399     }
8400 
8401     /* Find out if we can support regions: All languages must support the same
8402      * regions or none at all. */
8403     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
8404     {
8405 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
8406 	p = lp->lp_slang->sl_regions;
8407 	if (p[0] != 0)
8408 	{
8409 	    if (region_names == NULL)	    /* first language with regions */
8410 		region_names = p;
8411 	    else if (STRCMP(region_names, p) != 0)
8412 	    {
8413 		do_region = FALSE;	    /* region names are different */
8414 		break;
8415 	    }
8416 	}
8417     }
8418 
8419     if (do_region && region_names != NULL)
8420     {
8421 	if (pat == NULL)
8422 	{
8423 	    vim_snprintf((char *)IObuff, IOSIZE, "/regions=%s", region_names);
8424 	    ml_append(lnum++, IObuff, (colnr_T)0, FALSE);
8425 	}
8426     }
8427     else
8428 	do_region = FALSE;
8429 
8430     /*
8431      * Loop over all files loaded for the entries in 'spelllang'.
8432      */
8433     for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi)
8434     {
8435 	lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
8436 	slang = lp->lp_slang;
8437 	if (slang->sl_fbyts == NULL)	    /* reloading failed */
8438 	    continue;
8439 
8440 	if (pat == NULL)
8441 	{
8442 	    vim_snprintf((char *)IObuff, IOSIZE, "# file: %s", slang->sl_fname);
8443 	    ml_append(lnum++, IObuff, (colnr_T)0, FALSE);
8444 	}
8445 
8446 	/* When matching with a pattern and there are no prefixes only use
8447 	 * parts of the tree that match "pat". */
8448 	if (pat != NULL && slang->sl_pbyts == NULL)
8449 	    patlen = (int)STRLEN(pat);
8450 	else
8451 	    patlen = -1;
8452 
8453 	/* round 1: case-folded tree
8454 	 * round 2: keep-case tree */
8455 	for (round = 1; round <= 2; ++round)
8456 	{
8457 	    if (round == 1)
8458 	    {
8459 		dumpflags &= ~DUMPFLAG_KEEPCASE;
8460 		byts = slang->sl_fbyts;
8461 		idxs = slang->sl_fidxs;
8462 	    }
8463 	    else
8464 	    {
8465 		dumpflags |= DUMPFLAG_KEEPCASE;
8466 		byts = slang->sl_kbyts;
8467 		idxs = slang->sl_kidxs;
8468 	    }
8469 	    if (byts == NULL)
8470 		continue;		/* array is empty */
8471 
8472 	    depth = 0;
8473 	    arridx[0] = 0;
8474 	    curi[0] = 1;
8475 	    while (depth >= 0 && !got_int
8476 				       && (pat == NULL || !compl_interrupted))
8477 	    {
8478 		if (curi[depth] > byts[arridx[depth]])
8479 		{
8480 		    /* Done all bytes at this node, go up one level. */
8481 		    --depth;
8482 		    line_breakcheck();
8483 		    ins_compl_check_keys(50, FALSE);
8484 		}
8485 		else
8486 		{
8487 		    /* Do one more byte at this node. */
8488 		    n = arridx[depth] + curi[depth];
8489 		    ++curi[depth];
8490 		    c = byts[n];
8491 		    if (c == 0)
8492 		    {
8493 			/* End of word, deal with the word.
8494 			 * Don't use keep-case words in the fold-case tree,
8495 			 * they will appear in the keep-case tree.
8496 			 * Only use the word when the region matches. */
8497 			flags = (int)idxs[n];
8498 			if ((round == 2 || (flags & WF_KEEPCAP) == 0)
8499 				&& (flags & WF_NEEDCOMP) == 0
8500 				&& (do_region
8501 				    || (flags & WF_REGION) == 0
8502 				    || (((unsigned)flags >> 16)
8503 						       & lp->lp_region) != 0))
8504 			{
8505 			    word[depth] = NUL;
8506 			    if (!do_region)
8507 				flags &= ~WF_REGION;
8508 
8509 			    /* Dump the basic word if there is no prefix or
8510 			     * when it's the first one. */
8511 			    c = (unsigned)flags >> 24;
8512 			    if (c == 0 || curi[depth] == 2)
8513 			    {
8514 				dump_word(slang, word, pat, dir,
8515 						      dumpflags, flags, lnum);
8516 				if (pat == NULL)
8517 				    ++lnum;
8518 			    }
8519 
8520 			    /* Apply the prefix, if there is one. */
8521 			    if (c != 0)
8522 				lnum = dump_prefixes(slang, word, pat, dir,
8523 						      dumpflags, flags, lnum);
8524 			}
8525 		    }
8526 		    else
8527 		    {
8528 			/* Normal char, go one level deeper. */
8529 			word[depth++] = c;
8530 			arridx[depth] = idxs[n];
8531 			curi[depth] = 1;
8532 
8533 			/* Check if this characters matches with the pattern.
8534 			 * If not skip the whole tree below it.
8535 			 * Always ignore case here, dump_word() will check
8536 			 * proper case later.  This isn't exactly right when
8537 			 * length changes for multi-byte characters with
8538 			 * ignore case... */
8539 			if (depth <= patlen
8540 					&& MB_STRNICMP(word, pat, depth) != 0)
8541 			    --depth;
8542 		    }
8543 		}
8544 	    }
8545 	}
8546     }
8547 }
8548 
8549 /*
8550  * Dump one word: apply case modifications and append a line to the buffer.
8551  * When "lnum" is zero add insert mode completion.
8552  */
8553     static void
8554 dump_word(
8555     slang_T	*slang,
8556     char_u	*word,
8557     char_u	*pat,
8558     int		*dir,
8559     int		dumpflags,
8560     int		wordflags,
8561     linenr_T	lnum)
8562 {
8563     int		keepcap = FALSE;
8564     char_u	*p;
8565     char_u	*tw;
8566     char_u	cword[MAXWLEN];
8567     char_u	badword[MAXWLEN + 10];
8568     int		i;
8569     int		flags = wordflags;
8570 
8571     if (dumpflags & DUMPFLAG_ONECAP)
8572 	flags |= WF_ONECAP;
8573     if (dumpflags & DUMPFLAG_ALLCAP)
8574 	flags |= WF_ALLCAP;
8575 
8576     if ((dumpflags & DUMPFLAG_KEEPCASE) == 0 && (flags & WF_CAPMASK) != 0)
8577     {
8578 	/* Need to fix case according to "flags". */
8579 	make_case_word(word, cword, flags);
8580 	p = cword;
8581     }
8582     else
8583     {
8584 	p = word;
8585 	if ((dumpflags & DUMPFLAG_KEEPCASE)
8586 		&& ((captype(word, NULL) & WF_KEEPCAP) == 0
8587 						 || (flags & WF_FIXCAP) != 0))
8588 	    keepcap = TRUE;
8589     }
8590     tw = p;
8591 
8592     if (pat == NULL)
8593     {
8594 	/* Add flags and regions after a slash. */
8595 	if ((flags & (WF_BANNED | WF_RARE | WF_REGION)) || keepcap)
8596 	{
8597 	    STRCPY(badword, p);
8598 	    STRCAT(badword, "/");
8599 	    if (keepcap)
8600 		STRCAT(badword, "=");
8601 	    if (flags & WF_BANNED)
8602 		STRCAT(badword, "!");
8603 	    else if (flags & WF_RARE)
8604 		STRCAT(badword, "?");
8605 	    if (flags & WF_REGION)
8606 		for (i = 0; i < 7; ++i)
8607 		    if (flags & (0x10000 << i))
8608 			sprintf((char *)badword + STRLEN(badword), "%d", i + 1);
8609 	    p = badword;
8610 	}
8611 
8612 	if (dumpflags & DUMPFLAG_COUNT)
8613 	{
8614 	    hashitem_T  *hi;
8615 
8616 	    /* Include the word count for ":spelldump!". */
8617 	    hi = hash_find(&slang->sl_wordcount, tw);
8618 	    if (!HASHITEM_EMPTY(hi))
8619 	    {
8620 		vim_snprintf((char *)IObuff, IOSIZE, "%s\t%d",
8621 						     tw, HI2WC(hi)->wc_count);
8622 		p = IObuff;
8623 	    }
8624 	}
8625 
8626 	ml_append(lnum, p, (colnr_T)0, FALSE);
8627     }
8628     else if (((dumpflags & DUMPFLAG_ICASE)
8629 		    ? MB_STRNICMP(p, pat, STRLEN(pat)) == 0
8630 		    : STRNCMP(p, pat, STRLEN(pat)) == 0)
8631 		&& ins_compl_add_infercase(p, (int)STRLEN(p),
8632 					  p_ic, NULL, *dir, 0) == OK)
8633 	/* if dir was BACKWARD then honor it just once */
8634 	*dir = FORWARD;
8635 }
8636 
8637 /*
8638  * For ":spelldump": Find matching prefixes for "word".  Prepend each to
8639  * "word" and append a line to the buffer.
8640  * When "lnum" is zero add insert mode completion.
8641  * Return the updated line number.
8642  */
8643     static linenr_T
8644 dump_prefixes(
8645     slang_T	*slang,
8646     char_u	*word,	    /* case-folded word */
8647     char_u	*pat,
8648     int		*dir,
8649     int		dumpflags,
8650     int		flags,	    /* flags with prefix ID */
8651     linenr_T	startlnum)
8652 {
8653     idx_T	arridx[MAXWLEN];
8654     int		curi[MAXWLEN];
8655     char_u	prefix[MAXWLEN];
8656     char_u	word_up[MAXWLEN];
8657     int		has_word_up = FALSE;
8658     int		c;
8659     char_u	*byts;
8660     idx_T	*idxs;
8661     linenr_T	lnum = startlnum;
8662     int		depth;
8663     int		n;
8664     int		len;
8665     int		i;
8666 
8667     /* If the word starts with a lower-case letter make the word with an
8668      * upper-case letter in word_up[]. */
8669     c = PTR2CHAR(word);
8670     if (SPELL_TOUPPER(c) != c)
8671     {
8672 	onecap_copy(word, word_up, TRUE);
8673 	has_word_up = TRUE;
8674     }
8675 
8676     byts = slang->sl_pbyts;
8677     idxs = slang->sl_pidxs;
8678     if (byts != NULL)		/* array not is empty */
8679     {
8680 	/*
8681 	 * Loop over all prefixes, building them byte-by-byte in prefix[].
8682 	 * When at the end of a prefix check that it supports "flags".
8683 	 */
8684 	depth = 0;
8685 	arridx[0] = 0;
8686 	curi[0] = 1;
8687 	while (depth >= 0 && !got_int)
8688 	{
8689 	    n = arridx[depth];
8690 	    len = byts[n];
8691 	    if (curi[depth] > len)
8692 	    {
8693 		/* Done all bytes at this node, go up one level. */
8694 		--depth;
8695 		line_breakcheck();
8696 	    }
8697 	    else
8698 	    {
8699 		/* Do one more byte at this node. */
8700 		n += curi[depth];
8701 		++curi[depth];
8702 		c = byts[n];
8703 		if (c == 0)
8704 		{
8705 		    /* End of prefix, find out how many IDs there are. */
8706 		    for (i = 1; i < len; ++i)
8707 			if (byts[n + i] != 0)
8708 			    break;
8709 		    curi[depth] += i - 1;
8710 
8711 		    c = valid_word_prefix(i, n, flags, word, slang, FALSE);
8712 		    if (c != 0)
8713 		    {
8714 			vim_strncpy(prefix + depth, word, MAXWLEN - depth - 1);
8715 			dump_word(slang, prefix, pat, dir, dumpflags,
8716 				(c & WF_RAREPFX) ? (flags | WF_RARE)
8717 							       : flags, lnum);
8718 			if (lnum != 0)
8719 			    ++lnum;
8720 		    }
8721 
8722 		    /* Check for prefix that matches the word when the
8723 		     * first letter is upper-case, but only if the prefix has
8724 		     * a condition. */
8725 		    if (has_word_up)
8726 		    {
8727 			c = valid_word_prefix(i, n, flags, word_up, slang,
8728 									TRUE);
8729 			if (c != 0)
8730 			{
8731 			    vim_strncpy(prefix + depth, word_up,
8732 							 MAXWLEN - depth - 1);
8733 			    dump_word(slang, prefix, pat, dir, dumpflags,
8734 				    (c & WF_RAREPFX) ? (flags | WF_RARE)
8735 							       : flags, lnum);
8736 			    if (lnum != 0)
8737 				++lnum;
8738 			}
8739 		    }
8740 		}
8741 		else
8742 		{
8743 		    /* Normal char, go one level deeper. */
8744 		    prefix[depth++] = c;
8745 		    arridx[depth] = idxs[n];
8746 		    curi[depth] = 1;
8747 		}
8748 	    }
8749 	}
8750     }
8751 
8752     return lnum;
8753 }
8754 
8755 /*
8756  * Move "p" to the end of word "start".
8757  * Uses the spell-checking word characters.
8758  */
8759     char_u *
8760 spell_to_word_end(char_u *start, win_T *win)
8761 {
8762     char_u  *p = start;
8763 
8764     while (*p != NUL && spell_iswordp(p, win))
8765 	MB_PTR_ADV(p);
8766     return p;
8767 }
8768 
8769 #if defined(FEAT_INS_EXPAND) || defined(PROTO)
8770 /*
8771  * For Insert mode completion CTRL-X s:
8772  * Find start of the word in front of column "startcol".
8773  * We don't check if it is badly spelled, with completion we can only change
8774  * the word in front of the cursor.
8775  * Returns the column number of the word.
8776  */
8777     int
8778 spell_word_start(int startcol)
8779 {
8780     char_u	*line;
8781     char_u	*p;
8782     int		col = 0;
8783 
8784     if (no_spell_checking(curwin))
8785 	return startcol;
8786 
8787     /* Find a word character before "startcol". */
8788     line = ml_get_curline();
8789     for (p = line + startcol; p > line; )
8790     {
8791 	MB_PTR_BACK(line, p);
8792 	if (spell_iswordp_nmw(p, curwin))
8793 	    break;
8794     }
8795 
8796     /* Go back to start of the word. */
8797     while (p > line)
8798     {
8799 	col = (int)(p - line);
8800 	MB_PTR_BACK(line, p);
8801 	if (!spell_iswordp(p, curwin))
8802 	    break;
8803 	col = 0;
8804     }
8805 
8806     return col;
8807 }
8808 
8809 /*
8810  * Need to check for 'spellcapcheck' now, the word is removed before
8811  * expand_spelling() is called.  Therefore the ugly global variable.
8812  */
8813 static int spell_expand_need_cap;
8814 
8815     void
8816 spell_expand_check_cap(colnr_T col)
8817 {
8818     spell_expand_need_cap = check_need_cap(curwin->w_cursor.lnum, col);
8819 }
8820 
8821 /*
8822  * Get list of spelling suggestions.
8823  * Used for Insert mode completion CTRL-X ?.
8824  * Returns the number of matches.  The matches are in "matchp[]", array of
8825  * allocated strings.
8826  */
8827     int
8828 expand_spelling(
8829     linenr_T	lnum UNUSED,
8830     char_u	*pat,
8831     char_u	***matchp)
8832 {
8833     garray_T	ga;
8834 
8835     spell_suggest_list(&ga, pat, 100, spell_expand_need_cap, TRUE);
8836     *matchp = ga.ga_data;
8837     return ga.ga_len;
8838 }
8839 #endif
8840 
8841 #endif  /* FEAT_SPELL */
8842