[voikko] enchant diff 17.8.2007
Hannu Väisänen
hannu.vaisanen at joensuu.fi
Fri Aug 17 14:33:57 EEST 2007
On Fri, Aug 17, 2007 at 11:57:47AM +0300, Harri Pitkänen wrote:
> Lähettämäsi liite näyttää olevan itsessään oikein, mutta sähköpostiohjelmasi
> merkitsee sille väärän koodauksen, joka sotkee asioita ainakin luettaessa
> viestiä Kmailin avulla:
> | Content-Type: text/plain; charset=iso-8859-1
Jokohan se vaihtui utf-8:ksi?
> > Mistä löytyisi lista tarvittavista muunnoksista?
>
> Debianissa
> $ apt-cache search ispell-dictionary
> iamerican - An American English dictionary for ispell
> ibrazilian - Brazilian Portuguese dictionary for ispell
Toivottavasti nämä eivät ole erilaisia joka jakelussa.
Muuten, jonkinlainen muunnoslista on myös enchantin mukana tulevassa
ispellissä tiedostossa src/ispell/ispell_checker.cpp, mutta
kun sitä ei saa sieltä ulos...
Liitteenä on uusin diffi.
-------------- next part --------------
--- enchant/tests/enchant-ispell.c 2007-08-15 07:12:04.000000000 +0300
+++ enchant-hv/tests/enchant-ispell.c 2007-08-17 14:27:46.000000000 +0300
@@ -1,6 +1,7 @@
/* 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
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -31,6 +32,11 @@
/**
* 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
*/
#include <stdio.h>
@@ -44,6 +50,10 @@
/* word has to be bigger than this to be checked */
#define MIN_WORD_LENGTH 1
+/* -d dictionary */
+gchar *dictionary = 0;
+
+
typedef enum
{
MODE_NONE,
@@ -56,16 +66,20 @@
print_version (FILE * to)
{
fprintf (to, "@(#) International Ispell Version 3.1.20 (but really Enchant %s)\n", VERSION);
+ fflush (to);
}
static void
print_help (FILE * to, const char * prog)
{
- fprintf (to, "Usage: %s [options] -a|-l|-L|-v[v]|<file>\n", prog);
+ fprintf (to, "Usage: %s [options] -a|-d dict|-l|-L|-m|-v[v]|<file>\n", prog);
fprintf (to, "\t-a lists alternatives.\n");
+ fprintf (to, "\t-d dict uses dictionary <dict>.\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");
+ fflush (to);
}
static gboolean
@@ -95,8 +109,8 @@
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 */
+ /* Else str->str stays the same. we'll assume that it's
+ already utf8 and glib is just being stupid. */
}
return ret;
@@ -113,9 +127,10 @@
fwrite (native, 1, bytes_written, out);
g_free (native);
} else {
- /* we'll assume that it's already utf8 and glib is just being stupid */
+ /* We'll assume that it's already utf8 and glib is just being stupid. */
fwrite (str, 1, strlen (str), out);
}
+ fflush (out);
}
static void
@@ -124,11 +139,13 @@
size_t n_suggs;
char ** suggs;
- if (word->len <= MIN_WORD_LENGTH || enchant_dict_check (dict, word->str, word->len) == 0)
+ if (word->len <= MIN_WORD_LENGTH || enchant_dict_check (dict, word->str, word->len) == 0) {
if (lineCount)
fprintf (out, "* %ld\n", lineCount);
else
fwrite ("*\n", 1, 2, out);
+ fflush (out);
+ }
else {
suggs = enchant_dict_suggest (dict, word->str,
word->len, &n_suggs);
@@ -137,7 +154,8 @@
if (lineCount)
fprintf (out, "%ld ", lineCount);
print_utf (out, word->str);
- fprintf (out, " %ld\n", start_pos+1);
+ fprintf (out, " %ld\n", start_pos);
+ fflush (out);
}
else {
size_t i = 0;
@@ -157,6 +175,7 @@
else
fwrite ("\n", 1, 1, out);
}
+ fflush (out);
enchant_dict_free_string_list (dict, suggs);
}
@@ -171,64 +190,117 @@
fprintf (out, "%ld ", lineCount);
print_utf (out, word->str);
fwrite ("\n", 1, 1, out);
+ fflush (out);
+ }
+}
+
+
+static int
+is_word_char (gunichar uc, size_t n)
+{
+ switch (g_unichar_type(uc)) {
+ 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:
+ 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. */
+ default:
+ if ((n > 0) && (uc == g_utf8_get_char("'"))) {
+ return 1; /** Char ' is accepted only within a word. */
+ }
+ return 0;
+ }
+}
+
+
+typedef struct lang_map {
+ char *ispell;
+ char *enchant;
+} LangMap;
+
+
+/* Maps ispell language codes to enchant language codes. */
+/* This list is incomplete. */
+static const LangMap lingua[] = {
+ {"american", "en_US"},
+ {"british", "en_GB"},
+ {"finnish", "fi"},
+ {"suomi", "fi"}, /* For Voikko/tmispell compatibility. */
+ {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);
+ }
}
+ return code;
}
-/* splits a line into a set of (word,word_position) touples */
+
+/* Splits a line into a set of (word,word_position) touples. */
static GSList *
tokenize_line (GString * line)
{
GSList * tokens = NULL;
- size_t start_pos, cur_pos;
char *utf = (char *) line->str;
GString * word;
gunichar uc;
-
- start_pos = cur_pos = 0;
+ size_t cur_pos = 0;
+ size_t start_pos = 0;
word = g_string_new (NULL);
while (cur_pos < line->len && *utf) {
- uc = g_utf8_get_char (utf);
-
- switch (g_unichar_type(uc)) {
- 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:
- 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:
+
+ /* 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);
- cur_pos++;
- break;
- case G_UNICODE_OTHER_PUNCTUATION:
- if (uc == '\'') {
- g_string_append_unichar (word, uc);
- cur_pos++;
- break;
- }
- /* else fall through */
- default: /* some sort of non-word character */
- 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);
- start_pos = ++cur_pos;
- }
- break;
+ utf = g_utf8_next_char (utf);
+ uc = g_utf8_get_char (utf);
+ cur_pos = g_utf8_pointer_to_offset ((const char*)line->str, utf);
}
- utf = g_utf8_next_char (utf);
- }
+ /* Do not accept one or more ' at the end of the word. */
+ int i = word->len-1;
+ while ((i >= 0) && (word->str[i] == '\'')) {
+ g_string_truncate (word, i);
+ i--;
+ }
+
+ /* Save (word, position) touple. */
+ 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;
@@ -250,9 +322,14 @@
if (mode == MODE_A)
print_version (out);
- lang = enchant_get_user_language();
- if(!lang)
- return 1;
+ 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 at euro or de_DE.ISO-8859-15 */
@@ -261,6 +338,7 @@
if (!dict) {
fprintf (stderr, "Couldn't create a dictionary for %s\n", lang);
+ fflush (stderr);
g_free (lang);
enchant_broker_free (broker);
return 1;
@@ -277,7 +355,6 @@
lineCount++;
if (str->len) {
-
corrected_something = FALSE;
token_ptr = tokens = tokenize_line (str);
while (tokens != NULL) {
@@ -298,9 +375,10 @@
g_slist_free (token_ptr);
}
- if (mode == MODE_A && corrected_something)
+ if (mode == MODE_A && corrected_something) {
fwrite ("\n", 1, 1, out);
-
+ fflush (out);
+ }
g_string_truncate (str, 0);
}
@@ -329,7 +407,7 @@
char * arg = argv[i];
if (arg[0] == '-') {
if (strlen (arg) == 2) {
- /* it seems that the first one of these that is specified gets precedence */
+ /* 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)
@@ -338,7 +416,19 @@
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);
More information about the voikko
mailing list