Mercurial > vim
diff src/spell.c @ 474:a5fcf36ef512 v7.0127
updated for version 7.0127
author | vimboss |
---|---|
date | Wed, 10 Aug 2005 21:07:57 +0000 |
parents | bb99638a7b5f |
children | e6dfeb0a0f53 |
line wrap: on
line diff
--- a/src/spell.c +++ b/src/spell.c @@ -51,8 +51,9 @@ */ /* Use SPELL_PRINTTREE for debugging: dump the word tree after adding a word. - * Only use for small word lists! - * SPELL_COMPRESS_CNT is in how many words we compress the tree. */ + * Only use it for small word lists! + * SPELL_COMPRESS_CNT is in how many words we compress the tree to limit the + * amount of memory used (esp. for Italian). */ #if 0 # define SPELL_PRINTTREE # define SPELL_COMPRESS_CNT 1 @@ -639,6 +640,7 @@ static void clear_midword __ARGS((buf_T 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 int badword_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, int cnt, char_u *upp)); static int set_spell_chartab __ARGS((char_u *fol, char_u *low, char_u *upp)); @@ -722,7 +724,7 @@ static linenr_T apply_prefixes __ARGS((s : (c) < 256 ? spelltab.st_isu[c] : iswupper(c)) # else # define SPELL_ISUPPER(c) (enc_utf8 && (c) >= 128 ? utf_isupper(c) \ - : (c) < 256 ? spelltab.st_isu[c] : (c)) + : (c) < 256 ? spelltab.st_isu[c] : (FALSE)) # endif #endif @@ -873,7 +875,7 @@ spell_check(wp, ptr, attrp, capcol) #ifdef FEAT_MBYTE if (has_mbyte) - return mb_ptr2len_check(ptr); + return (*mb_ptr2len)(ptr); #endif return 1; } @@ -1358,7 +1360,8 @@ spell_valid_case(wordflags, treeflags) { return ((wordflags == WF_ALLCAP && (treeflags & WF_FIXCAP) == 0) || ((treeflags & (WF_ALLCAP | WF_KEEPCAP)) == 0 - && ((treeflags & WF_ONECAP) == 0 || wordflags == WF_ONECAP))); + && ((treeflags & WF_ONECAP) == 0 + || (wordflags & WF_ONECAP) != 0))); } /* @@ -2303,8 +2306,8 @@ set_sofo(lp, from, to) * sl_sal_first[] for this. */ for (p = from, s = to; *p != NUL && *s != NUL; ) { - c = mb_ptr2char_adv(&p); - mb_ptr_adv(s); + c = mb_cptr2char_adv(&p); + mb_cptr_adv(s); if (c >= 256) ++lp->sl_sal_first[c & 0xff]; } @@ -2327,8 +2330,8 @@ set_sofo(lp, from, to) vim_memset(lp->sl_sal_first, 0, sizeof(salfirst_T) * 256); for (p = from, s = to; *p != NUL && *s != NUL; ) { - c = mb_ptr2char_adv(&p); - i = mb_ptr2char_adv(&s); + c = mb_cptr2char_adv(&p); + i = mb_cptr2char_adv(&s); if (c >= 256) { /* Append the from-to chars at the end of the list with @@ -2840,8 +2843,8 @@ use_midword(lp, buf) char_u *bp; c = mb_ptr2char(p); - l = mb_ptr2len_check(p); - if (c < 256) + l = (*mb_ptr2len)(p); + if (c < 256 && l <= 2) buf->b_spell_ismw[c] = TRUE; else if (buf->b_spell_ismw_mb == NULL) /* First multi-byte char in "b_spell_ismw_mb". */ @@ -2945,6 +2948,50 @@ captype(word, end) return 0; } +/* + * Like captype() but for a KEEPCAP word add ONECAP if the word starts with a + * capital. So that make_case_word() can turn WOrd into Word. + * Add ALLCAP for "WOrD". + */ + static int +badword_captype(word, end) + char_u *word; + char_u *end; +{ + int flags = captype(word, end); + int l, u; + int first; + char_u *p; + + if (flags & WF_KEEPCAP) + { + /* Count the number of UPPER and lower case letters. */ + l = u = 0; + first = FALSE; + for (p = word; p < end; mb_ptr_adv(p)) + { + if (SPELL_ISUPPER(PTR2CHAR(p))) + { + ++u; + if (p == word) + first = TRUE; + } + else + ++l; + } + + /* If there are more UPPER than lower case letters suggest an + * ALLCAP word. Otherwise, if the first letter is UPPER then + * suggest ONECAP. Exception: "ALl" most likely should be "All", + * require three upper case letters. */ + if (u > l && u > 2) + flags |= WF_ALLCAP; + else if (first) + flags |= WF_ONECAP; + } + return flags; +} + # if defined(FEAT_MBYTE) || defined(EXITFREE) || defined(PROTO) /* * Free all languages. @@ -3097,8 +3144,8 @@ typedef struct affheader_S /* * Structure that is used to store the items in the word tree. This avoids - * the need to keep track of each allocated thing, it's freed all at once - * after ":mkspell" is done. + * the need to keep track of each allocated thing, everything is freed all at + * once after ":mkspell" is done. */ #define SBLOCKSIZE 16000 /* size of sb_data */ typedef struct sblock_S sblock_T; @@ -3129,7 +3176,10 @@ struct wordnode_S wordnode_T *wn_child; /* child (next byte in word) */ wordnode_T *wn_sibling; /* next sibling (alternate byte in word, always sorted) */ - int wn_refs; /* nr of references to this node */ + int wn_refs; /* Nr. of references to this node. Only + relevant for first node in a list of + siblings, in following siblings it is + always one. */ char_u wn_byte; /* Byte for this node. NUL for word end */ char_u wn_prefixID; /* when "wn_byte" is NUL: supported/required prefix ID or 0 */ @@ -3152,10 +3202,22 @@ typedef struct spellinfo_S { wordnode_T *si_foldroot; /* tree with case-folded words */ long si_foldwcount; /* nr of words in si_foldroot */ + int si_fold_added; /* nr of words added since compressing */ + wordnode_T *si_keeproot; /* tree with keep-case words */ long si_keepwcount; /* nr of words in si_keeproot */ + int si_keep_added; /* nr of words added since compressing */ + wordnode_T *si_prefroot; /* tree with postponed prefixes */ + sblock_T *si_blocks; /* memory blocks used */ + wordnode_T *si_first_free; /* List of nodes that have been freed during + compression, linked by "wn_child" field. */ +#ifdef SPELL_PRINTTREE + int si_wordnode_nr; /* sequence nr for nodes */ +#endif + + int si_ascii; /* handling only ASCII words */ int si_add; /* addition file */ int si_clear_chartab; /* when TRUE clear char tables */ @@ -3163,6 +3225,7 @@ typedef struct spellinfo_S vimconv_T si_conv; /* for conversion to 'encoding' */ int si_memtot; /* runtime memory used */ int si_verbose; /* verbose messages */ + int si_msg_count; /* number of words added since last message */ int si_region_count; /* number of regions supported (1 when there are no regions) */ char_u si_region_name[16]; /* region names (if count > 1) */ @@ -3181,28 +3244,29 @@ typedef struct spellinfo_S int si_newID; /* current value for ah_newID */ } spellinfo_T; -static afffile_T *spell_read_aff __ARGS((char_u *fname, spellinfo_T *spin)); +static afffile_T *spell_read_aff __ARGS((spellinfo_T *spin, char_u *fname)); static int str_equal __ARGS((char_u *s1, char_u *s2)); static void add_fromto __ARGS((spellinfo_T *spin, garray_T *gap, char_u *from, char_u *to)); static int sal_to_bool __ARGS((char_u *s)); static int has_non_ascii __ARGS((char_u *s)); static void spell_free_aff __ARGS((afffile_T *aff)); -static int spell_read_dic __ARGS((char_u *fname, spellinfo_T *spin, afffile_T *affile)); -static char_u *get_pfxlist __ARGS((afffile_T *affile, char_u *afflist, sblock_T **blp)); -static int store_aff_word __ARGS((char_u *word, spellinfo_T *spin, char_u *afflist, afffile_T *affile, hashtab_T *ht, hashtab_T *xht, int comb, int flags, char_u *pfxlist)); -static int spell_read_wordfile __ARGS((char_u *fname, spellinfo_T *spin)); -static void *getroom __ARGS((sblock_T **blp, size_t len, int align)); -static char_u *getroom_save __ARGS((sblock_T **blp, char_u *s)); +static int spell_read_dic __ARGS((spellinfo_T *spin, char_u *fname, afffile_T *affile)); +static char_u *get_pfxlist __ARGS((spellinfo_T *spin, afffile_T *affile, char_u *afflist)); +static int store_aff_word __ARGS((spellinfo_T *spin, char_u *word, char_u *afflist, afffile_T *affile, hashtab_T *ht, hashtab_T *xht, int comb, int flags, char_u *pfxlist)); +static int spell_read_wordfile __ARGS((spellinfo_T *spin, char_u *fname)); +static void *getroom __ARGS((spellinfo_T *spin, size_t len, int align)); +static char_u *getroom_save __ARGS((spellinfo_T *spin, char_u *s)); static void free_blocks __ARGS((sblock_T *bl)); -static wordnode_T *wordtree_alloc __ARGS((sblock_T **blp)); -static int store_word __ARGS((char_u *word, spellinfo_T *spin, int flags, int region, char_u *pfxlist)); -static int tree_add_word __ARGS((char_u *word, wordnode_T *tree, int flags, int region, int prefixID, spellinfo_T *spin)); -static wordnode_T *get_wordnode __ARGS((sblock_T **blp)); -static void free_wordnode __ARGS((wordnode_T *n)); -static void wordtree_compress __ARGS((wordnode_T *root, spellinfo_T *spin)); -static int node_compress __ARGS((wordnode_T *node, hashtab_T *ht, int *tot)); +static wordnode_T *wordtree_alloc __ARGS((spellinfo_T *spin)); +static int store_word __ARGS((spellinfo_T *spin, char_u *word, int flags, int region, char_u *pfxlist)); +static int tree_add_word __ARGS((spellinfo_T *spin, char_u *word, wordnode_T *tree, int flags, int region, int prefixID)); +static wordnode_T *get_wordnode __ARGS((spellinfo_T *spin)); +static void deref_wordnode __ARGS((spellinfo_T *spin, wordnode_T *node)); +static void free_wordnode __ARGS((spellinfo_T *spin, wordnode_T *n)); +static void wordtree_compress __ARGS((spellinfo_T *spin, wordnode_T *root)); +static int node_compress __ARGS((spellinfo_T *spin, wordnode_T *node, hashtab_T *ht, int *tot)); static int node_equal __ARGS((wordnode_T *n1, wordnode_T *n2)); -static void write_vim_spell __ARGS((char_u *fname, spellinfo_T *spin)); +static void write_vim_spell __ARGS((spellinfo_T *spin, char_u *fname)); static void clear_node __ARGS((wordnode_T *node)); static int put_node __ARGS((FILE *fd, wordnode_T *node, int index, int regionmask, int prefixtree)); static void mkspell __ARGS((int fcount, char_u **fnames, int ascii, int overwrite, int added_word)); @@ -3213,8 +3277,6 @@ static void init_spellfile __ARGS((void) * Use a negative number with the lower 8 bits zero. */ #define PFX_FLAGS -256 -static int words_added = 0; /* number of words added to tree */ - #ifdef SPELL_PRINTTREE /* * For debugging the tree code: print the current tree in a (more or less) @@ -3321,9 +3383,9 @@ spell_print_tree(wordnode_T *root) * Returns an afffile_T, NULL for complete failure. */ static afffile_T * -spell_read_aff(fname, spin) +spell_read_aff(spin, fname) + spellinfo_T *spin; char_u *fname; - spellinfo_T *spin; { FILE *fd; afffile_T *aff; @@ -3389,7 +3451,7 @@ spell_read_aff(fname, spin) /* * Allocate and init the afffile_T structure. */ - aff = (afffile_T *)getroom(&spin->si_blocks, sizeof(afffile_T), TRUE); + aff = (afffile_T *)getroom(spin, sizeof(afffile_T), TRUE); if (aff == NULL) return NULL; hash_init(&aff->af_pref); @@ -3516,14 +3578,14 @@ spell_read_aff(fname, spin) fname, lnum, items[4]); /* New affix letter. */ - cur_aff = (affheader_T *)getroom(&spin->si_blocks, + cur_aff = (affheader_T *)getroom(spin, sizeof(affheader_T), TRUE); if (cur_aff == NULL) break; #ifdef FEAT_MBYTE if (has_mbyte) { - l = mb_ptr2len_check(items[1]); + l = (*mb_ptr2len)(items[1]); if (l >= AH_KEY_LEN) l = 1; /* too long, must be an overlong sequence */ else @@ -3591,18 +3653,16 @@ spell_read_aff(fname, spin) /* New item for an affix letter. */ --aff_todo; - aff_entry = (affentry_T *)getroom(&spin->si_blocks, + aff_entry = (affentry_T *)getroom(spin, sizeof(affentry_T), TRUE); if (aff_entry == NULL) break; aff_entry->ae_rare = rare; if (STRCMP(items[2], "0") != 0) - aff_entry->ae_chop = getroom_save(&spin->si_blocks, - items[2]); + aff_entry->ae_chop = getroom_save(spin, items[2]); if (STRCMP(items[3], "0") != 0) - aff_entry->ae_add = getroom_save(&spin->si_blocks, - items[3]); + aff_entry->ae_add = getroom_save(spin, items[3]); /* Don't use an affix entry with non-ASCII characters when * "spin->si_ascii" is TRUE. */ @@ -3616,8 +3676,7 @@ spell_read_aff(fname, spin) { char_u buf[MAXLINELEN]; - aff_entry->ae_cond = getroom_save(&spin->si_blocks, - items[4]); + aff_entry->ae_cond = getroom_save(spin, items[4]); if (*items[0] == 'P') sprintf((char *)buf, "^%s", items[4]); else @@ -3638,7 +3697,7 @@ spell_read_aff(fname, spin) if (aff_entry->ae_chop != NULL && aff_entry->ae_add != NULL #ifdef FEAT_MBYTE - && aff_entry->ae_chop[mb_ptr2len_check( + && aff_entry->ae_chop[(*mb_ptr2len)( aff_entry->ae_chop)] == NUL #else && aff_entry->ae_chop[1] == NUL @@ -3673,7 +3732,7 @@ spell_read_aff(fname, spin) { onecap_copy(items[4], buf, TRUE); aff_entry->ae_cond = getroom_save( - &spin->si_blocks, buf); + spin, buf); } else #endif @@ -3713,7 +3772,7 @@ spell_read_aff(fname, spin) if (aff_entry->ae_cond == NULL) *pp = NULL; else - *pp = getroom_save(&spin->si_blocks, + *pp = getroom_save(spin, aff_entry->ae_cond); } @@ -3731,8 +3790,8 @@ spell_read_aff(fname, spin) n |= WFP_NC; if (upper) n |= WFP_UP; - tree_add_word(p, spin->si_prefroot, n, - idx, cur_aff->ah_newID, spin); + tree_add_word(spin, p, spin->si_prefroot, n, + idx, cur_aff->ah_newID); } } } @@ -3924,9 +3983,9 @@ add_fromto(spin, gap, from, to) { ftp = ((fromto_T *)gap->ga_data) + gap->ga_len; (void)spell_casefold(from, STRLEN(from), word, MAXWLEN); - ftp->ft_from = getroom_save(&spin->si_blocks, word); + ftp->ft_from = getroom_save(spin, word); (void)spell_casefold(to, STRLEN(to), word, MAXWLEN); - ftp->ft_to = getroom_save(&spin->si_blocks, word); + ftp->ft_to = getroom_save(spin, word); ++gap->ga_len; } } @@ -4000,9 +4059,9 @@ spell_free_aff(aff) * Returns OK or FAIL; */ static int -spell_read_dic(fname, spin, affile) +spell_read_dic(spin, fname, affile) + spellinfo_T *spin; char_u *fname; - spellinfo_T *spin; afffile_T *affile; { hashtab_T ht; @@ -4035,9 +4094,6 @@ spell_read_dic(fname, spin, affile) /* The hashtable is only used to detect duplicated words. */ hash_init(&ht); - spin->si_foldwcount = 0; - spin->si_keepwcount = 0; - if (spin->si_verbose || p_verbose > 2) { if (!spin->si_verbose) @@ -4048,6 +4104,9 @@ spell_read_dic(fname, spin, affile) verbose_leave(); } + /* start with a message for the first line */ + spin->si_msg_count = 999999; + /* Read and ignore the first line: word count. */ (void)vim_fgets(line, MAXLINELEN, fd); if (!vim_isdigit(*skipwhite(line))) @@ -4106,9 +4165,10 @@ spell_read_dic(fname, spin, affile) w = line; } - /* This takes time, print a message now and then. */ - if (spin->si_verbose && (lnum & 0x3ff) == 0) - { + /* This takes time, print a message every 10000 words. */ + if (spin->si_verbose && spin->si_msg_count > 10000) + { + spin->si_msg_count = 0; vim_snprintf((char *)message, sizeof(message), _("line %6d, word %6d - %s"), lnum, spin->si_foldwcount + spin->si_keepwcount, w); @@ -4121,7 +4181,7 @@ spell_read_dic(fname, spin, affile) } /* Store the word in the hashtable to be able to find duplicates. */ - dw = (char_u *)getroom_save(&spin->si_blocks, w); + dw = (char_u *)getroom_save(spin, w); if (dw == NULL) retval = FAIL; vim_free(pc); @@ -4154,24 +4214,24 @@ spell_read_dic(fname, spin, affile) if (affile->af_pfxpostpone) /* Need to store the list of prefix IDs with the word. */ - pfxlist = get_pfxlist(affile, afflist, &spin->si_blocks); + pfxlist = get_pfxlist(spin, affile, afflist); } /* Add the word to the word tree(s). */ - if (store_word(dw, spin, flags, spin->si_region, pfxlist) == FAIL) + if (store_word(spin, dw, flags, spin->si_region, pfxlist) == FAIL) retval = FAIL; if (afflist != NULL) { /* Find all matching suffixes and add the resulting words. * Additionally do matching prefixes that combine. */ - if (store_aff_word(dw, spin, afflist, affile, + if (store_aff_word(spin, dw, afflist, affile, &affile->af_suff, &affile->af_pref, FALSE, flags, pfxlist) == FAIL) retval = FAIL; /* Find all matching prefixes and add the resulting words. */ - if (store_aff_word(dw, spin, afflist, affile, + if (store_aff_word(spin, dw, afflist, affile, &affile->af_pref, NULL, FALSE, flags, pfxlist) == FAIL) retval = FAIL; @@ -4194,10 +4254,10 @@ spell_read_dic(fname, spin, affile) * or when out of memory. */ static char_u * -get_pfxlist(affile, afflist, blp) +get_pfxlist(spin, affile, afflist) + spellinfo_T *spin; afffile_T *affile; char_u *afflist; - sblock_T **blp; { char_u *p; int cnt; @@ -4226,7 +4286,7 @@ get_pfxlist(affile, afflist, blp) } } if (round == 1 && cnt > 0) - res = getroom(blp, cnt + 1, FALSE); + res = getroom(spin, cnt + 1, FALSE); if (res == NULL) break; } @@ -4246,9 +4306,9 @@ get_pfxlist(affile, afflist, blp) * Returns FAIL when out of memory. */ static int -store_aff_word(word, spin, afflist, affile, ht, xht, comb, flags, pfxlist) +store_aff_word(spin, word, afflist, affile, ht, xht, comb, flags, pfxlist) + spellinfo_T *spin; /* spell info */ char_u *word; /* basic word start */ - spellinfo_T *spin; /* spell info */ char_u *afflist; /* list of names of supported affixes */ afffile_T *affile; hashtab_T *ht; @@ -4361,14 +4421,14 @@ store_aff_word(word, spin, afflist, affi } /* Store the modified word. */ - if (store_word(newword, spin, use_flags, + if (store_word(spin, newword, use_flags, spin->si_region, use_pfxlist) == FAIL) retval = FAIL; /* When added a suffix and combining is allowed also * try adding prefixes additionally. */ if (xht != NULL && ah->ah_combine) - if (store_aff_word(newword, spin, afflist, affile, + if (store_aff_word(spin, newword, afflist, affile, xht, NULL, TRUE, use_flags, use_pfxlist) == FAIL) retval = FAIL; @@ -4385,9 +4445,9 @@ store_aff_word(word, spin, afflist, affi * Read a file with a list of words. */ static int -spell_read_wordfile(fname, spin) +spell_read_wordfile(spin, fname) + spellinfo_T *spin; char_u *fname; - spellinfo_T *spin; { FILE *fd; long lnum = 0; @@ -4573,7 +4633,7 @@ spell_read_wordfile(fname, spin) } /* Normal word: store it. */ - if (store_word(line, spin, flags, regionmask, NULL) == FAIL) + if (store_word(spin, line, flags, regionmask, NULL) == FAIL) { retval = FAIL; break; @@ -4598,18 +4658,19 @@ spell_read_wordfile(fname, spin) /* * Get part of an sblock_T, "len" bytes long. - * This avoids calling free() for every little struct we use. + * This avoids calling free() for every little struct we use (and keeping + * track of them). * The memory is cleared to all zeros. * Returns NULL when out of memory. */ static void * -getroom(blp, len, align) - sblock_T **blp; +getroom(spin, len, align) + spellinfo_T *spin; size_t len; /* length needed */ int align; /* align for pointer */ { char_u *p; - sblock_T *bl = *blp; + sblock_T *bl = spin->si_blocks; if (align && bl != NULL) /* Round size up for alignment. On some systems structures need to be @@ -4623,8 +4684,8 @@ getroom(blp, len, align) bl = (sblock_T *)alloc_clear((unsigned)(sizeof(sblock_T) + SBLOCKSIZE)); if (bl == NULL) return NULL; - bl->sb_next = *blp; - *blp = bl; + bl->sb_next = spin->si_blocks; + spin->si_blocks = bl; bl->sb_used = 0; } @@ -4638,13 +4699,13 @@ getroom(blp, len, align) * Make a copy of a string into memory allocated with getroom(). */ static char_u * -getroom_save(blp, s) - sblock_T **blp; +getroom_save(spin, s) + spellinfo_T *spin; char_u *s; { char_u *sc; - sc = (char_u *)getroom(blp, STRLEN(s) + 1, FALSE); + sc = (char_u *)getroom(spin, STRLEN(s) + 1, FALSE); if (sc != NULL) STRCPY(sc, s); return sc; @@ -4672,10 +4733,10 @@ free_blocks(bl) * Allocate the root of a word tree. */ static wordnode_T * -wordtree_alloc(blp) - sblock_T **blp; -{ - return (wordnode_T *)getroom(blp, sizeof(wordnode_T), TRUE); +wordtree_alloc(spin) + spellinfo_T *spin; +{ + return (wordnode_T *)getroom(spin, sizeof(wordnode_T), TRUE); } /* @@ -4687,9 +4748,9 @@ wordtree_alloc(blp) * When "pfxlist" is not NULL store the word for each postponed prefix ID. */ static int -store_word(word, spin, flags, region, pfxlist) +store_word(spin, word, flags, region, pfxlist) + spellinfo_T *spin; char_u *word; - spellinfo_T *spin; int flags; /* extra flags, WF_BANNED */ int region; /* supported region(s) */ char_u *pfxlist; /* list of prefix IDs or NULL */ @@ -4703,19 +4764,19 @@ store_word(word, spin, flags, region, pf (void)spell_casefold(word, len, foldword, MAXWLEN); for (p = pfxlist; res == OK; ++p) { - res = tree_add_word(foldword, spin->si_foldroot, ct | flags, - region, p == NULL ? 0 : *p, spin); + res = tree_add_word(spin, foldword, spin->si_foldroot, ct | flags, + region, p == NULL ? 0 : *p); if (p == NULL || *p == NUL) break; } ++spin->si_foldwcount; - if (res == OK && (ct == WF_KEEPCAP || flags & WF_KEEPCAP)) + if (res == OK && (ct == WF_KEEPCAP || (flags & WF_KEEPCAP))) { for (p = pfxlist; res == OK; ++p) { - res = tree_add_word(word, spin->si_keeproot, flags, - region, p == NULL ? 0 : *p, spin); + res = tree_add_word(spin, word, spin->si_keeproot, flags, + region, p == NULL ? 0 : *p); if (p == NULL || *p == NUL) break; } @@ -4731,20 +4792,19 @@ store_word(word, spin, flags, region, pf * Returns FAIL when out of memory. */ static int -tree_add_word(word, root, flags, region, prefixID, spin) +tree_add_word(spin, word, root, flags, region, prefixID) + spellinfo_T *spin; char_u *word; wordnode_T *root; int flags; int region; int prefixID; - spellinfo_T *spin; { wordnode_T *node = root; wordnode_T *np; wordnode_T *copyp, **copyprev; wordnode_T **prev = NULL; int i; - sblock_T **blp = &spin->si_blocks; /* Add each byte of the word to the tree, including the NUL at the end. */ for (i = 0; ; ++i) @@ -4759,7 +4819,7 @@ tree_add_word(word, root, flags, region, for (copyp = node; copyp != NULL; copyp = copyp->wn_sibling) { /* Allocate a new node and copy the info. */ - np = get_wordnode(blp); + np = get_wordnode(spin); if (np == NULL) return FAIL; np->wn_child = copyp->wn_child; @@ -4808,7 +4868,7 @@ tree_add_word(word, root, flags, region, || node->wn_prefixID != prefixID))) { /* Allocate a new node. */ - np = get_wordnode(blp); + np = get_wordnode(spin); if (np == NULL) return FAIL; np->wn_byte = word[i]; @@ -4844,85 +4904,124 @@ tree_add_word(word, root, flags, region, spell_print_tree(root->wn_sibling); #endif + /* count nr of words added since last message */ + ++spin->si_msg_count; + /* * Every so many words compress the tree, so that we don't use too much * memory. */ - if (++words_added >= SPELL_COMPRESS_CNT) - { - words_added = 0; - - msg_start(); - msg_puts((char_u *)_(msg_compressing)); - msg_clr_eos(); - msg_didout = FALSE; - msg_col = 0; - out_flush(); - wordtree_compress(root->wn_sibling, spin); + i = FALSE; + if (root == spin->si_foldroot) + { + if (++spin->si_fold_added >= SPELL_COMPRESS_CNT) + { + i = TRUE; + spin->si_fold_added = 0; + } + } + else if (root == spin->si_keeproot) + { + if (++spin->si_keep_added >= SPELL_COMPRESS_CNT) + { + i = TRUE; + spin->si_keep_added = 0; + } + } + if (i) + { + if (spin->si_verbose) + { + msg_start(); + msg_puts((char_u *)_(msg_compressing)); + msg_clr_eos(); + msg_didout = FALSE; + msg_col = 0; + out_flush(); + } + wordtree_compress(spin, root); } return OK; } -/* We keep a list of nodes that have been freed during compression. They are - * re-used when adding a new node. The "wn_child" fields links them. */ -static wordnode_T *first_free_node = NULL; -#ifdef SPELL_PRINTTREE -static int wordnode_nr = 0; -#endif - /* * Get a wordnode_T, either from the list of previously freed nodes or * allocate a new one. */ static wordnode_T * -get_wordnode(blp) - sblock_T **blp; +get_wordnode(spin) + spellinfo_T *spin; { wordnode_T *n; - if (first_free_node == NULL) - n = (wordnode_T *)getroom(blp, sizeof(wordnode_T), TRUE); + if (spin->si_first_free == NULL) + n = (wordnode_T *)getroom(spin, sizeof(wordnode_T), TRUE); else { - n = first_free_node; - first_free_node = n->wn_child; + n = spin->si_first_free; + spin->si_first_free = n->wn_child; vim_memset(n, 0, sizeof(wordnode_T)); } #ifdef SPELL_PRINTTREE - n->wn_nr = ++wordnode_nr; + n->wn_nr = ++spin->si_wordnode_nr; #endif return n; } /* + * Decrement the reference count on a node (which is the head of a list of + * siblings). If the reference count becomes zero free the node and its + * siblings. + */ + static void +deref_wordnode(spin, node) + spellinfo_T *spin; + wordnode_T *node; +{ + wordnode_T *np; + + if (--node->wn_refs == 0) + for (np = node; np != NULL; np = np->wn_sibling) + { + if (np->wn_child != NULL) + deref_wordnode(spin, np->wn_child); + free_wordnode(spin, np); + } +} + +/* * Free a wordnode_T for re-use later. + * Only the "wn_child" field becomes invalid. */ static void -free_wordnode(n) - wordnode_T *n; -{ - n->wn_child = first_free_node; - first_free_node = n; +free_wordnode(spin, n) + spellinfo_T *spin; + wordnode_T *n; +{ + n->wn_child = spin->si_first_free; + spin->si_first_free = n; } /* * Compress a tree: find tails that are identical and can be shared. */ static void -wordtree_compress(root, spin) +wordtree_compress(spin, root) + spellinfo_T *spin; wordnode_T *root; - spellinfo_T *spin; { hashtab_T ht; int n; int tot = 0; int perc; - if (root != NULL) + /* Skip the root itself, it's not actually used. The first sibling is the + * start of the tree. */ + if (root->wn_sibling != NULL) { hash_init(&ht); - n = node_compress(root, &ht, &tot); + n = node_compress(spin, root->wn_sibling, &ht, &tot); #ifndef SPELL_PRINTTREE if (spin->si_verbose || p_verbose > 2) @@ -4940,7 +5039,7 @@ wordtree_compress(root, spin) verbose_leave(); } #ifdef SPELL_PRINTTREE - spell_print_tree(root); + spell_print_tree(root->wn_sibling); #endif hash_clear(&ht); } @@ -4951,7 +5050,8 @@ wordtree_compress(root, spin) * Returns the number of compressed nodes. */ static int -node_compress(node, ht, tot) +node_compress(spin, node, ht, tot) + spellinfo_T *spin; wordnode_T *node; hashtab_T *ht; int *tot; /* total count of nodes before compressing, @@ -4978,7 +5078,7 @@ node_compress(node, ht, tot) if ((child = np->wn_child) != NULL) { /* Compress the child. This fills hashkey. */ - compressed += node_compress(child, ht, tot); + compressed += node_compress(spin, child, ht, tot); /* Try to find an identical child. */ hash = hash_hash(child->wn_u1.hashkey); @@ -4995,14 +5095,7 @@ node_compress(node, ht, tot) * current one. This means the current child and all * its siblings is unlinked from the tree. */ ++tp->wn_refs; - --child->wn_refs; - if (child->wn_refs == 0) - for (; child != NULL; child = child->wn_sibling) - { - if (child->wn_child != NULL) - --child->wn_child->wn_refs; - free_wordnode(child); - } + deref_wordnode(spin, child); np->wn_child = tp; ++compressed; break; @@ -5123,9 +5216,9 @@ rep_compare(s1, s2) * Write the Vim spell file "fname". */ static void -write_vim_spell(fname, spin) +write_vim_spell(spin, fname) + spellinfo_T *spin; char_u *fname; - spellinfo_T *spin; { FILE *fd; int regionmask; @@ -5523,11 +5616,6 @@ mkspell(fcount, fnames, ascii, overwrite ga_init2(&spin.si_sal, (int)sizeof(fromto_T), 20); ga_init2(&spin.si_map, (int)sizeof(char_u), 100); ga_init2(&spin.si_prefcond, (int)sizeof(char_u *), 50); - first_free_node = NULL; -#ifdef SPELL_PRINTTREE - wordnode_nr = 0; -#endif - words_added = 0; /* default: fnames[0] is output file, following are input files */ innames = &fnames[1]; @@ -5616,9 +5704,9 @@ mkspell(fcount, fnames, ascii, overwrite } spin.si_region_count = incount; - spin.si_foldroot = wordtree_alloc(&spin.si_blocks); - spin.si_keeproot = wordtree_alloc(&spin.si_blocks); - spin.si_prefroot = wordtree_alloc(&spin.si_blocks); + spin.si_foldroot = wordtree_alloc(&spin); + spin.si_keeproot = wordtree_alloc(&spin); + spin.si_prefroot = wordtree_alloc(&spin); if (spin.si_foldroot == NULL || spin.si_keeproot == NULL || spin.si_prefroot == NULL) @@ -5650,7 +5738,7 @@ mkspell(fcount, fnames, ascii, overwrite { /* Read the .aff file. Will init "spin->si_conv" based on the * "SET" line. */ - afile[i] = spell_read_aff(fname, &spin); + afile[i] = spell_read_aff(&spin, fname); if (afile[i] == NULL) error = TRUE; else @@ -5658,7 +5746,7 @@ mkspell(fcount, fnames, ascii, overwrite /* Read the .dic file and store the words in the trees. */ vim_snprintf((char *)fname, sizeof(fname), "%s.dic", innames[i]); - if (spell_read_dic(fname, &spin, afile[i]) == FAIL) + if (spell_read_dic(&spin, fname, afile[i]) == FAIL) error = TRUE; } } @@ -5666,7 +5754,7 @@ mkspell(fcount, fnames, ascii, overwrite { /* No .aff file, try reading the file as a word list. Store * the words in the trees. */ - if (spell_read_wordfile(innames[i], &spin) == FAIL) + if (spell_read_wordfile(&spin, innames[i]) == FAIL) error = TRUE; } @@ -5681,18 +5769,18 @@ mkspell(fcount, fnames, ascii, overwrite /* * Combine tails in the tree. */ - if (!added_word || p_verbose > 2) - { - if (added_word) + if (spin.si_verbose || p_verbose > 2) + { + if (!spin.si_verbose) verbose_enter(); MSG(_(msg_compressing)); out_flush(); - if (added_word) + if (!spin.si_verbose) verbose_leave(); } - wordtree_compress(spin.si_foldroot->wn_sibling, &spin); - wordtree_compress(spin.si_keeproot->wn_sibling, &spin); - wordtree_compress(spin.si_prefroot->wn_sibling, &spin); + wordtree_compress(&spin, spin.si_foldroot); + wordtree_compress(&spin, spin.si_keeproot); + wordtree_compress(&spin, spin.si_prefroot); } if (!error) @@ -5700,27 +5788,27 @@ mkspell(fcount, fnames, ascii, overwrite /* * Write the info in the spell file. */ - if (!added_word || p_verbose > 2) - { - if (added_word) + if (spin.si_verbose || p_verbose > 2) + { + if (!spin.si_verbose) verbose_enter(); smsg((char_u *)_("Writing spell file %s ..."), wfname); out_flush(); - if (added_word) + if (!spin.si_verbose) verbose_leave(); } - write_vim_spell(wfname, &spin); - - if (!added_word || p_verbose > 2) - { - if (added_word) + write_vim_spell(&spin, wfname); + + if (spin.si_verbose || p_verbose > 2) + { + if (!spin.si_verbose) verbose_enter(); MSG(_("Done!")); smsg((char_u *)_("Estimated runtime memory use: %d bytes"), spin.si_memtot); out_flush(); - if (added_word) + if (!spin.si_verbose) verbose_leave(); } @@ -6393,7 +6481,7 @@ spell_casefold(str, len, buf, buflen) buf[outi] = NUL; return FAIL; } - c = mb_ptr2char_adv(&p); + c = mb_cptr2char_adv(&p); outi += mb_char2bytes(SPELL_TOFOLD(c), buf + outi); } buf[outi] = NUL; @@ -6580,11 +6668,27 @@ spell_suggest() vim_free(repl_to); repl_to = NULL; +#ifdef FEAT_RIGHTLEFT + /* When 'rightleft' is set the list is drawn right-left. */ + cmdmsg_rl = curwin->w_p_rl; + if (cmdmsg_rl) + msg_col = Columns - 1; +#endif + /* List the suggestions. */ msg_start(); lines_left = Rows; /* avoid more prompt */ vim_snprintf((char *)IObuff, IOSIZE, _("Change \"%.*s\" to:"), sug.su_badlen, sug.su_badptr); +#ifdef FEAT_RIGHTLEFT + if (cmdmsg_rl && STRNCMP(IObuff, "Change", 6) == 0) + { + /* And now the rabbit from the high hat: Avoid showing the + * untranslated message rightleft. */ + vim_snprintf((char *)IObuff, IOSIZE, ":ot \"%.*s\" egnahC", + sug.su_badlen, sug.su_badptr); + } +#endif msg_puts(IObuff); msg_clr_eos(); msg_putchar('\n'); @@ -6601,7 +6705,14 @@ spell_suggest() vim_strncpy(wcopy + STRLEN(wcopy), sug.su_badptr + stp->st_orglen, sug.su_badlen - stp->st_orglen); - vim_snprintf((char *)IObuff, IOSIZE, _("%2d \"%s\""), i + 1, wcopy); + vim_snprintf((char *)IObuff, IOSIZE, "%2d", i + 1); +#ifdef FEAT_RIGHTLEFT + if (cmdmsg_rl) + rl_mirror(IObuff); +#endif + msg_puts(IObuff); + + vim_snprintf((char *)IObuff, IOSIZE, " \"%s\"", wcopy); msg_puts(IObuff); /* The word may replace more than "su_badlen". */ @@ -6616,18 +6727,27 @@ spell_suggest() { /* Add the score. */ if (sps_flags & (SPS_DOUBLE | SPS_BEST)) - vim_snprintf((char *)IObuff, IOSIZE, _(" (%s%d - %d)"), + vim_snprintf((char *)IObuff, IOSIZE, " (%s%d - %d)", stp->st_salscore ? "s " : "", stp->st_score, stp->st_altscore); else - vim_snprintf((char *)IObuff, IOSIZE, _(" (%d)"), + vim_snprintf((char *)IObuff, IOSIZE, " (%d)", stp->st_score); +#ifdef FEAT_RIGHTLEFT + if (cmdmsg_rl) + /* Mirror the numbers, but keep the leading space. */ + rl_mirror(IObuff + 1); +#endif msg_advance(30); msg_puts(IObuff); } msg_putchar('\n'); } +#ifdef FEAT_RIGHTLEFT + cmdmsg_rl = FALSE; + msg_col = 0; +#endif /* Ask for choice. */ i = prompt_for_number(&mouse_used); if (mouse_used) @@ -6815,7 +6935,8 @@ spell_find_suggest(badptr, su, maxcount, (void)spell_casefold(su->su_badptr, su->su_badlen, su->su_fbadword, MAXWLEN); /* get caps flags for bad word */ - su->su_badflags = captype(su->su_badptr, su->su_badptr + su->su_badlen); + su->su_badflags = badword_captype(su->su_badptr, + su->su_badptr + su->su_badlen); if (need_cap) su->su_badflags |= WF_ONECAP; @@ -6916,7 +7037,7 @@ spell_suggest_expr(su, expr) #endif /* - * Find suggestions a file "fname". + * Find suggestions in file "fname". Used for "file:" in 'spellsuggest'. */ static void spell_suggest_file(su, fname) @@ -7070,7 +7191,7 @@ onecap_copy(word, wcopy, upper) p = word; #ifdef FEAT_MBYTE if (has_mbyte) - c = mb_ptr2char_adv(&p); + c = mb_cptr2char_adv(&p); else #endif c = *p++; @@ -7108,7 +7229,7 @@ allcap_copy(word, wcopy) { #ifdef FEAT_MBYTE if (has_mbyte) - c = mb_ptr2char_adv(&s); + c = mb_cptr2char_adv(&s); else #endif c = *s++; @@ -7298,10 +7419,10 @@ suggest_try_change(su) else #endif n = sp->ts_fidx; - flags = captype(su->su_badptr, su->su_badptr + n); - su->su_badflags = captype(su->su_badptr + n, + flags = badword_captype(su->su_badptr, + su->su_badptr + n); + su->su_badflags = badword_captype(su->su_badptr + n, su->su_badptr + su->su_badlen); - ++depth; stack[depth] = stack[depth - 1]; sp = &stack[depth]; @@ -7380,7 +7501,7 @@ suggest_try_change(su) c = su->su_badflags; if ((c & WF_ALLCAP) #ifdef FEAT_MBYTE - && su->su_badlen == mb_ptr2len_check(su->su_badptr) + && su->su_badlen == (*mb_ptr2len)(su->su_badptr) #else && su->su_badlen == 1 #endif @@ -7492,7 +7613,7 @@ suggest_try_change(su) else #endif n = sp->ts_fidx; - su->su_badflags = captype(su->su_badptr + n, + su->su_badflags = badword_captype(su->su_badptr + n, su->su_badptr + su->su_badlen); /* Restart at top of the tree. */ @@ -7751,7 +7872,7 @@ suggest_try_change(su) #ifdef FEAT_MBYTE if (has_mbyte) { - n = mb_ptr2len_check(p); + n = mb_cptr2len(p); c = mb_ptr2char(p); c2 = mb_ptr2char(p + n); } @@ -7816,9 +7937,9 @@ suggest_try_change(su) #ifdef FEAT_MBYTE if (has_mbyte) { - n = mb_ptr2len_check(p); + n = mb_cptr2len(p); c = mb_ptr2char(p); - fl = mb_ptr2len_check(p + n); + fl = mb_cptr2len(p + n); c2 = mb_ptr2char(p + n); c3 = mb_ptr2char(p + n + fl); } @@ -7897,10 +8018,10 @@ suggest_try_change(su) #ifdef FEAT_MBYTE if (has_mbyte) { - n = mb_ptr2len_check(p); + n = mb_cptr2len(p); c = mb_ptr2char(p); - fl = mb_ptr2len_check(p + n); - fl += mb_ptr2len_check(p + n + fl); + fl = mb_cptr2len(p + n); + fl += mb_cptr2len(p + n + fl); mch_memmove(p, p + n, fl); mb_char2bytes(c, p + fl); stack[depth].ts_fidxtry = sp->ts_fidx + n + fl; @@ -7951,10 +8072,10 @@ suggest_try_change(su) #ifdef FEAT_MBYTE if (has_mbyte) { - n = mb_ptr2len_check(p); - n += mb_ptr2len_check(p + n); + n = mb_cptr2len(p); + n += mb_cptr2len(p + n); c = mb_ptr2char(p + n); - tl = mb_ptr2len_check(p + n); + tl = mb_cptr2len(p + n); mch_memmove(p + tl, p, n); mb_char2bytes(c, p); stack[depth].ts_fidxtry = sp->ts_fidx + n + tl; @@ -8230,8 +8351,8 @@ find_keepcap_word(slang, fword, kword) #ifdef FEAT_MBYTE if (has_mbyte) { - flen = mb_ptr2len_check(fword + fwordidx[depth]); - ulen = mb_ptr2len_check(uword + uwordidx[depth]); + flen = mb_cptr2len(fword + fwordidx[depth]); + ulen = mb_cptr2len(uword + uwordidx[depth]); } else #endif @@ -8703,7 +8824,7 @@ set_map_str(lp, map) for (p = map; *p != NUL; ) { #ifdef FEAT_MBYTE - c = mb_ptr2char_adv(&p); + c = mb_cptr2char_adv(&p); #else c = *p++; #endif @@ -9138,7 +9259,7 @@ spell_soundfold_sofo(slang, inword, res) * 255, sl_sal the rest. */ for (s = inword; *s != NUL; ) { - c = mb_ptr2char_adv(&s); + c = mb_cptr2char_adv(&s); if (enc_utf8 ? utf_class(c) == 0 : vim_iswhite(c)) c = ' '; else if (c < 256) @@ -9510,7 +9631,7 @@ spell_soundfold_wsal(slang, inword, res) for (s = inword; *s != NUL; ) { t = s; - c = mb_ptr2char_adv(&s); + c = mb_cptr2char_adv(&s); if (slang->sl_rem_accents) { if (enc_utf8 ? utf_class(c) == 0 : vim_iswhite(c)) @@ -10026,10 +10147,10 @@ spell_edit_score(badword, goodword) /* Get the characters from the multi-byte strings and put them in an * int array for easy access. */ for (p = badword, badlen = 0; *p != NUL; ) - wbadword[badlen++] = mb_ptr2char_adv(&p); + wbadword[badlen++] = mb_cptr2char_adv(&p); wbadword[badlen++] = 0; for (p = goodword, goodlen = 0; *p != NUL; ) - wgoodword[goodlen++] = mb_ptr2char_adv(&p); + wgoodword[goodlen++] = mb_cptr2char_adv(&p); wgoodword[goodlen++] = 0; } else