diff --git a/golded3/gccfgg.cpp b/golded3/gccfgg.cpp index 32692ed..bec25a6 100644 --- a/golded3/gccfgg.cpp +++ b/golded3/gccfgg.cpp @@ -764,6 +764,11 @@ CfgGed::CfgGed() { replylinkfloat = true; replylinklist = 0; replylinkshowalways = true; +#if defined(__GOLD_SPELL__) + scheckerdeflang = 0xFFFF; + scheckerenabled = NO; + strcpy(scheckeruserdic, "user.dic"); +#endif screenblanker = 180; screenblankertype = BLANK_SLIDEWIN; screenmaxcol = 0; diff --git a/golded3/gccfgg.h b/golded3/gccfgg.h index 740f55e..2ef3f60 100644 --- a/golded3/gccfgg.h +++ b/golded3/gccfgg.h @@ -320,6 +320,11 @@ const word CRC_REPLYLINKFLOAT = 0xA3EC; const word CRC_REPLYLINKLIST = 0x104F; const word CRC_REPLYLINKSHOWALWAYS = 0x2BCD; const word CRC_ROBOTNAME = 0x7393; +#if defined(__GOLD_SPELL__) +const word CRC_SCHECKERDEFLANG = 0xBBEB; +const word CRC_SCHECKERENABLED = 0x7394; +const word CRC_SCHECKERUSERDIC = 0x0753; +#endif const word CRC_SCREENBLANKER = 0x5CF7; const word CRC_SCREENMAXCOL = 0xFFFC; const word CRC_SCREENMAXROW = 0xFDF7; diff --git a/golded3/gccfgg0.cpp b/golded3/gccfgg0.cpp index 91d465a..909a055 100644 --- a/golded3/gccfgg0.cpp +++ b/golded3/gccfgg0.cpp @@ -519,6 +519,11 @@ SwitchR: SwitchS: switch(crc) { +#if defined(__GOLD_SPELL__) + case CRC_SCHECKERDEFLANG : CfgScheckerdeflang (); break; + case CRC_SCHECKERENABLED : CfgScheckerenabled (); break; + case CRC_SCHECKERUSERDIC : CfgScheckeruserdic (); break; +#endif case CRC_SCREENBLANKER : CfgScreenblanker (); break; case CRC_SCREENMAXCOL : CfgScreenmaxcol (); break; case CRC_SCREENMAXROW : CfgScreenmaxrow (); break; diff --git a/golded3/gccfgg7.cpp b/golded3/gccfgg7.cpp index 67a32fe..6231b60 100644 --- a/golded3/gccfgg7.cpp +++ b/golded3/gccfgg7.cpp @@ -222,6 +222,31 @@ void CfgRobotname() { // ------------------------------------------------------------------ +#if defined(__GOLD_SPELL__) +void CfgScheckerdeflang() +{ + CFG->scheckerdeflang = atoi(val); + if (CFG->scheckerdeflang == 0) + CFG->scheckerdeflang = 0xFFFF; +} + +// ------------------------------------------------------------------ + +void CfgScheckerenabled() +{ + CFG->scheckerenabled = GetYesno(val); +} + +// ------------------------------------------------------------------ + +void CfgScheckeruserdic() +{ + strcpy(CFG->scheckeruserdic, val); +} +#endif + +// ------------------------------------------------------------------ + void CfgScreenblanker() { GTok t; diff --git a/golded3/gckeys.cpp b/golded3/gckeys.cpp index 87f39fd..be3dd20 100644 --- a/golded3/gckeys.cpp +++ b/golded3/gckeys.cpp @@ -671,6 +671,9 @@ tglobalkey globalkeys[] = { { CRC_READSHOWDEL , KK_ReadShowDel , KT_R }, // 0x8615 { CRC_K_ENTER , Key_Ent , 0 }, // 0x87BD { CRC_EDITGOTOPLINE , KK_EditGoTopLine , KT_E }, // 0x87C2 +#if defined(__GOLD_SPELL__) + { CRC_EDITSCHECKERMENU , KK_EditSCheckerMenu , KT_E }, // 0x881F +#endif { CRC_HEADERTOGGLEARCSENT , KK_HeaderToggleArcsent , KT_H }, // 0x88A7 { CRC_EDITBLOCKPGDN , KK_EditBlockPgDn , KT_E }, // 0x895B { CRC_EDITASKEXIT , KK_EditAskExit , KT_E }, // 0x89AF diff --git a/golded3/gckeys.h b/golded3/gckeys.h index 92706f5..84badc5 100644 --- a/golded3/gckeys.h +++ b/golded3/gckeys.h @@ -112,6 +112,9 @@ const word CRC_EDITQUITNOW = 0x80BA; const word CRC_EDITREFLOW = 0x13F9; const word CRC_EDITSAVEFILE = 0x64A4; const word CRC_EDITSAVEMSG = 0x660C; +#if defined(__GOLD_SPELL__) +const word CRC_EDITSCHECKERMENU = 0x881F; +#endif const word CRC_EDITSCODENORMAL = 0xE4CE; const word CRC_EDITSCODEBOLD = 0x657D; const word CRC_EDITSCODEITALIC = 0x487F; diff --git a/golded3/gcmisc.cpp b/golded3/gcmisc.cpp index 1ae5dcd..c29fe4c 100644 --- a/golded3/gcmisc.cpp +++ b/golded3/gcmisc.cpp @@ -222,6 +222,14 @@ const word CRC_STYLECODE = 0x8B6C; const word CRC_STYLECODES = 0x4CB0; +// ------------------------------------------------------------------ + +#if defined(__GOLD_SPELL__) +const word CRC_SPELL = 0xB8AE; +const word CRC_SCERROR = 0xAB65; +#endif + + // ------------------------------------------------------------------ // Get color value @@ -414,6 +422,11 @@ void GetColors(char* value) { case CRC_STYLECODES: wptr = &GC_STYLE_; break; +#if defined(__GOLD_SPELL__) + case CRC_SPELL: + wptr = &GC_SPELL_; + break; +#endif default: return; } @@ -577,6 +590,11 @@ void GetColors(char* value) { wptr->_ReverseBoldItalicUnderscore = attr; } break; +#if defined(__GOLD_SPELL__) + case CRC_SCERROR: + wptr->_SpellError = attr; + break; +#endif default: return; } diff --git a/golded3/gcprot.h b/golded3/gcprot.h index 59c3fc5..a81da83 100644 --- a/golded3/gcprot.h +++ b/golded3/gcprot.h @@ -306,6 +306,11 @@ void CfgReplylinklist (); void CfgReplylinkshowalways(); void CfgReplyto (); void CfgRobotname (); +#if defined(__GOLD_SPELL__) +void CfgScheckerdeflang (); +void CfgScheckerenabled (); +void CfgScheckeruserdic (); +#endif void CfgScreenblanker (); void CfgScreenmaxcol (); void CfgScreenmaxrow (); diff --git a/golded3/geall.h b/golded3/geall.h index 606f3bf..f13cb72 100644 --- a/golded3/geall.h +++ b/golded3/geall.h @@ -638,6 +638,9 @@ struct SaveUtil { #define GC_CFGB_ CFG->color[11] #define GC_STYLE_ CFG->color[12] #define GC_SHAD_ CFG->color[13] +#if defined(__GOLD_SPELL__) +#define GC_SPELL_ CFG->color[14] +#endif // ------------------------------------------------------------------ @@ -690,6 +693,10 @@ struct SaveUtil { #define _ReverseItalicUnderscore c[14] #define _ReverseBoldItalicUnderscore c[15] +#if defined(__GOLD_SPELL__) +#define _SpellError c[0] +#endif + // ------------------------------------------------------------------ // Window part colors @@ -806,6 +813,10 @@ struct SaveUtil { #define C_STYLERUI_ GC_STYLE_._ReverseItalicUnderscore #define C_STYLERUIB GC_STYLE_._ReverseBoldItalicUnderscore +#if defined(__GOLD_SPELL__) +#define C_SCERROR GC_SPELL_._SpellError +#endif + // ------------------------------------------------------------------ // Window handles diff --git a/golded3/gecfgg.h b/golded3/gecfgg.h index d94bc92..23d82e4 100644 --- a/golded3/gecfgg.h +++ b/golded3/gecfgg.h @@ -309,6 +309,11 @@ public: int replylinklist; bool replylinkshowalways; gstrarray robotname; +#if defined(__GOLD_SPELL__) + word scheckerdeflang; + int scheckerenabled; + Path scheckeruserdic; +#endif int screenblanker; // blanktime; int screenblankertype; int screenmaxcol; // maxcols; diff --git a/golded3/geedit.cpp b/golded3/geedit.cpp index 972c244..3f59bfd 100644 --- a/golded3/geedit.cpp +++ b/golded3/geedit.cpp @@ -93,6 +93,16 @@ void IEclass::debugtest(char* __test, int __a, int __b, char* __file, int __line #endif +// ------------------------------------------------------------------ + +#if defined(__GOLD_SPELL__) +inline bool isscchar(int c) +{ + return isxalnum(c) || (c == '-') || (c == '\'') || (c == '.') ; +} +#endif + + // ------------------------------------------------------------------ // Make sure line type is correct @@ -240,6 +250,207 @@ void IEclass::gotorowcol(uint __col, uint __row) { } +// ------------------------------------------------------------------ + +#if defined(__GOLD_SPELL__) +void IEclass::dispstringsc(char *__buf, uint __beg, uint __end, uint __row, uint __col, char endchar) +{ + char scbuf[EDIT_BUFLEN]; + + uint bbeg = __beg; + uint bend = __beg; + uint bpos = __beg; + + if ((bbeg > 0) && isscchar(__buf[bbeg]) && isscchar(__buf[bbeg-1])) + { + for (; (bpos < __end) && isscchar(__buf[bpos]); bpos++); + bend = bpos; + } + + while (bpos < __end) + { + for (; (bpos < __end) && !isscchar(__buf[bpos]); bpos++); + bend = bpos; + + uint scpos = 0; + for (; (bpos < __end) && isscchar(__buf[bpos]); bpos++, scpos++) + scbuf[scpos] = __buf[bpos]; + + if ((scpos == 0) || ((bpos == __end) && isscchar(endchar))) + { + bend = bpos; + break; + } + + scbuf[scpos] = NUL; + + if (schecker.Check(scbuf)) + bend = bpos; + else + { + char savechar = __buf[bend]; + __buf[bend] = NUL; + StyleCodeHighlight(__buf+bbeg, __row, __col+bbeg-__beg, false, -1); + __buf[bend] = savechar; + + bbeg = bend; bend += scpos; + + bool oldusestylies = AA->adat->usestylies; + bool oldhighlighturls = CFG->highlighturls; + AA->adat->usestylies = false; + CFG->highlighturls = false; + + savechar = __buf[bend]; + __buf[bend] = NUL; + StyleCodeHighlight(__buf+bbeg, __row, __col+bbeg-__beg, false, C_SCERROR); + __buf[bend] = savechar; + + AA->adat->usestylies = oldusestylies; + CFG->highlighturls = oldhighlighturls; + + bbeg = bend; + } + } + + if (bbeg < bend) + StyleCodeHighlight(__buf+bbeg, __row, __col+bbeg-__beg, false, -1); +} + + +// ------------------------------------------------------------------ + +void IEclass::dispstring(Line* line, uint __row) +{ + GFTRK("Editdispstring"); + + // Get string length + uint _length = strlen(line->txt.c_str()); + + // String longer than window width? + _test_haltab(_length > (maxcol+1), _length, (maxcol+1)); + _length = MinV(_length, (maxcol+1)); + + // Buffer for translation to visual representation + char _buf[EDIT_BUFLEN]; + + // Space-pad and nul-terminate the buffer + memset(_buf, ' ', maxcol+1); + _buf[maxcol+1] = NUL; + + // Copy/translate string into buffer + for (uint _pos = 0; _pos < _length; _pos++) + { + char chr = line->txt[_pos]; + switch (chr) + { + case ' ': _buf[_pos] = EDIT->CharSpace(); break; + case '\n': _buf[_pos] = EDIT->CharPara(); break; + default: _buf[_pos] = chr; + } + } + + int selected = 0; + uint begblock = 0; + uint endblock = 0; + Line *fbline = NULL; + Line *lbline = NULL; + + if (blockcol != -1) + { + for (Line *ln = findfirstline(); ln; ln = ln->next) + { + if (ln == currline) + { + if (selected) { lbline = ln; selected ^= 1; endblock = col; } + else { fbline = ln; selected ^= 1; begblock = col; } + } + + if (ln->type & GLINE_BLOK) + { + if (selected) { lbline = ln; selected ^= 1; endblock = blockcol; } + else { fbline = ln; selected ^= 1; begblock = blockcol; } + } + + if (ln == line) { if (ln == lbline) selected = 1; break; } + if (lbline) break; + } + + if (selected) + { + if (fbline == lbline) + { + if (begblock > endblock) + { + int temp = begblock; + begblock = endblock; + endblock = temp; + } + else if (begblock == endblock) + begblock = endblock = 0; + } + else if (line == fbline) + endblock = maxcol+1; + else if (line == lbline) + begblock = 0; + else + { + begblock = 0; + endblock = maxcol+1; + } + } + else + begblock = endblock = 0; + } + + + if (0 < begblock) + { + char savechar = _buf[begblock]; + _buf[begblock] = NUL; + + if ((CFG->scheckerenabled == GAUTO) && schecker.IsLoaded() && + !(line->type & (GLINE_TAGL|GLINE_QUOT|GLINE_KLUD|GLINE_TEAR|GLINE_ORIG|GLINE_HIDD))) + { + dispstringsc(_buf, 0, begblock, __row, mincol, savechar); + } + else + StyleCodeHighlight(_buf, __row, mincol, false, -1); + + _buf[begblock] = savechar; + } + + if (begblock < endblock) + { + bool oldusestylies = AA->adat->usestylies; + bool oldhighlighturls = CFG->highlighturls; + AA->adat->usestylies = false; + CFG->highlighturls = false; + + char savechar = _buf[endblock]; + _buf[endblock] = NUL; + StyleCodeHighlight(_buf+begblock, __row, mincol+begblock, false, C_READA); + _buf[endblock] = savechar; + + AA->adat->usestylies = oldusestylies; + CFG->highlighturls = oldhighlighturls; + } + + if (endblock < (maxcol+1)) + { + if ((CFG->scheckerenabled == GAUTO) && schecker.IsLoaded() && + !(line->type & (GLINE_TAGL|GLINE_QUOT|GLINE_KLUD|GLINE_TEAR|GLINE_ORIG|GLINE_HIDD))) + { + dispstringsc(_buf, endblock, maxcol+1, __row, mincol+endblock, 0); + } + else + StyleCodeHighlight(_buf+endblock, __row, mincol+endblock, false, -1); + } + + GFTRK(NULL); +} +#else //#if defined(__GOLD_SPELL__) + + // ------------------------------------------------------------------ void IEclass::dispstring(const char* __string, uint __row, int attr, Line* line) { @@ -353,6 +564,7 @@ void IEclass::dispstring(const char* __string, uint __row, int attr, Line* line) GFTRK(NULL); } +#endif //#if defined(__GOLD_SPELL__) // ------------------------------------------------------------------ @@ -392,7 +604,11 @@ void IEclass::displine(Line* __line, uint __row) { // Display line setcolor(__line); +#if defined(__GOLD_SPELL__) + dispstring(__line, __row); +#else dispstring(__line->txt.c_str(), __row, -1, __line); +#endif GFTRK(NULL); } @@ -436,6 +652,12 @@ void IEclass::refresh(Line* __currline, uint __row) { } // If we ran out of lines, blank the rest +#if defined(__GOLD_SPELL__) + if (__row <= maxrow) + editwin.fill(__row, mincol, __row, maxcol, _box_table(W_BREAD, 1), C_READB|ACSET); + if (++__row <= maxrow) + editwin.fill(__row, mincol, maxrow, maxcol, ' ', C_READW); +#else if(__row <= maxrow) { vchar vbuf[256]; for(int c = 0; c < maxcol+1; c++) @@ -445,6 +667,7 @@ void IEclass::refresh(Line* __currline, uint __row) { while(__row <= maxrow) dispstring("", __row++); } +#endif GFTRK(NULL); } @@ -1859,6 +2082,58 @@ void IEclass::SaveMsg() { } +// ------------------------------------------------------------------ + +#if defined(__GOLD_SPELL__) +void IEclass::SCheckerMenu() +{ + if (!schecker.IsLoaded()) + return; + + const char *txt = currline->txt.c_str(); + GMenuSChecker menu; + int finaltag; + + if (!isscchar(txt[col])) + finaltag = menu.Run(schecker, ""); + else + { + char buff[EDIT_BUFLEN]; + size_t beg = col; + size_t end = col; + + for (; (beg > 0) && isscchar(txt[beg-1]); beg--); + for (; isscchar(txt[end]); end++); + size_t len = end - beg; + + memcpy(buff, &txt[beg], len); + buff[len] = 0; + + finaltag = menu.Run(schecker, buff); + if (finaltag >= 0) + { + std::string &str = schecker.GetSuggest()[finaltag].second; + size_t len2 = str.length() - 3; + txt = &str.c_str()[2]; + + if ((buff[len-1] == '.') && (txt[len2-1] != '.')) len--; + if (col > (beg + len2 - 1)) col = beg + len2 - 1; + + Undo->PushItem(EDIT_UNDO_DEL_TEXT, currline, beg, len); + currline->txt.erase(beg, len); + + Undo->PushItem(EDIT_UNDO_INS_TEXT|BATCH_MODE, currline, beg, len2); + currline->txt.insert(beg, txt, len2); + wrapit(&currline, &col, &row); + } + } + + if (finaltag == -2) + refresh(currline, row); +} +#endif + + // ------------------------------------------------------------------ int IEclass::isempty(Line* __line) { @@ -2476,6 +2751,9 @@ noselecting: case KK_EditReflow: Reflow(); break; case KK_EditSaveFile: SaveFile(); break; case KK_EditSaveMsg: SaveMsg(); break; +#if defined(__GOLD_SPELL__) + case KK_EditSCheckerMenu: SCheckerMenu(); break; +#endif case KK_EditSoundkill: Soundkill(); break; case KK_EditSpellCheck: SpellCheck(); break; case KK_EditTab: Tab(); break; @@ -2527,6 +2805,14 @@ int IEclass::Start(int __mode, uint* __position, GMsg* __msg) { msgmode = __mode; currline = __msg->lin; +#if defined(__GOLD_SPELL__) + if (CFG->scheckerenabled) + { + schecker.Init(); + schecker.Load(CFG->scheckerdeflang, CFG->scheckeruserdic); + } +#endif + if(AA->isinternet() and (CFG->soupexportmargin <= CFG->dispmargin)) margintext = CFG->soupexportmargin; else diff --git a/golded3/geedit.h b/golded3/geedit.h index 7ecf072..5fda67f 100644 --- a/golded3/geedit.h +++ b/golded3/geedit.h @@ -279,6 +279,12 @@ protected: int blockcol; int selecting; + // ---------------------------------------------------------------- + // Speller. + +#if defined(__GOLD_SPELL__) + CSpellChecker schecker; +#endif // ---------------------------------------------------------------- // Internal helper functions @@ -290,7 +296,12 @@ protected: int dispchar (vchar __ch, int attr=-1); void dispins (); void displine (Line* __line, uint __row); +#if defined(__GOLD_SPELL__) + void dispstringsc (char *__buf, uint __beg, uint __end, uint __row, uint __col, char endchar); + void dispstring (Line* line, uint __row); +#else void dispstring (const char* __string, uint __row, int attr=-1, Line* line=NULL); +#endif int downoneline (uint __row); void editexport (Line* __exportline, int __endat); Line* findanchor (); @@ -395,6 +406,9 @@ public: void ReTab (); void SaveFile (); void SaveMsg (); +#if defined(__GOLD_SPELL__) + void SCheckerMenu (); +#endif void Soundkill (); void SpellCheck (); void Tab (); diff --git a/golded3/gekeys.h b/golded3/gekeys.h index ca253a2..0f26d8e 100644 --- a/golded3/gekeys.h +++ b/golded3/gekeys.h @@ -181,6 +181,9 @@ const gkey KK_EditSCodeBold = 0xFF09; const gkey KK_EditSCodeItalic = 0xFF0A; const gkey KK_EditSCodeUnderline = 0xFF0B; const gkey KK_EditSCodeReverse = 0xFF0C; +#if defined(__GOLD_SPELL__) +const gkey KK_EditSCheckerMenu = 0xFF0D; +#endif const gkey KK_FileAbort = 0xFF10; const gkey KK_FileAskExit = 0xFF11; diff --git a/golded3/gemnus.cpp b/golded3/gemnus.cpp index 5fe0f55..c928a12 100644 --- a/golded3/gemnus.cpp +++ b/golded3/gemnus.cpp @@ -1070,3 +1070,137 @@ int GMenuConfirm::Run() { // ------------------------------------------------------------------ +#if defined(__GOLD_SPELL__) +int GMenuSChecker::Run(CSpellChecker &schecker, const char *word) +{ + enum + { + TAG_ADDWORD = 100, + TAG_LANG = 0x10000, + TAG_MORE = 0x20000, + TAG_INDEX = 0x30000 + }; + + schecker.Check(word); + CSpellSuggestV &suggest = schecker.Suggest(); + + std::string title; + if (!*word) + title = " SChecker "; + else + { + title = " "; + title += word; + title += " "; + } + + Init(); + SetColor(C_ASKW, C_ASKQ, C_ASKN, C_ASKS, CFG->switches.get(screenshadows) ? C_SHADOW : -1); + SetTitle(title.c_str(), C_ASKT, TLEFT); + SetPos(6, 0, title.length()+2, 0); + SetBorder(W_BASK, C_ASKB); + SetMask(M_CLALL); + SetHelp(0); + + Begin(); + SetTitle(""); + + size_t idx; + size_t levels = 0; + size_t numrows = 7; + + CSpellLangV &langs = schecker.GetLangs(); + LIDC lidc = schecker.GetLangCode(); + + std::vector langstr; + size_t langcount = langs.size(); + + for (idx = 0; idx < langcount; idx++) + { + char buff[10]; + LIDC code = langs[idx].GetLangCode(); + + buff[0] = ' '; + buff[1] = (code == lidc) ? '\x10' : ' '; + + itoa(code, &buff[2], 10); + strcat(buff, " "); + + langstr.push_back(std::string(buff)); + } + + if (langcount) + { + Item(TAG_LANG, "L Language... ", 0); + numrows++; + + SetPos(numrows, 1, 0, 0); + Begin(); + + for (idx = 0; idx < langcount; idx++) + Item(TAG_LANG+idx+1, langstr[idx].c_str()); + + End(); + } + + if (*word) + { + Item(TAG_ADDWORD, "A Add Word... "); + numrows++; + } + + if (suggest.size()) + { + ItemSep(); + numrows++; + } + + for (idx = 0; idx < suggest.size(); idx++) + { + Item(TAG_INDEX + idx, suggest[idx].second.c_str()); + + if ((numrows == (gvid->numrows - 5)) && (idx < suggest.size()-3)) + { + ItemSep(); + Item(TAG_MORE + levels, "M More... ", 0); + + levels++; + numrows = levels + 6; + + SetPos(numrows, levels, title.length()+2, 0); + BeginPullDown(); + } + + numrows++; + } + + for (size_t n = 0; n < levels; n++) + End(); + + if (suggest.size()) + SetTag(TAG_INDEX); + + End(); + + vcurhide(); + Start(); + vcurshow(); + + if (finaltag == TAG_ADDWORD) + { + schecker.AddWord(); + return -2; + } + else if ((finaltag > TAG_LANG) && (finaltag < TAG_MORE)) + { + schecker.Load(langs[finaltag-TAG_LANG-1].GetLangCode(), CFG->scheckeruserdic); + return -2; + } + + return (finaltag < TAG_INDEX) ? -1 : (finaltag - TAG_INDEX); +} +#endif + + +// ------------------------------------------------------------------ + diff --git a/golded3/gemnus.h b/golded3/gemnus.h index e827d4b..5d6bc5a 100644 --- a/golded3/gemnus.h +++ b/golded3/gemnus.h @@ -304,3 +304,14 @@ public: // ------------------------------------------------------------------ +#if defined(__GOLD_SPELL__) +class GMenuSChecker : public GMnu +{ +public: + int Run(CSpellChecker &schecker, const char *word); +}; +#endif + + +// ------------------------------------------------------------------ + diff --git a/golded3/golded.h b/golded3/golded.h index efa27f0..9302734 100644 --- a/golded3/golded.h +++ b/golded3/golded.h @@ -78,6 +78,7 @@ #include #include #include +#include // ------------------------------------------------------------------ diff --git a/goldlib/gall/gespell.cpp b/goldlib/gall/gespell.cpp new file mode 100644 index 0000000..c1fa140 --- /dev/null +++ b/goldlib/gall/gespell.cpp @@ -0,0 +1,498 @@ + +// ------------------------------------------------------------------ +// GoldED+ +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program 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 +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307 USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// SpellChecker functions. +// ------------------------------------------------------------------ + +#if defined(__GOLD_SPELL__) + +#if defined(_MSC_VER) + /* C4786: 'identifier' : identifier was truncated to 'number' + characters in the debug information + */ + #pragma warning(disable: 4786) +#endif + +#include + +#include +#include + + +// ------------------------------------------------------------------ + +#if defined(__WIN32__) + + +// ------------------------------------------------------------------ + +#define CHECK_ERROR(jump) if (error != ERROR_SUCCESS) goto jump +#define CHECK_NULL(ptr, jump) if (ptr == NULL) goto jump +#define CHECK_SEC(jump) if ((sec & 0xFF) != SC_SEC_NoErrors) goto jump + + +// ------------------------------------------------------------------ + +const char SC_RKEY_Prooftools[] = "Software\\Microsoft\\Shared Tools\\Proofing Tools"; +const char SC_RKEY_Grammar[] = "Grammar"; +const char SC_RKEY_Spelling[] = "Spelling"; +const char SC_RKEY_Hyphenation[] = "Hyphenation"; +const char SC_RKEY_Thesaurus[] = "Thesaurus"; + +// Spell Check Command Code +const SCCC SC_SCCC_VerifyWord = 1; +const SCCC SC_SCCC_VerifyBuffer = 2; +const SCCC SC_SCCC_Suggest = 3; +const SCCC SC_SCCC_SuggestMore = 4; +const SCCC SC_SCCC_HyphInfo = 5; +const SCCC SC_SCCC_Wildcard = 6; +const SCCC SC_SCCC_Anagram = 7; + +// Spell Check Return Status +const SCRS SC_SRCS_NoErrors = 0; +const SCRS SC_SRCS_UnknownInputWord = 1; +const SCRS SC_SRCS_ReturningChangeAlways = 2; +const SCRS SC_SRCS_ReturningChangeOnce = 3; +const SCRS SC_SRCS_InvalidHyphenation = 4; +const SCRS SC_SRCS_ErrorCapitalization = 5; +const SCRS SC_SRCS_WordConsideredAbbreviation = 6; +const SCRS SC_SRCS_HyphChangesSpelling = 7; +const SCRS SC_SRCS_NoMoreSuggestions = 8; +const SCRS SC_SRCS_MoreInfoThanBufferCouldHold = 9; +const SCRS SC_SRCS_NoSentenceStartCap = 10; +const SCRS SC_SRCS_RepeatWord = 11; +const SCRS SC_SRCS_ExtraSpaces = 12; +const SCRS SC_SRCS_MissingSpace = 13; +const SCRS SC_SRCS_InitialNumeral = 14; + +// Major Error Codes (Low Byte of SEC) +const SEC SC_SEC_NoErrors = 0; +const SEC SC_SEC_OOM = 1; +const SEC SC_SEC_ModuleError = 2; +const SEC SC_SEC_IOErrorMdr = 3; +const SEC SC_SEC_IOErrorUdr = 4; + +// Minor Error Codes (High Byte of SEC) +const SEC SC_SEC_ModuleAlreadyBusy = 128 << 8; +const SEC SC_SEC_InvalidID = 129 << 8; +const SEC SC_SEC_InvalidWsc = 130 << 8; +const SEC SC_SEC_InvalidMdr = 131 << 8; +const SEC SC_SEC_InvalidUdr = 132 << 8; +const SEC SC_SEC_InvalidSCC = 133 << 8; +const SEC SC_SEC_InvalidMainDict = 134 << 8; +const SEC SC_SEC_OperNotMatchedUserDict = 135 << 8; +const SEC SC_SEC_FileReadError = 136 << 8; +const SEC SC_SEC_FileWriteError = 137 << 8; +const SEC SC_SEC_FileCreateError = 138 << 8; +const SEC SC_SEC_FileShareError = 139 << 8; +const SEC SC_SEC_ModuleNotTerminated = 140 << 8; +const SEC SC_SEC_UserDictFull = 141 << 8; +const SEC SC_SEC_InvalidUdrEntry = 142 << 8; +const SEC SC_SEC_UdrEntryTooLong = 143 << 8; +const SEC SC_SEC_MdrCountExceeded = 144 << 8; +const SEC SC_SEC_UdrCountExceeded = 145 << 8; +const SEC SC_SEC_FileOpenError = 146 << 8; +const SEC SC_SEC_FileTooLargeError = 147 << 8; +const SEC SC_SEC_UdrReadOnly = 148 << 8; + +// Spell Options bitfield definitions +const dword SC_SO_SuggestFromUserDict = 0x0001; // Scan UDR as well as MDR +const dword SC_SO_IgnoreAllCaps = 0x0002; // Ignore a word if all upppercase +const dword SC_SO_IgnoreMixedDigits = 0x0004; // Ignore word if has any numbers in it +const dword SC_SO_IgnoreRomanNumerals = 0x0008; // Ignore word composed of all roman numerals +const dword SC_SO_FindUncappedSentences = 0x0010; // Flag sentences which don't start with a cap +const dword SC_SO_FindMissingSpaces = 0x0020; // Find missing spaces between words/sentences +const dword SC_SO_FindRepeatWord = 0x0040; // CSAPI to flag repeated words +const dword SC_SO_FindExtraSpaces = 0x0080; // CSAPI to flag extra spaces between words +const dword SC_SO_FindSpacesBeforePunc = 0x0100; // CSAPI to flag space preceeding certain punc +const dword SC_SO_FindSpacesAfterPunc = 0x0200; // CSAPI to flag space after certain punc +const dword SC_SO_RateSuggestions = 0x0400; + // All suggestions returned should be given some scaled value + // corresponding to liklihood of being correct alternative. + // Scale is 1..255, 255 most likely correction and 1 least likely +const dword SC_SO_FindInitialNumerals = 0x0800; // Flag words starting with number(s) +const dword SC_SO_ReportUDHits = 0x1000; + // Report (via scrsNoErrorsUDHit) where user dict was used during verification +const dword SC_SO_QuickSuggest = 0x2000; // Don't use typo suggest code (Soft-Art only) +const dword SC_SO_UseAllOpenUdr = 0x4000; + // Automatically use all udr's opened after this option is set, + // or all opened udr's with mdr's opened after this option is set. + // This option does not allow exclusion dicts to be edited. (HM only) +const dword SC_SO_SwapMdr = 0x8000; + // Keep the most recent 2 mdr's around. swap between them instead of actually + // closing and reopening mdr's. (HM only) +const dword SC_SO_SglStepSugg = 0x10000; + // Break after each suggestion task for faster return of control to the + // application. (HM only) + +const dword SC_SO_LangMode = 0xF0000000; // Language Mode mask +// Hebrew Language Modes -- (CT only) +const dword SC_SO_HebrewFullScript = 0x00000000; +const dword SC_SO_HebrewPartialScript = 0x10000000; +const dword SC_SO_HebrewMixedScript = 0x20000000; +const dword SC_SO_HebrewMixedAuthorizedScript = 0x30000000; +// French Language Modes -- (HM only) +const dword SC_SO_FrenchDialectDefault = 0x00000000; +const dword SC_SO_FrenchUnaccentedUppercase = 0x10000000; +const dword SC_SO_FrenchAccentedUppercase = 0x20000000; +// Russian Language Modes -- (HM only) +const dword SC_SO_RussianDialectDefault = 0x00000000; +const dword SC_SO_RussianIE = 0x10000000; +const dword SC_SO_RussianIO = 0x20000000; + + +// ------------------------------------------------------------------ + +bool CSpellLang::Init(HKEY hKey, const char *name) +{ + bool result = false; + int error; + HKEY hKeyLang; + + byte engine[_MAX_PATH]; + byte dictionary[_MAX_PATH]; + unsigned long esize = sizeof(engine); + unsigned long dsize = sizeof(dictionary); + + mLIDC = atoi(name); + + error = RegOpenKeyEx(hKey, name, 0, KEY_READ, &hKeyLang); + CHECK_ERROR(cleanup0); + + error = RegQueryValueEx(hKeyLang, "Engine", NULL, NULL, engine, &esize); + CHECK_ERROR(cleanup1); + error = RegQueryValueEx(hKeyLang, "Dictionary", NULL, NULL, dictionary, &dsize); + CHECK_ERROR(cleanup1); + + strcpy(mEngine, (char*)engine); + strcpy(mDictionary, (char*)dictionary); + + result = true; + +cleanup1: + RegCloseKey(hKeyLang); +cleanup0: + return result; +} + + +// ------------------------------------------------------------------ + +bool CSpellLang::Load(const char *userdic) +{ + bool result = false; + + mLibrary = LoadLibrary(mEngine); + CHECK_NULL(mLibrary, cleanup0); + + mSpellVer = (SpellVer_fn ) GetProcAddress(mLibrary, "SpellVer" ); CHECK_NULL(mSpellVer, cleanup1); + mSpellInit = (SpellInit_fn ) GetProcAddress(mLibrary, "SpellInit" ); CHECK_NULL(mSpellInit, cleanup1); + mSpellOptions = (SpellOptions_fn ) GetProcAddress(mLibrary, "SpellOptions" ); CHECK_NULL(mSpellOptions, cleanup1); + mSpellCheck = (SpellCheck_fn ) GetProcAddress(mLibrary, "SpellCheck" ); CHECK_NULL(mSpellCheck, cleanup1); + mSpellTerminate = (SpellTerminate_fn ) GetProcAddress(mLibrary, "SpellTerminate" ); CHECK_NULL(mSpellTerminate, cleanup1); + mSpellOpenMdr = (SpellOpenMdr_fn ) GetProcAddress(mLibrary, "SpellOpenMdr" ); CHECK_NULL(mSpellOpenMdr, cleanup1); + mSpellCloseMdr = (SpellCloseMdr_fn ) GetProcAddress(mLibrary, "SpellCloseMdr" ); CHECK_NULL(mSpellCloseMdr, cleanup1); + mSpellOpenUdr = (SpellOpenUdr_fn ) GetProcAddress(mLibrary, "SpellOpenUdr" ); CHECK_NULL(mSpellOpenUdr, cleanup1); + mSpellAddUdr = (SpellAddUdr_fn ) GetProcAddress(mLibrary, "SpellAddUdr" ); CHECK_NULL(mSpellAddUdr, cleanup1); + mSpellCloseUdr = (SpellCloseUdr_fn ) GetProcAddress(mLibrary, "SpellCloseUdr" ); CHECK_NULL(mSpellCloseUdr, cleanup1); + mSpellAddChangeUdr = (SpellAddChangeUdr_fn) GetProcAddress(mLibrary, "SpellAddChangeUdr"); CHECK_NULL(mSpellAddChangeUdr, cleanup1); + mSpellDelUdr = (SpellDelUdr_fn ) GetProcAddress(mLibrary, "SpellDelUdr" ); CHECK_NULL(mSpellDelUdr, cleanup1); + mSpellClearUdr = (SpellClearUdr_fn ) GetProcAddress(mLibrary, "SpellClearUdr" ); CHECK_NULL(mSpellClearUdr, cleanup1); + mSpellGetSizeUdr = (SpellGetSizeUdr_fn ) GetProcAddress(mLibrary, "SpellGetSizeUdr" ); CHECK_NULL(mSpellGetSizeUdr, cleanup1); + mSpellGetListUdr = (SpellGetListUdr_fn ) GetProcAddress(mLibrary, "SpellGetListUdr" ); CHECK_NULL(mSpellGetListUdr, cleanup1); + mSpellVerifyMdr = (SpellVerifyMdr_fn ) GetProcAddress(mLibrary, "SpellVerifyMdr" ); CHECK_NULL(mSpellVerifyMdr, cleanup1); + + memset(&mSIB, 0, sizeof(mSIB)); + memset(&mSRB, 0, sizeof(mSRB)); + memset(&mMDRS, 0, sizeof(mMDRS)); + mSLID = mUDR = 0; + + SEC sec; + +// word w1, w2, w3; +// mSpellVer(&w1, &w2, &w3); + + WSC wsc; + memset(&wsc, 0, sizeof(wsc)); + sec = mSpellInit(&mSLID, &wsc); + CHECK_SEC(cleanup1); + + sec = mSpellOpenMdr(mSLID, mDictionary, 0, 0, 1, mLIDC, &mMDRS); + CHECK_SEC(cleanup2); + + mSIB.cMdr = 1; + mSIB.lrgMdr = &mMDRS.mdr; + + sec = mSpellOptions(mSLID, SC_SO_SuggestFromUserDict|SC_SO_IgnoreAllCaps|SC_SO_IgnoreMixedDigits|SC_SO_IgnoreRomanNumerals|SC_SO_RateSuggestions); + CHECK_SEC(cleanup2); + + if (userdic) + { + BOOL ronly = FALSE; + sec = mSpellOpenUdr(mSLID, (char*)userdic, TRUE, 0xfffe, &mUDR, &ronly); + + if ((sec & 0xFF) == SC_SEC_NoErrors) + { + mSIB.cUdr = 1; + mSIB.lrgUdr = &mUDR; + } + } + + result = true; + goto cleanup0; + +cleanup2: + mSpellTerminate(mSLID, TRUE); +cleanup1: + FreeLibrary(mLibrary); + mLibrary = NULL; +cleanup0: + return result; +} + + +// ------------------------------------------------------------------ + +void CSpellLang::UnLoad() +{ + if (!mLibrary) return; + + if (mSIB.cUdr) mSpellCloseUdr(mSLID, mUDR, TRUE); + if (mSIB.cMdr) mSpellCloseMdr(mSLID, &mMDRS); + + FreeLibrary(mLibrary); + mLibrary = NULL; +} + + +// ------------------------------------------------------------------ + +bool CSpellLang::SpellCheck(const char *text) +{ + if (!IsLoaded()) return true; + + mSIB.wSpellState = 0; + mSIB.lrgChr = (char*)text; + mSIB.cChr = strlen(text); + + mSRB.cChr = sizeof(mSZ); + mSRB.cbRate = sizeof(mRate); + mSRB.lrgSZ = mSZ; + mSRB.lrgbRate = mRate; + + SEC error = mSpellCheck(mSLID, SC_SCCC_VerifyBuffer, &mSIB, &mSRB); + if (error & 0xFF) return false; + + return mSRB.scrs == SC_SRCS_NoErrors; +} + + +// ------------------------------------------------------------------ + +bool CSpellLang::SpellSuggest(const char *text, bool more) +{ + if (!IsLoaded()) return false; + + mSIB.wSpellState = 0; + mSIB.lrgChr = (char*)text; + mSIB.cChr = strlen(text); + + mSRB.cChr = sizeof(mSZ); + mSRB.cbRate = sizeof(mRate); + mSRB.lrgSZ = mSZ; + mSRB.lrgbRate = mRate; + + SEC error = mSpellCheck(mSLID, more ? SC_SCCC_SuggestMore : SC_SCCC_Suggest, &mSIB, &mSRB); + if (error & 0xFF) return false; + + return mSRB.scrs == SC_SRCS_NoErrors; +} + + +// ------------------------------------------------------------------ + +bool CSpellLang::AddWord(const char *text) +{ + if (!IsLoaded()) return false; + SEC error = mSpellAddUdr(mSLID, mUDR, (char*)text); + return (error & 0xFF) == 0; +} + + +// ------------------------------------------------------------------ + +CSpellChecker::CSpellChecker() +{ + mInited = false; + mLang = NULL; + mText[0] = 0; +} + +// ------------------------------------------------------------------ + +bool CSpellChecker::Init() +{ + int error; + unsigned long index = 0; + + HKEY hKeyPTools; + HKEY hKeySpelling; + + error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SC_RKEY_Prooftools, 0, KEY_READ, &hKeyPTools); + CHECK_ERROR(cleanup0); + + error = RegOpenKeyEx(hKeyPTools, SC_RKEY_Spelling, 0, KEY_READ, &hKeySpelling); + CHECK_ERROR(cleanup1); + + do + { + char name[1024]; + unsigned long nsize = sizeof(name); + + error = RegEnumKeyEx(hKeySpelling, index, name, &nsize, NULL, NULL, NULL, NULL); + if (error == ERROR_SUCCESS) + { + strcat(name, "\\Normal"); + AddLanguage(hKeySpelling, name); + index++; + } + } + while (error != ERROR_NO_MORE_ITEMS); + + RegCloseKey(hKeySpelling); +cleanup1: + RegCloseKey(hKeyPTools); +cleanup0: + return mInited = (mLangs.size() > 0); +} + + +// ------------------------------------------------------------------ + +void CSpellChecker::Close() +{ + if (!IsInited()) return; + mLangs.clear(); + mInited = false; + mLang = NULL; +} + + +// ------------------------------------------------------------------ + +bool CSpellChecker::Load(word lic, const char *userdic) +{ + if (!IsInited()) return false; + + std::vector::iterator it; + for (it = mLangs.begin(); it != mLangs.end(); it++) + { + if ((it->GetLangCode() == lic) && it->Load(userdic)) + { + UnLoad(); + mLang = it; + break; + } + } + + return IsLoaded(); +} + + +// ------------------------------------------------------------------ + +void CSpellChecker::UnLoad() +{ + if (!IsLoaded()) return; + mLang->UnLoad(); + mLang = NULL; +} + + +// ------------------------------------------------------------------ + +bool CSpellChecker::Check(const char *text) +{ + if (!IsLoaded()) return true; + + OemToChar(text, mText); + return mLang->SpellCheck(mText); +} + + +// ------------------------------------------------------------------ + +CSpellSuggestV &CSpellChecker::Suggest() +{ + mSuggest.clear(); + if (!IsLoaded()) return mSuggest; + if (!mLang->SpellSuggest(mText, false)) return mSuggest; + + bool flag = true; + bool more = false; + + for (int idx = 0; idx < mLang->mSRB.cChrMac; idx++) + { + if (mLang->mSZ[idx] == 0) { idx++; flag = true; } + + if (flag && mLang->mSZ[idx]) + { + flag = false; + CharToOem(&mLang->mSZ[idx], &mLang->mSZ[idx]); + mSuggest.push_back(std::pair(0, " " + std::string(&mLang->mSZ[idx]) + char(' '))); + } + else if (!more && !mLang->mSZ[idx]) + { + more = true; + + if (!mLang->SpellSuggest(mText, more = true)) + return mSuggest; + else + { + flag = true; + idx = -1; + } + } + } + + return mSuggest; +} + + +// ------------------------------------------------------------------ + +#undef CHECK_ERROR +#undef CHECK_NULL +#undef CHECK_SEC + + +// ------------------------------------------------------------------ + +#endif // #if defined(__WIN32__) + + +// ------------------------------------------------------------------ + +#endif // #if defined(__GOLD_SPELL__) + +// ------------------------------------------------------------------ diff --git a/goldlib/gall/gespell.h b/goldlib/gall/gespell.h new file mode 100644 index 0000000..c6270a0 --- /dev/null +++ b/goldlib/gall/gespell.h @@ -0,0 +1,235 @@ + +// ------------------------------------------------------------------ +// GoldED+ +// Copyright (C) 1990-1999 Odinn Sorensen +// Copyright (C) 1999-2000 Alexander S. Aganichev +// ------------------------------------------------------------------ +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program 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 +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, +// MA 02111-1307 USA +// ------------------------------------------------------------------ +// $Id$ +// ------------------------------------------------------------------ +// SpellChecker Structures and Classes. +// ------------------------------------------------------------------ + +#ifndef __GESPELL_H__ +#define __GESPELL_H__ + + +// ------------------------------------------------------------------ + +#if defined(__GOLD_SPELL__) + + +// ------------------------------------------------------------------ + +#if defined(__WIN32__) + + +// ------------------------------------------------------------------ + +typedef uint32_t MDR; // Main Dictionary Reference +typedef uint32_t UDR; // User Dictionary Reference +typedef uint16_t SEC; // Spell Error Code +typedef uint16_t LIDC; // Language Identifier Code +typedef uint16_t SCCC; // Spell Check Command Code +typedef uint32_t SLID; // Spell Id type +typedef uint16_t SCIS; // Spell Check Input Status +typedef uint16_t SCRS; // Spell Check Return Status + +typedef struct WizSpecChars +{ + byte bIgnore; + byte bHyphenHard; + byte bHyphenSoft; + byte bHyphenNonBreaking; + byte bEmDash; + byte bEnDash; + byte bEllipsis; + byte rgLineBreak[2]; + byte rgParaBreak[2]; +} WSC; + +typedef struct SpellInputBuffer +{ + word cChr; // Total characters in buffer area + word cMdr; // Count of MDR's specified in lrgMdr + word cUdr; // Count of UDR's specified in lrgUdr + word wSpellState; // State relative to previous SpellCheck call + char *lrgChr; // Pointer to text to be spell checked + MDR *lrgMdr; // List of main dicts to use when spelling the buffer + UDR *lrgUdr; // List of user dicts to use when spelling the buffer +} SIB; + +typedef struct SpellReturnBuffer +{ + // These fields are set by the SpellCheck() function + word iChrErr; // Position in the SIB + word cChrErr; // Length of error "word" in SIB + SCRS scrs; // Spell check return status + word cSZ; // Count of sz's put in buffer + word cChrMac; // Current total of chars in buffer + + // These fields MUST be set by the app, NULL pointers are invalid + word cChr; // Total space in lrgSZ + char *lrgSZ; // Ptr to alternatives format: word\0word\0...word\0\0 + byte *lrgbRate; // Ptr to Rating value for each suggest returned + word cbRate; // Number of elements in lrgbRate +} SRB; + +typedef struct mdrs +{ + MDR mdr; + LIDC lidc; + UDR udr; +} MDRS; + +typedef SEC (*SpellVer_fn ) (word*, word*, word*); +typedef SEC (*SpellInit_fn ) (SLID*, WSC*); +typedef SEC (*SpellOptions_fn ) (SLID, dword); +typedef SEC (*SpellCheck_fn ) (SLID, SCCC, SIB*, SRB*); +typedef SEC (*SpellTerminate_fn ) (SLID, BOOL); +typedef SEC (*SpellOpenMdr_fn ) (SLID, char*, char*, BOOL, BOOL, LIDC, MDRS*); +typedef SEC (*SpellCloseMdr_fn ) (SLID, MDRS*); +typedef SEC (*SpellOpenUdr_fn ) (SLID, char*, BOOL, word, UDR*, BOOL*); +typedef SEC (*SpellAddUdr_fn ) (SLID, UDR, char*); +typedef SEC (*SpellCloseUdr_fn ) (SLID, UDR, BOOL); +typedef SEC (*SpellAddChangeUdr_fn) (SLID, UDR, char*, char*); +typedef SEC (*SpellDelUdr_fn ) (SLID, UDR, char*); +typedef SEC (*SpellClearUdr_fn ) (SLID, UDR); +typedef SEC (*SpellGetSizeUdr_fn ) (SLID, UDR, word*); +typedef SEC (*SpellGetListUdr_fn ) (SLID, UDR, word, SRB*); +typedef SEC (*SpellVerifyMdr_fn ) (char*, LIDC, LIDC*); + +class CSpellLang +{ + friend class CSpellChecker; + +private: + LIDC mLIDC; + SLID mSLID; + MDRS mMDRS; + UDR mUDR; + SIB mSIB; + SRB mSRB; + + char mSZ[1024]; + byte mRate[1024]; + + char mEngine[_MAX_PATH]; + char mDictionary[_MAX_PATH]; + + HINSTANCE mLibrary; + + SpellVer_fn mSpellVer; + SpellInit_fn mSpellInit; + SpellOptions_fn mSpellOptions; + SpellCheck_fn mSpellCheck; + SpellTerminate_fn mSpellTerminate; + SpellOpenMdr_fn mSpellOpenMdr; + SpellCloseMdr_fn mSpellCloseMdr; + SpellOpenUdr_fn mSpellOpenUdr; + SpellAddUdr_fn mSpellAddUdr; + SpellCloseUdr_fn mSpellCloseUdr; + SpellAddChangeUdr_fn mSpellAddChangeUdr; + SpellDelUdr_fn mSpellDelUdr; + SpellClearUdr_fn mSpellClearUdr; + SpellGetSizeUdr_fn mSpellGetSizeUdr; + SpellGetListUdr_fn mSpellGetListUdr; + SpellVerifyMdr_fn mSpellVerifyMdr; + +public: + CSpellLang() { mLibrary = NULL; } + ~CSpellLang() { Close(); } + + bool Init(HKEY hKey, const char *name); + void Close() { UnLoad(); } + + bool Load(const char *userdic); + void UnLoad(); + + bool SpellCheck(const char *text); + bool SpellSuggest(const char *text, bool more); + bool AddWord(const char *text); + + LIDC GetLangCode() { return mLIDC; } + + bool IsLoaded() { return mLibrary != NULL; } +}; + + +typedef std::vector< std::pair > CSpellSuggestV; +typedef std::vector CSpellLangV; + +class CSpellChecker +{ +private: + bool mInited; + char mText[1024]; + + CSpellLang *mLang; + CSpellLangV mLangs; + CSpellSuggestV mSuggest; + +private: + void AddLanguage(HKEY hKey, const char *name) + { + CSpellLang lang; + + if (lang.Init(hKey, name)) + mLangs.push_back(lang); + } + +public: + CSpellChecker(); + ~CSpellChecker() { Close(); } + + bool Init(); + void Close(); + + bool Load(word lic, const char *userdic = NULL); + void UnLoad(); + + bool Check(const char *text); + CSpellSuggestV &Suggest(); + + bool Check(std::string &text) { return Check(text.c_str()); } + bool AddWord() { return IsLoaded() ? mLang->AddWord(mText) : false; }; + + CSpellSuggestV &GetSuggest() { return mSuggest; } + CSpellLangV &GetLangs() { return mLangs; } + LIDC GetLangCode() { return IsLoaded() ? mLang->GetLangCode() : 0xFFFF; } + + bool IsInited() { return mInited; } + bool IsLoaded() { return mLang != NULL; } +}; + + +// ------------------------------------------------------------------ + +#endif //#if defined(__WIN32__) + + +// ------------------------------------------------------------------ + +#endif //#if defined(__GOLD_SPELL__) + + +// ------------------------------------------------------------------ + +#endif //#ifndef __GESPELL_H__ + + +// ------------------------------------------------------------------