From 1ec55513c204e103d292f471deaf38aca0af4270 Mon Sep 17 00:00:00 2001 From: Reuben Thomas Date: Sun, 19 Feb 2017 13:14:26 +0000 Subject: Move installed programs from tests/ to src/ Fix a warning found by compiling in src with more warnings. --- src/.gitignore | 4 + src/Makefile.am | 10 +- src/enchant-ispell.c | 625 +++++++++++++++++++++++++++++++++++++++++++++++++ src/enchant-lsmod.c | 139 +++++++++++ tests/.gitignore | 4 - tests/Makefile.am | 2 - tests/enchant-ispell.c | 625 ------------------------------------------------- tests/enchant-lsmod.c | 139 ----------- 8 files changed, 775 insertions(+), 773 deletions(-) create mode 100644 src/enchant-ispell.c create mode 100644 src/enchant-lsmod.c delete mode 100644 tests/enchant-ispell.c delete mode 100644 tests/enchant-lsmod.c diff --git a/src/.gitignore b/src/.gitignore index f66b20d..67440b6 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1 +1,5 @@ +/enchant +/enchant.exe +/enchant-lsmod +/enchant-lsmod.exe /libenchant.rc diff --git a/src/Makefile.am b/src/Makefile.am index deedb5b..fb8f0c5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,10 @@ SUBDIRS=. aspell ispell uspell myspell hspell applespell voikko zemberek -AM_CPPFLAGS=-I$(top_srcdir) $(ENCHANT_CFLAGS) $(CC_WARN_CFLAGS) -DENCHANT_GLOBAL_MODULE_DIR=\"$(libdir)/enchant\" -DENCHANT_GLOBAL_ORDERING=\"$(datadir)/enchant\" -D_ENCHANT_BUILD=1 -DENCHANT_VERSION_STRING=\"@ENCHANT_MAJOR_VERSION@.@ENCHANT_MINOR_VERSION@.@ENCHANT_MICRO_VERSION@\" +AM_CPPFLAGS=-I$(top_srcdir) $(ENCHANT_CFLAGS) $(CC_WARN_CFLAGS) lib_LTLIBRARIES = libenchant.la +libenchant_la_CPPFLAGS = $(AM_CPPFLAGS) -DENCHANT_GLOBAL_MODULE_DIR=\"$(libdir)/enchant\" -DENCHANT_GLOBAL_ORDERING=\"$(datadir)/enchant\" -D_ENCHANT_BUILD=1 -DENCHANT_VERSION_STRING=\"@ENCHANT_MAJOR_VERSION@.@ENCHANT_MINOR_VERSION@.@ENCHANT_MICRO_VERSION@\" libenchant_la_LIBADD= $(ENCHANT_LIBS) @ENCHANT_WIN32_RESOURCE@ libenchant_la_LDFLAGS = -no-undefined -export-symbols-regex '^enchant_.*' @@ -20,11 +21,15 @@ libenchant_includedir = $(includedir)/enchant libenchant_include_HEADERS = enchant.h enchant-provider.h enchant++.h if WITH_APPLESPELL -AM_CPPFLAGS += @APPLESPELL_CFLAGS@ +libenchant_la_CPPFLAGS += @APPLESPELL_CFLAGS@ libenchant_la_LIBADD += @APPLESPELL_LIBS@ libenchant_la_LDFLAGS += @APPLESPELL_LDFLAGS@ endif +LDADD = libenchant.la $(ENCHANT_LIBS) +bin_PROGRAMS = enchant-lsmod enchant +enchant_SOURCES = enchant-ispell.c + EXTRA_DIST=enchant.i if OS_WIN32 @@ -32,4 +37,3 @@ if OS_WIN32 @ENCHANT_WIN32_RESOURCE@ : libenchant.rc $(top_srcdir)/lt-compile-resource libenchant.rc @ENCHANT_WIN32_RESOURCE@ endif - diff --git a/src/enchant-ispell.c b/src/enchant-ispell.c new file mode 100644 index 0000000..5d9aa4b --- /dev/null +++ b/src/enchant-ispell.c @@ -0,0 +1,625 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* enchant + * Copyright (C) 2003 Dom Lachowicz + * 2007 Hannu Väisänen + * 2016 Reuben Thomas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, Dom Lachowicz + * gives permission to link the code of this program with + * the non-LGPL Spelling Provider libraries (eg: a MSFT Office + * spell checker backend) and distribute linked combinations including + * the two. You must obey the GNU Lesser General Public License in all + * respects for all of the code used other than said providers. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +/** + * This is a rough approximation of an "ispell compatibility mode" + * for Enchant. + * + * Modified in 2007 to work when called from emacs which + * calls a spelling program (e.g. enchant) like this + * + * enchant -a -m -d dictionary + * + * Modified in 2016 to implement most ispell prefix commands. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "enchant.h" +#include "enchant-provider.h" + +/* word has to be bigger than this to be checked */ +#define MIN_WORD_LENGTH 1 + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +static const char *charset; + +typedef enum + { + MODE_NONE, + MODE_VERSION, + MODE_A, + MODE_L + } IspellMode_t; + +static void +print_version (FILE * to) +{ + fprintf (to, "@(#) International Ispell Version 3.1.20 (but really Enchant %s)\n", PACKAGE_VERSION); + fflush (to); +} + +static void +print_help (FILE * to, const char * prog) +{ + fprintf (to, "Usage: %s [options] -a|-d dict|-l|-L|-m|-v[v]|\n", prog); + fprintf (to, "\t-a lists suggestions in ispell pipe mode format.\n"); + fprintf (to, "\t-d dict uses dictionary .\n"); + fprintf (to, "\t-h Show this help message.\n"); + fprintf (to, "\t-l lists misspellings.\n"); + fprintf (to, "\t-m is ignored.\n"); + fprintf (to, "\t-L displays line numbers.\n"); + fprintf (to, "\t-v displays program version.\n"); +} + +static gboolean +consume_line (FILE * in, GString * str) +{ + int ch; + gsize bytes_read, bytes_written; + gchar * utf; + gboolean ret = TRUE; + + g_string_truncate (str, 0); + + while (ret && (ch = fgetc (in)) != EOF) { + if (ch == '\r') + continue; + else { + if (ch == '\n') + ret = FALSE; + else + g_string_append_c (str, ch); + } + } + + if (str->len) { + utf = g_convert(str->str, str->len, "UTF-8", charset, &bytes_read, &bytes_written, NULL); + if (utf) { + g_string_assign (str, utf); + g_free (utf); + } + /* Else str->str stays the same. we'll assume that it's + already utf8 and glib is just being stupid. */ + } + + return ret; +} + +static void +print_utf (FILE * out, const char * str) +{ + gsize bytes_read, bytes_written; + gchar * native; + + native = g_locale_from_utf8 (str, -1, &bytes_read, &bytes_written, NULL); + if (native) { + fwrite (native, 1, bytes_written, out); + g_free (native); + } else { + /* We'll assume that it's already utf8 and glib is just being stupid. */ + fwrite (str, 1, strlen (str), out); + } +} + +static void +do_mode_a (FILE * out, EnchantDict * dict, GString * word, size_t start_pos, size_t lineCount, gboolean terse_mode) +{ + size_t n_suggs; + char ** suggs; + + if (word->len <= MIN_WORD_LENGTH || enchant_dict_check (dict, word->str, word->len) == 0) { + if (!terse_mode) { + if (lineCount) + fprintf (out, "* %u\n", (unsigned int)lineCount); + else + fwrite ("*\n", 1, 2, out); + } + } + else { + suggs = enchant_dict_suggest (dict, word->str, + word->len, &n_suggs); + if (!n_suggs || !suggs) { + fwrite ("# ", 1, 2, out); + if (lineCount) + fprintf (out, "%u ", (unsigned int)lineCount); + print_utf (out, word->str); + fprintf (out, " %u\n", (unsigned int)start_pos); + } + else { + size_t i = 0; + + fwrite ("& ", 1, 2, out); + if (lineCount) + fprintf (out, "%u ", (unsigned int)lineCount); + print_utf (out, word->str); + fprintf (out, " %u %u:", (unsigned int)n_suggs, (unsigned int)start_pos); + + for (i = 0; i < n_suggs; i++) { + fprintf (out, " "); + print_utf (out, suggs[i]); + + if (i != (n_suggs - 1)) + fwrite (",", 1, 1, out); + else + fwrite ("\n", 1, 1, out); + } + + enchant_dict_free_string_list (dict, suggs); + } + } +} + +static void +do_mode_l (FILE * out, EnchantDict * dict, GString * word, size_t lineCount) +{ + if (enchant_dict_check (dict, word->str, word->len) != 0) { + if (lineCount) + fprintf (out, "%u ", (unsigned int)lineCount); + print_utf (out, word->str); + fwrite ("\n", 1, 1, out); + } +} + + +static int +is_word_char (gunichar uc, size_t n) +{ + GUnicodeType type; + + if (uc == g_utf8_get_char("'") || uc == g_utf8_get_char("’")) { + return 1; + } + + type = g_unichar_type(uc); + + switch (type) { + case G_UNICODE_MODIFIER_LETTER: + case G_UNICODE_LOWERCASE_LETTER: + case G_UNICODE_TITLECASE_LETTER: + case G_UNICODE_UPPERCASE_LETTER: + case G_UNICODE_OTHER_LETTER: + case G_UNICODE_COMBINING_MARK: /* Older name for G_UNICODE_SPACING_MARK; deprecated since glib 2.30 */ + case G_UNICODE_ENCLOSING_MARK: + case G_UNICODE_NON_SPACING_MARK: + case G_UNICODE_DECIMAL_NUMBER: + case G_UNICODE_LETTER_NUMBER: + case G_UNICODE_OTHER_NUMBER: + case G_UNICODE_CONNECT_PUNCTUATION: + return 1; /* Enchant 1.3.0 defines word chars like this. */ + + case G_UNICODE_DASH_PUNCTUATION: + if ((n > 0) && (type == G_UNICODE_DASH_PUNCTUATION)) { + return 1; /* hyphens only accepted within a word. */ + } + /* Fallthrough */ + + case G_UNICODE_CONTROL: + case G_UNICODE_FORMAT: + case G_UNICODE_UNASSIGNED: + case G_UNICODE_PRIVATE_USE: + case G_UNICODE_SURROGATE: + case G_UNICODE_CLOSE_PUNCTUATION: + case G_UNICODE_FINAL_PUNCTUATION: + case G_UNICODE_INITIAL_PUNCTUATION: + case G_UNICODE_OTHER_PUNCTUATION: + case G_UNICODE_OPEN_PUNCTUATION: + case G_UNICODE_CURRENCY_SYMBOL: + case G_UNICODE_MODIFIER_SYMBOL: + case G_UNICODE_MATH_SYMBOL: + case G_UNICODE_OTHER_SYMBOL: + case G_UNICODE_LINE_SEPARATOR: + case G_UNICODE_PARAGRAPH_SEPARATOR: + case G_UNICODE_SPACE_SEPARATOR: + default: + return 0; + } +} + + +typedef struct lang_map { + const char *ispell; + const char *enchant; +} LangMap; + + +/* Maps ispell language codes to enchant language codes. */ +/* The list is partially taken from src/ispell/ispell_checker.cpp. */ +static const LangMap lingua[] = { + {"american", "en_US"}, + {"brazilian", "pt_BR"}, + {"british", "en_GB"}, + {"bulgarian", "bg"}, + {"catala", "ca"}, + {"catalan", "ca"}, + {"danish", "da"}, + {"dansk", "da"}, + {"deutsch", "de"}, + {"dutch", "nl"}, + {"ellhnika", "el"}, + {"espanol", "es"}, + {"esperanto", "eo"}, + {"estonian", "et"}, + {"faeroese", "fo"}, + {"finnish", "fi"}, + {"francais", "fr"}, + {"french", "fr"}, + {"galician", "gl"}, + {"german", "de"}, + {"hungarian", "hu"}, + {"interlingua", "ia"}, + {"irish", "ga"}, + {"italian", "it"}, + {"latin", "la"}, + {"lietuviu", "lt"}, + {"lithuanian", "lt"}, + {"mlatin", "la"}, + {"nederlands", "nl"}, + {"norsk", "no"}, + {"norwegian", "no"}, + {"nynorsk", "nn"}, + {"polish", "pl"}, + {"portugues", "pt"}, + {"portuguese", "pt"}, + {"russian", "ru"}, + {"sardinian", "sc"}, + {"slovak", "sk"}, + {"slovenian", "sl"}, + {"slovensko", "sl"}, + {"spanish", "es"}, + {"suomi", "fi"}, /* For Emacs/Voikko/tmispell compatibility. */ + {"svenska", "sv"}, + {"swedish", "sv"}, + {"swiss", "de_CH"}, + {"ukrainian", "uk"}, + {"yiddish-yivo", "yi"}, + {NULL, NULL} /* Last item must be {NULL, NULL}. */ +}; + + +/* Converts ispell language code to enchant language code. */ +static gchar * +convert_language_code (gchar *code) +{ + size_t i; + for (i = 0; lingua[i].ispell; i++) { + if (!strcmp(code,lingua[i].ispell)) { + /* We must call g_strdup() because the calling program g_free()s the result. */ + return g_strdup (lingua[i].enchant); + } + } + /* Let's call g_strdup() here too! */ + return g_strdup (code); +} + + +/* Splits a line into a set of (word,word_position) tuples. */ +static GSList * +tokenize_line (GString * line) +{ + GSList * tokens = NULL; + char *utf = (char *) line->str; + + GString * word; + + gunichar uc; + size_t cur_pos = 0; + size_t start_pos = 0; + word = g_string_new (NULL); + + while (cur_pos < line->len && *utf) { + int i; + + /* Skip non-word characters. */ + cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); + uc = g_utf8_get_char (utf); + while (cur_pos < line->len && *utf && !is_word_char(uc,0)) { + utf = g_utf8_next_char (utf); + uc = g_utf8_get_char (utf); + cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); + } + start_pos = cur_pos; + + /* Skip over word. */ + while (cur_pos < line->len && *utf && is_word_char(uc,1)) { + g_string_append_unichar (word, uc); + utf = g_utf8_next_char (utf); + uc = g_utf8_get_char (utf); + cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); + } + + /* Do not accept one or more ' at the end of the word. */ + i = word->len-1; + while ((i >= 0) && (word->str[i] == '\'')) { + g_string_truncate (word, i); + i--; + } + + /* Save (word, position) tuple. */ + if (word->len) { + tokens = g_slist_append (tokens, g_string_new_len (word->str, word->len)); + tokens = g_slist_append (tokens, GINT_TO_POINTER(start_pos)); + g_string_truncate (word, 0); + } + } + g_string_free (word, TRUE); + + return tokens; +} + +static int +parse_file (FILE * in, FILE * out, IspellMode_t mode, int countLines, gchar *dictionary) +{ + EnchantBroker * broker; + EnchantDict * dict; + + GString * str, * word = NULL; + GSList * tokens, *token_ptr; + gchar * lang; + size_t pos, lineCount = 0; + + gboolean was_last_line = FALSE, corrected_something = FALSE, terse_mode = FALSE; + + if (mode == MODE_A) + print_version (out); + + if (dictionary) { + lang = convert_language_code (dictionary); + } + else { + lang = enchant_get_user_language(); + if(!lang) + return 1; + } + + /* Enchant will get rid of useless trailing garbage like de_DE@euro or de_DE.ISO-8859-15 */ + + broker = enchant_broker_init (); + dict = enchant_broker_request_dict (broker, lang); + + if (!dict) { + fprintf (stderr, "Couldn't create a dictionary for %s\n", lang); + g_free (lang); + enchant_broker_free (broker); + return 1; + } + + g_free (lang); + + str = g_string_new (NULL); + + while (!was_last_line) { + gboolean mode_A_no_command = FALSE; + was_last_line = consume_line (in, str); + + if (countLines) + lineCount++; + + if (str->len) { + corrected_something = FALSE; + + if (mode == MODE_A) { + switch (*str->str) { + case '&': /* Insert uncapitalised in personal word list */ + if (str->len > 1) { + gunichar c = g_utf8_get_char_validated(str->str + 1, str->len); + if (c > 0) { + str = g_string_erase(str, 1, g_utf8_next_char(str->str + 1) - (str->str + 1)); + g_string_insert_unichar(str, 1, g_unichar_tolower(c)); + } + } + /* FALLTHROUGH */ + case '*': /* Insert in personal word list */ + if (str->len == 1) + goto empty_word; + enchant_dict_add(dict, str->str + 1, -1); + break; + case '@': /* Accept for this session */ + if (str->len == 1) + goto empty_word; + enchant_dict_add_to_session(dict, str->str + 1, -1); + break; + + case '%': /* Exit terse mode */ + terse_mode = FALSE; + break; + case '!': /* Enter terse mode */ + terse_mode = TRUE; + break; + + /* Ignore these commands */ + case '#': /* Save personal word list (enchant does this automatically) */ + case '+': /* LaTeX mode */ + case '-': /* nroff mode [default] */ + case '~': /* change string character type (enchant is fixed to UTF-8) */ + case '`': /* Enter verbose-correction mode */ + break; + + case '$': /* Save correction for rest of session [aspell extension] */ + { /* Syntax: $$ra , */ + const gchar *prefix = "$$ra "; + if (g_str_has_prefix(str->str, prefix)) { + gchar *comma = g_utf8_strchr(str->str, -1, (gunichar)','); + char *mis = str->str + strlen(prefix); + char *cor = comma + 1; + ssize_t mis_len = comma - mis; + ssize_t cor_len = strlen(str->str) - (cor - str->str); + enchant_dict_store_replacement(dict, mis, mis_len, cor, cor_len); + } + } + break; + + case '^': /* ^ is used as prefix to prevent interpretation of original + first character as a command */ + /* FALLTHROUGH */ + default: /* A word or words to check */ + mode_A_no_command = TRUE; + break; + + empty_word: + fprintf (out, "Error: The word \"\" is invalid. Empty string.\n"); + } + } + + if (mode != MODE_A || mode_A_no_command) { + token_ptr = tokens = tokenize_line (str); + if (tokens == NULL) + putc('\n', out); + while (tokens != NULL) { + corrected_something = TRUE; + + word = (GString *)tokens->data; + tokens = tokens->next; + pos = GPOINTER_TO_INT(tokens->data); + tokens = tokens->next; + + if (mode == MODE_A) + do_mode_a (out, dict, word, pos, lineCount, terse_mode); + else if (mode == MODE_L) + do_mode_l (out, dict, word, lineCount); + + g_string_free(word, TRUE); + } + if (token_ptr) + g_slist_free (token_ptr); + } + } + + if (mode == MODE_A && corrected_something) { + fwrite ("\n", 1, 1, out); + } + g_string_truncate (str, 0); + fflush (out); + } + + enchant_broker_free_dict (broker, dict); + enchant_broker_free (broker); + + g_string_free (str, TRUE); + + return 0; +} + +int main (int argc, char ** argv) +{ + IspellMode_t mode = MODE_NONE; + + char * file = NULL; + int i, rval = 0; + + FILE * fp = stdin; + + int countLines = 0; + gchar *dictionary = 0; /* -d dictionary */ + + /* Initialize system locale */ + setlocale(LC_ALL, ""); + + g_get_charset(&charset); +#ifdef WIN32 + /* If reading from stdin, its CP may not be the system CP (which glib's locale gives us) */ + if (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR) { + charset = g_strdup_printf("CP%u", GetConsoleCP()); + } +#endif + + for (i = 1; i < argc; i++) { + char * arg = argv[i]; + if (arg[0] == '-') { + if (strlen (arg) == 2) { + /* It seems that the first one of these that is specified gets precedence. */ + if (arg[1] == 'a' && MODE_NONE == mode) + mode = MODE_A; + else if (arg[1] == 'l' && MODE_NONE == mode) + mode = MODE_L; + else if (arg[1] == 'v' && MODE_NONE == mode) + mode = MODE_VERSION; + else if (arg[1] == 'L' && MODE_NONE == mode) + countLines = 1; + else if (arg[1] == 'm') + ; /* Ignore. Emacs calls ispell with '-m'. */ + else if (arg[1] == 'd') { + i++; + dictionary = argv[i]; /* Emacs calls ispell with '-d dictionary'. */ + } + } + else if ((strlen (arg) == 3) && (arg[1] == 'v') && (arg[2] == 'v')) { + mode = MODE_VERSION; /* Emacs (or ispell.el) calls [ai]spell with '-vv'. */ + } + else if (arg[1] == 'd') { + dictionary = arg + 2; /* Accept "-ddictionary", i.e. no space between -d and dictionary. */ + } + else if (strlen (arg) > 2) { + fprintf (stderr, "-%c does not take any parameters.\n", arg[1]); + exit(1); + } + else + file = arg; + } + else + file = arg; + } + + if (mode == MODE_VERSION) { + print_version (stdout); + } + else if (mode == MODE_NONE && !file) { + print_help (stdout, argv[0]); + } + else { + if (file) { + fp = g_fopen (file, "rb"); + if (!fp) { + fprintf (stderr, "Error: Could not open the file \"%s\" for reading.\n", file); + exit (1); + } + } + + rval = parse_file (fp, stdout, mode, countLines, dictionary); + + if (file) + fclose (fp); + } + + return rval; +} diff --git a/src/enchant-lsmod.c b/src/enchant-lsmod.c new file mode 100644 index 0000000..6ed3f4f --- /dev/null +++ b/src/enchant-lsmod.c @@ -0,0 +1,139 @@ +/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* enchant + * Copyright (C) 2003 Dom Lachowicz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, Dom Lachowicz + * gives permission to link the code of this program with + * the non-LGPL Spelling Provider libraries (eg: a MSFT Office + * spell checker backend) and distribute linked combinations including + * the two. You must obey the GNU Lesser General Public License in all + * respects for all of the code used other than said providers. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "enchant.h" +#include "enchant-provider.h" + +static void +describe_dict (const char * const lang_tag, + const char * const provider_name, + const char * const provider_desc, + const char * const provider_file, + void * user_data) +{ + FILE * out = (FILE *)user_data; + fprintf (out, "%s (%s)\n", lang_tag, provider_name); +} + +static void +enumerate_providers (const char * name, + const char * desc, + const char * file, + void * user_data) +{ + FILE * out = (FILE *)user_data; + fprintf (out, "%s (%s)\n", name, desc); +} + +static void +enumerate_dicts (const char * const lang_tag, + const char * const provider_name, + const char * const provider_desc, + const char * const provider_file, + void * user_data) +{ + FILE * out = (FILE *)user_data; + fprintf (out, "%s (%s)\n", lang_tag, provider_name); +} + +int +main (int argc, char **argv) +{ + EnchantBroker *broker; + EnchantDict *dict; + char * lang_tag = NULL; + + int mode = 0, i; + + for (i = 1; i < argc; i++) { + if (!strcmp (argv[i], "-lang")) { + if (i < (argc - 1)) { + lang_tag = g_strdup (argv[++i]); + } else { + lang_tag = enchant_get_user_language(); + + if (!lang_tag || !strcmp (lang_tag, "C")) { + g_free(lang_tag); /* lang might be "C" */ + lang_tag = g_strdup ("en"); + } + } + mode = 1; + } else if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "-?") || !strcmp(argv[i], "-help")) { + printf ("%s [-lang [language_tag]] [-list-dicts] [-h] [-v]\n", argv[0]); + g_free (lang_tag); + return 0; + } else if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "-version")) { + printf ("%s %s\n", argv[0], PACKAGE_VERSION); + g_free (lang_tag); + return 0; + } else if (!strcmp (argv[i], "-list-dicts")) { + mode = 2; + } + } + + broker = enchant_broker_init (); + + if (mode == 0) { + enchant_broker_describe (broker, enumerate_providers, stdout); + } else if (mode == 1) { + + if (!lang_tag) { + printf ("Error: language tag not specified and environment variable $LANG not set.\n"); + enchant_broker_free (broker); + return 1; + } + + dict = enchant_broker_request_dict (broker, lang_tag); + + if (!dict) { + printf ("No dictionary available for '%s'.\n", lang_tag); + g_free (lang_tag); + enchant_broker_free (broker); + return 1; + } else { + enchant_dict_describe (dict, describe_dict, stdout); + enchant_broker_free_dict (broker, dict); + } + } else if (mode == 2) { + enchant_broker_list_dicts (broker, enumerate_dicts, stdout); + } + + g_free (lang_tag); + enchant_broker_free (broker); + + return 0; +} diff --git a/tests/.gitignore b/tests/.gitignore index b6b3a4d..25d92cc 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,7 +1,3 @@ -/enchant -/enchant.exe -/enchant-lsmod -/enchant-lsmod.exe /ispell /enchant.test /enchant.test.exe diff --git a/tests/Makefile.am b/tests/Makefile.am index aeef1fd..139f963 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -19,10 +19,8 @@ EXTRA_DIST = test.pwl.orig ispell.in LDADD = $(top_builddir)/src/libenchant.la $(ENCHANT_LIBS) check_PROGRAMS = enchant.test enchantxx.test -bin_PROGRAMS = enchant-lsmod enchant enchant_test_SOURCES = enchant.test.c -enchant_SOURCES = enchant-ispell.c enchantxx_test_SOURCES = enchantxx.test.cpp TESTS = $(check_PROGRAMS) diff --git a/tests/enchant-ispell.c b/tests/enchant-ispell.c deleted file mode 100644 index e3ff922..0000000 --- a/tests/enchant-ispell.c +++ /dev/null @@ -1,625 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* enchant - * Copyright (C) 2003 Dom Lachowicz - * 2007 Hannu Väisänen - * 2016 Reuben Thomas - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, Dom Lachowicz - * gives permission to link the code of this program with - * the non-LGPL Spelling Provider libraries (eg: a MSFT Office - * spell checker backend) and distribute linked combinations including - * the two. You must obey the GNU Lesser General Public License in all - * respects for all of the code used other than said providers. If you modify - * this file, you may extend this exception to your version of the - * file, but you are not obligated to do so. If you do not wish to - * do so, delete this exception statement from your version. - */ - -/** - * This is a rough approximation of an "ispell compatibility mode" - * for Enchant. - * - * Modified in 2007 to work when called from emacs which - * calls a spelling program (e.g. enchant) like this - * - * enchant -a -m -d dictionary - * - * Modified in 2016 to implement most ispell prefix commands. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "enchant.h" -#include "enchant-provider.h" - -/* word has to be bigger than this to be checked */ -#define MIN_WORD_LENGTH 1 - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#endif - -static const char *charset; - -typedef enum - { - MODE_NONE, - MODE_VERSION, - MODE_A, - MODE_L - } IspellMode_t; - -static void -print_version (FILE * to) -{ - fprintf (to, "@(#) International Ispell Version 3.1.20 (but really Enchant %s)\n", PACKAGE_VERSION); - fflush (to); -} - -static void -print_help (FILE * to, const char * prog) -{ - fprintf (to, "Usage: %s [options] -a|-d dict|-l|-L|-m|-v[v]|\n", prog); - fprintf (to, "\t-a lists suggestions in ispell pipe mode format.\n"); - fprintf (to, "\t-d dict uses dictionary .\n"); - fprintf (to, "\t-h Show this help message.\n"); - fprintf (to, "\t-l lists misspellings.\n"); - fprintf (to, "\t-m is ignored.\n"); - fprintf (to, "\t-L displays line numbers.\n"); - fprintf (to, "\t-v displays program version.\n"); -} - -static gboolean -consume_line (FILE * in, GString * str) -{ - int ch; - gsize bytes_read, bytes_written; - gchar * utf; - gboolean ret = TRUE; - - g_string_truncate (str, 0); - - while (ret && (ch = fgetc (in)) != EOF) { - if (ch == '\r') - continue; - else { - if (ch == '\n') - ret = FALSE; - else - g_string_append_c (str, ch); - } - } - - if (str->len) { - utf = g_convert(str->str, str->len, "UTF-8", charset, &bytes_read, &bytes_written, NULL); - if (utf) { - g_string_assign (str, utf); - g_free (utf); - } - /* Else str->str stays the same. we'll assume that it's - already utf8 and glib is just being stupid. */ - } - - return ret; -} - -static void -print_utf (FILE * out, const char * str) -{ - gsize bytes_read, bytes_written; - gchar * native; - - native = g_locale_from_utf8 (str, -1, &bytes_read, &bytes_written, NULL); - if (native) { - fwrite (native, 1, bytes_written, out); - g_free (native); - } else { - /* We'll assume that it's already utf8 and glib is just being stupid. */ - fwrite (str, 1, strlen (str), out); - } -} - -static void -do_mode_a (FILE * out, EnchantDict * dict, GString * word, size_t start_pos, size_t lineCount, gboolean terse_mode) -{ - size_t n_suggs; - char ** suggs; - - if (word->len <= MIN_WORD_LENGTH || enchant_dict_check (dict, word->str, word->len) == 0) { - if (!terse_mode) { - if (lineCount) - fprintf (out, "* %u\n", (unsigned int)lineCount); - else - fwrite ("*\n", 1, 2, out); - } - } - else { - suggs = enchant_dict_suggest (dict, word->str, - word->len, &n_suggs); - if (!n_suggs || !suggs) { - fwrite ("# ", 1, 2, out); - if (lineCount) - fprintf (out, "%u ", (unsigned int)lineCount); - print_utf (out, word->str); - fprintf (out, " %u\n", (unsigned int)start_pos); - } - else { - size_t i = 0; - - fwrite ("& ", 1, 2, out); - if (lineCount) - fprintf (out, "%u ", (unsigned int)lineCount); - print_utf (out, word->str); - fprintf (out, " %u %u:", (unsigned int)n_suggs, (unsigned int)start_pos); - - for (i = 0; i < n_suggs; i++) { - fprintf (out, " "); - print_utf (out, suggs[i]); - - if (i != (n_suggs - 1)) - fwrite (",", 1, 1, out); - else - fwrite ("\n", 1, 1, out); - } - - enchant_dict_free_string_list (dict, suggs); - } - } -} - -static void -do_mode_l (FILE * out, EnchantDict * dict, GString * word, size_t lineCount) -{ - if (enchant_dict_check (dict, word->str, word->len) != 0) { - if (lineCount) - fprintf (out, "%u ", (unsigned int)lineCount); - print_utf (out, word->str); - fwrite ("\n", 1, 1, out); - } -} - - -static int -is_word_char (gunichar uc, size_t n) -{ - GUnicodeType type; - - if (uc == g_utf8_get_char("'") || uc == g_utf8_get_char("’")) { - return 1; - } - - type = g_unichar_type(uc); - - switch (type) { - case G_UNICODE_MODIFIER_LETTER: - case G_UNICODE_LOWERCASE_LETTER: - case G_UNICODE_TITLECASE_LETTER: - case G_UNICODE_UPPERCASE_LETTER: - case G_UNICODE_OTHER_LETTER: - case G_UNICODE_COMBINING_MARK: /* Older name for G_UNICODE_SPACING_MARK; deprecated since glib 2.30 */ - case G_UNICODE_ENCLOSING_MARK: - case G_UNICODE_NON_SPACING_MARK: - case G_UNICODE_DECIMAL_NUMBER: - case G_UNICODE_LETTER_NUMBER: - case G_UNICODE_OTHER_NUMBER: - case G_UNICODE_CONNECT_PUNCTUATION: - return 1; /* Enchant 1.3.0 defines word chars like this. */ - - case G_UNICODE_DASH_PUNCTUATION: - if ((n > 0) && (type == G_UNICODE_DASH_PUNCTUATION)) { - return 1; /* hyphens only accepted within a word. */ - } - /* Fallthrough */ - - case G_UNICODE_CONTROL: - case G_UNICODE_FORMAT: - case G_UNICODE_UNASSIGNED: - case G_UNICODE_PRIVATE_USE: - case G_UNICODE_SURROGATE: - case G_UNICODE_CLOSE_PUNCTUATION: - case G_UNICODE_FINAL_PUNCTUATION: - case G_UNICODE_INITIAL_PUNCTUATION: - case G_UNICODE_OTHER_PUNCTUATION: - case G_UNICODE_OPEN_PUNCTUATION: - case G_UNICODE_CURRENCY_SYMBOL: - case G_UNICODE_MODIFIER_SYMBOL: - case G_UNICODE_MATH_SYMBOL: - case G_UNICODE_OTHER_SYMBOL: - case G_UNICODE_LINE_SEPARATOR: - case G_UNICODE_PARAGRAPH_SEPARATOR: - case G_UNICODE_SPACE_SEPARATOR: - default: - return 0; - } -} - - -typedef struct lang_map { - const char *ispell; - const char *enchant; -} LangMap; - - -/* Maps ispell language codes to enchant language codes. */ -/* The list is partially taken from src/ispell/ispell_checker.cpp. */ -static const LangMap lingua[] = { - {"american", "en_US"}, - {"brazilian", "pt_BR"}, - {"british", "en_GB"}, - {"bulgarian", "bg"}, - {"catala", "ca"}, - {"catalan", "ca"}, - {"danish", "da"}, - {"dansk", "da"}, - {"deutsch", "de"}, - {"dutch", "nl"}, - {"ellhnika", "el"}, - {"espanol", "es"}, - {"esperanto", "eo"}, - {"estonian", "et"}, - {"faeroese", "fo"}, - {"finnish", "fi"}, - {"francais", "fr"}, - {"french", "fr"}, - {"galician", "gl"}, - {"german", "de"}, - {"hungarian", "hu"}, - {"interlingua", "ia"}, - {"irish", "ga"}, - {"italian", "it"}, - {"latin", "la"}, - {"lietuviu", "lt"}, - {"lithuanian", "lt"}, - {"mlatin", "la"}, - {"nederlands", "nl"}, - {"norsk", "no"}, - {"norwegian", "no"}, - {"nynorsk", "nn"}, - {"polish", "pl"}, - {"portugues", "pt"}, - {"portuguese", "pt"}, - {"russian", "ru"}, - {"sardinian", "sc"}, - {"slovak", "sk"}, - {"slovenian", "sl"}, - {"slovensko", "sl"}, - {"spanish", "es"}, - {"suomi", "fi"}, /* For Emacs/Voikko/tmispell compatibility. */ - {"svenska", "sv"}, - {"swedish", "sv"}, - {"swiss", "de_CH"}, - {"ukrainian", "uk"}, - {"yiddish-yivo", "yi"}, - {NULL, NULL} /* Last item must be {NULL, NULL}. */ -}; - - -/* Converts ispell language code to enchant language code. */ -static gchar * -convert_language_code (gchar *code) -{ - size_t i; - for (i = 0; lingua[i].ispell; i++) { - if (!strcmp(code,lingua[i].ispell)) { - /* We must call g_strdup() because the calling program g_free()s the result. */ - return g_strdup (lingua[i].enchant); - } - } - /* Let's call g_strdup() here too! */ - return g_strdup (code); -} - - -/* Splits a line into a set of (word,word_position) tuples. */ -static GSList * -tokenize_line (GString * line) -{ - GSList * tokens = NULL; - char *utf = (char *) line->str; - - GString * word; - - gunichar uc; - size_t cur_pos = 0; - size_t start_pos = 0; - word = g_string_new (NULL); - - while (cur_pos < line->len && *utf) { - int i; - - /* Skip non-word characters. */ - cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); - uc = g_utf8_get_char (utf); - while (cur_pos < line->len && *utf && !is_word_char(uc,0)) { - utf = g_utf8_next_char (utf); - uc = g_utf8_get_char (utf); - cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); - } - start_pos = cur_pos; - - /* Skip over word. */ - while (cur_pos < line->len && *utf && is_word_char(uc,1)) { - g_string_append_unichar (word, uc); - utf = g_utf8_next_char (utf); - uc = g_utf8_get_char (utf); - cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf); - } - - /* Do not accept one or more ' at the end of the word. */ - i = word->len-1; - while ((i >= 0) && (word->str[i] == '\'')) { - g_string_truncate (word, i); - i--; - } - - /* Save (word, position) tuple. */ - if (word->len) { - tokens = g_slist_append (tokens, g_string_new_len (word->str, word->len)); - tokens = g_slist_append (tokens, GINT_TO_POINTER(start_pos)); - g_string_truncate (word, 0); - } - } - g_string_free (word, TRUE); - - return tokens; -} - -static int -parse_file (FILE * in, FILE * out, IspellMode_t mode, int countLines, gchar *dictionary) -{ - EnchantBroker * broker; - EnchantDict * dict; - - GString * str, * word = NULL; - GSList * tokens, *token_ptr; - gchar * lang; - size_t pos, lineCount = 0; - - gboolean was_last_line = FALSE, corrected_something = FALSE, terse_mode = FALSE; - - if (mode == MODE_A) - print_version (out); - - if (dictionary) { - lang = convert_language_code (dictionary); - } - else { - lang = enchant_get_user_language(); - if(!lang) - return 1; - } - - /* Enchant will get rid of useless trailing garbage like de_DE@euro or de_DE.ISO-8859-15 */ - - broker = enchant_broker_init (); - dict = enchant_broker_request_dict (broker, lang); - - if (!dict) { - fprintf (stderr, "Couldn't create a dictionary for %s\n", lang); - g_free (lang); - enchant_broker_free (broker); - return 1; - } - - g_free (lang); - - str = g_string_new (NULL); - - while (!was_last_line) { - gboolean mode_A_no_command = FALSE; - was_last_line = consume_line (in, str); - - if (countLines) - lineCount++; - - if (str->len) { - corrected_something = FALSE; - - if (mode == MODE_A) { - switch (*str->str) { - case '&': /* Insert uncapitalised in personal word list */ - if (str->len > 1) { - gunichar c = g_utf8_get_char_validated(str->str + 1, str->len); - if (c > 0) { - str = g_string_erase(str, 1, g_utf8_next_char(str->str + 1) - (str->str + 1)); - g_string_insert_unichar(str, 1, g_unichar_tolower(c)); - } - } - /* FALLTHROUGH */ - case '*': /* Insert in personal word list */ - if (str->len == 1) - goto empty_word; - enchant_dict_add(dict, str->str + 1, -1); - break; - case '@': /* Accept for this session */ - if (str->len == 1) - goto empty_word; - enchant_dict_add_to_session(dict, str->str + 1, -1); - break; - - case '%': /* Exit terse mode */ - terse_mode = FALSE; - break; - case '!': /* Enter terse mode */ - terse_mode = TRUE; - break; - - /* Ignore these commands */ - case '#': /* Save personal word list (enchant does this automatically) */ - case '+': /* LaTeX mode */ - case '-': /* nroff mode [default] */ - case '~': /* change string character type (enchant is fixed to UTF-8) */ - case '`': /* Enter verbose-correction mode */ - break; - - case '$': /* Save correction for rest of session [aspell extension] */ - { /* Syntax: $$ra , */ - gchar *prefix = "$$ra "; - if (g_str_has_prefix(str->str, prefix)) { - gchar *comma = g_utf8_strchr(str->str, -1, (gunichar)','); - char *mis = str->str + strlen(prefix); - char *cor = comma + 1; - ssize_t mis_len = comma - mis; - ssize_t cor_len = strlen(str->str) - (cor - str->str); - enchant_dict_store_replacement(dict, mis, mis_len, cor, cor_len); - } - } - break; - - case '^': /* ^ is used as prefix to prevent interpretation of original - first character as a command */ - /* FALLTHROUGH */ - default: /* A word or words to check */ - mode_A_no_command = TRUE; - break; - - empty_word: - fprintf (out, "Error: The word \"\" is invalid. Empty string.\n"); - } - } - - if (mode != MODE_A || mode_A_no_command) { - token_ptr = tokens = tokenize_line (str); - if (tokens == NULL) - putc('\n', out); - while (tokens != NULL) { - corrected_something = TRUE; - - word = (GString *)tokens->data; - tokens = tokens->next; - pos = GPOINTER_TO_INT(tokens->data); - tokens = tokens->next; - - if (mode == MODE_A) - do_mode_a (out, dict, word, pos, lineCount, terse_mode); - else if (mode == MODE_L) - do_mode_l (out, dict, word, lineCount); - - g_string_free(word, TRUE); - } - if (token_ptr) - g_slist_free (token_ptr); - } - } - - if (mode == MODE_A && corrected_something) { - fwrite ("\n", 1, 1, out); - } - g_string_truncate (str, 0); - fflush (out); - } - - enchant_broker_free_dict (broker, dict); - enchant_broker_free (broker); - - g_string_free (str, TRUE); - - return 0; -} - -int main (int argc, char ** argv) -{ - IspellMode_t mode = MODE_NONE; - - char * file = NULL; - int i, rval = 0; - - FILE * fp = stdin; - - int countLines = 0; - gchar *dictionary = 0; /* -d dictionary */ - - /* Initialize system locale */ - setlocale(LC_ALL, ""); - - g_get_charset(&charset); -#ifdef WIN32 - /* If reading from stdin, its CP may not be the system CP (which glib's locale gives us) */ - if (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR) { - charset = g_strdup_printf("CP%u", GetConsoleCP()); - } -#endif - - for (i = 1; i < argc; i++) { - char * arg = argv[i]; - if (arg[0] == '-') { - if (strlen (arg) == 2) { - /* It seems that the first one of these that is specified gets precedence. */ - if (arg[1] == 'a' && MODE_NONE == mode) - mode = MODE_A; - else if (arg[1] == 'l' && MODE_NONE == mode) - mode = MODE_L; - else if (arg[1] == 'v' && MODE_NONE == mode) - mode = MODE_VERSION; - else if (arg[1] == 'L' && MODE_NONE == mode) - countLines = 1; - else if (arg[1] == 'm') - ; /* Ignore. Emacs calls ispell with '-m'. */ - else if (arg[1] == 'd') { - i++; - dictionary = argv[i]; /* Emacs calls ispell with '-d dictionary'. */ - } - } - else if ((strlen (arg) == 3) && (arg[1] == 'v') && (arg[2] == 'v')) { - mode = MODE_VERSION; /* Emacs (or ispell.el) calls [ai]spell with '-vv'. */ - } - else if (arg[1] == 'd') { - dictionary = arg + 2; /* Accept "-ddictionary", i.e. no space between -d and dictionary. */ - } - else if (strlen (arg) > 2) { - fprintf (stderr, "-%c does not take any parameters.\n", arg[1]); - exit(1); - } - else - file = arg; - } - else - file = arg; - } - - if (mode == MODE_VERSION) { - print_version (stdout); - } - else if (mode == MODE_NONE && !file) { - print_help (stdout, argv[0]); - } - else { - if (file) { - fp = g_fopen (file, "rb"); - if (!fp) { - fprintf (stderr, "Error: Could not open the file \"%s\" for reading.\n", file); - exit (1); - } - } - - rval = parse_file (fp, stdout, mode, countLines, dictionary); - - if (file) - fclose (fp); - } - - return rval; -} diff --git a/tests/enchant-lsmod.c b/tests/enchant-lsmod.c deleted file mode 100644 index 6ed3f4f..0000000 --- a/tests/enchant-lsmod.c +++ /dev/null @@ -1,139 +0,0 @@ -/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* enchant - * Copyright (C) 2003 Dom Lachowicz - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02110-1301, USA. - * - * In addition, as a special exception, Dom Lachowicz - * gives permission to link the code of this program with - * the non-LGPL Spelling Provider libraries (eg: a MSFT Office - * spell checker backend) and distribute linked combinations including - * the two. You must obey the GNU Lesser General Public License in all - * respects for all of the code used other than said providers. If you modify - * this file, you may extend this exception to your version of the - * file, but you are not obligated to do so. If you do not wish to - * do so, delete this exception statement from your version. - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "enchant.h" -#include "enchant-provider.h" - -static void -describe_dict (const char * const lang_tag, - const char * const provider_name, - const char * const provider_desc, - const char * const provider_file, - void * user_data) -{ - FILE * out = (FILE *)user_data; - fprintf (out, "%s (%s)\n", lang_tag, provider_name); -} - -static void -enumerate_providers (const char * name, - const char * desc, - const char * file, - void * user_data) -{ - FILE * out = (FILE *)user_data; - fprintf (out, "%s (%s)\n", name, desc); -} - -static void -enumerate_dicts (const char * const lang_tag, - const char * const provider_name, - const char * const provider_desc, - const char * const provider_file, - void * user_data) -{ - FILE * out = (FILE *)user_data; - fprintf (out, "%s (%s)\n", lang_tag, provider_name); -} - -int -main (int argc, char **argv) -{ - EnchantBroker *broker; - EnchantDict *dict; - char * lang_tag = NULL; - - int mode = 0, i; - - for (i = 1; i < argc; i++) { - if (!strcmp (argv[i], "-lang")) { - if (i < (argc - 1)) { - lang_tag = g_strdup (argv[++i]); - } else { - lang_tag = enchant_get_user_language(); - - if (!lang_tag || !strcmp (lang_tag, "C")) { - g_free(lang_tag); /* lang might be "C" */ - lang_tag = g_strdup ("en"); - } - } - mode = 1; - } else if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "-?") || !strcmp(argv[i], "-help")) { - printf ("%s [-lang [language_tag]] [-list-dicts] [-h] [-v]\n", argv[0]); - g_free (lang_tag); - return 0; - } else if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "-version")) { - printf ("%s %s\n", argv[0], PACKAGE_VERSION); - g_free (lang_tag); - return 0; - } else if (!strcmp (argv[i], "-list-dicts")) { - mode = 2; - } - } - - broker = enchant_broker_init (); - - if (mode == 0) { - enchant_broker_describe (broker, enumerate_providers, stdout); - } else if (mode == 1) { - - if (!lang_tag) { - printf ("Error: language tag not specified and environment variable $LANG not set.\n"); - enchant_broker_free (broker); - return 1; - } - - dict = enchant_broker_request_dict (broker, lang_tag); - - if (!dict) { - printf ("No dictionary available for '%s'.\n", lang_tag); - g_free (lang_tag); - enchant_broker_free (broker); - return 1; - } else { - enchant_dict_describe (dict, describe_dict, stdout); - enchant_broker_free_dict (broker, dict); - } - } else if (mode == 2) { - enchant_broker_list_dicts (broker, enumerate_dicts, stdout); - } - - g_free (lang_tag); - enchant_broker_free (broker); - - return 0; -} -- cgit v1.2.1