#include #define LLOG(x) // LOG(x) #define LTIMING(x) RTIMING(x) using namespace Upp; struct SpellFile : Moveable { }; String spell_path; static StaticMutex spellmutex; void SetSpellPath(const String& p) { INTERLOCKED_(spellmutex) { spell_path = p; } } static String sZet(FileIn& in, int offset, int len) { in.Seek(offset); return ZDecompress(in.Get(len)); } bool SpellWordRaw(int lang, const WString& wrd) { LTIMING("SpellWordRaw"); LLOG("SpellWordRaw " << wrd << ' ' << LNGAsText(lang)); static VectorMap spellfile; int q = spellfile.Find(lang); if(q < 0) { String pp; String dir = ConfigFile("scd"); for(;;) { pp << dir << ';'; String d = GetFileFolder(dir); if(d == dir) break; dir = d; } pp << spell_path << ';' << getenv("LIB") << ';' << getenv("PATH") << ';'; String path = GetFileOnPath(LNGAsText(lang) + ".scd", pp); if(IsNull(path)) return true; FileIn in(path); if(!in || in.Get() != 255) return true; q = spellfile.GetCount(); SpellFile& f = spellfile.Add(lang); f.path = path; int n = in.GetL(); LLOG("Found scd file " << path << " blocks " << n); if(n > 0 && n < 100000) { for(int i = 0; i < n; i++) { SpellBlock& b = f.block.Add(); b.first = in.Get(in.Get()); b.ctrl_len = in.GetL(); b.text_len = in.GetL(); } if(in.IsEof()) f.block.Clear(); else { int off = (int)in.GetPos(); for(int i = 0; i < n; i++) { SpellBlock& b = f.block[i]; b.offset = off; off += b.ctrl_len + b.text_len; } } } } const SpellFile& f = spellfile[q]; String awrd = ToUpper(ToAscii(wrd).ToString()); String t1 = ToUtf8(wrd); String t2 = ToUtf8(ToLower(wrd)); // DDUMP(awrd); for(int i = 0;; i++) { // if(i + 1 < f.block.GetCount()) // DDUMP(f.block[i + 1].first); if(i + 1 >= f.block.GetCount() || awrd <= f.block[i + 1].first) { for(;;) { if(i >= f.block.GetCount()) return false; LLOG("Spell block " << i << ": " << f.block[i].first); const SpellBlock& b = f.block[i++]; if(b.first > awrd) { LLOG(" --- false"); return false; } FileIn in(f.path); String ctrl = sZet(in, b.offset, b.ctrl_len); String text = sZet(in, b.offset + b.ctrl_len, b.text_len); in.Close(); // LTIMING("Search"); String w; const char *s = ctrl; const char *e = ctrl.End(); const char *t = text; const char *te = text.End(); while(s < e && t < te) { w.Trim(*s++); while(*t) w.Cat(*t++); // DDUMP(w); if(w == t1 || w == t2) return true; t++; } } } } return false; } struct SpellKey : Moveable { int lang; WString wrd; unsigned GetHashValue() const { return CombineHash(lang, wrd); } bool operator==(const SpellKey& b) const { return lang == b.lang && wrd == b.wrd; } }; struct SpellMaker : LRUCache::Maker { SpellKey k; SpellKey Key() const { return k; } int Make(bool& r) const { r = SpellWordRaw(k.lang, k.wrd); return 1; } }; bool SpellWord(int lang, const WString& wrd) { INTERLOCKED_(spellmutex) { static LRUCache cache; cache.Shrink(2000); SpellMaker m; m.k.lang = lang; m.k.wrd = wrd; return cache.Get(m); } } bool SpellWord(int lang, const String& wrd) { return SpellWord(lang, wrd.ToWString()); } bool Spell(const char *s) { RDUMP(s); return SpellWord(LNG_('C','S','C','Z'), String(s)); } CONSOLE_APP_MAIN { SetSpellPath("D:\\"); FileIn in("D:\\src.txt"); int n = 0; while(!in.IsEof()) { String s = in.GetLine(); if(n++ % 10000 == 0) Cout() << n << ' ' << s << "\n"; if(!Spell(s)) { RLOG("Error: " << s); Cout() << "Error: " << s << '\n'; break; } s << "asdf"; if(Spell(s)) { RLOG("Error: " << s); Cout() << "Error: " << s << '\n'; break; } } }