diff options
Diffstat (limited to 'src/nvim/spell.c')
-rw-r--r-- | src/nvim/spell.c | 1007 |
1 files changed, 500 insertions, 507 deletions
diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 1e44d328b3..8e18be5bd1 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -50,7 +50,7 @@ // Use SPELL_PRINTTREE for debugging: dump the word tree after adding a word. // Only use it for small word lists! -// Use SPELL_COMPRESS_ALLWAYS for debugging: compress the word tree after +// Use SPELL_COMPRESS_ALWAYS for debugging: compress the word tree after // adding a word. Only use it for small word lists! // Use DEBUG_TRIEWALK to print the changes made in suggest_trie_walk() for a @@ -60,74 +60,84 @@ #include <inttypes.h> #include <limits.h> #include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <wctype.h> - -// for offsetof() #include <stddef.h> +#include <stdio.h> +#include <string.h> #include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cursor.h" +#include "nvim/decoration.h" +#include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" -#include "nvim/edit.h" #include "nvim/ex_cmds.h" +#include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" -#include "nvim/func_attr.h" #include "nvim/garray.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" #include "nvim/hashtab.h" -#include "nvim/input.h" +#include "nvim/highlight_defs.h" #include "nvim/insexpand.h" +#include "nvim/log.h" +#include "nvim/macros.h" #include "nvim/mark.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" -#include "nvim/normal.h" #include "nvim/option.h" +#include "nvim/os/fs.h" #include "nvim/os/input.h" -#include "nvim/os/os.h" -#include "nvim/os_unix.h" +#include "nvim/os/os_defs.h" #include "nvim/path.h" +#include "nvim/pos.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/search.h" #include "nvim/spell.h" +#include "nvim/spell_defs.h" #include "nvim/spellfile.h" #include "nvim/spellsuggest.h" #include "nvim/strings.h" #include "nvim/syntax.h" +#include "nvim/types.h" #include "nvim/undo.h" +#include "nvim/vim.h" +#include "nvim/window.h" // Result values. Lower number is accepted over higher one. -#define SP_BANNED (-1) -#define SP_RARE 0 -#define SP_OK 1 -#define SP_LOCAL 2 -#define SP_BAD 3 +enum { + SP_BANNED = -1, + SP_RARE = 0, + SP_OK = 1, + SP_LOCAL = 2, + SP_BAD = 3, +}; // First language that is loaded, start of the linked list of loaded // languages. slang_T *first_lang = NULL; // file used for "zG" and "zW" -char_u *int_wordlist = NULL; +char *int_wordlist = NULL; // Structure to store info for word matching. typedef struct matchinf_S { langp_T *mi_lp; // info for language and region // pointers to original text to be checked - char_u *mi_word; // start of word being checked - char_u *mi_end; // end of matching word so far - char_u *mi_fend; // next char to be added to mi_fword - char_u *mi_cend; // char after what was used for + char *mi_word; // start of word being checked + char *mi_end; // end of matching word so far + char *mi_fend; // next char to be added to mi_fword + char *mi_cend; // char after what was used for // mi_capflags // case-folded text - char_u mi_fword[MAXWLEN + 1]; // mi_word case-folded + char mi_fword[MAXWLEN + 1]; // mi_word case-folded int mi_fwordlen; // nr of valid bytes in mi_fword // for when checking word after a prefix @@ -150,20 +160,20 @@ typedef struct matchinf_S { win_T *mi_win; // buffer being checked // for NOBREAK - int mi_result2; // "mi_resul" without following word - char_u *mi_end2; // "mi_end" without following word + int mi_result2; // "mi_result" without following word + char *mi_end2; // "mi_end" without following word } matchinf_T; // Structure used for the cookie argument of do_in_runtimepath(). typedef struct spelload_S { - char_u sl_lang[MAXWLEN + 1]; // language name + char sl_lang[MAXWLEN + 1]; // language name slang_T *sl_slang; // resulting slang_T struct int sl_nobreak; // NOBREAK language found } spelload_T; #define SY_MAXLEN 30 typedef struct syl_item_S { - char_u sy_chars[SY_MAXLEN]; // the sequence of chars + char sy_chars[SY_MAXLEN]; // the sequence of chars int sy_len; } syl_item_T; @@ -184,8 +194,8 @@ int did_set_spelltab; char *e_format = N_("E759: Format error in spell file"); // Remember what "z?" replaced. -char_u *repl_from = NULL; -char_u *repl_to = NULL; +char *repl_from = NULL; +char *repl_to = NULL; /// Main spell-checking function. /// "ptr" points to a character that could be the start of a word. @@ -204,21 +214,19 @@ char_u *repl_to = NULL; /// /// @return the length of the word in bytes, also when it's OK, so that the /// caller can skip over the word. -size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docount) +size_t spell_check(win_T *wp, char *ptr, hlf_T *attrp, int *capcol, bool docount) { matchinf_T mi; // Most things are put in "mi" so that it can // be passed to functions quickly. size_t nrlen = 0; // found a number first - int c; size_t wrongcaplen = 0; - int lpi; bool count_word = docount; - bool use_camel_case = *wp->w_s->b_p_spo != NUL; + bool use_camel_case = (wp->w_s->b_p_spo_flags & SPO_CAMEL) != 0; bool camel_case = false; // A word never starts at a space or a control character. Return quickly // then, skipping over the character. - if (*ptr <= ' ') { + if ((uint8_t)(*ptr) <= ' ') { return 1; } @@ -234,11 +242,11 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou // julifeest". if (*ptr >= '0' && *ptr <= '9') { if (*ptr == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) { - mi.mi_end = (char_u *)skipbin((char *)ptr + 2); + mi.mi_end = (char *)skipbin(ptr + 2); } else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) { mi.mi_end = skiphex(ptr + 2); } else { - mi.mi_end = (char_u *)skipdigits((char *)ptr); + mi.mi_end = skipdigits(ptr); } nrlen = (size_t)(mi.mi_end - ptr); } @@ -250,7 +258,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou bool this_upper = false; // init for gcc if (use_camel_case) { - c = utf_ptr2char((char *)mi.mi_fend); + int c = utf_ptr2char(mi.mi_fend); this_upper = SPELL_ISUPPER(c); } @@ -258,7 +266,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou MB_PTR_ADV(mi.mi_fend); if (use_camel_case) { const bool prev_upper = this_upper; - c = utf_ptr2char((char *)mi.mi_fend); + int c = utf_ptr2char(mi.mi_fend); this_upper = SPELL_ISUPPER(c); camel_case = !prev_upper && this_upper; } @@ -267,7 +275,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL) { // Check word starting with capital letter. - c = utf_ptr2char((char *)ptr); + int c = utf_ptr2char(ptr); if (!SPELL_ISUPPER(c)) { wrongcaplen = (size_t)(mi.mi_fend - ptr); } @@ -294,7 +302,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou (void)spell_casefold(wp, ptr, (int)(mi.mi_fend - ptr), mi.mi_fword, MAXWLEN + 1); - mi.mi_fwordlen = (int)STRLEN(mi.mi_fword); + mi.mi_fwordlen = (int)strlen(mi.mi_fword); if (camel_case && mi.mi_fwordlen > 0) { // introduce a fake word end space into the folded word. @@ -308,7 +316,7 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou // Loop over the languages specified in 'spelllang'. // We check them all, because a word may be matched longer in another // language. - for (lpi = 0; lpi < wp->w_s->b_langp.ga_len; ++lpi) { + for (int lpi = 0; lpi < wp->w_s->b_langp.ga_len; lpi++) { mi.mi_lp = LANGP_ENTRY(wp->w_s->b_langp, lpi); // If reloading fails the language is still in the list but everything @@ -358,21 +366,21 @@ size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docou // Check for end of sentence. regmatch.regprog = wp->w_s->b_cap_prog; regmatch.rm_ic = false; - int r = vim_regexec(®match, (char *)ptr, 0); + int r = vim_regexec(®match, ptr, 0); wp->w_s->b_cap_prog = regmatch.regprog; if (r) { *capcol = (int)(regmatch.endp[0] - ptr); } } - return (size_t)(utfc_ptr2len((char *)ptr)); + return (size_t)(utfc_ptr2len(ptr)); } else if (mi.mi_end == ptr) { // Always include at least one character. Required for when there // is a mixup in "midword". MB_PTR_ADV(mi.mi_end); } else if (mi.mi_result == SP_BAD && LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) { - char_u *p, *fp; + char *p, *fp; int save_result = mi.mi_result; // First language in 'spelllang' is NOBREAK. Find first position @@ -427,7 +435,7 @@ static void find_word(matchinf_T *mip, int mode) { int wlen = 0; int flen; - char_u *ptr; + char *ptr; slang_T *slang = mip->mi_lp->lp_slang; char_u *byts; idx_T *idxs; @@ -436,7 +444,7 @@ static void find_word(matchinf_T *mip, int mode) // Check for word with matching case in keep-case tree. ptr = mip->mi_word; flen = 9999; // no case folding, always enough bytes - byts = slang->sl_kbyts; + byts = (char_u *)slang->sl_kbyts; idxs = slang->sl_kidxs; if (mode == FIND_KEEPCOMPOUND) { @@ -447,7 +455,7 @@ static void find_word(matchinf_T *mip, int mode) // Check for case-folded in case-folded tree. ptr = mip->mi_fword; flen = mip->mi_fwordlen; // available case-folded bytes - byts = slang->sl_fbyts; + byts = (char_u *)slang->sl_fbyts; idxs = slang->sl_fidxs; if (mode == FIND_PREFIX) { @@ -468,7 +476,6 @@ static void find_word(matchinf_T *mip, int mode) int endlen[MAXWLEN]; // length at possible word endings idx_T endidx[MAXWLEN]; // possible word endings int endidxcnt = 0; - int len; int c; // Repeat advancing in the tree until: @@ -480,7 +487,7 @@ static void find_word(matchinf_T *mip, int mode) flen = fold_more(mip); } - len = byts[arridx++]; + int len = byts[arridx++]; // If the first possible byte is a zero the word could end here. // Remember this index, we first check for the longest word. @@ -511,7 +518,7 @@ static void find_word(matchinf_T *mip, int mode) } // Perform a binary search in the list of accepted bytes. - c = ptr[wlen]; + c = (uint8_t)ptr[wlen]; if (c == TAB) { // <Tab> is handled like <Space> c = ' '; } @@ -555,7 +562,7 @@ static void find_word(matchinf_T *mip, int mode) } } - char_u *p; + char *p; bool word_ends; // Verify that one of the possible endings is valid. Try the longest @@ -585,8 +592,8 @@ static void find_word(matchinf_T *mip, int mode) // when folding case. This can be slow, take a shortcut when the // case-folded word is equal to the keep-case word. p = mip->mi_word; - if (STRNCMP(ptr, p, wlen) != 0) { - for (char_u *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) { + if (strncmp(ptr, p, (size_t)wlen) != 0) { + for (char *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) { MB_PTR_ADV(p); } wlen = (int)(p - mip->mi_word); @@ -597,7 +604,7 @@ static void find_word(matchinf_T *mip, int mode) // prefix ID. // Repeat this if there are more flags/region alternatives until there // is a match. - for (len = byts[arridx - 1]; len > 0 && byts[arridx] == 0; len--, arridx++) { + for (int len = byts[arridx - 1]; len > 0 && byts[arridx] == 0; len--, arridx++) { uint32_t flags = (uint32_t)idxs[arridx]; // For the fold-case tree check that the case of the checked word @@ -616,11 +623,10 @@ static void find_word(matchinf_T *mip, int mode) || !spell_valid_case(mip->mi_capflags, (int)flags)) { continue; } - } - // When mode is FIND_PREFIX the word must support the prefix: - // check the prefix ID and the condition. Do that for the list at - // mip->mi_prefarridx that find_prefix() filled. - else if (mode == FIND_PREFIX && !prefix_found) { + } else if (mode == FIND_PREFIX && !prefix_found) { + // When mode is FIND_PREFIX the word must support the prefix: + // check the prefix ID and the condition. Do that for the list at + // mip->mi_prefarridx that find_prefix() filled. c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx, (int)flags, mip->mi_word + mip->mi_cprefixlen, slang, @@ -681,7 +687,8 @@ static void find_word(matchinf_T *mip, int mode) } // Quickly check if compounding is possible with this flag. - if (!byte_in_str(mip->mi_complen == 0 ? slang->sl_compstartflags : slang->sl_compallflags, + if (!byte_in_str(mip->mi_complen == + 0 ? slang->sl_compstartflags : slang->sl_compallflags, (int)((unsigned)flags >> 24))) { continue; } @@ -697,10 +704,10 @@ static void find_word(matchinf_T *mip, int mode) // Need to check the caps type of the appended compound // word. - if (STRNCMP(ptr, mip->mi_word, mip->mi_compoff) != 0) { + if (strncmp(ptr, mip->mi_word, (size_t)mip->mi_compoff) != 0) { // case folding may have changed the length p = mip->mi_word; - for (char_u *s = ptr; s < ptr + mip->mi_compoff; MB_PTR_ADV(s)) { + for (char *s = ptr; s < ptr + mip->mi_compoff; MB_PTR_ADV(s)) { MB_PTR_ADV(p); } } else { @@ -733,14 +740,14 @@ static void find_word(matchinf_T *mip, int mode) mip->mi_compflags[mip->mi_complen] = (char_u)((unsigned)flags >> 24); mip->mi_compflags[mip->mi_complen + 1] = NUL; if (word_ends) { - char_u fword[MAXWLEN] = { 0 }; + char fword[MAXWLEN] = { 0 }; if (slang->sl_compsylmax < MAXWLEN) { // "fword" is only needed for checking syllables. if (ptr == mip->mi_word) { (void)spell_casefold(mip->mi_win, ptr, wlen, fword, MAXWLEN); } else { - STRLCPY(fword, ptr, endlen[endidxcnt] + 1); + xstrlcpy(fword, ptr, (size_t)endlen[endidxcnt] + 1); } } if (!can_compound(slang, fword, mip->mi_compflags)) { @@ -752,9 +759,8 @@ static void find_word(matchinf_T *mip, int mode) // COMPOUNDRULE, discard the compounded word. continue; } - } - // Check NEEDCOMPOUND: can't use word without compounding. - else if (flags & WF_NEEDCOMP) { + } else if (flags & WF_NEEDCOMP) { + // skip if word is only valid in a compound continue; } @@ -762,7 +768,7 @@ static void find_word(matchinf_T *mip, int mode) if (!word_ends) { int save_result = mip->mi_result; - char_u *save_end = mip->mi_end; + char *save_end = mip->mi_end; langp_T *save_lp = mip->mi_lp; // Check that a valid word follows. If there is one and we @@ -782,8 +788,8 @@ static void find_word(matchinf_T *mip, int mode) // folding case. This can be slow, take a shortcut when // the case-folded word is equal to the keep-case word. p = mip->mi_fword; - if (STRNCMP(ptr, p, wlen) != 0) { - for (char_u *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) { + if (strncmp(ptr, p, (size_t)wlen) != 0) { + for (char *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) { MB_PTR_ADV(p); } mip->mi_compoff = (int)(p - mip->mi_fword); @@ -792,14 +798,14 @@ static void find_word(matchinf_T *mip, int mode) #if 0 c = mip->mi_compoff; #endif - ++mip->mi_complen; + mip->mi_complen++; if (flags & WF_COMPROOT) { - ++mip->mi_compextra; + mip->mi_compextra++; } // For NOBREAK we need to try all NOBREAK languages, at least // to find the ".add" file(s). - for (int lpi = 0; lpi < mip->mi_win->w_s->b_langp.ga_len; ++lpi) { + for (int lpi = 0; lpi < mip->mi_win->w_s->b_langp.ga_len; lpi++) { if (slang->sl_nobreak) { mip->mi_lp = LANGP_ENTRY(mip->mi_win->w_s->b_langp, lpi); if (mip->mi_lp->lp_slang->sl_fidxs == NULL @@ -833,9 +839,9 @@ static void find_word(matchinf_T *mip, int mode) break; } } - --mip->mi_complen; + mip->mi_complen--; if (flags & WF_COMPROOT) { - --mip->mi_compextra; + mip->mi_compextra--; } mip->mi_lp = save_lp; @@ -903,19 +909,16 @@ static void find_word(matchinf_T *mip, int mode) /// end of ptr[wlen] and the second part matches after it. /// /// @param gap &sl_comppat -bool match_checkcompoundpattern(char_u *ptr, int wlen, garray_T *gap) +bool match_checkcompoundpattern(char *ptr, int wlen, garray_T *gap) { - char_u *p; - int len; - for (int i = 0; i + 1 < gap->ga_len; i += 2) { - p = ((char_u **)gap->ga_data)[i + 1]; - if (STRNCMP(ptr + wlen, p, STRLEN(p)) == 0) { + char *p = ((char **)gap->ga_data)[i + 1]; + if (strncmp(ptr + wlen, p, strlen(p)) == 0) { // Second part matches at start of following compound word, now // check if first part matches at end of previous word. - p = ((char_u **)gap->ga_data)[i]; - len = (int)STRLEN(p); - if (len <= wlen && STRNCMP(ptr + wlen - len, p, len) == 0) { + p = ((char **)gap->ga_data)[i]; + int len = (int)strlen(p); + if (len <= wlen && strncmp(ptr + wlen - len, p, (size_t)len) == 0) { return true; } } @@ -923,20 +926,20 @@ bool match_checkcompoundpattern(char_u *ptr, int wlen, garray_T *gap) return false; } -// Returns true if "flags" is a valid sequence of compound flags and "word" -// does not have too many syllables. -bool can_compound(slang_T *slang, const char_u *word, const char_u *flags) +/// @return true if "flags" is a valid sequence of compound flags and "word" +/// does not have too many syllables. +bool can_compound(slang_T *slang, const char *word, const uint8_t *flags) FUNC_ATTR_NONNULL_ALL { - char_u uflags[MAXWLEN * 2] = { 0 }; + char uflags[MAXWLEN * 2] = { 0 }; if (slang->sl_compprog == NULL) { return false; } // Need to convert the single byte flags to utf8 characters. - char_u *p = uflags; + char *p = uflags; for (int i = 0; flags[i] != NUL; i++) { - p += utf_char2bytes(flags[i], (char *)p); + p += utf_char2bytes(flags[i], p); } *p = NUL; p = uflags; @@ -949,7 +952,7 @@ bool can_compound(slang_T *slang, const char_u *word, const char_u *flags) // COMPOUNDWORDMAX then compounding is not allowed. if (slang->sl_compsylmax < MAXWLEN && count_syllables(slang, word) > slang->sl_compsylmax) { - return (int)STRLEN(flags) < slang->sl_compmax; + return (int)strlen((char *)flags) < slang->sl_compmax; } return true; } @@ -958,18 +961,14 @@ bool can_compound(slang_T *slang, const char_u *word, const char_u *flags) // compound rule. This is used to stop trying a compound if the flags // collected so far can't possibly match any compound rule. // Caller must check that slang->sl_comprules is not NULL. -bool match_compoundrule(slang_T *slang, char_u *compflags) +bool match_compoundrule(slang_T *slang, const char_u *compflags) { - char_u *p; - int i; - int c; - // loop over all the COMPOUNDRULE entries - for (p = slang->sl_comprules; *p != NUL; ++p) { + for (char_u *p = (char_u *)slang->sl_comprules; *p != NUL; p++) { // loop over the flags in the compound word we have made, match // them against the current rule entry - for (i = 0;; ++i) { - c = compflags[i]; + for (int i = 0;; i++) { + int c = compflags[i]; if (c == NUL) { // found a rule that matches for the flags we have so far return true; @@ -1015,15 +1014,12 @@ bool match_compoundrule(slang_T *slang, char_u *compflags) /// @param totprefcnt nr of prefix IDs /// @param arridx idx in sl_pidxs[] /// @param cond_req only use prefixes with a condition -int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang, +int valid_word_prefix(int totprefcnt, int arridx, int flags, char *word, slang_T *slang, bool cond_req) { - int prefcnt; - int pidx; - int prefid = (int)((unsigned)flags >> 24); - for (prefcnt = totprefcnt - 1; prefcnt >= 0; prefcnt--) { - pidx = slang->sl_pidxs[arridx + prefcnt]; + for (int prefcnt = totprefcnt - 1; prefcnt >= 0; prefcnt--) { + int pidx = slang->sl_pidxs[arridx + prefcnt]; // Check the prefix ID. if (prefid != (pidx & 0xff)) { @@ -1063,30 +1059,23 @@ int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang static void find_prefix(matchinf_T *mip, int mode) { idx_T arridx = 0; - int len; int wlen = 0; - int flen; - int c; - char_u *ptr; - idx_T lo, hi, m; slang_T *slang = mip->mi_lp->lp_slang; - char_u *byts; - idx_T *idxs; - byts = slang->sl_pbyts; + char_u *byts = (char_u *)slang->sl_pbyts; if (byts == NULL) { return; // array is empty } // We use the case-folded word here, since prefixes are always // case-folded. - ptr = mip->mi_fword; - flen = mip->mi_fwordlen; // available case-folded bytes + char_u *ptr = (char_u *)mip->mi_fword; + int flen = mip->mi_fwordlen; // available case-folded bytes if (mode == FIND_COMPOUND) { // Skip over the previously found word(s). ptr += mip->mi_compoff; flen -= mip->mi_compoff; } - idxs = slang->sl_pidxs; + idx_T *idxs = slang->sl_pidxs; // Repeat advancing in the tree until: // - there is a byte that doesn't match, @@ -1097,7 +1086,7 @@ static void find_prefix(matchinf_T *mip, int mode) flen = fold_more(mip); } - len = byts[arridx++]; + int len = byts[arridx++]; // If the first possible byte is a zero the prefix could end here. // Check if the following word matches and supports the prefix. @@ -1137,11 +1126,11 @@ static void find_prefix(matchinf_T *mip, int mode) } // Perform a binary search in the list of accepted bytes. - c = ptr[wlen]; - lo = arridx; - hi = arridx + len - 1; + int c = ptr[wlen]; + idx_T lo = arridx; + idx_T hi = arridx + len - 1; while (lo < hi) { - m = (lo + hi) / 2; + idx_T m = (lo + hi) / 2; if (byts[m] > c) { hi = m - 1; } else if (byts[m] < c) { @@ -1169,10 +1158,7 @@ static void find_prefix(matchinf_T *mip, int mode) // Return the length of the folded chars in bytes. static int fold_more(matchinf_T *mip) { - int flen; - char_u *p; - - p = mip->mi_fend; + char *p = mip->mi_fend; do { MB_PTR_ADV(mip->mi_fend); } while (*mip->mi_fend != NUL && spell_iswordp(mip->mi_fend, mip->mi_win)); @@ -1185,7 +1171,7 @@ static int fold_more(matchinf_T *mip) (void)spell_casefold(mip->mi_win, p, (int)(mip->mi_fend - p), mip->mi_fword + mip->mi_fwordlen, MAXWLEN - mip->mi_fwordlen); - flen = (int)STRLEN(mip->mi_fword + mip->mi_fwordlen); + int flen = (int)strlen(mip->mi_fword + mip->mi_fwordlen); mip->mi_fwordlen += flen; return flen; } @@ -1214,6 +1200,31 @@ bool no_spell_checking(win_T *wp) return false; } +static void decor_spell_nav_start(win_T *wp) +{ + decor_state = (DecorState){ 0 }; + decor_redraw_reset(wp->w_buffer, &decor_state); +} + +static bool decor_spell_nav_col(win_T *wp, linenr_T lnum, linenr_T *decor_lnum, int col, + char **decor_error) +{ + if (*decor_lnum != lnum) { + decor_providers_invoke_spell(wp, lnum - 1, col, lnum - 1, -1, decor_error); + decor_redraw_line(wp->w_buffer, lnum - 1, &decor_state); + *decor_lnum = lnum; + } + decor_redraw_col(wp->w_buffer, col, col, false, &decor_state); + return decor_state.spell == kTrue; +} + +static inline bool can_syn_spell(win_T *wp, linenr_T lnum, int col) +{ + bool can_spell; + (void)syn_get_id(wp, lnum, col, false, &can_spell, false); + return can_spell; +} + /// Moves to the next spell error. /// "curline" is false for "[s", "]s", "[S" and "]S". /// "curline" is true to find word under/after cursor in the same line. @@ -1227,21 +1238,16 @@ bool no_spell_checking(win_T *wp) /// @return 0 if not found, length of the badly spelled word otherwise. size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *attrp) { - linenr_T lnum; pos_T found_pos; size_t found_len = 0; - char_u *line; - char_u *p; - char_u *endp; hlf_T attr = HLF_COUNT; size_t len; int has_syntax = syntax_present(wp); - int col; - bool can_spell; - char_u *buf = NULL; + colnr_T col; + char *buf = NULL; size_t buflen = 0; int skip = 0; - int capcol = -1; + colnr_T capcol = -1; bool found_one = false; bool wrapped = false; @@ -1249,6 +1255,8 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att return 0; } + size_t ret = 0; + // Start looking for bad word at the start of the line, because we can't // start halfway through a word, we don't know where it starts or ends. // @@ -1258,13 +1266,26 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att // We concatenate the start of the next line, so that wrapped words work // (e.g. "et<line-break>cetera"). Doesn't work when searching backwards // though... - lnum = wp->w_cursor.lnum; + linenr_T lnum = wp->w_cursor.lnum; clearpos(&found_pos); + char *decor_error = NULL; + // Ephemeral extmarks are currently stored in the global decor_state. + // When looking for spell errors, we need to: + // - temporarily reset decor_state + // - run the _on_spell_nav decor callback for each line we look at + // - detect if any spell marks are present + // - restore decor_state to the value saved here. + // TODO(lewis6991): un-globalize decor_state and allow ephemeral marks to be stored into a + // temporary DecorState. + DecorState saved_decor_start = decor_state; + linenr_T decor_lnum = -1; + decor_spell_nav_start(wp); + while (!got_int) { - line = ml_get_buf(wp->w_buffer, lnum, false); + char *line = ml_get_buf(wp->w_buffer, lnum, false); - len = STRLEN(line); + len = strlen(line); if (buflen < len + MAXWLEN + 2) { xfree(buf); buflen = len + MAXWLEN + 2; @@ -1279,10 +1300,10 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att // For checking first word with a capital skip white space. if (capcol == 0) { - capcol = (int)getwhitecols(line); + capcol = (colnr_T)getwhitecols(line); } else if (curline && wp == curwin) { // For spellbadword(): check if first word needs a capital. - col = (int)getwhitecols(line); + col = (colnr_T)getwhitecols(line); if (check_need_cap(lnum, col)) { capcol = col; } @@ -1298,12 +1319,12 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att bool empty_line = *skipwhite((const char *)line) == NUL; STRCPY(buf, line); if (lnum < wp->w_buffer->b_ml.ml_line_count) { - spell_cat_line(buf + STRLEN(buf), + spell_cat_line(buf + strlen(buf), ml_get_buf(wp->w_buffer, lnum + 1, false), MAXWLEN); } - p = buf + skip; - endp = buf + len; + char *p = buf + skip; + char *endp = buf + len; while (p < endp) { // When searching backward don't search after the cursor. Unless // we wrapped around the end of the buffer. @@ -1329,30 +1350,31 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att || ((colnr_T)(curline ? p - buf + (ptrdiff_t)len : p - buf) > wp->w_cursor.col)) { - if (has_syntax) { - col = (int)(p - buf); - (void)syn_get_id(wp, lnum, (colnr_T)col, - FALSE, &can_spell, FALSE); - if (!can_spell) { - attr = HLF_COUNT; - } - } else { - can_spell = true; + col = (colnr_T)(p - buf); + + bool can_spell = (!has_syntax && (wp->w_s->b_p_spo_flags & SPO_NPBUFFER) == 0) + || decor_spell_nav_col(wp, lnum, &decor_lnum, col, &decor_error) + || (has_syntax && can_syn_spell(wp, lnum, col)); + + if (!can_spell) { + attr = HLF_COUNT; } if (can_spell) { found_one = true; - found_pos.lnum = lnum; - found_pos.col = (int)(p - buf); - found_pos.coladd = 0; + found_pos = (pos_T) { + .lnum = lnum, + .col = col, + .coladd = 0 + }; if (dir == FORWARD) { // No need to search further. wp->w_cursor = found_pos; - xfree(buf); if (attrp != NULL) { *attrp = attr; } - return len; + ret = len; + goto theend; } else if (curline) { // Insert mode completion: put cursor after // the bad word. @@ -1376,8 +1398,8 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att if (dir == BACKWARD && found_pos.lnum != 0) { // Use the last match in the line (before the cursor). wp->w_cursor = found_pos; - xfree(buf); - return found_len; + ret = found_len; + goto theend; } if (curline) { @@ -1447,43 +1469,45 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att line_breakcheck(); } +theend: + decor_state_free(&decor_state); + xfree(decor_error); + decor_state = saved_decor_start; xfree(buf); - return 0; + return ret; } // For spell checking: concatenate the start of the following line "line" into // "buf", blanking-out special characters. Copy less than "maxlen" bytes. // Keep the blanks at the start of the next line, this is used in win_line() // to skip those bytes if the word was OK. -void spell_cat_line(char_u *buf, char_u *line, int maxlen) +void spell_cat_line(char *buf, char *line, int maxlen) { - char_u *p; - int n; - - p = (char_u *)skipwhite((char *)line); - while (vim_strchr("*#/\"\t", *p) != NULL) { + char_u *p = (char_u *)skipwhite(line); + while (vim_strchr("*#/\"\t", (uint8_t)(*p)) != NULL) { p = (char_u *)skipwhite((char *)p + 1); } - if (*p != NUL) { - // Only worth concatenating if there is something else than spaces to - // concatenate. - n = (int)(p - line) + 1; - if (n < maxlen - 1) { - memset(buf, ' ', (size_t)n); - STRLCPY(buf + n, p, maxlen - n); - } + if (*p == NUL) { + return; + } + + // Only worth concatenating if there is something else than spaces to + // concatenate. + int n = (int)(p - (char_u *)line) + 1; + if (n < maxlen - 1) { + memset(buf, ' ', (size_t)n); + xstrlcpy(buf + n, (char *)p, (size_t)(maxlen - n)); } } // Load word list(s) for "lang" from Vim spell file(s). // "lang" must be the language without the region: e.g., "en". -static void spell_load_lang(char_u *lang) +static void spell_load_lang(char *lang) { char fname_enc[85]; int r; spelload_T sl; - int round; // Copy the language name to pass it to spell_load_cb() as a cookie. // It's truncated when an error is detected. @@ -1491,22 +1515,26 @@ static void spell_load_lang(char_u *lang) sl.sl_slang = NULL; sl.sl_nobreak = false; + // Disallow deleting the current buffer. Autocommands can do weird things + // and cause "lang" to be freed. + curbuf->b_locked++; + // We may retry when no spell file is found for the language, an // autocommand may load it then. - for (round = 1; round <= 2; ++round) { + for (int round = 1; round <= 2; round++) { // Find the first spell file for "lang" in 'runtimepath' and load it. - vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5, + vim_snprintf(fname_enc, sizeof(fname_enc) - 5, "spell/%s.%s.spl", lang, spell_enc()); - r = do_in_runtimepath((char *)fname_enc, 0, spell_load_cb, &sl); + r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl); if (r == FAIL && *sl.sl_lang != NUL) { // Try loading the ASCII version. - vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5, + vim_snprintf(fname_enc, sizeof(fname_enc) - 5, "spell/%s.ascii.spl", lang); - r = do_in_runtimepath((char *)fname_enc, 0, spell_load_cb, &sl); + r = do_in_runtimepath(fname_enc, 0, spell_load_cb, &sl); if (r == FAIL && *sl.sl_lang != NUL && round == 1 - && apply_autocmds(EVENT_SPELLFILEMISSING, (char *)lang, + && apply_autocmds(EVENT_SPELLFILEMISSING, lang, curbuf->b_fname, false, curbuf)) { continue; } @@ -1530,38 +1558,40 @@ static void spell_load_lang(char_u *lang) } } else if (sl.sl_slang != NULL) { // At least one file was loaded, now load ALL the additions. - STRCPY(fname_enc + STRLEN(fname_enc) - 3, "add.spl"); - do_in_runtimepath((char *)fname_enc, DIP_ALL, spell_load_cb, &sl); + STRCPY(fname_enc + strlen(fname_enc) - 3, "add.spl"); + do_in_runtimepath(fname_enc, DIP_ALL, spell_load_cb, &sl); } + + curbuf->b_locked--; } // Return the encoding used for spell checking: Use 'encoding', except that we // use "latin1" for "latin9". And limit to 60 characters (just in case). -char_u *spell_enc(void) +char *spell_enc(void) { - if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0) { + if (strlen(p_enc) < 60 && strcmp(p_enc, "iso-8859-15") != 0) { return p_enc; } - return (char_u *)"latin1"; + return "latin1"; } // Get the name of the .spl file for the internal wordlist into // "fname[MAXPATHL]". -static void int_wordlist_spl(char_u *fname) +static void int_wordlist_spl(char *fname) { - vim_snprintf((char *)fname, MAXPATHL, SPL_FNAME_TMPL, + vim_snprintf(fname, MAXPATHL, SPL_FNAME_TMPL, int_wordlist, spell_enc()); } -// Allocate a new slang_T for language "lang". "lang" can be NULL. -// Caller must fill "sl_next". -slang_T *slang_alloc(char_u *lang) +/// Allocate a new slang_T for language "lang". "lang" can be NULL. +/// Caller must fill "sl_next". +slang_T *slang_alloc(char *lang) FUNC_ATTR_NONNULL_RET { slang_T *lp = xcalloc(1, sizeof(slang_T)); if (lang != NULL) { - lp->sl_name = vim_strsave(lang); + lp->sl_name = xstrdup(lang); } ga_init(&lp->sl_rep, sizeof(fromto_T), 10); ga_init(&lp->sl_repsal, sizeof(fromto_T), 10); @@ -1624,7 +1654,7 @@ void slang_clear(slang_T *lp) GA_DEEP_CLEAR(gap, salitem_T, free_salitem); } - for (int i = 0; i < lp->sl_prefixcnt; ++i) { + for (int i = 0; i < lp->sl_prefixcnt; i++) { vim_regfree(lp->sl_prefprog[i]); } lp->sl_prefixcnt = 0; @@ -1673,20 +1703,20 @@ void slang_clear_sug(slang_T *lp) static void spell_load_cb(char *fname, void *cookie) { spelload_T *slp = (spelload_T *)cookie; - slang_T *slang; - - slang = spell_load_file((char_u *)fname, slp->sl_lang, NULL, false); - if (slang != NULL) { - // When a previously loaded file has NOBREAK also use it for the - // ".add" files. - if (slp->sl_nobreak && slang->sl_add) { - slang->sl_nobreak = true; - } else if (slang->sl_nobreak) { - slp->sl_nobreak = true; - } + slang_T *slang = spell_load_file(fname, slp->sl_lang, NULL, false); + if (slang == NULL) { + return; + } - slp->sl_slang = slang; + // When a previously loaded file has NOBREAK also use it for the + // ".add" files. + if (slp->sl_nobreak && slang->sl_add) { + slang->sl_nobreak = true; + } else if (slang->sl_nobreak) { + slp->sl_nobreak = true; } + + slp->sl_slang = slang; } /// Add a word to the hashtable of common words. @@ -1696,31 +1726,29 @@ static void spell_load_cb(char *fname, void *cookie) /// @param[in] word added to common words hashtable /// @param[in] len length of word or -1 for NUL terminated /// @param[in] count 1 to count once, 10 to init -void count_common_word(slang_T *lp, char_u *word, int len, uint8_t count) +void count_common_word(slang_T *lp, char *word, int len, uint8_t count) { - hash_T hash; - hashitem_T *hi; - wordcount_T *wc; - char_u buf[MAXWLEN]; - char_u *p; + char buf[MAXWLEN]; + char *p; if (len == -1) { p = word; } else if (len >= MAXWLEN) { return; } else { - STRLCPY(buf, word, len + 1); + xstrlcpy(buf, word, (size_t)len + 1); p = buf; } - hash = hash_hash(p); - const size_t p_len = STRLEN(p); - hi = hash_lookup(&lp->sl_wordcount, (const char *)p, p_len, hash); + wordcount_T *wc; + hash_T hash = hash_hash(p); + const size_t p_len = strlen(p); + hashitem_T *hi = hash_lookup(&lp->sl_wordcount, (const char *)p, p_len, hash); if (HASHITEM_EMPTY(hi)) { wc = xmalloc(sizeof(wordcount_T) + p_len); memcpy(wc->wc_word, p, p_len + 1); wc->wc_count = count; - hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash); + hash_add_item(&lp->sl_wordcount, hi, (char *)wc->wc_word, hash); } else { wc = HI2WC(hi); wc->wc_count = (uint16_t)(wc->wc_count + count); @@ -1732,11 +1760,9 @@ void count_common_word(slang_T *lp, char_u *word, int len, uint8_t count) // Returns true if byte "n" appears in "str". // Like strchr() but independent of locale. -bool byte_in_str(char_u *str, int n) +bool byte_in_str(uint8_t *str, int n) { - char_u *p; - - for (p = str; *p != NUL; ++p) { + for (uint8_t *p = str; *p != NUL; p++) { if (*p == n) { return true; } @@ -1748,21 +1774,18 @@ bool byte_in_str(char_u *str, int n) // in "slang->sl_syl_items". int init_syl_tab(slang_T *slang) { - char_u *p; - char_u *s; - int l; - ga_init(&slang->sl_syl_items, sizeof(syl_item_T), 4); - p = (char_u *)vim_strchr((char *)slang->sl_syllable, '/'); + char *p = vim_strchr((char *)slang->sl_syllable, '/'); while (p != NULL) { *p++ = NUL; if (*p == NUL) { // trailing slash break; } - s = p; - p = (char_u *)vim_strchr((char *)p, '/'); + char *s = p; + p = vim_strchr(p, '/'); + int l; if (p == NULL) { - l = (int)STRLEN(s); + l = (int)strlen(s); } else { l = (int)(p - s); } @@ -1771,7 +1794,7 @@ int init_syl_tab(slang_T *slang) } syl_item_T *syl = GA_APPEND_VIA_PTR(syl_item_T, &slang->sl_syl_items); - STRLCPY(syl->sy_chars, s, l + 1); + xstrlcpy(syl->sy_chars, s, (size_t)l + 1); syl->sy_len = l; } return OK; @@ -1780,20 +1803,18 @@ int init_syl_tab(slang_T *slang) // Count the number of syllables in "word". // When "word" contains spaces the syllables after the last space are counted. // Returns zero if syllables are not defines. -static int count_syllables(slang_T *slang, const char_u *word) +static int count_syllables(slang_T *slang, const char *word) FUNC_ATTR_NONNULL_ALL { int cnt = 0; bool skip = false; int len; - syl_item_T *syl; - int c; if (slang->sl_syllable == NULL) { return 0; } - for (const char_u *p = word; *p != NUL; p += len) { + for (const char *p = word; *p != NUL; p += len) { // When running into a space reset counter. if (*p == ' ') { len = 1; @@ -1803,10 +1824,10 @@ static int count_syllables(slang_T *slang, const char_u *word) // Find longest match of syllable items. len = 0; - for (int i = 0; i < slang->sl_syl_items.ga_len; ++i) { - syl = ((syl_item_T *)slang->sl_syl_items.ga_data) + i; + for (int i = 0; i < slang->sl_syl_items.ga_len; i++) { + syl_item_T *syl = ((syl_item_T *)slang->sl_syl_items.ga_data) + i; if (syl->sy_len > len - && STRNCMP(p, syl->sy_chars, syl->sy_len) == 0) { + && strncmp(p, syl->sy_chars, (size_t)syl->sy_len) == 0) { len = syl->sy_len; } } @@ -1815,12 +1836,12 @@ static int count_syllables(slang_T *slang, const char_u *word) skip = false; } else { // No recognized syllable item, at least a syllable char then? - c = utf_ptr2char((char *)p); - len = utfc_ptr2len((char *)p); + int c = utf_ptr2char(p); + len = utfc_ptr2len(p); if (vim_strchr((char *)slang->sl_syllable, c) == NULL) { skip = false; // No, search for next syllable } else if (!skip) { - ++cnt; // Yes, count it + cnt++; // Yes, count it skip = true; // don't count following syllable chars } } @@ -1828,31 +1849,31 @@ static int count_syllables(slang_T *slang, const char_u *word) return cnt; } -// Parse 'spelllang' and set w_s->b_langp accordingly. -// Returns NULL if it's OK, an error message otherwise. +/// Parse 'spelllang' and set w_s->b_langp accordingly. +/// @return NULL if it's OK, an untranslated error message otherwise. char *did_set_spelllang(win_T *wp) { garray_T ga; char *splp; - char_u *region; - char_u region_cp[3]; + char *region; + char region_cp[3]; bool filename; int region_mask; slang_T *slang; int c; - char_u lang[MAXWLEN + 1]; - char_u spf_name[MAXPATHL]; + char lang[MAXWLEN + 1]; + char spf_name[MAXPATHL]; int len; - char_u *p; + char *p; int round; char *spf; - char_u *use_region = NULL; + char *use_region = NULL; bool dont_use_region = false; bool nobreak = false; langp_T *lp, *lp2; static bool recursive = false; char *ret_msg = NULL; - char_u *spl_copy; + char *spl_copy; bufref_T bufref; set_bufref(&bufref, wp->w_buffer); @@ -1870,22 +1891,22 @@ char *did_set_spelllang(win_T *wp) // Make a copy of 'spelllang', the SpellFileMissing autocommands may change // it under our fingers. - spl_copy = vim_strsave(wp->w_s->b_p_spl); + spl_copy = xstrdup(wp->w_s->b_p_spl); wp->w_s->b_cjk = 0; // Loop over comma separated language names. - for (splp = (char *)spl_copy; *splp != NUL;) { + for (splp = spl_copy; *splp != NUL;) { // Get one language name. - copy_option_part(&splp, (char *)lang, MAXWLEN, ","); + copy_option_part(&splp, lang, MAXWLEN, ","); region = NULL; - len = (int)STRLEN(lang); + len = (int)strlen(lang); if (!valid_spelllang(lang)) { continue; } - if (STRCMP(lang, "cjk") == 0) { + if (strcmp(lang, "cjk") == 0) { wp->w_s->b_cjk = 1; continue; } @@ -1893,14 +1914,14 @@ char *did_set_spelllang(win_T *wp) // If the name ends in ".spl" use it as the name of the spell file. // If there is a region name let "region" point to it and remove it // from the name. - if (len > 4 && FNAMECMP(lang + len - 4, ".spl") == 0) { + if (len > 4 && path_fnamecmp(lang + len - 4, ".spl") == 0) { filename = true; // Locate a region and remove it from the file name. - p = (char_u *)vim_strchr(path_tail((char *)lang), '_'); + p = vim_strchr(path_tail(lang), '_'); if (p != NULL && ASCII_ISALPHA(p[1]) && ASCII_ISALPHA(p[2]) && !ASCII_ISALPHA(p[3])) { - STRLCPY(region_cp, p + 1, 3); + xstrlcpy(region_cp, p + 1, 3); memmove(p, p + 3, (size_t)(len - (p - lang) - 2)); region = region_cp; } else { @@ -1909,7 +1930,7 @@ char *did_set_spelllang(win_T *wp) // Check if we loaded this language before. for (slang = first_lang; slang != NULL; slang = slang->sl_next) { - if (path_full_compare((char *)lang, (char *)slang->sl_fname, false, true) + if (path_full_compare(lang, slang->sl_fname, false, true) == kEqualFiles) { break; } @@ -1934,7 +1955,7 @@ char *did_set_spelllang(win_T *wp) if (region != NULL) { // If the region differs from what was used before then don't // use it for 'spellfile'. - if (use_region != NULL && STRCMP(region, use_region) != 0) { + if (use_region != NULL && strcmp(region, use_region) != 0) { dont_use_region = true; } use_region = region; @@ -1947,8 +1968,8 @@ char *did_set_spelllang(win_T *wp) } else { spell_load_lang(lang); // SpellFileMissing autocommands may do anything, including - // destroying the buffer we are using... - if (!bufref_valid(&bufref)) { + // destroying the buffer we are using or closing the window. + if (!bufref_valid(&bufref) || !win_valid_any_tab(wp)) { ret_msg = N_("E797: SpellFileMissing autocommand deleted buffer"); goto theend; } @@ -1958,7 +1979,7 @@ char *did_set_spelllang(win_T *wp) // Loop over the languages, there can be several files for "lang". for (slang = first_lang; slang != NULL; slang = slang->sl_next) { if (filename - ? path_full_compare((char *)lang, (char *)slang->sl_fname, false, true) == kEqualFiles + ? path_full_compare(lang, slang->sl_fname, false, true) == kEqualFiles : STRICMP(lang, slang->sl_name) == 0) { region_mask = REGION_ALL; if (!filename && region != NULL) { @@ -1999,7 +2020,7 @@ char *did_set_spelllang(win_T *wp) // round 1: load first name in 'spellfile'. // round 2: load second name in 'spellfile. // etc. - spf = (char *)curwin->w_s->b_p_spf; + spf = curwin->w_s->b_p_spf; for (round = 0; round == 0 || *spf != NUL; round++) { if (round == 0) { // Internal wordlist, if there is one. @@ -2009,14 +2030,14 @@ char *did_set_spelllang(win_T *wp) int_wordlist_spl(spf_name); } else { // One entry in 'spellfile'. - copy_option_part(&spf, (char *)spf_name, MAXPATHL - 5, ","); + copy_option_part(&spf, spf_name, MAXPATHL - 5, ","); STRCAT(spf_name, ".spl"); // If it was already found above then skip it. - for (c = 0; c < ga.ga_len; ++c) { + for (c = 0; c < ga.ga_len; c++) { p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname; if (p != NULL - && path_full_compare((char *)spf_name, (char *)p, false, true) == kEqualFiles) { + && path_full_compare(spf_name, p, false, true) == kEqualFiles) { break; } } @@ -2027,7 +2048,7 @@ char *did_set_spelllang(win_T *wp) // Check if it was loaded already. for (slang = first_lang; slang != NULL; slang = slang->sl_next) { - if (path_full_compare((char *)spf_name, (char *)slang->sl_fname, false, true) + if (path_full_compare(spf_name, slang->sl_fname, false, true) == kEqualFiles) { break; } @@ -2039,8 +2060,8 @@ char *did_set_spelllang(win_T *wp) if (round == 0) { STRCPY(lang, "internal wordlist"); } else { - STRLCPY(lang, path_tail((char *)spf_name), MAXWLEN + 1); - p = (char_u *)vim_strchr((char *)lang, '.'); + xstrlcpy(lang, path_tail(spf_name), MAXWLEN + 1); + p = vim_strchr(lang, '.'); if (p != NULL) { *p = NUL; // truncate at ".encoding.add" } @@ -2085,7 +2106,7 @@ char *did_set_spelllang(win_T *wp) // For each language figure out what language to use for sound folding and // REP items. If the language doesn't support it itself use another one // with the same name. E.g. for "en-math" use "en". - for (int i = 0; i < ga.ga_len; ++i) { + for (int i = 0; i < ga.ga_len; i++) { lp = LANGP_ENTRY(ga, i); // sound folding @@ -2094,10 +2115,10 @@ char *did_set_spelllang(win_T *wp) lp->lp_sallang = lp->lp_slang; } else { // find first similar language that does sound folding - for (int j = 0; j < ga.ga_len; ++j) { + for (int j = 0; j < ga.ga_len; j++) { lp2 = LANGP_ENTRY(ga, j); if (!GA_EMPTY(&lp2->lp_slang->sl_sal) - && STRNCMP(lp->lp_slang->sl_name, + && strncmp(lp->lp_slang->sl_name, lp2->lp_slang->sl_name, 2) == 0) { lp->lp_sallang = lp2->lp_slang; break; @@ -2111,10 +2132,10 @@ char *did_set_spelllang(win_T *wp) lp->lp_replang = lp->lp_slang; } else { // find first similar language that has REP items - for (int j = 0; j < ga.ga_len; ++j) { + for (int j = 0; j < ga.ga_len; j++) { lp2 = LANGP_ENTRY(ga, j); if (!GA_EMPTY(&lp2->lp_slang->sl_rep) - && STRNCMP(lp->lp_slang->sl_name, + && strncmp(lp->lp_slang->sl_name, lp2->lp_slang->sl_name, 2) == 0) { lp->lp_replang = lp2->lp_slang; break; @@ -2122,7 +2143,7 @@ char *did_set_spelllang(win_T *wp) } } } - redraw_later(wp, NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); theend: xfree(spl_copy); @@ -2137,8 +2158,8 @@ static void clear_midword(win_T *wp) XFREE_CLEAR(wp->w_s->b_spell_ismw_mb); } -// Use the "sl_midword" field of language "lp" for buffer "buf". -// They add up to any currently used midword characters. +/// Use the "sl_midword" field of language "lp" for buffer "buf". +/// They add up to any currently used midword characters. static void use_midword(slang_T *lp, win_T *wp) FUNC_ATTR_NONNULL_ALL { @@ -2146,21 +2167,21 @@ static void use_midword(slang_T *lp, win_T *wp) return; } - for (char_u *p = lp->sl_midword; *p != NUL;) { - const int c = utf_ptr2char((char *)p); - const int l = utfc_ptr2len((char *)p); + for (char *p = (char *)lp->sl_midword; *p != NUL;) { + const int c = utf_ptr2char(p); + const int l = utfc_ptr2len(p); if (c < 256 && l <= 2) { wp->w_s->b_spell_ismw[c] = true; } else if (wp->w_s->b_spell_ismw_mb == NULL) { // First multi-byte char in "b_spell_ismw_mb". - wp->w_s->b_spell_ismw_mb = vim_strnsave(p, (size_t)l); + wp->w_s->b_spell_ismw_mb = xstrnsave(p, (size_t)l); } else { // Append multi-byte chars to "b_spell_ismw_mb". - const int n = (int)STRLEN(wp->w_s->b_spell_ismw_mb); - char_u *bp = vim_strnsave(wp->w_s->b_spell_ismw_mb, (size_t)n + (size_t)l); + const int n = (int)strlen(wp->w_s->b_spell_ismw_mb); + char *bp = xstrnsave(wp->w_s->b_spell_ismw_mb, (size_t)n + (size_t)l); xfree(wp->w_s->b_spell_ismw_mb); wp->w_s->b_spell_ismw_mb = bp; - STRLCPY(bp + n, p, l + 1); + xstrlcpy(bp + n, p, (size_t)l + 1); } p += l; } @@ -2169,7 +2190,7 @@ static void use_midword(slang_T *lp, win_T *wp) // Find the region "region[2]" in "rp" (points to "sl_regions"). // Each region is simply stored as the two characters of its name. // Returns the index if found (first is 0), REGION_ALL if not found. -static int find_region(char_u *rp, char_u *region) +static int find_region(const char *rp, const char *region) { int i; @@ -2194,13 +2215,10 @@ static int find_region(char_u *rp, char_u *region) /// @param[in] end End of word or NULL for NUL delimited string /// /// @returns Case type of word -int captype(char_u *word, char_u *end) +int captype(char *word, const char *end) FUNC_ATTR_NONNULL_ARG(1) { - char_u *p; - int firstcap; - bool allcap; - bool past_second = false; // past second word char + char *p; // find first letter for (p = word; !spell_iswordp_nmw(p, curwin); MB_PTR_ADV(p)) { @@ -2208,14 +2226,16 @@ int captype(char_u *word, char_u *end) return 0; // only non-word characters, illegal word } } - int c = mb_ptr2char_adv((const char_u **)&p); - firstcap = allcap = SPELL_ISUPPER(c); + int c = mb_ptr2char_adv((const char **)&p); + bool allcap; + bool firstcap = allcap = SPELL_ISUPPER(c); + bool past_second = false; // past second word char // Need to check all letters to find a word with mixed upper/lower. // But a word with an upper char only at start is a ONECAP. for (; end == NULL ? *p != NUL : p < end; MB_PTR_ADV(p)) { if (spell_iswordp_nmw(p, curwin)) { - c = utf_ptr2char((char *)p); + c = utf_ptr2char(p); if (!SPELL_ISUPPER(c)) { // UUl -> KEEPCAP if (past_second && allcap) { @@ -2242,28 +2262,27 @@ int captype(char_u *word, char_u *end) // Delete the internal wordlist and its .spl file. void spell_delete_wordlist(void) { - char_u fname[MAXPATHL] = { 0 }; - - if (int_wordlist != NULL) { - os_remove((char *)int_wordlist); - int_wordlist_spl(fname); - os_remove((char *)fname); - XFREE_CLEAR(int_wordlist); + if (int_wordlist == NULL) { + return; } + + char fname[MAXPATHL] = { 0 }; + os_remove(int_wordlist); + int_wordlist_spl(fname); + os_remove(fname); + XFREE_CLEAR(int_wordlist); } // Free all languages. void spell_free_all(void) { - slang_T *slang; - // Go through all buffers and handle 'spelllang'. <VN> FOR_ALL_BUFFERS(buf) { ga_clear(&buf->b_s.b_langp); } while (first_lang != NULL) { - slang = first_lang; + slang_T *slang = first_lang; first_lang = slang->sl_next; slang_free(slang); } @@ -2319,37 +2338,37 @@ buf_T *open_spellbuf(void) // Close the buffer used for spell info. void close_spellbuf(buf_T *buf) { - if (buf != NULL) { - ml_close(buf, TRUE); - xfree(buf); + if (buf == NULL) { + return; } + + ml_close(buf, true); + xfree(buf); } // Init the chartab used for spelling for ASCII. void clear_spell_chartab(spelltab_T *sp) { - int i; - // Init everything to false (zero). CLEAR_FIELD(sp->st_isw); CLEAR_FIELD(sp->st_isu); - for (i = 0; i < 256; i++) { + for (int i = 0; i < 256; i++) { sp->st_fold[i] = (char_u)i; sp->st_upper[i] = (char_u)i; } // We include digits. A word shouldn't start with a digit, but handling // that is done separately. - for (i = '0'; i <= '9'; ++i) { + for (int i = '0'; i <= '9'; i++) { sp->st_isw[i] = true; } - for (i = 'A'; i <= 'Z'; ++i) { + for (int i = 'A'; i <= 'Z'; i++) { sp->st_isw[i] = true; sp->st_isu[i] = true; sp->st_fold[i] = (char_u)(i + 0x20); } - for (i = 'a'; i <= 'z'; ++i) { + for (int i = 'a'; i <= 'z'; i++) { sp->st_isw[i] = true; sp->st_upper[i] = (char_u)(i - 0x20); } @@ -2361,11 +2380,9 @@ void clear_spell_chartab(spelltab_T *sp) // locale. For utf-8 we don't use isalpha() but our own functions. void init_spell_chartab(void) { - int i; - did_set_spelltab = false; clear_spell_chartab(&spelltab); - for (i = 128; i < 256; i++) { + for (int i = 128; i < 256; i++) { int f = utf_fold(i); int u = mb_toupper(i); @@ -2385,29 +2402,27 @@ void init_spell_chartab(void) /// Thus this only works properly when past the first character of the word. /// /// @param wp Buffer used. -bool spell_iswordp(const char_u *p, const win_T *wp) +bool spell_iswordp(const char *p, const win_T *wp) FUNC_ATTR_NONNULL_ALL { - int c; - - const int l = utfc_ptr2len((char *)p); - const char_u *s = p; + const int l = utfc_ptr2len(p); + const char *s = p; if (l == 1) { // be quick for ASCII - if (wp->w_s->b_spell_ismw[*p]) { + if (wp->w_s->b_spell_ismw[(uint8_t)(*p)]) { s = p + 1; // skip a mid-word character } } else { - c = utf_ptr2char((char *)p); + int c = utf_ptr2char(p); if (c < 256 ? wp->w_s->b_spell_ismw[c] : (wp->w_s->b_spell_ismw_mb != NULL - && vim_strchr((char *)wp->w_s->b_spell_ismw_mb, c) != NULL)) { + && vim_strchr(wp->w_s->b_spell_ismw_mb, c) != NULL)) { s = p + l; } } - c = utf_ptr2char((char *)s); + int c = utf_ptr2char(s); if (c > 255) { return spell_mb_isword_class(mb_get_class(s), wp); } @@ -2416,9 +2431,9 @@ bool spell_iswordp(const char_u *p, const win_T *wp) // Returns true if "p" points to a word character. // Unlike spell_iswordp() this doesn't check for "midword" characters. -bool spell_iswordp_nmw(const char_u *p, win_T *wp) +bool spell_iswordp_nmw(const char *p, win_T *wp) { - int c = utf_ptr2char((char *)p); + int c = utf_ptr2char(p); if (c > 255) { return spell_mb_isword_class(mb_get_class(p), wp); } @@ -2448,7 +2463,7 @@ static bool spell_iswordp_w(const int *p, const win_T *wp) if (*p < 256 ? wp->w_s->b_spell_ismw[*p] : (wp->w_s->b_spell_ismw_mb != NULL - && vim_strchr((char *)wp->w_s->b_spell_ismw_mb, + && vim_strchr(wp->w_s->b_spell_ismw_mb, *p) != NULL)) { s = p + 1; } else { @@ -2465,7 +2480,7 @@ static bool spell_iswordp_w(const int *p, const win_T *wp) // Uses the character definitions from the .spl file. // When using a multi-byte 'encoding' the length may change! // Returns FAIL when something wrong. -int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int buflen) +int spell_casefold(const win_T *wp, char *str, int len, char *buf, int buflen) FUNC_ATTR_NONNULL_ALL { if (len >= buflen) { @@ -2476,12 +2491,12 @@ int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int bufle int outi = 0; // Fold one character at a time. - for (char_u *p = str; p < str + len;) { + for (char *p = str; p < str + len;) { if (outi + MB_MAXBYTES > buflen) { buf[outi] = NUL; return FAIL; } - int c = mb_cptr2char_adv((const char_u **)&p); + int c = mb_cptr2char_adv((const char **)&p); // Exception: greek capital sigma 0x03A3 folds to 0x03C3, except // when it is the last character in a word, then it folds to @@ -2496,7 +2511,7 @@ int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int bufle c = SPELL_TOFOLD(c); } - outi += utf_char2bytes(c, (char *)buf + outi); + outi += utf_char2bytes(c, buf + outi); } buf[outi] = NUL; @@ -2508,18 +2523,14 @@ int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int bufle bool check_need_cap(linenr_T lnum, colnr_T col) { bool need_cap = false; - char_u *line; - char_u *line_copy = NULL; - char_u *p; - colnr_T endcol; - regmatch_T regmatch; if (curwin->w_s->b_cap_prog == NULL) { return false; } - line = get_cursor_line_ptr(); - endcol = 0; + char *line = get_cursor_line_ptr(); + char *line_copy = NULL; + colnr_T endcol = 0; if (getwhitecols(line) >= (int)col) { // At start of line, check if previous line is empty or sentence // ends there. @@ -2527,13 +2538,13 @@ bool check_need_cap(linenr_T lnum, colnr_T col) need_cap = true; } else { line = ml_get(lnum - 1); - if (*skipwhite((char *)line) == NUL) { + if (*skipwhite(line) == NUL) { need_cap = true; } else { // Append a space in place of the line break. - line_copy = concat_str(line, (char_u *)" "); + line_copy = concat_str(line, " "); line = line_copy; - endcol = (colnr_T)STRLEN(line); + endcol = (colnr_T)strlen(line); } } } else { @@ -2542,15 +2553,17 @@ bool check_need_cap(linenr_T lnum, colnr_T col) if (endcol > 0) { // Check if sentence ends before the bad word. - regmatch.regprog = curwin->w_s->b_cap_prog; - regmatch.rm_ic = FALSE; - p = line + endcol; + regmatch_T regmatch = { + .regprog = curwin->w_s->b_cap_prog, + .rm_ic = false + }; + char *p = line + endcol; for (;;) { MB_PTR_BACK(line, p); if (p == line || spell_iswordp_nmw(p, curwin)) { break; } - if (vim_regexec(®match, (char *)p, 0) + if (vim_regexec(®match, p, 0) && regmatch.endp[0] == line + endcol) { need_cap = true; break; @@ -2568,10 +2581,6 @@ bool check_need_cap(linenr_T lnum, colnr_T col) void ex_spellrepall(exarg_T *eap) { pos_T pos = curwin->w_cursor; - char_u *frompat; - int addlen; - char_u *line; - char_u *p; bool save_ws = p_ws; linenr_T prev_lnum = 0; @@ -2579,10 +2588,11 @@ void ex_spellrepall(exarg_T *eap) emsg(_("E752: No previous spell replacement")); return; } - addlen = (int)(STRLEN(repl_to) - STRLEN(repl_from)); + int addlen = (int)(strlen(repl_to) - strlen(repl_from)); - frompat = xmalloc(STRLEN(repl_from) + 7); - sprintf((char *)frompat, "\\V\\<%s\\>", repl_from); + size_t frompatlen = strlen(repl_from) + 7; + char *frompat = xmalloc(frompatlen); + snprintf(frompat, frompatlen, "\\V\\<%s\\>", repl_from); p_ws = false; sub_nsubs = 0; @@ -2596,14 +2606,14 @@ void ex_spellrepall(exarg_T *eap) // Only replace when the right word isn't there yet. This happens // when changing "etc" to "etc.". - line = get_cursor_line_ptr(); - if (addlen <= 0 || STRNCMP(line + curwin->w_cursor.col, - repl_to, STRLEN(repl_to)) != 0) { - p = xmalloc(STRLEN(line) + (size_t)addlen + 1); + char *line = get_cursor_line_ptr(); + if (addlen <= 0 || strncmp(line + curwin->w_cursor.col, + repl_to, strlen(repl_to)) != 0) { + char *p = xmalloc(strlen(line) + (size_t)addlen + 1); memmove(p, line, (size_t)curwin->w_cursor.col); STRCPY(p + curwin->w_cursor.col, repl_to); - STRCAT(p, line + curwin->w_cursor.col + STRLEN(repl_from)); - ml_replace(curwin->w_cursor.lnum, (char *)p, false); + STRCAT(p, line + curwin->w_cursor.col + strlen(repl_from)); + ml_replace(curwin->w_cursor.lnum, p, false); changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); if (curwin->w_cursor.lnum != prev_lnum) { @@ -2612,7 +2622,7 @@ void ex_spellrepall(exarg_T *eap) } sub_nsubs++; } - curwin->w_cursor.col += (colnr_T)STRLEN(repl_to); + curwin->w_cursor.col += (colnr_T)strlen(repl_to); } p_ws = save_ws; @@ -2633,30 +2643,30 @@ void ex_spellrepall(exarg_T *eap) /// @param[in] word source string to copy /// @param[in,out] wcopy copied string, with case of first letter changed /// @param[in] upper True to upper case, otherwise lower case -void onecap_copy(char_u *word, char_u *wcopy, bool upper) +void onecap_copy(char *word, char *wcopy, bool upper) { - char_u *p = word; - int c = mb_cptr2char_adv((const char_u **)&p); + char *p = word; + int c = mb_cptr2char_adv((const char **)&p); if (upper) { c = SPELL_TOUPPER(c); } else { c = SPELL_TOFOLD(c); } - int l = utf_char2bytes(c, (char *)wcopy); - STRLCPY(wcopy + l, p, MAXWLEN - l); + int l = utf_char2bytes(c, wcopy); + xstrlcpy(wcopy + l, p, (size_t)(MAXWLEN - l)); } // Make a copy of "word" with all the letters upper cased into // "wcopy[MAXWLEN]". The result is NUL terminated. -void allcap_copy(char_u *word, char_u *wcopy) +void allcap_copy(char *word, char *wcopy) { - char_u *d = wcopy; - for (char_u *s = word; *s != NUL;) { - int c = mb_cptr2char_adv((const char_u **)&s); + char_u *d = (char_u *)wcopy; + for (char *s = word; *s != NUL;) { + int c = mb_cptr2char_adv((const char **)&s); if (c == 0xdf) { c = 'S'; - if (d - wcopy >= MAXWLEN - 1) { + if (d - (char_u *)wcopy >= MAXWLEN - 1) { break; } *d++ = (char_u)c; @@ -2664,7 +2674,7 @@ void allcap_copy(char_u *word, char_u *wcopy) c = SPELL_TOUPPER(c); } - if (d - wcopy >= MAXWLEN - MB_MAXBYTES) { + if (d - (char_u *)wcopy >= MAXWLEN - MB_MAXBYTES) { break; } d += utf_char2bytes(c, (char *)d); @@ -2674,9 +2684,9 @@ void allcap_copy(char_u *word, char_u *wcopy) // Case-folding may change the number of bytes: Count nr of chars in // fword[flen] and return the byte length of that many chars in "word". -int nofold_len(char_u *fword, int flen, char_u *word) +int nofold_len(char *fword, int flen, char *word) { - char_u *p; + char *p; int i = 0; for (p = fword; p < fword + flen; MB_PTR_ADV(p)) { @@ -2689,7 +2699,7 @@ int nofold_len(char_u *fword, int flen, char_u *word) } // Copy "fword" to "cword", fixing case according to "flags". -void make_case_word(char_u *fword, char_u *cword, int flags) +void make_case_word(char *fword, char *cword, int flags) { if (flags & WF_ALLCAP) { // Make it all upper-case @@ -2719,9 +2729,9 @@ char *eval_soundfold(const char *const word) langp_T *const lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); if (!GA_EMPTY(&lp->lp_slang->sl_sal)) { // soundfold the word - char_u sound[MAXWLEN]; - spell_soundfold(lp->lp_slang, (char_u *)word, false, sound); - return xstrdup((const char *)sound); + char sound[MAXWLEN]; + spell_soundfold(lp->lp_slang, (char *)word, false, sound); + return xstrdup(sound); } } } @@ -2745,20 +2755,19 @@ char *eval_soundfold(const char *const word) /// @param[in] inword word to soundfold /// @param[in] folded whether inword is already case-folded /// @param[in,out] res destination for soundfolded word -void spell_soundfold(slang_T *slang, char_u *inword, bool folded, char_u *res) +void spell_soundfold(slang_T *slang, char *inword, bool folded, char *res) { - char_u fword[MAXWLEN]; - char_u *word; - if (slang->sl_sofo) { // SOFOFROM and SOFOTO used spell_soundfold_sofo(slang, inword, res); } else { + char fword[MAXWLEN]; + char *word; // SAL items used. Requires the word to be case-folded. if (folded) { word = inword; } else { - (void)spell_casefold(curwin, inword, (int)STRLEN(inword), fword, MAXWLEN); + (void)spell_casefold(curwin, inword, (int)strlen(inword), fword, MAXWLEN); word = fword; } @@ -2768,7 +2777,7 @@ void spell_soundfold(slang_T *slang, char_u *inword, bool folded, char_u *res) // Perform sound folding of "inword" into "res" according to SOFOFROM and // SOFOTO lines. -static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) +static void spell_soundfold_sofo(slang_T *slang, char *inword, char *res) { int ri = 0; @@ -2776,8 +2785,8 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) // The sl_sal_first[] table contains the translation for chars up to // 255, sl_sal the rest. - for (char_u *s = inword; *s != NUL;) { - int c = mb_cptr2char_adv((const char_u **)&s); + for (char *s = inword; *s != NUL;) { + int c = mb_cptr2char_adv((const char **)&s); if (utf_class(c) == 0) { c = ' '; } else if (c < 256) { @@ -2802,7 +2811,7 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) } if (c != NUL && c != prevc) { - ri += utf_char2bytes(c, (char *)res + ri); + ri += utf_char2bytes(c, res + ri); if (ri + MB_MAXBYTES > MAXWLEN) { break; } @@ -2815,34 +2824,31 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) // Turn "inword" into its sound-a-like equivalent in "res[MAXWLEN]". // Multi-byte version of spell_soundfold(). -static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) +static void spell_soundfold_wsal(slang_T *slang, const char *inword, char *res) { salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data; int word[MAXWLEN] = { 0 }; int wres[MAXWLEN] = { 0 }; - int l; int *ws; int *pf; - int i, j, z; + int j, z; int reslen; - int n, k = 0; + int k = 0; int z0; int k0; int n0; - int c; int pri; int p0 = -333; int c0; bool did_white = false; - int wordlen; // Convert the multi-byte string to a wide-character string. // Remove accents, if wanted. We actually remove all non-word characters. // But keep white space. - wordlen = 0; - for (const char_u *s = inword; *s != NUL;) { - const char_u *t = s; - c = mb_cptr2char_adv(&s); + int wordlen = 0; + for (const char *s = (char *)inword; *s != NUL;) { + const char_u *t = (char_u *)s; + int c = mb_cptr2char_adv(&s); if (slang->sl_rem_accents) { if (utf_class(c) == 0) { if (did_white) { @@ -2852,7 +2858,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) did_white = true; } else { did_white = false; - if (!spell_iswordp_nmw(t, curwin)) { + if (!spell_iswordp_nmw((char *)t, curwin)) { continue; } } @@ -2861,13 +2867,14 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) } word[wordlen] = NUL; + int c; // This algorithm comes from Aspell phonet.cpp. // Converted from C++ to C. Added support for multi-byte chars. // Changed to keep spaces. - i = reslen = z = 0; + int i = reslen = z = 0; while ((c = word[i]) != NUL) { // Start with the first rule that has the character in the word. - n = slang->sl_sal_first[c & 0xff]; + int n = slang->sl_sal_first[c & 0xff]; z0 = 0; if (n >= 0) { @@ -2875,7 +2882,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) // If c is 0x300 need extra check for the end of the array, as // (c & 0xff) is NUL. for (; ((ws = smp[n].sm_lead_w)[0] & 0xff) == (c & 0xff) - && ws[0] != NUL; ++n) { + && ws[0] != NUL; n++) { // Quickly skip entries that don't match the word. Most // entries are less than three chars, optimize for that. if (c != ws[0]) { @@ -2887,7 +2894,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) continue; } if (k > 2) { - for (j = 2; j < k; ++j) { + for (j = 2; j < k; j++) { if (word[i + j] != ws[j]) { break; } @@ -2908,7 +2915,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) } k++; } - char_u *s = smp[n].sm_rules; + char_u *s = (char_u *)smp[n].sm_rules; pri = 5; // default priority p0 = *s; @@ -2948,7 +2955,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) // Test follow-up rule for "word[i + k]"; loop over // all entries with the same index byte. for (; ((ws = smp[n0].sm_lead_w)[0] & 0xff) - == (c0 & 0xff); ++n0) { + == (c0 & 0xff); n0++) { // Quickly skip entries that don't match the word. if (c0 != ws[0]) { continue; @@ -2960,7 +2967,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) } if (k0 > 2) { pf = word + i + k + 1; - for (j = 2; j < k0; ++j) { + for (j = 2; j < k0; j++) { if (*pf++ != ws[j]) { break; } @@ -2985,7 +2992,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) } p0 = 5; - s = smp[n0].sm_rules; + s = (char_u *)smp[n0].sm_rules; while (*s == '-') { // "k0" gets NOT reduced because // "if (k0 == k)" @@ -3026,7 +3033,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) // replace string ws = smp[n].sm_to_w; - s = smp[n].sm_rules; + s = (char_u *)smp[n].sm_rules; p0 = (vim_strchr((char *)s, '<') != NULL) ? 1 : 0; if (p0 == 1 && z == 0) { // rule with '<' is used @@ -3102,9 +3109,9 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) } // Convert wide characters in "wres" to a multi-byte string in "res". - l = 0; - for (n = 0; n < reslen; n++) { - l += utf_char2bytes(wres[n], (char *)res + l); + int l = 0; + for (int n = 0; n < reslen; n++) { + l += utf_char2bytes(wres[n], res + l); if (l + MB_MAXBYTES > MAXWLEN) { break; } @@ -3143,20 +3150,19 @@ void ex_spellinfo(exarg_T *eap) // ":spelldump" void ex_spelldump(exarg_T *eap) { - char *spl; - long dummy; - if (no_spell_checking(curwin)) { return; } - (void)get_option_value("spl", &dummy, &spl, OPT_LOCAL); + char *spl; + long dummy; + (void)get_option_value("spl", &dummy, &spl, NULL, OPT_LOCAL); // Create a new empty buffer in a new window. do_cmdline_cmd("new"); // enable spelling locally in the new window - set_option_value("spell", true, "", OPT_LOCAL); - set_option_value("spl", dummy, spl, OPT_LOCAL); + set_option_value_give_err("spell", true, "", OPT_LOCAL); + set_option_value_give_err("spl", dummy, spl, OPT_LOCAL); xfree(spl); if (!buf_is_empty(curbuf)) { @@ -3169,7 +3175,7 @@ void ex_spelldump(exarg_T *eap) if (curbuf->b_ml.ml_line_count > 1) { ml_delete(curbuf->b_ml.ml_line_count, false); } - redraw_later(curwin, NOT_VALID); + redraw_later(curwin, UPD_NOT_VALID); } /// Go through all possible words and: @@ -3181,24 +3187,23 @@ void ex_spelldump(exarg_T *eap) /// @param ic ignore case /// @param dir direction for adding matches /// @param dumpflags_arg DUMPFLAG_* -void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) +void spell_dump_compl(char *pat, int ic, Direction *dir, int dumpflags_arg) { langp_T *lp; slang_T *slang; idx_T arridx[MAXWLEN]; int curi[MAXWLEN]; - char_u word[MAXWLEN]; + char word[MAXWLEN]; int c; - char_u *byts; + char *byts; idx_T *idxs; linenr_T lnum = 0; - int round; int depth; int n; int flags; - char_u *region_names = NULL; // region names being used + char *region_names = NULL; // region names being used bool do_region = true; // dump region names and numbers - char_u *p; + char *p; int dumpflags = dumpflags_arg; int patlen; @@ -3212,7 +3217,7 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) if (n == WF_ONECAP) { dumpflags |= DUMPFLAG_ONECAP; } else if (n == WF_ALLCAP - && (int)STRLEN(pat) > utfc_ptr2len((char *)pat)) { + && (int)strlen(pat) > utfc_ptr2len(pat)) { dumpflags |= DUMPFLAG_ALLCAP; } } @@ -3220,13 +3225,13 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) // Find out if we can support regions: All languages must support the same // regions or none at all. - for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) { + for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) { lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); p = lp->lp_slang->sl_regions; if (p[0] != 0) { if (region_names == NULL) { // first language with regions region_names = p; - } else if (STRCMP(region_names, p) != 0) { + } else if (strcmp(region_names, p) != 0) { do_region = false; // region names are different break; } @@ -3235,15 +3240,15 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) if (do_region && region_names != NULL) { if (pat == NULL) { - vim_snprintf((char *)IObuff, IOSIZE, "/regions=%s", region_names); - ml_append(lnum++, (char *)IObuff, (colnr_T)0, false); + vim_snprintf(IObuff, IOSIZE, "/regions=%s", region_names); + ml_append(lnum++, IObuff, (colnr_T)0, false); } } else { do_region = false; } // Loop over all files loaded for the entries in 'spelllang'. - for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) { + for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) { lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi); slang = lp->lp_slang; if (slang->sl_fbyts == NULL) { // reloading failed @@ -3251,21 +3256,21 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) } if (pat == NULL) { - vim_snprintf((char *)IObuff, IOSIZE, "# file: %s", slang->sl_fname); - ml_append(lnum++, (char *)IObuff, (colnr_T)0, false); + vim_snprintf(IObuff, IOSIZE, "# file: %s", slang->sl_fname); + ml_append(lnum++, IObuff, (colnr_T)0, false); } // When matching with a pattern and there are no prefixes only use // parts of the tree that match "pat". if (pat != NULL && slang->sl_pbyts == NULL) { - patlen = (int)STRLEN(pat); + patlen = (int)strlen(pat); } else { patlen = -1; } // round 1: case-folded tree // round 2: keep-case tree - for (round = 1; round <= 2; ++round) { + for (int round = 1; round <= 2; round++) { if (round == 1) { dumpflags &= ~DUMPFLAG_KEEPCASE; byts = slang->sl_fbyts; @@ -3291,8 +3296,8 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) } else { // Do one more byte at this node. n = arridx[depth] + curi[depth]; - ++curi[depth]; - c = byts[n]; + curi[depth]++; + c = (uint8_t)byts[n]; if (c == 0 || depth >= MAXWLEN - 1) { // End of word or reached maximum length, deal with the // word. @@ -3315,8 +3320,7 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) // when it's the first one. c = (int)((unsigned)flags >> 24); if (c == 0 || curi[depth] == 2) { - dump_word(slang, word, pat, dir, - dumpflags, flags, lnum); + dump_word(slang, word, pat, dir, dumpflags, flags, lnum); if (pat == NULL) { lnum++; } @@ -3330,7 +3334,7 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) } } else { // Normal char, go one level deeper. - word[depth++] = (char_u)c; + word[depth++] = (char)c; arridx[depth] = idxs[n]; curi[depth] = 1; @@ -3352,17 +3356,15 @@ void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg) } } -// Dumps one word: apply case modifications and append a line to the buffer. -// When "lnum" is zero add insert mode completion. -static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, int dumpflags, +/// Dumps one word: apply case modifications and append a line to the buffer. +/// When "lnum" is zero add insert mode completion. +static void dump_word(slang_T *slang, char *word, char *pat, Direction *dir, int dumpflags, int wordflags, linenr_T lnum) { bool keepcap = false; - char_u *p; - char_u *tw; - char_u cword[MAXWLEN]; - char_u badword[MAXWLEN + 10]; - int i; + char *p; + char cword[MAXWLEN]; + char badword[MAXWLEN + 10]; int flags = wordflags; if (dumpflags & DUMPFLAG_ONECAP) { @@ -3384,7 +3386,7 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, keepcap = true; } } - tw = p; + char *tw = p; if (pat == NULL) { // Add flags and regions after a slash. @@ -3400,10 +3402,10 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, STRCAT(badword, "?"); } if (flags & WF_REGION) { - for (i = 0; i < 7; i++) { + for (int i = 0; i < 7; i++) { if (flags & (0x10000 << i)) { - const size_t badword_len = STRLEN(badword); - snprintf((char *)badword + badword_len, + const size_t badword_len = strlen(badword); + snprintf(badword + badword_len, sizeof(badword) - badword_len, "%d", i + 1); } @@ -3416,19 +3418,19 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, hashitem_T *hi; // Include the word count for ":spelldump!". - hi = hash_find(&slang->sl_wordcount, (char *)tw); + hi = hash_find(&slang->sl_wordcount, tw); if (!HASHITEM_EMPTY(hi)) { - vim_snprintf((char *)IObuff, IOSIZE, "%s\t%d", + vim_snprintf(IObuff, IOSIZE, "%s\t%d", tw, HI2WC(hi)->wc_count); p = IObuff; } } - ml_append(lnum, (char *)p, (colnr_T)0, false); + ml_append(lnum, p, (colnr_T)0, false); } else if (((dumpflags & DUMPFLAG_ICASE) - ? mb_strnicmp(p, pat, STRLEN(pat)) == 0 - : STRNCMP(p, pat, STRLEN(pat)) == 0) - && ins_compl_add_infercase(p, (int)STRLEN(p), + ? mb_strnicmp(p, pat, strlen(pat)) == 0 + : strncmp(p, pat, strlen(pat)) == 0) + && ins_compl_add_infercase(p, (int)strlen(p), p_ic, NULL, *dir, false) == OK) { // if dir was BACKWARD then honor it just once *dir = FORWARD; @@ -3443,42 +3445,35 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, /// @param flags flags with prefix ID /// /// @return the updated line number. -static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Direction *dir, - int dumpflags, int flags, linenr_T startlnum) +static linenr_T dump_prefixes(slang_T *slang, char *word, char *pat, Direction *dir, int dumpflags, + int flags, linenr_T startlnum) { idx_T arridx[MAXWLEN]; int curi[MAXWLEN]; - char_u prefix[MAXWLEN]; - char_u word_up[MAXWLEN]; + char prefix[MAXWLEN]; + char word_up[MAXWLEN]; bool has_word_up = false; - int c; - char_u *byts; - idx_T *idxs; linenr_T lnum = startlnum; - int depth; - int n; - int len; - int i; // If the word starts with a lower-case letter make the word with an // upper-case letter in word_up[]. - c = utf_ptr2char((char *)word); + int c = utf_ptr2char(word); if (SPELL_TOUPPER(c) != c) { onecap_copy(word, word_up, true); has_word_up = true; } - byts = slang->sl_pbyts; - idxs = slang->sl_pidxs; + char_u *byts = (char_u *)slang->sl_pbyts; + idx_T *idxs = slang->sl_pidxs; if (byts != NULL) { // array not is empty // Loop over all prefixes, building them byte-by-byte in prefix[]. // When at the end of a prefix check that it supports "flags". - depth = 0; + int depth = 0; arridx[0] = 0; curi[0] = 1; while (depth >= 0 && !got_int) { - n = arridx[depth]; - len = byts[n]; + int n = arridx[depth]; + int len = byts[n]; if (curi[depth] > len) { // Done all bytes at this node, go up one level. depth--; @@ -3486,11 +3481,12 @@ static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Directi } else { // Do one more byte at this node. n += curi[depth]; - ++curi[depth]; + curi[depth]++; c = byts[n]; if (c == 0) { // End of prefix, find out how many IDs there are. - for (i = 1; i < len; ++i) { + int i; + for (i = 1; i < len; i++) { if (byts[n + i] != 0) { break; } @@ -3499,10 +3495,9 @@ static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Directi c = valid_word_prefix(i, n, flags, word, slang, false); if (c != 0) { - STRLCPY(prefix + depth, word, MAXWLEN - depth); + xstrlcpy(prefix + depth, word, (size_t)(MAXWLEN - depth)); dump_word(slang, prefix, pat, dir, dumpflags, - (c & WF_RAREPFX) ? (flags | WF_RARE) - : flags, lnum); + (c & WF_RAREPFX) ? (flags | WF_RARE) : flags, lnum); if (lnum != 0) { lnum++; } @@ -3512,13 +3507,11 @@ static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Directi // first letter is upper-case, but only if the prefix has // a condition. if (has_word_up) { - c = valid_word_prefix(i, n, flags, word_up, slang, - true); + c = valid_word_prefix(i, n, flags, word_up, slang, true); if (c != 0) { - STRLCPY(prefix + depth, word_up, MAXWLEN - depth); + xstrlcpy(prefix + depth, word_up, (size_t)(MAXWLEN - depth)); dump_word(slang, prefix, pat, dir, dumpflags, - (c & WF_RAREPFX) ? (flags | WF_RARE) - : flags, lnum); + (c & WF_RAREPFX) ? (flags | WF_RARE) : flags, lnum); if (lnum != 0) { lnum++; } @@ -3526,7 +3519,7 @@ static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Directi } } else { // Normal char, go one level deeper. - prefix[depth++] = (char_u)c; + prefix[depth++] = (char)c; arridx[depth] = idxs[n]; curi[depth] = 1; } @@ -3539,9 +3532,9 @@ static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Directi // Move "p" to the end of word "start". // Uses the spell-checking word characters. -char_u *spell_to_word_end(char_u *start, win_T *win) +char *spell_to_word_end(char *start, win_T *win) { - char_u *p = start; + char *p = start; while (*p != NUL && spell_iswordp(p, win)) { MB_PTR_ADV(p); @@ -3556,16 +3549,14 @@ char_u *spell_to_word_end(char_u *start, win_T *win) // Returns the column number of the word. int spell_word_start(int startcol) { - char_u *line; - char_u *p; - int col = 0; - if (no_spell_checking(curwin)) { return startcol; } + char *line = get_cursor_line_ptr(); + char *p; + // Find a word character before "startcol". - line = get_cursor_line_ptr(); for (p = line + startcol; p > line;) { MB_PTR_BACK(line, p); if (spell_iswordp_nmw(p, curwin)) { @@ -3573,6 +3564,8 @@ int spell_word_start(int startcol) } } + int col = 0; + // Go back to start of the word. while (p > line) { col = (int)(p - line); @@ -3599,7 +3592,7 @@ void spell_expand_check_cap(colnr_T col) // Used for Insert mode completion CTRL-X ?. // Returns the number of matches. The matches are in "matchp[]", array of // allocated strings. -int expand_spelling(linenr_T lnum, char_u *pat, char ***matchp) +int expand_spelling(linenr_T lnum, char *pat, char ***matchp) { garray_T ga; @@ -3608,19 +3601,19 @@ int expand_spelling(linenr_T lnum, char_u *pat, char ***matchp) return ga.ga_len; } -/// Return true if "val" is a valid 'spelllang' value. -bool valid_spelllang(const char_u *val) +/// @return true if "val" is a valid 'spelllang' value. +bool valid_spelllang(const char *val) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return valid_name(val, ".-_,@"); } -/// Return true if "val" is a valid 'spellfile' value. -bool valid_spellfile(const char_u *val) +/// @return true if "val" is a valid 'spellfile' value. +bool valid_spellfile(const char *val) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - for (const char_u *s = val; *s != NUL; s++) { - if (!vim_isfilec(*s) && *s != ',' && *s != ' ') { + for (const char *s = val; *s != NUL; s++) { + if (!vim_isfilec((uint8_t)(*s)) && *s != ',' && *s != ' ') { return false; } } @@ -3632,22 +3625,23 @@ char *did_set_spell_option(bool is_spellfile) char *errmsg = NULL; if (is_spellfile) { - int l = (int)STRLEN(curwin->w_s->b_p_spf); + int l = (int)strlen(curwin->w_s->b_p_spf); if (l > 0 - && (l < 4 || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) { + && (l < 4 || strcmp(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) { errmsg = e_invarg; } } - if (errmsg == NULL) { - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == curbuf && wp->w_p_spell) { - errmsg = did_set_spelllang(wp); - break; - } - } + if (errmsg != NULL) { + return errmsg; } + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_buffer == curbuf && wp->w_p_spell) { + errmsg = did_set_spelllang(wp); + break; + } + } return errmsg; } @@ -3657,14 +3651,13 @@ char *compile_cap_prog(synblock_T *synblock) FUNC_ATTR_NONNULL_ALL { regprog_T *rp = synblock->b_cap_prog; - char_u *re; if (synblock->b_p_spc == NULL || *synblock->b_p_spc == NUL) { synblock->b_cap_prog = NULL; } else { // Prepend a ^ so that we only match at one column - re = concat_str((char_u *)"^", synblock->b_p_spc); - synblock->b_cap_prog = vim_regcomp((char *)re, RE_MAGIC); + char *re = concat_str("^", synblock->b_p_spc); + synblock->b_cap_prog = vim_regcomp(re, RE_MAGIC); xfree(re); if (synblock->b_cap_prog == NULL) { synblock->b_cap_prog = rp; // restore the previous program |