Codebase list enchant-2 / 15c7026
Update upstream source from tag 'upstream/2.3.2' Update to upstream version '2.3.2' with Debian dir d7fec9721862c74c333dd8bafc066bc39fbd604b Jeremy Bicha 2 years ago
27 changed file(s) with 399 addition(s) and 413 deletion(s). Raw diff Collapse all Expand all
0 2.3.2 (November 16, 2021)
1 -------------------------
2
3 Fix the generation of man pages, so that installation-dependent paths are
4 correctly inserted.
5
6 Improve error reporting when enchant-lsmod cannot open a dictionary for a
7 given language, in particular with the Aspell backend.
8
9 Fix compilation on MingW.
10
11 Some minor code cleanup.
12
13
014 2.3.1 (August 9, 2021)
115 ----------------------
216
00 #! /bin/sh
11 # Guess values for system-dependent variables and create Makefiles.
2 # Generated by GNU Autoconf 2.69 for enchant 2.3.1.
2 # Generated by GNU Autoconf 2.69 for enchant 2.3.2.
33 #
44 #
55 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
586586 # Identity of this package.
587587 PACKAGE_NAME='enchant'
588588 PACKAGE_TARNAME='enchant'
589 PACKAGE_VERSION='2.3.1'
590 PACKAGE_STRING='enchant 2.3.1'
589 PACKAGE_VERSION='2.3.2'
590 PACKAGE_STRING='enchant 2.3.2'
591591 PACKAGE_BUGREPORT=''
592592 PACKAGE_URL=''
593593
17861786 # Omit some internal or obsolete options to make the list less imposing.
17871787 # This message is too long to be a string in the A/UX 3.1 sh.
17881788 cat <<_ACEOF
1789 \`configure' configures enchant 2.3.1 to adapt to many kinds of systems.
1789 \`configure' configures enchant 2.3.2 to adapt to many kinds of systems.
17901790
17911791 Usage: $0 [OPTION]... [VAR=VALUE]...
17921792
18571857
18581858 if test -n "$ac_init_help"; then
18591859 case $ac_init_help in
1860 short | recursive ) echo "Configuration of enchant 2.3.1:";;
1860 short | recursive ) echo "Configuration of enchant 2.3.2:";;
18611861 esac
18621862 cat <<\_ACEOF
18631863
20242024 test -n "$ac_init_help" && exit $ac_status
20252025 if $ac_init_version; then
20262026 cat <<\_ACEOF
2027 enchant configure 2.3.1
2027 enchant configure 2.3.2
20282028 generated by GNU Autoconf 2.69
20292029
20302030 Copyright (C) 2012 Free Software Foundation, Inc.
28802880 This file contains any messages produced by compilers while
28812881 running configure, to aid debugging if configure makes a mistake.
28822882
2883 It was created by enchant $as_me 2.3.1, which was
2883 It was created by enchant $as_me 2.3.2, which was
28842884 generated by GNU Autoconf 2.69. Invocation command line was
28852885
28862886 $ $0 $@
37513751
37523752 # Define the identity of the package.
37533753 PACKAGE='enchant'
3754 VERSION='2.3.1'
3754 VERSION='2.3.2'
37553755
37563756
37573757 cat >>confdefs.h <<_ACEOF
2526425264 # report actual input values of CONFIG_FILES etc. instead of their
2526525265 # values after options handling.
2526625266 ac_log="
25267 This file was extended by enchant $as_me 2.3.1, which was
25267 This file was extended by enchant $as_me 2.3.2, which was
2526825268 generated by GNU Autoconf 2.69. Invocation command line was
2526925269
2527025270 CONFIG_FILES = $CONFIG_FILES
2533025330 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
2533125331 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
2533225332 ac_cs_version="\\
25333 enchant config.status 2.3.1
25333 enchant config.status 2.3.2
2533425334 configured by $0, generated by GNU Autoconf 2.69,
2533525335 with options \\"\$ac_cs_config\\"
2533625336
0 AC_INIT([enchant],[2.3.1])
0 AC_INIT([enchant],[2.3.2])
11 AC_CONFIG_SRCDIR(src/enchant.h)
22 AC_CONFIG_AUX_DIR([build-aux])
33 AM_INIT_AUTOMAKE([subdir-objects])
7070 size_t len, size_t * out_n_suggs)
7171 {
7272 AspellSpeller *manager = (AspellSpeller *) me->user_data;
73
73
7474 char *normalizedWord = g_utf8_normalize (word, len, G_NORMALIZE_NFC);
7575 const AspellWordList *word_list = aspell_speller_suggest (manager, normalizedWord, strlen(normalizedWord));
7676 g_free(normalizedWord);
8383 {
8484 size_t n_suggestions = aspell_word_list_size (word_list);
8585 *out_n_suggs = n_suggestions;
86
86
8787 if (n_suggestions)
8888 {
8989 sugg_arr = g_new0 (char *, n_suggestions + 1);
90
90
9191 for (size_t i = 0; i < n_suggestions; i++)
9292 {
9393 const char *sugg = aspell_string_enumeration_next (suggestions);
9898 delete_aspell_string_enumeration (suggestions);
9999 }
100100 }
101
101
102102 return sugg_arr;
103103 }
104104
136136 AspellConfig *spell_config = new_aspell_config ();
137137 aspell_config_replace (spell_config, "language-tag", tag);
138138 aspell_config_replace (spell_config, "encoding", "utf-8");
139
139
140140 AspellCanHaveError *spell_error = new_aspell_speller (spell_config);
141141 delete_aspell_config (spell_config);
142
142
143143 if (aspell_error_number (spell_error) != 0)
144144 {
145 enchant_provider_set_error (me, aspell_error_message (spell_error));
145146 delete_aspell_can_have_error(spell_error);
146147 return NULL;
147148 }
148
149
149150 AspellSpeller *manager = to_aspell_speller (spell_error);
150
151
151152 EnchantDict *dict = g_new0 (EnchantDict, 1);
152153 dict->user_data = (void *) manager;
153154 dict->check = aspell_dict_check;
155156 dict->add_to_personal = aspell_dict_add_to_personal;
156157 dict->add_to_session = aspell_dict_add_to_session;
157158 dict->store_replacement = aspell_dict_store_replacement;
158
159
159160 return dict;
160161 }
161162
164165 {
165166 AspellSpeller *manager = (AspellSpeller *) dict->user_data;
166167 delete_aspell_speller (manager);
167
168
168169 g_free (dict);
169170 }
170171
171 static char **
172 aspell_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER,
172 static char **
173 aspell_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER,
173174 size_t * out_n_dicts)
174175 {
175176 AspellConfig * spell_config = new_aspell_config ();
189190 if (*out_n_dicts) {
190191 out_list = g_new0 (char *, *out_n_dicts + 1);
191192 dels = aspell_dict_info_list_elements (dlist);
192
193
193194 for (size_t i = 0; i < *out_n_dicts; i++) {
194 entry = aspell_dict_info_enumeration_next (dels);
195 entry = aspell_dict_info_enumeration_next (dels);
195196 /* FIXME: should this be entry->code or entry->name ? */
196197 out_list[i] = g_strdup (entry->code);
197198 }
198
199
199200 delete_aspell_dict_info_enumeration (dels);
200201 }
201
202
202203 delete_aspell_config (spell_config);
203
204
204205 return out_list;
205206 }
206207
6565 "utf-8", "iso8859-8", NULL, &len, NULL);
6666 }
6767 }
68
68
6969 return sugg_arr;
7070 }
7171
8686 struct dict_radix *hspell_dict = (struct dict_radix *)me->user_data;
8787 char *iso_word = hspell_convert_to_iso8859_8 (me, word, len);
8888 g_return_val_if_fail (iso_word, -1);
89
89
9090 /* check */
9191 int preflen;
9292 int res = hspell_check_word (hspell_dict, iso_word, &preflen);
93
93
9494 /* if not correct try gimatria */
9595 if (res != 1)
9696 res = hspell_is_canonic_gimatria (iso_word) != 0;
97
97
9898 g_free (iso_word);
99
99
100100 return (res != 1);
101101 }
102102
112112 struct corlist cl;
113113 corlist_init (&cl);
114114 hspell_trycorrect (hspell_dict, iso_word, &cl);
115
115
116116 *out_n_suggs = corlist_n (&cl);
117117 char **sugg_arr = corlist2strv (&cl, *out_n_suggs);
118118 corlist_free (&cl);
119119 g_free (iso_word);
120
121 return sugg_arr;
120
121 return sugg_arr;
122122 }
123123
124124 static EnchantDict *
126126 {
127127 if(!((strlen(tag) >= 2) && tag[0] == 'h' && tag[1] == 'e'))
128128 return NULL;
129
129
130130 /* try to set a new session */
131131 struct dict_radix *hspell_dict = NULL;
132132 int dict_flag = hspell_init (&hspell_dict, HSPELL_OPT_DEFAULT);
133
133
134134 if (dict_flag != 0 || !hspell_dict)
135135 {
136136 enchant_provider_set_error (me, "can't create new dict.");
137137 return NULL;
138138 }
139
139
140140 EnchantDict *dict = g_new0 (EnchantDict, 1);
141141 dict->user_data = (void *) hspell_dict;
142142 dict->check = hspell_dict_check;
143143 dict->suggest = hspell_dict_suggest;
144
144
145145 return dict;
146146 }
147147
155155
156156 /* test for the existence of, then return $prefix/share/hspell/hebrew.wgz */
157157
158 static char **
159 hspell_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER,
158 static char **
159 hspell_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER,
160160 size_t * out_n_dicts)
161161 {
162162 const char * dictionary_path = hspell_get_dictionary_path();
166166 if(dictionary_path && *dictionary_path && g_file_test (dictionary_path, G_FILE_TEST_EXISTS)) {
167167 out_list = g_new0 (char *, 2);
168168 out_list[(*out_n_dicts)++] = g_strdup ("he");
169 }
170
169 }
170
171171 return out_list;
172172 }
173173
3636
3737 #include <stdio.h>
3838 #include <stdlib.h>
39 #include <string.h>
39 #include <string.h>
4040
4141 #include <string>
4242 #include <vector>
241241 size_t tag_len = strlen(tag);
242242
243243 if (dir_entry_len - dic_suffix_len < tag_len)
244 return false;
244 return false;
245245 if (strcmp(dir_entry+dir_entry_len-dic_suffix_len, dic_suffix) != 0)
246 return false;
246 return false;
247247 if (strncmp (dir_entry, tag, tag_len) != 0)
248 return false;
248 return false;
249249 //e.g. requested dict for "fi",
250250 //reject "fil_PH.dic"
251251 //allow "fi-FOO.dic", "fi_FOO.dic", "fi.dic", etc.
252252 if (!ispunct(dir_entry[tag_len]))
253 return false;
253 return false;
254254 return true;
255255 }
256256
267267 return strdup (names[i].c_str());
268268 }
269269 }
270
270
271271 std::vector<std::string> dirs;
272272 s_buildDictionaryDirs (dirs);
273273
277277 const char *dir_entry;
278278 while ((dir_entry = g_dir_read_name (dir)) != NULL) {
279279 if (is_plausible_dict_for_tag(dir_entry, tag)) {
280 char *dict = g_build_filename (dirs[i].c_str(),
280 char *dict = g_build_filename (dirs[i].c_str(),
281281 dir_entry, nullptr);
282282 if(s_fileExists(s_correspondingAffFile(dict))) {
283283 g_dir_close (dir);
347347 hunspell_dict_check (EnchantDict * me, const char *const word, size_t len)
348348 {
349349 HunspellChecker * checker = static_cast<HunspellChecker *>(me->user_data);
350
350
351351 if (checker->checkWord(word, len))
352352 return 0;
353
353
354354 return 1;
355355 }
356356
409409
410410 extern "C" {
411411
412 static char **
413 hunspell_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER,
412 static char **
413 hunspell_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER,
414414 size_t * out_n_dicts)
415415 {
416416 std::vector<std::string> dict_dirs, dicts;
438438 hunspell_provider_request_dict(EnchantProvider * me _GL_UNUSED_PARAMETER, const char *const tag)
439439 {
440440 HunspellChecker * checker = new HunspellChecker();
441
441
442442 if (!checker)
443443 return NULL;
444
444
445445 if (!checker->requestDictionary(tag)) {
446446 delete checker;
447447 return NULL;
448448 }
449
449
450450 EnchantDict *dict = g_new0(EnchantDict, 1);
451451 dict->user_data = (void *) checker;
452452 dict->check = hunspell_dict_check;
454454 // don't implement personal, session
455455 dict->get_extra_word_characters = hunspell_dict_get_extra_word_characters;
456456 dict->is_word_character = hunspell_dict_is_word_character;
457
457
458458 return dict;
459459 }
460460
463463 {
464464 HunspellChecker *checker = (HunspellChecker *) dict->user_data;
465465 delete checker;
466
466
467467 g_free (dict);
468468 }
469469
4949 static int
5050 voikko_dict_check (EnchantDict * me, const char *const word, size_t len)
5151 {
52 char *word_nul = strndup(word, len);
52 char *word_nul = g_strndup(word, len);
5353 int result = voikkoSpellCstr((struct VoikkoHandle *)me->user_data, word_nul);
5454 free(word_nul);
5555 if (result == VOIKKO_SPELL_FAILED)
6464 voikko_dict_suggest (EnchantDict * me, const char *const word,
6565 size_t len, size_t * out_n_suggs)
6666 {
67 char *word_nul = strndup(word, len);
67 char *word_nul = g_strndup(word, len);
6868 char **voikko_sugg_arr = voikkoSuggestCstr((struct VoikkoHandle *)me->user_data, word_nul);
6969 free(word_nul);
7070 if (voikko_sugg_arr == NULL)
112112
113113 static int
114114 voikko_provider_dictionary_exists (struct str_enchant_provider * me _GL_UNUSED_PARAMETER,
115 const char *const tag)
115 const char *const tag)
116116 {
117117 size_t i;
118118 int exists = 0;
00 /* Copyright (C) 2006 Barış Metin <baris@pardus.org.tr>
11 * Copyright (C) 2007 Serkan Kaba <serkan_kaba@yahoo.com>
2 *
2 *
33 * This library is free software; you can redistribute it and/or
44 * modify it under the terms of the GNU Lesser General Public
55 * License as published by the Free Software Foundation; either
5151 "/net/zemberekserver/server/dbus/ZemberekDbus",
5252 "net.zemberekserver.server.dbus.ZemberekDbusInterface",
5353 &Error);
54
54
5555 dbus_g_connection_unref (connection);
5656 if (proxy == NULL) {
5757 return false;
6666 public:
6767 Zemberek();
6868 ~Zemberek();
69
69
7070 int checkWord(const char* word) const;
7171 char** suggestWord(const char* word, size_t *out_n_suggs);
7272
100100 Zemberek::~Zemberek()
101101 {
102102 if(proxy)
103 g_object_unref (proxy);
103 g_object_unref (proxy);
104104 if(connection)
105 dbus_g_connection_unref (connection);
105 dbus_g_connection_unref (connection);
106106 }
107107
108108
111111 gboolean result;
112112 GError *Error = NULL;
113113 if (!dbus_g_proxy_call (proxy, "kelimeDenetle", &Error,
114 G_TYPE_STRING,word,G_TYPE_INVALID,
115 G_TYPE_BOOLEAN, &result, G_TYPE_INVALID)) {
116 g_error_free (Error);
117 return -1;
114 G_TYPE_STRING,word,G_TYPE_INVALID,
115 G_TYPE_BOOLEAN, &result, G_TYPE_INVALID)) {
116 g_error_free (Error);
117 return -1;
118118 }
119119 else
120120 return !result;
126126 char** suggs;
127127 GError *Error = NULL;
128128 if (!dbus_g_proxy_call (proxy, "oner", &Error,
129 G_TYPE_STRING,word,G_TYPE_INVALID,
130 G_TYPE_STRV, &suggs,G_TYPE_INVALID)) {
131 g_error_free (Error);
132 return NULL;
129 G_TYPE_STRING,word,G_TYPE_INVALID,
130 G_TYPE_STRV, &suggs,G_TYPE_INVALID)) {
131 g_error_free (Error);
132 return NULL;
133133 }
134134 *out_n_suggs = g_strv_length(suggs);
135135 return suggs;
171171 zemberek_provider_request_dict(EnchantProvider *me _GL_UNUSED_PARAMETER, const char *tag)
172172 {
173173 if (!((strcmp(tag, "tr") == 0) || (strncmp(tag, "tr_", 3) == 0)))
174 return NULL; // only handle turkish
174 return NULL; // only handle turkish
175175
176176 try
177177 {
178 Zemberek* checker = new Zemberek();
179
180 EnchantDict* dict = g_new0(EnchantDict, 1);
181 dict->user_data = (void *) checker;
182 dict->check = zemberek_dict_check;
183 dict->suggest = zemberek_dict_suggest;
184
185 return dict;
178 Zemberek* checker = new Zemberek();
179
180 EnchantDict* dict = g_new0(EnchantDict, 1);
181 dict->user_data = (void *) checker;
182 dict->check = zemberek_dict_check;
183 dict->suggest = zemberek_dict_suggest;
184
185 return dict;
186186 }
187187 catch(...)
188188 {
189 // will fail if zemberek service isn't running
190 return NULL;
189 // will fail if zemberek service isn't running
190 return NULL;
191191 }
192192 }
193193
202202 static const char *
203203 zemberek_provider_identify (EnchantProvider * me _GL_UNUSED_PARAMETER)
204204 {
205 return "zemberek";
205 return "zemberek";
206206 }
207207
208208 static const char *
209209 zemberek_provider_describe (EnchantProvider * me _GL_UNUSED_PARAMETER)
210210 {
211 return "Zemberek Provider";
211 return "Zemberek Provider";
212212 }
213213
214214 static char **
215215 zemberek_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER,
216 size_t * out_n_dicts)
216 size_t * out_n_dicts)
217217 {
218218 if (!zemberek_service_is_running ())
219219 {
220 *out_n_dicts = 0;
221 return NULL;
220 *out_n_dicts = 0;
221 return NULL;
222222 }
223223 else
224224 {
225 *out_n_dicts = 1;
226 char ** out_list = g_new0 (char *, 2);
227 out_list[0] = g_strdup ("tr");
228
229 return out_list;
225 *out_n_dicts = 1;
226 char ** out_list = g_new0 (char *, 2);
227 out_list[0] = g_strdup ("tr");
228
229 return out_list;
230230 }
231231 }
232232
1818
1919 libenchant_includedir = $(pkgincludedir)-@ENCHANT_MAJOR_VERSION@
2020 libenchant_include_HEADERS = enchant.h enchant-provider.h enchant++.h
21 noinst_HEADERS = debug.h
2122
2223 pkgdata_DATA = enchant.ordering
2324
2425 dist_man_MANS = enchant-@ENCHANT_MAJOR_VERSION@.1 enchant-lsmod-@ENCHANT_MAJOR_VERSION@.1
2526
2627 edit = sed \
27 -e 's|@datadir[@]|$(datadir)|g'
28 -e 's|DATADIR|$(datadir)|g'
2829
2930 DISTCLEANFILES = $(dist_man_MANS)
3031
3435 mv $@.tmp $@
3536
3637 enchant-lsmod-@ENCHANT_MAJOR_VERSION@.1: $(builddir)/enchant-lsmod.1 Makefile.am $(top_builddir)/config.status
37 rm -f $@ $@.tmp
38 $(edit) $(abs_builddir)/enchant-lsmod.1 >$@.tmp
39 mv $@.tmp $@
38 cp $(abs_builddir)/enchant-lsmod.1 $@
4039
4140 LDADD = libenchant-@ENCHANT_MAJOR_VERSION@.la $(ENCHANT_LIBS) $(top_builddir)/lib/libgnu.la
4241 bin_PROGRAMS = enchant-@ENCHANT_MAJOR_VERSION@ enchant-lsmod-@ENCHANT_MAJOR_VERSION@
126126 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
127127 $(ACLOCAL_M4)
128128 DIST_COMMON = $(srcdir)/Makefile.am $(libenchant_include_HEADERS) \
129 $(am__DIST_COMMON)
129 $(noinst_HEADERS) $(am__DIST_COMMON)
130130 mkinstalldirs = $(install_sh) -d
131131 CONFIG_HEADER = $(top_builddir)/config.h
132132 CONFIG_CLEAN_FILES = libenchant.rc enchant.1 enchant-lsmod.1
253253 NROFF = nroff
254254 MANS = $(dist_man_MANS)
255255 DATA = $(pkgdata_DATA)
256 HEADERS = $(libenchant_include_HEADERS)
256 HEADERS = $(libenchant_include_HEADERS) $(noinst_HEADERS)
257257 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
258258 # Read a list of newline-separated strings from the standard input,
259259 # and print each of them once, without duplicates. Input order is
799799 pwl.h $(am__append_3)
800800 libenchant_includedir = $(pkgincludedir)-@ENCHANT_MAJOR_VERSION@
801801 libenchant_include_HEADERS = enchant.h enchant-provider.h enchant++.h
802 noinst_HEADERS = debug.h
802803 pkgdata_DATA = enchant.ordering
803804 dist_man_MANS = enchant-@ENCHANT_MAJOR_VERSION@.1 enchant-lsmod-@ENCHANT_MAJOR_VERSION@.1
804805 edit = sed \
805 -e 's|@datadir[@]|$(datadir)|g'
806 -e 's|DATADIR|$(datadir)|g'
806807
807808 DISTCLEANFILES = $(dist_man_MANS)
808809 LDADD = libenchant-@ENCHANT_MAJOR_VERSION@.la $(ENCHANT_LIBS) $(top_builddir)/lib/libgnu.la
13271328 mv $@.tmp $@
13281329
13291330 enchant-lsmod-@ENCHANT_MAJOR_VERSION@.1: $(builddir)/enchant-lsmod.1 Makefile.am $(top_builddir)/config.status
1330 rm -f $@ $@.tmp
1331 $(edit) $(abs_builddir)/enchant-lsmod.1 >$@.tmp
1332 mv $@.tmp $@
1331 cp $(abs_builddir)/enchant-lsmod.1 $@
13331332
13341333 .rc.lo:
13351334 $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) $< -o $@
0 /* enchant
1 * Copyright (C) 2021 Reuben Thomas <rrt@sc3d.org>
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the
15 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 * Boston, MA 02110-1301, USA.
17 *
18 * In addition, as a special exception, the copyright holders
19 * give permission to link the code of this program with
20 * non-LGPL Spelling Provider libraries (eg: a MSFT Office
21 * spell checker backend) and distribute linked combinations including
22 * the two. You must obey the GNU Lesser General Public License in all
23 * respects for all of the code used other than said providers. If you modify
24 * this file, you may extend this exception to your version of the
25 * file, but you are not obligated to do so. If you do not wish to
26 * do so, delete this exception statement from your version.
27 */
28
29 #ifdef DEBUG
30 #define debug(...) fprintf(stderr, __VA_ARGS__)
31 #else
32 #define debug(...)
33 #endif
3434 #include <vector>
3535 #include <exception>
3636
37 namespace enchant
37 namespace enchant
3838 {
3939 void set_prefix_dir (const std::string prefix) {
4040 enchant_set_prefix_dir (prefix.c_str ());
4545 class Exception : public std::exception
4646 {
4747 public:
48 explicit Exception (const char * ex)
48 explicit Exception (const char * ex)
4949 : std::exception (), m_ex ("") {
5050 if (ex)
5151 m_ex = ex;
5353
5454 virtual ~Exception () noexcept {
5555 }
56
56
5757 virtual const char * what () const noexcept {
5858 return m_ex.c_str();
5959 }
6565 class Dict
6666 {
6767 friend class enchant::Broker;
68
68
6969 public:
70
70
7171 ~Dict () {
7272 enchant_broker_free_dict (m_broker, m_dict);
7373 }
74
74
7575 bool check (const std::string & utf8word) {
7676 int val;
7777
78 val = enchant_dict_check (m_dict, utf8word.c_str(),
78 val = enchant_dict_check (m_dict, utf8word.c_str(),
7979 utf8word.size());
8080 if (val == 0)
8181 return true;
8888 return false; // never reached
8989 }
9090
91 void suggest (const std::string & utf8word,
91 void suggest (const std::string & utf8word,
9292 std::vector<std::string> & out_suggestions) {
9393 size_t n_suggs;
9494 char ** suggs;
95
95
9696 out_suggestions.clear ();
97
98 suggs = enchant_dict_suggest (m_dict, utf8word.c_str(),
97
98 suggs = enchant_dict_suggest (m_dict, utf8word.c_str(),
9999 utf8word.size(), &n_suggs);
100
100
101101 if (suggs && n_suggs) {
102102 out_suggestions.reserve(n_suggs);
103103
104104 for (size_t i = 0; i < n_suggs; i++) {
105105 out_suggestions.push_back (suggs[i]);
106106 }
107
107
108108 enchant_dict_free_string_list (m_dict, suggs);
109109 }
110110 }
111
111
112112 std::vector<std::string> suggest (const std::string & utf8word) {
113113 std::vector<std::string> result;
114114 suggest (utf8word, result);
115115 return result;
116116 }
117
117
118118 void add (const std::string & utf8word) {
119 enchant_dict_add (m_dict, utf8word.c_str(),
119 enchant_dict_add (m_dict, utf8word.c_str(),
120120 utf8word.size());
121121 }
122
122
123123 void add_to_session (const std::string & utf8word) {
124 enchant_dict_add_to_session (m_dict, utf8word.c_str(),
125 utf8word.size());
126 }
127
124 enchant_dict_add_to_session (m_dict, utf8word.c_str(),
125 utf8word.size());
126 }
127
128128 void is_added (const std::string & utf8word) {
129 enchant_dict_is_added (m_dict, utf8word.c_str(),
130 utf8word.size());
131 }
132
129 enchant_dict_is_added (m_dict, utf8word.c_str(),
130 utf8word.size());
131 }
132
133133 void remove (const std::string & utf8word) {
134 enchant_dict_remove (m_dict, utf8word.c_str(),
134 enchant_dict_remove (m_dict, utf8word.c_str(),
135135 utf8word.size());
136136 }
137
137
138138 void remove_from_session (const std::string & utf8word) {
139 enchant_dict_remove_from_session (m_dict, utf8word.c_str(),
139 enchant_dict_remove_from_session (m_dict, utf8word.c_str(),
140140 utf8word.size());
141141 }
142142
143143 void is_removed (const std::string & utf8word) {
144 enchant_dict_is_removed (m_dict, utf8word.c_str(),
145 utf8word.size());
146 }
147
148 void store_replacement (const std::string & utf8bad,
144 enchant_dict_is_removed (m_dict, utf8word.c_str(),
145 utf8word.size());
146 }
147
148 void store_replacement (const std::string & utf8bad,
149149 const std::string & utf8good) {
150 enchant_dict_store_replacement (m_dict,
150 enchant_dict_store_replacement (m_dict,
151151 utf8bad.c_str(), utf8bad.size(),
152152 utf8good.c_str(), utf8good.size());
153153 }
154
154
155155 const std::string & get_lang () const {
156156 return m_lang;
157157 }
171171 private:
172172
173173 // space reserved for API/ABI expansion
174 void * _private[5];
174 void * _private[5];
175175
176176 static void s_describe_fn (const char * const lang,
177177 const char * const provider_name,
179179 const char * const provider_file,
180180 void * user_data) {
181181 enchant::Dict * dict = static_cast<enchant::Dict *> (user_data);
182
182
183183 dict->m_lang = lang;
184184 dict->m_provider_name = provider_name;
185185 dict->m_provider_desc = provider_desc;
195195 Dict ();
196196 Dict (const Dict & rhs);
197197 Dict& operator=(const Dict & rhs);
198
198
199199 EnchantDict * m_dict;
200200 EnchantBroker * m_broker;
201201
204204 std::string m_provider_desc;
205205 std::string m_provider_file;
206206 }; // class enchant::Dict
207
207
208208 class Broker
209209 {
210
210
211211 public:
212
212
213213 Broker ()
214214 : m_broker (enchant_broker_init ())
215215 {
221221
222222 Dict * request_dict (const std::string & lang) {
223223 EnchantDict * dict = enchant_broker_request_dict (m_broker, lang.c_str());
224
224
225225 if (!dict) {
226226 throw enchant::Exception (enchant_broker_get_error (m_broker));
227227 return 0; // never reached
228228 }
229
229
230230 return new Dict (dict, m_broker);
231231 }
232232
233233 Dict * request_pwl_dict (const std::string & pwl) {
234234 EnchantDict * dict = enchant_broker_request_pwl_dict (m_broker, pwl.c_str());
235
235
236236 if (!dict) {
237237 throw enchant::Exception (enchant_broker_get_error (m_broker));
238238 return 0; // never reached
239239 }
240
240
241241 return new Dict (dict, m_broker);
242242 }
243
243
244244 bool dict_exists (const std::string & lang) {
245245 if (enchant_broker_dict_exists (m_broker, lang.c_str()))
246246 return true;
247247 return false;
248248 }
249
249
250250 void set_ordering (const std::string & tag, const std::string & ordering) {
251251 enchant_broker_set_ordering (m_broker, tag.c_str(), ordering.c_str());
252252 }
253
253
254254 void describe (EnchantBrokerDescribeFn fn, void * user_data = NULL) {
255255 enchant_broker_describe (m_broker, fn, user_data);
256256 }
257
257
258258 void list_dicts (EnchantDictDescribeFn fn, void * user_data = NULL) {
259259 enchant_broker_list_dicts (m_broker, fn, user_data);
260260 }
264264 // not implemented
265265 Broker (const Broker & rhs);
266266 Broker& operator=(const Broker & rhs);
267
267
268268 EnchantBroker * m_broker;
269269 }; // class enchant::Broker
270270 } // enchant namespace
3535 to decide which spelling provider to use for particular languages.
3636 The per-user file takes precedence.
3737 .PP
38 The ordering file takes the form language_tag:<comma-separated list of spelling
39 providers>. To see what providers are available, run \fIenchant-lsmod-2\fR. '*' is
38 The ordering file takes the form \fIlanguage_tag:<comma-separated list of spelling
39 providers>\fR. The language tag is an IETF BCP 47 language tag, typically of the form \fICOUNTRY_LANGUAGE\fR.
40 To see what dictionaries are available, run \fIenchant-lsmod-2\fR. '*' is
4041 used to mean "use this ordering for all languages, unless instructed otherwise." For example:
4142 .PP
4243 *:aspell,hunspell,nuspell
5859 \fICSIDL_LOCAL_APPDATA\\enchant\fR (Windows systems)
5960 Default: \fIC:\\Documents and Settings\\\fRusername\fI\\Local Settings\\Application Data\\enchant
6061 .TP
61 \fI${prefix}/share/enchant\fR
62 \fI/home/rrt/.local/share/enchant\fR
6263 (Or the equivalent location relative to the enchant library for a relocatable build.)
6364 .PP
6465 Dictionaries are looked for in a subdirectory with the same name as the
65 provider; for example, \fI${prefix}/share/enchant/hunspell\fR and
66 provider; for example, \fI/home/rrt/.local/share/enchant/hunspell\fR and
6667 \fI~/.config/enchant/hunspell\fR.
6768 .PP
6869 Some providers may also look in a standard system directory for their
102102 } else {
103103 EnchantDict *dict = enchant_broker_request_dict (broker, lang_tag);
104104 if (!dict) {
105 fprintf (stderr, "No dictionary available for '%s'\n", lang_tag);
105 fprintf (stderr, "No dictionary available for '%s'", lang_tag);
106 const char *errmsg = enchant_broker_get_error (broker);
107 if (errmsg != NULL)
108 fprintf (stderr, ": %s", errmsg);
109 putc('\n', stderr);
106110 retcode = 1;
107111 } else {
108112 enchant_dict_describe (dict,
127127
128128 int (*check) (struct str_enchant_dict * me, const char *const word,
129129 size_t len);
130
130
131131 /* returns utf8*/
132132 char **(*suggest) (struct str_enchant_dict * me,
133133 const char *const word, size_t len,
134134 size_t * out_n_suggs);
135
135
136136 void (*add_to_personal) (struct str_enchant_dict * me,
137137 const char *const word, size_t len);
138
138
139139 void (*add_to_session) (struct str_enchant_dict * me,
140140 const char *const word, size_t len);
141
141
142142 void (*store_replacement) (struct str_enchant_dict * me,
143143 const char *const mis, size_t mis_len,
144144 const char *const cor, size_t cor_len);
145
145
146146 void (*add_to_exclude) (struct str_enchant_dict * me,
147147 const char *const word, size_t len);
148148
151151 int (*is_word_character) (struct str_enchant_dict * me,
152152 uint32_t uc_in, size_t n);
153153 };
154
154
155155 struct str_enchant_provider
156156 {
157157 void *user_data;
158158 void *enchant_private_data;
159159 EnchantBroker * owner;
160
160
161161 void (*dispose) (struct str_enchant_provider * me);
162
162
163163 EnchantDict *(*request_dict) (struct str_enchant_provider * me,
164164 const char *const tag);
165
165
166166 void (*dispose_dict) (struct str_enchant_provider * me,
167167 EnchantDict * dict);
168
168
169169 int (*dictionary_exists) (struct str_enchant_provider * me,
170170 const char *const tag);
171171
3535 to decide which spelling provider to use for particular languages.
3636 The per-user file takes precedence.
3737 .PP
38 The ordering file takes the form language_tag:<comma-separated list of spelling
39 providers>. To see what providers are available, run \fIenchant-lsmod-@ENCHANT_MAJOR_VERSION@\fR. '*' is
38 The ordering file takes the form \fIlanguage_tag:<comma-separated list of spelling
39 providers>\fR. The language tag is an IETF BCP 47 language tag, typically of the form \fICOUNTRY_LANGUAGE\fR.
40 To see what dictionaries are available, run \fIenchant-lsmod-@ENCHANT_MAJOR_VERSION@\fR. '*' is
4041 used to mean "use this ordering for all languages, unless instructed otherwise." For example:
4142 .PP
4243 *:aspell,hunspell,nuspell
5859 \fICSIDL_LOCAL_APPDATA\\enchant\fR (Windows systems)
5960 Default: \fIC:\\Documents and Settings\\\fRusername\fI\\Local Settings\\Application Data\\enchant
6061 .TP
61 \fI@datadir@/enchant\fR
62 \fIDATADIR/enchant\fR
6263 (Or the equivalent location relative to the enchant library for a relocatable build.)
6364 .PP
6465 Dictionaries are looked for in a subdirectory with the same name as the
65 provider; for example, \fI@datadir@/enchant/hunspell\fR and
66 provider; for example, \fIDATADIR/enchant/hunspell\fR and
6667 \fI~/.config/enchant/hunspell\fR.
6768 .PP
6869 Some providers may also look in a standard system directory for their
5555
5656 static const char *charset;
5757
58 typedef enum
58 typedef enum
5959 {
6060 MODE_NONE,
6161 MODE_A,
6262 MODE_L
6363 } IspellMode_t;
6464
65 static void
65 static void
6666 print_version (FILE * to)
6767 {
6868 fprintf (to, "@(#) International Ispell Version 3.1.20 (but really Enchant %s)\n", PACKAGE_VERSION);
109109 if (utf) {
110110 g_string_assign (str, utf);
111111 g_free (utf);
112 }
113 /* Else str->str stays the same. we'll assume that it's
112 }
113 /* Else str->str stays the same. we'll assume that it's
114114 already utf8 and glib is just being stupid. */
115115 }
116116
127127 if (native) {
128128 fwrite (native, 1, bytes_written, stdout);
129129 g_free (native);
130 } else {
130 } else
131131 /* Assume that it's already utf8 and glib is just being stupid. */
132132 printf ("%s", str);
133 }
134133 }
135134
136135 static int
170169 printf ("%u ", (unsigned int)lineCount);
171170 print_utf (word->str);
172171 printf (" %u %u:", (unsigned int)n_suggs, (unsigned int)start_pos);
173
172
174173 for (size_t i = 0; i < n_suggs; i++) {
175174 putchar (' ');
176175 print_utf (suggs[i]);
211210 while (cur_pos < line->len && *utf) {
212211 gunichar uc;
213212
214 /* Skip non-word characters. */
213 /* Skip non-word characters. */
215214 cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf);
216215 uc = g_utf8_get_char (utf);
217216 while (cur_pos < line->len && *utf && !enchant_dict_is_word_character (dict, uc, 0)) {
218 utf = g_utf8_next_char (utf);
217 utf = g_utf8_next_char (utf);
219218 uc = g_utf8_get_char (utf);
220219 cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf);
221220 }
224223 /* Skip over word characters. */
225224 while (cur_pos < line->len && *utf && enchant_dict_is_word_character (dict, uc, 1)) {
226225 g_string_append_unichar (word, uc);
227 utf = g_utf8_next_char (utf);
226 utf = g_utf8_next_char (utf);
228227 uc = g_utf8_get_char (utf);
229228 cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf);
230229 }
231230
232 /* Skip backwards over any characters that can't appear at the end of a word. */
233 for (gchar *i_utf = word->str + word->len;
231 /* Skip backwards over any characters that can't appear at the end of a word. */
232 for (gchar *i_utf = word->str + word->len;
234233 (i_utf = g_utf8_find_prev_char (word->str, i_utf)) != NULL;
235234 g_string_truncate (word, i_utf - word->str)) {
236235 uc = g_utf8_get_char (i_utf);
239238 }
240239
241240 /* Save (word, position) tuple. */
242 if (word->len) {
243 tokens = g_slist_append (tokens, g_string_new_len (word->str, word->len));
241 if (word->len) {
242 tokens = g_slist_append (tokens, g_string_new_len (word->str, word->len));
244243 tokens = g_slist_append (tokens, GINT_TO_POINTER(start_pos));
245244 g_string_truncate (word, 0);
246245 }
255254 {
256255 EnchantBroker * broker;
257256 EnchantDict * dict;
258
257
259258 GString * str, * word = NULL;
260259 GSList * tokens, *token_ptr;
261260 gchar * lang;
269268 if (dictionary)
270269 lang = strdup (dictionary);
271270 else {
272 lang = enchant_get_user_language();
271 lang = enchant_get_user_language();
273272 if(!lang)
274273 return 1;
275 }
274 }
276275
277276 /* Enchant will get rid of trailing information like de_DE@euro or de_DE.ISO-8859-15 */
278
277
279278 broker = enchant_broker_init ();
280279 dict = enchant_broker_request_dict (broker, lang);
281280
289288 free (lang);
290289
291290 str = g_string_new (NULL);
292
291
293292 while (!was_last_line) {
294293 gboolean mode_A_no_command = FALSE;
295294 was_last_line = consume_line (in, str);
363362 ssize_t mis_len = comma - mis;
364363 ssize_t cor_len = strlen(str->str) - (cor - str->str);
365364 enchant_dict_store_replacement(dict, mis, mis_len, cor, cor_len);
366 } else if (g_str_has_prefix(str->str, "$$wc")) { /* Return the extra word chars list */
365 } else if (g_str_has_prefix(str->str, "$$wc"))
366 /* Return the extra word chars list */
367367 printf("%s\n", enchant_dict_get_extra_word_characters(dict));
368 }
369368 }
370369 break;
371370
403402 if (token_ptr)
404403 g_slist_free (token_ptr);
405404 }
406 }
407
408 if (mode == MODE_A && corrected_something) {
405 }
406
407 if (mode == MODE_A && corrected_something)
409408 putchar('\n');
410 }
411409 g_string_truncate (str, 0);
412410 fflush (stdout);
413411 }
436434 g_get_charset(&charset);
437435 #ifdef _WIN32
438436 /* If reading from stdin, its CP may not be the system CP (which glib's locale gives us) */
439 if (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR) {
437 if (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR)
440438 charset = g_strdup_printf("CP%u", GetConsoleCP());
441 }
442439 #endif
443440
444441 int optchar;
514511 enchant_pwl_free (pwl);
515512 if (file)
516513 fclose (fp);
517
514
518515 return rval;
519516 }
110110 * language that does not explictly declare an ordering.
111111 */
112112 void enchant_broker_set_ordering (EnchantBroker * broker,
113 const char * const tag,
113 const char * const tag,
114114 const char * const ordering);
115115 /**
116116 * enchant_broker_get_error
135135 const char * const provider_desc,
136136 const char * const provider_dll_file,
137137 void * user_data);
138
138
139139 /**
140140 * enchant_broker_describe
141141 * @broker: A non-null #EnchantBroker
175175 * Returns: A %null terminated list of UTF-8 encoded suggestions, or %null
176176 */
177177 char **enchant_dict_suggest (EnchantDict * dict, const char *const word,
178 ssize_t len, size_t * out_n_suggs);
178 ssize_t len, size_t * out_n_suggs);
179179
180180 /**
181181 * enchant_dict_add
00 /* enchant
11 * Copyright (C) 2003, 2004 Dom Lachowicz
2 * Copyright (C) 2017 Reuben Thomas <rrt@sc3d.org>
2 * Copyright (C) 2017-2021 Reuben Thomas <rrt@sc3d.org>
33 *
44 * This library is free software; you can redistribute it and/or
55 * modify it under the terms of the GNU Lesser General Public
4545
4646 #include "enchant.h"
4747 #include "enchant-provider.h"
48 #include "debug.h"
4849 #include "pwl.h"
4950 #include "unused-parameter.h"
5051 #include "relocatable.h"
165166 {
166167 const char * it;
167168 for (it = tag; *it; ++it)
168 {
169 if(!g_ascii_isalnum(*it) && *it != '_')
170 return 0;
171 }
169 if(!g_ascii_isalnum(*it) && *it != '_')
170 return 0;
172171
173172 return it != tag; /*empty tag invalid*/
174173 }
771770 {
772771 if (provider == NULL)
773772 g_warning ("EnchantProvider cannot be NULL\n");
773 else if (provider->dispose == NULL)
774 g_warning ("EnchantProvider's dispose method cannot be NULL\n");
775 else if (provider->request_dict == NULL)
776 g_warning ("EnchantProvider's request_dict method cannot be NULL\n");
777 else if (provider->dispose_dict == NULL)
778 g_warning ("EnchantProvider's dispose_dict method cannot be NULL\n");
774779 else if (provider->identify == NULL)
775780 g_warning ("EnchantProvider's identify method cannot be NULL\n");
776781 else if (!g_utf8_validate((*provider->identify)(provider), -1, NULL))
777 g_warning ("EnchantProvider's identify method does not return valid UTF-8.\n");
782 g_warning ("EnchantProvider's identify method does not return valid UTF-8\n");
778783 else if (provider->describe == NULL)
779784 g_warning ("EnchantProvider's describe method cannot be NULL\n");
780785 else if (!g_utf8_validate((*provider->describe)(provider), -1, NULL))
781 g_warning ("EnchantProvider's describe method does not return valid UTF-8.\n");
782 else if (provider->dispose == NULL)
783 g_warning ("EnchantProvider's dispose method cannot be NULL\n");
784 else if (provider->dispose_dict == NULL)
785 g_warning ("EnchantProvider's dispose_dict method cannot be NULL\n");
786 g_warning ("EnchantProvider's describe method does not return valid UTF-8\n");
786787 else if (provider->list_dicts == NULL)
787788 g_warning ("EnchantProvider's list_dicts method cannot be NULL\n");
788789 else
835836 }
836837 }
837838 else
838 {
839 g_module_close (module);
840 }
839 g_module_close (module);
841840 }
842841 else
843 {
844 g_warning ("Error loading plugin: %s\n", g_module_error());
845 }
842 g_warning ("Error loading plugin: %s\n", g_module_error());
846843
847844 g_free (filename);
848845 #ifdef _WIN32
960957
961958 /* append providers not in the list, or from an unordered list */
962959 for (GSList * iter = broker->provider_list; iter != NULL; iter = g_slist_next (iter))
963 {
964 if (!g_slist_find (list, iter->data))
965 list = g_slist_append (list, iter->data);
966 }
960 if (!g_slist_find (list, iter->data))
961 list = g_slist_append (list, iter->data);
967962
968963 return list;
969964 }
10831078 GSList * list = enchant_get_ordered_providers (broker, tag);
10841079 for (GSList *listIter = list; listIter != NULL; listIter = g_slist_next (listIter))
10851080 {
1086 EnchantProvider * provider;
1087
1088 provider = (EnchantProvider *) listIter->data;
1089
1090 if (provider->request_dict)
1081 EnchantProvider * provider = (EnchantProvider *) listIter->data;
1082
1083 dict = (*provider->request_dict) (provider, tag);
1084
1085 if (dict)
10911086 {
1092 dict = (*provider->request_dict) (provider, tag);
1093
1094 if (dict)
1095 {
1096
1097 EnchantSession *session = enchant_session_new (provider, tag);
1098 EnchantDictPrivateData *enchant_dict_private_data = g_new0 (EnchantDictPrivateData, 1);
1099 enchant_dict_private_data->reference_count = 1;
1100 enchant_dict_private_data->session = session;
1101 dict->enchant_private_data = (void *)enchant_dict_private_data;
1102 g_hash_table_insert (broker->dict_map, (gpointer)strdup (tag), dict);
1103 break;
1104 }
1087 EnchantSession *session = enchant_session_new (provider, tag);
1088 EnchantDictPrivateData *enchant_dict_private_data = g_new0 (EnchantDictPrivateData, 1);
1089 enchant_dict_private_data->reference_count = 1;
1090 enchant_dict_private_data->session = session;
1091 dict->enchant_private_data = (void *)enchant_dict_private_data;
1092 g_hash_table_insert (broker->dict_map, (gpointer)strdup (tag), dict);
1093 break;
11051094 }
11061095 }
11071096 g_slist_free (list);
11211110
11221111 char * normalized_tag = enchant_normalize_dictionary_tag (tag);
11231112 if(!enchant_is_valid_dictionary_tag(normalized_tag))
1124 {
1125 enchant_broker_set_error (broker, "invalid tag character found");
1126 }
1113 enchant_broker_set_error (broker, "invalid tag character found");
11271114 else if ((dict = _enchant_broker_request_dict (broker, normalized_tag)) == NULL)
11281115 {
11291116 char * iso_639_only_tag = enchant_iso_639_from_tag (normalized_tag);
11761163 {
11771164 EnchantProvider *provider = (EnchantProvider *) list->data;
11781165
1179 if (provider->list_dicts)
1166 size_t n_dicts;
1167 char ** dicts = (*provider->list_dicts) (provider, &n_dicts);
1168
1169 for (size_t i = 0; i < n_dicts; i++)
11801170 {
1181 size_t n_dicts;
1182 char ** dicts = (*provider->list_dicts) (provider, &n_dicts);
1183
1184 for (size_t i = 0; i < n_dicts; i++)
1185 {
1186 const char * tag = dicts[i];
1187 if (enchant_is_valid_dictionary_tag (tag)) {
1188 GSList *providers = enchant_get_ordered_providers (broker, tag);
1189 gint this_priority = g_slist_index (providers, provider);
1190 if (this_priority != -1) {
1191 gint min_priority = this_priority + 1;
1192 gpointer ptr = g_hash_table_lookup (tag_map, tag);
1193 if (ptr != NULL)
1194 min_priority = g_slist_index (providers, ptr);
1195 if (this_priority < min_priority)
1196 g_hash_table_insert (tag_map, strdup (tag), provider);
1197 }
1198 g_slist_free (providers);
1199 }
1171 const char * tag = dicts[i];
1172 if (enchant_is_valid_dictionary_tag (tag)) {
1173 GSList *providers = enchant_get_ordered_providers (broker, tag);
1174 gint this_priority = g_slist_index (providers, provider);
1175 if (this_priority != -1) {
1176 gint min_priority = this_priority + 1;
1177 gpointer ptr = g_hash_table_lookup (tag_map, tag);
1178 if (ptr != NULL)
1179 min_priority = g_slist_index (providers, ptr);
1180 if (this_priority < min_priority)
1181 g_hash_table_insert (tag_map, strdup (tag), provider);
12001182 }
1201
1202 enchant_free_string_list (dicts);
1183 g_slist_free (providers);
1184 }
12031185 }
1186
1187 enchant_free_string_list (dicts);
12041188 }
12051189
12061190 GSList *tags = NULL;
12521236 int exists = 0;
12531237
12541238 if (provider->dictionary_exists)
1255 {
1256 exists = (*provider->dictionary_exists) (provider, tag);
1257 }
1258 else if (provider->list_dicts)
1239 exists = (*provider->dictionary_exists) (provider, tag);
1240 else
12591241 {
12601242 size_t n_dicts;
12611243 char ** dicts = (*provider->list_dicts) (provider, &n_dicts);
12621244
12631245 for (size_t i = 0; i < n_dicts; i++)
1264 {
1265 if (!strcmp(dicts[i], tag)) {
1266 exists = 1;
1267 break;
1268 }
1246 if (!strcmp(dicts[i], tag)) {
1247 exists = 1;
1248 break;
12691249 }
12701250
12711251 enchant_free_string_list (dicts);
12851265 if (g_hash_table_lookup (broker->dict_map, (gpointer) tag) != NULL)
12861266 return 1;
12871267
1288 for (GSList *list = broker->provider_list; list != NULL; list = g_slist_next (list)) {
1268 for (GSList *list = broker->provider_list; list != NULL; list = g_slist_next (list))
12891269 if (enchant_provider_dictionary_exists ((EnchantProvider *) list->data, tag))
12901270 return 1;
1291 }
12921271
12931272 return 0;
12941273 }
13051284 int exists = 0;
13061285
13071286 if(!enchant_is_valid_dictionary_tag(normalized_tag))
1308 {
1309 enchant_broker_set_error (broker, "invalid tag character found");
1310 }
1287 enchant_broker_set_error (broker, "invalid tag character found");
13111288 else if ((exists = _enchant_broker_dict_exists (broker, normalized_tag)) == 0)
13121289 {
1313 char * iso_639_only_tag;
1314
1315 iso_639_only_tag = enchant_iso_639_from_tag (normalized_tag);
1290 char * iso_639_only_tag = enchant_iso_639_from_tag (normalized_tag);
13161291
13171292 if (strcmp (normalized_tag, iso_639_only_tag) != 0)
1318 {
1319 exists = _enchant_broker_dict_exists (broker, iso_639_only_tag);
1320 }
1293 exists = _enchant_broker_dict_exists (broker, iso_639_only_tag);
13211294
13221295 free (iso_639_only_tag);
13231296 }
13451318 gunichar uc = (gunichar)uc_in;
13461319
13471320 /* Accept quote marks anywhere except at the end of a word */
1348 if (uc == g_utf8_get_char("'") || uc == g_utf8_get_char("’")) {
1321 if (uc == g_utf8_get_char("'") || uc == g_utf8_get_char("’"))
13491322 return n < 2;
1350 }
13511323
13521324 GUnicodeType type = g_unichar_type(uc);
13531325
13671339 return 1; /* Enchant 1.3.0 defines word chars like this. */
13681340
13691341 case G_UNICODE_DASH_PUNCTUATION:
1370 if ((n == 1) && (type == G_UNICODE_DASH_PUNCTUATION)) {
1342 if ((n == 1) && (type == G_UNICODE_DASH_PUNCTUATION))
13711343 return 1; /* hyphens only accepted within a word. */
1372 }
13731344 /* Fallthrough */
13741345
13751346 case G_UNICODE_CONTROL:
00 #include <winver.h>
11
22 VS_VERSION_INFO VERSIONINFO
3 FILEVERSION 2,3,1
4 PRODUCTVERSION 2,3,1,0
3 FILEVERSION 2,3,2
4 PRODUCTVERSION 2,3,2,0
55 FILEFLAGSMASK 0
66 FILEFLAGS 0
77 FILEOS VOS__WINDOWS32
1414 BEGIN
1515 VALUE "CompanyName", "none"
1616 VALUE "FileDescription", "libenchant"
17 VALUE "FileVersion", "2.3.1"
17 VALUE "FileVersion", "2.3.2"
1818 VALUE "InternalName", "libenchant-2.3"
1919 VALUE "LegalCopyright", "Copyright (C) 2002-2007 Dom Lachowicz"
2020 VALUE "OriginalFilename", "libenchant-2.3.dll"
2121 VALUE "ProductName", "libenchant"
22 VALUE "ProductVersion", "2.3.1"
22 VALUE "ProductVersion", "2.3.2"
2323 END
2424 END
2525 BLOCK "VarFileInfo"
00 /* enchant
11 * Copyright (C) 2003, 2004 Dom Lachowicz
2 * Copyright (C) 2016-2021 Reuben Thomas <rrt@sc3d.org>
23 *
34 * This library is free software; you can redistribute it and/or
45 * modify it under the terms of the GNU Lesser General Public
7475
7576 /* A PWL dictionary is stored as a Trie-like data structure EnchantTrie.
7677 * The EnchantTrie datatype is completely recursive - all child nodes
77 * are simply EnchantTrie pointers. This means that all functions
78 * are simply EnchantTrie pointers. This means that all functions
7879 * that potentially modify a trie need to return the modified trie,
7980 * as additional memory may have been allocated.
8081 *
201202 *
202203 * Returns: a new PWL object used to store/check/suggest words
203204 * or NULL if the file cannot be opened or created
204 */
205 */
205206 EnchantPWL* enchant_pwl_init_with_file(const char * file)
206207 {
207208 g_return_val_if_fail (file != NULL, NULL);
232233 pwl->words_in_trie = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
233234
234235 FILE *f = g_fopen(pwl->filename, "r");
235 if (!f)
236 if (!f)
236237 return;
237238
238239 pwl->file_changed = stats.st_mtime;
239240
240241 enchant_lock_file (f);
241
242
242243 char buffer[BUFSIZ + 1];
243244 size_t line_number = 1;
244245 for (; NULL != (fgets (buffer, sizeof (buffer), f)); ++line_number)
247248 if(line_number == 1 && BOM == g_utf8_get_char(line))
248249 line = g_utf8_next_char(line);
249250
250 if(line[strlen(line)-1] != '\n' && !feof(f)) /* ignore lines longer than BUFSIZ. */
251 if(line[strlen(line)-1] != '\n' && !feof(f)) /* ignore lines longer than BUFSIZ. */
251252 {
252253 g_warning ("Line too long (ignored) in %s at line:%zu\n", pwl->filename, line_number);
253254 while (NULL != (fgets (buffer, sizeof (buffer), f)))
254255 {
255 if (line[strlen(buffer)-1]=='\n')
256 if (line[strlen(buffer)-1]=='\n')
256257 break;
257258 }
258259 continue;
267268 g_warning ("Bad UTF-8 sequence in %s at line:%zu\n", pwl->filename, line_number);
268269 }
269270 }
270
271
271272 enchant_unlock_file (f);
272273 fclose (f);
273274 }
288289 g_free (normalized_word);
289290 return;
290291 }
291
292
292293 g_hash_table_insert (pwl->words_in_trie, normalized_word, g_strndup(word,len));
293294
294295 pwl->trie = enchant_trie_insert(pwl->trie, normalized_word);
307308 pwl->trie = NULL; /* make trie empty if has no content */
308309 }
309310 }
310
311
311312 g_free(normalized_word);
312313 }
313314
345346 }
346347
347348 if (fwrite (word, sizeof(char), len, f) == (size_t)len)
348 {
349 putc ('\n', f);
350 }
349 putc ('\n', f);
351350 enchant_unlock_file (f);
352351 fclose (f);
353 }
352 }
354353 }
355354 }
356355
400399 fwrite (searchstart, sizeof(char), length - (searchstart - contents), f);
401400 break;
402401 }
403 else
402 else
404403 {
405404 char* foundend = needle+len;
406405 if((needle == filestart || contents[needle-contents-1] == '\n' || contents[needle-contents-1] == '\r') &&
418417 }
419418 }
420419 g_free(key);
421
420
422421 GStatBuf stats;
423422 if(g_stat(pwl->filename, &stats)==0)
424423 pwl->file_changed = stats.st_mtime;
426425 enchant_unlock_file (f);
427426
428427 fclose (f);
429 }
428 }
430429 g_free(contents);
431430 }
432431 }
503502 if ((type != G_UNICODE_UPPERCASE_LETTER && type != G_UNICODE_TITLECASE_LETTER) ||
504503 ch != g_unichar_totitle(ch))
505504 return 0;
506
505
507506 for (const char* it = g_utf8_next_char(word); it < word + len; it = g_utf8_next_char(it))
508507 {
509508 type = g_unichar_type(g_utf8_get_char(it));
538537 enchant_pwl_refresh_from_file(pwl);
539538
540539 int exists = enchant_pwl_contains(pwl, word, len);
541
540
542541 if(exists)
543542 return 0;
544543
571570 (*((int*)(matcher->cbdata)))++;
572571 }
573572
574 static void enchant_pwl_case_and_denormalize_suggestions(EnchantPWL *pwl,
575 const char *const word, size_t len,
573 static void enchant_pwl_case_and_denormalize_suggestions(EnchantPWL *pwl,
574 const char *const word, size_t len,
576575 EnchantSuggList* suggs_list)
577576 {
578577 gchar* (*utf8_case_convert_function)(const gchar*str, gssize len) = NULL;
580579 utf8_case_convert_function = enchant_utf8_strtitle;
581580 else if (enchant_is_all_caps(word, len))
582581 utf8_case_convert_function = g_utf8_strup;
583
582
584583 for (size_t i = 0; i < suggs_list->n_suggs; ++i)
585584 {
586585 gchar* suggestion = g_hash_table_lookup (pwl->words_in_trie, suggs_list->suggs[i]);
591590 cased_suggestion = utf8_case_convert_function(suggestion, suggestion_len);
592591 else
593592 cased_suggestion = g_strndup(suggestion, suggestion_len);
594
593
595594 g_free(suggs_list->suggs[i]);
596595 suggs_list->suggs[i] = cased_suggestion;
597596 }
614613 return best_dist;
615614 }
616615
617 /* gives the best set of suggestions from pwl that are at least as good as the
616 /* gives the best set of suggestions from pwl that are at least as good as the
618617 * given suggs (if suggs == NULL just best from pwl) */
619618 char** enchant_pwl_suggest(EnchantPWL *pwl, const char *const word,
620619 ssize_t len, char** suggs, size_t* out_n_suggs)
644643 (*out_n_suggs) = sugg_list.n_suggs;
645644
646645 enchant_pwl_case_and_denormalize_suggestions(pwl, word, len, &sugg_list);
647
646
648647 return sugg_list.suggs;
649648 }
650649
662661 size_t loc;
663662 for(loc=0; loc < sugg_list->n_suggs; loc++) {
664663 /* Better than an existing suggestion, so stop */
665 if(sugg_list->sugg_errs[loc] > matcher->num_errors) {
664 if(sugg_list->sugg_errs[loc] > matcher->num_errors)
666665 break;
667 }
668666 /* Already in the list with better score, just return */
669667 if(strcmp(match,sugg_list->suggs[loc])==0) {
670668 g_free(match);
678676 }
679677
680678 int changes = 1; /* num words added to list */
681
679
682680 /* Remove all elements with worse score */
683681 for(size_t i=loc; i < sugg_list->n_suggs; i++){
684682 g_free(sugg_list->suggs[i]);
693691 static void enchant_trie_free(EnchantTrie* trie)
694692 {
695693 /* Don't try to free NULL or the EOSTrie pointer */
696 if(trie == NULL || trie == EOSTrie) {
697 return;
698 }
694 if(trie == NULL || trie == EOSTrie)
695 return;
699696
700697 /* Because we have not set a destroy function for the hashtable
701698 * (to make code cleaner below), we need to explicitly free all
719716
720717 static EnchantTrie* enchant_trie_insert(EnchantTrie* trie,const char *const word)
721718 {
722 if (trie == NULL) {
719 if (trie == NULL)
723720 trie = g_new0(EnchantTrie, 1);
724 }
725721
726722 if (trie->value == NULL) {
727723 if (trie->subtries == NULL) {
743739 }
744740 } else {
745741 /* Create new hash table for subtries, and reinsert */
746 trie->subtries = g_hash_table_new_full(g_str_hash,
742 trie->subtries = g_hash_table_new_full(g_str_hash,
747743 g_str_equal, g_free, NULL);
748744 char *tmpWord = trie->value;
749745 trie->value = NULL;
763759 if (trie->value == NULL) {
764760 if (trie->subtries != NULL) {
765761 /* Store multiple words in subtries */
766 if (word[0] == '\0') {
762 if (word[0] == '\0')
767763 /* End-of-string is marked with special node */
768764 g_hash_table_remove(trie->subtries, "");
769 } else {
765 else {
770766 ssize_t nxtCh = (ssize_t)(g_utf8_next_char(word) - word);
771767 char *tmpWord = g_strndup(word, nxtCh);
772768 EnchantTrie *subtrie = g_hash_table_lookup(trie->subtries, tmpWord);
798794 g_list_free(keys);
799795 }
800796 }
801 } else {
802 if(strcmp(trie->value, word) == 0)
803 {
804 g_free(trie->value);
805 trie->value = NULL;
806 }
807 }
808 }
809
810 static EnchantTrie* enchant_trie_get_subtrie(EnchantTrie* trie,
797 } else if(strcmp(trie->value, word) == 0) {
798 g_free(trie->value);
799 trie->value = NULL;
800 }
801 }
802
803 static EnchantTrie* enchant_trie_get_subtrie(EnchantTrie* trie,
811804 EnchantTrieMatcher* matcher,
812805 char** nxtChS)
813806 {
829822 g_return_if_fail(matcher);
830823
831824 /* Can't match in the empty trie */
832 if(trie == NULL) {
833 return;
834 }
825 if(trie == NULL)
826 return;
835827
836828 /* Bail out if over the error limits */
837829 if(matcher->num_errors > matcher->max_errors){
842834 if (trie == EOSTrie) {
843835 size_t word_len = strlen(matcher->word);
844836 int errs = matcher->num_errors;
845 if((ssize_t)word_len > matcher->word_pos) {
837 if((ssize_t)word_len > matcher->word_pos)
846838 matcher->num_errors = errs + word_len - matcher->word_pos;
847 }
848 if (matcher->num_errors <= matcher->max_errors) {
839 if (matcher->num_errors <= matcher->max_errors)
849840 matcher->cbfunc(g_strdup(matcher->path),matcher);
850 }
851841 matcher->num_errors = errs;
852842 return;
853843 }
858848 int errs = matcher->num_errors;
859849 value = trie->value;
860850 if(matcher->mode == case_insensitive)
861 {
862 value = g_utf8_strdown(value, -1);
863 }
864 matcher->num_errors = errs + edit_dist(value,
851 value = g_utf8_strdown(value, -1);
852 matcher->num_errors = errs + edit_dist(value,
865853 &(matcher->word[matcher->word_pos]));
866854 if(matcher->mode == case_insensitive)
867 {
868 g_free(value);
869 }
870
871 if (matcher->num_errors <= matcher->max_errors) {
855 g_free(value);
856
857 if (matcher->num_errors <= matcher->max_errors)
872858 matcher->cbfunc(g_strconcat(matcher->path,
873859 trie->value,NULL),
874860 matcher);
875 }
876861 matcher->num_errors = errs;
877862 return;
878863 }
917902
918903 ssize_t nxtChI = (ssize_t) (g_utf8_next_char(&matcher->word[matcher->word_pos]) - matcher->word);
919904
920 /* Dont handle actual matches, that's already done */
921 if (strncmp(key,&matcher->word[matcher->word_pos],nxtChI-matcher->word_pos) == 0) {
922 return;
923 }
905 /* Don't handle actual matches, that's already done */
906 if (strncmp(key,&matcher->word[matcher->word_pos],nxtChI-matcher->word_pos) == 0)
907 return;
924908
925909 enchant_trie_matcher_pushpath(matcher,key);
926910
951935 }
952936
953937 g_free(key2);
954
938
955939 matcher->word_pos = oldPos;
956940 }
957941
10161000 {
10171001 g_return_if_fail(matcher->path_pos >= 0);
10181002 matcher->path_pos = matcher->path_pos - num;
1019 if(matcher->path_pos < 0) {
1003 if(matcher->path_pos < 0)
10201004 matcher->path_pos = 0;
1021 }
10221005 matcher->path[matcher->path_pos] = '\0';
10231006 }
10241007
10291012 gunichar * word2 = g_utf8_to_ucs4_fast(utf8word2, -1, &len2);
10301013
10311014 int * table = g_new0(int, (len1+1)*(len2+1));
1032
1015
10331016 /* Initialise outer rows of table */
10341017 for (glong i = 0; i < len1 + 1; i++)
10351018 table[i*(len2+1)] = i;
10411024 for (glong j = 1; j < len2+1; j++) {
10421025 int cost = word1[i-1] != word2[j-1];
10431026 int v1 = table[(i-1)*(len2+1)+j] + 1;
1044 if (i > 1 && j > 1 && word1[i-1] == word2[j-2] && word1[i-2] == word2[j-1]) {
1027 if (i > 1 && j > 1 && word1[i-1] == word2[j-2] && word1[i-2] == word2[j-1])
10451028 v1 = MIN (v1, table[(i-2)*(len2+1)+(j-2)] + cost);
1046 }
10471029
10481030 int v2 = table[i*(len2+1)+(j-1)] + 1;
10491031 int v3 = table[(i-1)*(len2+1)+(j-1)] + cost;
6161 TEST_FIXTURE(ProviderListDicts_TestFixture,
6262 ProviderListDicts_ForEachReturned_RequestDictSucceeds)
6363 {
64 if(_provider->list_dicts && _provider->request_dict)
64 if(_provider->list_dicts)
6565 {
66 size_t n_dicts;
66 size_t n_dicts;
6767
68 _dicts = (*_provider->list_dicts) (_provider, &n_dicts);
69 for (size_t i = 0; i < n_dicts; i++)
70 {
71 EnchantDict* dict = (*_provider->request_dict) (_provider, _dicts[i]);
72 CHECK(dict != NULL);
73 if (dict && _provider->dispose_dict)
74 {
68 _dicts = (*_provider->list_dicts) (_provider, &n_dicts);
69 for (size_t i = 0; i < n_dicts; i++)
70 {
71 EnchantDict* dict = (*_provider->request_dict) (_provider, _dicts[i]);
72 CHECK(dict != NULL);
73 if (dict)
7574 _provider->dispose_dict(_provider, dict);
76 }
7775 }
7876 }
7977 }
3333 //Teardown
3434 ~ProviderRequestDictionary_TestFixture()
3535 {
36 if (_dict && _provider->dispose_dict)
37 {
38 _provider->dispose_dict(_provider, _dict);
39 }
36 if (_dict)
37 _provider->dispose_dict(_provider, _dict);
4038 }
4139 };
4240
4846 TEST_FIXTURE(ProviderRequestDictionary_TestFixture,
4947 ProviderRequestDictionary_ProviderDoesNotHave_ReturnsNull)
5048 {
51 if (_provider->request_dict)
52 {
53 _dict = (*_provider->request_dict) (_provider, "zxx"); /*zxx is no linguistic content*/
54 CHECK_EQUAL((void*)NULL, _dict);
55 }
49 _dict = (*_provider->request_dict) (_provider, "zxx"); /*zxx is no linguistic content*/
50 CHECK_EQUAL((void*)NULL, _dict);
5651 }
57
58 TEST_FIXTURE(ProviderRequestDictionary_TestFixture,
59 ProviderRequestDictionary_ProviderDoesNotHave_ProviderDoesNotSetError)
60 {
61 if (_provider->request_dict)
62 {
63 _dict = (*_provider->request_dict) (_provider, "zxx"); /*zxx is no linguistic content*/
64 CHECK_EQUAL((void*)NULL, GetErrorMessage(_provider));
65 }
66 }
2525 #include <gmodule.h>
2626 #include <assert.h>
2727 #include <string.h>
28 #include <stdlib.h>
2829 #include "unittest_enchant_providers.h"
2930
3031 int Test(char* path);
166167 g_provider->dispose(g_provider);
167168
168169 g_provider = NULL;
170 free(broker.error);
169171 }
170172
171173 if(module){
6868
6969 // Try getting dictionary for user's default language
7070 char *lang = enchant_get_user_language();
71 if (_provider->request_dict)
72 {
73 dict = (*_provider->request_dict) (_provider, lang);
74 }
71 dict = (*_provider->request_dict) (_provider, lang);
7572 g_free (lang);
7673
7774 // If not available, get the first dictionary listed as being available
78 if (!dict && _provider->list_dicts && _provider->request_dict)
75 if (!dict && _provider->list_dicts)
7976 {
8077 size_t n_dicts;
8178
8986
9087 EnchantDict* GetDictionary(const char* language)
9188 {
92 if(_provider->request_dict)
93 {
9489 return (*_provider->request_dict) (_provider, language);
95 }
96 return NULL;
9790 }
9891
9992 virtual void ReleaseDictionary(EnchantDict* dict)
10093 {
101 if (dict && _provider->dispose_dict)
102 {
94 if (dict)
10395 _provider->dispose_dict(_provider, dict);
104 }
10596 }
10697 };
2828 mock_provider_dispose(EnchantProvider *me)
2929 {
3030 g_free(me);
31 }
32
33 static EnchantDict *
34 mock_provider_request_dict(EnchantProvider *, const char *const)
35 {
36 return NULL;
3137 }
3238
3339 static void
8793
8894 provider = g_new0(EnchantProvider, 1);
8995 provider->dispose = mock_provider_dispose; //although this is technically optional, it will result in a memory leak
90 provider->request_dict = NULL;
96 provider->request_dict = mock_provider_request_dict; // this is required or module won't load
9197 provider->dispose_dict = mock_provider_dispose_dict;
9298 provider->identify = hasIdentify ? mock_provider_identify : NULL; // this is required or module won't load
9399 provider->describe = hasDescribe ? mock_provider_describe : NULL; // this is required or module won't load
308308 AddWordsToDictionary(sNoiseWords);
309309
310310 std::vector<std::string> suggestions = GetSuggestionsFromWord("saskep");
311 CHECK(suggestions.size() > 0);
311312 // FIXME: The string in the next line was originally "hasten", but the
312313 // test failed. Is this now correct?
313314 CHECK(suggestions[0] != "hastens");