Mercurial > vim
comparison src/spell.c @ 310:04bf54c587f4
updated for version 7.0082
author | vimboss |
---|---|
date | Tue, 07 Jun 2005 21:00:02 +0000 |
parents | 7010607c5753 |
children | 96789bc4346a |
comparison
equal
deleted
inserted
replaced
309:ba02e70f9b18 | 310:04bf54c587f4 |
---|---|
149 typedef struct slang_S slang_T; | 149 typedef struct slang_S slang_T; |
150 struct slang_S | 150 struct slang_S |
151 { | 151 { |
152 slang_T *sl_next; /* next language */ | 152 slang_T *sl_next; /* next language */ |
153 char_u *sl_name; /* language name "en", "en.rare", "nl", etc. */ | 153 char_u *sl_name; /* language name "en", "en.rare", "nl", etc. */ |
154 char_u *sl_fname; /* name of .spl file */ | |
155 int sl_add; /* TRUE if it's an addition. */ | |
154 char_u *sl_fbyts; /* case-folded word bytes */ | 156 char_u *sl_fbyts; /* case-folded word bytes */ |
155 int *sl_fidxs; /* case-folded word indexes */ | 157 int *sl_fidxs; /* case-folded word indexes */ |
156 char_u *sl_kbyts; /* keep-case word bytes */ | 158 char_u *sl_kbyts; /* keep-case word bytes */ |
157 int *sl_kidxs; /* keep-case word indexes */ | 159 int *sl_kidxs; /* keep-case word indexes */ |
158 char_u *sl_try; /* "TRY" from .aff file TODO: not used */ | 160 char_u *sl_try; /* "TRY" from .aff file TODO: not used */ |
246 # define SPELL_ISWORDP(p) (spelltab.st_isw[*(p)]) | 248 # define SPELL_ISWORDP(p) (spelltab.st_isw[*(p)]) |
247 #endif | 249 #endif |
248 | 250 |
249 static slang_T *slang_alloc __ARGS((char_u *lang)); | 251 static slang_T *slang_alloc __ARGS((char_u *lang)); |
250 static void slang_free __ARGS((slang_T *lp)); | 252 static void slang_free __ARGS((slang_T *lp)); |
253 static void slang_clear __ARGS((slang_T *lp)); | |
251 static void find_word __ARGS((matchinf_T *mip, int keepcap)); | 254 static void find_word __ARGS((matchinf_T *mip, int keepcap)); |
252 static void spell_load_lang __ARGS((char_u *lang)); | 255 static void spell_load_lang __ARGS((char_u *lang)); |
253 static void spell_load_file __ARGS((char_u *fname, void *cookie)); | 256 static char_u *spell_enc __ARGS((void)); |
257 static void spell_load_cb __ARGS((char_u *fname, void *cookie)); | |
258 static void spell_load_file __ARGS((char_u *fname, char_u *lang, slang_T *old_lp)); | |
254 static int read_tree __ARGS((FILE *fd, char_u *byts, int *idxs, int maxidx, int startidx)); | 259 static int read_tree __ARGS((FILE *fd, char_u *byts, int *idxs, int maxidx, int startidx)); |
255 static int find_region __ARGS((char_u *rp, char_u *region)); | 260 static int find_region __ARGS((char_u *rp, char_u *region)); |
256 static int captype __ARGS((char_u *word, char_u *end)); | 261 static int captype __ARGS((char_u *word, char_u *end)); |
262 static void spell_reload_one __ARGS((char_u *fname)); | |
257 static int set_spell_charflags __ARGS((char_u *flags, int cnt, char_u *upp)); | 263 static int set_spell_charflags __ARGS((char_u *flags, int cnt, char_u *upp)); |
258 #ifdef FEAT_MBYTE | |
259 static int set_spell_chartab __ARGS((char_u *fol, char_u *low, char_u *upp)); | 264 static int set_spell_chartab __ARGS((char_u *fol, char_u *low, char_u *upp)); |
260 static void write_spell_chartab __ARGS((FILE *fd)); | 265 static void write_spell_chartab __ARGS((FILE *fd)); |
261 #endif | |
262 static int spell_isupper __ARGS((int c)); | 266 static int spell_isupper __ARGS((int c)); |
263 static int spell_casefold __ARGS((char_u *p, int len, char_u *buf, int buflen)); | 267 static int spell_casefold __ARGS((char_u *p, int len, char_u *buf, int buflen)); |
264 | 268 |
265 static char *e_format = N_("E759: Format error in spell file"); | 269 static char *e_format = N_("E759: Format error in spell file"); |
266 | 270 |
631 int len; | 635 int len; |
632 int has_syntax = syntax_present(curbuf); | 636 int has_syntax = syntax_present(curbuf); |
633 int col; | 637 int col; |
634 int can_spell; | 638 int can_spell; |
635 | 639 |
636 if (!curwin->w_p_spell || *curwin->w_buffer->b_p_spl == NUL) | 640 if (!curwin->w_p_spell || *curbuf->b_p_spl == NUL) |
637 { | 641 { |
638 EMSG(_("E756: Spell checking not enabled")); | 642 EMSG(_("E756: Spell checking not enabled")); |
639 return FAIL; | 643 return FAIL; |
640 } | 644 } |
641 | 645 |
744 return FAIL; /* interrupted */ | 748 return FAIL; /* interrupted */ |
745 } | 749 } |
746 | 750 |
747 /* | 751 /* |
748 * Load word list(s) for "lang" from Vim spell file(s). | 752 * Load word list(s) for "lang" from Vim spell file(s). |
749 * "lang" must be the language without the region: "en". | 753 * "lang" must be the language without the region: e.g., "en". |
750 */ | 754 */ |
751 static void | 755 static void |
752 spell_load_lang(lang) | 756 spell_load_lang(lang) |
753 char_u *lang; | 757 char_u *lang; |
754 { | 758 { |
755 char_u fname_enc[80]; | 759 char_u fname_enc[85]; |
756 char_u *p; | |
757 int r; | 760 int r; |
758 char_u langcp[MAXWLEN + 1]; | 761 char_u langcp[MAXWLEN + 1]; |
759 | 762 |
760 /* Copy the language name to pass it to spell_load_file() as a cookie. | 763 /* Copy the language name to pass it to spell_load_cb() as a cookie. |
761 * It's truncated when an error is detected. */ | 764 * It's truncated when an error is detected. */ |
762 STRCPY(langcp, lang); | 765 STRCPY(langcp, lang); |
763 | 766 |
764 /* Find all spell files for "lang" in 'runtimepath' and load them. | 767 /* |
765 * Use 'encoding', except that we use "latin1" for "latin9". */ | 768 * Find the first spell file for "lang" in 'runtimepath' and load it. |
766 #ifdef FEAT_MBYTE | 769 */ |
767 if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0) | 770 vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5, |
768 p = p_enc; | 771 "spell/%s.%s.spl", lang, spell_enc()); |
769 else | 772 r = do_in_runtimepath(fname_enc, FALSE, spell_load_cb, &langcp); |
770 #endif | |
771 p = (char_u *)"latin1"; | |
772 vim_snprintf((char *)fname_enc, sizeof(fname_enc), | |
773 "spell/%s.%s.spl", lang, p); | |
774 r = do_in_runtimepath(fname_enc, TRUE, spell_load_file, &langcp); | |
775 | 773 |
776 if (r == FAIL && *langcp != NUL) | 774 if (r == FAIL && *langcp != NUL) |
777 { | 775 { |
778 /* Try loading the ASCII version. */ | 776 /* Try loading the ASCII version. */ |
779 vim_snprintf((char *)fname_enc, sizeof(fname_enc), | 777 vim_snprintf((char *)fname_enc, sizeof(fname_enc) - 5, |
780 "spell/%s.ascii.spl", lang); | 778 "spell/%s.ascii.spl", lang); |
781 r = do_in_runtimepath(fname_enc, TRUE, spell_load_file, &langcp); | 779 r = do_in_runtimepath(fname_enc, FALSE, spell_load_cb, &langcp); |
782 } | 780 } |
783 | 781 |
784 if (r == FAIL) | 782 if (r == FAIL) |
785 smsg((char_u *)_("Warning: Cannot find word list \"%s\""), | 783 smsg((char_u *)_("Warning: Cannot find word list \"%s\""), |
786 fname_enc + 6); | 784 fname_enc + 6); |
785 else if (*langcp != NUL) | |
786 { | |
787 /* Load all the additions. */ | |
788 STRCPY(fname_enc + STRLEN(fname_enc) - 3, "add.spl"); | |
789 do_in_runtimepath(fname_enc, TRUE, spell_load_cb, &langcp); | |
790 } | |
791 } | |
792 | |
793 /* | |
794 * Return the encoding used for spell checking: Use 'encoding', except that we | |
795 * use "latin1" for "latin9". And limit to 60 characters (just in case). | |
796 */ | |
797 static char_u * | |
798 spell_enc() | |
799 { | |
800 | |
801 #ifdef FEAT_MBYTE | |
802 if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0) | |
803 return p_enc; | |
804 #endif | |
805 return (char_u *)"latin1"; | |
787 } | 806 } |
788 | 807 |
789 /* | 808 /* |
790 * Allocate a new slang_T. | 809 * Allocate a new slang_T. |
791 * Caller must fill "sl_next". | 810 * Caller must fill "sl_next". |
811 static void | 830 static void |
812 slang_free(lp) | 831 slang_free(lp) |
813 slang_T *lp; | 832 slang_T *lp; |
814 { | 833 { |
815 vim_free(lp->sl_name); | 834 vim_free(lp->sl_name); |
835 vim_free(lp->sl_fname); | |
836 slang_clear(lp); | |
837 vim_free(lp); | |
838 } | |
839 | |
840 /* | |
841 * Clear an slang_T so that the file can be reloaded. | |
842 */ | |
843 static void | |
844 slang_clear(lp) | |
845 slang_T *lp; | |
846 { | |
816 vim_free(lp->sl_fbyts); | 847 vim_free(lp->sl_fbyts); |
848 lp->sl_fbyts = NULL; | |
817 vim_free(lp->sl_kbyts); | 849 vim_free(lp->sl_kbyts); |
850 lp->sl_kbyts = NULL; | |
818 vim_free(lp->sl_fidxs); | 851 vim_free(lp->sl_fidxs); |
852 lp->sl_fidxs = NULL; | |
819 vim_free(lp->sl_kidxs); | 853 vim_free(lp->sl_kidxs); |
854 lp->sl_kidxs = NULL; | |
820 ga_clear(&lp->sl_rep); | 855 ga_clear(&lp->sl_rep); |
821 vim_free(lp->sl_try); | 856 vim_free(lp->sl_try); |
822 vim_free(lp); | 857 lp->sl_try = NULL; |
823 } | 858 } |
824 | 859 |
825 /* | 860 /* |
826 * Load one spell file and store the info into a slang_T. | 861 * Load one spell file and store the info into a slang_T. |
827 * Invoked through do_in_runtimepath(). | 862 * Invoked through do_in_runtimepath(). |
828 */ | 863 */ |
829 static void | 864 static void |
830 spell_load_file(fname, cookie) | 865 spell_load_cb(fname, cookie) |
831 char_u *fname; | 866 char_u *fname; |
832 void *cookie; /* points to the language name */ | 867 void *cookie; /* points to the language name */ |
833 { | 868 { |
834 char_u *lang = cookie; | 869 spell_load_file(fname, (char_u *)cookie, NULL); |
870 } | |
871 | |
872 /* | |
873 * Load one spell file and store the info into a slang_T. | |
874 * | |
875 * This is invoked in two ways: | |
876 * - From spell_load_cb() to load a spell file for the first time. "lang" is | |
877 * the language name, "old_lp" is NULL. Will allocate an slang_T. | |
878 * - To reload a spell file that was changed. "lang" is NULL and "old_lp" | |
879 * points to the existing slang_T. | |
880 */ | |
881 static void | |
882 spell_load_file(fname, lang, old_lp) | |
883 char_u *fname; | |
884 char_u *lang; | |
885 slang_T *old_lp; | |
886 { | |
835 FILE *fd; | 887 FILE *fd; |
836 char_u buf[MAXWLEN + 1]; | 888 char_u buf[MAXWLEN + 1]; |
837 char_u *p; | 889 char_u *p; |
838 int i; | 890 int i; |
839 int len; | 891 int len; |
842 linenr_T save_sourcing_lnum = sourcing_lnum; | 894 linenr_T save_sourcing_lnum = sourcing_lnum; |
843 int cnt, ccnt; | 895 int cnt, ccnt; |
844 char_u *fol; | 896 char_u *fol; |
845 slang_T *lp = NULL; | 897 slang_T *lp = NULL; |
846 | 898 |
847 fd = fopen((char *)fname, "r"); | 899 fd = mch_fopen((char *)fname, "r"); |
848 if (fd == NULL) | 900 if (fd == NULL) |
849 { | 901 { |
850 EMSG2(_(e_notopen), fname); | 902 EMSG2(_(e_notopen), fname); |
851 goto endFAIL; | 903 goto endFAIL; |
852 } | 904 } |
853 | 905 if (p_verbose > 2) |
854 lp = slang_alloc(lang); | 906 { |
855 if (lp == NULL) | 907 verbose_enter(); |
856 goto endFAIL; | 908 smsg((char_u *)_("Reading spell file \"%s\""), fname); |
909 verbose_leave(); | |
910 } | |
911 | |
912 if (old_lp == NULL) | |
913 { | |
914 lp = slang_alloc(lang); | |
915 if (lp == NULL) | |
916 goto endFAIL; | |
917 | |
918 /* Remember the file name, used to reload the file when it's updated. */ | |
919 lp->sl_fname = vim_strsave(fname); | |
920 if (lp->sl_fname == NULL) | |
921 goto endFAIL; | |
922 | |
923 /* Check for .add.spl. */ | |
924 lp->sl_add = strstr((char *)gettail(fname), ".add.") != NULL; | |
925 } | |
926 else | |
927 lp = old_lp; | |
857 | 928 |
858 /* Set sourcing_name, so that error messages mention the file name. */ | 929 /* Set sourcing_name, so that error messages mention the file name. */ |
859 sourcing_name = fname; | 930 sourcing_name = fname; |
860 sourcing_lnum = 0; | 931 sourcing_lnum = 0; |
861 | 932 |
976 if (i < 0) | 1047 if (i < 0) |
977 goto formerr; | 1048 goto formerr; |
978 } | 1049 } |
979 } | 1050 } |
980 | 1051 |
981 lp->sl_next = first_lang; | 1052 /* For a new file link it in the list of spell files. */ |
982 first_lang = lp; | 1053 if (old_lp == NULL) |
1054 { | |
1055 lp->sl_next = first_lang; | |
1056 first_lang = lp; | |
1057 } | |
983 | 1058 |
984 goto endOK; | 1059 goto endOK; |
985 | 1060 |
986 endFAIL: | 1061 endFAIL: |
987 /* truncating the name signals the error to spell_load_lang() */ | 1062 if (lang != NULL) |
988 *lang = NUL; | 1063 /* truncating the name signals the error to spell_load_lang() */ |
989 if (lp != NULL) | 1064 *lang = NUL; |
1065 if (lp != NULL && old_lp == NULL) | |
990 slang_free(lp); | 1066 slang_free(lp); |
991 | 1067 |
992 endOK: | 1068 endOK: |
993 if (fd != NULL) | 1069 if (fd != NULL) |
994 fclose(fd); | 1070 fclose(fd); |
1141 * Loop over the languages, there can be several files for each. | 1217 * Loop over the languages, there can be several files for each. |
1142 */ | 1218 */ |
1143 for (lp = first_lang; lp != NULL; lp = lp->sl_next) | 1219 for (lp = first_lang; lp != NULL; lp = lp->sl_next) |
1144 if (STRNICMP(lp->sl_name, lang, 2) == 0) | 1220 if (STRNICMP(lp->sl_name, lang, 2) == 0) |
1145 { | 1221 { |
1146 if (region == NULL) | 1222 if (region == NULL || lp->sl_add) |
1147 region_mask = REGION_ALL; | 1223 region_mask = REGION_ALL; |
1148 else | 1224 else |
1149 { | 1225 { |
1150 /* find region in sl_regions */ | 1226 /* find region in sl_regions */ |
1151 c = find_region(lp->sl_regions, region); | 1227 c = find_region(lp->sl_regions, region); |
1235 /* find first letter */ | 1311 /* find first letter */ |
1236 for (p = word; !SPELL_ISWORDP(p); mb_ptr_adv(p)) | 1312 for (p = word; !SPELL_ISWORDP(p); mb_ptr_adv(p)) |
1237 if (p >= end) | 1313 if (p >= end) |
1238 return 0; /* only non-word characters, illegal word */ | 1314 return 0; /* only non-word characters, illegal word */ |
1239 #ifdef FEAT_MBYTE | 1315 #ifdef FEAT_MBYTE |
1240 c = mb_ptr2char_adv(&p); | 1316 if (has_mbyte) |
1241 #else | 1317 c = mb_ptr2char_adv(&p); |
1242 c = *p++; | 1318 else |
1243 #endif | 1319 #endif |
1320 c = *p++; | |
1244 firstcap = allcap = spell_isupper(c); | 1321 firstcap = allcap = spell_isupper(c); |
1245 | 1322 |
1246 /* | 1323 /* |
1247 * Need to check all letters to find a word with mixed upper/lower. | 1324 * Need to check all letters to find a word with mixed upper/lower. |
1248 * But a word with an upper char only at start is a ONECAP. | 1325 * But a word with an upper char only at start is a ONECAP. |
1305 did_set_spelllang(buf); | 1382 did_set_spelllang(buf); |
1306 } | 1383 } |
1307 } | 1384 } |
1308 # endif | 1385 # endif |
1309 | 1386 |
1310 | 1387 /* |
1311 #if defined(FEAT_MBYTE) || defined(PROTO) | 1388 * Reload the spell file "fname" if it's loaded. |
1389 */ | |
1390 static void | |
1391 spell_reload_one(fname) | |
1392 char_u *fname; | |
1393 { | |
1394 slang_T *lp; | |
1395 | |
1396 for (lp = first_lang; lp != NULL; lp = lp->sl_next) | |
1397 if (fullpathcmp(fname, lp->sl_fname, FALSE) == FPC_SAME) | |
1398 { | |
1399 slang_clear(lp); | |
1400 spell_load_file(fname, NULL, lp); | |
1401 redraw_all_later(NOT_VALID); | |
1402 } | |
1403 } | |
1404 | |
1405 | |
1312 /* | 1406 /* |
1313 * Functions for ":mkspell". | 1407 * Functions for ":mkspell". |
1314 * Only possible with the multi-byte feature. | |
1315 */ | 1408 */ |
1316 | 1409 |
1317 #define MAXLINELEN 500 /* Maximum length in bytes of a line in a .aff | 1410 #define MAXLINELEN 500 /* Maximum length in bytes of a line in a .aff |
1318 and .dic file. */ | 1411 and .dic file. */ |
1319 /* | 1412 /* |
1321 */ | 1414 */ |
1322 typedef struct afffile_S | 1415 typedef struct afffile_S |
1323 { | 1416 { |
1324 char_u *af_enc; /* "SET", normalized, alloc'ed string or NULL */ | 1417 char_u *af_enc; /* "SET", normalized, alloc'ed string or NULL */ |
1325 char_u *af_try; /* "TRY" line in "af_enc" encoding */ | 1418 char_u *af_try; /* "TRY" line in "af_enc" encoding */ |
1326 int af_rar; /* ID for rare word */ | 1419 int af_rar; /* RAR ID for rare word */ |
1327 int af_huh; /* ID for keep-case word */ | 1420 int af_kep; /* KEP ID for keep-case word */ |
1328 hashtab_T af_pref; /* hashtable for prefixes, affheader_T */ | 1421 hashtab_T af_pref; /* hashtable for prefixes, affheader_T */ |
1329 hashtab_T af_suff; /* hashtable for suffixes, affheader_T */ | 1422 hashtab_T af_suff; /* hashtable for suffixes, affheader_T */ |
1330 garray_T af_rep; /* list of repentry_T entries from REP lines */ | 1423 garray_T af_rep; /* list of repentry_T entries from REP lines */ |
1331 } afffile_T; | 1424 } afffile_T; |
1332 | 1425 |
1393 { | 1486 { |
1394 wordnode_T *si_foldroot; /* tree with case-folded words */ | 1487 wordnode_T *si_foldroot; /* tree with case-folded words */ |
1395 wordnode_T *si_keeproot; /* tree with keep-case words */ | 1488 wordnode_T *si_keeproot; /* tree with keep-case words */ |
1396 sblock_T *si_blocks; /* memory blocks used */ | 1489 sblock_T *si_blocks; /* memory blocks used */ |
1397 int si_ascii; /* handling only ASCII words */ | 1490 int si_ascii; /* handling only ASCII words */ |
1491 int si_add; /* addition file */ | |
1398 int si_region; /* region mask */ | 1492 int si_region; /* region mask */ |
1399 vimconv_T si_conv; /* for conversion to 'encoding' */ | 1493 vimconv_T si_conv; /* for conversion to 'encoding' */ |
1400 int si_memtot; /* runtime memory used */ | 1494 int si_memtot; /* runtime memory used */ |
1495 int si_verbose; /* verbose messages */ | |
1401 } spellinfo_T; | 1496 } spellinfo_T; |
1402 | 1497 |
1403 static afffile_T *spell_read_aff __ARGS((char_u *fname, spellinfo_T *spin)); | 1498 static afffile_T *spell_read_aff __ARGS((char_u *fname, spellinfo_T *spin)); |
1404 static int has_non_ascii __ARGS((char_u *s)); | 1499 static int has_non_ascii __ARGS((char_u *s)); |
1405 static void spell_free_aff __ARGS((afffile_T *aff)); | 1500 static void spell_free_aff __ARGS((afffile_T *aff)); |
1410 static char_u *getroom_save __ARGS((sblock_T **blp, char_u *s)); | 1505 static char_u *getroom_save __ARGS((sblock_T **blp, char_u *s)); |
1411 static void free_blocks __ARGS((sblock_T *bl)); | 1506 static void free_blocks __ARGS((sblock_T *bl)); |
1412 static wordnode_T *wordtree_alloc __ARGS((sblock_T **blp)); | 1507 static wordnode_T *wordtree_alloc __ARGS((sblock_T **blp)); |
1413 static int store_word __ARGS((char_u *word, spellinfo_T *spin, int flags)); | 1508 static int store_word __ARGS((char_u *word, spellinfo_T *spin, int flags)); |
1414 static int tree_add_word __ARGS((char_u *word, wordnode_T *tree, int flags, int region, sblock_T **blp)); | 1509 static int tree_add_word __ARGS((char_u *word, wordnode_T *tree, int flags, int region, sblock_T **blp)); |
1415 static void wordtree_compress __ARGS((wordnode_T *root)); | 1510 static void wordtree_compress __ARGS((wordnode_T *root, spellinfo_T *spin)); |
1416 static int node_compress __ARGS((wordnode_T *node, hashtab_T *ht, int *tot)); | 1511 static int node_compress __ARGS((wordnode_T *node, hashtab_T *ht, int *tot)); |
1417 static int node_equal __ARGS((wordnode_T *n1, wordnode_T *n2)); | 1512 static int node_equal __ARGS((wordnode_T *n1, wordnode_T *n2)); |
1418 static void write_vim_spell __ARGS((char_u *fname, spellinfo_T *spin, int regcount, char_u *regchars)); | 1513 static void write_vim_spell __ARGS((char_u *fname, spellinfo_T *spin, int regcount, char_u *regchars)); |
1419 static int put_tree __ARGS((FILE *fd, wordnode_T *node, int index, int regionmask)); | 1514 static int put_tree __ARGS((FILE *fd, wordnode_T *node, int index, int regionmask)); |
1515 static void mkspell __ARGS((int fcount, char_u **fnames, int ascii, int overwrite, int verbose)); | |
1516 static void init_spellfile __ARGS((void)); | |
1420 | 1517 |
1421 /* | 1518 /* |
1422 * Read an affix ".aff" file. | 1519 * Read an affix ".aff" file. |
1423 * Returns an afffile_T, NULL for failure. | 1520 * Returns an afffile_T, NULL for failure. |
1424 */ | 1521 */ |
1445 static char *e_affname = N_("Affix name too long in %s line %d: %s"); | 1542 static char *e_affname = N_("Affix name too long in %s line %d: %s"); |
1446 | 1543 |
1447 /* | 1544 /* |
1448 * Open the file. | 1545 * Open the file. |
1449 */ | 1546 */ |
1450 fd = fopen((char *)fname, "r"); | 1547 fd = mch_fopen((char *)fname, "r"); |
1451 if (fd == NULL) | 1548 if (fd == NULL) |
1452 { | 1549 { |
1453 EMSG2(_(e_notopen), fname); | 1550 EMSG2(_(e_notopen), fname); |
1454 return NULL; | 1551 return NULL; |
1455 } | 1552 } |
1456 | 1553 |
1457 smsg((char_u *)_("Reading affix file %s..."), fname); | 1554 if (spin->si_verbose || p_verbose > 2) |
1458 out_flush(); | 1555 { |
1556 if (!spin->si_verbose) | |
1557 verbose_enter(); | |
1558 smsg((char_u *)_("Reading affix file %s..."), fname); | |
1559 out_flush(); | |
1560 if (!spin->si_verbose) | |
1561 verbose_leave(); | |
1562 } | |
1459 | 1563 |
1460 /* | 1564 /* |
1461 * Allocate and init the afffile_T structure. | 1565 * Allocate and init the afffile_T structure. |
1462 */ | 1566 */ |
1463 aff = (afffile_T *)getroom(&spin->si_blocks, sizeof(afffile_T)); | 1567 aff = (afffile_T *)getroom(&spin->si_blocks, sizeof(afffile_T)); |
1479 if (*rline == '#') | 1583 if (*rline == '#') |
1480 continue; | 1584 continue; |
1481 | 1585 |
1482 /* Convert from "SET" to 'encoding' when needed. */ | 1586 /* Convert from "SET" to 'encoding' when needed. */ |
1483 vim_free(pc); | 1587 vim_free(pc); |
1588 #ifdef FEAT_MBYTE | |
1484 if (spin->si_conv.vc_type != CONV_NONE) | 1589 if (spin->si_conv.vc_type != CONV_NONE) |
1485 { | 1590 { |
1486 pc = string_convert(&spin->si_conv, rline, NULL); | 1591 pc = string_convert(&spin->si_conv, rline, NULL); |
1487 if (pc == NULL) | 1592 if (pc == NULL) |
1488 { | 1593 { |
1491 continue; | 1596 continue; |
1492 } | 1597 } |
1493 line = pc; | 1598 line = pc; |
1494 } | 1599 } |
1495 else | 1600 else |
1601 #endif | |
1496 { | 1602 { |
1497 pc = NULL; | 1603 pc = NULL; |
1498 line = rline; | 1604 line = rline; |
1499 } | 1605 } |
1500 | 1606 |
1521 if (itemcnt > 0) | 1627 if (itemcnt > 0) |
1522 { | 1628 { |
1523 if (STRCMP(items[0], "SET") == 0 && itemcnt == 2 | 1629 if (STRCMP(items[0], "SET") == 0 && itemcnt == 2 |
1524 && aff->af_enc == NULL) | 1630 && aff->af_enc == NULL) |
1525 { | 1631 { |
1632 #ifdef FEAT_MBYTE | |
1526 /* Setup for conversion from "ENC" to 'encoding'. */ | 1633 /* Setup for conversion from "ENC" to 'encoding'. */ |
1527 aff->af_enc = enc_canonize(items[1]); | 1634 aff->af_enc = enc_canonize(items[1]); |
1528 if (aff->af_enc != NULL && !spin->si_ascii | 1635 if (aff->af_enc != NULL && !spin->si_ascii |
1529 && convert_setup(&spin->si_conv, aff->af_enc, | 1636 && convert_setup(&spin->si_conv, aff->af_enc, |
1530 p_enc) == FAIL) | 1637 p_enc) == FAIL) |
1531 smsg((char_u *)_("Conversion in %s not supported: from %s to %s"), | 1638 smsg((char_u *)_("Conversion in %s not supported: from %s to %s"), |
1532 fname, aff->af_enc, p_enc); | 1639 fname, aff->af_enc, p_enc); |
1640 #else | |
1641 smsg((char_u *)_("Conversion in %s not supported"), fname); | |
1642 #endif | |
1533 } | 1643 } |
1534 else if (STRCMP(items[0], "NOSPLITSUGS") == 0 && itemcnt == 1) | 1644 else if (STRCMP(items[0], "NOSPLITSUGS") == 0 && itemcnt == 1) |
1535 { | 1645 { |
1536 /* ignored */ | 1646 /* ignored */ |
1537 } | 1647 } |
1545 { | 1655 { |
1546 aff->af_rar = items[1][0]; | 1656 aff->af_rar = items[1][0]; |
1547 if (items[1][1] != NUL) | 1657 if (items[1][1] != NUL) |
1548 smsg((char_u *)_(e_affname), fname, lnum, items[1]); | 1658 smsg((char_u *)_(e_affname), fname, lnum, items[1]); |
1549 } | 1659 } |
1550 else if (STRCMP(items[0], "HUH") == 0 && itemcnt == 2 | 1660 else if (STRCMP(items[0], "KEP") == 0 && itemcnt == 2 |
1551 && aff->af_huh == 0) | 1661 && aff->af_kep == 0) |
1552 { | 1662 { |
1553 aff->af_huh = items[1][0]; | 1663 aff->af_kep = items[1][0]; |
1554 if (items[1][1] != NUL) | 1664 if (items[1][1] != NUL) |
1555 smsg((char_u *)_(e_affname), fname, lnum, items[1]); | 1665 smsg((char_u *)_(e_affname), fname, lnum, items[1]); |
1556 } | 1666 } |
1557 else if ((STRCMP(items[0], "PFX") == 0 | 1667 else if ((STRCMP(items[0], "PFX") == 0 |
1558 || STRCMP(items[0], "SFX") == 0) | 1668 || STRCMP(items[0], "SFX") == 0) |
1780 int flags; | 1890 int flags; |
1781 | 1891 |
1782 /* | 1892 /* |
1783 * Open the file. | 1893 * Open the file. |
1784 */ | 1894 */ |
1785 fd = fopen((char *)fname, "r"); | 1895 fd = mch_fopen((char *)fname, "r"); |
1786 if (fd == NULL) | 1896 if (fd == NULL) |
1787 { | 1897 { |
1788 EMSG2(_(e_notopen), fname); | 1898 EMSG2(_(e_notopen), fname); |
1789 return FAIL; | 1899 return FAIL; |
1790 } | 1900 } |
1791 | 1901 |
1792 /* The hashtable is only used to detect duplicated words. */ | 1902 /* The hashtable is only used to detect duplicated words. */ |
1793 hash_init(&ht); | 1903 hash_init(&ht); |
1794 | 1904 |
1795 smsg((char_u *)_("Reading dictionary file %s..."), fname); | 1905 if (spin->si_verbose || p_verbose > 2) |
1796 out_flush(); | 1906 { |
1907 if (!spin->si_verbose) | |
1908 verbose_enter(); | |
1909 smsg((char_u *)_("Reading dictionary file %s..."), fname); | |
1910 out_flush(); | |
1911 if (!spin->si_verbose) | |
1912 verbose_leave(); | |
1913 } | |
1797 | 1914 |
1798 /* Read and ignore the first line: word count. */ | 1915 /* Read and ignore the first line: word count. */ |
1799 (void)vim_fgets(line, MAXLINELEN, fd); | 1916 (void)vim_fgets(line, MAXLINELEN, fd); |
1800 if (!isdigit(*skipwhite(line))) | 1917 if (!isdigit(*skipwhite(line))) |
1801 EMSG2(_("E760: No word count in %s"), fname); | 1918 EMSG2(_("E760: No word count in %s"), fname); |
1818 if (l == 0) | 1935 if (l == 0) |
1819 continue; /* empty line */ | 1936 continue; /* empty line */ |
1820 line[l] = NUL; | 1937 line[l] = NUL; |
1821 | 1938 |
1822 /* This takes time, print a message now and then. */ | 1939 /* This takes time, print a message now and then. */ |
1823 if ((lnum & 0x3ff) == 0) | 1940 if (spin->si_verbose && (lnum & 0x3ff) == 0) |
1824 { | 1941 { |
1825 vim_snprintf((char *)message, sizeof(message), | 1942 vim_snprintf((char *)message, sizeof(message), |
1826 _("line %6d - %s"), lnum, line); | 1943 _("line %6d - %s"), lnum, line); |
1827 msg_start(); | 1944 msg_start(); |
1828 msg_outtrans_attr(message, 0); | 1945 msg_outtrans_attr(message, 0); |
1842 { | 1959 { |
1843 ++non_ascii; | 1960 ++non_ascii; |
1844 continue; | 1961 continue; |
1845 } | 1962 } |
1846 | 1963 |
1964 #ifdef FEAT_MBYTE | |
1847 /* Convert from "SET" to 'encoding' when needed. */ | 1965 /* Convert from "SET" to 'encoding' when needed. */ |
1848 if (spin->si_conv.vc_type != CONV_NONE) | 1966 if (spin->si_conv.vc_type != CONV_NONE) |
1849 { | 1967 { |
1850 pc = string_convert(&spin->si_conv, line, NULL); | 1968 pc = string_convert(&spin->si_conv, line, NULL); |
1851 if (pc == NULL) | 1969 if (pc == NULL) |
1855 continue; | 1973 continue; |
1856 } | 1974 } |
1857 w = pc; | 1975 w = pc; |
1858 } | 1976 } |
1859 else | 1977 else |
1978 #endif | |
1860 { | 1979 { |
1861 pc = NULL; | 1980 pc = NULL; |
1862 w = line; | 1981 w = line; |
1863 } | 1982 } |
1864 | 1983 |
1881 flags = 0; | 2000 flags = 0; |
1882 if (afflist != NULL) | 2001 if (afflist != NULL) |
1883 { | 2002 { |
1884 /* Check for affix name that stands for keep-case word and stands | 2003 /* Check for affix name that stands for keep-case word and stands |
1885 * for rare word (if defined). */ | 2004 * for rare word (if defined). */ |
1886 if (affile->af_huh != NUL | 2005 if (affile->af_kep != NUL |
1887 && vim_strchr(afflist, affile->af_huh) != NULL) | 2006 && vim_strchr(afflist, affile->af_kep) != NULL) |
1888 flags |= WF_KEEPCAP; | 2007 flags |= WF_KEEPCAP; |
1889 if (affile->af_rar != NUL | 2008 if (affile->af_rar != NUL |
1890 && vim_strchr(afflist, affile->af_rar) != NULL) | 2009 && vim_strchr(afflist, affile->af_rar) != NULL) |
1891 flags |= WF_RARE; | 2010 flags |= WF_RARE; |
1892 } | 2011 } |
1981 *newword = NUL; | 2100 *newword = NUL; |
1982 else | 2101 else |
1983 STRCPY(newword, ae->ae_add); | 2102 STRCPY(newword, ae->ae_add); |
1984 p = word; | 2103 p = word; |
1985 if (ae->ae_chop != NULL) | 2104 if (ae->ae_chop != NULL) |
2105 { | |
1986 /* Skip chop string. */ | 2106 /* Skip chop string. */ |
1987 for (i = mb_charlen(ae->ae_chop); i > 0; --i) | 2107 #ifdef FEAT_MBYTE |
2108 if (has_mbyte) | |
2109 i = mb_charlen(ae->ae_chop); | |
2110 else | |
2111 #endif | |
2112 i = STRLEN(ae->ae_chop); | |
2113 for ( ; i > 0; --i) | |
1988 mb_ptr_adv(p); | 2114 mb_ptr_adv(p); |
2115 } | |
1989 STRCAT(newword, p); | 2116 STRCAT(newword, p); |
1990 } | 2117 } |
1991 else | 2118 else |
1992 { | 2119 { |
1993 /* suffix: chop/add at the end of the word */ | 2120 /* suffix: chop/add at the end of the word */ |
1994 STRCPY(newword, word); | 2121 STRCPY(newword, word); |
1995 if (ae->ae_chop != NULL) | 2122 if (ae->ae_chop != NULL) |
1996 { | 2123 { |
1997 /* Remove chop string. */ | 2124 /* Remove chop string. */ |
1998 p = newword + STRLEN(newword); | 2125 p = newword + STRLEN(newword); |
1999 for (i = mb_charlen(ae->ae_chop); i > 0; --i) | 2126 #ifdef FEAT_MBYTE |
2127 if (has_mbyte) | |
2128 i = mb_charlen(ae->ae_chop); | |
2129 else | |
2130 #endif | |
2131 i = STRLEN(ae->ae_chop); | |
2132 for ( ; i > 0; --i) | |
2000 mb_ptr_back(newword, p); | 2133 mb_ptr_back(newword, p); |
2001 *p = NUL; | 2134 *p = NUL; |
2002 } | 2135 } |
2003 if (ae->ae_add != NULL) | 2136 if (ae->ae_add != NULL) |
2004 STRCAT(newword, ae->ae_add); | 2137 STRCAT(newword, ae->ae_add); |
2038 char_u *pc = NULL; | 2171 char_u *pc = NULL; |
2039 int l; | 2172 int l; |
2040 int retval = OK; | 2173 int retval = OK; |
2041 int did_word = FALSE; | 2174 int did_word = FALSE; |
2042 int non_ascii = 0; | 2175 int non_ascii = 0; |
2043 char_u *enc; | |
2044 int flags; | 2176 int flags; |
2045 | 2177 |
2046 /* | 2178 /* |
2047 * Open the file. | 2179 * Open the file. |
2048 */ | 2180 */ |
2049 fd = fopen((char *)fname, "r"); | 2181 fd = mch_fopen((char *)fname, "r"); |
2050 if (fd == NULL) | 2182 if (fd == NULL) |
2051 { | 2183 { |
2052 EMSG2(_(e_notopen), fname); | 2184 EMSG2(_(e_notopen), fname); |
2053 return FAIL; | 2185 return FAIL; |
2054 } | 2186 } |
2055 | 2187 |
2056 smsg((char_u *)_("Reading word file %s..."), fname); | 2188 if (spin->si_verbose || p_verbose > 2) |
2057 out_flush(); | 2189 { |
2190 if (!spin->si_verbose) | |
2191 verbose_enter(); | |
2192 smsg((char_u *)_("Reading word file %s..."), fname); | |
2193 out_flush(); | |
2194 if (!spin->si_verbose) | |
2195 verbose_leave(); | |
2196 } | |
2058 | 2197 |
2059 /* | 2198 /* |
2060 * Read all the lines in the file one by one. | 2199 * Read all the lines in the file one by one. |
2061 */ | 2200 */ |
2062 while (!vim_fgets(rline, MAXLINELEN, fd) && !got_int) | 2201 while (!vim_fgets(rline, MAXLINELEN, fd) && !got_int) |
2076 continue; /* empty or blank line */ | 2215 continue; /* empty or blank line */ |
2077 rline[l] = NUL; | 2216 rline[l] = NUL; |
2078 | 2217 |
2079 /* Convert from "=encoding={encoding}" to 'encoding' when needed. */ | 2218 /* Convert from "=encoding={encoding}" to 'encoding' when needed. */ |
2080 vim_free(pc); | 2219 vim_free(pc); |
2220 #ifdef FEAT_MBYTE | |
2081 if (spin->si_conv.vc_type != CONV_NONE) | 2221 if (spin->si_conv.vc_type != CONV_NONE) |
2082 { | 2222 { |
2083 pc = string_convert(&spin->si_conv, rline, NULL); | 2223 pc = string_convert(&spin->si_conv, rline, NULL); |
2084 if (pc == NULL) | 2224 if (pc == NULL) |
2085 { | 2225 { |
2088 continue; | 2228 continue; |
2089 } | 2229 } |
2090 line = pc; | 2230 line = pc; |
2091 } | 2231 } |
2092 else | 2232 else |
2233 #endif | |
2093 { | 2234 { |
2094 pc = NULL; | 2235 pc = NULL; |
2095 line = rline; | 2236 line = rline; |
2096 } | 2237 } |
2097 | 2238 |
2108 else if (did_word) | 2249 else if (did_word) |
2109 smsg((char_u *)_("=encoding= line after word ignored in %s line %d: %s"), | 2250 smsg((char_u *)_("=encoding= line after word ignored in %s line %d: %s"), |
2110 fname, lnum, line); | 2251 fname, lnum, line); |
2111 else | 2252 else |
2112 { | 2253 { |
2254 #ifdef FEAT_MBYTE | |
2255 char_u *enc; | |
2256 | |
2113 /* Setup for conversion to 'encoding'. */ | 2257 /* Setup for conversion to 'encoding'. */ |
2114 enc = enc_canonize(line + 10); | 2258 enc = enc_canonize(line + 10); |
2115 if (enc != NULL && !spin->si_ascii | 2259 if (enc != NULL && !spin->si_ascii |
2116 && convert_setup(&spin->si_conv, enc, | 2260 && convert_setup(&spin->si_conv, enc, |
2117 p_enc) == FAIL) | 2261 p_enc) == FAIL) |
2118 smsg((char_u *)_("Conversion in %s not supported: from %s to %s"), | 2262 smsg((char_u *)_("Conversion in %s not supported: from %s to %s"), |
2119 fname, line + 10, p_enc); | 2263 fname, line + 10, p_enc); |
2120 vim_free(enc); | 2264 vim_free(enc); |
2265 #else | |
2266 smsg((char_u *)_("Conversion in %s not supported"), fname); | |
2267 #endif | |
2121 } | 2268 } |
2122 continue; | 2269 continue; |
2123 } | 2270 } |
2124 | 2271 |
2125 if (*line == '=') | 2272 if (*line == '=') |
2167 } | 2314 } |
2168 | 2315 |
2169 vim_free(pc); | 2316 vim_free(pc); |
2170 fclose(fd); | 2317 fclose(fd); |
2171 | 2318 |
2172 if (spin->si_ascii && non_ascii > 0) | 2319 if (spin->si_ascii && non_ascii > 0 && (spin->si_verbose || p_verbose > 2)) |
2320 { | |
2321 if (p_verbose > 2) | |
2322 verbose_enter(); | |
2173 smsg((char_u *)_("Ignored %d words with non-ASCII characters"), | 2323 smsg((char_u *)_("Ignored %d words with non-ASCII characters"), |
2174 non_ascii); | 2324 non_ascii); |
2325 if (p_verbose > 2) | |
2326 verbose_leave(); | |
2327 } | |
2175 return retval; | 2328 return retval; |
2176 } | 2329 } |
2177 | 2330 |
2178 /* | 2331 /* |
2179 * Get part of an sblock_T, "len" bytes long. | 2332 * Get part of an sblock_T, "len" bytes long. |
2341 | 2494 |
2342 /* | 2495 /* |
2343 * Compress a tree: find tails that are identical and can be shared. | 2496 * Compress a tree: find tails that are identical and can be shared. |
2344 */ | 2497 */ |
2345 static void | 2498 static void |
2346 wordtree_compress(root) | 2499 wordtree_compress(root, spin) |
2347 wordnode_T *root; | 2500 wordnode_T *root; |
2501 spellinfo_T *spin; | |
2348 { | 2502 { |
2349 hashtab_T ht; | 2503 hashtab_T ht; |
2350 int n; | 2504 int n; |
2351 int tot = 0; | 2505 int tot = 0; |
2352 | 2506 |
2353 if (root != NULL) | 2507 if (root != NULL) |
2354 { | 2508 { |
2355 hash_init(&ht); | 2509 hash_init(&ht); |
2356 n = node_compress(root, &ht, &tot); | 2510 n = node_compress(root, &ht, &tot); |
2357 smsg((char_u *)_("Compressed %d of %d nodes; %d%% remaining"), | 2511 if (spin->si_verbose || p_verbose > 2) |
2512 { | |
2513 if (!spin->si_verbose) | |
2514 verbose_enter(); | |
2515 smsg((char_u *)_("Compressed %d of %d nodes; %d%% remaining"), | |
2358 n, tot, (tot - n) * 100 / tot); | 2516 n, tot, (tot - n) * 100 / tot); |
2517 if (p_verbose > 2) | |
2518 verbose_leave(); | |
2519 } | |
2359 hash_clear(&ht); | 2520 hash_clear(&ht); |
2360 } | 2521 } |
2361 } | 2522 } |
2362 | 2523 |
2363 /* | 2524 /* |
2514 int regionmask; | 2675 int regionmask; |
2515 int round; | 2676 int round; |
2516 wordnode_T *tree; | 2677 wordnode_T *tree; |
2517 int nodecount; | 2678 int nodecount; |
2518 | 2679 |
2519 fd = fopen((char *)fname, "w"); | 2680 fd = mch_fopen((char *)fname, "w"); |
2520 if (fd == NULL) | 2681 if (fd == NULL) |
2521 { | 2682 { |
2522 EMSG2(_(e_notopen), fname); | 2683 EMSG2(_(e_notopen), fname); |
2523 return; | 2684 return; |
2524 } | 2685 } |
2688 return newindex; | 2849 return newindex; |
2689 } | 2850 } |
2690 | 2851 |
2691 | 2852 |
2692 /* | 2853 /* |
2693 * ":mkspell outfile infile ..." | 2854 * ":mkspell [-ascii] outfile infile ..." |
2855 * ":mkspell [-ascii] addfile" | |
2694 */ | 2856 */ |
2695 void | 2857 void |
2696 ex_mkspell(eap) | 2858 ex_mkspell(eap) |
2697 exarg_T *eap; | 2859 exarg_T *eap; |
2698 { | 2860 { |
2699 int fcount; | 2861 int fcount; |
2700 char_u **fnames; | 2862 char_u **fnames; |
2863 char_u *arg = eap->arg; | |
2864 int ascii = FALSE; | |
2865 | |
2866 if (STRNCMP(arg, "-ascii", 6) == 0) | |
2867 { | |
2868 ascii = TRUE; | |
2869 arg = skipwhite(arg + 6); | |
2870 } | |
2871 | |
2872 /* Expand all the remaining arguments (e.g., $VIMRUNTIME). */ | |
2873 if (get_arglist_exp(arg, &fcount, &fnames) == OK) | |
2874 { | |
2875 mkspell(fcount, fnames, ascii, eap->forceit, TRUE); | |
2876 FreeWild(fcount, fnames); | |
2877 } | |
2878 } | |
2879 | |
2880 /* | |
2881 * Create a Vim spell file from one or more word lists. | |
2882 * "fnames[0]" is the output file name. | |
2883 * "fnames[fcount - 1]" is the last input file name. | |
2884 * Exception: when "fnames[0]" ends in ".add" it's used as the input file name | |
2885 * and ".spl" is appended to make the output file name. | |
2886 */ | |
2887 static void | |
2888 mkspell(fcount, fnames, ascii, overwrite, verbose) | |
2889 int fcount; | |
2890 char_u **fnames; | |
2891 int ascii; /* -ascii argument given */ | |
2892 int overwrite; /* overwrite existing output file */ | |
2893 int verbose; /* give progress messages */ | |
2894 { | |
2701 char_u fname[MAXPATHL]; | 2895 char_u fname[MAXPATHL]; |
2702 char_u wfname[MAXPATHL]; | 2896 char_u wfname[MAXPATHL]; |
2897 char_u **innames; | |
2898 int incount; | |
2703 afffile_T *(afile[8]); | 2899 afffile_T *(afile[8]); |
2704 int i; | 2900 int i; |
2705 int len; | 2901 int len; |
2706 char_u region_name[16]; | 2902 char_u region_name[16]; |
2707 struct stat st; | 2903 struct stat st; |
2708 char_u *arg = eap->arg; | |
2709 int error = FALSE; | 2904 int error = FALSE; |
2710 spellinfo_T spin; | 2905 spellinfo_T spin; |
2711 | 2906 |
2712 vim_memset(&spin, 0, sizeof(spin)); | 2907 vim_memset(&spin, 0, sizeof(spin)); |
2713 | 2908 spin.si_verbose = verbose; |
2714 if (STRNCMP(arg, "-ascii", 6) == 0) | 2909 spin.si_ascii = ascii; |
2715 { | 2910 |
2716 spin.si_ascii = TRUE; | 2911 /* default: fnames[0] is output file, following are input files */ |
2717 arg = skipwhite(arg + 6); | 2912 innames = &fnames[1]; |
2718 } | 2913 incount = fcount - 1; |
2719 | 2914 |
2720 /* Expand all the remaining arguments (e.g., $VIMRUNTIME). */ | 2915 if (fcount >= 1) |
2721 if (get_arglist_exp(arg, &fcount, &fnames) == FAIL) | 2916 { |
2722 return; | 2917 len = STRLEN(fnames[0]); |
2723 if (fcount < 2) | 2918 if (fcount == 1 && len > 4 && STRCMP(fnames[0] + len - 4, ".add") == 0) |
2919 { | |
2920 /* For ":mkspell path/en.latin1.add" output file is | |
2921 * "path/en.latin1.add.spl". */ | |
2922 innames = &fnames[0]; | |
2923 incount = 1; | |
2924 vim_snprintf((char *)wfname, sizeof(wfname), "%s.spl", fnames[0]); | |
2925 } | |
2926 else if (len > 4 && STRCMP(fnames[0] + len - 4, ".spl") == 0) | |
2927 { | |
2928 /* Name ends in ".spl", use as the file name. */ | |
2929 STRNCPY(wfname, fnames[0], sizeof(wfname)); | |
2930 wfname[sizeof(wfname) - 1] = NUL; | |
2931 } | |
2932 else | |
2933 /* Name should be language, make the file name from it. */ | |
2934 vim_snprintf((char *)wfname, sizeof(wfname), "%s.%s.spl", fnames[0], | |
2935 spin.si_ascii ? (char_u *)"ascii" : spell_enc()); | |
2936 | |
2937 /* Check for .ascii.spl. */ | |
2938 if (strstr((char *)gettail(wfname), ".ascii.") != NULL) | |
2939 spin.si_ascii = TRUE; | |
2940 | |
2941 /* Check for .add.spl. */ | |
2942 if (strstr((char *)gettail(wfname), ".add.") != NULL) | |
2943 spin.si_add = TRUE; | |
2944 } | |
2945 | |
2946 if (incount <= 0) | |
2724 EMSG(_(e_invarg)); /* need at least output and input names */ | 2947 EMSG(_(e_invarg)); /* need at least output and input names */ |
2725 else if (fcount > 9) | 2948 else if (incount > 8) |
2726 EMSG(_("E754: Only up to 8 regions supported")); | 2949 EMSG(_("E754: Only up to 8 regions supported")); |
2727 else | 2950 else |
2728 { | 2951 { |
2729 /* Check for overwriting before doing things that may take a lot of | 2952 /* Check for overwriting before doing things that may take a lot of |
2730 * time. */ | 2953 * time. */ |
2731 vim_snprintf((char *)wfname, sizeof(wfname), "%s.%s.spl", fnames[0], | 2954 if (!overwrite && mch_stat((char *)wfname, &st) >= 0) |
2732 spin.si_ascii ? (char_u *)"ascii" : p_enc); | |
2733 if (!eap->forceit && mch_stat((char *)wfname, &st) >= 0) | |
2734 { | 2955 { |
2735 EMSG(_(e_exists)); | 2956 EMSG(_(e_exists)); |
2736 goto theend; | 2957 return; |
2737 } | 2958 } |
2738 if (mch_isdir(fnames[0])) | 2959 if (mch_isdir(wfname)) |
2739 { | 2960 { |
2740 EMSG2(_(e_isadir2), fnames[0]); | 2961 EMSG2(_(e_isadir2), wfname); |
2741 goto theend; | 2962 return; |
2742 } | 2963 } |
2743 | 2964 |
2744 /* | 2965 /* |
2745 * Init the aff and dic pointers. | 2966 * Init the aff and dic pointers. |
2746 * Get the region names if there are more than 2 arguments. | 2967 * Get the region names if there are more than 2 arguments. |
2747 */ | 2968 */ |
2748 for (i = 1; i < fcount; ++i) | 2969 for (i = 0; i < incount; ++i) |
2749 { | 2970 { |
2750 afile[i - 1] = NULL; | 2971 afile[i] = NULL; |
2751 | 2972 |
2752 if (fcount > 2) | 2973 if (fcount > 2) |
2753 { | 2974 { |
2754 len = STRLEN(fnames[i]); | 2975 len = STRLEN(innames[i]); |
2755 if (STRLEN(gettail(fnames[i])) < 5 || fnames[i][len - 3] != '_') | 2976 if (STRLEN(gettail(innames[i])) < 5 |
2977 || innames[i][len - 3] != '_') | |
2756 { | 2978 { |
2757 EMSG2(_("E755: Invalid region in %s"), fnames[i]); | 2979 EMSG2(_("E755: Invalid region in %s"), innames[i]); |
2758 goto theend; | 2980 return; |
2759 } | 2981 } |
2760 else | 2982 region_name[i * 2] = TOLOWER_ASC(innames[i][len - 2]); |
2761 { | 2983 region_name[i * 2 + 1] = TOLOWER_ASC(innames[i][len - 1]); |
2762 region_name[(i - 1) * 2] = TOLOWER_ASC(fnames[i][len - 2]); | 2984 } |
2763 region_name[(i - 1) * 2 + 1] = | 2985 } |
2764 TOLOWER_ASC(fnames[i][len - 1]); | 2986 |
2765 } | 2987 if (!spin.si_add) |
2766 } | 2988 /* Clear the char type tables, don't want to use any of the |
2767 } | 2989 * currently used spell properties. */ |
2768 | 2990 init_spell_chartab(); |
2769 /* Clear the char type tables, don't want to use any of the currently | |
2770 * used spell properties. */ | |
2771 init_spell_chartab(); | |
2772 | 2991 |
2773 spin.si_foldroot = wordtree_alloc(&spin.si_blocks); | 2992 spin.si_foldroot = wordtree_alloc(&spin.si_blocks); |
2774 spin.si_keeproot = wordtree_alloc(&spin.si_blocks); | 2993 spin.si_keeproot = wordtree_alloc(&spin.si_blocks); |
2775 if (spin.si_foldroot == NULL || spin.si_keeproot == NULL) | 2994 if (spin.si_foldroot == NULL || spin.si_keeproot == NULL) |
2776 { | 2995 { |
2777 error = TRUE; | 2996 error = TRUE; |
2778 goto theend; | 2997 return; |
2779 } | 2998 } |
2780 | 2999 |
2781 /* | 3000 /* |
2782 * Read all the .aff and .dic files. | 3001 * Read all the .aff and .dic files. |
2783 * Text is converted to 'encoding'. | 3002 * Text is converted to 'encoding'. |
2784 * Words are stored in the case-folded and keep-case trees. | 3003 * Words are stored in the case-folded and keep-case trees. |
2785 */ | 3004 */ |
2786 for (i = 1; i < fcount && !error; ++i) | 3005 for (i = 0; i < incount && !error; ++i) |
2787 { | 3006 { |
2788 spin.si_conv.vc_type = CONV_NONE; | 3007 spin.si_conv.vc_type = CONV_NONE; |
2789 spin.si_region = 1 << (i - 1); | 3008 spin.si_region = 1 << i; |
2790 | 3009 |
2791 vim_snprintf((char *)fname, sizeof(fname), "%s.aff", fnames[i]); | 3010 vim_snprintf((char *)fname, sizeof(fname), "%s.aff", innames[i]); |
2792 if (mch_stat((char *)fname, &st) >= 0) | 3011 if (mch_stat((char *)fname, &st) >= 0) |
2793 { | 3012 { |
2794 /* Read the .aff file. Will init "spin->si_conv" based on the | 3013 /* Read the .aff file. Will init "spin->si_conv" based on the |
2795 * "SET" line. */ | 3014 * "SET" line. */ |
2796 afile[i - 1] = spell_read_aff(fname, &spin); | 3015 afile[i] = spell_read_aff(fname, &spin); |
2797 if (afile[i - 1] == NULL) | 3016 if (afile[i] == NULL) |
2798 error = TRUE; | 3017 error = TRUE; |
2799 else | 3018 else |
2800 { | 3019 { |
2801 /* Read the .dic file and store the words in the trees. */ | 3020 /* Read the .dic file and store the words in the trees. */ |
2802 vim_snprintf((char *)fname, sizeof(fname), "%s.dic", | 3021 vim_snprintf((char *)fname, sizeof(fname), "%s.dic", |
2803 fnames[i]); | 3022 innames[i]); |
2804 if (spell_read_dic(fname, &spin, afile[i - 1]) == FAIL) | 3023 if (spell_read_dic(fname, &spin, afile[i]) == FAIL) |
2805 error = TRUE; | 3024 error = TRUE; |
2806 } | 3025 } |
2807 } | 3026 } |
2808 else | 3027 else |
2809 { | 3028 { |
2810 /* No .aff file, try reading the file as a word list. Store | 3029 /* No .aff file, try reading the file as a word list. Store |
2811 * the words in the trees. */ | 3030 * the words in the trees. */ |
2812 if (spell_read_wordfile(fnames[i], &spin) == FAIL) | 3031 if (spell_read_wordfile(innames[i], &spin) == FAIL) |
2813 error = TRUE; | 3032 error = TRUE; |
2814 } | 3033 } |
2815 | 3034 |
3035 #ifdef FEAT_MBYTE | |
2816 /* Free any conversion stuff. */ | 3036 /* Free any conversion stuff. */ |
2817 convert_setup(&spin.si_conv, NULL, NULL); | 3037 convert_setup(&spin.si_conv, NULL, NULL); |
3038 #endif | |
2818 } | 3039 } |
2819 | 3040 |
2820 if (!error) | 3041 if (!error) |
2821 { | 3042 { |
2822 /* | 3043 /* |
2826 spin.si_keeproot = spin.si_keeproot->wn_sibling; | 3047 spin.si_keeproot = spin.si_keeproot->wn_sibling; |
2827 | 3048 |
2828 /* | 3049 /* |
2829 * Combine tails in the tree. | 3050 * Combine tails in the tree. |
2830 */ | 3051 */ |
2831 MSG(_("Compressing word tree...")); | 3052 if (verbose || p_verbose > 2) |
2832 out_flush(); | 3053 { |
2833 wordtree_compress(spin.si_foldroot); | 3054 if (!verbose) |
2834 wordtree_compress(spin.si_keeproot); | 3055 verbose_enter(); |
3056 MSG(_("Compressing word tree...")); | |
3057 out_flush(); | |
3058 if (!verbose) | |
3059 verbose_leave(); | |
3060 } | |
3061 wordtree_compress(spin.si_foldroot, &spin); | |
3062 wordtree_compress(spin.si_keeproot, &spin); | |
2835 } | 3063 } |
2836 | 3064 |
2837 if (!error) | 3065 if (!error) |
2838 { | 3066 { |
2839 /* | 3067 /* |
2840 * Write the info in the spell file. | 3068 * Write the info in the spell file. |
2841 */ | 3069 */ |
2842 smsg((char_u *)_("Writing spell file %s..."), wfname); | 3070 if (verbose || p_verbose > 2) |
2843 out_flush(); | 3071 { |
2844 write_vim_spell(wfname, &spin, fcount - 1, region_name); | 3072 if (!verbose) |
2845 MSG(_("Done!")); | 3073 verbose_enter(); |
2846 | 3074 smsg((char_u *)_("Writing spell file %s..."), wfname); |
2847 smsg((char_u *)_("Estimated runtime memory use: %d bytes"), | 3075 out_flush(); |
3076 if (!verbose) | |
3077 verbose_leave(); | |
3078 } | |
3079 | |
3080 write_vim_spell(wfname, &spin, incount, region_name); | |
3081 | |
3082 if (verbose || p_verbose > 2) | |
3083 { | |
3084 if (!verbose) | |
3085 verbose_enter(); | |
3086 MSG(_("Done!")); | |
3087 smsg((char_u *)_("Estimated runtime memory use: %d bytes"), | |
2848 spin.si_memtot); | 3088 spin.si_memtot); |
2849 out_flush(); | 3089 out_flush(); |
2850 | 3090 if (!verbose) |
2851 /* May need to reload spell dictionaries */ | 3091 verbose_leave(); |
2852 spell_reload(); | 3092 } |
3093 | |
3094 /* If the file is loaded need to reload it. */ | |
3095 spell_reload_one(wfname); | |
2853 } | 3096 } |
2854 | 3097 |
2855 /* Free the allocated memory. */ | 3098 /* Free the allocated memory. */ |
2856 free_blocks(spin.si_blocks); | 3099 free_blocks(spin.si_blocks); |
2857 | 3100 |
2858 /* Free the .aff file structures. */ | 3101 /* Free the .aff file structures. */ |
2859 for (i = 1; i < fcount; ++i) | 3102 for (i = 0; i < incount; ++i) |
2860 if (afile[i - 1] != NULL) | 3103 if (afile[i] != NULL) |
2861 spell_free_aff(afile[i - 1]); | 3104 spell_free_aff(afile[i]); |
2862 } | 3105 } |
2863 | 3106 } |
2864 theend: | 3107 |
2865 FreeWild(fcount, fnames); | 3108 |
2866 } | 3109 /* |
2867 | 3110 * ":spellgood {word}" |
2868 #endif /* FEAT_MBYTE */ | 3111 * ":spellwrong {word}" |
3112 */ | |
3113 void | |
3114 ex_spell(eap) | |
3115 exarg_T *eap; | |
3116 { | |
3117 spell_add_word(eap->arg, STRLEN(eap->arg), eap->cmdidx == CMD_spellwrong); | |
3118 } | |
3119 | |
3120 /* | |
3121 * Add "word[len]" to 'spellfile' as a good or bad word. | |
3122 */ | |
3123 void | |
3124 spell_add_word(word, len, bad) | |
3125 char_u *word; | |
3126 int len; | |
3127 int bad; | |
3128 { | |
3129 FILE *fd; | |
3130 buf_T *buf; | |
3131 | |
3132 if (*curbuf->b_p_spf == NUL) | |
3133 init_spellfile(); | |
3134 if (*curbuf->b_p_spf == NUL) | |
3135 EMSG(_("E999: 'spellfile' is not set")); | |
3136 else | |
3137 { | |
3138 /* Check that the user isn't editing the .add file somewhere. */ | |
3139 buf = buflist_findname_exp(curbuf->b_p_spf); | |
3140 if (buf != NULL && buf->b_ml.ml_mfp == NULL) | |
3141 buf = NULL; | |
3142 if (buf != NULL && bufIsChanged(buf)) | |
3143 EMSG(_(e_bufloaded)); | |
3144 else | |
3145 { | |
3146 fd = mch_fopen((char *)curbuf->b_p_spf, "a"); | |
3147 if (fd == NULL) | |
3148 EMSG2(_(e_notopen), curbuf->b_p_spf); | |
3149 else | |
3150 { | |
3151 if (bad) | |
3152 fprintf(fd, "/!%.*s\n", len, word); | |
3153 else | |
3154 fprintf(fd, "%.*s\n", len, word); | |
3155 fclose(fd); | |
3156 | |
3157 /* Update the .add.spl file. */ | |
3158 mkspell(1, &curbuf->b_p_spf, FALSE, TRUE, FALSE); | |
3159 | |
3160 /* If the .add file is edited somewhere, reload it. */ | |
3161 if (buf != NULL) | |
3162 buf_reload(buf); | |
3163 } | |
3164 } | |
3165 } | |
3166 } | |
3167 | |
3168 /* | |
3169 * Initialize 'spellfile' for the current buffer. | |
3170 */ | |
3171 static void | |
3172 init_spellfile() | |
3173 { | |
3174 char_u buf[MAXPATHL]; | |
3175 int l; | |
3176 slang_T *sl; | |
3177 char_u *rtp; | |
3178 | |
3179 if (*curbuf->b_p_spl != NUL && curbuf->b_langp.ga_len > 0) | |
3180 { | |
3181 /* Loop over all entries in 'runtimepath'. */ | |
3182 rtp = p_rtp; | |
3183 while (*rtp != NUL) | |
3184 { | |
3185 /* Copy the path from 'runtimepath' to buf[]. */ | |
3186 copy_option_part(&rtp, buf, MAXPATHL, ","); | |
3187 if (filewritable(buf) == 2) | |
3188 { | |
3189 sl = LANGP_ENTRY(curbuf->b_langp, 0)->lp_slang; | |
3190 l = STRLEN(buf); | |
3191 vim_snprintf((char *)buf + l, MAXPATHL - l, | |
3192 "/spell/%.2s.%s.add", | |
3193 sl->sl_name, | |
3194 strstr((char *)gettail(sl->sl_fname), ".ascii.") != NULL | |
3195 ? (char_u *)"ascii" : spell_enc()); | |
3196 set_option_value((char_u *)"spellfile", 0L, buf, OPT_LOCAL); | |
3197 break; | |
3198 } | |
3199 } | |
3200 } | |
3201 } | |
2869 | 3202 |
2870 | 3203 |
2871 /* | 3204 /* |
2872 * Init the chartab used for spelling for ASCII. | 3205 * Init the chartab used for spelling for ASCII. |
2873 * EBCDIC is not supported! | 3206 * EBCDIC is not supported! |
2935 } | 3268 } |
2936 } | 3269 } |
2937 } | 3270 } |
2938 } | 3271 } |
2939 | 3272 |
2940 #if defined(FEAT_MBYTE) || defined(PROTO) | |
2941 static char *e_affform = N_("E761: Format error in affix file FOL, LOW or UPP"); | 3273 static char *e_affform = N_("E761: Format error in affix file FOL, LOW or UPP"); |
2942 static char *e_affrange = N_("E762: Character in FOL, LOW or UPP is out of range"); | 3274 static char *e_affrange = N_("E762: Character in FOL, LOW or UPP is out of range"); |
2943 | 3275 |
2944 /* | 3276 /* |
2945 * Set the spell character tables from strings in the affix file. | 3277 * Set the spell character tables from strings in the affix file. |
3014 return FAIL; | 3346 return FAIL; |
3015 } | 3347 } |
3016 | 3348 |
3017 return set_spell_finish(&new_st); | 3349 return set_spell_finish(&new_st); |
3018 } | 3350 } |
3019 #endif | |
3020 | 3351 |
3021 /* | 3352 /* |
3022 * Set the spell character tables from strings in the .spl file. | 3353 * Set the spell character tables from strings in the .spl file. |
3023 */ | 3354 */ |
3024 static int | 3355 static int |
3080 } | 3411 } |
3081 | 3412 |
3082 return OK; | 3413 return OK; |
3083 } | 3414 } |
3084 | 3415 |
3085 #if defined(FEAT_MBYTE) || defined(PROTO) | |
3086 /* | 3416 /* |
3087 * Write the current tables into the .spl file. | 3417 * Write the current tables into the .spl file. |
3088 * This makes sure the same characters are recognized as word characters when | 3418 * This makes sure the same characters are recognized as word characters when |
3089 * generating an when using a spell file. | 3419 * generating an when using a spell file. |
3090 */ | 3420 */ |
3105 flags |= SPELL_ISWORD; | 3435 flags |= SPELL_ISWORD; |
3106 if (spelltab.st_isu[i]) | 3436 if (spelltab.st_isu[i]) |
3107 flags |= SPELL_ISUPPER; | 3437 flags |= SPELL_ISUPPER; |
3108 fputc(flags, fd); /* <charflags> */ | 3438 fputc(flags, fd); /* <charflags> */ |
3109 | 3439 |
3110 len += mb_char2bytes(spelltab.st_fold[i], charbuf + len); | 3440 #ifdef FEAT_MBYTE |
3441 if (has_mbyte) | |
3442 len += mb_char2bytes(spelltab.st_fold[i], charbuf + len); | |
3443 else | |
3444 #endif | |
3445 charbuf[len++] = spelltab.st_fold[i]; | |
3111 } | 3446 } |
3112 | 3447 |
3113 put_bytes(fd, (long_u)len, 2); /* <fcharlen> */ | 3448 put_bytes(fd, (long_u)len, 2); /* <fcharlen> */ |
3114 fwrite(charbuf, (size_t)len, (size_t)1, fd); /* <fchars> */ | 3449 fwrite(charbuf, (size_t)len, (size_t)1, fd); /* <fchars> */ |
3115 } | 3450 } |
3116 #endif | |
3117 | 3451 |
3118 /* | 3452 /* |
3119 * Return TRUE if "c" is an upper-case character for spelling. | 3453 * Return TRUE if "c" is an upper-case character for spelling. |
3120 */ | 3454 */ |
3121 static int | 3455 static int |