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
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 | ||
0 | 14 | 2.3.1 (August 9, 2021) |
1 | 15 | ---------------------- |
2 | 16 |
0 | 0 | #! /bin/sh |
1 | 1 | # 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. | |
3 | 3 | # |
4 | 4 | # |
5 | 5 | # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. |
586 | 586 | # Identity of this package. |
587 | 587 | PACKAGE_NAME='enchant' |
588 | 588 | 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' | |
591 | 591 | PACKAGE_BUGREPORT='' |
592 | 592 | PACKAGE_URL='' |
593 | 593 | |
1786 | 1786 | # Omit some internal or obsolete options to make the list less imposing. |
1787 | 1787 | # This message is too long to be a string in the A/UX 3.1 sh. |
1788 | 1788 | 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. | |
1790 | 1790 | |
1791 | 1791 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1792 | 1792 | |
1857 | 1857 | |
1858 | 1858 | if test -n "$ac_init_help"; then |
1859 | 1859 | 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:";; | |
1861 | 1861 | esac |
1862 | 1862 | cat <<\_ACEOF |
1863 | 1863 | |
2024 | 2024 | test -n "$ac_init_help" && exit $ac_status |
2025 | 2025 | if $ac_init_version; then |
2026 | 2026 | cat <<\_ACEOF |
2027 | enchant configure 2.3.1 | |
2027 | enchant configure 2.3.2 | |
2028 | 2028 | generated by GNU Autoconf 2.69 |
2029 | 2029 | |
2030 | 2030 | Copyright (C) 2012 Free Software Foundation, Inc. |
2880 | 2880 | This file contains any messages produced by compilers while |
2881 | 2881 | running configure, to aid debugging if configure makes a mistake. |
2882 | 2882 | |
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 | |
2884 | 2884 | generated by GNU Autoconf 2.69. Invocation command line was |
2885 | 2885 | |
2886 | 2886 | $ $0 $@ |
3751 | 3751 | |
3752 | 3752 | # Define the identity of the package. |
3753 | 3753 | PACKAGE='enchant' |
3754 | VERSION='2.3.1' | |
3754 | VERSION='2.3.2' | |
3755 | 3755 | |
3756 | 3756 | |
3757 | 3757 | cat >>confdefs.h <<_ACEOF |
25264 | 25264 | # report actual input values of CONFIG_FILES etc. instead of their |
25265 | 25265 | # values after options handling. |
25266 | 25266 | 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 | |
25268 | 25268 | generated by GNU Autoconf 2.69. Invocation command line was |
25269 | 25269 | |
25270 | 25270 | CONFIG_FILES = $CONFIG_FILES |
25330 | 25330 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
25331 | 25331 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
25332 | 25332 | ac_cs_version="\\ |
25333 | enchant config.status 2.3.1 | |
25333 | enchant config.status 2.3.2 | |
25334 | 25334 | configured by $0, generated by GNU Autoconf 2.69, |
25335 | 25335 | with options \\"\$ac_cs_config\\" |
25336 | 25336 |
0 | AC_INIT([enchant],[2.3.1]) | |
0 | AC_INIT([enchant],[2.3.2]) | |
1 | 1 | AC_CONFIG_SRCDIR(src/enchant.h) |
2 | 2 | AC_CONFIG_AUX_DIR([build-aux]) |
3 | 3 | AM_INIT_AUTOMAKE([subdir-objects]) |
70 | 70 | size_t len, size_t * out_n_suggs) |
71 | 71 | { |
72 | 72 | AspellSpeller *manager = (AspellSpeller *) me->user_data; |
73 | ||
73 | ||
74 | 74 | char *normalizedWord = g_utf8_normalize (word, len, G_NORMALIZE_NFC); |
75 | 75 | const AspellWordList *word_list = aspell_speller_suggest (manager, normalizedWord, strlen(normalizedWord)); |
76 | 76 | g_free(normalizedWord); |
83 | 83 | { |
84 | 84 | size_t n_suggestions = aspell_word_list_size (word_list); |
85 | 85 | *out_n_suggs = n_suggestions; |
86 | ||
86 | ||
87 | 87 | if (n_suggestions) |
88 | 88 | { |
89 | 89 | sugg_arr = g_new0 (char *, n_suggestions + 1); |
90 | ||
90 | ||
91 | 91 | for (size_t i = 0; i < n_suggestions; i++) |
92 | 92 | { |
93 | 93 | const char *sugg = aspell_string_enumeration_next (suggestions); |
98 | 98 | delete_aspell_string_enumeration (suggestions); |
99 | 99 | } |
100 | 100 | } |
101 | ||
101 | ||
102 | 102 | return sugg_arr; |
103 | 103 | } |
104 | 104 | |
136 | 136 | AspellConfig *spell_config = new_aspell_config (); |
137 | 137 | aspell_config_replace (spell_config, "language-tag", tag); |
138 | 138 | aspell_config_replace (spell_config, "encoding", "utf-8"); |
139 | ||
139 | ||
140 | 140 | AspellCanHaveError *spell_error = new_aspell_speller (spell_config); |
141 | 141 | delete_aspell_config (spell_config); |
142 | ||
142 | ||
143 | 143 | if (aspell_error_number (spell_error) != 0) |
144 | 144 | { |
145 | enchant_provider_set_error (me, aspell_error_message (spell_error)); | |
145 | 146 | delete_aspell_can_have_error(spell_error); |
146 | 147 | return NULL; |
147 | 148 | } |
148 | ||
149 | ||
149 | 150 | AspellSpeller *manager = to_aspell_speller (spell_error); |
150 | ||
151 | ||
151 | 152 | EnchantDict *dict = g_new0 (EnchantDict, 1); |
152 | 153 | dict->user_data = (void *) manager; |
153 | 154 | dict->check = aspell_dict_check; |
155 | 156 | dict->add_to_personal = aspell_dict_add_to_personal; |
156 | 157 | dict->add_to_session = aspell_dict_add_to_session; |
157 | 158 | dict->store_replacement = aspell_dict_store_replacement; |
158 | ||
159 | ||
159 | 160 | return dict; |
160 | 161 | } |
161 | 162 | |
164 | 165 | { |
165 | 166 | AspellSpeller *manager = (AspellSpeller *) dict->user_data; |
166 | 167 | delete_aspell_speller (manager); |
167 | ||
168 | ||
168 | 169 | g_free (dict); |
169 | 170 | } |
170 | 171 | |
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, | |
173 | 174 | size_t * out_n_dicts) |
174 | 175 | { |
175 | 176 | AspellConfig * spell_config = new_aspell_config (); |
189 | 190 | if (*out_n_dicts) { |
190 | 191 | out_list = g_new0 (char *, *out_n_dicts + 1); |
191 | 192 | dels = aspell_dict_info_list_elements (dlist); |
192 | ||
193 | ||
193 | 194 | 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); | |
195 | 196 | /* FIXME: should this be entry->code or entry->name ? */ |
196 | 197 | out_list[i] = g_strdup (entry->code); |
197 | 198 | } |
198 | ||
199 | ||
199 | 200 | delete_aspell_dict_info_enumeration (dels); |
200 | 201 | } |
201 | ||
202 | ||
202 | 203 | delete_aspell_config (spell_config); |
203 | ||
204 | ||
204 | 205 | return out_list; |
205 | 206 | } |
206 | 207 |
65 | 65 | "utf-8", "iso8859-8", NULL, &len, NULL); |
66 | 66 | } |
67 | 67 | } |
68 | ||
68 | ||
69 | 69 | return sugg_arr; |
70 | 70 | } |
71 | 71 | |
86 | 86 | struct dict_radix *hspell_dict = (struct dict_radix *)me->user_data; |
87 | 87 | char *iso_word = hspell_convert_to_iso8859_8 (me, word, len); |
88 | 88 | g_return_val_if_fail (iso_word, -1); |
89 | ||
89 | ||
90 | 90 | /* check */ |
91 | 91 | int preflen; |
92 | 92 | int res = hspell_check_word (hspell_dict, iso_word, &preflen); |
93 | ||
93 | ||
94 | 94 | /* if not correct try gimatria */ |
95 | 95 | if (res != 1) |
96 | 96 | res = hspell_is_canonic_gimatria (iso_word) != 0; |
97 | ||
97 | ||
98 | 98 | g_free (iso_word); |
99 | ||
99 | ||
100 | 100 | return (res != 1); |
101 | 101 | } |
102 | 102 | |
112 | 112 | struct corlist cl; |
113 | 113 | corlist_init (&cl); |
114 | 114 | hspell_trycorrect (hspell_dict, iso_word, &cl); |
115 | ||
115 | ||
116 | 116 | *out_n_suggs = corlist_n (&cl); |
117 | 117 | char **sugg_arr = corlist2strv (&cl, *out_n_suggs); |
118 | 118 | corlist_free (&cl); |
119 | 119 | g_free (iso_word); |
120 | ||
121 | return sugg_arr; | |
120 | ||
121 | return sugg_arr; | |
122 | 122 | } |
123 | 123 | |
124 | 124 | static EnchantDict * |
126 | 126 | { |
127 | 127 | if(!((strlen(tag) >= 2) && tag[0] == 'h' && tag[1] == 'e')) |
128 | 128 | return NULL; |
129 | ||
129 | ||
130 | 130 | /* try to set a new session */ |
131 | 131 | struct dict_radix *hspell_dict = NULL; |
132 | 132 | int dict_flag = hspell_init (&hspell_dict, HSPELL_OPT_DEFAULT); |
133 | ||
133 | ||
134 | 134 | if (dict_flag != 0 || !hspell_dict) |
135 | 135 | { |
136 | 136 | enchant_provider_set_error (me, "can't create new dict."); |
137 | 137 | return NULL; |
138 | 138 | } |
139 | ||
139 | ||
140 | 140 | EnchantDict *dict = g_new0 (EnchantDict, 1); |
141 | 141 | dict->user_data = (void *) hspell_dict; |
142 | 142 | dict->check = hspell_dict_check; |
143 | 143 | dict->suggest = hspell_dict_suggest; |
144 | ||
144 | ||
145 | 145 | return dict; |
146 | 146 | } |
147 | 147 | |
155 | 155 | |
156 | 156 | /* test for the existence of, then return $prefix/share/hspell/hebrew.wgz */ |
157 | 157 | |
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, | |
160 | 160 | size_t * out_n_dicts) |
161 | 161 | { |
162 | 162 | const char * dictionary_path = hspell_get_dictionary_path(); |
166 | 166 | if(dictionary_path && *dictionary_path && g_file_test (dictionary_path, G_FILE_TEST_EXISTS)) { |
167 | 167 | out_list = g_new0 (char *, 2); |
168 | 168 | out_list[(*out_n_dicts)++] = g_strdup ("he"); |
169 | } | |
170 | ||
169 | } | |
170 | ||
171 | 171 | return out_list; |
172 | 172 | } |
173 | 173 |
36 | 36 | |
37 | 37 | #include <stdio.h> |
38 | 38 | #include <stdlib.h> |
39 | #include <string.h> | |
39 | #include <string.h> | |
40 | 40 | |
41 | 41 | #include <string> |
42 | 42 | #include <vector> |
241 | 241 | size_t tag_len = strlen(tag); |
242 | 242 | |
243 | 243 | if (dir_entry_len - dic_suffix_len < tag_len) |
244 | return false; | |
244 | return false; | |
245 | 245 | if (strcmp(dir_entry+dir_entry_len-dic_suffix_len, dic_suffix) != 0) |
246 | return false; | |
246 | return false; | |
247 | 247 | if (strncmp (dir_entry, tag, tag_len) != 0) |
248 | return false; | |
248 | return false; | |
249 | 249 | //e.g. requested dict for "fi", |
250 | 250 | //reject "fil_PH.dic" |
251 | 251 | //allow "fi-FOO.dic", "fi_FOO.dic", "fi.dic", etc. |
252 | 252 | if (!ispunct(dir_entry[tag_len])) |
253 | return false; | |
253 | return false; | |
254 | 254 | return true; |
255 | 255 | } |
256 | 256 | |
267 | 267 | return strdup (names[i].c_str()); |
268 | 268 | } |
269 | 269 | } |
270 | ||
270 | ||
271 | 271 | std::vector<std::string> dirs; |
272 | 272 | s_buildDictionaryDirs (dirs); |
273 | 273 | |
277 | 277 | const char *dir_entry; |
278 | 278 | while ((dir_entry = g_dir_read_name (dir)) != NULL) { |
279 | 279 | 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(), | |
281 | 281 | dir_entry, nullptr); |
282 | 282 | if(s_fileExists(s_correspondingAffFile(dict))) { |
283 | 283 | g_dir_close (dir); |
347 | 347 | hunspell_dict_check (EnchantDict * me, const char *const word, size_t len) |
348 | 348 | { |
349 | 349 | HunspellChecker * checker = static_cast<HunspellChecker *>(me->user_data); |
350 | ||
350 | ||
351 | 351 | if (checker->checkWord(word, len)) |
352 | 352 | return 0; |
353 | ||
353 | ||
354 | 354 | return 1; |
355 | 355 | } |
356 | 356 | |
409 | 409 | |
410 | 410 | extern "C" { |
411 | 411 | |
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, | |
414 | 414 | size_t * out_n_dicts) |
415 | 415 | { |
416 | 416 | std::vector<std::string> dict_dirs, dicts; |
438 | 438 | hunspell_provider_request_dict(EnchantProvider * me _GL_UNUSED_PARAMETER, const char *const tag) |
439 | 439 | { |
440 | 440 | HunspellChecker * checker = new HunspellChecker(); |
441 | ||
441 | ||
442 | 442 | if (!checker) |
443 | 443 | return NULL; |
444 | ||
444 | ||
445 | 445 | if (!checker->requestDictionary(tag)) { |
446 | 446 | delete checker; |
447 | 447 | return NULL; |
448 | 448 | } |
449 | ||
449 | ||
450 | 450 | EnchantDict *dict = g_new0(EnchantDict, 1); |
451 | 451 | dict->user_data = (void *) checker; |
452 | 452 | dict->check = hunspell_dict_check; |
454 | 454 | // don't implement personal, session |
455 | 455 | dict->get_extra_word_characters = hunspell_dict_get_extra_word_characters; |
456 | 456 | dict->is_word_character = hunspell_dict_is_word_character; |
457 | ||
457 | ||
458 | 458 | return dict; |
459 | 459 | } |
460 | 460 | |
463 | 463 | { |
464 | 464 | HunspellChecker *checker = (HunspellChecker *) dict->user_data; |
465 | 465 | delete checker; |
466 | ||
466 | ||
467 | 467 | g_free (dict); |
468 | 468 | } |
469 | 469 |
49 | 49 | static int |
50 | 50 | voikko_dict_check (EnchantDict * me, const char *const word, size_t len) |
51 | 51 | { |
52 | char *word_nul = strndup(word, len); | |
52 | char *word_nul = g_strndup(word, len); | |
53 | 53 | int result = voikkoSpellCstr((struct VoikkoHandle *)me->user_data, word_nul); |
54 | 54 | free(word_nul); |
55 | 55 | if (result == VOIKKO_SPELL_FAILED) |
64 | 64 | voikko_dict_suggest (EnchantDict * me, const char *const word, |
65 | 65 | size_t len, size_t * out_n_suggs) |
66 | 66 | { |
67 | char *word_nul = strndup(word, len); | |
67 | char *word_nul = g_strndup(word, len); | |
68 | 68 | char **voikko_sugg_arr = voikkoSuggestCstr((struct VoikkoHandle *)me->user_data, word_nul); |
69 | 69 | free(word_nul); |
70 | 70 | if (voikko_sugg_arr == NULL) |
112 | 112 | |
113 | 113 | static int |
114 | 114 | voikko_provider_dictionary_exists (struct str_enchant_provider * me _GL_UNUSED_PARAMETER, |
115 | const char *const tag) | |
115 | const char *const tag) | |
116 | 116 | { |
117 | 117 | size_t i; |
118 | 118 | int exists = 0; |
0 | 0 | /* Copyright (C) 2006 Barış Metin <baris@pardus.org.tr> |
1 | 1 | * Copyright (C) 2007 Serkan Kaba <serkan_kaba@yahoo.com> |
2 | * | |
2 | * | |
3 | 3 | * This library is free software; you can redistribute it and/or |
4 | 4 | * modify it under the terms of the GNU Lesser General Public |
5 | 5 | * License as published by the Free Software Foundation; either |
51 | 51 | "/net/zemberekserver/server/dbus/ZemberekDbus", |
52 | 52 | "net.zemberekserver.server.dbus.ZemberekDbusInterface", |
53 | 53 | &Error); |
54 | ||
54 | ||
55 | 55 | dbus_g_connection_unref (connection); |
56 | 56 | if (proxy == NULL) { |
57 | 57 | return false; |
66 | 66 | public: |
67 | 67 | Zemberek(); |
68 | 68 | ~Zemberek(); |
69 | ||
69 | ||
70 | 70 | int checkWord(const char* word) const; |
71 | 71 | char** suggestWord(const char* word, size_t *out_n_suggs); |
72 | 72 | |
100 | 100 | Zemberek::~Zemberek() |
101 | 101 | { |
102 | 102 | if(proxy) |
103 | g_object_unref (proxy); | |
103 | g_object_unref (proxy); | |
104 | 104 | if(connection) |
105 | dbus_g_connection_unref (connection); | |
105 | dbus_g_connection_unref (connection); | |
106 | 106 | } |
107 | 107 | |
108 | 108 | |
111 | 111 | gboolean result; |
112 | 112 | GError *Error = NULL; |
113 | 113 | 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; | |
118 | 118 | } |
119 | 119 | else |
120 | 120 | return !result; |
126 | 126 | char** suggs; |
127 | 127 | GError *Error = NULL; |
128 | 128 | 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; | |
133 | 133 | } |
134 | 134 | *out_n_suggs = g_strv_length(suggs); |
135 | 135 | return suggs; |
171 | 171 | zemberek_provider_request_dict(EnchantProvider *me _GL_UNUSED_PARAMETER, const char *tag) |
172 | 172 | { |
173 | 173 | if (!((strcmp(tag, "tr") == 0) || (strncmp(tag, "tr_", 3) == 0))) |
174 | return NULL; // only handle turkish | |
174 | return NULL; // only handle turkish | |
175 | 175 | |
176 | 176 | try |
177 | 177 | { |
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; | |
186 | 186 | } |
187 | 187 | catch(...) |
188 | 188 | { |
189 | // will fail if zemberek service isn't running | |
190 | return NULL; | |
189 | // will fail if zemberek service isn't running | |
190 | return NULL; | |
191 | 191 | } |
192 | 192 | } |
193 | 193 | |
202 | 202 | static const char * |
203 | 203 | zemberek_provider_identify (EnchantProvider * me _GL_UNUSED_PARAMETER) |
204 | 204 | { |
205 | return "zemberek"; | |
205 | return "zemberek"; | |
206 | 206 | } |
207 | 207 | |
208 | 208 | static const char * |
209 | 209 | zemberek_provider_describe (EnchantProvider * me _GL_UNUSED_PARAMETER) |
210 | 210 | { |
211 | return "Zemberek Provider"; | |
211 | return "Zemberek Provider"; | |
212 | 212 | } |
213 | 213 | |
214 | 214 | static char ** |
215 | 215 | zemberek_provider_list_dicts (EnchantProvider * me _GL_UNUSED_PARAMETER, |
216 | size_t * out_n_dicts) | |
216 | size_t * out_n_dicts) | |
217 | 217 | { |
218 | 218 | if (!zemberek_service_is_running ()) |
219 | 219 | { |
220 | *out_n_dicts = 0; | |
221 | return NULL; | |
220 | *out_n_dicts = 0; | |
221 | return NULL; | |
222 | 222 | } |
223 | 223 | else |
224 | 224 | { |
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; | |
230 | 230 | } |
231 | 231 | } |
232 | 232 |
18 | 18 | |
19 | 19 | libenchant_includedir = $(pkgincludedir)-@ENCHANT_MAJOR_VERSION@ |
20 | 20 | libenchant_include_HEADERS = enchant.h enchant-provider.h enchant++.h |
21 | noinst_HEADERS = debug.h | |
21 | 22 | |
22 | 23 | pkgdata_DATA = enchant.ordering |
23 | 24 | |
24 | 25 | dist_man_MANS = enchant-@ENCHANT_MAJOR_VERSION@.1 enchant-lsmod-@ENCHANT_MAJOR_VERSION@.1 |
25 | 26 | |
26 | 27 | edit = sed \ |
27 | -e 's|@datadir[@]|$(datadir)|g' | |
28 | -e 's|DATADIR|$(datadir)|g' | |
28 | 29 | |
29 | 30 | DISTCLEANFILES = $(dist_man_MANS) |
30 | 31 | |
34 | 35 | mv $@.tmp $@ |
35 | 36 | |
36 | 37 | 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 $@ | |
40 | 39 | |
41 | 40 | LDADD = libenchant-@ENCHANT_MAJOR_VERSION@.la $(ENCHANT_LIBS) $(top_builddir)/lib/libgnu.la |
42 | 41 | bin_PROGRAMS = enchant-@ENCHANT_MAJOR_VERSION@ enchant-lsmod-@ENCHANT_MAJOR_VERSION@ |
126 | 126 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ |
127 | 127 | $(ACLOCAL_M4) |
128 | 128 | DIST_COMMON = $(srcdir)/Makefile.am $(libenchant_include_HEADERS) \ |
129 | $(am__DIST_COMMON) | |
129 | $(noinst_HEADERS) $(am__DIST_COMMON) | |
130 | 130 | mkinstalldirs = $(install_sh) -d |
131 | 131 | CONFIG_HEADER = $(top_builddir)/config.h |
132 | 132 | CONFIG_CLEAN_FILES = libenchant.rc enchant.1 enchant-lsmod.1 |
253 | 253 | NROFF = nroff |
254 | 254 | MANS = $(dist_man_MANS) |
255 | 255 | DATA = $(pkgdata_DATA) |
256 | HEADERS = $(libenchant_include_HEADERS) | |
256 | HEADERS = $(libenchant_include_HEADERS) $(noinst_HEADERS) | |
257 | 257 | am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) |
258 | 258 | # Read a list of newline-separated strings from the standard input, |
259 | 259 | # and print each of them once, without duplicates. Input order is |
799 | 799 | pwl.h $(am__append_3) |
800 | 800 | libenchant_includedir = $(pkgincludedir)-@ENCHANT_MAJOR_VERSION@ |
801 | 801 | libenchant_include_HEADERS = enchant.h enchant-provider.h enchant++.h |
802 | noinst_HEADERS = debug.h | |
802 | 803 | pkgdata_DATA = enchant.ordering |
803 | 804 | dist_man_MANS = enchant-@ENCHANT_MAJOR_VERSION@.1 enchant-lsmod-@ENCHANT_MAJOR_VERSION@.1 |
804 | 805 | edit = sed \ |
805 | -e 's|@datadir[@]|$(datadir)|g' | |
806 | -e 's|DATADIR|$(datadir)|g' | |
806 | 807 | |
807 | 808 | DISTCLEANFILES = $(dist_man_MANS) |
808 | 809 | LDADD = libenchant-@ENCHANT_MAJOR_VERSION@.la $(ENCHANT_LIBS) $(top_builddir)/lib/libgnu.la |
1327 | 1328 | mv $@.tmp $@ |
1328 | 1329 | |
1329 | 1330 | 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 $@ | |
1333 | 1332 | |
1334 | 1333 | .rc.lo: |
1335 | 1334 | $(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 |
34 | 34 | #include <vector> |
35 | 35 | #include <exception> |
36 | 36 | |
37 | namespace enchant | |
37 | namespace enchant | |
38 | 38 | { |
39 | 39 | void set_prefix_dir (const std::string prefix) { |
40 | 40 | enchant_set_prefix_dir (prefix.c_str ()); |
45 | 45 | class Exception : public std::exception |
46 | 46 | { |
47 | 47 | public: |
48 | explicit Exception (const char * ex) | |
48 | explicit Exception (const char * ex) | |
49 | 49 | : std::exception (), m_ex ("") { |
50 | 50 | if (ex) |
51 | 51 | m_ex = ex; |
53 | 53 | |
54 | 54 | virtual ~Exception () noexcept { |
55 | 55 | } |
56 | ||
56 | ||
57 | 57 | virtual const char * what () const noexcept { |
58 | 58 | return m_ex.c_str(); |
59 | 59 | } |
65 | 65 | class Dict |
66 | 66 | { |
67 | 67 | friend class enchant::Broker; |
68 | ||
68 | ||
69 | 69 | public: |
70 | ||
70 | ||
71 | 71 | ~Dict () { |
72 | 72 | enchant_broker_free_dict (m_broker, m_dict); |
73 | 73 | } |
74 | ||
74 | ||
75 | 75 | bool check (const std::string & utf8word) { |
76 | 76 | int val; |
77 | 77 | |
78 | val = enchant_dict_check (m_dict, utf8word.c_str(), | |
78 | val = enchant_dict_check (m_dict, utf8word.c_str(), | |
79 | 79 | utf8word.size()); |
80 | 80 | if (val == 0) |
81 | 81 | return true; |
88 | 88 | return false; // never reached |
89 | 89 | } |
90 | 90 | |
91 | void suggest (const std::string & utf8word, | |
91 | void suggest (const std::string & utf8word, | |
92 | 92 | std::vector<std::string> & out_suggestions) { |
93 | 93 | size_t n_suggs; |
94 | 94 | char ** suggs; |
95 | ||
95 | ||
96 | 96 | 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(), | |
99 | 99 | utf8word.size(), &n_suggs); |
100 | ||
100 | ||
101 | 101 | if (suggs && n_suggs) { |
102 | 102 | out_suggestions.reserve(n_suggs); |
103 | 103 | |
104 | 104 | for (size_t i = 0; i < n_suggs; i++) { |
105 | 105 | out_suggestions.push_back (suggs[i]); |
106 | 106 | } |
107 | ||
107 | ||
108 | 108 | enchant_dict_free_string_list (m_dict, suggs); |
109 | 109 | } |
110 | 110 | } |
111 | ||
111 | ||
112 | 112 | std::vector<std::string> suggest (const std::string & utf8word) { |
113 | 113 | std::vector<std::string> result; |
114 | 114 | suggest (utf8word, result); |
115 | 115 | return result; |
116 | 116 | } |
117 | ||
117 | ||
118 | 118 | void add (const std::string & utf8word) { |
119 | enchant_dict_add (m_dict, utf8word.c_str(), | |
119 | enchant_dict_add (m_dict, utf8word.c_str(), | |
120 | 120 | utf8word.size()); |
121 | 121 | } |
122 | ||
122 | ||
123 | 123 | 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 | ||
128 | 128 | 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 | ||
133 | 133 | void remove (const std::string & utf8word) { |
134 | enchant_dict_remove (m_dict, utf8word.c_str(), | |
134 | enchant_dict_remove (m_dict, utf8word.c_str(), | |
135 | 135 | utf8word.size()); |
136 | 136 | } |
137 | ||
137 | ||
138 | 138 | 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(), | |
140 | 140 | utf8word.size()); |
141 | 141 | } |
142 | 142 | |
143 | 143 | 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, | |
149 | 149 | const std::string & utf8good) { |
150 | enchant_dict_store_replacement (m_dict, | |
150 | enchant_dict_store_replacement (m_dict, | |
151 | 151 | utf8bad.c_str(), utf8bad.size(), |
152 | 152 | utf8good.c_str(), utf8good.size()); |
153 | 153 | } |
154 | ||
154 | ||
155 | 155 | const std::string & get_lang () const { |
156 | 156 | return m_lang; |
157 | 157 | } |
171 | 171 | private: |
172 | 172 | |
173 | 173 | // space reserved for API/ABI expansion |
174 | void * _private[5]; | |
174 | void * _private[5]; | |
175 | 175 | |
176 | 176 | static void s_describe_fn (const char * const lang, |
177 | 177 | const char * const provider_name, |
179 | 179 | const char * const provider_file, |
180 | 180 | void * user_data) { |
181 | 181 | enchant::Dict * dict = static_cast<enchant::Dict *> (user_data); |
182 | ||
182 | ||
183 | 183 | dict->m_lang = lang; |
184 | 184 | dict->m_provider_name = provider_name; |
185 | 185 | dict->m_provider_desc = provider_desc; |
195 | 195 | Dict (); |
196 | 196 | Dict (const Dict & rhs); |
197 | 197 | Dict& operator=(const Dict & rhs); |
198 | ||
198 | ||
199 | 199 | EnchantDict * m_dict; |
200 | 200 | EnchantBroker * m_broker; |
201 | 201 | |
204 | 204 | std::string m_provider_desc; |
205 | 205 | std::string m_provider_file; |
206 | 206 | }; // class enchant::Dict |
207 | ||
207 | ||
208 | 208 | class Broker |
209 | 209 | { |
210 | ||
210 | ||
211 | 211 | public: |
212 | ||
212 | ||
213 | 213 | Broker () |
214 | 214 | : m_broker (enchant_broker_init ()) |
215 | 215 | { |
221 | 221 | |
222 | 222 | Dict * request_dict (const std::string & lang) { |
223 | 223 | EnchantDict * dict = enchant_broker_request_dict (m_broker, lang.c_str()); |
224 | ||
224 | ||
225 | 225 | if (!dict) { |
226 | 226 | throw enchant::Exception (enchant_broker_get_error (m_broker)); |
227 | 227 | return 0; // never reached |
228 | 228 | } |
229 | ||
229 | ||
230 | 230 | return new Dict (dict, m_broker); |
231 | 231 | } |
232 | 232 | |
233 | 233 | Dict * request_pwl_dict (const std::string & pwl) { |
234 | 234 | EnchantDict * dict = enchant_broker_request_pwl_dict (m_broker, pwl.c_str()); |
235 | ||
235 | ||
236 | 236 | if (!dict) { |
237 | 237 | throw enchant::Exception (enchant_broker_get_error (m_broker)); |
238 | 238 | return 0; // never reached |
239 | 239 | } |
240 | ||
240 | ||
241 | 241 | return new Dict (dict, m_broker); |
242 | 242 | } |
243 | ||
243 | ||
244 | 244 | bool dict_exists (const std::string & lang) { |
245 | 245 | if (enchant_broker_dict_exists (m_broker, lang.c_str())) |
246 | 246 | return true; |
247 | 247 | return false; |
248 | 248 | } |
249 | ||
249 | ||
250 | 250 | void set_ordering (const std::string & tag, const std::string & ordering) { |
251 | 251 | enchant_broker_set_ordering (m_broker, tag.c_str(), ordering.c_str()); |
252 | 252 | } |
253 | ||
253 | ||
254 | 254 | void describe (EnchantBrokerDescribeFn fn, void * user_data = NULL) { |
255 | 255 | enchant_broker_describe (m_broker, fn, user_data); |
256 | 256 | } |
257 | ||
257 | ||
258 | 258 | void list_dicts (EnchantDictDescribeFn fn, void * user_data = NULL) { |
259 | 259 | enchant_broker_list_dicts (m_broker, fn, user_data); |
260 | 260 | } |
264 | 264 | // not implemented |
265 | 265 | Broker (const Broker & rhs); |
266 | 266 | Broker& operator=(const Broker & rhs); |
267 | ||
267 | ||
268 | 268 | EnchantBroker * m_broker; |
269 | 269 | }; // class enchant::Broker |
270 | 270 | } // enchant namespace |
35 | 35 | to decide which spelling provider to use for particular languages. |
36 | 36 | The per-user file takes precedence. |
37 | 37 | .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 | |
40 | 41 | used to mean "use this ordering for all languages, unless instructed otherwise." For example: |
41 | 42 | .PP |
42 | 43 | *:aspell,hunspell,nuspell |
58 | 59 | \fICSIDL_LOCAL_APPDATA\\enchant\fR (Windows systems) |
59 | 60 | Default: \fIC:\\Documents and Settings\\\fRusername\fI\\Local Settings\\Application Data\\enchant |
60 | 61 | .TP |
61 | \fI${prefix}/share/enchant\fR | |
62 | \fI/home/rrt/.local/share/enchant\fR | |
62 | 63 | (Or the equivalent location relative to the enchant library for a relocatable build.) |
63 | 64 | .PP |
64 | 65 | 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 | |
66 | 67 | \fI~/.config/enchant/hunspell\fR. |
67 | 68 | .PP |
68 | 69 | Some providers may also look in a standard system directory for their |
102 | 102 | } else { |
103 | 103 | EnchantDict *dict = enchant_broker_request_dict (broker, lang_tag); |
104 | 104 | 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); | |
106 | 110 | retcode = 1; |
107 | 111 | } else { |
108 | 112 | enchant_dict_describe (dict, |
127 | 127 | |
128 | 128 | int (*check) (struct str_enchant_dict * me, const char *const word, |
129 | 129 | size_t len); |
130 | ||
130 | ||
131 | 131 | /* returns utf8*/ |
132 | 132 | char **(*suggest) (struct str_enchant_dict * me, |
133 | 133 | const char *const word, size_t len, |
134 | 134 | size_t * out_n_suggs); |
135 | ||
135 | ||
136 | 136 | void (*add_to_personal) (struct str_enchant_dict * me, |
137 | 137 | const char *const word, size_t len); |
138 | ||
138 | ||
139 | 139 | void (*add_to_session) (struct str_enchant_dict * me, |
140 | 140 | const char *const word, size_t len); |
141 | ||
141 | ||
142 | 142 | void (*store_replacement) (struct str_enchant_dict * me, |
143 | 143 | const char *const mis, size_t mis_len, |
144 | 144 | const char *const cor, size_t cor_len); |
145 | ||
145 | ||
146 | 146 | void (*add_to_exclude) (struct str_enchant_dict * me, |
147 | 147 | const char *const word, size_t len); |
148 | 148 | |
151 | 151 | int (*is_word_character) (struct str_enchant_dict * me, |
152 | 152 | uint32_t uc_in, size_t n); |
153 | 153 | }; |
154 | ||
154 | ||
155 | 155 | struct str_enchant_provider |
156 | 156 | { |
157 | 157 | void *user_data; |
158 | 158 | void *enchant_private_data; |
159 | 159 | EnchantBroker * owner; |
160 | ||
160 | ||
161 | 161 | void (*dispose) (struct str_enchant_provider * me); |
162 | ||
162 | ||
163 | 163 | EnchantDict *(*request_dict) (struct str_enchant_provider * me, |
164 | 164 | const char *const tag); |
165 | ||
165 | ||
166 | 166 | void (*dispose_dict) (struct str_enchant_provider * me, |
167 | 167 | EnchantDict * dict); |
168 | ||
168 | ||
169 | 169 | int (*dictionary_exists) (struct str_enchant_provider * me, |
170 | 170 | const char *const tag); |
171 | 171 |
35 | 35 | to decide which spelling provider to use for particular languages. |
36 | 36 | The per-user file takes precedence. |
37 | 37 | .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 | |
40 | 41 | used to mean "use this ordering for all languages, unless instructed otherwise." For example: |
41 | 42 | .PP |
42 | 43 | *:aspell,hunspell,nuspell |
58 | 59 | \fICSIDL_LOCAL_APPDATA\\enchant\fR (Windows systems) |
59 | 60 | Default: \fIC:\\Documents and Settings\\\fRusername\fI\\Local Settings\\Application Data\\enchant |
60 | 61 | .TP |
61 | \fI@datadir@/enchant\fR | |
62 | \fIDATADIR/enchant\fR | |
62 | 63 | (Or the equivalent location relative to the enchant library for a relocatable build.) |
63 | 64 | .PP |
64 | 65 | 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 | |
66 | 67 | \fI~/.config/enchant/hunspell\fR. |
67 | 68 | .PP |
68 | 69 | Some providers may also look in a standard system directory for their |
55 | 55 | |
56 | 56 | static const char *charset; |
57 | 57 | |
58 | typedef enum | |
58 | typedef enum | |
59 | 59 | { |
60 | 60 | MODE_NONE, |
61 | 61 | MODE_A, |
62 | 62 | MODE_L |
63 | 63 | } IspellMode_t; |
64 | 64 | |
65 | static void | |
65 | static void | |
66 | 66 | print_version (FILE * to) |
67 | 67 | { |
68 | 68 | fprintf (to, "@(#) International Ispell Version 3.1.20 (but really Enchant %s)\n", PACKAGE_VERSION); |
109 | 109 | if (utf) { |
110 | 110 | g_string_assign (str, utf); |
111 | 111 | 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 | |
114 | 114 | already utf8 and glib is just being stupid. */ |
115 | 115 | } |
116 | 116 | |
127 | 127 | if (native) { |
128 | 128 | fwrite (native, 1, bytes_written, stdout); |
129 | 129 | g_free (native); |
130 | } else { | |
130 | } else | |
131 | 131 | /* Assume that it's already utf8 and glib is just being stupid. */ |
132 | 132 | printf ("%s", str); |
133 | } | |
134 | 133 | } |
135 | 134 | |
136 | 135 | static int |
170 | 169 | printf ("%u ", (unsigned int)lineCount); |
171 | 170 | print_utf (word->str); |
172 | 171 | printf (" %u %u:", (unsigned int)n_suggs, (unsigned int)start_pos); |
173 | ||
172 | ||
174 | 173 | for (size_t i = 0; i < n_suggs; i++) { |
175 | 174 | putchar (' '); |
176 | 175 | print_utf (suggs[i]); |
211 | 210 | while (cur_pos < line->len && *utf) { |
212 | 211 | gunichar uc; |
213 | 212 | |
214 | /* Skip non-word characters. */ | |
213 | /* Skip non-word characters. */ | |
215 | 214 | cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); |
216 | 215 | uc = g_utf8_get_char (utf); |
217 | 216 | 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); | |
219 | 218 | uc = g_utf8_get_char (utf); |
220 | 219 | cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); |
221 | 220 | } |
224 | 223 | /* Skip over word characters. */ |
225 | 224 | while (cur_pos < line->len && *utf && enchant_dict_is_word_character (dict, uc, 1)) { |
226 | 225 | g_string_append_unichar (word, uc); |
227 | utf = g_utf8_next_char (utf); | |
226 | utf = g_utf8_next_char (utf); | |
228 | 227 | uc = g_utf8_get_char (utf); |
229 | 228 | cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); |
230 | 229 | } |
231 | 230 | |
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; | |
234 | 233 | (i_utf = g_utf8_find_prev_char (word->str, i_utf)) != NULL; |
235 | 234 | g_string_truncate (word, i_utf - word->str)) { |
236 | 235 | uc = g_utf8_get_char (i_utf); |
239 | 238 | } |
240 | 239 | |
241 | 240 | /* 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)); | |
244 | 243 | tokens = g_slist_append (tokens, GINT_TO_POINTER(start_pos)); |
245 | 244 | g_string_truncate (word, 0); |
246 | 245 | } |
255 | 254 | { |
256 | 255 | EnchantBroker * broker; |
257 | 256 | EnchantDict * dict; |
258 | ||
257 | ||
259 | 258 | GString * str, * word = NULL; |
260 | 259 | GSList * tokens, *token_ptr; |
261 | 260 | gchar * lang; |
269 | 268 | if (dictionary) |
270 | 269 | lang = strdup (dictionary); |
271 | 270 | else { |
272 | lang = enchant_get_user_language(); | |
271 | lang = enchant_get_user_language(); | |
273 | 272 | if(!lang) |
274 | 273 | return 1; |
275 | } | |
274 | } | |
276 | 275 | |
277 | 276 | /* Enchant will get rid of trailing information like de_DE@euro or de_DE.ISO-8859-15 */ |
278 | ||
277 | ||
279 | 278 | broker = enchant_broker_init (); |
280 | 279 | dict = enchant_broker_request_dict (broker, lang); |
281 | 280 | |
289 | 288 | free (lang); |
290 | 289 | |
291 | 290 | str = g_string_new (NULL); |
292 | ||
291 | ||
293 | 292 | while (!was_last_line) { |
294 | 293 | gboolean mode_A_no_command = FALSE; |
295 | 294 | was_last_line = consume_line (in, str); |
363 | 362 | ssize_t mis_len = comma - mis; |
364 | 363 | ssize_t cor_len = strlen(str->str) - (cor - str->str); |
365 | 364 | 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 */ | |
367 | 367 | printf("%s\n", enchant_dict_get_extra_word_characters(dict)); |
368 | } | |
369 | 368 | } |
370 | 369 | break; |
371 | 370 | |
403 | 402 | if (token_ptr) |
404 | 403 | g_slist_free (token_ptr); |
405 | 404 | } |
406 | } | |
407 | ||
408 | if (mode == MODE_A && corrected_something) { | |
405 | } | |
406 | ||
407 | if (mode == MODE_A && corrected_something) | |
409 | 408 | putchar('\n'); |
410 | } | |
411 | 409 | g_string_truncate (str, 0); |
412 | 410 | fflush (stdout); |
413 | 411 | } |
436 | 434 | g_get_charset(&charset); |
437 | 435 | #ifdef _WIN32 |
438 | 436 | /* 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) | |
440 | 438 | charset = g_strdup_printf("CP%u", GetConsoleCP()); |
441 | } | |
442 | 439 | #endif |
443 | 440 | |
444 | 441 | int optchar; |
514 | 511 | enchant_pwl_free (pwl); |
515 | 512 | if (file) |
516 | 513 | fclose (fp); |
517 | ||
514 | ||
518 | 515 | return rval; |
519 | 516 | } |
110 | 110 | * language that does not explictly declare an ordering. |
111 | 111 | */ |
112 | 112 | void enchant_broker_set_ordering (EnchantBroker * broker, |
113 | const char * const tag, | |
113 | const char * const tag, | |
114 | 114 | const char * const ordering); |
115 | 115 | /** |
116 | 116 | * enchant_broker_get_error |
135 | 135 | const char * const provider_desc, |
136 | 136 | const char * const provider_dll_file, |
137 | 137 | void * user_data); |
138 | ||
138 | ||
139 | 139 | /** |
140 | 140 | * enchant_broker_describe |
141 | 141 | * @broker: A non-null #EnchantBroker |
175 | 175 | * Returns: A %null terminated list of UTF-8 encoded suggestions, or %null |
176 | 176 | */ |
177 | 177 | 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); | |
179 | 179 | |
180 | 180 | /** |
181 | 181 | * enchant_dict_add |
0 | 0 | /* enchant |
1 | 1 | * 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> | |
3 | 3 | * |
4 | 4 | * This library is free software; you can redistribute it and/or |
5 | 5 | * modify it under the terms of the GNU Lesser General Public |
45 | 45 | |
46 | 46 | #include "enchant.h" |
47 | 47 | #include "enchant-provider.h" |
48 | #include "debug.h" | |
48 | 49 | #include "pwl.h" |
49 | 50 | #include "unused-parameter.h" |
50 | 51 | #include "relocatable.h" |
165 | 166 | { |
166 | 167 | const char * it; |
167 | 168 | 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; | |
172 | 171 | |
173 | 172 | return it != tag; /*empty tag invalid*/ |
174 | 173 | } |
771 | 770 | { |
772 | 771 | if (provider == NULL) |
773 | 772 | 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"); | |
774 | 779 | else if (provider->identify == NULL) |
775 | 780 | g_warning ("EnchantProvider's identify method cannot be NULL\n"); |
776 | 781 | 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"); | |
778 | 783 | else if (provider->describe == NULL) |
779 | 784 | g_warning ("EnchantProvider's describe method cannot be NULL\n"); |
780 | 785 | 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"); | |
786 | 787 | else if (provider->list_dicts == NULL) |
787 | 788 | g_warning ("EnchantProvider's list_dicts method cannot be NULL\n"); |
788 | 789 | else |
835 | 836 | } |
836 | 837 | } |
837 | 838 | else |
838 | { | |
839 | g_module_close (module); | |
840 | } | |
839 | g_module_close (module); | |
841 | 840 | } |
842 | 841 | 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()); | |
846 | 843 | |
847 | 844 | g_free (filename); |
848 | 845 | #ifdef _WIN32 |
960 | 957 | |
961 | 958 | /* append providers not in the list, or from an unordered list */ |
962 | 959 | 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); | |
967 | 962 | |
968 | 963 | return list; |
969 | 964 | } |
1083 | 1078 | GSList * list = enchant_get_ordered_providers (broker, tag); |
1084 | 1079 | for (GSList *listIter = list; listIter != NULL; listIter = g_slist_next (listIter)) |
1085 | 1080 | { |
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) | |
1091 | 1086 | { |
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; | |
1105 | 1094 | } |
1106 | 1095 | } |
1107 | 1096 | g_slist_free (list); |
1121 | 1110 | |
1122 | 1111 | char * normalized_tag = enchant_normalize_dictionary_tag (tag); |
1123 | 1112 | 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"); | |
1127 | 1114 | else if ((dict = _enchant_broker_request_dict (broker, normalized_tag)) == NULL) |
1128 | 1115 | { |
1129 | 1116 | char * iso_639_only_tag = enchant_iso_639_from_tag (normalized_tag); |
1176 | 1163 | { |
1177 | 1164 | EnchantProvider *provider = (EnchantProvider *) list->data; |
1178 | 1165 | |
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++) | |
1180 | 1170 | { |
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); | |
1200 | 1182 | } |
1201 | ||
1202 | enchant_free_string_list (dicts); | |
1183 | g_slist_free (providers); | |
1184 | } | |
1203 | 1185 | } |
1186 | ||
1187 | enchant_free_string_list (dicts); | |
1204 | 1188 | } |
1205 | 1189 | |
1206 | 1190 | GSList *tags = NULL; |
1252 | 1236 | int exists = 0; |
1253 | 1237 | |
1254 | 1238 | 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 | |
1259 | 1241 | { |
1260 | 1242 | size_t n_dicts; |
1261 | 1243 | char ** dicts = (*provider->list_dicts) (provider, &n_dicts); |
1262 | 1244 | |
1263 | 1245 | 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; | |
1269 | 1249 | } |
1270 | 1250 | |
1271 | 1251 | enchant_free_string_list (dicts); |
1285 | 1265 | if (g_hash_table_lookup (broker->dict_map, (gpointer) tag) != NULL) |
1286 | 1266 | return 1; |
1287 | 1267 | |
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)) | |
1289 | 1269 | if (enchant_provider_dictionary_exists ((EnchantProvider *) list->data, tag)) |
1290 | 1270 | return 1; |
1291 | } | |
1292 | 1271 | |
1293 | 1272 | return 0; |
1294 | 1273 | } |
1305 | 1284 | int exists = 0; |
1306 | 1285 | |
1307 | 1286 | 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"); | |
1311 | 1288 | else if ((exists = _enchant_broker_dict_exists (broker, normalized_tag)) == 0) |
1312 | 1289 | { |
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); | |
1316 | 1291 | |
1317 | 1292 | 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); | |
1321 | 1294 | |
1322 | 1295 | free (iso_639_only_tag); |
1323 | 1296 | } |
1345 | 1318 | gunichar uc = (gunichar)uc_in; |
1346 | 1319 | |
1347 | 1320 | /* 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("’")) | |
1349 | 1322 | return n < 2; |
1350 | } | |
1351 | 1323 | |
1352 | 1324 | GUnicodeType type = g_unichar_type(uc); |
1353 | 1325 | |
1367 | 1339 | return 1; /* Enchant 1.3.0 defines word chars like this. */ |
1368 | 1340 | |
1369 | 1341 | case G_UNICODE_DASH_PUNCTUATION: |
1370 | if ((n == 1) && (type == G_UNICODE_DASH_PUNCTUATION)) { | |
1342 | if ((n == 1) && (type == G_UNICODE_DASH_PUNCTUATION)) | |
1371 | 1343 | return 1; /* hyphens only accepted within a word. */ |
1372 | } | |
1373 | 1344 | /* Fallthrough */ |
1374 | 1345 | |
1375 | 1346 | case G_UNICODE_CONTROL: |
0 | 0 | #include <winver.h> |
1 | 1 | |
2 | 2 | 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 | |
5 | 5 | FILEFLAGSMASK 0 |
6 | 6 | FILEFLAGS 0 |
7 | 7 | FILEOS VOS__WINDOWS32 |
14 | 14 | BEGIN |
15 | 15 | VALUE "CompanyName", "none" |
16 | 16 | VALUE "FileDescription", "libenchant" |
17 | VALUE "FileVersion", "2.3.1" | |
17 | VALUE "FileVersion", "2.3.2" | |
18 | 18 | VALUE "InternalName", "libenchant-2.3" |
19 | 19 | VALUE "LegalCopyright", "Copyright (C) 2002-2007 Dom Lachowicz" |
20 | 20 | VALUE "OriginalFilename", "libenchant-2.3.dll" |
21 | 21 | VALUE "ProductName", "libenchant" |
22 | VALUE "ProductVersion", "2.3.1" | |
22 | VALUE "ProductVersion", "2.3.2" | |
23 | 23 | END |
24 | 24 | END |
25 | 25 | BLOCK "VarFileInfo" |
0 | 0 | /* enchant |
1 | 1 | * Copyright (C) 2003, 2004 Dom Lachowicz |
2 | * Copyright (C) 2016-2021 Reuben Thomas <rrt@sc3d.org> | |
2 | 3 | * |
3 | 4 | * This library is free software; you can redistribute it and/or |
4 | 5 | * modify it under the terms of the GNU Lesser General Public |
74 | 75 | |
75 | 76 | /* A PWL dictionary is stored as a Trie-like data structure EnchantTrie. |
76 | 77 | * 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 | |
78 | 79 | * that potentially modify a trie need to return the modified trie, |
79 | 80 | * as additional memory may have been allocated. |
80 | 81 | * |
201 | 202 | * |
202 | 203 | * Returns: a new PWL object used to store/check/suggest words |
203 | 204 | * or NULL if the file cannot be opened or created |
204 | */ | |
205 | */ | |
205 | 206 | EnchantPWL* enchant_pwl_init_with_file(const char * file) |
206 | 207 | { |
207 | 208 | g_return_val_if_fail (file != NULL, NULL); |
232 | 233 | pwl->words_in_trie = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); |
233 | 234 | |
234 | 235 | FILE *f = g_fopen(pwl->filename, "r"); |
235 | if (!f) | |
236 | if (!f) | |
236 | 237 | return; |
237 | 238 | |
238 | 239 | pwl->file_changed = stats.st_mtime; |
239 | 240 | |
240 | 241 | enchant_lock_file (f); |
241 | ||
242 | ||
242 | 243 | char buffer[BUFSIZ + 1]; |
243 | 244 | size_t line_number = 1; |
244 | 245 | for (; NULL != (fgets (buffer, sizeof (buffer), f)); ++line_number) |
247 | 248 | if(line_number == 1 && BOM == g_utf8_get_char(line)) |
248 | 249 | line = g_utf8_next_char(line); |
249 | 250 | |
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. */ | |
251 | 252 | { |
252 | 253 | g_warning ("Line too long (ignored) in %s at line:%zu\n", pwl->filename, line_number); |
253 | 254 | while (NULL != (fgets (buffer, sizeof (buffer), f))) |
254 | 255 | { |
255 | if (line[strlen(buffer)-1]=='\n') | |
256 | if (line[strlen(buffer)-1]=='\n') | |
256 | 257 | break; |
257 | 258 | } |
258 | 259 | continue; |
267 | 268 | g_warning ("Bad UTF-8 sequence in %s at line:%zu\n", pwl->filename, line_number); |
268 | 269 | } |
269 | 270 | } |
270 | ||
271 | ||
271 | 272 | enchant_unlock_file (f); |
272 | 273 | fclose (f); |
273 | 274 | } |
288 | 289 | g_free (normalized_word); |
289 | 290 | return; |
290 | 291 | } |
291 | ||
292 | ||
292 | 293 | g_hash_table_insert (pwl->words_in_trie, normalized_word, g_strndup(word,len)); |
293 | 294 | |
294 | 295 | pwl->trie = enchant_trie_insert(pwl->trie, normalized_word); |
307 | 308 | pwl->trie = NULL; /* make trie empty if has no content */ |
308 | 309 | } |
309 | 310 | } |
310 | ||
311 | ||
311 | 312 | g_free(normalized_word); |
312 | 313 | } |
313 | 314 | |
345 | 346 | } |
346 | 347 | |
347 | 348 | if (fwrite (word, sizeof(char), len, f) == (size_t)len) |
348 | { | |
349 | putc ('\n', f); | |
350 | } | |
349 | putc ('\n', f); | |
351 | 350 | enchant_unlock_file (f); |
352 | 351 | fclose (f); |
353 | } | |
352 | } | |
354 | 353 | } |
355 | 354 | } |
356 | 355 | |
400 | 399 | fwrite (searchstart, sizeof(char), length - (searchstart - contents), f); |
401 | 400 | break; |
402 | 401 | } |
403 | else | |
402 | else | |
404 | 403 | { |
405 | 404 | char* foundend = needle+len; |
406 | 405 | if((needle == filestart || contents[needle-contents-1] == '\n' || contents[needle-contents-1] == '\r') && |
418 | 417 | } |
419 | 418 | } |
420 | 419 | g_free(key); |
421 | ||
420 | ||
422 | 421 | GStatBuf stats; |
423 | 422 | if(g_stat(pwl->filename, &stats)==0) |
424 | 423 | pwl->file_changed = stats.st_mtime; |
426 | 425 | enchant_unlock_file (f); |
427 | 426 | |
428 | 427 | fclose (f); |
429 | } | |
428 | } | |
430 | 429 | g_free(contents); |
431 | 430 | } |
432 | 431 | } |
503 | 502 | if ((type != G_UNICODE_UPPERCASE_LETTER && type != G_UNICODE_TITLECASE_LETTER) || |
504 | 503 | ch != g_unichar_totitle(ch)) |
505 | 504 | return 0; |
506 | ||
505 | ||
507 | 506 | for (const char* it = g_utf8_next_char(word); it < word + len; it = g_utf8_next_char(it)) |
508 | 507 | { |
509 | 508 | type = g_unichar_type(g_utf8_get_char(it)); |
538 | 537 | enchant_pwl_refresh_from_file(pwl); |
539 | 538 | |
540 | 539 | int exists = enchant_pwl_contains(pwl, word, len); |
541 | ||
540 | ||
542 | 541 | if(exists) |
543 | 542 | return 0; |
544 | 543 | |
571 | 570 | (*((int*)(matcher->cbdata)))++; |
572 | 571 | } |
573 | 572 | |
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, | |
576 | 575 | EnchantSuggList* suggs_list) |
577 | 576 | { |
578 | 577 | gchar* (*utf8_case_convert_function)(const gchar*str, gssize len) = NULL; |
580 | 579 | utf8_case_convert_function = enchant_utf8_strtitle; |
581 | 580 | else if (enchant_is_all_caps(word, len)) |
582 | 581 | utf8_case_convert_function = g_utf8_strup; |
583 | ||
582 | ||
584 | 583 | for (size_t i = 0; i < suggs_list->n_suggs; ++i) |
585 | 584 | { |
586 | 585 | gchar* suggestion = g_hash_table_lookup (pwl->words_in_trie, suggs_list->suggs[i]); |
591 | 590 | cased_suggestion = utf8_case_convert_function(suggestion, suggestion_len); |
592 | 591 | else |
593 | 592 | cased_suggestion = g_strndup(suggestion, suggestion_len); |
594 | ||
593 | ||
595 | 594 | g_free(suggs_list->suggs[i]); |
596 | 595 | suggs_list->suggs[i] = cased_suggestion; |
597 | 596 | } |
614 | 613 | return best_dist; |
615 | 614 | } |
616 | 615 | |
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 | |
618 | 617 | * given suggs (if suggs == NULL just best from pwl) */ |
619 | 618 | char** enchant_pwl_suggest(EnchantPWL *pwl, const char *const word, |
620 | 619 | ssize_t len, char** suggs, size_t* out_n_suggs) |
644 | 643 | (*out_n_suggs) = sugg_list.n_suggs; |
645 | 644 | |
646 | 645 | enchant_pwl_case_and_denormalize_suggestions(pwl, word, len, &sugg_list); |
647 | ||
646 | ||
648 | 647 | return sugg_list.suggs; |
649 | 648 | } |
650 | 649 | |
662 | 661 | size_t loc; |
663 | 662 | for(loc=0; loc < sugg_list->n_suggs; loc++) { |
664 | 663 | /* 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) | |
666 | 665 | break; |
667 | } | |
668 | 666 | /* Already in the list with better score, just return */ |
669 | 667 | if(strcmp(match,sugg_list->suggs[loc])==0) { |
670 | 668 | g_free(match); |
678 | 676 | } |
679 | 677 | |
680 | 678 | int changes = 1; /* num words added to list */ |
681 | ||
679 | ||
682 | 680 | /* Remove all elements with worse score */ |
683 | 681 | for(size_t i=loc; i < sugg_list->n_suggs; i++){ |
684 | 682 | g_free(sugg_list->suggs[i]); |
693 | 691 | static void enchant_trie_free(EnchantTrie* trie) |
694 | 692 | { |
695 | 693 | /* 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; | |
699 | 696 | |
700 | 697 | /* Because we have not set a destroy function for the hashtable |
701 | 698 | * (to make code cleaner below), we need to explicitly free all |
719 | 716 | |
720 | 717 | static EnchantTrie* enchant_trie_insert(EnchantTrie* trie,const char *const word) |
721 | 718 | { |
722 | if (trie == NULL) { | |
719 | if (trie == NULL) | |
723 | 720 | trie = g_new0(EnchantTrie, 1); |
724 | } | |
725 | 721 | |
726 | 722 | if (trie->value == NULL) { |
727 | 723 | if (trie->subtries == NULL) { |
743 | 739 | } |
744 | 740 | } else { |
745 | 741 | /* 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, | |
747 | 743 | g_str_equal, g_free, NULL); |
748 | 744 | char *tmpWord = trie->value; |
749 | 745 | trie->value = NULL; |
763 | 759 | if (trie->value == NULL) { |
764 | 760 | if (trie->subtries != NULL) { |
765 | 761 | /* Store multiple words in subtries */ |
766 | if (word[0] == '\0') { | |
762 | if (word[0] == '\0') | |
767 | 763 | /* End-of-string is marked with special node */ |
768 | 764 | g_hash_table_remove(trie->subtries, ""); |
769 | } else { | |
765 | else { | |
770 | 766 | ssize_t nxtCh = (ssize_t)(g_utf8_next_char(word) - word); |
771 | 767 | char *tmpWord = g_strndup(word, nxtCh); |
772 | 768 | EnchantTrie *subtrie = g_hash_table_lookup(trie->subtries, tmpWord); |
798 | 794 | g_list_free(keys); |
799 | 795 | } |
800 | 796 | } |
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, | |
811 | 804 | EnchantTrieMatcher* matcher, |
812 | 805 | char** nxtChS) |
813 | 806 | { |
829 | 822 | g_return_if_fail(matcher); |
830 | 823 | |
831 | 824 | /* Can't match in the empty trie */ |
832 | if(trie == NULL) { | |
833 | return; | |
834 | } | |
825 | if(trie == NULL) | |
826 | return; | |
835 | 827 | |
836 | 828 | /* Bail out if over the error limits */ |
837 | 829 | if(matcher->num_errors > matcher->max_errors){ |
842 | 834 | if (trie == EOSTrie) { |
843 | 835 | size_t word_len = strlen(matcher->word); |
844 | 836 | int errs = matcher->num_errors; |
845 | if((ssize_t)word_len > matcher->word_pos) { | |
837 | if((ssize_t)word_len > matcher->word_pos) | |
846 | 838 | 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) | |
849 | 840 | matcher->cbfunc(g_strdup(matcher->path),matcher); |
850 | } | |
851 | 841 | matcher->num_errors = errs; |
852 | 842 | return; |
853 | 843 | } |
858 | 848 | int errs = matcher->num_errors; |
859 | 849 | value = trie->value; |
860 | 850 | 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, | |
865 | 853 | &(matcher->word[matcher->word_pos])); |
866 | 854 | 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) | |
872 | 858 | matcher->cbfunc(g_strconcat(matcher->path, |
873 | 859 | trie->value,NULL), |
874 | 860 | matcher); |
875 | } | |
876 | 861 | matcher->num_errors = errs; |
877 | 862 | return; |
878 | 863 | } |
917 | 902 | |
918 | 903 | ssize_t nxtChI = (ssize_t) (g_utf8_next_char(&matcher->word[matcher->word_pos]) - matcher->word); |
919 | 904 | |
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; | |
924 | 908 | |
925 | 909 | enchant_trie_matcher_pushpath(matcher,key); |
926 | 910 | |
951 | 935 | } |
952 | 936 | |
953 | 937 | g_free(key2); |
954 | ||
938 | ||
955 | 939 | matcher->word_pos = oldPos; |
956 | 940 | } |
957 | 941 | |
1016 | 1000 | { |
1017 | 1001 | g_return_if_fail(matcher->path_pos >= 0); |
1018 | 1002 | matcher->path_pos = matcher->path_pos - num; |
1019 | if(matcher->path_pos < 0) { | |
1003 | if(matcher->path_pos < 0) | |
1020 | 1004 | matcher->path_pos = 0; |
1021 | } | |
1022 | 1005 | matcher->path[matcher->path_pos] = '\0'; |
1023 | 1006 | } |
1024 | 1007 | |
1029 | 1012 | gunichar * word2 = g_utf8_to_ucs4_fast(utf8word2, -1, &len2); |
1030 | 1013 | |
1031 | 1014 | int * table = g_new0(int, (len1+1)*(len2+1)); |
1032 | ||
1015 | ||
1033 | 1016 | /* Initialise outer rows of table */ |
1034 | 1017 | for (glong i = 0; i < len1 + 1; i++) |
1035 | 1018 | table[i*(len2+1)] = i; |
1041 | 1024 | for (glong j = 1; j < len2+1; j++) { |
1042 | 1025 | int cost = word1[i-1] != word2[j-1]; |
1043 | 1026 | 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]) | |
1045 | 1028 | v1 = MIN (v1, table[(i-2)*(len2+1)+(j-2)] + cost); |
1046 | } | |
1047 | 1029 | |
1048 | 1030 | int v2 = table[i*(len2+1)+(j-1)] + 1; |
1049 | 1031 | int v3 = table[(i-1)*(len2+1)+(j-1)] + cost; |
61 | 61 | TEST_FIXTURE(ProviderListDicts_TestFixture, |
62 | 62 | ProviderListDicts_ForEachReturned_RequestDictSucceeds) |
63 | 63 | { |
64 | if(_provider->list_dicts && _provider->request_dict) | |
64 | if(_provider->list_dicts) | |
65 | 65 | { |
66 | size_t n_dicts; | |
66 | size_t n_dicts; | |
67 | 67 | |
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) | |
75 | 74 | _provider->dispose_dict(_provider, dict); |
76 | } | |
77 | 75 | } |
78 | 76 | } |
79 | 77 | } |
33 | 33 | //Teardown |
34 | 34 | ~ProviderRequestDictionary_TestFixture() |
35 | 35 | { |
36 | if (_dict && _provider->dispose_dict) | |
37 | { | |
38 | _provider->dispose_dict(_provider, _dict); | |
39 | } | |
36 | if (_dict) | |
37 | _provider->dispose_dict(_provider, _dict); | |
40 | 38 | } |
41 | 39 | }; |
42 | 40 | |
48 | 46 | TEST_FIXTURE(ProviderRequestDictionary_TestFixture, |
49 | 47 | ProviderRequestDictionary_ProviderDoesNotHave_ReturnsNull) |
50 | 48 | { |
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); | |
56 | 51 | } |
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 | } |
25 | 25 | #include <gmodule.h> |
26 | 26 | #include <assert.h> |
27 | 27 | #include <string.h> |
28 | #include <stdlib.h> | |
28 | 29 | #include "unittest_enchant_providers.h" |
29 | 30 | |
30 | 31 | int Test(char* path); |
166 | 167 | g_provider->dispose(g_provider); |
167 | 168 | |
168 | 169 | g_provider = NULL; |
170 | free(broker.error); | |
169 | 171 | } |
170 | 172 | |
171 | 173 | if(module){ |
68 | 68 | |
69 | 69 | // Try getting dictionary for user's default language |
70 | 70 | 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); | |
75 | 72 | g_free (lang); |
76 | 73 | |
77 | 74 | // 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) | |
79 | 76 | { |
80 | 77 | size_t n_dicts; |
81 | 78 | |
89 | 86 | |
90 | 87 | EnchantDict* GetDictionary(const char* language) |
91 | 88 | { |
92 | if(_provider->request_dict) | |
93 | { | |
94 | 89 | return (*_provider->request_dict) (_provider, language); |
95 | } | |
96 | return NULL; | |
97 | 90 | } |
98 | 91 | |
99 | 92 | virtual void ReleaseDictionary(EnchantDict* dict) |
100 | 93 | { |
101 | if (dict && _provider->dispose_dict) | |
102 | { | |
94 | if (dict) | |
103 | 95 | _provider->dispose_dict(_provider, dict); |
104 | } | |
105 | 96 | } |
106 | 97 | }; |
28 | 28 | mock_provider_dispose(EnchantProvider *me) |
29 | 29 | { |
30 | 30 | g_free(me); |
31 | } | |
32 | ||
33 | static EnchantDict * | |
34 | mock_provider_request_dict(EnchantProvider *, const char *const) | |
35 | { | |
36 | return NULL; | |
31 | 37 | } |
32 | 38 | |
33 | 39 | static void |
87 | 93 | |
88 | 94 | provider = g_new0(EnchantProvider, 1); |
89 | 95 | 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 | |
91 | 97 | provider->dispose_dict = mock_provider_dispose_dict; |
92 | 98 | provider->identify = hasIdentify ? mock_provider_identify : NULL; // this is required or module won't load |
93 | 99 | provider->describe = hasDescribe ? mock_provider_describe : NULL; // this is required or module won't load |
308 | 308 | AddWordsToDictionary(sNoiseWords); |
309 | 309 | |
310 | 310 | std::vector<std::string> suggestions = GetSuggestionsFromWord("saskep"); |
311 | CHECK(suggestions.size() > 0); | |
311 | 312 | // FIXME: The string in the next line was originally "hasten", but the |
312 | 313 | // test failed. Is this now correct? |
313 | 314 | CHECK(suggestions[0] != "hastens"); |