summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/spell.c1269
2 files changed, 327 insertions, 944 deletions
diff --git a/Makefile b/Makefile
index afd8ad64c..7e916edb2 100644
--- a/Makefile
+++ b/Makefile
@@ -282,6 +282,7 @@ unixrt: dist prepare
tar cf - \
$(RT_SCRIPTS) \
$(LANG_GEN) \
+ $(LANG_GEN_BIN) \
| (cd dist/$(VIMRTDIR); tar xf -)
cd dist && tar cf $(VIMVER)-rt2.tar $(VIMRTDIR)
gzip -9 dist/$(VIMVER)-rt2.tar
@@ -439,6 +440,7 @@ dosrt_unix2dos: dist prepare no_title.vim
$(RT_UNIX_DOS_BIN) \
$(RT_ALL_BIN) \
$(RT_DOS_BIN) \
+ $(LANG_GEN_BIN) \
| (cd dist/vim/$(VIMRTDIR); tar xf -)
mv dist/vim/$(VIMRTDIR)/runtime/* dist/vim/$(VIMRTDIR)
rmdir dist/vim/$(VIMRTDIR)/runtime
diff --git a/src/spell.c b/src/spell.c
index e3a97fc83..9f1f00c00 100644
--- a/src/spell.c
+++ b/src/spell.c
@@ -903,6 +903,13 @@ spell_load_lang(lang)
sprintf((char *)fname_enc, "spell/%s.%s.spl", lang, p);
r = do_in_runtimepath(fname_enc, TRUE, spell_load_file, lp);
+ if (r == FAIL && !lp->sl_error)
+ {
+ /* Try loading the ASCII version. */
+ sprintf((char *)fname_enc, "spell/%s.ascii.spl", lang);
+
+ r = do_in_runtimepath(fname_enc, TRUE, spell_load_file, lp);
+ }
if (r == FAIL || lp->sl_error)
{
slang_free(lp);
@@ -1001,8 +1008,8 @@ spell_load_file(fname, cookie)
int affitemcnt;
int bl_used = SBLOCKSIZE;
int widx;
- int prefm; /* 1 if <= 256 prefixes, sizeof(short_u) otherw. */
- int suffm; /* 1 if <= 256 suffixes, sizeof(short_u) otherw. */
+ int prefm = 0; /* 1 if <= 256 prefixes, sizeof(short_u) otherw. */
+ int suffm = 0; /* 1 if <= 256 suffixes, sizeof(short_u) otherw. */
int wlen;
int flags;
affitem_T *ai, *ai2, **aip;
@@ -1480,6 +1487,7 @@ did_set_spelllang(buf)
e = vim_strchr(lang, ',');
if (e == NULL)
e = lang + STRLEN(lang);
+ region = NULL;
if (e > lang + 2)
{
if (e - lang >= MAXWLEN)
@@ -1490,8 +1498,6 @@ did_set_spelllang(buf)
if (lang[2] == '_')
region = lang + 3;
}
- else
- region = NULL;
for (lp = first_lang; lp != NULL; lp = lp->sl_next)
if (STRNICMP(lp->sl_name, lang, 2) == 0)
@@ -1726,7 +1732,13 @@ struct affentry_S
affentry_T *ae_next; /* next affix with same name/number */
char_u *ae_chop; /* text to chop off basic word (can be NULL) */
char_u *ae_add; /* text to add to basic word (can be NULL) */
- char_u *ae_add_nw; /* first non-word character in "ae_add" */
+ char_u *ae_add_nw; /* For a suffix: first non-word char in
+ * "ae_add"; for a prefix with only non-word
+ * chars: equal to "ae_add", for a prefix with
+ * word and non-word chars: first non-word
+ * char after word char. NULL otherwise. */
+ char_u *ae_add_pw; /* For a prefix with both word and non-word
+ * chars: first word char. NULL otherwise. */
char_u *ae_cond; /* condition (NULL for ".") */
regprog_T *ae_prog; /* regexp program for ae_cond or NULL */
short_u ae_affnr; /* for old affix: new affix number */
@@ -1778,10 +1790,11 @@ static affhash_T dumas;
#define HI2AS(hi) ((affhash_T *)((hi)->hi_key - (dumas.as_word - (char_u *)&dumas)))
-static afffile_T *spell_read_aff __ARGS((char_u *fname, vimconv_T *conv));
+static afffile_T *spell_read_aff __ARGS((char_u *fname, vimconv_T *conv, int ascii));
static void spell_free_aff __ARGS((afffile_T *aff));
-static int spell_read_dic __ARGS((hashtab_T *ht, char_u *fname, vimconv_T *conv));
-static int get_new_aff __ARGS((hashtab_T *oldaff, garray_T *gap));
+static int has_non_ascii __ARGS((char_u *s));
+static int spell_read_dic __ARGS((hashtab_T *ht, char_u *fname, vimconv_T *conv, int ascii));
+static int get_new_aff __ARGS((hashtab_T *oldaff, garray_T *gap, int prefix));
static void spell_free_dic __ARGS((hashtab_T *dic));
static int same_affentries __ARGS((affheader_T *ah1, affheader_T *ah2));
static void add_affhash __ARGS((hashtab_T *ht, char_u *key, int newnr));
@@ -1801,15 +1814,17 @@ static void write_bword __ARGS((FILE *fd, basicword_T *bw, int lowcap, basicword
static void free_wordtable __ARGS((hashtab_T *ht));
static void free_basicword __ARGS((basicword_T *bw));
static void free_affixentries __ARGS((affentry_T *first));
+static void free_affix_entry __ARGS((affentry_T *ap));
/*
* Read an affix ".aff" file.
* Returns an afffile_T, NULL for failure.
*/
static afffile_T *
-spell_read_aff(fname, conv)
+spell_read_aff(fname, conv, ascii)
char_u *fname;
vimconv_T *conv; /* info for encoding conversion */
+ int ascii; /* Only accept ASCII characters */
{
FILE *fd;
afffile_T *aff;
@@ -1895,7 +1910,7 @@ spell_read_aff(fname, conv)
{
/* Setup for conversion from "ENC" to 'encoding'. */
aff->af_enc = enc_canonize(items[1]);
- if (aff->af_enc != NULL
+ if (aff->af_enc != NULL && !ascii
&& convert_setup(conv, aff->af_enc, p_enc) == FAIL)
smsg((char_u *)_("Conversion in %s not supported: from %s to %s"),
fname, aff->af_enc, p_enc);
@@ -1952,8 +1967,7 @@ spell_read_aff(fname, conv)
(unsigned)sizeof(affentry_T));
if (aff_entry == NULL)
break;
- aff_entry->ae_next = cur_aff->ah_first;
- cur_aff->ah_first = aff_entry;
+
if (STRCMP(items[2], "0") != 0)
aff_entry->ae_chop = vim_strsave(items[2]);
if (STRCMP(items[3], "0") != 0)
@@ -1969,6 +1983,19 @@ spell_read_aff(fname, conv)
sprintf((char *)buf, "%s$", items[4]);
aff_entry->ae_prog = vim_regcomp(buf, RE_MAGIC + RE_STRING);
}
+
+ if (ascii && (has_non_ascii(aff_entry->ae_chop)
+ || has_non_ascii(aff_entry->ae_add)))
+ {
+ /* Don't use an affix entry with non-ASCII characters when
+ * "ascii" is TRUE. */
+ free_affix_entry(aff_entry);
+ }
+ else
+ {
+ aff_entry->ae_next = cur_aff->ah_first;
+ cur_aff->ah_first = aff_entry;
+ }
}
else if (STRCMP(items[0], "REP") == 0 && itemcnt == 2)
/* Ignore REP count */;
@@ -1997,6 +2024,23 @@ spell_read_aff(fname, conv)
}
/*
+ * Return TRUE if string "s" contains a non-ASCII character (128 or higher).
+ * When "s" is NULL FALSE is returned.
+ */
+ static int
+has_non_ascii(s)
+ char_u *s;
+{
+ char_u *p;
+
+ if (s != NULL)
+ for (p = s; *p != NUL; ++p)
+ if (*p >= 128)
+ return TRUE;
+ return FALSE;
+}
+
+/*
* Free the structure filled by spell_read_aff().
*/
static void
@@ -2049,10 +2093,11 @@ spell_free_aff(aff)
* Each entry in the hashtab_T is a dicword_T.
*/
static int
-spell_read_dic(ht, fname, conv)
+spell_read_dic(ht, fname, conv, ascii)
hashtab_T *ht;
char_u *fname;
vimconv_T *conv; /* info for encoding conversion */
+ int ascii; /* only accept ASCII words */
{
char_u line[MAXLINELEN];
char_u *p;
@@ -2102,6 +2147,10 @@ spell_read_dic(ht, fname, conv)
if (p != NULL)
*p++ = NUL;
+ /* Skip non-ASCII words when "ascii" is TRUE. */
+ if (ascii && has_non_ascii(line))
+ continue;
+
/* Convert from "SET" to 'encoding' when needed. */
if (conv->vc_type != CONV_NONE)
{
@@ -2170,9 +2219,11 @@ spell_free_dic(dic)
* Returns OK or FAIL;
*/
static int
-get_new_aff(oldaff, gap)
+get_new_aff(oldaff, gap, prefix)
hashtab_T *oldaff; /* hashtable with affheader_T */
garray_T *gap; /* table with new affixes */
+ int prefix; /* TRUE when doing prefixes, FALSE for
+ suffixes */
{
int oldtodo;
affheader_T *oldah, *newah, *gapah;
@@ -2218,17 +2269,44 @@ get_new_aff(oldaff, gap)
oldae = oldae->ae_next)
{
oldae->ae_add_nw = NULL;
+ oldae->ae_add_pw = NULL;
if (oldae->ae_add != NULL)
{
- /* Check for non-word characters in the suffix. If there
+ /* Check for non-word characters in the affix. If there
* is one this affix will be turned into an addition.
* This is stored with the old affix, that is where
* trans_affixes() will check. */
for (p = oldae->ae_add; *p != NUL; mb_ptr_adv(p))
if (!spell_iswordc(p))
+ {
+ oldae->ae_add_nw = p;
break;
- if (*p != NUL)
- oldae->ae_add_nw = p;
+ }
+
+ if (prefix && oldae->ae_add_nw != NULL)
+ {
+ /* If a prefix has both word and non-word characters
+ * special treatment is necessary. If it has only
+ * non-word characters it becomes a leadstring. */
+ for (p = oldae->ae_add; *p != NUL; mb_ptr_adv(p))
+ if (spell_iswordc(p))
+ {
+ oldae->ae_add_pw = p;
+ break;
+ }
+ if (oldae->ae_add_pw != NULL)
+ {
+ /* Mixed prefix, set ae_add_nw to first non-word
+ * char after ae_add_pw (if there is one). */
+ oldae->ae_add_nw = NULL;
+ for ( ; *p != NUL; mb_ptr_adv(p))
+ if (!spell_iswordc(p))
+ {
+ oldae->ae_add_nw = p;
+ break;
+ }
+ }
+ }
}
if (oldae->ae_cond == NULL)
@@ -2458,12 +2536,14 @@ trans_affixes(dw, bw, oldaff, newwords)
basicword_T *nbw;
int alen;
int wlen;
- garray_T fixga;
+ garray_T suffixga; /* list of words with non-word suffixes */
+ garray_T prefixga; /* list of words with non-word prefixes */
char_u nword[MAXWLEN];
int flags;
int n;
- ga_init2(&fixga, (int)sizeof(basicword_T *), 5);
+ ga_init2(&suffixga, (int)sizeof(basicword_T *), 5);
+ ga_init2(&prefixga, (int)sizeof(basicword_T *), 5);
/* Loop over all the affix names of the old word. */
key[1] = NUL;
@@ -2494,8 +2574,8 @@ trans_affixes(dw, bw, oldaff, newwords)
if (ae->ae_prog == NULL
|| vim_regexec(&regmatch, dw->dw_word, (colnr_T)0))
{
- if (ae->ae_add_nw != NULL && (gap == &bw->bw_suffix
- ? bw->bw_addstring : bw->bw_leadstring) == NULL)
+ if ((ae->ae_add_nw != NULL || ae->ae_add_pw != NULL)
+ && (gap != &bw->bw_suffix || bw->bw_addstring == NULL))
{
/* Affix has a non-word character and isn't prepended to
* leader or appended to addition. Need to use another
@@ -2527,6 +2607,7 @@ trans_affixes(dw, bw, oldaff, newwords)
flags = captype(nword, nword + STRLEN(nword));
if (flags & BWF_KEEPCAP)
{
+ /* "caseword" excludes the addition */
nword[STRLEN(dw->dw_word) + alen] = NUL;
nbw->bw_caseword = vim_strsave(nword);
}
@@ -2542,8 +2623,9 @@ trans_affixes(dw, bw, oldaff, newwords)
STRCPY(nbw->bw_word, bw->bw_word);
if (alen > 0 || ae->ae_chop != NULL)
{
- /* Suffix starts with word character. Append
- * it to the word. Add new word entry. */
+ /* Suffix starts with word character and/or
+ * chop off something. Append it to the word.
+ * Add new word entry. */
wlen = STRLEN(nbw->bw_word);
if (ae->ae_chop != NULL)
wlen -= STRLEN(ae->ae_chop);
@@ -2558,15 +2640,154 @@ trans_affixes(dw, bw, oldaff, newwords)
bw->bw_next = nbw;
/* Remember this word, we need to set bw_prefix
+ * and bw_prefix later. */
+ if (ga_grow(&suffixga, 1) == OK)
+ ((basicword_T **)suffixga.ga_data)
+ [suffixga.ga_len++] = nbw;
+ }
+ }
+ else if (ae->ae_add_nw == NULL)
+ {
+ /* Prefix that starts with non-word char(s) and may be
+ * followed by word chars: Make a leadstring and
+ * prepend word chars before the word. */
+ alen = STRLEN(ae->ae_add_pw);
+ nbw = (basicword_T *)alloc((unsigned)(
+ sizeof(basicword_T) + STRLEN(bw->bw_word)
+ + alen + 1));
+ if (nbw != NULL)
+ {
+ *nbw = *bw;
+ ga_init2(&nbw->bw_prefix, sizeof(short_u), 1);
+ ga_init2(&nbw->bw_suffix, sizeof(short_u), 1);
+
+ /* Adding the prefix may change the caps. */
+ STRCPY(nword, ae->ae_add);
+ p = dw->dw_word;
+ if (ae->ae_chop != NULL)
+ /* Skip chop string. */
+ for (i = mb_charlen(ae->ae_chop); i > 0; --i)
+ mb_ptr_adv( p);
+ STRCAT(nword, p);
+
+ flags = captype(nword, nword + STRLEN(nword));
+ if (flags & BWF_KEEPCAP)
+ /* "caseword" excludes the addition */
+ nbw->bw_caseword = vim_strsave(nword
+ + (ae->ae_add_pw - ae->ae_add));
+ else
+ nbw->bw_caseword = NULL;
+ nbw->bw_flags &= ~(BWF_ONECAP | BWF_ALLCAP
+ | BWF_KEEPCAP);
+ nbw->bw_flags |= flags;
+
+ if (bw->bw_addstring != NULL)
+ nbw->bw_addstring =
+ vim_strsave(bw->bw_addstring);
+ else
+ nbw->bw_addstring = NULL;
+ nbw->bw_leadstring = vim_strnsave(ae->ae_add,
+ ae->ae_add_pw - ae->ae_add);
+
+ if (alen > 0 || ae->ae_chop != NULL)
+ {
+ /* Prefix ends in word character and/or chop
+ * off something. Prepend it to the word.
+ * Add new word entry. */
+ STRCPY(nbw->bw_word, ae->ae_add_pw);
+ p = bw->bw_word;
+ if (ae->ae_chop != NULL)
+ p += STRLEN(ae->ae_chop);
+ STRCAT(nbw->bw_word, p);
+ add_to_wordlist(newwords, nbw);
+ }
+ else
+ {
+ /* Basic word is the same, link "nbw" after
+ * "bw". */
+ STRCPY(nbw->bw_word, bw->bw_word);
+ bw->bw_next = nbw;
+ }
+
+ /* Remember this word, we need to set bw_suffix
* and bw_suffix later. */
- if (ga_grow(&fixga, 1) == OK)
- ((basicword_T **)fixga.ga_data)[fixga.ga_len++]
- = nbw;
+ if (ga_grow(&prefixga, 1) == OK)
+ ((basicword_T **)prefixga.ga_data)
+ [prefixga.ga_len++] = nbw;
}
}
else
{
- /* TODO: prefix with non-word char */
+ /* Prefix with both non-word and word characters: Turn
+ * prefix into basic word, original word becomes an
+ * addstring. */
+
+ /* Fold-case the word characters in the prefix into
+ * nword[]. */
+ alen = 0;
+ for (p = ae->ae_add_pw; p < ae->ae_add_nw; p += n)
+ {
+#ifdef FEAT_MBYTE
+ n = (*mb_ptr2len_check)(p);
+#else
+ n = 1;
+#endif
+ (void)str_foldcase(p, n, nword + alen,
+ MAXWLEN - alen);
+ alen += STRLEN(nword + alen);
+ }
+
+ /* Allocate a new word entry. */
+ nbw = (basicword_T *)alloc((unsigned)(
+ sizeof(basicword_T) + alen + 1));
+ if (nbw != NULL)
+ {
+ *nbw = *bw;
+ ga_init2(&nbw->bw_prefix, sizeof(short_u), 1);
+ ga_init2(&nbw->bw_suffix, sizeof(short_u), 1);
+
+ mch_memmove(nbw->bw_word, nword, alen);
+ nbw->bw_word[alen] = NUL;
+
+ /* Use the cap type of the prefix. */
+ alen = ae->ae_add_nw - ae->ae_add_pw;
+ mch_memmove(nword, ae->ae_add_pw, alen);
+ nword[alen] = NUL;
+ flags = captype(nword, nword + STRLEN(nword));
+ if (flags & BWF_KEEPCAP)
+ nbw->bw_caseword = vim_strsave(nword);
+ else
+ nbw->bw_caseword = NULL;
+ nbw->bw_flags &= ~(BWF_ONECAP | BWF_ALLCAP
+ | BWF_KEEPCAP);
+ nbw->bw_flags |= flags;
+
+ /* The addstring is the prefix after the word
+ * characters, the original word excluding "chop",
+ * plus any addition. */
+ STRCPY(nword, ae->ae_add_nw);
+ p = bw->bw_word;
+ if (ae->ae_chop != NULL)
+ p += STRLEN(ae->ae_chop);
+ STRCAT(nword, p);
+ if (bw->bw_addstring != NULL)
+ STRCAT(nword, bw->bw_addstring);
+ nbw->bw_addstring = vim_strsave(nword);
+
+ if (ae->ae_add_pw > ae->ae_add)
+ nbw->bw_leadstring = vim_strnsave(ae->ae_add,
+ ae->ae_add_pw - ae->ae_add);
+ else
+ nbw->bw_leadstring = NULL;
+
+ add_to_wordlist(newwords, nbw);
+
+ /* Remember this word, we need to set bw_suffix
+ * and bw_suffix later. */
+ if (ga_grow(&prefixga, 1) == OK)
+ ((basicword_T **)prefixga.ga_data)
+ [prefixga.ga_len++] = nbw;
+ }
}
}
else
@@ -2601,11 +2822,10 @@ trans_affixes(dw, bw, oldaff, newwords)
/*
* For the words that we added for suffixes with non-word characters: Use
* the prefix list of the main word.
- * TODO: do the same for prefixes.
*/
- for (i = 0; i < fixga.ga_len; ++i)
+ for (i = 0; i < suffixga.ga_len; ++i)
{
- nbw = ((basicword_T **)fixga.ga_data)[i];
+ nbw = ((basicword_T **)suffixga.ga_data)[i];
if (ga_grow(&nbw->bw_prefix, bw->bw_prefix.ga_len) == OK)
{
mch_memmove(nbw->bw_prefix.ga_data, bw->bw_prefix.ga_data,
@@ -2614,7 +2834,23 @@ trans_affixes(dw, bw, oldaff, newwords)
}
}
- ga_clear(&fixga);
+ /*
+ * For the words that we added for prefixes with non-word characters: Use
+ * the suffix list of the main word.
+ */
+ for (i = 0; i < prefixga.ga_len; ++i)
+ {
+ nbw = ((basicword_T **)prefixga.ga_data)[i];
+ if (ga_grow(&nbw->bw_suffix, bw->bw_suffix.ga_len) == OK)
+ {
+ mch_memmove(nbw->bw_suffix.ga_data, bw->bw_suffix.ga_data,
+ bw->bw_suffix.ga_len * sizeof(short_u));
+ nbw->bw_suffix.ga_len = bw->bw_suffix.ga_len;
+ }
+ }
+
+ ga_clear(&suffixga);
+ ga_clear(&prefixga);
}
/*
@@ -2642,8 +2878,9 @@ build_wordlist(newwords, oldwords, oldaff, regionmask)
char_u *p;
int clen;
int flags;
- char_u *cp;
+ char_u *cp = NULL;
int l;
+ char_u message[MAXLINELEN + MAXWLEN];
todo = oldwords->ht_used;
for (old_hi = oldwords->ht_array; todo > 0; ++old_hi)
@@ -2654,14 +2891,15 @@ build_wordlist(newwords, oldwords, oldaff, regionmask)
dw = HI2DW(old_hi);
/* This takes time, print a message now and then. */
- if ((todo & 0x3ff) == 0 || todo == oldwords->ht_used - 1)
+ if ((todo & 0x3ff) == 0 || todo == (int)oldwords->ht_used - 1)
{
- if (todo != oldwords->ht_used - 1)
- {
- msg_didout = FALSE;
- msg_col = 0;
- }
- smsg((char_u *)_("%6d todo - %s"), todo, dw->dw_word);
+ sprintf((char *)message, _("%6d todo - %s"),
+ todo, dw->dw_word);
+ msg_start();
+ msg_outtrans_attr(message, 0);
+ msg_clr_eos();
+ msg_didout = FALSE;
+ msg_col = 0;
out_flush();
ui_breakcheck();
if (got_int)
@@ -2874,6 +3112,7 @@ expand_affixes(newwords, prefgap, suffgap)
affentry_T *pae, *sae;
garray_T add_words;
int n;
+ char_u message[MAXLINELEN + MAXWLEN];
ga_init2(&add_words, sizeof(basicword_T *), 10);
@@ -2883,6 +3122,23 @@ expand_affixes(newwords, prefgap, suffgap)
if (!HASHITEM_EMPTY(hi))
{
--todo;
+
+ /* This takes time, print a message now and then. */
+ if ((todo & 0x3ff) == 0 || todo == (int)newwords->ht_used - 1)
+ {
+ sprintf((char *)message, _("%6d todo - %s"),
+ todo, HI2BW(hi)->bw_word);
+ msg_start();
+ msg_outtrans_attr(message, 0);
+ msg_clr_eos();
+ msg_didout = FALSE;
+ msg_col = 0;
+ out_flush();
+ ui_breakcheck();
+ if (got_int)
+ break;
+ }
+
for (bw = HI2BW(hi); bw != NULL; bw = bw->bw_next)
{
/*
@@ -3318,7 +3574,7 @@ write_vim_spell(fname, prefga, suffga, newwords, regcount, regchars)
char_u **wtab;
int todo;
int flags, aflags;
- basicword_T *bw, *bwf, *bw2, *prevbw = NULL;
+ basicword_T *bw, *bwf, *bw2 = NULL, *prevbw = NULL;
int regionmask; /* mask for all relevant region bits */
int i;
int cnt;
@@ -3397,7 +3653,7 @@ write_vim_spell(fname, prefga, suffga, newwords, regcount, regchars)
/* Now write each basic word to the spell file. */
ga_init2(&bwga, sizeof(basicword_T *), 10);
- for (todo = 0; todo < newwords->ht_used; ++todo)
+ for (todo = 0; (long_u)todo < newwords->ht_used; ++todo)
{
bwf = KEY2BW(wtab[todo]);
@@ -3661,9 +3917,17 @@ ex_mkspell(eap)
struct stat st;
int round;
vimconv_T conv;
+ int ascii = FALSE;
+ char_u *arg = eap->arg;
- /* Expand all the arguments (e.g., $VIMRUNTIME). */
- if (get_arglist_exp(eap->arg, &fcount, &fnames) == FAIL)
+ if (STRNCMP(arg, "-ascii", 6) == 0)
+ {
+ ascii = TRUE;
+ arg = skipwhite(arg + 6);
+ }
+
+ /* Expand all the remaining arguments (e.g., $VIMRUNTIME). */
+ if (get_arglist_exp(arg, &fcount, &fnames) == FAIL)
return;
if (fcount < 2)
EMSG(_(e_invarg)); /* need at least output and input names */
@@ -3673,7 +3937,8 @@ ex_mkspell(eap)
{
/* Check for overwriting before doing things that may take a lot of
* time. */
- sprintf((char *)wfname, "%s.%s.spl", fnames[0], p_enc);
+ sprintf((char *)wfname, "%s.%s.spl", fnames[0],
+ ascii ? (char_u *)"ascii" : p_enc);
if (!eap->forceit && mch_stat((char *)wfname, &st) >= 0)
{
EMSG(_(e_exists));
@@ -3719,12 +3984,12 @@ ex_mkspell(eap)
/* Read the .aff file. Will init "conv" based on the "SET" line. */
conv.vc_type = CONV_NONE;
sprintf((char *)fname, "%s.aff", fnames[i]);
- if ((afile[i - 1] = spell_read_aff(fname, &conv)) == NULL)
+ if ((afile[i - 1] = spell_read_aff(fname, &conv, ascii)) == NULL)
break;
/* Read the .dic file. */
sprintf((char *)fname, "%s.dic", fnames[i]);
- if (spell_read_dic(&dfile[i - 1], fname, &conv) == FAIL)
+ if (spell_read_dic(&dfile[i - 1], fname, &conv, ascii) == FAIL)
break;
/* Free any conversion stuff. */
@@ -3755,7 +4020,8 @@ ex_mkspell(eap)
ga_init2(gap, sizeof(affheader_T), 50);
for (i = 1; i < fcount; ++i)
get_new_aff(round == 1 ? &afile[i - 1]->af_pref
- : &afile[i - 1]->af_suff, gap);
+ : &afile[i - 1]->af_suff,
+ gap, round == 1);
}
/*
@@ -3863,7 +4129,7 @@ free_basicword(bw)
}
/*
- * Free a list of affentry_T.
+ * Free a list of affentry_T and what they contain.
*/
static void
free_affixentries(first)
@@ -3874,909 +4140,24 @@ free_affixentries(first)
for (ap = first; ap != NULL; ap = an)
{
an = ap->ae_next;
- vim_free(ap->ae_chop);
- vim_free(ap->ae_add);
- vim_free(ap->ae_cond);
- vim_free(ap->ae_prog);
- vim_free(ap);
+ free_affix_entry(ap);
}
}
-#endif /* FEAT_MBYTE */
-
-#endif /* FEAT_SYN_HL */
-
-#if 0 /* old spell code with words in .spl file */
-/*
- * Structure that is used to store the text from the language file. This
- * avoids the need to allocate space for each individual word. It's allocated
- * in big chunks for speed.
- */
-#define SBLOCKSIZE 4096 /* default size of sb_data */
-typedef struct sblock_S sblock_T;
-struct sblock_S
-{
- sblock_T *sb_next; /* next block in list */
- char_u sb_data[1]; /* data, actually longer */
-};
-
-/* Structure to store words and additions. Used twice : once for case-folded
- * and once for keep-case words. */
-typedef struct winfo_S
-{
- hashtab_T wi_ht; /* hashtable with all words, both dword_T and
- nword_T (check flags for DW_NWORD) */
- garray_T wi_add; /* table with pointers to additions in a
- dword_T */
- int wi_addlen; /* longest addition length */
-} winfo_T;
-
/*
- * Structure used to store words and other info for one language.
- */
-typedef struct slang_S slang_T;
-struct slang_S
-{
- slang_T *sl_next; /* next language */
- char_u sl_name[2]; /* language name "en", "nl", etc. */
- winfo_T sl_fwords; /* case-folded words and additions */
- winfo_T sl_kwords; /* keep-case words and additions */
- char_u sl_regions[17]; /* table with up to 8 region names plus NUL */
- sblock_T *sl_block; /* list with allocated memory blocks */
-};
-
-static slang_T *first_lang = NULL;
-
-/* Entry for dword in "sl_ht". Also used for part of an nword, starting with
- * the first non-word character. And used for additions in wi_add. */
-typedef struct dword_S
-{
- char_u dw_region; /* one bit per region where it's valid */
- char_u dw_flags; /* DW_ flags */
- char_u dw_word[1]; /* actually longer, NUL terminated */
-} dword_T;
-
-#define REGION_ALL 0xff
-
-#define HI2DWORD(hi) (dword_T *)(hi->hi_key - 2)
-
-/* Entry for a nword in "sl_ht". Note that the last three items must be
- * identical to dword_T, so that they can be in the same hashtable. */
-typedef struct nword_S
-{
- garray_T nw_ga; /* table with pointers to dword_T for part
- starting with non-word character */
- int nw_maxlen; /* longest nword length (after the dword) */
- char_u nw_region; /* one bit per region where it's valid */
- char_u nw_flags; /* DW_ flags */
- char_u nw_word[1]; /* actually longer, NUL terminated */
-} nword_T;
-
-/* Get nword_T pointer from hashitem that uses nw_word */
-static nword_T dumnw;
-#define HI2NWORD(hi) ((nword_T *)((hi)->hi_key - (dumnw.nw_word - (char_u *)&dumnw)))
-
-#define DW_CAP 0x01 /* word must start with capital */
-#define DW_RARE 0x02 /* rare word */
-#define DW_NWORD 0x04 /* this is an nword_T */
-#define DW_DWORD 0x08 /* (also) use as dword without nword */
-
-/*
- * Structure used in "b_langp", filled from 'spelllang'.
- */
-typedef struct langp_S
-{
- slang_T *lp_slang; /* info for this language (NULL for last one) */
- int lp_region; /* bitmask for region or REGION_ALL */
-} langp_T;
-
-#define LANGP_ENTRY(ga, i) (((langp_T *)(ga).ga_data) + (i))
-#define DWORD_ENTRY(gap, i) *(((dword_T **)(gap)->ga_data) + i)
-
-#define SP_OK 0
-#define SP_BAD 1
-#define SP_RARE 2
-#define SP_LOCAL 3
-
-static char *e_invchar2 = N_("E753: Invalid character in \"%s\"");
-
-static slang_T *spell_load_lang __ARGS((char_u *lang));
-static void spell_load_file __ARGS((char_u *fname));
-static int find_region __ARGS((char_u *rp, char_u *region));
-
-/*
- * Main spell-checking function.
- * "ptr" points to the start of a word.
- * "*attrp" is set to the attributes for a badly spelled word. For a non-word
- * or when it's OK it remains unchanged.
- * This must only be called when 'spelllang' is not empty.
- * Returns the length of the word in bytes, also when it's OK, so that the
- * caller can skip over the word.
- */
- int
-spell_check(wp, ptr, attrp)
- win_T *wp; /* current window */
- char_u *ptr;
- int *attrp;
-{
- char_u *e; /* end of word */
- char_u *ne; /* new end of word */
- char_u *me; /* max. end of match */
- langp_T *lp;
- int result;
- int len = 0;
- hashitem_T *hi;
- int round;
- char_u kword[MAXWLEN + 1]; /* word copy */
- char_u fword[MAXWLEN + 1]; /* word with case folded */
- char_u match[MAXWLEN + 1]; /* fword with additional chars */
- char_u kwordclen[MAXWLEN + 1]; /* len of orig chars after kword[] */
- char_u fwordclen[MAXWLEN + 1]; /* len of chars after fword[] */
- char_u *clen;
- int cidx = 0; /* char index in xwordclen[] */
- hash_T fhash; /* hash for fword */
- hash_T khash; /* hash for kword */
- int match_len = 0; /* length of match[] */
- int fmatch_len = 0; /* length of nword match in chars */
- garray_T *gap;
- int l, t;
- char_u *p, *tp;
- int n;
- dword_T *dw;
- dword_T *tdw;
- winfo_T *wi;
- nword_T *nw;
- int w_isupper;
-
- /* Find the end of the word. We already know that *ptr is a word char. */
- e = ptr;
- do
- {
- mb_ptr_adv(e);
- ++len;
- } while (*e != NUL && spell_iswordc(e));
-
- /* A word starting with a number is always OK. */
- if (*ptr >= '0' && *ptr <= '9')
- return (int)(e - ptr);
-
-#ifdef FEAT_MBYTE
- w_isupper = MB_ISUPPER(mb_ptr2char(ptr));
-#else
- w_isupper = MB_ISUPPER(*ptr);
-#endif
-
- /* Make a copy of the word so that it can be NUL terminated.
- * Compute hash value. */
- mch_memmove(kword, ptr, e - ptr);
- kword[e - ptr] = NUL;
- khash = hash_hash(kword);
-
- /* Make case-folded copy of the Word. Compute its hash value. */
- (void)str_foldcase(ptr, e - ptr, fword, MAXWLEN + 1);
- fhash = hash_hash(fword);
-
- /* Further case-folded characters to check for an nword match go in
- * match[]. */
- me = e;
-
- /* "ne" is the end for the longest match */
- ne = e;
-
- /* The word is bad unless we find it in the dictionary. */
- result = SP_BAD;
-
- /*
- * Loop over the languages specified in 'spelllang'.
- * We check them all, because a matching nword may be longer than an
- * already found dword or nword.
- */
- for (lp = LANGP_ENTRY(wp->w_buffer->b_langp, 0); lp->lp_slang != NULL; ++lp)
- {
- /*
- * Check for a matching word in the hashtable.
- * Check both the keep-case word and the fold-case word.
- */
- for (round = 0; round <= 1; ++round)
- {
- if (round == 0)
- {
- wi = &lp->lp_slang->sl_kwords;
- hi = hash_lookup(&wi->wi_ht, kword, khash);
- }
- else
- {
- wi = &lp->lp_slang->sl_fwords;
- hi = hash_lookup(&wi->wi_ht, fword, fhash);
- }
- if (!HASHITEM_EMPTY(hi))
- {
- /*
- * If this is an nword entry, check for match with remainder.
- */
- dw = HI2DWORD(hi);
- if (dw->dw_flags & DW_NWORD)
- {
- /* If the word is not defined as a dword we must find an
- * nword. */
- if ((dw->dw_flags & DW_DWORD) == 0)
- dw = NULL;
-
- /* Fold more characters when needed for the nword. Need
- * to do one extra to check for a non-word character after
- * the nword. Also keep the byte-size of each character,
- * both before and after folding case. */
- nw = HI2NWORD(hi);
- while ((round == 0
- ? me - e <= nw->nw_maxlen
- : match_len <= nw->nw_maxlen)
- && *me != NUL)
- {
-#ifdef FEAT_MBYTE
- l = mb_ptr2len_check(me);
-#else
- l = 1;
-#endif
- (void)str_foldcase(me, l, match + match_len,
- MAXWLEN - match_len + 1);
- me += l;
- kwordclen[cidx] = l;
- fwordclen[cidx] = STRLEN(match + match_len);
- match_len += fwordclen[cidx];
- ++cidx;
- }
-
- if (round == 0)
- {
- clen = kwordclen;
- tp = e;
- }
- else
- {
- clen = fwordclen;
- tp = match;
- }
-
- /* Match with each item. The longest match wins:
- * "you've" is longer than "you". */
- gap = &nw->nw_ga;
- for (t = 0; t < gap->ga_len; ++t)
- {
- /* Skip entries with wrong case for first char.
- * Continue if it's a rare word without a captial. */
- tdw = DWORD_ENTRY(gap, t);
- if ((tdw->dw_flags & (DW_CAP | DW_RARE)) == DW_CAP
- && !w_isupper)
- continue;
-
- p = tdw->dw_word;
- l = 0;
- for (n = 0; p[n] != 0; n += clen[l++])
- if (vim_memcmp(p + n, tp + n, clen[l]) != 0)
- break;
-
- /* Use a match if it's longer than previous matches
- * and the next character is not a word character. */
- if (p[n] == 0 && l > fmatch_len && (tp[n] == 0
- || !spell_iswordc(tp + n)))
- {
- dw = tdw;
- fmatch_len = l;
- if (round == 0)
- ne = tp + n;
- else
- {
- /* Need to use the length of the original
- * chars, not the fold-case ones. */
- ne = e;
- for (l = 0; l < fmatch_len; ++l)
- ne += kwordclen[l];
- }
- if ((lp->lp_region & tdw->dw_region) == 0)
- result = SP_LOCAL;
- else if ((tdw->dw_flags & DW_CAP) && !w_isupper)
- result = SP_RARE;
- else
- result = SP_OK;
- }
- }
-
- }
-
- if (dw != NULL)
- {
- if (dw->dw_flags & DW_CAP)
- {
- /* Need to check first letter is uppercase. If it is,
- * check region. If it isn't it may be a rare word.
- * */
- if (w_isupper)
- {
- if ((dw->dw_region & lp->lp_region) == 0)
- result = SP_LOCAL;
- else
- result = SP_OK;
- }
- else if (dw->dw_flags & DW_RARE)
- result = SP_RARE;
- }
- else
- {
- if ((dw->dw_region & lp->lp_region) == 0)
- result = SP_LOCAL;
- else if (dw->dw_flags & DW_RARE)
- result = SP_RARE;
- else
- result = SP_OK;
- }
- }
- }
- }
-
- /*
- * Check for an addition.
- * Only after a dword, not after an nword.
- * Check both the keep-case word and the fold-case word.
- */
- if (fmatch_len == 0)
- for (round = 0; round <= 1; ++round)
- {
- if (round == 0)
- wi = &lp->lp_slang->sl_kwords;
- else
- wi = &lp->lp_slang->sl_fwords;
- gap = &wi->wi_add;
- if (gap->ga_len == 0) /* no additions, skip quickly */
- continue;
-
- /* Fold characters when needed for the addition. Need to do one
- * extra to check for a word character after the addition. */
- while ((round == 0
- ? me - e <= wi->wi_addlen
- : match_len <= wi->wi_addlen)
- && *me != NUL)
- {
-#ifdef FEAT_MBYTE
- l = mb_ptr2len_check(me);
-#else
- l = 1;
-#endif
- (void)str_foldcase(me, l, match + match_len,
- MAXWLEN - match_len + 1);
- me += l;
- kwordclen[cidx] = l;
- fwordclen[cidx] = STRLEN(match + match_len);
- match_len += fwordclen[cidx];
- ++cidx;
- }
-
- if (round == 0)
- {
- clen = kwordclen;
- tp = e;
- }
- else
- {
- clen = fwordclen;
- tp = match;
- }
-
- /* Addition lookup. Uses a linear search, there should be
- * very few. If there is a match adjust "ne" to the end.
- * This doesn't change whether a word was good or bad, only
- * the length. */
- for (t = 0; t < gap->ga_len; ++t)
- {
- tdw = DWORD_ENTRY(gap, t);
- p = tdw->dw_word;
- l = 0;
- for (n = 0; p[n] != 0; n += clen[l++])
- if (vim_memcmp(p + n, tp + n, clen[l]) != 0)
- break;
-
- /* Use a match if it's longer than previous matches
- * and the next character is not a word character. */
- if (p[n] == 0 && l > fmatch_len
- && (tp[n] == 0 || !spell_iswordc(tp + n)))
- {
- fmatch_len = l;
- if (round == 0)
- ne = tp + n;
- else
- {
- /* Need to use the length of the original
- * chars, not the fold-case ones. */
- ne = e;
- for (l = 0; l < fmatch_len; ++l)
- ne += kwordclen[l];
- }
- }
- }
- }
- }
-
- if (result != SP_OK)
- {
- if (result == SP_BAD)
- *attrp = highlight_attr[HLF_SPB];
- else if (result == SP_RARE)
- *attrp = highlight_attr[HLF_SPR];
- else
- *attrp = highlight_attr[HLF_SPL];
- }
-
- return (int)(ne - ptr);
-}
-
-static slang_T *load_lp; /* passed from spell_load_lang() to
- spell_load_file() */
-
-/*
- * Load language "lang[2]".
- */
- static slang_T *
-spell_load_lang(lang)
- char_u *lang;
-{
- slang_T *lp;
- char_u fname_enc[80];
- char_u fname_ascii[20];
- char_u *p;
- int r;
-
- lp = (slang_T *)alloc(sizeof(slang_T));
- if (lp != NULL)
- {
- lp->sl_name[0] = lang[0];
- lp->sl_name[1] = lang[1];
- hash_init(&lp->sl_fwords.wi_ht);
- ga_init2(&lp->sl_fwords.wi_add, sizeof(dword_T *), 4);
- lp->sl_fwords.wi_addlen = 0;
- hash_init(&lp->sl_kwords.wi_ht);
- ga_init2(&lp->sl_kwords.wi_add, sizeof(dword_T *), 4);
- lp->sl_kwords.wi_addlen = 0;
- lp->sl_regions[0] = NUL;
- lp->sl_block = NULL;
-
- /* Find all spell files for "lang" in 'runtimepath' and load them.
- * Use 'encoding', except that we use "latin1" for "latin9". */
-#ifdef FEAT_MBYTE
- if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0)
- p = p_enc;
- else
-#endif
- p = (char_u *)"latin1";
- load_lp = lp;
- sprintf((char *)fname_enc, "spell/%c%c.%s.spl", lang[0], lang[1], p);
- r = do_in_runtimepath(fname_enc, TRUE, spell_load_file);
- if (r == FAIL)
- {
- /* Try again to find an ASCII spell file. */
- sprintf((char *)fname_ascii, "spell/%c%c.spl", lang[0], lang[1]);
- r = do_in_runtimepath(fname_ascii, TRUE, spell_load_file);
- }
-
- if (r == FAIL)
- {
- vim_free(lp);
- lp = NULL;
- smsg((char_u *)_("Warning: Cannot find dictionary \"%s\""),
- fname_enc + 6);
- }
- else
- {
- lp->sl_next = first_lang;
- first_lang = lp;
- }
- }
-
- return lp;
-}
-
-/*
- * Load one spell file into "load_lp".
- * Invoked through do_in_runtimepath().
+ * Free one affentry_T and what it contains.
*/
static void
-spell_load_file(fname)
- char_u *fname;
+free_affix_entry(ap)
+ affentry_T *ap;
{
- int fd;
- size_t len;
- int l;
- char_u *p = NULL, *np;
- sblock_T *bl = NULL;
- int bl_used = 0;
- size_t rest = 0;
- char_u *rbuf; /* read buffer */
- char_u *rbuf_end; /* past last valid char in "rbuf" */
- hash_T hash;
- hashitem_T *hi;
- int c;
- int cc;
- int region = REGION_ALL;
- int wlen;
- winfo_T *wi;
- dword_T *dw, *edw = NULL;
- nword_T *nw = NULL;
- int flags;
- char_u *save_sourcing_name = sourcing_name;
- linenr_T save_sourcing_lnum = sourcing_lnum;
-
- rbuf = alloc((unsigned)(SBLOCKSIZE + MAXWLEN + 1));
- if (rbuf == NULL)
- return;
-
- fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
- if (fd < 0)
- {
- EMSG2(_(e_notopen), fname);
- goto theend;
- }
-
- sourcing_name = fname;
- sourcing_lnum = 0;
-
- /* Get the length of the whole file. */
- len = lseek(fd, (off_t)0, SEEK_END);
- lseek(fd, (off_t)0, SEEK_SET);
-
- /*
- * Read the file one block at a time.
- * "rest" is the length of an incomplete line at the previous block.
- * "p" points to the remainder.
- */
- while (len > 0)
- {
- /* Read a block from the file. Prepend the remainder of the previous
- * block, if any. */
- if (rest > 0)
- {
- if (rest > MAXWLEN) /* truncate long line (should be comment) */
- rest = MAXWLEN;
- mch_memmove(rbuf, p, rest);
- --sourcing_lnum;
- }
- if (len > SBLOCKSIZE)
- l = SBLOCKSIZE;
- else
- l = len;
- len -= l;
- if (read(fd, rbuf + rest, l) != l)
- {
- EMSG2(_(e_notread), fname);
- break;
- }
- rbuf_end = rbuf + l + rest;
- rest = 0;
-
- /* Deal with each line that was read until we finish the block. */
- for (p = rbuf; p < rbuf_end; p = np)
- {
- ++sourcing_lnum;
-
- /* "np" points to the first char after the line (CR, NL or white
- * space). */
- for (np = p; np < rbuf_end && *np >= ' '; mb_ptr_adv(np))
- ;
- if (np >= rbuf_end)
- {
- /* Incomplete line or end of file. */
- rest = np - p;
- if (len == 0)
- EMSG(_("E751: Truncated spell file"));
- break;
- }
- *np = NUL; /* terminate the line with a NUL */
-
- if (*p == '-')
- {
- /*
- * Region marker: ---, -xx, -xx-yy, etc.
- */
- ++p;
- if (*p == '-')
- {
- if (p[1] != '-' || p[2] != NUL)
- {
- EMSG2(_(e_invchar2), p - 1);
- len = 0;
- break;
- }
- region = REGION_ALL;
- }
- else
- {
- char_u *rp = load_lp->sl_regions;
- int r;
-
- /* Start of a region. The region may be repeated:
- * "-ca-uk". Fill "region" with the bit mask for the
- * ones we find. */
- region = 0;
- for (;;)
- {
- r = find_region(rp, p);
- if (r == REGION_ALL)
- {
- /* new region, add it to sl_regions[] */
- r = STRLEN(rp);
- if (r >= 16)
- {
- EMSG2(_("E752: Too many regions: %s"), p);
- len = 0;
- break;
- }
- else
- {
- rp[r] = p[0];
- rp[r + 1] = p[1];
- rp[r + 2] = NUL;
- r = 1 << (r / 2);
- }
- }
- else
- r = 1 << r;
-
- region |= r;
- if (p[2] != '-')
- {
- if (p[2] > ' ')
- {
- EMSG2(_(e_invchar2), p - 1);
- len = 0;
- }
- break;
- }
- p += 3;
- }
- }
- }
- else if (*p != '#' && *p != NUL)
- {
- /*
- * Not an empty line or comment.
- */
- if (*p == '!')
- {
- wi = &load_lp->sl_kwords; /* keep case */
- ++p;
- }
- else
- wi = &load_lp->sl_fwords; /* fold case */
-
- flags = 0;
- c = *p;
- if (c == '>') /* rare word */
- {
- flags = DW_RARE;
- ++p;
- }
- else if (*p == '+') /* addition */
- ++p;
-
- if (c != '+' && !spell_iswordc(p))
- {
- EMSG2(_(e_invchar2), p);
- len = 0;
- break;
- }
-
- /* Make sure there is room for the word. Folding case may
- * double the size. */
- wlen = np - p;
- if (bl == NULL || bl_used + sizeof(dword_T) + wlen
-#ifdef FEAT_MBYTE
- * (has_mbyte ? 2 : 1)
-#endif
- >= SBLOCKSIZE)
- {
- /* Allocate a block of memory to store the dword_T in.
- * This is not freed until spell_reload() is called. */
- bl = (sblock_T *)alloc((unsigned)(sizeof(sblock_T)
- + SBLOCKSIZE));
- if (bl == NULL)
- {
- len = 0;
- break;
- }
- bl->sb_next = load_lp->sl_block;
- load_lp->sl_block = bl;
- bl_used = 0;
- }
- dw = (dword_T *)(bl->sb_data + bl_used);
-
- /* For fold-case words fold the case and check for start
- * with uppercase letter. */
- if (wi == &load_lp->sl_fwords)
- {
-#ifdef FEAT_MBYTE
- if (MB_ISUPPER(mb_ptr2char(p)))
-#else
- if (MB_ISUPPER(*p))
-#endif
- flags |= DW_CAP;
-
- /* Fold case. */
- (void)str_foldcase(p, np - p, dw->dw_word, wlen
-#ifdef FEAT_MBYTE
- * (has_mbyte ? 2 : 1)
-#endif
- + 1);
-#ifdef FEAT_MBYTE
- /* case folding may change length of word */
- wlen = STRLEN(dw->dw_word);
-#endif
- }
- else
- {
- /* Keep case: copy the word as-is. */
- mch_memmove(dw->dw_word, p, wlen + 1);
- }
-
- if (c == '+')
- {
- garray_T *gap = &wi->wi_add;
-
- /* Addition. TODO: search for matching entry? */
- if (wi->wi_addlen < wlen)
- wi->wi_addlen = wlen;
- if (ga_grow(gap, 1) == FAIL)
- {
- len = 0;
- break;
- }
- *(((dword_T **)gap->ga_data) + gap->ga_len) = dw;
- ++gap->ga_len;
- dw->dw_region = region;
- dw->dw_flags = flags;
- bl_used += sizeof(dword_T) + wlen;
- }
- else
- {
- /*
- * Check for a non-word character. If found it's
- * going to be an nword.
- * For an nword we split in two: the leading dword and
- * the remainder. The dword goes in the hashtable
- * with an nword_T, the remainder is put in the
- * dword_T (starting with the first non-word
- * character).
- */
- cc = NUL;
- for (p = dw->dw_word; *p != NUL; mb_ptr_adv(p))
- if (!spell_iswordc(p))
- {
- cc = *p;
- *p = NUL;
- break;
- }
-
- /* check if we already have this dword */
- hash = hash_hash(dw->dw_word);
- hi = hash_lookup(&wi->wi_ht, dw->dw_word, hash);
- if (!HASHITEM_EMPTY(hi))
- {
- /* Existing entry. */
- edw = HI2DWORD(hi);
- if ((edw->dw_flags & (DW_CAP | DW_RARE))
- == (dw->dw_flags & (DW_CAP | DW_RARE)))
- {
- if (p_verbose > 0)
- smsg((char_u *)_("Warning: duplicate word \"%s\" in %s"),
- dw->dw_word, fname);
- }
- }
-
- if (cc != NUL) /* nword */
- {
- if (HASHITEM_EMPTY(hi)
- || (edw->dw_flags & DW_NWORD) == 0)
- {
- sblock_T *sb;
-
- /* Need to allocate a new nword_T. Put it in an
- * sblock_T, so that we can free it later. */
- sb = (sblock_T *)alloc(
- (unsigned)(sizeof(sblock_T)
- + sizeof(nword_T) + wlen));
- if (sb == NULL)
- {
- len = 0;
- break;
- }
- sb->sb_next = load_lp->sl_block;
- load_lp->sl_block = sb;
- nw = (nword_T *)sb->sb_data;
-
- ga_init2(&nw->nw_ga, sizeof(dword_T *), 4);
- nw->nw_maxlen = 0;
- STRCPY(nw->nw_word, dw->dw_word);
- if (!HASHITEM_EMPTY(hi))
- {
- /* Note: the nw_region and nw_flags is for
- * the dword that matches with the start
- * of this nword, not for the nword
- * itself! */
- nw->nw_region = edw->dw_region;
- nw->nw_flags = edw->dw_flags | DW_NWORD;
-
- /* Remove the dword item so that we can
- * add it as an nword. */
- hash_remove(&wi->wi_ht, hi);
- hi = hash_lookup(&wi->wi_ht,
- nw->nw_word, hash);
- }
- else
- {
- nw->nw_region = 0;
- nw->nw_flags = DW_NWORD;
- }
- }
- else
- nw = HI2NWORD(hi);
- }
-
- if (HASHITEM_EMPTY(hi))
- {
- /* Add new dword or nword entry. */
- hash_add_item(&wi->wi_ht, hi, cc == NUL
- ? dw->dw_word : nw->nw_word, hash);
- if (cc == NUL)
- {
- /* New dword: init the values and count the
- * used space. */
- dw->dw_flags = DW_DWORD | flags;
- dw->dw_region = region;
- bl_used += sizeof(dword_T) + wlen;
- }
- }
- else if (cc == NUL)
- {
- /* existing dword: add the region and flags */
- dw = edw;
- dw->dw_region |= region;
- dw->dw_flags |= DW_DWORD | flags;
- }
-
- if (cc != NUL)
- {
- /* Use the dword for the non-word character and
- * following characters. */
- dw->dw_region = region;
- dw->dw_flags = flags;
- STRCPY(dw->dw_word + 1, p + 1);
- dw->dw_word[0] = cc;
- l = wlen - (p - dw->dw_word);
- bl_used += sizeof(dword_T) + l;
- if (nw->nw_maxlen < l)
- nw->nw_maxlen = l;
-
- /* Add the dword to the growarray in the nword. */
- if (ga_grow(&nw->nw_ga, 1) == FAIL)
- {
- len = 0;
- break;
- }
- *((dword_T **)nw->nw_ga.ga_data + nw->nw_ga.ga_len)
- = dw;
- ++nw->nw_ga.ga_len;
- }
- }
- }
-
- /* Skip over CR and NL characters and trailing white space. */
- while (np < rbuf_end && *np <= ' ')
- ++np;
- }
- }
-
- close(fd);
-theend:
- sourcing_name = save_sourcing_name;
- sourcing_lnum = save_sourcing_lnum;
- vim_free(rbuf);
+ vim_free(ap->ae_chop);
+ vim_free(ap->ae_add);
+ vim_free(ap->ae_cond);
+ vim_free(ap->ae_prog);
+ vim_free(ap);
}
+#endif /* FEAT_MBYTE */
-#endif
+#endif /* FEAT_SYN_HL */