diff options
Diffstat (limited to 'src/spell.c')
-rw-r--r-- | src/spell.c | 223 |
1 files changed, 150 insertions, 73 deletions
diff --git a/src/spell.c b/src/spell.c index 015a7108b..f23cf9866 100644 --- a/src/spell.c +++ b/src/spell.c @@ -192,7 +192,10 @@ * <flags> 1 byte bitmask of: * WF_ALLCAP word must have only capitals * WF_ONECAP first char of word must be capital + * WF_KEEPCAP keep-case word + * WF_FIXCAP keep-case word, all caps not allowed * WF_RARE rare word + * WF_BANNED bad word * WF_REGION <region> follows * WF_PFX <prefixID> follows * @@ -241,9 +244,10 @@ typedef long idx_T; #define WF_RARE 0x08 /* rare word */ #define WF_BANNED 0x10 /* bad word */ #define WF_PFX 0x20 /* prefix ID list follows */ +#define WF_FIXCAP 0x40 /* keep-case word, allcap not allowed */ #define WF_KEEPCAP 0x80 /* keep-case word */ -#define WF_CAPMASK (WF_ONECAP | WF_ALLCAP | WF_KEEPCAP) +#define WF_CAPMASK (WF_ONECAP | WF_ALLCAP | WF_KEEPCAP | WF_FIXCAP) #define WF_RAREPFX 0x1000000 /* in sl_pidxs: flag for rare postponed prefix; must be above prefixID (one byte) @@ -584,14 +588,14 @@ static void find_word __ARGS((matchinf_T *mip, int mode)); static int valid_word_prefix __ARGS((int totprefcnt, int arridx, int prefid, char_u *word, slang_T *slang)); static void find_prefix __ARGS((matchinf_T *mip)); static int fold_more __ARGS((matchinf_T *mip)); -static int spell_valid_case __ARGS((int origflags, int treeflags)); +static int spell_valid_case __ARGS((int wordflags, int treeflags)); static int no_spell_checking __ARGS((void)); static void spell_load_lang __ARGS((char_u *lang)); static char_u *spell_enc __ARGS((void)); static void int_wordlist_spl __ARGS((char_u *fname)); static void spell_load_cb __ARGS((char_u *fname, void *cookie)); static slang_T *spell_load_file __ARGS((char_u *fname, char_u *lang, slang_T *old_lp, int silent)); -static char_u *read_cnt_string __ARGS((FILE *fd, int cnt_bytes, int *errp)); +static char_u *read_cnt_string __ARGS((FILE *fd, int cnt_bytes, int *lenp)); static int set_sofo __ARGS((slang_T *lp, char_u *from, char_u *to)); static void set_sal_first __ARGS((slang_T *lp)); #ifdef FEAT_MBYTE @@ -603,7 +607,7 @@ static void use_midword __ARGS((slang_T *lp, buf_T *buf)); static int find_region __ARGS((char_u *rp, char_u *region)); static int captype __ARGS((char_u *word, char_u *end)); static void spell_reload_one __ARGS((char_u *fname, int added_word)); -static int set_spell_charflags __ARGS((char_u *flags, char_u *upp)); +static int set_spell_charflags __ARGS((char_u *flags, int cnt, char_u *upp)); static int set_spell_chartab __ARGS((char_u *fol, char_u *low, char_u *upp)); static void write_spell_chartab __ARGS((FILE *fd)); static int spell_casefold __ARGS((char_u *p, int len, char_u *buf, int buflen)); @@ -1293,13 +1297,13 @@ fold_more(mip) * case. */ static int -spell_valid_case(origflags, treeflags) - int origflags; /* flags for the checked word. */ +spell_valid_case(wordflags, treeflags) + int wordflags; /* flags for the checked word. */ int treeflags; /* flags for the word in the spell tree */ { - return (origflags == WF_ALLCAP + return ((wordflags == WF_ALLCAP && (treeflags & WF_FIXCAP) == 0) || ((treeflags & (WF_ALLCAP | WF_KEEPCAP)) == 0 - && ((treeflags & WF_ONECAP) == 0 || origflags == WF_ONECAP))); + && ((treeflags & WF_ONECAP) == 0 || wordflags == WF_ONECAP))); } /* @@ -1837,12 +1841,12 @@ formerr: /* <charflagslen> <charflags> */ p = read_cnt_string(fd, 1, &cnt); - if (cnt == FAIL) + if (cnt < 0) goto endFAIL; /* <fcharslen> <fchars> */ - fol = read_cnt_string(fd, 2, &cnt); - if (cnt == FAIL) + fol = read_cnt_string(fd, 2, &ccnt); + if (ccnt < 0) { vim_free(p); goto endFAIL; @@ -1850,7 +1854,7 @@ formerr: /* Set the word-char flags and fill SPELL_ISUPPER() table. */ if (p != NULL && fol != NULL) - i = set_spell_charflags(p, fol); + i = set_spell_charflags(p, cnt, fol); vim_free(p); vim_free(fol); @@ -1861,7 +1865,7 @@ formerr: /* <midwordlen> <midword> */ lp->sl_midword = read_cnt_string(fd, 2, &cnt); - if (cnt == FAIL) + if (cnt < 0) goto endFAIL; /* <prefcondcnt> <prefcond> ... */ @@ -1912,10 +1916,10 @@ formerr: { ftp = &((fromto_T *)gap->ga_data)[gap->ga_len]; ftp->ft_from = read_cnt_string(fd, 1, &i); - if (i == FAIL) + if (i <= 0) goto endFAIL; ftp->ft_to = read_cnt_string(fd, 1, &i); - if (i == FAIL) + if (i <= 0) { vim_free(ftp->ft_from); goto endFAIL; @@ -1942,6 +1946,8 @@ formerr: lp->sl_rem_accents = TRUE; if (i & SAL_SOFO) lp->sl_sofo = TRUE; + else + lp->sl_sofo = FALSE; cnt = (getc(fd) << 8) + getc(fd); /* <salcount> */ if (cnt < 0) @@ -1957,19 +1963,24 @@ formerr: /* <salfromlen> <salfrom> */ bp = read_cnt_string(fd, 2, &cnt); - if (cnt == FAIL) + if (cnt < 0) goto endFAIL; /* <saltolen> <salto> */ fol = read_cnt_string(fd, 2, &cnt); - if (cnt == FAIL) + if (cnt < 0) { vim_free(bp); goto endFAIL; } /* Store the info in lp->sl_sal and/or lp->sl_sal_first. */ - i = set_sofo(lp, bp, fol); + if (bp != NULL && fol != NULL) + i = set_sofo(lp, bp, fol); + else if (bp != NULL || fol != NULL) + i = FAIL; /* only one of two strings is an error */ + else + i = OK; vim_free(bp); vim_free(fol); @@ -2036,7 +2047,7 @@ formerr: /* <saltolen> <salto> */ smp->sm_to = read_cnt_string(fd, 1, &ccnt); - if (ccnt == FAIL) + if (ccnt < 0) { vim_free(smp->sm_lead); goto formerr; @@ -2052,10 +2063,13 @@ formerr: smp->sm_oneof_w = NULL; else smp->sm_oneof_w = mb_str2wide(smp->sm_oneof); - smp->sm_to_w = mb_str2wide(smp->sm_to); + if (smp->sm_to == NULL) + smp->sm_to_w = NULL; + else + smp->sm_to_w = mb_str2wide(smp->sm_to); if (smp->sm_lead_w == NULL || (smp->sm_oneof_w == NULL && smp->sm_oneof != NULL) - || smp->sm_to_w == NULL) + || (smp->sm_to_w == NULL && smp->sm_to != NULL)) { vim_free(smp->sm_lead); vim_free(smp->sm_to); @@ -2074,11 +2088,13 @@ formerr: /* <maplen> <mapstr> */ p = read_cnt_string(fd, 2, &cnt); - if (cnt == FAIL) + if (cnt < 0) goto endFAIL; - set_map_str(lp, p); - vim_free(p); - + if (p != NULL) + { + set_map_str(lp, p); + vim_free(p); + } /* round 1: <LWORDTREE> * round 2: <KWORDTREE> @@ -2155,13 +2171,13 @@ endOK: * Read a length field from "fd" in "cnt_bytes" bytes. * Allocate memory, read the string into it and add a NUL at the end. * Returns NULL when the count is zero. - * Sets "*errp" to FAIL when there is an error, OK otherwise. + * Sets "*cntp" to -1 when there is an error, length of the result otherwise. */ static char_u * -read_cnt_string(fd, cnt_bytes, errp) +read_cnt_string(fd, cnt_bytes, cntp) FILE *fd; int cnt_bytes; - int *errp; + int *cntp; { int cnt = 0; int i; @@ -2173,18 +2189,20 @@ read_cnt_string(fd, cnt_bytes, errp) if (cnt < 0) { EMSG(_(e_spell_trunc)); - *errp = FAIL; + *cntp = -1; return NULL; } + *cntp = cnt; + if (cnt == 0) + return NULL; /* nothing to read, return NULL */ /* allocate memory */ str = alloc((unsigned)cnt + 1); if (str == NULL) { - *errp = FAIL; + *cntp = -1; return NULL; } - *errp = OK; /* Read the string. Doesn't check for truncated file. */ for (i = 0; i < cnt; ++i) @@ -2512,6 +2530,8 @@ did_set_spelllang(buf) char_u *p; int round; char_u *spf; + char_u *use_region = NULL; + int dont_use_region = FALSE; ga_init2(&ga, sizeof(langp_T), 2); clear_midword(buf); @@ -2545,7 +2565,15 @@ did_set_spelllang(buf) region = lang + len - 2; len -= 3; lang[len] = NUL; + + /* 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) + dont_use_region = TRUE; + use_region = region; } + else + dont_use_region = TRUE; /* Check if we loaded this language before. */ for (lp = first_lang; lp != NULL; lp = lp->sl_next) @@ -2576,7 +2604,15 @@ did_set_spelllang(buf) c = find_region(lp->sl_regions, region); if (c == REGION_ALL) { - if (!lp->sl_add) + if (lp->sl_add) + { + if (*lp->sl_regions != NUL) + /* This addition file is for other regions. */ + region_mask = 0; + } + else + /* This is probably an error. Give a warning and + * accept the words anyway. */ smsg((char_u *) _("Warning: region %s not supported"), region); @@ -2585,15 +2621,18 @@ did_set_spelllang(buf) region_mask = 1 << c; } - if (ga_grow(&ga, 1) == FAIL) + if (region_mask != 0) { - ga_clear(&ga); - return e_outofmem; + if (ga_grow(&ga, 1) == FAIL) + { + ga_clear(&ga); + return e_outofmem; + } + LANGP_ENTRY(ga, ga.ga_len)->lp_slang = lp; + LANGP_ENTRY(ga, ga.ga_len)->lp_region = region_mask; + ++ga.ga_len; + use_midword(lp, buf); } - LANGP_ENTRY(ga, ga.ga_len)->lp_slang = lp; - LANGP_ENTRY(ga, ga.ga_len)->lp_region = region_mask; - ++ga.ga_len; - use_midword(lp, buf); } } @@ -2649,10 +2688,25 @@ did_set_spelllang(buf) } if (lp != NULL && ga_grow(&ga, 1) == OK) { - LANGP_ENTRY(ga, ga.ga_len)->lp_slang = lp; - LANGP_ENTRY(ga, ga.ga_len)->lp_region = REGION_ALL; - ++ga.ga_len; - use_midword(lp, buf); + region_mask = REGION_ALL; + if (use_region != NULL && !dont_use_region) + { + /* find region in sl_regions */ + c = find_region(lp->sl_regions, use_region); + if (c != REGION_ALL) + region_mask = 1 << c; + else if (*lp->sl_regions != NUL) + /* This spell file is for other regions. */ + region_mask = 0; + } + + if (region_mask != 0) + { + LANGP_ENTRY(ga, ga.ga_len)->lp_slang = lp; + LANGP_ENTRY(ga, ga.ga_len)->lp_region = region_mask; + ++ga.ga_len; + use_midword(lp, buf); + } } } @@ -2697,6 +2751,9 @@ use_midword(lp, buf) { char_u *p; + if (lp->sl_midword == NULL) /* there aren't any */ + return; + for (p = lp->sl_midword; *p != NUL; ) #ifdef FEAT_MBYTE if (has_mbyte) @@ -3799,7 +3856,7 @@ spell_read_dic(fname, spin, affile) * for rare word (if defined). */ if (affile->af_kep != NUL && vim_strchr(afflist, affile->af_kep) != NULL) - flags |= WF_KEEPCAP; + flags |= WF_KEEPCAP | WF_FIXCAP; if (affile->af_rar != NUL && vim_strchr(afflist, affile->af_rar) != NULL) flags |= WF_RARE; @@ -4150,6 +4207,9 @@ spell_read_wordfile(fname, spin) { spin->si_region_count = STRLEN(line) / 2; STRCPY(spin->si_region_name, line); + + /* Adjust the mask for a word valid in all regions. */ + spin->si_region = (1 << spin->si_region_count) - 1; } } continue; @@ -4171,7 +4231,7 @@ spell_read_wordfile(fname, spin) while (*p != NUL) { if (*p == '=') /* keep-case word */ - flags |= WF_KEEPCAP; + flags |= WF_KEEPCAP | WF_FIXCAP; else if (*p == '!') /* Bad, bad, wicked word. */ flags |= WF_BANNED; else if (*p == '?') /* Rare word. */ @@ -5604,34 +5664,39 @@ set_spell_chartab(fol, low, upp) * Set the spell character tables from strings in the .spl file. */ static int -set_spell_charflags(flags, upp) +set_spell_charflags(flags, cnt, fol) char_u *flags; - char_u *upp; + int cnt; /* length of "flags" */ + char_u *fol; { /* We build the new tables here first, so that we can compare with the * previous one. */ spelltab_T new_st; int i; - char_u *p = upp; + char_u *p = fol; int c; clear_spell_chartab(&new_st); - for (i = 0; flags[i] != NUL; ++i) + for (i = 0; i < 128; ++i) { - new_st.st_isw[i + 128] = (flags[i] & CF_WORD) != 0; - new_st.st_isu[i + 128] = (flags[i] & CF_UPPER) != 0; + if (i < cnt) + { + new_st.st_isw[i + 128] = (flags[i] & CF_WORD) != 0; + new_st.st_isu[i + 128] = (flags[i] & CF_UPPER) != 0; + } - if (*p == NUL) - return FAIL; + if (*p != NUL) + { #ifdef FEAT_MBYTE - c = mb_ptr2char_adv(&p); + c = mb_ptr2char_adv(&p); #else - c = *p++; + c = *p++; #endif - new_st.st_fold[i + 128] = c; - if (i + 128 != c && new_st.st_isu[i + 128] && c < 256) - new_st.st_upper[c] = i + 128; + new_st.st_fold[i + 128] = c; + if (i + 128 != c && new_st.st_isu[i + 128] && c < 256) + new_st.st_upper[c] = i + 128; + } } return set_spell_finish(&new_st); @@ -7992,6 +8057,8 @@ suggest_try_soundalike(su) { byts = lp->lp_slang->sl_kbyts; idxs = lp->lp_slang->sl_kidxs; + if (byts == NULL) /* no keep-case words */ + continue; } depth = 0; @@ -8836,6 +8903,8 @@ spell_soundfold_sal(slang, inword, res) /* replace string */ s = smp[n].sm_to; + if (s == NULL) + s = (char_u *)""; pf = smp[n].sm_rules; p0 = (vim_strchr(pf, '<') != NULL) ? 1 : 0; if (p0 == 1 && z == 0) @@ -9138,18 +9207,20 @@ spell_soundfold_wsal(slang, inword, res) if (p0 == 1 && z == 0) { /* rule with '<' is used */ - if (reslen > 0 && *ws != NUL && (wres[reslen - 1] == c + if (reslen > 0 && ws != NULL && *ws != NUL + && (wres[reslen - 1] == c || wres[reslen - 1] == *ws)) reslen--; z0 = 1; z = 1; k0 = 0; - while (*ws != NUL && word[i + k0] != NUL) - { - word[i + k0] = *ws; - k0++; - ws++; - } + if (ws != NULL) + while (*ws != NUL && word[i + k0] != NUL) + { + word[i + k0] = *ws; + k0++; + ws++; + } if (k > k0) mch_memmove(word + i + k0, word + i + k, sizeof(int) * (STRLEN(word + i + k) + 1)); @@ -9162,14 +9233,19 @@ spell_soundfold_wsal(slang, inword, res) /* no '<' rule used */ i += k - 1; z = 0; - while (*ws != NUL && ws[1] != NUL && reslen < MAXWLEN) - { - if (reslen == 0 || wres[reslen - 1] != *ws) - wres[reslen++] = *ws; - ws++; - } + if (ws != NULL) + while (*ws != NUL && ws[1] != NUL + && reslen < MAXWLEN) + { + if (reslen == 0 || wres[reslen - 1] != *ws) + wres[reslen++] = *ws; + ws++; + } /* new "actual letter" */ - c = *ws; + if (ws == NULL) + c = NUL; + else + c = *ws; if (strstr((char *)s, "^^") != NULL) { if (c != NUL) @@ -9722,7 +9798,8 @@ dump_word(word, round, flags, lnum) else { p = word; - if (round == 2 && (captype(word, NULL) & WF_KEEPCAP) == 0) + if (round == 2 && ((captype(word, NULL) & WF_KEEPCAP) == 0 + || (flags & WF_FIXCAP) != 0)) keepcap = TRUE; } |