diff options
Diffstat (limited to 'src/tools/hunspell.cxx')
-rw-r--r-- | src/tools/hunspell.cxx | 1785 |
1 files changed, 1785 insertions, 0 deletions
diff --git a/src/tools/hunspell.cxx b/src/tools/hunspell.cxx new file mode 100644 index 0000000..07ad6bb --- /dev/null +++ b/src/tools/hunspell.cxx @@ -0,0 +1,1785 @@ +// glibc < 3.0 (for mkstemp) +#ifndef __USE_MISC +#define __USE_MISC +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "config.h" +#include "hunspell.hxx" +#include "csutil.hxx" + +#ifndef HUNSPELL_EXTRA +#define suggest_auto suggest +#endif + +#define HUNSPELL_VERSION VERSION +#define INPUTLEN 50 + +#define HUNSPELL_PIPE_HEADING "@(#) International Ispell Version 3.2.06 (but really Hunspell "VERSION")\n" +#define HUNSPELL_HEADING "Hunspell " + +//for debugging only +//#define LOG + +#define DEFAULTDICNAME "default" + +#ifdef WIN32 + +#define LIBDIR "C:\\Hunspell\\" +#define USEROOODIR "Application Data\\OpenOffice.org 2\\user\\wordbook" +#define OOODIR \ + "C:\\Program files\\OpenOffice.org 2.4\\share\\dict\\ooo\\;" \ + "C:\\Program files\\OpenOffice.org 2.3\\share\\dict\\ooo\\;" \ + "C:\\Program files\\OpenOffice.org 2.2\\share\\dict\\ooo\\;" \ + "C:\\Program files\\OpenOffice.org 2.1\\share\\dict\\ooo\\;" \ + "C:\\Program files\\OpenOffice.org 2.0\\share\\dict\\ooo\\" +#define HOME "%USERPROFILE%\\" +#define DICBASENAME "hunspell_" +#define LOGFILE "C:\\Hunspell\\log" +#define DIRSEPCH '\\' +#define DIRSEP "\\" +#define PATHSEP ";" + +#include "textparser.hxx" +#include "htmlparser.hxx" +#include "latexparser.hxx" +#include "manparser.hxx" +#include "firstparser.hxx" + +#else + +// Not Windows +#include <sys/types.h> +#include <dirent.h> +#include <unistd.h> +#include "textparser.hxx" +#include "htmlparser.hxx" +#include "latexparser.hxx" +#include "manparser.hxx" +#include "firstparser.hxx" + +#define LIBDIR \ + "/usr/share/hunspell:" \ + "/usr/share/myspell:" \ + "/usr/share/myspell/dicts:" \ + "/Library/Spelling" +#define USEROOODIR \ + ".openoffice.org/3/user/wordbook:" \ + ".openoffice.org2/user/wordbook:" \ + ".openoffice.org2.0/user/wordbook:" \ + "Library/Spelling" +#define OOODIR \ + "/opt/openoffice.org/basis3.0/share/dict/ooo:" \ + "/usr/lib/openoffice.org/basis3.0/share/dict/ooo:" \ + "/opt/openoffice.org2.4/share/dict/ooo:" \ + "/usr/lib/openoffice.org2.4/share/dict/ooo:" \ + "/opt/openoffice.org2.3/share/dict/ooo:" \ + "/usr/lib/openoffice.org2.3/share/dict/ooo:" \ + "/opt/openoffice.org2.2/share/dict/ooo:" \ + "/usr/lib/openoffice.org2.2/share/dict/ooo:" \ + "/opt/openoffice.org2.1/share/dict/ooo:" \ + "/usr/lib/openoffice.org2.1/share/dict/ooo:" \ + "/opt/openoffice.org2.0/share/dict/ooo:" \ + "/usr/lib/openoffice.org2.0/share/dict/ooo" +#define HOME getenv("HOME") +#define DICBASENAME ".hunspell_" +#define LOGFILE "/tmp/hunspell.log" +#define DIRSEPCH '/' +#define DIRSEP "/" +#define PATHSEP ":" +#endif + +#ifdef HAVE_ICONV +#include <iconv.h> +char text_conv[MAXLNLEN]; +#endif + +#if ENABLE_NLS +# ifdef HAVE_LOCALE_H +# include <locale.h> +# ifdef HAVE_LANGINFO_CODESET +# include <langinfo.h> +# endif +# endif +# ifdef HAVE_LIBINTL_H +# include <libintl.h> +# else +# include <../../intl/libintl.h> +# endif +#else +# define gettext +# undef HAVE_LOCALE_H +# undef HAVE_LIBINTL_H +#endif + +#ifdef HAVE_CURSES_H +#ifdef HAVE_NCURSESW_H +#include <ncurses.h> +#else +#include <curses.h> +#endif +#endif + +#ifdef HAVE_READLINE +#include <readline/readline.h> +#else +#define readline scanline +#endif + +#define TEMPNAME "hunSPELL.bak" + +extern char * mystrdup(const char * s); + +// file formats: + +enum { FMT_TEXT, FMT_LATEX, FMT_HTML, FMT_MAN, FMT_FIRST }; + +struct wordlist { + char * word; + wordlist * next; +}; + +// global variables + +char * wordchars = NULL; +char * dicpath = NULL; +int wordchars_len; +unsigned short * wordchars_utf16 = NULL; +int wordchars_utf16_free = 0; +int wordchars_utf16_len; +char * dicname = NULL; +char * privdicname = NULL; +const char * currentfilename = NULL; + +int modified; // modified file sign +enum { NORMAL, + BADWORD, // print only bad words + WORDFILTER, // print only bad words from 1 word/line input + BADLINE, // print only lines with bad words + STEM, // stem input words + ANALYZE, // analyze input words + PIPE, // print only stars for LyX compatibility + AUTO0, // search typical error (based on SuggestMgr::suggest_auto()) + AUTO, // automatic spelling to standard output + AUTO2, // automatic spelling to standard output with sed log + AUTO3 }; // automatic spelling to standard output with gcc error format +int filter_mode = NORMAL; +int printgood = 0; // print only good words and lines +int showpath = 0; // show detected path of the dictionary +int checkurl = 0; // check URLs and mail addresses +int warn = 0; // warn potential mistakes (dictionary words with WARN flags) +const char * ui_enc = NULL; // locale character encoding (default for I/O) +const char * io_enc = NULL; // I/O character encoding + +#define DMAX 10 // maximal count of loaded dictionaries + +const char * dic_enc[DMAX]; // dictionary encoding +char * path = NULL; +int dmax = 0; // dictionary count + +// functions + +#ifdef HAVE_ICONV +static const char* fix_encoding_name(const char *enc) +{ + if (strcmp(enc, "TIS620-2533") == 0) + enc = "TIS620"; + return enc; +} +#endif + +/* change character encoding */ +char * chenc(char * st, const char * enc1, const char * enc2) { + char * out = st; +#ifdef HAVE_ICONV + if (enc1 && enc2 && strcmp(enc1, enc2) != 0) { + + size_t c1 = strlen(st) + 1; + size_t c2 = MAXLNLEN; + char * source = st; + char * dest = text_conv; + iconv_t conv = iconv_open(fix_encoding_name(enc2), fix_encoding_name(enc1)); + if (conv == (iconv_t) -1) { + fprintf(stderr, gettext("error - iconv_open: %s -> %s\n"), enc2, enc1); + } else { + size_t res = iconv(conv, (ICONV_CONST char **) &source, &c1, &dest, &c2); + iconv_close(conv); + if (res != (size_t) -1) out = text_conv; + } + } +#endif + return out; +} + +TextParser * get_parser(int format, char * extension, Hunspell * pMS) { + TextParser * p = NULL; + int io_utf8 = 0; + char * denc = pMS->get_dic_encoding(); +#ifdef HAVE_ICONV + initialize_utf_tbl(); // also need for 8-bit tokenization + if (io_enc) { + if ((strcmp(io_enc, "UTF-8") == 0) || + (strcmp(io_enc, "utf-8") == 0) || + (strcmp(io_enc, "UTF8") == 0) || + (strcmp(io_enc, "utf8") == 0)) { + io_utf8 = 1; + io_enc = "UTF-8"; + } + } else if (ui_enc) { + io_enc = ui_enc; + if (strcmp(ui_enc, "UTF-8") == 0) io_utf8 = 1; + } else { + io_enc = denc; + if (strcmp(denc, "UTF-8") == 0) io_utf8 = 1; + } + + if (io_utf8) { + wordchars_utf16 = pMS->get_wordchars_utf16(&wordchars_utf16_len); + if ((strcmp(denc, "UTF-8") != 0) && pMS->get_wordchars()) { + char * wchars = (char *) pMS->get_wordchars(); + int wlen = strlen(wchars); + size_t c1 = wlen; + size_t c2 = MAXLNLEN; + char * dest = text_conv; + iconv_t conv = iconv_open("UTF-8", fix_encoding_name(denc)); + if (conv == (iconv_t) -1) { + fprintf(stderr, gettext("error - iconv_open: UTF-8 -> %s\n"), denc); + wordchars_utf16 = NULL; + wordchars_utf16_len = 0; + } else { + iconv(conv, (ICONV_CONST char **) &wchars, &c1, &dest, &c2); + iconv_close(conv); + wordchars_utf16 = (unsigned short *) malloc(sizeof(unsigned short) * wlen); + int n = u8_u16((w_char *) wordchars_utf16, wlen, text_conv); + if (n > 0) flag_qsort(wordchars_utf16, 0, n); + wordchars_utf16_len = n; + wordchars_utf16_free = 1; + } + } + } else { + // 8-bit input encoding + // detect letters by unicodeisalpha() for tokenization + char letters[MAXLNLEN]; + char * pletters = letters; + char ch[2]; + char u8[10]; + *pletters = '\0'; + iconv_t conv = iconv_open("UTF-8", fix_encoding_name(io_enc)); + if (conv == (iconv_t) -1) { + fprintf(stderr, gettext("error - iconv_open: UTF-8 -> %s\n"), io_enc); + } else { + for (int i = 32; i < 256; i++) { + size_t c1 = 1; + size_t c2 = 10; + char * dest = u8; + u8[0] = '\0'; + char * ch8bit = ch; + ch[0] = (char) i; + ch[1] = '\0'; + size_t res = iconv(conv, (ICONV_CONST char **) &ch8bit, &c1, &dest, &c2); + if (res != (size_t) -1) { + unsigned short idx; + w_char w; + w.l = 0; + w.h = 0; + u8_u16(&w, 1, u8); + idx = (w.h << 8) + w.l; + if (unicodeisalpha(idx)) { + *pletters = (char) i; + pletters++; + } + } + } + iconv_close(conv); + } + *pletters = '\0'; + + // UTF-8 wordchars -> 8 bit wordchars + int len = 0; + char * wchars = (char *) pMS->get_wordchars(); + if (wchars) { + if ((strcmp(denc, "UTF-8")==0)) { + pMS->get_wordchars_utf16(&len); + } else { + len = strlen(wchars); + } + char * dest = letters + strlen(letters); // append wordchars + size_t c1 = len + 1; + size_t c2 = len + 1; + iconv_t conv = iconv_open(fix_encoding_name(io_enc), fix_encoding_name(denc)); + if (conv == (iconv_t) -1) { + fprintf(stderr, gettext("error - iconv_open: %s -> %s\n"), io_enc, denc); + } else { + iconv(conv, (ICONV_CONST char **) &wchars, &c1, &dest, &c2); + iconv_close(conv); + *dest = '\0'; + } + } + if (*letters) wordchars = mystrdup(letters); + } +#else + if (strcmp(denc, "UTF-8") == 0) { + wordchars_utf16 = pMS->get_wordchars_utf16(&wordchars_utf16_len); + io_utf8 = 1; + } else { + char * casechars = get_casechars(denc); + wordchars = (char *) pMS->get_wordchars(); + if (casechars && wordchars) { + casechars = (char *) realloc(casechars, strlen(casechars) + strlen(wordchars) + 1); + strcat(casechars, wordchars); + } + wordchars = casechars; + } + io_enc = denc; +#endif + + if (io_utf8) { + switch (format) { + case FMT_LATEX: p = new LaTeXParser(wordchars_utf16, wordchars_utf16_len); break; + case FMT_HTML: p = new HTMLParser(wordchars_utf16, wordchars_utf16_len); break; + case FMT_MAN: p = new ManParser(wordchars_utf16, wordchars_utf16_len); break; + case FMT_FIRST: p = new FirstParser(wordchars); + } + } else { + switch (format) { + case FMT_LATEX: p = new LaTeXParser(wordchars); break; + case FMT_HTML: p = new HTMLParser(wordchars); break; + case FMT_MAN: p = new ManParser(wordchars); break; + case FMT_FIRST: p = new FirstParser(wordchars); + } + } + + if ((!p) && (extension)) { + if ((strcmp(extension, "html") == 0) || + (strcmp(extension, "htm") == 0) || + (strcmp(extension, "xml") == 0)) { + if (io_utf8) { + p = new HTMLParser(wordchars_utf16, wordchars_utf16_len); + } else { + p = new HTMLParser(wordchars); + } + } else if (((extension[0] > '0') && (extension[0] <= '9'))) { + if (io_utf8) { + p = new ManParser(wordchars_utf16, wordchars_utf16_len); + } else { + p = new ManParser(wordchars); + } + } else if ((strcmp(extension, "tex") == 0)) { + if (io_utf8) { + p = new LaTeXParser(wordchars_utf16, wordchars_utf16_len); + } else { + p = new LaTeXParser(wordchars); + } + } + } + if (!p) { + if (io_utf8) { + p = new TextParser(wordchars_utf16, wordchars_utf16_len); + } else { + p = new TextParser(wordchars); + } + } + p->set_url_checking(checkurl); + return p; +} + + +#ifdef LOG +void log(char * message) +{ + FILE *f = fopen(LOGFILE,"a"); + if (f) { + fprintf(f,"%s\n",message); + fclose(f); + } else { + fprintf(stderr,"Logfile..."); + } +} +#endif + +int putdic(char * word, Hunspell * pMS) +{ + char * w; + + word = chenc(word, ui_enc, dic_enc[0]); + + if (((w = strstr(word + 1, "/")) == NULL)) { + if (*word == '*') return pMS->remove(word + 1); + else return pMS->add(word); + } else { + char c; + int ret; + c = *w; + *w = '\0'; + if (*(w+1) == '/') { + ret = pMS->add_with_affix(word, w + 2); // word//pattern (back comp.) + } else { + ret = pMS->add_with_affix(word, w + 1); // word/pattern + } + *w = c; + return ret; + } +} + +void load_privdic(char * filename, Hunspell * pMS) +{ + char buf[MAXLNLEN]; + FILE *dic = fopen(filename,"r"); + if (dic) { + while(fgets(buf,MAXLNLEN,dic)) { + if (*(buf + strlen(buf) - 1) == '\n') *(buf + strlen(buf) - 1) = '\0'; + putdic(buf,pMS); + } + fclose(dic); + } +} + +int exist(char * filename) +{ + FILE *f = fopen(filename,"r"); + if (f) { + fclose(f); + return 1; + } + return 0; +} + +int save_privdic(char * filename, char * filename2, wordlist * w) +{ + wordlist * r; + FILE *dic = fopen(filename,"r"); + if (dic) { + fclose(dic); + dic = fopen(filename,"a"); + } else { + dic = fopen(filename2,"a"); + } + if (! dic) return 0; + while (w != NULL) { + char *word = chenc(w->word, io_enc, ui_enc); + fprintf(dic,"%s\n",word); +#ifdef LOG + log(word);log("\n"); +#endif + r = w; + free(w->word); + w = w->next; + free(r); + } + fclose(dic); + return 1; +} + +char * basename(char * s, char c) { + char * p = s + strlen(s); + while ((*p != c) && (p != s)) p--; + if (*p == c) p++; + return p; +} + +#ifdef HAVE_CURSES_H +char * scanline(char * message) { + char input[INPUTLEN]; + printw(message); + echo(); + getnstr(input, INPUTLEN); + noecho(); + return mystrdup(input); +} +#endif + +// check words in the dictionaries (and set first checked dictionary) +int check(Hunspell ** pMS, int * d, char * token, int * info, char ** root) { + for (int i = 0; i < dmax; i++) { + if (pMS[*d]->spell(chenc(token, io_enc, dic_enc[*d]), info, root) && !(warn && (*info & SPELL_WARN))) { + return 1; + } + if (++(*d) == dmax) *d = 0; + } + return 0; +} + +void pipe_interface(Hunspell ** pMS, int format, FILE * fileid) { + char buf[MAXLNLEN]; + char * buf2; + wordlist * dicwords = NULL; + char * token; + int pos; + int bad; + int lineno = 0; + int terse_mode = 0; + int verbose_mode = 0; + int d = 0; + + TextParser * parser = get_parser(format, NULL, pMS[0]); + + if ((filter_mode == NORMAL)) { + fprintf(stdout,gettext(HUNSPELL_HEADING)); + fprintf(stdout,HUNSPELL_VERSION); + if (pMS[0]->get_version()) fprintf(stdout," - %s", pMS[0]->get_version()); + fprintf(stdout,"\n"); + fflush(stdout); + } + +nextline: while(fgets(buf, MAXLNLEN, fileid)) { + if (*(buf + strlen(buf) - 1) == '\n') *(buf + strlen(buf) - 1) = '\0'; + lineno++; +#ifdef LOG + log(buf); +#endif + bad = 0; + pos = 0; + + // execute commands + if (filter_mode == PIPE) { + pos = -1; + switch (buf[0]) { + case '%': { verbose_mode = terse_mode = 0; break; } + case '!': { terse_mode = 1; break; } + case '`': { verbose_mode = 1; break; } + case '+': { + delete parser; + parser = get_parser(FMT_LATEX, NULL, pMS[0]); + parser->set_url_checking(checkurl); + break; + } + case '-': { + delete parser; + parser = get_parser(format, NULL, pMS[0]); + break; + } + case '@': { putdic(buf+1, pMS[d]); break; } + case '*': { + struct wordlist* i = + (struct wordlist *) malloc (sizeof(struct wordlist)); + i->word = mystrdup(buf+1); + i->next = dicwords; + dicwords = i; + putdic(buf+1, pMS[d]); + break; + } + case '#': { + if (HOME) strcpy(buf,HOME); else { + fprintf(stderr, gettext("error - missing HOME variable\n")); + continue; + } +#ifndef WIN32 + strcat(buf,"/"); +#endif + buf2 = buf+strlen(buf); + if (!privdicname) { + strcat(buf,DICBASENAME); + strcat(buf,basename(dicname,DIRSEPCH)); + } else { + strcat(buf,privdicname); + } + if (save_privdic(buf2, buf, dicwords)) { + dicwords=NULL; + } + break; + } + case '^': { + pos = 1; + } + + default: { + pos = 0; + } + + } // end switch + } // end filter_mode == PIPE + +if (pos >= 0) { + parser->put_line(buf + pos); + while ((token = parser->next_token())) { + switch (filter_mode) { + + case BADWORD: { + if (!check(pMS, &d, token, NULL, NULL)) { + bad = 1; + if (! printgood) fprintf(stdout,"%s\n", token); + } else { + if (printgood) fprintf(stdout,"%s\n", token); + } + free(token); + continue; + } + + case WORDFILTER: { + if (!check(pMS, &d, token, NULL, NULL)) { + bad = 1; + if (! printgood) fprintf(stdout,"%s\n", buf); + } else { + if (printgood) fprintf(stdout,"%s\n", buf); + } + free(token); + goto nextline; + } + + case BADLINE: { + if (!check(pMS, &d, token, NULL, NULL)) { + bad = 1; + } + free(token); + continue; + } + + case AUTO0: + case AUTO: + case AUTO2: + case AUTO3: { + FILE * f = (filter_mode == AUTO) ? stderr : stdout; + if (!check(pMS, &d, token, NULL, NULL)) { + char ** wlst = NULL; + bad = 1; + int ns = pMS[d]->suggest_auto(&wlst, chenc(token, io_enc, dic_enc[d])); + if (ns > 0) { + parser->change_token(chenc(wlst[0], dic_enc[d], io_enc)); + if (filter_mode == AUTO3) { + fprintf(f,"%s:%d: Locate: %s | Try: %s\n", + currentfilename, lineno, + token, chenc(wlst[0], dic_enc[d], io_enc)); + } else if (filter_mode == AUTO2) { + fprintf(f,"%ds/%s/%s/g; # %s\n", lineno, + token, chenc(wlst[0], dic_enc[d], io_enc), buf); + } else { + fprintf(f,gettext("Line %d: %s -> "), lineno, + chenc(token, io_enc, ui_enc)); + fprintf(f, "%s\n", + chenc(wlst[0], dic_enc[d], ui_enc)); + } + } + pMS[d]->free_list(&wlst, ns); + } + free(token); + continue; + } + + case STEM: { + char ** result; + int n = pMS[d]->stem(&result, chenc(token, io_enc, dic_enc[d])); + for (int i = 0; i < n; i++) { + fprintf(stdout, "%s %s\n", token, chenc(result[i], dic_enc[d], ui_enc)); + } + pMS[d]->free_list(&result, n); + if (n == 0 && token[strlen(token) - 1] == '.') { + token[strlen(token) - 1] = '\0'; + n = pMS[d]->stem(&result, token); + for (int i = 0; i < n; i++) { + fprintf(stdout, "%s %s\n", token, chenc(result[i], dic_enc[d], ui_enc)); + } + pMS[d]->free_list(&result, n); + } + if (n == 0) fprintf(stdout, "%s\n", chenc(token, dic_enc[d], ui_enc)); + fprintf(stdout, "\n"); + free(token); + continue; + } + + case ANALYZE: { + char ** result; + int n = pMS[d]->analyze(&result, chenc(token, io_enc, dic_enc[d])); + for (int i = 0; i < n; i++) { + fprintf(stdout, "%s %s\n", token, chenc(result[i], dic_enc[d], ui_enc)); + } + pMS[d]->free_list(&result, n); + if (n == 0 && token[strlen(token) - 1] == '.') { + token[strlen(token) - 1] = '\0'; + n = pMS[d]->analyze(&result, token); + for (int i = 0; i < n; i++) { + fprintf(stdout, "%s %s\n", token, chenc(result[i], dic_enc[d], ui_enc)); + } + pMS[d]->free_list(&result, n); + } + if (n == 0) fprintf(stdout, "%s\n", chenc(token, dic_enc[d], ui_enc)); + fprintf(stdout, "\n"); + free(token); + continue; + } + + case PIPE: { + int info; + char * root = NULL; + if (check(pMS, &d, token, &info, &root)) { + if (!terse_mode) { + if (verbose_mode) fprintf(stdout,"* %s\n", token); + else fprintf(stdout,"*\n"); + } + fflush(stdout); + } else { + char ** wlst = NULL; + int ns = pMS[d]->suggest(&wlst, token); + if (ns == 0) { + fprintf(stdout,"# %s %d", token, + parser->get_tokenpos() + pos); + } else { + fprintf(stdout,"& %s %d %d: ", token, ns, + parser->get_tokenpos() + pos); + fprintf(stdout,"%s", chenc(wlst[0], dic_enc[d], io_enc)); + } + for (int j = 1; j < ns; j++) { + fprintf(stdout, ", %s", chenc(wlst[j], dic_enc[d], io_enc)); + } + pMS[d]->free_list(&wlst, ns); + fprintf(stdout, "\n"); + fflush(stdout); + } + if (root) free(root); + free(token); + continue; + } + case NORMAL: { + int info; + char * root = NULL; + if (check(pMS, &d, token, &info, &root)) { + if (info & SPELL_COMPOUND) { + fprintf(stdout,"-\n"); + } else if (root) { + fprintf(stdout,"+ %s\n", chenc(root, dic_enc[d], ui_enc)); + } else { + fprintf(stdout,"*\n"); + } + fflush(stdout); + if (root) free(root); + } else { + char ** wlst = NULL; + int ns = pMS[d]->suggest(&wlst, chenc(token, io_enc, dic_enc[d])); + if (ns == 0) { + fprintf(stdout,"# %s %d", chenc(token, io_enc, ui_enc), + parser->get_tokenpos() + pos); + } else { + fprintf(stdout,"& %s %d %d: ", chenc(token, io_enc, ui_enc), ns, + parser->get_tokenpos() + pos); + fprintf(stdout,"%s", chenc(wlst[0], dic_enc[d], ui_enc)); + } + for (int j = 1; j < ns; j++) { + fprintf(stdout, ", %s", chenc(wlst[j], dic_enc[d], ui_enc)); + } + pMS[d]->free_list(&wlst, ns); + fprintf(stdout, "\n"); + fflush(stdout); + } + free(token); + } + } + } + + switch (filter_mode) { + case AUTO: { + fprintf(stdout,"%s\n", parser->get_line()); + break; + } + + case BADLINE: { + if (((printgood) && (!bad)) || + (!printgood && (bad))) fprintf(stdout,"%s\n",buf); + break; + } + + case PIPE: + case NORMAL: { + fprintf(stdout,"\n"); + fflush(stdout); + break; + } + + } +} // if +} // while + +if (parser) delete(parser); + +} // pipe_interface + +#ifdef HAVE_READLINE + +#ifdef HAVE_CURSES_H +static const char * rltext; + +// set base text of input line +static int set_rltext () +{ + if (rltext) + { + rl_insert_text (rltext); + rltext = NULL; + rl_startup_hook = (rl_hook_func_t *)NULL; + } + return 0; +} + +#endif + +// Readline escape +static int rl_escape (int count, int key) +{ + rl_delete_text(0, rl_end); + rl_done = 1; + return 0; +} +#endif + +#ifdef HAVE_CURSES_H +int expand_tab(char * dest, char * src, int limit) { + int i = 0; + int u8 = ((ui_enc != NULL) && (strcmp(ui_enc, "UTF-8") == 0)) ? 1 : 0; + int chpos = 0; + for(int j = 0; (i < limit) && (src[j] != '\0') && (src[j] != '\r'); j++) { + dest[i] = src[j]; + if (src[j] == '\t') { + int end = 8 - (chpos % 8); + for(int k = 0; k < end; k++) { + dest[i] = ' '; + i++; + chpos++; + } + } else { + i++; + if (!u8 || (src[j] & 0xc0) != 0x80) chpos++; + } + } + dest[i] = '\0'; + return chpos; +} + +// UTF-8-aware version of strncpy (but output is always null terminated) +// What we should deal in is cursor position cells in a terminal emulator, +// i.e. the number of visual columns occupied like wcwidth/wcswidth does +// What we're really current doing is to deal in the number of characters, +// like mbstowcs which isn't quite correct, but close enough for western +// text in UTF-8 +void strncpyu8(char * dest, const char * src, int begin, int n) { + int u8 = ((ui_enc != NULL) && (strcmp(ui_enc, "UTF-8") == 0)) ? 1 : 0; + int i = 0; + while (i < begin + n) { + if (i >= begin) + { + if (!*src) + break; + *dest++ = *src; + } + if (!u8 || (*src & 0xc0) != 0x80) + i++; + ++src; + } + *dest = '\0'; +} + +//See strncpyu8 for gotchas +int strlenu8(const char * src) { + int u8 = ((ui_enc != NULL) && (strcmp(ui_enc, "UTF-8") == 0)) ? 1 : 0; + int i = 0; + while (*src) { + if (!u8 || (*src & 0xc0) != 0x80) + i++; + ++src; + } + return i; +} + +void dialogscreen(TextParser * parser, char * token, + char * filename, int forbidden, char ** wlst, int ns) { + int x, y; + char line[MAXLNLEN]; + char line2[MAXLNLEN]; + getmaxyx(stdscr,y,x); + clear(); + + if (forbidden & SPELL_FORBIDDEN) printw(gettext("FORBIDDEN!")); else + if (forbidden & SPELL_WARN) printw(gettext("Spelling mistake?")); + printw(gettext("\t%s\t\tFile: %s\n\n"), chenc(token, io_enc, ui_enc), filename); + + // handle long lines and tabulators + + char lines[MAXPREVLINE][MAXLNLEN]; + + for (int i = 0; i < MAXPREVLINE; i++) { + expand_tab(lines[i], chenc(parser->get_prevline(i), io_enc, ui_enc), MAXLNLEN); + } + + int prevline = 0; + + strncpy(line, parser->get_prevline(0), parser->get_tokenpos()); + line[parser->get_tokenpos()] = '\0'; + int tokenbeg = expand_tab(line2, chenc(line, io_enc, ui_enc), MAXLNLEN); + + strncpy(line, parser->get_prevline(0), parser->get_tokenpos() + strlen(token)); + line[parser->get_tokenpos() + strlen(token)] = '\0'; + int tokenend = expand_tab(line2, chenc(line, io_enc, ui_enc), MAXLNLEN); + + int rowindex = tokenend / x; + int beginrow = rowindex - tokenbeg / x; + if (beginrow >= MAXPREVLINE) beginrow = MAXPREVLINE - 1; + + for (int i = 0; i < MAXPREVLINE; i++) { + strncpyu8(line, lines[prevline], x * rowindex, x); + mvprintw(MAXPREVLINE + 1 - i, 0, "%s", line); + rowindex--; + if (rowindex == -1) { + prevline++; + rowindex = strlenu8(lines[prevline]) / x; + } + } + + int linestartpos = tokenbeg - (tokenbeg % x); + strncpyu8(line, lines[0], x * rowindex + linestartpos, tokenbeg % x); + mvprintw(MAXPREVLINE + 1 - beginrow, 0, "%s", line); + attron(A_REVERSE); + printw("%s", chenc(token, io_enc, ui_enc)); + attroff(A_REVERSE); + + mvprintw(MAXPREVLINE + 2, 0, "\n"); + for (int i = 0; i < ns; i++) { + if ((ns > 10) && (i < 10)) { + printw(" 0%d: %s\n", i, chenc(wlst[i], io_enc, ui_enc)); + } else { + printw(" %d: %s\n", i, chenc(wlst[i], io_enc, ui_enc)); + } + } + +/* TRANSLATORS: the capital letters are shortcuts, mark one letter similarly + in your translation and translate the standalone letter accordingly later */ + mvprintw(y-3, 0, "%s\n", + gettext("\n[SPACE] R)epl A)ccept I)nsert U)ncap S)tem Q)uit e(X)it or ? for help\n")); +} + +char * lower_first_char(char *token, const char *io_enc, int langnum) +{ + const char *utf8str = chenc(token, io_enc, "UTF-8"); + int max = strlen(utf8str); + w_char *u = new w_char[max]; + int len = u8_u16(u, max, utf8str); + unsigned short idx = (u[0].h << 8) + u[0].l; + idx = unicodetolower(idx, langnum); + u[0].h = (unsigned char) (idx >> 8); + u[0].l = (unsigned char) (idx & 0x00FF); + char *scratch = (char*)malloc(max + 1 + 4); + u16_u8(scratch, max+4, u, len); + delete[] u; + char *result = chenc(scratch, "UTF-8", io_enc); + if (result != scratch) + { + free (scratch); + result = mystrdup(result); + } + return result; +} + + // for terminal interface +int dialog(TextParser * parser, Hunspell * pMS, char * token, char * filename, + char ** wlst, int ns, int forbidden) { + char buf[MAXLNLEN]; + char * buf2; + wordlist * dicwords = NULL; + int c; + + dialogscreen(parser, token, filename, forbidden, wlst, ns); + + char firstletter='\0'; + + while ((c=getch())) { + switch (c) { + case '0': + case '1': if ((firstletter=='\0') && (ns>10)) { + firstletter=c; + break; + } + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + modified=1; + if ((firstletter!='\0') && (firstletter=='1')) { + c += 10; + } + c -= '0'; + if (c>=ns) break; + parser->change_token(wlst[c]); + goto ki; + } + case ' ': { + goto ki; + } + case '?': { + clear(); +printw(gettext("Whenever a word is found that is not in the dictionary\n" + "it is printed on the first line of the screen. If the dictionary\n" + "contains any similar words, they are listed with a number\n" + "next to each one. You have the option of replacing the word\n" + "completely, or choosing one of the suggested words.\n")); +printw(gettext("\nCommands are:\n\n")); +printw(gettext("R Replace the misspelled word completely.\n")); +printw(gettext("Space Accept the word this time only.\n")); +printw(gettext("A Accept the word for the rest of this session.\n")); +printw(gettext("I Accept the word, and put it in your private dictionary.\n")); +printw(gettext("U Accept and add lowercase version to private dictionary.\n")); +printw(gettext( +"S\tAsk a stem and a model word and store them in the private dictionary.\n" +"\tThe stem will be accepted also with the affixes of the model word.\n" +)); +printw(gettext("0-n Replace with one of the suggested words.\n")); +printw(gettext("X Write the rest of this file, ignoring misspellings, and start next file.\n")); +printw(gettext("Q Quit immediately. Asks for confirmation. Leaves file unchanged.\n")); +printw(gettext("^Z Suspend program. Restart with fg command.\n")); +printw(gettext("? Show this help screen.\n")); +printw(gettext("\n-- Type space to continue -- \n")); + while (getch()!=' '); + } + case 12: { + dialogscreen(parser, token, filename, forbidden, wlst, ns); + break; + } + default: { +/* TRANSLATORS: translate this letter according to the shortcut letter used + previously in the translation of "R)epl" before */ + if (c==(gettext("r"))[0]) { + char i[MAXLNLEN]; + char *temp; + + modified=1; + + +#ifdef HAVE_READLINE + endwin(); + rltext = ""; + if (rltext && *rltext) rl_startup_hook = set_rltext; +#endif + temp = readline(gettext("Replace with: ")); +#ifdef HAVE_READLINE + initscr(); + cbreak(); +#endif + + if ((!temp) || (temp[0] == '\0')) { + free(temp); + dialogscreen(parser, token, filename, forbidden, wlst, ns); + break; + } + + strncpy(i, temp, MAXLNLEN); + free(temp); + + parser->change_token(i); + + return 2; // replace + } +/* TRANSLATORS: translate these letters according to the shortcut letter used + previously in the translation of "U)ncap" and I)nsert before */ + int u_key = gettext("u")[0]; + int i_key = gettext("i")[0]; + + if (c==u_key || c==i_key) { + struct wordlist* i = (struct wordlist *) malloc (sizeof(struct wordlist)); + i->word = (c==i_key) ? mystrdup(token) : lower_first_char(token, io_enc, pMS->get_langnum()); + i->next = dicwords; + dicwords = i; + // save + if (HOME) strcpy(buf,HOME); else { + fprintf(stderr, gettext("error - missing HOME variable\n")); + break; + } +#ifndef WIN32 + strcat(buf,"/"); +#endif + buf2 = buf+strlen(buf); + if (!privdicname) { + strcat(buf,DICBASENAME); + strcat(buf,basename(dicname,DIRSEPCH)); + } else { + strcat(buf,privdicname); + } + if (save_privdic(buf2, buf, dicwords)) { + dicwords=NULL; + } else { + fprintf(stderr,gettext("Cannot update personal dictionary.")); + break; + } + } // no break +/* TRANSLATORS: translate this letter according to the shortcut letter used + previously in the translation of "U)ncap" and I)nsert before */ + if ((c==(gettext("u"))[0]) || (c==(gettext("i"))[0]) || (c==(gettext("a"))[0])) { + modified=1; + putdic(token, pMS); + goto ki; + } +/* TRANSLATORS: translate this letter according to the shortcut letter used + previously in the translation of "S)tem" before */ + if (c==(gettext("s"))[0]) { + modified=1; + + char w[MAXLNLEN], w2[MAXLNLEN], w3[MAXLNLEN]; + char *temp; + + strncpy(w, token, MAXLNLEN); + temp = basename(w, '-'); + if (w < temp) { + *(temp-1) = '\0'; + } else { + char ** poslst = NULL; +#ifdef HUNSPELL_EXPERIMENTAL + int ps = pMS->suggest_pos_stems(&poslst, token); +#else + int ps = 0; +#endif + if (ps > 0) { + strcpy(buf, poslst[0]); + for (int i = 0; i < ps; i++) { + if (strlen(poslst[i]) <= strlen(buf)) strcpy(buf, poslst[i]); + free(poslst[i]); + } + strcpy(w, buf); + } + if (poslst) free(poslst); + } + +#ifdef HAVE_READLINE + endwin(); + rltext = w; + if (rltext && *rltext) rl_startup_hook = set_rltext; +#endif + temp = readline(gettext("New word (stem): ")); + + if ((!temp) || (temp[0] == '\0')) { + free(temp); +#ifdef HAVE_READLINE + initscr(); + cbreak(); +#endif + dialogscreen(parser, token, filename, forbidden, wlst, ns); + break; + } + + strncpy(w, temp, MAXLNLEN); + free(temp); + +#ifdef HAVE_READLINE + initscr(); + cbreak(); +#endif + dialogscreen(parser, token, filename, forbidden, wlst, ns); + refresh(); + +#ifdef HAVE_READLINE + endwin(); + rltext = ""; + if (rltext && *rltext) rl_startup_hook = set_rltext; +#endif + temp = readline(gettext("Model word (a similar dictionary word): ")); + +#ifdef HAVE_READLINE + initscr(); + cbreak(); +#endif + + if ((!temp) || (temp[0] == '\0')) { + free(temp); + dialogscreen(parser, token, filename, forbidden, wlst, ns); + break; + } + + strncpy(w2, temp, MAXLNLEN); + free(temp); + + if (strlen(w) + strlen(w2) + 2 < MAXLNLEN) { + sprintf(w3, "%s/%s", w, w2); + } else break; + + if (!putdic(w3, pMS)) { + + struct wordlist* i = + (struct wordlist *) malloc (sizeof(struct wordlist)); + i->word = mystrdup(w3); + i->next = dicwords; + dicwords = i; + + if (strlen(w) + strlen(w2) + 4 < MAXLNLEN) { + sprintf(w3, "%s-/%s-", w, w2); + if (putdic(w3, pMS)) { + struct wordlist* i = + (struct wordlist *) malloc (sizeof(struct wordlist)); + i->word = mystrdup(w3); + i->next = dicwords; + dicwords = i; + } + } + // save + + if (HOME) strcpy(buf,HOME); else { + fprintf(stderr, gettext("error - missing HOME variable\n")); + continue; + } +#ifndef WIN32 + strcat(buf,"/"); +#endif + buf2 = buf + strlen(buf); + if (!privdicname) { + strcat(buf,DICBASENAME); + strcat(buf,basename(dicname,DIRSEPCH)); + } else { + strcat(buf,privdicname); + } + if (save_privdic(buf2, buf, dicwords)) { + dicwords = NULL; + } else { + fprintf(stderr, gettext("Cannot update personal dictionary.")); + break; + } + + } else { + dialogscreen(parser, token, filename, forbidden, wlst, ns); + printw(gettext("Model word must be in the dictionary. Press any key!")); + getch(); + dialogscreen(parser, token, filename, forbidden, wlst, ns); + break; + } + goto ki; + } +/* TRANSLATORS: translate this letter according to the shortcut letter used + previously in the translation of "e(X)it" before */ + if (c==(gettext("x"))[0]) { + return 1; + } +/* TRANSLATORS: translate this letter according to the shortcut letter used + previously in the translation of "Q)uit" before */ + if (c==(gettext("q"))[0]) { + if (modified) { + printw(gettext("Are you sure you want to throw away your changes? ")); +/* TRANSLATORS: translate this letter according to the shortcut letter y)es */ + if (getch()==(gettext("y"))[0]) return -1; + dialogscreen(parser, token, filename, forbidden, wlst, ns); + break; + } else { + return -1; + } + } + } + } + } + ki: return 0; +} + +int interactive_line(TextParser * parser, Hunspell ** pMS, char * filename, FILE * tempfile) +{ + char * token; + int dialogexit = 0; + int info; + int d = 0; + while ((token=parser->next_token())) { + if (!check(pMS, &d, token, &info, NULL)) { + dialogscreen(parser, token, filename, info, NULL, 0); // preview + refresh(); + char ** wlst = NULL; + int ns = pMS[d]->suggest(&wlst, chenc(token, io_enc, dic_enc[d])); + if (ns==0) { + dialogexit = dialog(parser, pMS[d], token, filename, wlst, ns, info); + } else { + for (int j = 0; j < ns; j++) { + char d2io[MAXLNLEN]; + strcpy(d2io, chenc(wlst[j], dic_enc[d], io_enc)); + wlst[j] = (char *) realloc(wlst[j], strlen(d2io) + 1); + strcpy(wlst[j], d2io); + } + dialogexit = dialog(parser, pMS[d], token, filename, wlst, ns, info); + } + for (int j = 0; j < ns; j++) { + free(wlst[j]); + } + free(wlst); + } + free(token); + if ((dialogexit==-1) || (dialogexit==1)) goto ki2; + } + + ki2: fprintf(tempfile,"%s\n",token=parser->get_line()); + free(token); + return dialogexit; +} + +void interactive_interface(Hunspell ** pMS, char * filename, int format) +{ + char buf[MAXLNLEN]; + + FILE *text; + + text = fopen(filename, "r"); + + int dialogexit; + int check=1; + + TextParser * parser; + char * extension = basename(filename, '.'); + parser = get_parser(format, extension, pMS[0]); + + char * tempname = (char *) malloc(strlen(filename) + strlen(TEMPNAME) + 1); + strcpy(tempname, filename); + strcpy(basename(tempname, DIRSEPCH), TEMPNAME); + + FILE *tempfile; + + if (!(tempfile = fopen(tempname, "w"))) { + fprintf(stderr, gettext("Can't create tempfile %s.\n"), tempname); + endwin(); + exit(1); + } + + while(fgets(buf,MAXLNLEN,text)) { + if (check) { + if (*(buf + strlen(buf) - 1) == '\n') *(buf + strlen(buf) - 1) = '\0'; + parser->put_line(buf); + dialogexit = interactive_line(parser,pMS,filename,tempfile); + switch (dialogexit) { + case -1: { + clear(); + refresh(); + unlink(tempname); + endwin(); + exit(0); + } + case 1: { + check = 0; + } + } + } else { + fprintf(tempfile,"%s",buf); + } + } + fclose(text); + fclose(tempfile); + delete parser; + + if (! modified) { + unlink(tempname); + } else { + rename(tempname, filename); + } + free(tempname); +} + +#endif + +char * add(char * dest, const char * st) { + if (!dest) { + dest = mystrdup(st); + } else { + dest = (char *) realloc(dest, strlen(dest) + strlen(st) + 1); + strcat(dest, st); + } + return dest; +} + +char * exist2(char * dir, int len, const char * name, const char * ext) { + char buf[MAXLNLEN]; + const char * sep = (len == 0) ? "": DIRSEP; + strncpy(buf, dir, len); + strcpy(buf + len, sep); + strcat(buf, name); + strcat(buf, ext); + if (exist(buf)) return mystrdup(buf); + strcat(buf, HZIP_EXTENSION); + if (exist(buf)) { + buf[strlen(buf) - strlen(HZIP_EXTENSION)] = '\0'; + return mystrdup(buf); + } + return NULL; +} + +#ifndef WIN32 +int listdicpath(char * dir, int len) { + char buf[MAXLNLEN]; + const char * sep = (len == 0) ? "": DIRSEP; + strncpy(buf, dir, len); + strcpy(buf + len, sep); + DIR *d = opendir(buf); + if (!d) return 0; + struct dirent * de; + while ((de = readdir(d))) { + int len = strlen(de->d_name); + if ((len > 4 && strcmp(de->d_name + len - 4, ".dic") == 0) || + (len > 7 && strcmp(de->d_name + len - 7, ".dic.hz") == 0)) { + char * s = mystrdup(de->d_name); + s[len - ((s[len - 1] == 'z') ? 7 : 4)] = '\0'; + fprintf(stderr, "%s%s\n", buf, s); + free(s); + } + } + closedir(d); + return 1; +} +#endif + +// search existing path for file "name + ext" +char * search(char * begin, char * name, const char * ext) { + char * end = begin; + while (1) { + while (!((*end == *PATHSEP) || (*end == '\0'))) end++; + char * res = NULL; + if (name) { + res = exist2(begin, end - begin, name, ext); + } else { +#ifndef WIN32 + listdicpath(begin, end - begin); +#endif + } + if ((*end == '\0') || res) return res; + end++; + begin = end; + } +} + +int main(int argc, char** argv) +{ + char buf[MAXLNLEN]; + Hunspell * pMS[DMAX]; + char * key = NULL; + int arg_files = -1; // first filename argumentum position in argv + int format = FMT_TEXT; + int argstate = 0; + +#ifdef ENABLE_NLS +# ifdef HAVE_LOCALE_H + setlocale(LC_ALL, ""); + textdomain("hunspell"); +# ifdef HAVE_LANGINFO_CODESET + ui_enc = nl_langinfo(CODESET); +# endif +# endif +#endif + +#ifdef HAVE_READLINE + rl_set_key("", rl_escape, rl_get_keymap()); + rl_bind_key('\t', rl_insert); +#endif + +#ifdef LOG + log("START"); +#endif + + for(int i=1; i<argc; i++) { +#ifdef LOG + log(argv[i]); +#endif + + if (argstate == 1) { + if (dicname) free(dicname); + dicname = mystrdup(argv[i]); + argstate = 0; + } else if (argstate == 2) { + if (privdicname) free(privdicname); + privdicname = mystrdup(argv[i]); + argstate = 0; + } else if (argstate == 3) { + io_enc = argv[i]; + argstate = 0; + } else if (argstate == 4) { + key = argv[i]; + argstate = 0; + } else if (strcmp(argv[i],"-d")==0) argstate=1; + else if (strcmp(argv[i],"-p")==0) argstate=2; + else if (strcmp(argv[i],"-i")==0) argstate=3; + else if (strcmp(argv[i],"-P")==0) argstate=4; + else if ((strcmp(argv[i],"-h") == 0) || (strcmp(argv[i],"--help") == 0)) { + fprintf(stderr,gettext("Usage: hunspell [OPTION]... [FILE]...\n")); + fprintf(stderr,gettext("Check spelling of each FILE. Without FILE, check standard input.\n\n")); + fprintf(stderr,gettext(" -1\t\tcheck only first field in lines (delimiter = tabulator)\n")); + fprintf(stderr,gettext(" -a\t\tIspell's pipe interface\n")); + fprintf(stderr,gettext(" --check-url\tCheck URLs, e-mail addresses and directory paths\n")); + fprintf(stderr,gettext(" -d d[,d2,...]\tuse d (d2 etc.) dictionaries\n")); + fprintf(stderr,gettext(" -D\t\tshow available dictionaries\n")); + fprintf(stderr,gettext(" -G\t\tprint only correct words or lines\n")); + fprintf(stderr,gettext(" -h, --help\tdisplay this help and exit\n")); + fprintf(stderr,gettext(" -H\t\tHTML input file format\n")); + fprintf(stderr,gettext(" -i enc\tinput encoding\n")); + fprintf(stderr,gettext(" -l\t\tprint misspelled words\n")); + fprintf(stderr,gettext(" -L\t\tprint lines with misspelled words\n")); + fprintf(stderr,gettext(" -m \t\tanalyze the words of the input text\n")); + fprintf(stderr,gettext(" -n\t\tnroff/troff input file format\n")); + fprintf(stderr,gettext(" -p dict\tset dict custom dictionary\n")); + fprintf(stderr,gettext(" -r\t\twarn of the potential mistakes (rare words)\n")); + fprintf(stderr,gettext(" -P password\tset password for encrypted dictionaries\n")); + fprintf(stderr,gettext(" -s \t\tstem the words of the input text\n")); + fprintf(stderr,gettext(" -t\t\tTeX/LaTeX input file format\n")); +// experimental functions: missing Unicode support +// fprintf(stderr,gettext(" -u\t\tshow typical misspellings\n")); +// fprintf(stderr,gettext(" -u2\t\tprint typical misspellings in sed format\n")); +// fprintf(stderr,gettext(" -u3\t\tprint typical misspellings in gcc error format\n")); +// fprintf(stderr,gettext(" -U\t\tautomatic correction of typical misspellings to stdout\n")); + fprintf(stderr,gettext(" -v, --version\tprint version number\n")); + fprintf(stderr,gettext(" -vv\t\tprint Ispell compatible version number\n")); + fprintf(stderr,gettext(" -w\t\tprint misspelled words (= lines) from one word/line input.\n\n")); + fprintf(stderr,gettext("Example: hunspell -d en_US file.txt # interactive spelling\n" + " hunspell -l file.txt # print misspelled words\n" + " hunspell -i utf-8 file.txt # check UTF-8 encoded file\n\n")); + fprintf(stderr,gettext("Bug reports: http://hunspell.sourceforge.net\n")); + exit(0); + } else if ((strcmp(argv[i],"-vv")==0) || (strcmp(argv[i],"-v")==0) || (strcmp(argv[i],"--version")==0)) { + fprintf(stdout,gettext(HUNSPELL_PIPE_HEADING)); + fprintf(stdout,"\n"); + if (strcmp(argv[i],"-vv")!=0) { + fprintf(stdout,gettext("\nCopyright (C) 2002-2008 L\303\241szl\303\263 N\303\251meth. License: MPL/GPL/LGPL.\n\n" + "Based on OpenOffice.org's Myspell library.\n" + "Myspell's copyright (C) Kevin Hendricks, 2001-2002, License: BSD.\n\n")); + fprintf(stdout,gettext("This is free software; see the source for copying conditions. There is NO\n" + "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,\n" + "to the extent permitted by law.\n")); + } + exit(0); + } else if ((strcmp(argv[i],"-a")==0)) { + filter_mode = PIPE; + fprintf(stdout,gettext(HUNSPELL_PIPE_HEADING)); + fflush(stdout); + } else if ((strcmp(argv[i],"-m")==0)) { + /* + if -a was used, don't override, i.e. keep ispell compatability + ispell: Make possible root/affix combinations that aren't in the dictionary. + hunspell: Analyze the words of the input text + */ + if (filter_mode != PIPE) + filter_mode = ANALYZE; + } else if ((strcmp(argv[i],"-s")==0)) { + /* + if -a was used, don't override, i.e. keep ispell compatability + ispell: Stop itself with a SIGTSTP signal after each line of input. + hunspell: Stem the words of the input text + */ + if (filter_mode != PIPE) + filter_mode = STEM; + } else if ((strcmp(argv[i],"-t")==0)) { + format = FMT_LATEX; + } else if ((strcmp(argv[i],"-n")==0)) { + format = FMT_MAN; + } else if ((strcmp(argv[i],"-H")==0)) { + format = FMT_HTML; + } else if ((strcmp(argv[i],"-l")==0)) { + filter_mode = BADWORD; + } else if ((strcmp(argv[i],"-w")==0)) { + /* + if -a was used, don't override, i.e. keep ispell compatability + ispell: Specify additional characters that can be part of a word. + hunspell: Print misspelled words (= lines) from one word/line input + */ + if (filter_mode != PIPE) + filter_mode = WORDFILTER; + } else if ((strcmp(argv[i],"-L")==0)) { + /* + if -a was used, don't override, i.e. keep ispell compatability + ispell: Number of lines of context to be shown at the bottom of the screen + hunspell: Print lines with misspelled words + */ + if (filter_mode != PIPE) + filter_mode = BADLINE; + } else if ((strcmp(argv[i],"-u")==0)) { + /* + if -a was used, don't override, i.e. keep ispell compatability + ispell: None + hunspell: Show typical misspellings + */ + if (filter_mode != PIPE) + filter_mode = AUTO0; + } else if ((strcmp(argv[i],"-U")==0)) { + /* + if -a was used, don't override, i.e. keep ispell compatability + ispell: None + hunspell: Automatic correction of typical misspellings to stdout + */ + if (filter_mode != PIPE) + filter_mode = AUTO; + } else if ((strcmp(argv[i],"-u2")==0)) { + /* + if -a was used, don't override, i.e. keep ispell compatability + ispell: None + hunspell: Print typical misspellings in sed format + */ + if (filter_mode != PIPE) + filter_mode = AUTO2; + } else if ((strcmp(argv[i],"-u3")==0)) { + /* + if -a was used, don't override, i.e. keep ispell compatability + ispell: None + hunspell: Print typical misspellings in gcc error format + */ + if (filter_mode != PIPE) + filter_mode = AUTO3; + } else if ((strcmp(argv[i],"-G")==0)) { + printgood = 1; + } else if ((strcmp(argv[i],"-1")==0)) { + format = FMT_FIRST; + } else if ((strcmp(argv[i],"-D")==0)) { + showpath = 1; + } else if ((strcmp(argv[i],"-r")==0)) { + warn = 1; +fprintf(stderr, "BEKAPCS"); + } else if ((strcmp(argv[i],"--check-url")==0)) { + checkurl = 1; + } else if ((arg_files==-1) && ((argv[i][0] != '-') && (argv[i][0] != '\0'))) { + arg_files = i; + if (! exist(argv[i])) { // first check (before time-consuming dic. load) + fprintf(stderr,gettext("Can't open %s.\n"),argv[i]); +#ifdef HAVE_CURSES_H + endwin(); +#endif + exit(1); + } + } + } + + if (printgood && (filter_mode == NORMAL)) filter_mode = BADWORD; + + if (! dicname) { + if (! (dicname=getenv("DICTIONARY"))) { + /* + * Search in order of LC_ALL, LC_MESSAGES & + * LANG + */ + const char *tests[] = { "LC_ALL", "LC_MESSAGES", "LANG" }; + for (size_t i = 0; i < sizeof(tests) / sizeof(const char*); ++i) { + if ((dicname=getenv(tests[i])) && strcmp(dicname, "") != 0) { + dicname = mystrdup(dicname); + char * dot = strchr(dicname, '.'); + if (dot) *dot = '\0'; + char * at = strchr(dicname, '@'); + if (at) *at = '\0'; + break; + } + } + + if (dicname && ((strcmp(dicname, "C") == 0) || (strcmp(dicname, "POSIX") == 0))) { + free(dicname); + dicname=mystrdup("en_US"); + } + + if (! dicname) { + dicname=mystrdup(DEFAULTDICNAME); + } + } else { + dicname = mystrdup(dicname); + } + } + path = add(mystrdup("."), PATHSEP); // <- check path in local directory + path = add(path, PATHSEP); // <- check path in root directory + if (getenv("DICPATH")) path = add(add(path, getenv("DICPATH")), PATHSEP); + path = add(add(path, LIBDIR), PATHSEP); + if (HOME) path = add(add(add(add(path, HOME), DIRSEP), USEROOODIR), PATHSEP); + path = add(path, OOODIR); + + if (showpath) { + fprintf(stderr, gettext("SEARCH PATH:\n%s\n"), path); + fprintf(stderr, gettext("AVAILABLE DICTIONARIES (path is not mandatory for -d option):\n")); + search(path, NULL, NULL); + } + + if (!privdicname) privdicname = mystrdup(getenv("WORDLIST")); + + char * dicplus = strchr(dicname, ','); + if (dicplus) *dicplus = '\0'; + char * aff = search(path, dicname, ".aff"); + char * dic = search(path, dicname, ".dic"); + if (aff && dic) { + if (showpath) { + fprintf(stderr, gettext("LOADED DICTIONARY:\n%s\n%s\n"), aff, dic); + } + pMS[0] = new Hunspell(aff, dic, key); + dic_enc[0] = pMS[0]->get_dic_encoding(); + dmax = 1; + if (pMS[0] && dicplus) while (dicplus) { + char * dicname2 = dicplus + 1; + dicplus = strchr(dicname2, ','); + if (dicplus) *dicplus = '\0'; + free(aff); + free(dic); + aff = search(path, dicname2, ".aff"); + dic = search(path, dicname2, ".dic"); + if (aff && dic) { + if (dmax < DMAX) { + pMS[dmax] = new Hunspell(aff, dic, key); + dic_enc[dmax] = pMS[dmax]->get_dic_encoding(); + dmax++; + } else fprintf(stderr, gettext("error - %s exceeds dictionary limit.\n"), dicname2); + } else if (dic) pMS[dmax-1]->add_dic(dic); + } + } else { + fprintf(stderr,gettext("Can't open affix or dictionary files for dictionary named \"%s\".\n"), dicname); + exit(1); + } + + /* open the private dictionaries */ + if (HOME) { + strcpy(buf,HOME); +#ifndef WIN32 + strcat(buf,"/"); +#endif + if (!privdicname) { + strcat(buf,DICBASENAME); + strcat(buf,basename(dicname,DIRSEPCH)); + load_privdic(buf, pMS[0]); + strcpy(buf,DICBASENAME); + strcat(buf,basename(dicname,DIRSEPCH)); + load_privdic(buf, pMS[0]); + } else { + strcat(buf,privdicname); + load_privdic(buf, pMS[0]); + strcpy(buf,privdicname); + load_privdic(buf, pMS[0]); + } + } + + if (arg_files==-1) { + pipe_interface(pMS, format, stdin); + } else if (filter_mode != NORMAL) { + for (int i = arg_files; i < argc; i++) { + if (exist(argv[i])) { + modified = 0; + currentfilename = argv[i]; + FILE * f = fopen(argv[i], "r"); + pipe_interface(pMS, format, f); + fclose(f); + } else { + fprintf(stderr, gettext("Can't open %s.\n"), argv[i]); + exit(1); + } + } + } else if (filter_mode == NORMAL) { +#ifdef HAVE_CURSES_H + initscr(); + cbreak(); + noecho(); + nonl(); + intrflush(stdscr,FALSE); + + for (int i = arg_files; i < argc; i++) { + if (exist(argv[i])) { + modified = 0; + interactive_interface(pMS, argv[i], format); + } else { + fprintf(stderr, gettext("Can't open %s.\n"), argv[i]); + endwin(); + exit(1); + } + } + + clear(); + refresh(); + endwin(); +#else + fprintf(stderr, gettext("Hunspell has been compiled without Ncurses user interface.\n")); +#endif + } + + if (dicname) free(dicname); + if (privdicname) free(privdicname); + if (path) free(path); + if (aff) free(aff); + if (dic) free(dic); + if (wordchars) free(wordchars); + if (wordchars_utf16_free) free(wordchars_utf16); +#ifdef HAVE_ICONV + free_utf_tbl(); +#endif + for (int i = 0; i < dmax; i++) delete pMS[i]; + return 0; +} |