Updated hunspell to 1.3.2
authorSven Strickroth <email@cs-ware.de>
Sun, 24 Mar 2013 16:42:12 +0000 (24 17:42 +0100)
committerSven Strickroth <email@cs-ware.de>
Sun, 24 Mar 2013 16:55:56 +0000 (24 17:55 +0100)
Also synced with TortoiseSVN so that it matches revision 24024.

Signed-off-by: Sven Strickroth <email@cs-ware.de>
35 files changed:
ext/hunspell/affentry.cxx
ext/hunspell/affentry.hxx
ext/hunspell/affixmgr.cxx
ext/hunspell/affixmgr.hxx
ext/hunspell/atypes.hxx
ext/hunspell/baseaffix.hxx
ext/hunspell/config.h
ext/hunspell/csutil.cxx
ext/hunspell/csutil.hxx
ext/hunspell/dictmgr.cxx
ext/hunspell/dictmgr.hxx
ext/hunspell/filemgr.cxx [new file with mode: 0644]
ext/hunspell/filemgr.hxx [new file with mode: 0644]
ext/hunspell/hashmgr.cxx
ext/hunspell/hashmgr.hxx
ext/hunspell/htypes.hxx
ext/hunspell/hunspell.cxx
ext/hunspell/hunspell.h
ext/hunspell/hunspell.hxx
ext/hunspell/hunspell.vcxproj
ext/hunspell/hunspell.vcxproj.filters
ext/hunspell/hunvisapi.h [new file with mode: 0644]
ext/hunspell/hunvisapi.h.in [new file with mode: 0644]
ext/hunspell/hunzip.cxx [new file with mode: 0644]
ext/hunspell/hunzip.hxx [new file with mode: 0644]
ext/hunspell/license.hunspell
ext/hunspell/phonet.cxx [new file with mode: 0644]
ext/hunspell/phonet.hxx [new file with mode: 0644]
ext/hunspell/replist.cxx [new file with mode: 0644]
ext/hunspell/replist.hxx [new file with mode: 0644]
ext/hunspell/suggestmgr.cxx
ext/hunspell/suggestmgr.hxx
ext/hunspell/utf_info.cxx
ext/hunspell/w_char.hxx [new file with mode: 0644]
src/TortoiseProc/TortoiseProc.vcxproj

index ce727b0..246084e 100644 (file)
@@ -1,50 +1,37 @@
 #include "license.hunspell"\r
 #include "license.myspell"\r
 \r
-#ifndef MOZILLA_CLIENT\r
-#include <cstdlib>\r
-#include <cstring>\r
-#include <cctype>\r
-#include <cstdio>\r
-#else\r
-#include <stdlib.h> \r
+#include <stdlib.h>\r
 #include <string.h>\r
-#include <stdio.h> \r
+#include <stdio.h>\r
 #include <ctype.h>\r
-#endif\r
 \r
 #include "affentry.hxx"\r
 #include "csutil.hxx"\r
 \r
-#ifndef MOZILLA_CLIENT\r
-#ifndef W32\r
-using namespace std;\r
-#endif\r
-#endif\r
-\r
-\r
 PfxEntry::PfxEntry(AffixMgr* pmgr, affentry* dp)\r
 {\r
   // register affix manager\r
   pmyMgr = pmgr;\r
 \r
-  // set up its intial values\r
\r
-  aflag = dp->aflag;         // flag \r
+  // set up its initial values\r
+\r
+  aflag = dp->aflag;         // flag\r
   strip = dp->strip;         // string to strip\r
   appnd = dp->appnd;         // string to append\r
   stripl = dp->stripl;       // length of strip string\r
   appndl = dp->appndl;       // length of append string\r
-  numconds = dp->numconds;   // number of conditions to match\r
-  opts = dp->opts;         // cross product flag\r
+  numconds = dp->numconds;   // length of the condition\r
+  opts = dp->opts;           // cross product flag\r
   // then copy over all of the conditions\r
-  memcpy(&conds.base[0],&dp->conds.base[0],SETSIZE*sizeof(conds.base[0]));\r
+  if (opts & aeLONGCOND) {\r
+    memcpy(c.conds, dp->c.l.conds1, MAXCONDLEN_1);\r
+    c.l.conds2 = dp->c.l.conds2;\r
+  } else memcpy(c.conds, dp->c.conds, MAXCONDLEN);\r
   next = NULL;\r
   nextne = NULL;\r
   nexteq = NULL;\r
-#ifdef HUNSPELL_EXPERIMENTAL\r
   morphcode = dp->morphcode;\r
-#endif\r
   contclass = dp->contclass;\r
   contclasslen = dp->contclasslen;\r
 }\r
@@ -58,14 +45,8 @@ PfxEntry::~PfxEntry()
     pmyMgr = NULL;\r
     appnd = NULL;\r
     strip = NULL;\r
-    if (opts & aeUTF8) {\r
-        for (int i = 0; i < 8; i++) {\r
-            if (conds.utf8.wchars[i]) free(conds.utf8.wchars[i]);\r
-        }\r
-    }\r
-#ifdef HUNSPELL_EXPERIMENTAL\r
+    if (opts & aeLONGCOND) free(c.l.conds2);\r
     if (morphcode && !(opts & aeALIASM)) free(morphcode);\r
-#endif\r
     if (contclass && !(opts & aeALIASF)) free(contclass);\r
 }\r
 \r
@@ -74,8 +55,9 @@ char * PfxEntry::add(const char * word, int len)
 {\r
     char tword[MAXWORDUTF8LEN + 4];\r
 \r
-    if ((len > stripl) && (len >= numconds) && test_condition(word) &&\r
-       (!stripl || (strncmp(word, strip, stripl) == 0)) && \r
+    if ((len > stripl || (len == 0 && pmyMgr->get_fullstrip())) && \r
+       (len >= numconds) && test_condition(word) &&\r
+       (!stripl || (strncmp(word, strip, stripl) == 0)) &&\r
        ((MAXWORDUTF8LEN + 4) > (len + appndl - stripl))) {\r
     /* we have a match so add prefix */\r
               char * pp = tword;\r
@@ -86,51 +68,87 @@ char * PfxEntry::add(const char * word, int len)
                strcpy(pp, (word + stripl));\r
                return mystrdup(tword);\r
      }\r
-     return NULL;    \r
+     return NULL;\r
 }\r
 \r
+inline char * PfxEntry::nextchar(char * p) {\r
+    if (p) {\r
+        p++;\r
+        if (opts & aeLONGCOND) {\r
+            // jump to the 2nd part of the condition\r
+            if (p == c.conds + MAXCONDLEN_1) return c.l.conds2;\r
+        // end of the MAXCONDLEN length condition\r
+        } else if (p == c.conds + MAXCONDLEN) return NULL;\r
+       return *p ? p : NULL;\r
+    }\r
+    return NULL;\r
+}\r
 \r
 inline int PfxEntry::test_condition(const char * st)\r
 {\r
-    int cond;\r
-    unsigned char * cp = (unsigned char *)st;\r
-    if (!(opts & aeUTF8)) { // 256-character codepage\r
-        for (cond = 0;  cond < numconds;  cond++) {\r
-            if ((conds.base[*cp++] & (1 << cond)) == 0) return 0;\r
-        }\r
-    } else { // UTF-8 encoding\r
-      unsigned short wc;\r
-      for (cond = 0;  cond < numconds;  cond++) {\r
-        // a simple 7-bit ASCII character in UTF-8\r
-        if ((*cp >> 7) == 0) {\r
-            // also check limit (end of word)\r
-            if ((!*cp) || ((conds.utf8.ascii[*cp++] & (1 << cond)) == 0)) return 0;\r
-        // UTF-8 multibyte character\r
-        } else {\r
-            // not dot wildcard in rule\r
-            if (!conds.utf8.all[cond]) {\r
-                if (conds.utf8.neg[cond]) {\r
-                    u8_u16((w_char *) &wc, 1, (char *) cp);\r
-                    if (conds.utf8.wchars[cond] && \r
-                        flag_bsearch((unsigned short *)conds.utf8.wchars[cond],\r
-                            wc, (short) conds.utf8.wlen[cond])) return 0;\r
-                } else {\r
-                    if (!conds.utf8.wchars[cond]) return 0;\r
-                    u8_u16((w_char *) &wc, 1, (char *) cp);\r
-                    if (!flag_bsearch((unsigned short *)conds.utf8.wchars[cond],\r
-                         wc, (short)conds.utf8.wlen[cond])) return 0;\r
-                }\r
+    const char * pos = NULL; // group with pos input position\r
+    bool neg = false;        // complementer\r
+    bool ingroup = false;    // character in the group\r
+    if (numconds == 0) return 1;\r
+    char * p = c.conds;\r
+    while (1) {\r
+      switch (*p) {\r
+        case '\0': return 1;\r
+        case '[': { \r
+                neg = false;\r
+                ingroup = false;\r
+                p = nextchar(p);\r
+                pos = st; break;\r
+            }\r
+        case '^': { p = nextchar(p); neg = true; break; }\r
+        case ']': { \r
+                if ((neg && ingroup) || (!neg && !ingroup)) return 0;\r
+                pos = NULL;\r
+                p = nextchar(p);\r
+                // skip the next character\r
+                if (!ingroup && *st) for (st++; (opts & aeUTF8) && (*st & 0xc0) == 0x80; st++);\r
+                if (*st == '\0' && p) return 0; // word <= condition\r
+                break;\r
+            }\r
+         case '.': if (!pos) { // dots are not metacharacters in groups: [.]\r
+                p = nextchar(p);\r
+                // skip the next character\r
+                for (st++; (opts & aeUTF8) && (*st & 0xc0) == 0x80; st++);\r
+                if (*st == '\0' && p) return 0; // word <= condition\r
+                break;\r
+            }\r
+    default: {\r
+                if (*st == *p) {\r
+                    st++;\r
+                    p = nextchar(p);\r
+                    if ((opts & aeUTF8) && (*(st - 1) & 0x80)) { // multibyte\r
+                        while (p && (*p & 0xc0) == 0x80) {       // character\r
+                            if (*p != *st) {\r
+                                if (!pos) return 0;\r
+                                st = pos;\r
+                                break;\r
+                            }\r
+                            p = nextchar(p);\r
+                            st++;\r
+                        }\r
+                        if (pos && st != pos) {\r
+                            ingroup = true;\r
+                            while (p && *p != ']' && (p = nextchar(p)));\r
+                        }\r
+                    } else if (pos) {\r
+                        ingroup = true;\r
+                        while (p && *p != ']' && (p = nextchar(p)));\r
+                    }\r
+                } else if (pos) { // group\r
+                    p = nextchar(p);\r
+                } else return 0;\r
             }\r
-            // jump to next UTF-8 character\r
-            for(cp++; (*cp & 0xc0) == 0x80; cp++);\r
-        }\r
       }\r
+      if (!p) return 1;\r
     }\r
-    return 1;\r
 }\r
 \r
-\r
-// check if this prefix entry matches \r
+// check if this prefix entry matches\r
 struct hentry * PfxEntry::checkword(const char * word, int len, char in_compound, const FLAG needflag)\r
 {\r
     int                 tmpl;   // length of tmpword\r
@@ -144,7 +162,7 @@ struct hentry * PfxEntry::checkword(const char * word, int len, char in_compound
 \r
      tmpl = len - appndl;\r
 \r
-     if ((tmpl > 0) &&  (tmpl + stripl >= numconds)) {\r
+     if (tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) {\r
 \r
             // generate new root word by removing prefix and adding\r
             // back any characters that would have been stripped\r
@@ -165,8 +183,8 @@ struct hentry * PfxEntry::checkword(const char * word, int len, char in_compound
                 if ((he = pmyMgr->lookup(tmpword)) != NULL) {\r
                    do {\r
                       if (TESTAFF(he->astr, aflag, he->alen) &&\r
-                        // forbid single prefixes with pseudoroot flag\r
-                        ! TESTAFF(contclass, pmyMgr->get_pseudoroot(), contclasslen) &&\r
+                        // forbid single prefixes with needaffix flag\r
+                        ! TESTAFF(contclass, pmyMgr->get_needaffix(), contclasslen) &&\r
                         // needflag\r
                         ((!needflag) || TESTAFF(he->astr, needflag, he->alen) ||\r
                          (contclass && TESTAFF(contclass, needflag, contclasslen))))\r
@@ -174,14 +192,14 @@ struct hentry * PfxEntry::checkword(const char * word, int len, char in_compound
                       he = he->next_homonym; // check homonyms\r
                    } while (he);\r
                 }\r
-                \r
-                // prefix matched but no root word was found \r
-                // if aeXPRODUCT is allowed, try again but now \r
+\r
+                // prefix matched but no root word was found\r
+                // if aeXPRODUCT is allowed, try again but now\r
                 // ross checked combined with a suffix\r
 \r
                 //if ((opts & aeXPRODUCT) && in_compound) {\r
                 if ((opts & aeXPRODUCT)) {\r
-                   he = pmyMgr->suffix_check(tmpword, tmpl, aeXPRODUCT, (AffEntry *)this, NULL, \r
+                   he = pmyMgr->suffix_check(tmpword, tmpl, aeXPRODUCT, this, NULL,\r
                         0, NULL, FLAG_NULL, needflag, in_compound);\r
                    if (he) return he;\r
                 }\r
@@ -190,7 +208,7 @@ struct hentry * PfxEntry::checkword(const char * word, int len, char in_compound
     return NULL;\r
 }\r
 \r
-// check if this prefix entry matches \r
+// check if this prefix entry matches\r
 struct hentry * PfxEntry::check_twosfx(const char * word, int len,\r
     char in_compound, const FLAG needflag)\r
 {\r
@@ -205,7 +223,8 @@ struct hentry * PfxEntry::check_twosfx(const char * word, int len,
 \r
      tmpl = len - appndl;\r
 \r
-     if ((tmpl > 0) &&  (tmpl + stripl >= numconds)) {\r
+     if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) &&\r
+        (tmpl + stripl >= numconds)) {\r
 \r
             // generate new root word by removing prefix and adding\r
             // back any characters that would have been stripped\r
@@ -224,12 +243,12 @@ struct hentry * PfxEntry::check_twosfx(const char * word, int len,
             if (test_condition(tmpword)) {\r
                 tmpl += stripl;\r
 \r
-                // prefix matched but no root word was found \r
-                // if aeXPRODUCT is allowed, try again but now \r
+                // prefix matched but no root word was found\r
+                // if aeXPRODUCT is allowed, try again but now\r
                 // cross checked combined with a suffix\r
 \r
                 if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) {\r
-                   he = pmyMgr->suffix_check_twosfx(tmpword, tmpl, aeXPRODUCT, (AffEntry *)this, needflag);\r
+                   he = pmyMgr->suffix_check_twosfx(tmpword, tmpl, aeXPRODUCT, this, needflag);\r
                    if (he) return he;\r
                 }\r
             }\r
@@ -237,8 +256,7 @@ struct hentry * PfxEntry::check_twosfx(const char * word, int len,
     return NULL;\r
 }\r
 \r
-#ifdef HUNSPELL_EXPERIMENTAL\r
-// check if this prefix entry matches \r
+// check if this prefix entry matches\r
 char * PfxEntry::check_twosfx_morph(const char * word, int len,\r
          char in_compound, const FLAG needflag)\r
 {\r
@@ -252,7 +270,8 @@ char * PfxEntry::check_twosfx_morph(const char * word, int len,
 \r
      tmpl = len - appndl;\r
 \r
-     if ((tmpl > 0) &&  (tmpl + stripl >= numconds)) {\r
+     if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) &&\r
+        (tmpl + stripl >= numconds)) {\r
 \r
             // generate new root word by removing prefix and adding\r
             // back any characters that would have been stripped\r
@@ -271,20 +290,20 @@ char * PfxEntry::check_twosfx_morph(const char * word, int len,
             if (test_condition(tmpword)) {\r
                 tmpl += stripl;\r
 \r
-                // prefix matched but no root word was found \r
-                // if aeXPRODUCT is allowed, try again but now \r
+                // prefix matched but no root word was found\r
+                // if aeXPRODUCT is allowed, try again but now\r
                 // ross checked combined with a suffix\r
 \r
                 if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) {\r
                     return pmyMgr->suffix_check_twosfx_morph(tmpword, tmpl,\r
-                             aeXPRODUCT, (AffEntry *)this, needflag);\r
+                             aeXPRODUCT, this, needflag);\r
                 }\r
             }\r
      }\r
     return NULL;\r
 }\r
 \r
-// check if this prefix entry matches \r
+// check if this prefix entry matches\r
 char * PfxEntry::check_morph(const char * word, int len, char in_compound, const FLAG needflag)\r
 {\r
     int                 tmpl;   // length of tmpword\r
@@ -292,7 +311,7 @@ char * PfxEntry::check_morph(const char * word, int len, char in_compound, const
     char                tmpword[MAXWORDUTF8LEN + 4];\r
     char                result[MAXLNLEN];\r
     char * st;\r
-    \r
+\r
     *result = '\0';\r
 \r
     // on entry prefix is 0 length or already matches the beginning of the word.\r
@@ -302,7 +321,8 @@ char * PfxEntry::check_morph(const char * word, int len, char in_compound, const
 \r
      tmpl = len - appndl;\r
 \r
-     if ((tmpl > 0) &&  (tmpl + stripl >= numconds)) {\r
+     if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) &&\r
+        (tmpl + stripl >= numconds)) {\r
 \r
             // generate new root word by removing prefix and adding\r
             // back any characters that would have been stripped\r
@@ -323,64 +343,79 @@ char * PfxEntry::check_morph(const char * word, int len, char in_compound, const
                 if ((he = pmyMgr->lookup(tmpword)) != NULL) {\r
                     do {\r
                       if (TESTAFF(he->astr, aflag, he->alen) &&\r
-                        // forbid single prefixes with pseudoroot flag\r
-                        ! TESTAFF(contclass, pmyMgr->get_pseudoroot(), contclasslen) &&\r
+                        // forbid single prefixes with needaffix flag\r
+                        ! TESTAFF(contclass, pmyMgr->get_needaffix(), contclasslen) &&\r
                         // needflag\r
                         ((!needflag) || TESTAFF(he->astr, needflag, he->alen) ||\r
                          (contclass && TESTAFF(contclass, needflag, contclasslen)))) {\r
-                            if (morphcode) strcat(result, morphcode); else strcat(result,getKey());\r
-                            if (he->description) {\r
-                                if ((*(he->description)=='[')||(*(he->description)=='<')) strcat(result,he->word);\r
-                                strcat(result,he->description);\r
+                            if (morphcode) {\r
+                                mystrcat(result, " ", MAXLNLEN);\r
+                                mystrcat(result, morphcode, MAXLNLEN);\r
+                            } else mystrcat(result,getKey(), MAXLNLEN);\r
+                            if (!HENTRY_FIND(he, MORPH_STEM)) {\r
+                                mystrcat(result, " ", MAXLNLEN);\r
+                                mystrcat(result, MORPH_STEM, MAXLNLEN);\r
+                                mystrcat(result, HENTRY_WORD(he), MAXLNLEN);\r
+                            }\r
+                            // store the pointer of the hash entry\r
+                            if (HENTRY_DATA(he)) {\r
+                                mystrcat(result, " ", MAXLNLEN);\r
+                                mystrcat(result, HENTRY_DATA2(he), MAXLNLEN);\r
+                            } else {\r
+                                // return with debug information\r
+                                char * flag = pmyMgr->encode_flag(getFlag());\r
+                                mystrcat(result, " ", MAXLNLEN);\r
+                                mystrcat(result, MORPH_FLAG, MAXLNLEN);\r
+                                mystrcat(result, flag, MAXLNLEN);\r
+                                free(flag);\r
                             }\r
-                            strcat(result, "\n");\r
+                            mystrcat(result, "\n", MAXLNLEN);\r
                       }\r
                       he = he->next_homonym;\r
                     } while (he);\r
                 }\r
 \r
-                // prefix matched but no root word was found \r
-                // if aeXPRODUCT is allowed, try again but now \r
+                // prefix matched but no root word was found\r
+                // if aeXPRODUCT is allowed, try again but now\r
                 // ross checked combined with a suffix\r
 \r
                 if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) {\r
-                   st = pmyMgr->suffix_check_morph(tmpword, tmpl, aeXPRODUCT, (AffEntry *)this, \r
+                   st = pmyMgr->suffix_check_morph(tmpword, tmpl, aeXPRODUCT, this,\r
                      FLAG_NULL, needflag);\r
                    if (st) {\r
-                        strcat(result, st);\r
+                        mystrcat(result, st, MAXLNLEN);\r
                         free(st);\r
                    }\r
                 }\r
             }\r
      }\r
-     \r
+    \r
     if (*result) return mystrdup(result);\r
     return NULL;\r
 }\r
-#endif // END OF HUNSPELL_EXPERIMENTAL CODE\r
 \r
 SfxEntry::SfxEntry(AffixMgr * pmgr, affentry* dp)\r
 {\r
   // register affix manager\r
   pmyMgr = pmgr;\r
 \r
-  // set up its intial values\r
-  aflag = dp->aflag;         // char flag \r
+  // set up its initial values\r
+  aflag = dp->aflag;         // char flag\r
   strip = dp->strip;         // string to strip\r
   appnd = dp->appnd;         // string to append\r
   stripl = dp->stripl;       // length of strip string\r
   appndl = dp->appndl;       // length of append string\r
-  numconds = dp->numconds;   // number of conditions to match\r
-  opts = dp->opts;         // cross product flag\r
+  numconds = dp->numconds;   // length of the condition\r
+  opts = dp->opts;           // cross product flag\r
 \r
   // then copy over all of the conditions\r
-  memcpy(&conds.base[0],&dp->conds.base[0],SETSIZE*sizeof(conds.base[0]));\r
+  if (opts & aeLONGCOND) {\r
+    memcpy(c.l.conds1, dp->c.l.conds1, MAXCONDLEN_1);\r
+    c.l.conds2 = dp->c.l.conds2;\r
+  } else memcpy(c.conds, dp->c.conds, MAXCONDLEN);\r
 \r
   rappnd = myrevstrdup(appnd);\r
-\r
-#ifdef HUNSPELL_EXPERIMENTAL\r
   morphcode = dp->morphcode;\r
-#endif\r
   contclass = dp->contclass;\r
   contclasslen = dp->contclasslen;\r
 }\r
@@ -394,15 +429,9 @@ SfxEntry::~SfxEntry()
     if (strip) free(strip);\r
     pmyMgr = NULL;\r
     appnd = NULL;\r
-    strip = NULL;    \r
-    if (opts & aeUTF8) {\r
-        for (int i = 0; i < 8; i++) {\r
-            if (conds.utf8.wchars[i]) free(conds.utf8.wchars[i]);  \r
-        }\r
-    }\r
-#ifdef HUNSPELL_EXPERIMENTAL\r
+    strip = NULL;\r
+    if (opts & aeLONGCOND) free(c.l.conds2);\r
     if (morphcode && !(opts & aeALIASM)) free(morphcode);\r
-#endif\r
     if (contclass && !(opts & aeALIASF)) free(contclass);\r
 }\r
 \r
@@ -412,7 +441,8 @@ char * SfxEntry::add(const char * word, int len)
     char                tword[MAXWORDUTF8LEN + 4];\r
 \r
      /* make sure all conditions match */\r
-     if ((len > stripl) && (len >= numconds) && test_condition(word + len, word) &&\r
+     if ((len > stripl || (len == 0 && pmyMgr->get_fullstrip())) &&\r
+        (len >= numconds) && test_condition(word + len, word) &&\r
         (!stripl || (strcmp(word + len - stripl, strip) == 0)) &&\r
         ((MAXWORDUTF8LEN + 4) > (len + appndl - stripl))) {\r
               /* we have a match so add suffix */\r
@@ -427,60 +457,118 @@ char * SfxEntry::add(const char * word, int len)
      return NULL;\r
 }\r
 \r
+inline char * SfxEntry::nextchar(char * p) {\r
+    if (p) {\r
+       p++;\r
+       if (opts & aeLONGCOND) {\r
+           // jump to the 2nd part of the condition\r
+           if (p == c.l.conds1 + MAXCONDLEN_1) return c.l.conds2;\r
+       // end of the MAXCONDLEN length condition\r
+       } else if (p == c.conds + MAXCONDLEN) return NULL;\r
+       return *p ? p : NULL;\r
+    }\r
+    return NULL;\r
+}\r
 \r
 inline int SfxEntry::test_condition(const char * st, const char * beg)\r
 {\r
-    int cond;\r
-    unsigned char * cp = (unsigned char *) st;\r
-    if (!(opts & aeUTF8)) { // 256-character codepage\r
-        // Dömölki affix algorithm\r
-        for (cond = numconds;  --cond >= 0; ) {\r
-            if ((conds.base[*--cp] & (1 << cond)) == 0) return 0;\r
-        }\r
-    } else { // UTF-8 encoding\r
-      unsigned short wc;\r
-      for (cond = numconds;  --cond >= 0; ) {\r
-        // go to next character position and check limit\r
-        if ((char *) --cp < beg) return 0;\r
-        // a simple 7-bit ASCII character in UTF-8\r
-        if ((*cp >> 7) == 0) {\r
-            if ((conds.utf8.ascii[*cp] & (1 << cond)) == 0) return 0;\r
-        // UTF-8 multibyte character\r
-        } else {\r
-            // go to first character of UTF-8 multibyte character\r
-            for (; (*cp & 0xc0) == 0x80; cp--);\r
-            // not dot wildcard in rule\r
-            if (!conds.utf8.all[cond]) {\r
-                if (conds.utf8.neg[cond]) {\r
-                    u8_u16((w_char *) &wc, 1, (char *) cp);\r
-                    if (conds.utf8.wchars[cond] && \r
-                        flag_bsearch((unsigned short *)conds.utf8.wchars[cond],\r
-                            wc, (short) conds.utf8.wlen[cond])) return 0;\r
-                } else {\r
-                    if (!conds.utf8.wchars[cond]) return 0;\r
-                    u8_u16((w_char *) &wc, 1, (char *) cp);\r
-                    if (!flag_bsearch((unsigned short *)conds.utf8.wchars[cond],\r
-                         wc, (short)conds.utf8.wlen[cond])) return 0;\r
+    const char * pos = NULL;    // group with pos input position\r
+    bool neg = false;           // complementer\r
+    bool ingroup = false;       // character in the group\r
+    if (numconds == 0) return 1;\r
+    char * p = c.conds;\r
+    st--;\r
+    int i = 1;\r
+    while (1) {\r
+      switch (*p) {\r
+        case '\0': return 1;\r
+        case '[': { p = nextchar(p); pos = st; break; }\r
+        case '^': { p = nextchar(p); neg = true; break; }\r
+        case ']': { if (!neg && !ingroup) return 0;\r
+                i++;\r
+                // skip the next character\r
+                if (!ingroup) {\r
+                    for (; (opts & aeUTF8) && (st >= beg) && (*st & 0xc0) == 0x80; st--);\r
+                    st--;\r
+                }                    \r
+                pos = NULL;\r
+                neg = false;\r
+                ingroup = false;\r
+                p = nextchar(p);\r
+                if (st < beg && p) return 0; // word <= condition\r
+                break;\r
+            }\r
+        case '.': if (!pos) { // dots are not metacharacters in groups: [.]\r
+                p = nextchar(p);\r
+                // skip the next character\r
+                for (st--; (opts & aeUTF8) && (st >= beg) && (*st & 0xc0) == 0x80; st--);\r
+                if (st < beg) { // word <= condition\r
+                   if (p) return 0; else return 1;\r
+               }\r
+                if ((opts & aeUTF8) && (*st & 0x80)) { // head of the UTF-8 character\r
+                    st--;\r
+                    if (st < beg) { // word <= condition\r
+                       if (p) return 0; else return 1;\r
+                   }\r
                 }\r
+                break;\r
+            }\r
+    default: {\r
+                if (*st == *p) {\r
+                    p = nextchar(p);\r
+                    if ((opts & aeUTF8) && (*st & 0x80)) {\r
+                        st--;\r
+                        while (p && (st >= beg)) {\r
+                            if (*p != *st) {\r
+                                if (!pos) return 0;\r
+                                st = pos;\r
+                                break;\r
+                            }\r
+                            // first byte of the UTF-8 multibyte character\r
+                            if ((*p & 0xc0) != 0x80) break;\r
+                            p = nextchar(p);\r
+                            st--;\r
+                        }\r
+                        if (pos && st != pos) {\r
+                            if (neg) return 0;\r
+                            else if (i == numconds) return 1;\r
+                            ingroup = true;\r
+                            while (p && *p != ']' && (p = nextchar(p)));\r
+                           st--;\r
+                        }\r
+                        if (p && *p != ']') p = nextchar(p);\r
+                    } else if (pos) {\r
+                        if (neg) return 0;\r
+                        else if (i == numconds) return 1;\r
+                        ingroup = true;\r
+                       while (p && *p != ']' && (p = nextchar(p)));\r
+//                     if (p && *p != ']') p = nextchar(p);\r
+                        st--;\r
+                    }\r
+                    if (!pos) {\r
+                        i++;\r
+                        st--;\r
+                    }\r
+                    if (st < beg && p && *p != ']') return 0; // word <= condition\r
+                } else if (pos) { // group\r
+                    p = nextchar(p);\r
+                } else return 0;\r
             }\r
-        }\r
       }\r
+      if (!p) return 1;\r
     }\r
-    return 1;\r
 }\r
 \r
-\r
-\r
-// see if this suffix is present in the word \r
+// see if this suffix is present in the word\r
 struct hentry * SfxEntry::checkword(const char * word, int len, int optflags,\r
-    AffEntry* ppfx, char ** wlst, int maxSug, int * ns, const FLAG cclass, const FLAG needflag,\r
+    PfxEntry* ppfx, char ** wlst, int maxSug, int * ns, const FLAG cclass, const FLAG needflag,\r
     const FLAG badflag)\r
 {\r
-    int                 tmpl;            // length of tmpword \r
+    int                 tmpl;            // length of tmpword\r
     struct hentry *     he;              // hash entry pointer\r
     unsigned char *     cp;\r
     char                tmpword[MAXWORDUTF8LEN + 4];\r
-    PfxEntry* ep = (PfxEntry *) ppfx;\r
+    PfxEntry* ep = ppfx;\r
 \r
     // if this suffix is being cross checked with a prefix\r
     // but it does not support cross products skip it\r
@@ -496,8 +584,9 @@ struct hentry * SfxEntry::checkword(const char * word, int len, int optflags,
     tmpl = len - appndl;\r
     // the second condition is not enough for UTF-8 strings\r
     // it checked in test_condition()\r
-    \r
-    if ((tmpl > 0)  &&  (tmpl + stripl >= numconds)) {\r
+\r
+    if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) &&\r
+        (tmpl + stripl >= numconds)) {\r
 \r
             // generate new root word by removing suffix and adding\r
             // back any characters that would have been stripped or\r
@@ -513,7 +602,8 @@ struct hentry * SfxEntry::checkword(const char * word, int len, int optflags,
 \r
             // now make sure all of the conditions on characters\r
             // are met.  Please see the appendix at the end of\r
-            // this file for more info on exactly what is being            // tested\r
+            // this file for more info on exactly what is being\r
+            // tested\r
 \r
             // if all conditions are met then check if resulting\r
             // root word in the dictionary\r
@@ -527,21 +617,21 @@ struct hentry * SfxEntry::checkword(const char * word, int len, int optflags,
                     do {\r
                         // check conditional suffix (enabled by prefix)\r
                         if ((TESTAFF(he->astr, aflag, he->alen) || (ep && ep->getCont() &&\r
-                                    TESTAFF(ep->getCont(), aflag, ep->getContLen()))) && \r
-                            (((optflags & aeXPRODUCT) == 0) || \r
-                            TESTAFF(he->astr, ep->getFlag(), he->alen) ||\r
+                                    TESTAFF(ep->getCont(), aflag, ep->getContLen()))) &&\r
+                            (((optflags & aeXPRODUCT) == 0) ||\r
+                            (ep && TESTAFF(he->astr, ep->getFlag(), he->alen)) ||\r
                              // enabled by prefix\r
-                            ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen))\r
+                            ((contclass) && (ep && TESTAFF(contclass, ep->getFlag(), contclasslen)))\r
                             ) &&\r
                             // handle cont. class\r
-                            ((!cclass) || \r
+                            ((!cclass) ||\r
                                 ((contclass) && TESTAFF(contclass, cclass, contclasslen))\r
                             ) &&\r
                             // check only in compound homonyms (bad flags)\r
                             (!badflag || !TESTAFF(he->astr, badflag, he->alen)\r
-                            ) &&                            \r
+                            ) &&\r
                             // handle required flag\r
-                            ((!needflag) || \r
+                            ((!needflag) ||\r
                               (TESTAFF(he->astr, needflag, he->alen) ||\r
                               ((contclass) && TESTAFF(contclass, needflag, contclasslen)))\r
                             )\r
@@ -549,12 +639,12 @@ struct hentry * SfxEntry::checkword(const char * word, int len, int optflags,
                         he = he->next_homonym; // check homonyms\r
                     } while (he);\r
 \r
-                // obsolote stemming code (used only by the \r
+                // obsolote stemming code (used only by the\r
                 // experimental SuffixMgr:suggest_pos_stems)\r
                 // store resulting root in wlst\r
                 } else if (wlst && (*ns < maxSug)) {\r
                     int cwrd = 1;\r
-                    for (int k=0; k < *ns; k++) \r
+                    for (int k=0; k < *ns; k++)\r
                         if (strcmp(tmpword, wlst[k]) == 0) cwrd = 0;\r
                     if (cwrd) {\r
                         wlst[*ns] = mystrdup(tmpword);\r
@@ -571,15 +661,15 @@ struct hentry * SfxEntry::checkword(const char * word, int len, int optflags,
     return NULL;\r
 }\r
 \r
-// see if two-level suffix is present in the word \r
+// see if two-level suffix is present in the word\r
 struct hentry * SfxEntry::check_twosfx(const char * word, int len, int optflags,\r
-    AffEntry* ppfx, const FLAG needflag)\r
+    PfxEntry* ppfx, const FLAG needflag)\r
 {\r
-    int                 tmpl;            // length of tmpword \r
+    int                 tmpl;            // length of tmpword\r
     struct hentry *     he;              // hash entry pointer\r
     unsigned char *     cp;\r
     char                tmpword[MAXWORDUTF8LEN + 4];\r
-    PfxEntry* ep = (PfxEntry *) ppfx;\r
+    PfxEntry* ep = ppfx;\r
 \r
 \r
     // if this suffix is being cross checked with a prefix\r
@@ -595,7 +685,8 @@ struct hentry * SfxEntry::check_twosfx(const char * word, int len, int optflags,
 \r
     tmpl = len - appndl;\r
 \r
-    if ((tmpl > 0)  &&  (tmpl + stripl >= numconds)) {\r
+    if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) &&\r
+       (tmpl + stripl >= numconds)) {\r
 \r
             // generate new root word by removing suffix and adding\r
             // back any characters that would have been stripped or\r
@@ -619,7 +710,7 @@ struct hentry * SfxEntry::check_twosfx(const char * word, int len, int optflags,
             if (test_condition((char *) cp, (char *) tmpword)) {\r
                 if (ppfx) {\r
                     // handle conditional suffix\r
-                    if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen)) \r
+                    if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen))\r
                         he = pmyMgr->suffix_check(tmpword, tmpl, 0, NULL, NULL, 0, NULL, (FLAG) aflag, needflag);\r
                     else\r
                         he = pmyMgr->suffix_check(tmpword, tmpl, optflags, ppfx, NULL, 0, NULL, (FLAG) aflag, needflag);\r
@@ -632,19 +723,18 @@ struct hentry * SfxEntry::check_twosfx(const char * word, int len, int optflags,
     return NULL;\r
 }\r
 \r
-#ifdef HUNSPELL_EXPERIMENTAL\r
-// see if two-level suffix is present in the word \r
+// see if two-level suffix is present in the word\r
 char * SfxEntry::check_twosfx_morph(const char * word, int len, int optflags,\r
-    AffEntry* ppfx, const FLAG needflag)\r
+    PfxEntry* ppfx, const FLAG needflag)\r
 {\r
-    int                 tmpl;            // length of tmpword \r
+    int                 tmpl;            // length of tmpword\r
     unsigned char *     cp;\r
     char                tmpword[MAXWORDUTF8LEN + 4];\r
-    PfxEntry* ep = (PfxEntry *) ppfx;\r
+    PfxEntry* ep = ppfx;\r
     char * st;\r
 \r
     char result[MAXLNLEN];\r
-    \r
+\r
     *result = '\0';\r
 \r
     // if this suffix is being cross checked with a prefix\r
@@ -660,7 +750,8 @@ char * SfxEntry::check_twosfx_morph(const char * word, int len, int optflags,
 \r
     tmpl = len - appndl;\r
 \r
-    if ((tmpl > 0)  &&  (tmpl + stripl >= numconds)) {\r
+    if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) &&\r
+       (tmpl + stripl >= numconds)) {\r
 \r
             // generate new root word by removing suffix and adding\r
             // back any characters that would have been stripped or\r
@@ -687,17 +778,18 @@ char * SfxEntry::check_twosfx_morph(const char * word, int len, int optflags,
                     if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen)) {\r
                         st = pmyMgr->suffix_check_morph(tmpword, tmpl, 0, NULL, aflag, needflag);\r
                         if (st) {\r
-                            if (((PfxEntry *) ppfx)->getMorph()) {\r
-                                strcat(result, ((PfxEntry *) ppfx)->getMorph());\r
+                            if (ppfx->getMorph()) {\r
+                                mystrcat(result, ppfx->getMorph(), MAXLNLEN);\r
+                                mystrcat(result, " ", MAXLNLEN);\r
                             }\r
-                            strcat(result,st);\r
+                            mystrcat(result,st, MAXLNLEN);\r
                             free(st);\r
                             mychomp(result);\r
                         }\r
                     } else {\r
                         st = pmyMgr->suffix_check_morph(tmpword, tmpl, optflags, ppfx, aflag, needflag);\r
                         if (st) {\r
-                            strcat(result, st);\r
+                            mystrcat(result, st, MAXLNLEN);\r
                             free(st);\r
                             mychomp(result);\r
                         }\r
@@ -705,7 +797,7 @@ char * SfxEntry::check_twosfx_morph(const char * word, int len, int optflags,
                 } else {\r
                         st = pmyMgr->suffix_check_morph(tmpword, tmpl, 0, NULL, aflag, needflag);\r
                         if (st) {\r
-                            strcat(result, st);\r
+                            mystrcat(result, st, MAXLNLEN);\r
                             free(st);\r
                             mychomp(result);\r
                         }\r
@@ -715,28 +807,28 @@ char * SfxEntry::check_twosfx_morph(const char * word, int len, int optflags,
     }\r
     return NULL;\r
 }\r
-#endif // END OF HUNSPELL_EXPERIMENTAL CODE\r
 \r
 // get next homonym with same affix\r
-struct hentry * SfxEntry::get_next_homonym(struct hentry * he, int optflags, AffEntry* ppfx, \r
+struct hentry * SfxEntry::get_next_homonym(struct hentry * he, int optflags, PfxEntry* ppfx,\r
     const FLAG cclass, const FLAG needflag)\r
 {\r
-    PfxEntry* ep = (PfxEntry *) ppfx;\r
+    PfxEntry* ep = ppfx;\r
+    FLAG eFlag = ep ? ep->getFlag() : FLAG_NULL;\r
 \r
     while (he->next_homonym) {\r
         he = he->next_homonym;\r
-        if ((TESTAFF(he->astr, aflag, he->alen) || (ep && ep->getCont() && TESTAFF(ep->getCont(), aflag, ep->getContLen()))) && \r
-                            ((optflags & aeXPRODUCT) == 0 || \r
-                            TESTAFF(he->astr, ep->getFlag(), he->alen) ||\r
+        if ((TESTAFF(he->astr, aflag, he->alen) || (ep && ep->getCont() && TESTAFF(ep->getCont(), aflag, ep->getContLen()))) &&\r
+                            ((optflags & aeXPRODUCT) == 0 ||\r
+                            TESTAFF(he->astr, eFlag, he->alen) ||\r
                              // handle conditional suffix\r
-                            ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen))\r
+                            ((contclass) && TESTAFF(contclass, eFlag, contclasslen))\r
                             ) &&\r
                             // handle cont. class\r
-                            ((!cclass) || \r
+                            ((!cclass) ||\r
                                 ((contclass) && TESTAFF(contclass, cclass, contclasslen))\r
                             ) &&\r
                             // handle required flag\r
-                            ((!needflag) || \r
+                            ((!needflag) ||\r
                               (TESTAFF(he->astr, needflag, he->alen) ||\r
                               ((contclass) && TESTAFF(contclass, needflag, contclasslen)))\r
                             )\r
index bb21773..eaf361f 100644 (file)
@@ -1,13 +1,15 @@
 #ifndef _AFFIX_HXX_
 #define _AFFIX_HXX_
 
+#include "hunvisapi.h"
+
 #include "atypes.hxx"
 #include "baseaffix.hxx"
 #include "affixmgr.hxx"
 
 /* A Prefix Entry  */
 
-class PfxEntry : public AffEntry
+class LIBHUNSPELL_DLL_EXPORTED PfxEntry : protected AffEntry
 {
        AffixMgr*    pmyMgr;
 
@@ -54,6 +56,7 @@ public:
   inline void   setNextEQ(PfxEntry * ptr) { nexteq = ptr; }
   inline void   setFlgNxt(PfxEntry * ptr) { flgnxt = ptr; }
   
+  inline char * nextchar(char * p);
   inline int    test_condition(const char * st);
 };
 
@@ -62,7 +65,7 @@ public:
 
 /* A Suffix Entry */
 
-class SfxEntry : public AffEntry
+class LIBHUNSPELL_DLL_EXPORTED SfxEntry : protected AffEntry
 {
        AffixMgr*    pmyMgr;
        char *       rappnd;
@@ -83,16 +86,16 @@ public:
 
   inline bool          allowCross() { return ((opts & aeXPRODUCT) != 0); }
   struct hentry *   checkword(const char * word, int len, int optflags, 
-                    AffEntry* ppfx, char ** wlst, int maxSug, int * ns,
+                    PfxEntry* ppfx, char ** wlst, int maxSug, int * ns,
 //                    const FLAG cclass = FLAG_NULL, const FLAG needflag = FLAG_NULL, char in_compound=IN_CPD_NOT);
                     const FLAG cclass = FLAG_NULL, const FLAG needflag = FLAG_NULL, const FLAG badflag = 0);
 
-  struct hentry *   check_twosfx(const char * word, int len, int optflags, AffEntry* ppfx, const FLAG needflag = NULL);
+  struct hentry *   check_twosfx(const char * word, int len, int optflags, PfxEntry* ppfx, const FLAG needflag = NULL);
 
   char *      check_twosfx_morph(const char * word, int len, int optflags,
-                 AffEntry* ppfx, const FLAG needflag = FLAG_NULL);
+                 PfxEntry* ppfx, const FLAG needflag = FLAG_NULL);
   struct hentry * get_next_homonym(struct hentry * he);
-  struct hentry * get_next_homonym(struct hentry * word, int optflags, AffEntry* ppfx, 
+  struct hentry * get_next_homonym(struct hentry * word, int optflags, PfxEntry* ppfx, 
     const FLAG cclass, const FLAG needflag);
 
 
@@ -123,7 +126,9 @@ public:
   inline void   setNextEQ(SfxEntry * ptr) { nexteq = ptr; }
   inline void   setFlgNxt(SfxEntry * ptr) { flgnxt = ptr; }
 
+  inline char * nextchar(char * p);
   inline int    test_condition(const char * st, const char * begin);
+
 };
 
 #endif
index 0792642..25a38bf 100644 (file)
@@ -1,17 +1,12 @@
 #include "license.hunspell"\r
 #include "license.myspell"\r
 \r
-#ifndef MOZILLA_CLIENT\r
-#include <cstdlib>\r
-#include <cstring>\r
-#include <cctype>\r
-#include <cstdio>\r
-#else\r
-#include <stdlib.h> \r
+#include <stdlib.h>\r
 #include <string.h>\r
-#include <stdio.h> \r
+#include <stdio.h>\r
 #include <ctype.h>\r
-#endif\r
+\r
+#include <vector>\r
 \r
 #include "affixmgr.hxx"\r
 #include "affentry.hxx"\r
 \r
 #include "csutil.hxx"\r
 \r
-#ifndef MOZILLA_CLIENT\r
-#ifndef W32\r
-using namespace std;\r
-#endif\r
-#endif\r
-\r
-AffixMgr::AffixMgr(const char * affpath, HashMgr* ptr) \r
+AffixMgr::AffixMgr(const char * affpath, HashMgr** ptr, int * md, const char * key) \r
 {\r
   // register hash manager and load affix data from aff file\r
-  pHMgr = ptr;\r
+  pHMgr = ptr[0];\r
+  alldic = ptr;\r
+  maxdic = md;\r
+  keystring = NULL;\r
   trystring = NULL;\r
   encoding=NULL;\r
+  csconv=NULL;\r
   utf8 = 0;\r
   complexprefixes = 0;\r
   maptable = NULL;\r
   nummap = 0;\r
   breaktable = NULL;\r
-  numbreak = 0;\r
+  numbreak = -1;\r
   reptable = NULL;\r
   numrep = 0;\r
+  iconvtable = NULL;\r
+  oconvtable = NULL;\r
   checkcpdtable = NULL;\r
+  // allow simplified compound forms (see 3rd field of CHECKCOMPOUNDPATTERN)\r
+  simplifiedcpd = 0;\r
   numcheckcpd = 0;\r
   defcpdtable = NULL;\r
   numdefcpd = 0;\r
+  phone = NULL;\r
   compoundflag = FLAG_NULL; // permits word in compound forms\r
   compoundbegin = FLAG_NULL; // may be first word in compound forms\r
   compoundmiddle = FLAG_NULL; // may be middle word in compound forms\r
@@ -54,11 +52,13 @@ AffixMgr::AffixMgr(const char * affpath, HashMgr* ptr)
   checkcompoundrep = 0; // forbid bad compounds (may be non compound word with a REP substitution)\r
   checkcompoundcase = 0; // forbid upper and lowercase combinations at word bounds\r
   checkcompoundtriple = 0; // forbid compounds with triple letters\r
-  forbiddenword = FLAG_NULL; // forbidden word signing flag\r
+  simplifiedtriple = 0; // allow simplified triple letters in compounds (Schiff+fahrt -> Schiffahrt)\r
+  forbiddenword = FORBIDDENWORD; // forbidden word signing flag\r
   nosuggest = FLAG_NULL; // don't suggest words signed with NOSUGGEST flag\r
+  nongramsuggest = FLAG_NULL;\r
   lang = NULL; // language\r
   langnum = 0; // language code (see http://l10n.openoffice.org/languages.html)\r
-  pseudoroot = FLAG_NULL; // forbidden root, allowed only with suffixes\r
+  needaffix = FLAG_NULL; // forbidden root, allowed only with suffixes\r
   cpdwordmax = -1; // default: unlimited wordcount in compound words\r
   cpdmin = -1;  // undefined\r
   cpdmaxsyllable = 0; // default: unlimited syllablecount in compound words\r
@@ -82,14 +82,20 @@ AffixMgr::AffixMgr(const char * affpath, HashMgr* ptr)
   lemma_present = FLAG_NULL; \r
   circumfix = FLAG_NULL; \r
   onlyincompound = FLAG_NULL; \r
-  flag_mode = FLAG_CHAR; // default one-character flags in affix and dic file\r
   maxngramsugs = -1; // undefined\r
+  maxdiff = -1; // undefined\r
+  onlymaxdiff = 0;\r
+  maxcpdsugs = -1; // undefined\r
   nosplitsugs = 0;\r
   sugswithdots = 0;\r
   keepcase = 0;\r
+  forceucase = 0;\r
+  warn = 0;\r
+  forbidwarn = 0;\r
   checksharps = 0;\r
+  substandard = FLAG_NULL;\r
+  fullstrip = 0;\r
 \r
-  derived = NULL; // XXX not threadsafe variable for experimental stemming\r
   sfx = NULL;\r
   pfx = NULL;\r
 \r
@@ -104,9 +110,8 @@ AffixMgr::AffixMgr(const char * affpath, HashMgr* ptr)
     contclasses[j] = 0;\r
   }\r
 \r
-  if (parse_file(affpath)) {\r
+  if (parse_file(affpath, key)) {\r
      HUNSPELL_WARNING(stderr, "Failure loading aff file %s\n",affpath);\r
-     wordchars = mystrdup("qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM");\r
   }\r
   \r
   if (cpdmin == -1) cpdmin = MINCPDLEN;\r
@@ -116,11 +121,10 @@ AffixMgr::AffixMgr(const char * affpath, HashMgr* ptr)
 \r
 AffixMgr::~AffixMgr() \r
 {\r
\r
   // pass through linked prefix entries and clean up\r
   for (int i=0; i < SETSIZE ;i++) {\r
        pFlag[i] = NULL;\r
-       PfxEntry * ptr = (PfxEntry *)pStart[i];\r
+       PfxEntry * ptr = pStart[i];\r
        PfxEntry * nptr = NULL;\r
        while (ptr) {\r
             nptr = ptr->getNext();\r
@@ -133,7 +137,7 @@ AffixMgr::~AffixMgr()
   // pass through linked suffix entries and clean up\r
   for (int j=0; j < SETSIZE ; j++) {\r
        sFlag[j] = NULL;\r
-       SfxEntry * ptr = (SfxEntry *)sStart[j];\r
+       SfxEntry * ptr = sStart[j];\r
        SfxEntry * nptr = NULL;\r
        while (ptr) {\r
             nptr = ptr->getNext();\r
@@ -144,14 +148,18 @@ AffixMgr::~AffixMgr()
        sStart[j] = NULL;\r
   }\r
 \r
+  if (keystring) free(keystring);\r
+  keystring=NULL;\r
   if (trystring) free(trystring);\r
   trystring=NULL;\r
   if (encoding) free(encoding);\r
   encoding=NULL;\r
   if (maptable) {  \r
      for (int j=0; j < nummap; j++) {\r
-        if (maptable[j].set) free(maptable[j].set);\r
-        if (maptable[j].set_utf16) free(maptable[j].set_utf16);\r
+        for (int k=0; k < maptable[j].len; k++) {\r
+           if (maptable[j].set[k]) free(maptable[j].set[k]);\r
+        }\r
+        free(maptable[j].set);\r
         maptable[j].set = NULL;\r
         maptable[j].len = 0;\r
      }\r
@@ -168,16 +176,26 @@ AffixMgr::~AffixMgr()
      breaktable = NULL;\r
   }\r
   numbreak = 0;\r
-  if (reptable) {  \r
+  if (reptable) {\r
      for (int j=0; j < numrep; j++) {\r
         free(reptable[j].pattern);\r
         free(reptable[j].pattern2);\r
-        reptable[j].pattern = NULL;\r
-        reptable[j].pattern2 = NULL;\r
      }\r
      free(reptable);  \r
      reptable = NULL;\r
   }\r
+  if (iconvtable) delete iconvtable;\r
+  if (oconvtable) delete oconvtable;\r
+  if (phone && phone->rules) {\r
+     for (int j=0; j < phone->num + 1; j++) {\r
+        free(phone->rules[j * 2]);\r
+        free(phone->rules[j * 2 + 1]);\r
+     }\r
+     free(phone->rules);\r
+     free(phone);  \r
+     phone = NULL;\r
+  }\r
+\r
   if (defcpdtable) {  \r
      for (int j=0; j < numdefcpd; j++) {\r
         free(defcpdtable[j].def);\r
@@ -191,8 +209,10 @@ AffixMgr::~AffixMgr()
      for (int j=0; j < numcheckcpd; j++) {\r
         free(checkcpdtable[j].pattern);\r
         free(checkcpdtable[j].pattern2);\r
+        free(checkcpdtable[j].pattern3);\r
         checkcpdtable[j].pattern = NULL;\r
         checkcpdtable[j].pattern2 = NULL;\r
+        checkcpdtable[j].pattern3 = NULL;\r
      }\r
      free(checkcpdtable);  \r
      checkcpdtable = NULL;\r
@@ -207,7 +227,8 @@ AffixMgr::~AffixMgr()
   FREE_FLAG(compoundroot);\r
   FREE_FLAG(forbiddenword);\r
   FREE_FLAG(nosuggest);\r
-  FREE_FLAG(pseudoroot);\r
+  FREE_FLAG(nongramsuggest);\r
+  FREE_FLAG(needaffix);\r
   FREE_FLAG(lemma_present);\r
   FREE_FLAG(circumfix);\r
   FREE_FLAG(onlyincompound);\r
@@ -226,20 +247,18 @@ AffixMgr::~AffixMgr()
   if (ignorechars) free(ignorechars);\r
   if (ignorechars_utf16) free(ignorechars_utf16);\r
   if (version) free(version);\r
-  if (derived) free(derived);\r
   checknum=0;\r
+#ifdef MOZILLA_CLIENT\r
+  delete [] csconv;\r
+#endif\r
 }\r
 \r
 \r
 // read in aff file and build up prefix and suffix entry objects \r
-int  AffixMgr::parse_file(const char * affpath)\r
+int  AffixMgr::parse_file(const char * affpath, const char * key)\r
 {\r
-\r
-  // io buffers\r
-  char line[MAXLNLEN+1];\r
\r
-  // affix type\r
-  char ft;\r
+  char * line; // io buffers\r
+  char ft;     // affix type\r
   \r
   // checking flag duplication\r
   char dupflags[CONTSIZE];\r
@@ -249,8 +268,7 @@ int  AffixMgr::parse_file(const char * affpath)
   int firstline = 1;\r
   \r
   // open the affix file\r
-  FILE * afflst;\r
-  afflst = fopen(affpath,"r");\r
+  FileMgr * afflst = new FileMgr(affpath, key);\r
   if (!afflst) {\r
     HUNSPELL_WARNING(stderr, "error: could not open affix description file %s\n",affpath);\r
     return 1;\r
@@ -259,43 +277,47 @@ int  AffixMgr::parse_file(const char * affpath)
   // step one is to parse the affix file building up the internal\r
   // affix data structures\r
 \r
-\r
     // read in each line ignoring any that do not\r
     // start with a known line type indicator\r
-    while (fgets(line,MAXLNLEN,afflst)) {\r
+    while ((line = afflst->getline())) {\r
        mychomp(line);\r
 \r
        /* remove byte order mark */\r
        if (firstline) {\r
          firstline = 0;\r
-         if (strncmp(line,"",3) == 0) {\r
+         // Affix file begins with byte order mark: possible incompatibility with old Hunspell versions\r
+         if (strncmp(line,"\xEF\xBB\xBF",3) == 0) {\r
             memmove(line, line+3, strlen(line+3)+1);\r
-            HUNSPELL_WARNING(stderr, "warning: affix file begins with byte order mark: possible incompatibility with old Hunspell versions\n");\r
          }\r
        }\r
 \r
+       /* parse in the keyboard string */\r
+       if (strncmp(line,"KEY",3) == 0) {\r
+          if (parse_string(line, &keystring, afflst->getlinenum())) {\r
+             delete afflst;\r
+             return 1;\r
+          }\r
+       }\r
+\r
        /* parse in the try string */\r
        if (strncmp(line,"TRY",3) == 0) {\r
-          if (parse_string(line, &trystring, "TRY")) {\r
-             fclose(afflst);\r
+          if (parse_string(line, &trystring, afflst->getlinenum())) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the name of the character set used by the .dict and .aff */\r
        if (strncmp(line,"SET",3) == 0) {\r
-          if (parse_string(line, &encoding, "SET")) {\r
-             fclose(afflst);\r
+          if (parse_string(line, &encoding, afflst->getlinenum())) {\r
+             delete afflst;\r
              return 1;\r
           }\r
           if (strcmp(encoding, "UTF-8") == 0) {\r
              utf8 = 1;\r
 #ifndef OPENOFFICEORG\r
 #ifndef MOZILLA_CLIENT\r
-             if (initialize_utf_tbl()) {\r
-               fclose(afflst);\r
-               return 1;\r
-             }\r
+             if (initialize_utf_tbl()) return 1;\r
 #endif\r
 #endif\r
           }\r
@@ -307,8 +329,8 @@ int  AffixMgr::parse_file(const char * affpath)
 \r
        /* parse in the flag used by the controlled compound words */\r
        if (strncmp(line,"COMPOUNDFLAG",12) == 0) {\r
-          if (parse_flag(line, &compoundflag, "COMPOUNDFLAG")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &compoundflag, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
@@ -316,13 +338,13 @@ int  AffixMgr::parse_file(const char * affpath)
        /* parse in the flag used by compound words */\r
        if (strncmp(line,"COMPOUNDBEGIN",13) == 0) {\r
           if (complexprefixes) {\r
-            if (parse_flag(line, &compoundend, "COMPOUNDBEGIN")) {\r
-              fclose(afflst);\r
+            if (parse_flag(line, &compoundend, afflst)) {\r
+              delete afflst;\r
               return 1;\r
             }\r
           } else {\r
-            if (parse_flag(line, &compoundbegin, "COMPOUNDBEGIN")) {\r
-              fclose(afflst);\r
+            if (parse_flag(line, &compoundbegin, afflst)) {\r
+              delete afflst;\r
               return 1;\r
             }\r
           }\r
@@ -330,21 +352,21 @@ int  AffixMgr::parse_file(const char * affpath)
 \r
        /* parse in the flag used by compound words */\r
        if (strncmp(line,"COMPOUNDMIDDLE",14) == 0) {\r
-          if (parse_flag(line, &compoundmiddle, "COMPOUNDMIDDLE")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &compoundmiddle, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
        /* parse in the flag used by compound words */\r
        if (strncmp(line,"COMPOUNDEND",11) == 0) {\r
           if (complexprefixes) {\r
-            if (parse_flag(line, &compoundbegin, "COMPOUNDEND")) {\r
-              fclose(afflst);\r
+            if (parse_flag(line, &compoundbegin, afflst)) {\r
+              delete afflst;\r
               return 1;\r
             }\r
           } else {\r
-            if (parse_flag(line, &compoundend, "COMPOUNDEND")) {\r
-              fclose(afflst);\r
+            if (parse_flag(line, &compoundend, afflst)) {\r
+              delete afflst;\r
               return 1;\r
             }\r
           }\r
@@ -352,32 +374,32 @@ int  AffixMgr::parse_file(const char * affpath)
 \r
        /* parse in the data used by compound_check() method */\r
        if (strncmp(line,"COMPOUNDWORDMAX",15) == 0) {\r
-          if (parse_num(line, &cpdwordmax, "COMPOUNDWORDMAX")) {\r
-             fclose(afflst);\r
+          if (parse_num(line, &cpdwordmax, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the flag sign compounds in dictionary */\r
        if (strncmp(line,"COMPOUNDROOT",12) == 0) {\r
-          if (parse_flag(line, &compoundroot, "COMPOUNDROOT")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &compoundroot, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the flag used by compound_check() method */\r
        if (strncmp(line,"COMPOUNDPERMITFLAG",18) == 0) {\r
-          if (parse_flag(line, &compoundpermitflag, "COMPOUNDPERMITFLAG")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &compoundpermitflag, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the flag used by compound_check() method */\r
        if (strncmp(line,"COMPOUNDFORBIDFLAG",18) == 0) {\r
-          if (parse_flag(line, &compoundforbidflag, "COMPOUNDFORBIDFLAG")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &compoundforbidflag, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
@@ -394,69 +416,80 @@ int  AffixMgr::parse_file(const char * affpath)
                    checkcompoundtriple = 1;\r
        }\r
 \r
+       if (strncmp(line,"SIMPLIFIEDTRIPLE",16) == 0) {\r
+                   simplifiedtriple = 1;\r
+       }\r
+\r
        if (strncmp(line,"CHECKCOMPOUNDCASE",17) == 0) {\r
                    checkcompoundcase = 1;\r
        }\r
 \r
        if (strncmp(line,"NOSUGGEST",9) == 0) {\r
-          if (parse_flag(line, &nosuggest, "NOSUGGEST")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &nosuggest, afflst)) {\r
+             delete afflst;\r
+             return 1;\r
+          }\r
+       }\r
+\r
+       if (strncmp(line,"NONGRAMSUGGEST",14) == 0) {\r
+          if (parse_flag(line, &nongramsuggest, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the flag used by forbidden words */\r
        if (strncmp(line,"FORBIDDENWORD",13) == 0) {\r
-          if (parse_flag(line, &forbiddenword, "FORBIDDENWORD")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &forbiddenword, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the flag used by forbidden words */\r
        if (strncmp(line,"LEMMA_PRESENT",13) == 0) {\r
-          if (parse_flag(line, &lemma_present, "LEMMA_PRESENT")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &lemma_present, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the flag used by circumfixes */\r
        if (strncmp(line,"CIRCUMFIX",9) == 0) {\r
-          if (parse_flag(line, &circumfix, "CIRCUMFIX")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &circumfix, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the flag used by fogemorphemes */\r
        if (strncmp(line,"ONLYINCOMPOUND",14) == 0) {\r
-          if (parse_flag(line, &onlyincompound, "ONLYINCOMPOUND")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &onlyincompound, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
-       /* parse in the flag used by `pseudoroots' */\r
+       /* parse in the flag used by `needaffixs' */\r
        if (strncmp(line,"PSEUDOROOT",10) == 0) {\r
-          if (parse_flag(line, &pseudoroot, "PSEUDOROOT")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &needaffix, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
-       /* parse in the flag used by `pseudoroots' */\r
+       /* parse in the flag used by `needaffixs' */\r
        if (strncmp(line,"NEEDAFFIX",9) == 0) {\r
-          if (parse_flag(line, &pseudoroot, "NEEDAFFIX")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &needaffix, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the minimal length for words in compounds */\r
        if (strncmp(line,"COMPOUNDMIN",11) == 0) {\r
-          if (parse_num(line, &cpdmin, "COMPOUNDMIN")) {\r
-             fclose(afflst);\r
+          if (parse_num(line, &cpdmin, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
           if (cpdmin < 1) cpdmin = 1;\r
@@ -464,16 +497,16 @@ int  AffixMgr::parse_file(const char * affpath)
 \r
        /* parse in the max. words and syllables in compounds */\r
        if (strncmp(line,"COMPOUNDSYLLABLE",16) == 0) {\r
-          if (parse_cpdsyllable(line)) {\r
-             fclose(afflst);\r
+          if (parse_cpdsyllable(line, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the flag used by compound_check() method */\r
        if (strncmp(line,"SYLLABLENUM",11) == 0) {\r
-          if (parse_string(line, &cpdsyllablenum, "SYLLABLENUM")) {\r
-             fclose(afflst);\r
+          if (parse_string(line, &cpdsyllablenum, afflst->getlinenum())) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
@@ -485,16 +518,16 @@ int  AffixMgr::parse_file(const char * affpath)
 \r
        /* parse in the extra word characters */\r
        if (strncmp(line,"WORDCHARS",9) == 0) {\r
-          if (parse_array(line, &wordchars, &wordchars_utf16, &wordchars_utf16_len, "WORDCHARS", utf8)) {\r
-             fclose(afflst);\r
+          if (parse_array(line, &wordchars, &wordchars_utf16, &wordchars_utf16_len, utf8, afflst->getlinenum())) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the ignored characters (for example, Arabic optional diacretics charachters */\r
        if (strncmp(line,"IGNORE",6) == 0) {\r
-          if (parse_array(line, &ignorechars, &ignorechars_utf16, &ignorechars_utf16_len, "IGNORE", utf8)) {\r
-             fclose(afflst);\r
+          if (parse_array(line, &ignorechars, &ignorechars_utf16, &ignorechars_utf16_len, utf8, afflst->getlinenum())) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
@@ -502,7 +535,31 @@ int  AffixMgr::parse_file(const char * affpath)
        /* parse in the typical fault correcting table */\r
        if (strncmp(line,"REP",3) == 0) {\r
           if (parse_reptable(line, afflst)) {\r
-             fclose(afflst);\r
+             delete afflst;\r
+             return 1;\r
+          }\r
+       }\r
+\r
+       /* parse in the input conversion table */\r
+       if (strncmp(line,"ICONV",5) == 0) {\r
+          if (parse_convtable(line, afflst, &iconvtable, "ICONV")) {\r
+             delete afflst;\r
+             return 1;\r
+          }\r
+       }\r
+\r
+       /* parse in the input conversion table */\r
+       if (strncmp(line,"OCONV",5) == 0) {\r
+          if (parse_convtable(line, afflst, &oconvtable, "OCONV")) {\r
+             delete afflst;\r
+             return 1;\r
+          }\r
+       }\r
+\r
+       /* parse in the phonetic translation table */\r
+       if (strncmp(line,"PHONE",5) == 0) {\r
+          if (parse_phonetable(line, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
@@ -510,7 +567,7 @@ int  AffixMgr::parse_file(const char * affpath)
        /* parse in the checkcompoundpattern table */\r
        if (strncmp(line,"CHECKCOMPOUNDPATTERN",20) == 0) {\r
           if (parse_checkcpdtable(line, afflst)) {\r
-             fclose(afflst);\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
@@ -518,7 +575,7 @@ int  AffixMgr::parse_file(const char * affpath)
        /* parse in the defcompound table */\r
        if (strncmp(line,"COMPOUNDRULE",12) == 0) {\r
           if (parse_defcpdtable(line, afflst)) {\r
-             fclose(afflst);\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
@@ -526,7 +583,7 @@ int  AffixMgr::parse_file(const char * affpath)
        /* parse in the related character map table */\r
        if (strncmp(line,"MAP",3) == 0) {\r
           if (parse_maptable(line, afflst)) {\r
-             fclose(afflst);\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
@@ -534,30 +591,45 @@ int  AffixMgr::parse_file(const char * affpath)
        /* parse in the word breakpoints table */\r
        if (strncmp(line,"BREAK",5) == 0) {\r
           if (parse_breaktable(line, afflst)) {\r
-             fclose(afflst);\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
        /* parse in the language for language specific codes */\r
        if (strncmp(line,"LANG",4) == 0) {\r
-          if (parse_string(line, &lang, "LANG")) {\r
-             fclose(afflst);\r
+          if (parse_string(line, &lang, afflst->getlinenum())) {\r
+             delete afflst;\r
              return 1;\r
           }\r
           langnum = get_lang_num(lang);\r
        }\r
 \r
        if (strncmp(line,"VERSION",7) == 0) {\r
-          if (parse_string(line, &version, "VERSION")) {\r
-             fclose(afflst);\r
+          for(line = line + 7; *line == ' ' || *line == '\t'; line++);\r
+          version = mystrdup(line);\r
+       }\r
+\r
+       if (strncmp(line,"MAXNGRAMSUGS",12) == 0) {\r
+          if (parse_num(line, &maxngramsugs, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
 \r
-       if (strncmp(line,"MAXNGRAMSUGS",12) == 0) {\r
-          if (parse_num(line, &maxngramsugs, "MAXNGRAMSUGS")) {\r
-             fclose(afflst);\r
+       if (strncmp(line,"ONLYMAXDIFF", 11) == 0)\r
+                   onlymaxdiff = 1;\r
+\r
+       if (strncmp(line,"MAXDIFF",7) == 0) {\r
+          if (parse_num(line, &maxdiff, afflst)) {\r
+             delete afflst;\r
+             return 1;\r
+          }\r
+       }\r
+\r
+       if (strncmp(line,"MAXCPDSUGS",10) == 0) {\r
+          if (parse_num(line, &maxcpdsugs, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
@@ -566,14 +638,46 @@ int  AffixMgr::parse_file(const char * affpath)
                    nosplitsugs=1;\r
        }\r
 \r
+       if (strncmp(line,"FULLSTRIP",9) == 0) {\r
+                   fullstrip=1;\r
+       }\r
+\r
        if (strncmp(line,"SUGSWITHDOTS",12) == 0) {\r
                    sugswithdots=1;\r
        }\r
 \r
        /* parse in the flag used by forbidden words */\r
        if (strncmp(line,"KEEPCASE",8) == 0) {\r
-          if (parse_flag(line, &keepcase, "KEEPCASE")) {\r
-             fclose(afflst);\r
+          if (parse_flag(line, &keepcase, afflst)) {\r
+             delete afflst;\r
+             return 1;\r
+          }\r
+       }\r
+\r
+       /* parse in the flag used by `forceucase' */\r
+       if (strncmp(line,"FORCEUCASE",10) == 0) {\r
+          if (parse_flag(line, &forceucase, afflst)) {\r
+             delete afflst;\r
+             return 1;\r
+          }\r
+       }\r
+\r
+       /* parse in the flag used by `warn' */\r
+       if (strncmp(line,"WARN",4) == 0) {\r
+          if (parse_flag(line, &warn, afflst)) {\r
+             delete afflst;\r
+             return 1;\r
+          }\r
+       }\r
+\r
+       if (strncmp(line,"FORBIDWARN",10) == 0) {\r
+                   forbidwarn=1;\r
+       }\r
+\r
+       /* parse in the flag used by the affix generator */\r
+       if (strncmp(line,"SUBSTANDARD",11) == 0) {\r
+          if (parse_flag(line, &substandard, afflst)) {\r
+             delete afflst;\r
              return 1;\r
           }\r
        }\r
@@ -588,11 +692,11 @@ int  AffixMgr::parse_file(const char * affpath)
        if (strncmp(line,"SFX",3) == 0) ft = complexprefixes ? 'P' : 'S';\r
        if (ft != ' ') {\r
           if (dupflags_ini) {\r
-            for (int i = 0; i < CONTSIZE; i++) dupflags[i] = 0;\r
+            memset(dupflags, 0, sizeof(dupflags));\r
             dupflags_ini = 0;\r
           }\r
           if (parse_affix(line, ft, afflst, dupflags)) {\r
-             fclose(afflst);\r
+             delete afflst;\r
              process_pfx_tree_to_list();\r
              process_sfx_tree_to_list();\r
              return 1;\r
@@ -600,7 +704,7 @@ int  AffixMgr::parse_file(const char * affpath)
        }\r
 \r
     }\r
-    fclose(afflst);\r
+    delete afflst;\r
 \r
     // convert affix trees to sorted list\r
     process_pfx_tree_to_list();\r
@@ -626,14 +730,14 @@ int  AffixMgr::parse_file(const char * affpath)
     // from entry.  One to take next if the current prefix is found (call it nexteq)\r
     // and one to take next if the current prefix is not found (call it nextne).\r
 \r
-    // Since we have built ordered lists, all that remains is to properly intialize \r
+    // Since we have built ordered lists, all that remains is to properly initialize \r
     // the nextne and nexteq pointers that relate them\r
 \r
     process_pfx_order();\r
     process_sfx_order();\r
 \r
-    // expand wordchars string, based on csutil (for external tokenization)\r
-\r
+    /* get encoding for CHECKCOMPOUNDCASE */\r
+    if (!utf8) {\r
     char * enc = get_encoding();\r
     csconv = get_current_cs(enc);\r
     free(enc);\r
@@ -654,13 +758,16 @@ int  AffixMgr::parse_file(const char * affpath)
     }\r
 \r
     wordchars = mystrdup(expw);\r
+    }\r
 \r
-    // temporary BREAK definition for German dash handling (OOo issue 64400)\r
-    if ((langnum == LANG_de) && (!breaktable)) {\r
-        breaktable = (char **) malloc(sizeof(char *));\r
+    // default BREAK definition\r
+    if (numbreak == -1) {\r
+        breaktable = (char **) malloc(sizeof(char *) * 3);\r
         if (!breaktable) return 1;\r
         breaktable[0] = mystrdup("-");\r
-        numbreak = 1;\r
+        breaktable[1] = mystrdup("^-");\r
+        breaktable[2] = mystrdup("-$");\r
+        if (breaktable[0] && breaktable[1] && breaktable[2]) numbreak = 3;\r
     }\r
     return 0;\r
 }\r
@@ -670,28 +777,28 @@ int  AffixMgr::parse_file(const char * affpath)
 // both by prefix flag, and sorted by prefix string itself \r
 // so we need to set up two indexes\r
 \r
-int AffixMgr::build_pfxtree(AffEntry* pfxptr)\r
+int AffixMgr::build_pfxtree(PfxEntry* pfxptr)\r
 {\r
   PfxEntry * ptr;\r
   PfxEntry * pptr;\r
-  PfxEntry * ep = (PfxEntry*) pfxptr;\r
+  PfxEntry * ep = pfxptr;\r
 \r
   // get the right starting points\r
   const char * key = ep->getKey();\r
   const unsigned char flg = (unsigned char) (ep->getFlag() & 0x00FF);\r
 \r
   // first index by flag which must exist\r
-  ptr = (PfxEntry*)pFlag[flg];\r
+  ptr = pFlag[flg];\r
   ep->setFlgNxt(ptr);\r
-  pFlag[flg] = (AffEntry *) ep;\r
+  pFlag[flg] = ep;\r
 \r
 \r
   // handle the special case of null affix string\r
   if (strlen(key) == 0) {\r
     // always inset them at head of list at element 0\r
-     ptr = (PfxEntry*)pStart[0];\r
+     ptr = pStart[0];\r
      ep->setNext(ptr);\r
-     pStart[0] = (AffEntry*)ep;\r
+     pStart[0] = ep;\r
      return 0;\r
   }\r
 \r
@@ -700,11 +807,11 @@ int AffixMgr::build_pfxtree(AffEntry* pfxptr)
   ep->setNextNE(NULL);\r
 \r
   unsigned char sp = *((const unsigned char *)key);\r
-  ptr = (PfxEntry*)pStart[sp];\r
+  ptr = pStart[sp];\r
   \r
   // handle the first insert \r
   if (!ptr) {\r
-     pStart[sp] = (AffEntry*)ep;\r
+     pStart[sp] = ep;\r
      return 0;\r
   }\r
 \r
@@ -734,29 +841,29 @@ int AffixMgr::build_pfxtree(AffEntry* pfxptr)
 // we want to be able to quickly access suffix information\r
 // both by suffix flag, and sorted by the reverse of the\r
 // suffix string itself; so we need to set up two indexes\r
-int AffixMgr::build_sfxtree(AffEntry* sfxptr)\r
+int AffixMgr::build_sfxtree(SfxEntry* sfxptr)\r
 {\r
   SfxEntry * ptr;\r
   SfxEntry * pptr;\r
-  SfxEntry * ep = (SfxEntry *) sfxptr;\r
+  SfxEntry * ep = sfxptr;\r
 \r
   /* get the right starting point */\r
   const char * key = ep->getKey();\r
   const unsigned char flg = (unsigned char) (ep->getFlag() & 0x00FF);\r
 \r
   // first index by flag which must exist\r
-  ptr = (SfxEntry*)sFlag[flg];\r
+  ptr = sFlag[flg];\r
   ep->setFlgNxt(ptr);\r
-  sFlag[flg] = (AffEntry *) ep;\r
+  sFlag[flg] = ep;\r
 \r
   // next index by affix string\r
 \r
   // handle the special case of null affix string\r
   if (strlen(key) == 0) {\r
     // always inset them at head of list at element 0\r
-     ptr = (SfxEntry*)sStart[0];\r
+     ptr = sStart[0];\r
      ep->setNext(ptr);\r
-     sStart[0] = (AffEntry*)ep;\r
+     sStart[0] = ep;\r
      return 0;\r
   }\r
 \r
@@ -765,11 +872,11 @@ int AffixMgr::build_sfxtree(AffEntry* sfxptr)
   ep->setNextNE(NULL);\r
 \r
   unsigned char sp = *((const unsigned char *)key);\r
-  ptr = (SfxEntry*)sStart[sp];\r
+  ptr = sStart[sp];\r
   \r
   // handle the first insert \r
   if (!ptr) {\r
-     sStart[sp] = (AffEntry*)ep;\r
+     sStart[sp] = ep;\r
      return 0;\r
   }\r
 \r
@@ -805,12 +912,12 @@ int AffixMgr::process_pfx_tree_to_list()
 }\r
 \r
 \r
-AffEntry* AffixMgr::process_pfx_in_order(AffEntry* ptr, AffEntry* nptr)\r
+PfxEntry* AffixMgr::process_pfx_in_order(PfxEntry* ptr, PfxEntry* nptr)\r
 {\r
   if (ptr) {\r
-    nptr = process_pfx_in_order(((PfxEntry*) ptr)->getNextNE(), nptr);\r
-    ((PfxEntry*) ptr)->setNext((PfxEntry*) nptr);\r
-    nptr = process_pfx_in_order(((PfxEntry*) ptr)->getNextEQ(), ptr);\r
+    nptr = process_pfx_in_order(ptr->getNextNE(), nptr);\r
+    ptr->setNext(nptr);\r
+    nptr = process_pfx_in_order(ptr->getNextEQ(), ptr);\r
   }\r
   return nptr;\r
 }\r
@@ -825,12 +932,12 @@ int AffixMgr:: process_sfx_tree_to_list()
   return 0;\r
 }\r
 \r
-AffEntry* AffixMgr::process_sfx_in_order(AffEntry* ptr, AffEntry* nptr)\r
+SfxEntry* AffixMgr::process_sfx_in_order(SfxEntry* ptr, SfxEntry* nptr)\r
 {\r
   if (ptr) {\r
-    nptr = process_sfx_in_order(((SfxEntry*) ptr)->getNextNE(), nptr);\r
-    ((SfxEntry*) ptr)->setNext((SfxEntry*) nptr);\r
-    nptr = process_sfx_in_order(((SfxEntry*) ptr)->getNextEQ(), ptr);\r
+    nptr = process_sfx_in_order(ptr->getNextNE(), nptr);\r
+    ptr->setNext(nptr);\r
+    nptr = process_sfx_in_order(ptr->getNextEQ(), ptr);\r
   }\r
   return nptr;\r
 }\r
@@ -845,7 +952,7 @@ int AffixMgr::process_pfx_order()
     // loop through each prefix list starting point\r
     for (int i=1; i < SETSIZE; i++) {\r
 \r
-         ptr = (PfxEntry*)pStart[i];\r
+         ptr = pStart[i];\r
 \r
          // look through the remainder of the list\r
          //  and find next entry with affix that \r
@@ -871,7 +978,7 @@ int AffixMgr::process_pfx_order()
          // but not a subset of the next, search can end here\r
          // so set NextNE properly\r
 \r
-         ptr = (PfxEntry *) pStart[i];\r
+         ptr = pStart[i];\r
          for (; ptr != NULL; ptr = ptr->getNext()) {\r
              PfxEntry * nptr = ptr->getNext();\r
              PfxEntry * mptr = NULL;\r
@@ -894,7 +1001,7 @@ int AffixMgr::process_sfx_order()
     // loop through each prefix list starting point\r
     for (int i=1; i < SETSIZE; i++) {\r
 \r
-         ptr = (SfxEntry *) sStart[i];\r
+         ptr = sStart[i];\r
 \r
          // look through the remainder of the list\r
          //  and find next entry with affix that \r
@@ -920,7 +1027,7 @@ int AffixMgr::process_sfx_order()
          // but not a subset of the next, search can end here\r
          // so set NextNE properly\r
 \r
-         ptr = (SfxEntry *) sStart[i];\r
+         ptr = sStart[i];\r
          for (; ptr != NULL; ptr = ptr->getNext()) {\r
              SfxEntry * nptr = ptr->getNext();\r
              SfxEntry * mptr = NULL;\r
@@ -934,191 +1041,52 @@ int AffixMgr::process_sfx_order()
     return 0;\r
 }\r
 \r
+// add flags to the result for dictionary debugging\r
+void AffixMgr::debugflag(char * result, unsigned short flag) {\r
+    char * st = encode_flag(flag);\r
+    mystrcat(result, " ", MAXLNLEN);\r
+    mystrcat(result, MORPH_FLAG, MAXLNLEN);\r
+    if (st) {\r
+        mystrcat(result, st, MAXLNLEN);\r
+        free(st);\r
+    }\r
+}\r
 \r
-\r
-// takes aff file condition string and creates the\r
-// conds array - please see the appendix at the end of the\r
-// file affentry.cxx which describes what is going on here\r
-// in much more detail\r
-\r
-int AffixMgr::encodeit(struct affentry * ptr, char * cs)\r
+// calculate the character length of the condition\r
+int AffixMgr::condlen(char * st)\r
 {\r
-  unsigned char c;\r
-  int i, j, k;\r
-  unsigned char mbr[MAXLNLEN];\r
-  w_char wmbr[MAXLNLEN];\r
-  w_char * wpos = wmbr;\r
-\r
-  // now clear the conditions array */\r
-  for (i=0;i<SETSIZE;i++) ptr->conds.base[i] = (unsigned char) 0;\r
-\r
-  // now parse the string to create the conds array */\r
-  int nc = strlen(cs);\r
-  unsigned char neg = 0;   // complement indicator\r
-  int grp = 0;   // group indicator\r
-  unsigned char n = 0;     // number of conditions\r
-  int ec = 0;    // end condition indicator\r
-  int nm = 0;    // number of member in group\r
-\r
-  // if no condition just return\r
-  if (strcmp(cs,".")==0) {\r
-    ptr->numconds = 0;\r
-    return 0;\r
+  int l = 0;\r
+  bool group = false;\r
+  for(; *st; st++) {\r
+    if (*st == '[') {\r
+        group = true;\r
+        l++;\r
+    } else if (*st == ']') group = false;\r
+    else if (!group && (!utf8 ||\r
+        (!(*st & 0x80) || ((*st & 0xc0) == 0x80)))) l++;\r
   }\r
+  return l;\r
+}\r
 \r
-  i = 0;\r
-  while (i < nc) {\r
-    c = *((unsigned char *)(cs + i));\r
-\r
-    // start group indicator\r
-    if (c == '[') {\r
-       grp = 1;\r
-       c = 0;\r
-    }\r
-\r
-    // complement flag\r
-    if ((grp == 1) && (c == '^')) {\r
-       neg = 1;\r
-       c = 0;\r
-    }\r
-\r
-    // end goup indicator\r
-    if (c == ']') {\r
-       ec = 1;\r
-       c = 0;\r
-    }\r
-\r
-    // add character of group to list\r
-    if ((grp == 1) && (c != 0)) {\r
-      *(mbr + nm) = c;\r
-      nm++;\r
-      c = 0;\r
-    }\r
-\r
-    // end of condition \r
-    if (c != 0) {\r
-       ec = 1;\r
+int AffixMgr::encodeit(affentry &entry, char * cs)\r
+{\r
+  if (strcmp(cs,".") != 0) {\r
+    entry.numconds = (char) condlen(cs);\r
+    strncpy(entry.c.conds, cs, MAXCONDLEN);\r
+    // long condition (end of conds padded by strncpy)\r
+    if (entry.c.conds[MAXCONDLEN - 1] && cs[MAXCONDLEN]) {\r
+      entry.opts += aeLONGCOND;\r
+      entry.c.l.conds2 = mystrdup(cs + MAXCONDLEN_1);\r
+      if (!entry.c.l.conds2) return 1;\r
     }\r
-\r
-  if (ec) {    \r
-    if (!utf8) {\r
-      if (grp == 1) {\r
-        if (neg == 0) {\r
-          // set the proper bits in the condition array vals for those chars\r
-          for (j=0;j<nm;j++) {\r
-             k = (unsigned int) mbr[j];\r
-             ptr->conds.base[k] = ptr->conds.base[k] | ((unsigned char)1 << n);\r
-          }\r
-        } else {\r
-          // complement so set all of them and then unset indicated ones\r
-           for (j=0;j<SETSIZE;j++) ptr->conds.base[j] = ptr->conds.base[j] | ((unsigned char)1 << n);\r
-           for (j=0;j<nm;j++) {\r
-             k = (unsigned int) mbr[j];\r
-             ptr->conds.base[k] = ptr->conds.base[k] & ~((unsigned char)1 << n);\r
-           }\r
-        }\r
-        neg = 0;\r
-        grp = 0;   \r
-        nm = 0;\r
-      } else {\r
-         // not a group so just set the proper bit for this char\r
-         // but first handle special case of . inside condition\r
-         if (c == '.') {\r
-            // wild card character so set them all\r
-            for (j=0;j<SETSIZE;j++) ptr->conds.base[j] = ptr->conds.base[j] | ((unsigned char)1 << n);\r
-         } else {  \r
-            ptr->conds.base[(unsigned int) c] = ptr->conds.base[(unsigned int)c] | ((unsigned char)1 << n);\r
-         }\r
-      }\r
-      n++;\r
-      ec = 0;\r
-    } else { // UTF-8 character set\r
-      if (grp == 1) {\r
-        ptr->conds.utf8.neg[n] = neg;\r
-        if (neg == 0) {\r
-          // set the proper bits in the condition array vals for those chars\r
-          for (j=0;j<nm;j++) {\r
-             k = (unsigned int) mbr[j];\r
-             if (k >> 7) {\r
-                u8_u16(wpos, 1, (char *) mbr + j);\r
-                wpos++;\r
-                if ((k & 0xe0) == 0xe0) j+=2; else j++; // 3-byte UTF-8 character\r
-             } else {\r
-                ptr->conds.utf8.ascii[k] = ptr->conds.utf8.ascii[k] | ((unsigned char)1 << n);\r
-             }\r
-          }\r
-        } else { // neg == 1\r
-          // complement so set all of them and then unset indicated ones\r
-           for (j=0;j<(SETSIZE/2);j++) ptr->conds.utf8.ascii[j] = ptr->conds.utf8.ascii[j] | ((unsigned char)1 << n);\r
-           for (j=0;j<nm;j++) {\r
-             k = (unsigned int) mbr[j];\r
-             if (k >> 7) {\r
-                u8_u16(wpos, 1, (char *) mbr + j);\r
-                wpos++;\r
-                if ((k & 0xe0) == 0xe0) j+=2; else j++; // 3-byte UTF-8 character\r
-             } else {\r
-                ptr->conds.utf8.ascii[k] = ptr->conds.utf8.ascii[k] & ~((unsigned char)1 << n);\r
-             }\r
-           }\r
-        }\r
-        neg = 0;\r
-        grp = 0;   \r
-        nm = 0;\r
-        ptr->conds.utf8.wlen[n] = wpos - wmbr;\r
-        if ((wpos - wmbr) != 0) {\r
-            ptr->conds.utf8.wchars[n] = (w_char *) malloc(sizeof(w_char) * (wpos - wmbr));\r
-            if (!ptr->conds.utf8.wchars[n]) return 1;\r
-            memcpy(ptr->conds.utf8.wchars[n], wmbr, sizeof(w_char) * (wpos - wmbr));\r
-            flag_qsort((unsigned short *) ptr->conds.utf8.wchars[n], 0, ptr->conds.utf8.wlen[n]);\r
-            wpos = wmbr;\r
-        }\r
-      } else { // grp == 0\r
-         // is UTF-8 character?\r
-         if (c >> 7) {\r
-            ptr->conds.utf8.wchars[n] = (w_char *) malloc(sizeof(w_char));\r
-            if (!ptr->conds.utf8.wchars[n]) return 1;\r
-            ptr->conds.utf8.wlen[n] = 1;\r
-            u8_u16(ptr->conds.utf8.wchars[n], 1, cs + i);\r
-            if ((c & 0xe0) == 0xe0) i+=2; else i++; // 3-byte UFT-8 character\r
-         } else {\r
-            ptr->conds.utf8.wchars[n] = NULL;\r
-            // not a group so just set the proper bit for this char\r
-            // but first handle special case of . inside condition\r
-            if (c == '.') {\r
-                ptr->conds.utf8.all[n] = 1;\r
-                // wild card character so set them all\r
-                for (j=0;j<(SETSIZE/2);j++) ptr->conds.utf8.ascii[j] = ptr->conds.utf8.ascii[j] | ((unsigned char)1 << n);\r
-            } else {\r
-                ptr->conds.utf8.all[n] = 0;\r
-                ptr->conds.utf8.ascii[(unsigned int) c] = ptr->conds.utf8.ascii[(unsigned int)c] | ((unsigned char)1 << n);\r
-            }\r
-         }\r
-         neg = 0;\r
-      }\r
-      n++;\r
-      ec = 0;\r
-      neg = 0;\r
-    }  \r
-  }\r
-\r
-    i++;\r
+  } else {\r
+    entry.numconds = 0;\r
+    entry.c.conds[0] = '\0';\r
   }\r
-  ptr->numconds = n;\r
   return 0;\r
 }\r
 \r
- // return 1 if s1 is a leading subset of s2\r
-/* inline int AffixMgr::isSubset(const char * s1, const char * s2)\r
- {\r
-    while ((*s1 == *s2) && *s1) {\r
-        s1++;\r
-        s2++;\r
-    }\r
-    return (*s1 == '\0');\r
- }\r
-*/\r
-\r
- // return 1 if s1 is a leading subset of s2 (dots are for infixes)\r
+// return 1 if s1 is a leading subset of s2 (dots are for infixes)\r
 inline int AffixMgr::isSubset(const char * s1, const char * s2)\r
  {\r
     while (((*s1 == *s2) || (*s1 == '.')) && (*s1 != '\0')) {\r
@@ -1140,7 +1108,7 @@ struct hentry * AffixMgr::prefix_check(const char * word, int len, char in_compo
     sfxappnd = NULL;\r
     \r
     // first handle the special case of 0 length prefixes\r
-    PfxEntry * pe = (PfxEntry *) pStart[0];\r
+    PfxEntry * pe = pStart[0];\r
     while (pe) {\r
         if (\r
             // fogemorpheme\r
@@ -1153,7 +1121,7 @@ struct hentry * AffixMgr::prefix_check(const char * word, int len, char in_compo
                     // check prefix\r
                     rv = pe->checkword(word, len, in_compound, needflag);\r
                     if (rv) {\r
-                        pfx=(AffEntry *)pe; // BUG: pfx not stateless\r
+                        pfx=pe; // BUG: pfx not stateless\r
                         return rv;\r
                     }\r
              }\r
@@ -1162,7 +1130,7 @@ struct hentry * AffixMgr::prefix_check(const char * word, int len, char in_compo
   \r
     // now handle the general case\r
     unsigned char sp = *((const unsigned char *)word);\r
-    PfxEntry * pptr = (PfxEntry *)pStart[sp];\r
+    PfxEntry * pptr = pStart[sp];\r
 \r
     while (pptr) {\r
         if (isSubset(pptr->getKey(),word)) {\r
@@ -1177,7 +1145,7 @@ struct hentry * AffixMgr::prefix_check(const char * word, int len, char in_compo
             // check prefix\r
                   rv = pptr->checkword(word, len, in_compound, needflag);\r
                   if (rv) {\r
-                    pfx=(AffEntry *)pptr; // BUG: pfx not stateless\r
+                    pfx=pptr; // BUG: pfx not stateless\r
                     return rv;\r
                   }\r
              }\r
@@ -1200,7 +1168,7 @@ struct hentry * AffixMgr::prefix_check_twosfx(const char * word, int len,
     sfxappnd = NULL;\r
     \r
     // first handle the special case of 0 length prefixes\r
-    PfxEntry * pe = (PfxEntry *) pStart[0];\r
+    PfxEntry * pe = pStart[0];\r
     \r
     while (pe) {\r
         rv = pe->check_twosfx(word, len, in_compound, needflag);\r
@@ -1210,13 +1178,13 @@ struct hentry * AffixMgr::prefix_check_twosfx(const char * word, int len,
   \r
     // now handle the general case\r
     unsigned char sp = *((const unsigned char *)word);\r
-    PfxEntry * pptr = (PfxEntry *)pStart[sp];\r
+    PfxEntry * pptr = pStart[sp];\r
 \r
     while (pptr) {\r
         if (isSubset(pptr->getKey(),word)) {\r
             rv = pptr->check_twosfx(word, len, in_compound, needflag);\r
             if (rv) {\r
-                pfx = (AffEntry *)pptr;\r
+                pfx = pptr;\r
                 return rv;\r
             }\r
             pptr = pptr->getNextEQ();\r
@@ -1228,7 +1196,6 @@ struct hentry * AffixMgr::prefix_check_twosfx(const char * word, int len,
     return NULL;\r
 }\r
 \r
-#ifdef HUNSPELL_EXPERIMENTAL\r
 // check word for prefixes\r
 char * AffixMgr::prefix_check_morph(const char * word, int len, char in_compound,\r
     const FLAG needflag)\r
@@ -1242,11 +1209,11 @@ char * AffixMgr::prefix_check_morph(const char * word, int len, char in_compound
     sfxappnd = NULL;\r
     \r
     // first handle the special case of 0 length prefixes\r
-    PfxEntry * pe = (PfxEntry *) pStart[0];\r
+    PfxEntry * pe = pStart[0];\r
     while (pe) {\r
        st = pe->check_morph(word,len,in_compound, needflag);\r
        if (st) {\r
-            strcat(result, st);\r
+            mystrcat(result, st, MAXLNLEN);\r
             free(st);\r
        }\r
        // if (rv) return rv;\r
@@ -1255,7 +1222,7 @@ char * AffixMgr::prefix_check_morph(const char * word, int len, char in_compound
   \r
     // now handle the general case\r
     unsigned char sp = *((const unsigned char *)word);\r
-    PfxEntry * pptr = (PfxEntry *)pStart[sp];\r
+    PfxEntry * pptr = pStart[sp];\r
 \r
     while (pptr) {\r
         if (isSubset(pptr->getKey(),word)) {\r
@@ -1264,8 +1231,8 @@ char * AffixMgr::prefix_check_morph(const char * word, int len, char in_compound
               // fogemorpheme\r
               if ((in_compound != IN_CPD_NOT) || !((pptr->getCont() && \r
                         (TESTAFF(pptr->getCont(), onlyincompound, pptr->getContLen()))))) {\r
-                    strcat(result, st);\r
-                    pfx = (AffEntry *)pptr;\r
+                    mystrcat(result, st, MAXLNLEN);\r
+                    pfx = pptr;\r
                 }\r
                 free(st);\r
             }\r
@@ -1293,11 +1260,11 @@ char * AffixMgr::prefix_check_twosfx_morph(const char * word, int len,
     sfxappnd = NULL;\r
     \r
     // first handle the special case of 0 length prefixes\r
-    PfxEntry * pe = (PfxEntry *) pStart[0];\r
+    PfxEntry * pe = pStart[0];\r
     while (pe) {\r
         st = pe->check_twosfx_morph(word,len,in_compound, needflag);\r
         if (st) {\r
-            strcat(result, st);\r
+            mystrcat(result, st, MAXLNLEN);\r
             free(st);\r
         }\r
         pe = pe->getNext();\r
@@ -1305,15 +1272,15 @@ char * AffixMgr::prefix_check_twosfx_morph(const char * word, int len,
   \r
     // now handle the general case\r
     unsigned char sp = *((const unsigned char *)word);\r
-    PfxEntry * pptr = (PfxEntry *)pStart[sp];\r
+    PfxEntry * pptr = pStart[sp];\r
 \r
     while (pptr) {\r
         if (isSubset(pptr->getKey(),word)) {\r
             st = pptr->check_twosfx_morph(word, len, in_compound, needflag);\r
             if (st) {\r
-                strcat(result, st);\r
+                mystrcat(result, st, MAXLNLEN);\r
                 free(st);\r
-                pfx = (AffEntry *)pptr;\r
+                pfx = pptr;\r
             }\r
             pptr = pptr->getNextEQ();\r
         } else {\r
@@ -1324,8 +1291,6 @@ char * AffixMgr::prefix_check_twosfx_morph(const char * word, int len,
     if (*result) return mystrdup(result);\r
     return NULL;\r
 }\r
-#endif // END OF HUNSPELL_EXPERIMENTAL CODE\r
-\r
 \r
 // Is word a non compound with a REP substitution (see checkcompoundrep)?\r
 int AffixMgr::cpdrep_check(const char * word, int wl)\r
@@ -1354,13 +1319,23 @@ int AffixMgr::cpdrep_check(const char * word, int wl)
 }\r
 \r
 // forbid compoundings when there are special patterns at word bound\r
-int AffixMgr::cpdpat_check(const char * word, int pos)\r
+int AffixMgr::cpdpat_check(const char * word, int pos, hentry * r1, hentry * r2, const char affixed)\r
 {\r
   int len;\r
   for (int i = 0; i < numcheckcpd; i++) {\r
       if (isSubset(checkcpdtable[i].pattern2, word + pos) &&\r
-        (len = strlen(checkcpdtable[i].pattern)) && (pos > len) &&\r
-        (strncmp(word + pos - len, checkcpdtable[i].pattern, len) == 0)) return 1;\r
+        (!r1 || !checkcpdtable[i].cond ||\r
+          (r1->astr && TESTAFF(r1->astr, checkcpdtable[i].cond, r1->alen))) &&\r
+        (!r2 || !checkcpdtable[i].cond2 ||\r
+          (r2->astr && TESTAFF(r2->astr, checkcpdtable[i].cond2, r2->alen))) &&\r
+        // zero length pattern => only TESTAFF\r
+        // zero pattern (0/flag) => unmodified stem (zero affixes allowed)\r
+        (!*(checkcpdtable[i].pattern) || (\r
+            (*(checkcpdtable[i].pattern)=='0' && r1->blen <= pos && strncmp(word + pos - r1->blen, r1->word, r1->blen) == 0) ||\r
+            (*(checkcpdtable[i].pattern)!='0' && (len = strlen(checkcpdtable[i].pattern)) &&\r
+                strncmp(word + pos - len, checkcpdtable[i].pattern, len) == 0)))) {\r
+            return 1;\r
+        }\r
   }\r
   return 0;\r
 }\r
@@ -1376,7 +1351,8 @@ int AffixMgr::cpdcase_check(const char * word, int pos)
       u8_u16(&w, 1, p);\r
       unsigned short a = (u.h << 8) + u.l;\r
       unsigned short b = (w.h << 8) + w.l;\r
-      if (((unicodetoupper(a, langnum) == a) || (unicodetoupper(b, langnum) == b))) return 1;\r
+      if (((unicodetoupper(a, langnum) == a) || (unicodetoupper(b, langnum) == b)) &&\r
+          (a != '-') && (b != '-')) return 1;\r
   } else {\r
       unsigned char a = *(word + pos - 1);\r
       unsigned char b = *(word + pos);\r
@@ -1392,15 +1368,40 @@ int AffixMgr::defcpd_check(hentry *** words, short wnum, hentry * rv, hentry **
   signed short btwp[MAXWORDLEN]; // word positions for metacharacters\r
   int btnum[MAXWORDLEN]; // number of matched characters in metacharacter positions\r
   short bt = 0;  \r
-  int i;\r
+  int i, j;\r
   int ok;\r
   int w = 0;\r
+\r
   if (!*words) {\r
     w = 1;\r
     *words = def;\r
   }\r
+\r
+  if (!*words) {\r
+    return 0;\r
+  }\r
+\r
   (*words)[wnum] = rv;\r
 \r
+  // has the last word COMPOUNDRULE flag?\r
+  if (rv->alen == 0) {\r
+    (*words)[wnum] = NULL;\r
+    if (w) *words = NULL;\r
+    return 0;\r
+  }\r
+  ok = 0;\r
+  for (i = 0; i < numdefcpd; i++) {\r
+    for (j = 0; j < defcpdtable[i].len; j++) {\r
+       if (defcpdtable[i].def[j] != '*' && defcpdtable[i].def[j] != '?' &&\r
+          TESTAFF(rv->astr, defcpdtable[i].def[j], rv->alen)) ok = 1;\r
+    }\r
+  }\r
+  if (ok == 0) {\r
+    (*words)[wnum] = NULL;\r
+    if (w) *words = NULL;\r
+    return 0;\r
+  }\r
+\r
   for (i = 0; i < numdefcpd; i++) {\r
     signed short pp = 0; // pattern position\r
     signed short wp = 0; // "words" position\r
@@ -1445,17 +1446,18 @@ int AffixMgr::defcpd_check(hentry *** words, short wnum, hentry * rv, hentry **
         while ((defcpdtable[i].len > r) && ((r+1) < defcpdtable[i].len) &&\r
             ((defcpdtable[i].def[r+1] == '*') || (defcpdtable[i].def[r+1] == '?'))) r+=2;\r
         if (defcpdtable[i].len <= r) return 1;\r
-    }    \r
+    }\r
     // backtrack\r
     if (bt) do {\r
         ok = 1;\r
         btnum[bt - 1]--;\r
         pp = btpp[bt - 1];\r
-        wp = btwp[bt - 1] + btnum[bt - 1];\r
+        wp = btwp[bt - 1] + (signed short) btnum[bt - 1];\r
     } while ((btnum[bt - 1] < 0) && --bt);\r
   } while (bt);\r
 \r
-  if (ok && ok2 && (!all || (defcpdtable[i].len <= pp))) return 1; \r
+  if (ok && ok2 && (!all || (defcpdtable[i].len <= pp))) return 1;\r
+\r
   // check zero ending\r
   while (ok && ok2 && (defcpdtable[i].len > pp) && ((pp+1) < defcpdtable[i].len) &&\r
     ((defcpdtable[i].def[pp+1] == '*') || (defcpdtable[i].def[pp+1] == '?'))) pp+=2;\r
@@ -1495,7 +1497,7 @@ short AffixMgr::get_syllable(const char * word, int wlen)
     } else if (cpdvowels_utf16) {\r
         w_char w[MAXWORDUTF8LEN];\r
         int i = u8_u16(w, MAXWORDUTF8LEN, word);\r
-        for (; i; i--) {\r
+        for (; i > 0; i--) {\r
             if (flag_bsearch((unsigned short *) cpdvowels_utf16,\r
                 ((unsigned short *) w)[i - 1], cpdvowels_utf16_len)) num++;\r
         }\r
@@ -1503,101 +1505,138 @@ short AffixMgr::get_syllable(const char * word, int wlen)
     return num;\r
 }\r
 \r
+void AffixMgr::setcminmax(int * cmin, int * cmax, const char * word, int len) {\r
+    if (utf8) {\r
+        int i;\r
+        for (*cmin = 0, i = 0; (i < cpdmin) && word[*cmin]; i++) {\r
+          for ((*cmin)++; (word[*cmin] & 0xc0) == 0x80; (*cmin)++);\r
+        }\r
+        for (*cmax = len, i = 0; (i < (cpdmin - 1)) && *cmax; i++) {\r
+          for ((*cmax)--; (word[*cmax] & 0xc0) == 0x80; (*cmax)--);\r
+        }\r
+    } else {\r
+        *cmin = cpdmin;\r
+        *cmax = len - cpdmin + 1;\r
+    }\r
+}\r
+\r
+\r
 // check if compound word is correctly spelled\r
 // hu_mov_rule = spec. Hungarian rule (XXX)\r
 struct hentry * AffixMgr::compound_check(const char * word, int len, \r
     short wordnum, short numsyllable, short maxwordnum, short wnum, hentry ** words = NULL,\r
-    char hu_mov_rule = 0, int * cmpdstemnum = NULL, int * cmpdstem = NULL, char is_sug = 0)\r
+    char hu_mov_rule = 0, char is_sug = 0, int * info = NULL)\r
 {\r
     int i; \r
     short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2;\r
-    int oldcmpdstemnum = 0;\r
     struct hentry * rv = NULL;\r
     struct hentry * rv_first;\r
     struct hentry * rwords[MAXWORDLEN]; // buffer for COMPOUND pattern checking\r
     char st [MAXWORDUTF8LEN + 4];\r
-    char ch;\r
+    char ch = '\0';\r
     int cmin;\r
     int cmax;\r
-    \r
+    int striple = 0;\r
+    int scpd = 0;\r
+    int soldi = 0;\r
+    int oldcmin = 0;\r
+    int oldcmax = 0;\r
+    int oldlen = 0;\r
+    int checkedstriple = 0;\r
+    int onlycpdrule;\r
+    int affixed = 0;\r
+    hentry ** oldwords = words;\r
+\r
     int checked_prefix;\r
 \r
-#ifdef HUNSTEM\r
-    if (cmpdstemnum) {\r
-        if (wordnum == 0) {\r
-            *cmpdstemnum = 1;\r
-        } else {\r
-            (*cmpdstemnum)++;\r
-        }\r
-    }\r
-#endif\r
-    if (utf8) {\r
-        for (cmin = 0, i = 0; (i < cpdmin) && word[cmin]; i++) {\r
-          cmin++;\r
-          for (; (word[cmin] & 0xc0) == 0x80; cmin++);\r
-        }\r
-        for (cmax = len, i = 0; (i < (cpdmin - 1)) && cmax; i++) {\r
-          cmax--;\r
-          for (; (word[cmax] & 0xc0) == 0x80; cmax--);\r
-        }\r
-    } else {\r
-        cmin = cpdmin;\r
-        cmax = len - cpdmin + 1;\r
-    }\r
+    setcminmax(&cmin, &cmax, word, len);\r
 \r
     strcpy(st, word);\r
 \r
     for (i = cmin; i < cmax; i++) {\r
+        // go to end of the UTF-8 character\r
+        if (utf8) {\r
+            for (; (st[i] & 0xc0) == 0x80; i++);\r
+            if (i >= cmax) return NULL;\r
+        }\r
+\r
+        words = oldwords;\r
+        onlycpdrule = (words) ? 1 : 0;\r
+\r
+        do { // onlycpdrule loop\r
 \r
         oldnumsyllable = numsyllable;\r
         oldwordnum = wordnum;\r
         checked_prefix = 0;\r
 \r
-        // go to end of the UTF-8 character\r
-        if (utf8) {\r
-            for (; (st[i] & 0xc0) == 0x80; i++);\r
-            if (i >= cmax) return NULL;\r
+\r
+        do { // simplified checkcompoundpattern loop\r
+\r
+        if (scpd > 0) {\r
+          for (; scpd <= numcheckcpd && (!checkcpdtable[scpd-1].pattern3 ||\r
+            strncmp(word + i, checkcpdtable[scpd-1].pattern3, strlen(checkcpdtable[scpd-1].pattern3)) != 0); scpd++);\r
+\r
+          if (scpd > numcheckcpd) break; // break simplified checkcompoundpattern loop\r
+          strcpy(st + i, checkcpdtable[scpd-1].pattern);\r
+          soldi = i;\r
+          i += strlen(checkcpdtable[scpd-1].pattern);\r
+          strcpy(st + i, checkcpdtable[scpd-1].pattern2);\r
+          strcpy(st + i + strlen(checkcpdtable[scpd-1].pattern2), word + soldi + strlen(checkcpdtable[scpd-1].pattern3));\r
+\r
+          oldlen = len;\r
+          len += strlen(checkcpdtable[scpd-1].pattern) + strlen(checkcpdtable[scpd-1].pattern2) - strlen(checkcpdtable[scpd-1].pattern3);\r
+          oldcmin = cmin;\r
+          oldcmax = cmax;\r
+          setcminmax(&cmin, &cmax, st, len);\r
+\r
+          cmax = len - cpdmin + 1;\r
         }\r
 \r
-        \r
         ch = st[i];\r
         st[i] = '\0';\r
 \r
         sfx = NULL;\r
         pfx = NULL;\r
-        \r
+\r
         // FIRST WORD\r
-        \r
+\r
+        affixed = 1;\r
         rv = lookup(st); // perhaps without prefix\r
 \r
         // search homonym with compound flag\r
         while ((rv) && !hu_mov_rule &&\r
-            ((pseudoroot && TESTAFF(rv->astr, pseudoroot, rv->alen)) ||\r
-                !((compoundflag && !words && TESTAFF(rv->astr, compoundflag, rv->alen)) ||\r
-                  (compoundbegin && !wordnum &&\r
+            ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||\r
+                !((compoundflag && !words && !onlycpdrule && TESTAFF(rv->astr, compoundflag, rv->alen)) ||\r
+                  (compoundbegin && !wordnum && !onlycpdrule && \r
                         TESTAFF(rv->astr, compoundbegin, rv->alen)) ||\r
-                  (compoundmiddle && wordnum && !words &&\r
+                  (compoundmiddle && wordnum && !words && !onlycpdrule &&\r
                     TESTAFF(rv->astr, compoundmiddle, rv->alen)) ||\r
-                  (numdefcpd &&\r
+                  (numdefcpd && onlycpdrule &&\r
                     ((!words && !wordnum && defcpd_check(&words, wnum, rv, (hentry **) &rwords, 0)) ||\r
-                    (words && defcpd_check(&words, wnum, rv, (hentry **) &rwords, 0))))\r
-                  ))) {\r
+                    (words && defcpd_check(&words, wnum, rv, (hentry **) &rwords, 0))))) ||\r
+                  (scpd != 0 && checkcpdtable[scpd-1].cond != FLAG_NULL &&\r
+                    !TESTAFF(rv->astr, checkcpdtable[scpd-1].cond, rv->alen)))\r
+                  ) {\r
             rv = rv->next_homonym;\r
         }\r
 \r
+        if (rv) affixed = 0;\r
+\r
         if (!rv) {\r
+            if (onlycpdrule) break;\r
             if (compoundflag && \r
              !(rv = prefix_check(st, i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundflag))) {\r
                 if ((rv = suffix_check(st, i, 0, NULL, NULL, 0, NULL,\r
                         FLAG_NULL, compoundflag, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) && !hu_mov_rule &&\r
-                    ((SfxEntry*)sfx)->getCont() &&\r
-                        ((compoundforbidflag && TESTAFF(((SfxEntry*)sfx)->getCont(), compoundforbidflag, \r
-                            ((SfxEntry*)sfx)->getContLen())) || (compoundend &&\r
-                        TESTAFF(((SfxEntry*)sfx)->getCont(), compoundend, \r
-                            ((SfxEntry*)sfx)->getContLen())))) {\r
+                    sfx->getCont() &&\r
+                        ((compoundforbidflag && TESTAFF(sfx->getCont(), compoundforbidflag, \r
+                            sfx->getContLen())) || (compoundend &&\r
+                        TESTAFF(sfx->getCont(), compoundend, \r
+                            sfx->getContLen())))) {\r
                         rv = NULL;\r
                 }\r
             }\r
+\r
             if (rv ||\r
               (((wordnum == 0) && compoundbegin &&\r
                 ((rv = suffix_check(st, i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundbegin, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||\r
@@ -1606,50 +1645,53 @@ struct hentry * AffixMgr::compound_check(const char * word, int len,
                 ((rv = suffix_check(st, i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundmiddle, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||\r
                 (rv = prefix_check(st, i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundmiddle)))))\r
               ) checked_prefix = 1;\r
-        // else check forbiddenwords and pseudoroot\r
+        // else check forbiddenwords and needaffix\r
         } else if (rv->astr && (TESTAFF(rv->astr, forbiddenword, rv->alen) ||\r
-            TESTAFF(rv->astr, pseudoroot, rv->alen) || \r
+            TESTAFF(rv->astr, needaffix, rv->alen) ||\r
+            TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) ||\r
             (is_sug && nosuggest && TESTAFF(rv->astr, nosuggest, rv->alen))\r
              )) {\r
                 st[i] = ch;\r
-                continue;\r
+                //continue;\r
+                break;\r
         }\r
 \r
             // check non_compound flag in suffix and prefix\r
             if ((rv) && !hu_mov_rule &&\r
-                ((pfx && ((PfxEntry*)pfx)->getCont() &&\r
-                    TESTAFF(((PfxEntry*)pfx)->getCont(), compoundforbidflag, \r
-                        ((PfxEntry*)pfx)->getContLen())) ||\r
-                (sfx && ((SfxEntry*)sfx)->getCont() &&\r
-                    TESTAFF(((SfxEntry*)sfx)->getCont(), compoundforbidflag, \r
-                        ((SfxEntry*)sfx)->getContLen())))) {\r
+                ((pfx && pfx->getCont() &&\r
+                    TESTAFF(pfx->getCont(), compoundforbidflag, \r
+                        pfx->getContLen())) ||\r
+                (sfx && sfx->getCont() &&\r
+                    TESTAFF(sfx->getCont(), compoundforbidflag, \r
+                        sfx->getContLen())))) {\r
                     rv = NULL;\r
             }\r
 \r
             // check compoundend flag in suffix and prefix\r
             if ((rv) && !checked_prefix && compoundend && !hu_mov_rule &&\r
-                ((pfx && ((PfxEntry*)pfx)->getCont() &&\r
-                    TESTAFF(((PfxEntry*)pfx)->getCont(), compoundend, \r
-                        ((PfxEntry*)pfx)->getContLen())) ||\r
-                (sfx && ((SfxEntry*)sfx)->getCont() &&\r
-                    TESTAFF(((SfxEntry*)sfx)->getCont(), compoundend, \r
-                        ((SfxEntry*)sfx)->getContLen())))) {\r
+                ((pfx && pfx->getCont() &&\r
+                    TESTAFF(pfx->getCont(), compoundend, \r
+                        pfx->getContLen())) ||\r
+                (sfx && sfx->getCont() &&\r
+                    TESTAFF(sfx->getCont(), compoundend, \r
+                        sfx->getContLen())))) {\r
                     rv = NULL;\r
             }\r
-            \r
+\r
             // check compoundmiddle flag in suffix and prefix\r
             if ((rv) && !checked_prefix && (wordnum==0) && compoundmiddle && !hu_mov_rule &&\r
-                ((pfx && ((PfxEntry*)pfx)->getCont() &&\r
-                    TESTAFF(((PfxEntry*)pfx)->getCont(), compoundmiddle, \r
-                        ((PfxEntry*)pfx)->getContLen())) ||\r
-                (sfx && ((SfxEntry*)sfx)->getCont() &&\r
-                    TESTAFF(((SfxEntry*)sfx)->getCont(), compoundmiddle, \r
-                        ((SfxEntry*)sfx)->getContLen())))) {\r
+                ((pfx && pfx->getCont() &&\r
+                    TESTAFF(pfx->getCont(), compoundmiddle, \r
+                        pfx->getContLen())) ||\r
+                (sfx && sfx->getCont() &&\r
+                    TESTAFF(sfx->getCont(), compoundmiddle, \r
+                        sfx->getContLen())))) {\r
                     rv = NULL;\r
-            }       \r
+            }\r
 \r
         // check forbiddenwords\r
         if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) ||\r
+            TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) ||\r
             (is_sug && nosuggest && TESTAFF(rv->astr, nosuggest, rv->alen)))) {\r
                 return NULL;\r
             }\r
@@ -1676,63 +1718,78 @@ struct hentry * AffixMgr::compound_check(const char * word, int len,
                 )\r
               )\r
 // END of LANG_hu section\r
+          ) &&\r
+          (\r
+             // test CHECKCOMPOUNDPATTERN conditions\r
+             scpd == 0 || checkcpdtable[scpd-1].cond == FLAG_NULL || \r
+                TESTAFF(rv->astr, checkcpdtable[scpd-1].cond, rv->alen)\r
           )\r
-          && ! (( checkcompoundtriple && // test triple letters\r
+          && ! (( checkcompoundtriple && scpd == 0 && !words && // test triple letters\r
                    (word[i-1]==word[i]) && (\r
-                      ((i>1) && (word[i-1]==word[i-2])) || \r
+                      ((i>1) && (word[i-1]==word[i-2])) ||\r
                       ((word[i-1]==word[i+1])) // may be word[i+1] == '\0'\r
                    )\r
                ) ||\r
-               ( \r
-                 // test CHECKCOMPOUNDPATTERN\r
-                 numcheckcpd && cpdpat_check(word, i)\r
-               ) ||\r
-               ( \r
-                 checkcompoundcase && cpdcase_check(word, i)\r
+               (\r
+                 checkcompoundcase && scpd == 0 && !words && cpdcase_check(word, i)\r
                ))\r
          )\r
 // LANG_hu section: spec. Hungarian rule\r
          || ((!rv) && (langnum == LANG_hu) && hu_mov_rule && (rv = affix_check(st,i)) &&\r
-              (sfx && ((SfxEntry*)sfx)->getCont() && ( // XXX hardwired Hungarian dic. codes\r
-                        TESTAFF(((SfxEntry*)sfx)->getCont(), (unsigned short) 'x', ((SfxEntry*)sfx)->getContLen()) ||\r
-                        TESTAFF(((SfxEntry*)sfx)->getCont(), (unsigned short) '%', ((SfxEntry*)sfx)->getContLen())\r
-                    )                \r
+              (sfx && sfx->getCont() && ( // XXX hardwired Hungarian dic. codes\r
+                        TESTAFF(sfx->getCont(), (unsigned short) 'x', sfx->getContLen()) ||\r
+                        TESTAFF(sfx->getCont(), (unsigned short) '%', sfx->getContLen())\r
+                    )\r
                )\r
              )\r
-// END of LANG_hu section\r
-         ) {\r
+         ) { // first word is ok condition\r
 \r
 // LANG_hu section: spec. Hungarian rule\r
             if (langnum == LANG_hu) {\r
-                // calculate syllable number of the word            \r
+                // calculate syllable number of the word\r
                 numsyllable += get_syllable(st, i);\r
-\r
                 // + 1 word, if syllable number of the prefix > 1 (hungarian convention)\r
-                if (pfx && (get_syllable(((PfxEntry *)pfx)->getKey(),strlen(((PfxEntry *)pfx)->getKey())) > 1)) wordnum++;\r
+                if (pfx && (get_syllable(pfx->getKey(),strlen(pfx->getKey())) > 1)) wordnum++;\r
             }\r
 // END of LANG_hu section\r
 \r
-#ifdef HUNSTEM\r
-            if (cmpdstem) cmpdstem[*cmpdstemnum - 1] = i;\r
-#endif\r
-\r
             // NEXT WORD(S)\r
             rv_first = rv;\r
-            rv = lookup((word+i)); // perhaps without prefix\r
+            st[i] = ch;\r
+\r
+        do { // striple loop\r
+\r
+            // check simplifiedtriple\r
+            if (simplifiedtriple) { \r
+              if (striple) { \r
+                checkedstriple = 1;\r
+                i--; // check "fahrt" instead of "ahrt" in "Schiffahrt"\r
+              } else if (i > 2 && *(word+i - 1) == *(word + i - 2)) striple = 1;\r
+            }\r
+\r
+            rv = lookup((st+i)); // perhaps without prefix\r
 \r
         // search homonym with compound flag\r
-        while ((rv) && ((pseudoroot && TESTAFF(rv->astr, pseudoroot, rv->alen)) ||\r
+        while ((rv) && ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||\r
                         !((compoundflag && !words && TESTAFF(rv->astr, compoundflag, rv->alen)) ||\r
                           (compoundend && !words && TESTAFF(rv->astr, compoundend, rv->alen)) ||\r
-                           (numdefcpd && words && defcpd_check(&words, wnum + 1, rv, NULL,1))))) {\r
+                           (numdefcpd && words && defcpd_check(&words, wnum + 1, rv, NULL,1))) ||\r
+                             (scpd != 0 && checkcpdtable[scpd-1].cond2 != FLAG_NULL &&\r
+                                !TESTAFF(rv->astr, checkcpdtable[scpd-1].cond2, rv->alen))\r
+                           )) {\r
             rv = rv->next_homonym;\r
         }\r
 \r
-            if (rv && words && words[wnum + 1]) return rv;\r
+            // check FORCEUCASE\r
+            if (rv && forceucase && (rv) &&\r
+                (TESTAFF(rv->astr, forceucase, rv->alen)) && !(info && *info & SPELL_ORIGCAP)) rv = NULL;\r
+\r
+            if (rv && words && words[wnum + 1]) return rv_first;\r
 \r
             oldnumsyllable2 = numsyllable;\r
             oldwordnum2 = wordnum;\r
 \r
+\r
 // LANG_hu section: spec. Hungarian rule, XXX hardwired dictionary code\r
             if ((rv) && (langnum == LANG_hu) && (TESTAFF(rv->astr, 'I', rv->alen)) && !(TESTAFF(rv->astr, 'J', rv->alen))) {\r
                 numsyllable--;\r
@@ -1747,6 +1804,7 @@ struct hentry * AffixMgr::compound_check(const char * word, int len,
 \r
             // check forbiddenwords\r
             if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) ||\r
+                TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) ||\r
                (is_sug && nosuggest && TESTAFF(rv->astr, nosuggest, rv->alen)))) return NULL;\r
 \r
             // second word is acceptable, as a root?\r
@@ -1760,50 +1818,70 @@ struct hentry * AffixMgr::compound_check(const char * word, int len,
                     )\r
                 && (\r
                       ((cpdwordmax==-1) || (wordnum+1<cpdwordmax)) || \r
-                      ((cpdmaxsyllable==0) || \r
-                          (numsyllable + get_syllable(rv->word,rv->wlen)<=cpdmaxsyllable))\r
-                    )\r
-                && (\r
+                      ((cpdmaxsyllable!=0) && \r
+                          (numsyllable + get_syllable(HENTRY_WORD(rv), rv->clen)<=cpdmaxsyllable))\r
+                    ) &&\r
+               (\r
+                 // test CHECKCOMPOUNDPATTERN\r
+                 !numcheckcpd || scpd != 0 || !cpdpat_check(word, i, rv_first, rv, 0)\r
+               ) &&\r
+                (\r
                      (!checkcompounddup || (rv != rv_first))\r
                    )\r
+            // test CHECKCOMPOUNDPATTERN conditions\r
+                && (scpd == 0 || checkcpdtable[scpd-1].cond2 == FLAG_NULL ||\r
+                      TESTAFF(rv->astr, checkcpdtable[scpd-1].cond2, rv->alen))\r
                 )\r
                  {\r
                       // forbid compound word, if it is a non compound word with typical fault\r
                       if (checkcompoundrep && cpdrep_check(word,len)) return NULL;\r
-                      return rv;\r
+                      return rv_first;\r
             }\r
 \r
-            numsyllable = oldnumsyllable2 ;\r
+            numsyllable = oldnumsyllable2;\r
             wordnum = oldwordnum2;\r
 \r
             // perhaps second word has prefix or/and suffix\r
             sfx = NULL;\r
             sfxflag = FLAG_NULL;\r
-            rv = (compoundflag) ? affix_check((word+i),strlen(word+i), compoundflag, IN_CPD_END) : NULL;\r
-            if (!rv && compoundend) {\r
+            rv = (compoundflag && !onlycpdrule) ? affix_check((word+i),strlen(word+i), compoundflag, IN_CPD_END) : NULL;\r
+            if (!rv && compoundend && !onlycpdrule) {\r
                 sfx = NULL;\r
                 pfx = NULL;\r
                 rv = affix_check((word+i),strlen(word+i), compoundend, IN_CPD_END);\r
             }\r
-            \r
+\r
             if (!rv && numdefcpd && words) {\r
                 rv = affix_check((word+i),strlen(word+i), 0, IN_CPD_END);\r
-                if (rv && defcpd_check(&words, wnum + 1, rv, NULL, 1)) return rv;\r
+                if (rv && defcpd_check(&words, wnum + 1, rv, NULL, 1)) return rv_first;\r
+                rv = NULL;\r
             }\r
 \r
+            // test CHECKCOMPOUNDPATTERN conditions (allowed forms)\r
+            if (rv && !(scpd == 0 || checkcpdtable[scpd-1].cond2 == FLAG_NULL || \r
+                TESTAFF(rv->astr, checkcpdtable[scpd-1].cond2, rv->alen))) rv = NULL;\r
+\r
+            // test CHECKCOMPOUNDPATTERN conditions (forbidden compounds)\r
+            if (rv && numcheckcpd && scpd == 0 && cpdpat_check(word, i, rv_first, rv, affixed)) rv = NULL;\r
+\r
             // check non_compound flag in suffix and prefix\r
             if ((rv) && \r
-                ((pfx && ((PfxEntry*)pfx)->getCont() &&\r
-                    TESTAFF(((PfxEntry*)pfx)->getCont(), compoundforbidflag, \r
-                        ((PfxEntry*)pfx)->getContLen())) ||\r
-                (sfx && ((SfxEntry*)sfx)->getCont() &&\r
-                    TESTAFF(((SfxEntry*)sfx)->getCont(), compoundforbidflag, \r
-                        ((SfxEntry*)sfx)->getContLen())))) {\r
+                ((pfx && pfx->getCont() &&\r
+                    TESTAFF(pfx->getCont(), compoundforbidflag, \r
+                        pfx->getContLen())) ||\r
+                (sfx && sfx->getCont() &&\r
+                    TESTAFF(sfx->getCont(), compoundforbidflag, \r
+                        sfx->getContLen())))) {\r
                     rv = NULL;\r
             }\r
 \r
+            // check FORCEUCASE\r
+            if (rv && forceucase && (rv) &&\r
+                (TESTAFF(rv->astr, forceucase, rv->alen)) && !(info && *info & SPELL_ORIGCAP)) rv = NULL;\r
+\r
             // check forbiddenwords\r
             if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) ||\r
+                TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) ||\r
                (is_sug && nosuggest && TESTAFF(rv->astr, nosuggest, rv->alen)))) return NULL;\r
 \r
             // pfxappnd = prefix of word+i, or NULL\r
@@ -1814,7 +1892,7 @@ struct hentry * AffixMgr::compound_check(const char * word, int len,
             if (langnum == LANG_hu) {\r
                 // calculate syllable number of the word\r
                 numsyllable += get_syllable(word + i, strlen(word + i));\r
-                \r
+\r
                 // - affix syllable num.\r
                 // XXX only second suffix (inflections, not derivations)\r
                 if (sfxappnd) {\r
@@ -1822,22 +1900,22 @@ struct hentry * AffixMgr::compound_check(const char * word, int len,
                     numsyllable -= get_syllable(tmp, strlen(tmp));\r
                     free(tmp);\r
                 }\r
-                \r
+\r
                 // + 1 word, if syllable number of the prefix > 1 (hungarian convention)\r
-                if (pfx && (get_syllable(((PfxEntry *)pfx)->getKey(),strlen(((PfxEntry *)pfx)->getKey())) > 1)) wordnum++;\r
+                if (pfx && (get_syllable(pfx->getKey(),strlen(pfx->getKey())) > 1)) wordnum++;\r
 \r
                 // increment syllable num, if last word has a SYLLABLENUM flag\r
                 // and the suffix is beginning `s'\r
-            \r
+\r
                 if (cpdsyllablenum) {\r
                     switch (sfxflag) {\r
                         case 'c': { numsyllable+=2; break; }\r
                         case 'J': { numsyllable += 1; break; }\r
-                        case 'I': { if (TESTAFF(rv->astr, 'J', rv->alen)) numsyllable += 1; break; }\r
+                        case 'I': { if (rv && TESTAFF(rv->astr, 'J', rv->alen)) numsyllable += 1; break; }\r
                     }\r
                 }\r
             }\r
-            \r
+\r
             // increment word number, if the second word has a compoundroot flag\r
             if ((rv) && (compoundroot) && \r
                 (TESTAFF(rv->astr, compoundroot, rv->alen))) {\r
@@ -1851,7 +1929,7 @@ struct hentry * AffixMgr::compound_check(const char * word, int len,
             if ((rv) && \r
                     (\r
                       ((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) || \r
-                      ((cpdmaxsyllable == 0) || \r
+                      ((cpdmaxsyllable != 0) && \r
                           (numsyllable <= cpdmaxsyllable))\r
                     )\r
                 && (\r
@@ -1859,41 +1937,91 @@ struct hentry * AffixMgr::compound_check(const char * word, int len,
                    )) {\r
                     // forbid compound word, if it is a non compound word with typical fault\r
                     if (checkcompoundrep && cpdrep_check(word, len)) return NULL;\r
-                    return rv;\r
+                    return rv_first;\r
             }\r
 \r
             numsyllable = oldnumsyllable2;\r
             wordnum = oldwordnum2;\r
-#ifdef HUNSTEM\r
-            if (cmpdstemnum) oldcmpdstemnum = *cmpdstemnum;\r
-#endif\r
+\r
             // perhaps second word is a compound word (recursive call)\r
             if (wordnum < maxwordnum) {\r
-                rv = compound_check((word+i),strlen(word+i), wordnum+1,\r
-                     numsyllable, maxwordnum, wnum + 1, words,\r
-                     0, cmpdstemnum, cmpdstem, is_sug);\r
+                rv = compound_check((st+i),strlen(st+i), wordnum+1,\r
+                     numsyllable, maxwordnum, wnum + 1, words, 0, is_sug, info);\r
+                \r
+                if (rv && numcheckcpd && ((scpd == 0 && cpdpat_check(word, i, rv_first, rv, affixed)) ||\r
+                   (scpd != 0 && !cpdpat_check(word, i, rv_first, rv, affixed)))) rv = NULL;\r
             } else {\r
                 rv=NULL;\r
             }\r
             if (rv) {\r
                 // forbid compound word, if it is a non compound word with typical fault\r
-                if (checkcompoundrep && cpdrep_check(word, len)) return NULL;\r
-                return rv;\r
-            } else {\r
-#ifdef HUNSTEM\r
-            if (cmpdstemnum) *cmpdstemnum = oldcmpdstemnum;\r
-#endif\r
+                if (checkcompoundrep || forbiddenword) {\r
+                    struct hentry * rv2 = NULL;\r
+\r
+                    if (checkcompoundrep && cpdrep_check(word, len)) return NULL;\r
+                    \r
+                    // check first part\r
+                    if (strncmp(rv->word, word + i, rv->blen) == 0) {\r
+                        char r = *(st + i + rv->blen);\r
+                        *(st + i + rv->blen) = '\0';\r
+                        \r
+                        if (checkcompoundrep && cpdrep_check(st, i + rv->blen)) {\r
+                            *(st + i + rv->blen) = r;\r
+                            continue;\r
+                        }\r
+\r
+                        if (forbiddenword) {\r
+                            rv2 = lookup(word);\r
+                            if (!rv2) rv2 = affix_check(word, len);\r
+                            if (rv2 && rv2->astr && TESTAFF(rv2->astr, forbiddenword, rv2->alen) && \r
+                                (strncmp(rv2->word, st, i + rv->blen) == 0)) {\r
+                                    return NULL;\r
+                            }\r
+                        }\r
+                        *(st + i + rv->blen) = r;\r
+                    }\r
+                }\r
+                return rv_first;\r
             }\r
+          } while (striple && !checkedstriple); // end of striple loop\r
+\r
+          if (checkedstriple) {\r
+            i++;\r
+            checkedstriple = 0;\r
+            striple = 0;\r
+          }\r
+\r
+        } // first word is ok condition\r
+\r
+        if (soldi != 0) {\r
+          i = soldi;\r
+          soldi = 0;\r
+          len = oldlen;\r
+          cmin = oldcmin;\r
+          cmax = oldcmax;\r
         }\r
-        st[i] = ch;\r
+        scpd++;\r
+\r
+\r
+        } while (!onlycpdrule && simplifiedcpd && scpd <= numcheckcpd); // end of simplifiedcpd loop\r
+\r
+        scpd = 0;\r
         wordnum = oldwordnum;\r
         numsyllable = oldnumsyllable;\r
+\r
+        if (soldi != 0) {\r
+          i = soldi;\r
+          strcpy(st, word); // XXX add more optim.\r
+          soldi = 0;\r
+        } else st[i] = ch;\r
+\r
+        } while (numdefcpd && oldwordnum == 0 && !onlycpdrule && (onlycpdrule = 1)); // end of onlycpd loop\r
+\r
     }\r
-    \r
+\r
     return NULL;\r
-}    \r
+}\r
 \r
-#ifdef HUNSPELL_EXPERIMENTAL\r
 // check if compound word is correctly spelled\r
 // hu_mov_rule = spec. Hungarian rule (XXX)\r
 int AffixMgr::compound_check_morph(const char * word, int len, \r
@@ -1909,26 +2037,18 @@ int AffixMgr::compound_check_morph(const char * word, int len,
     struct hentry * rwords[MAXWORDLEN]; // buffer for COMPOUND pattern checking\r
     char st [MAXWORDUTF8LEN + 4];\r
     char ch;\r
-    \r
+\r
     int checked_prefix;\r
     char presult[MAXLNLEN];\r
 \r
     int cmin;\r
     int cmax;\r
-    \r
-    if (utf8) {\r
-        for (cmin = 0, i = 0; (i < cpdmin) && word[cmin]; i++) {\r
-          cmin++;\r
-          for (; (word[cmin] & 0xc0) == 0x80; cmin++);\r
-        }\r
-        for (cmax = len, i = 0; (i < (cpdmin - 1)) && cmax; i++) {\r
-          cmax--;\r
-          for (; (word[cmax] & 0xc0) == 0x80; cmax--);\r
-        }\r
-    } else {\r
-        cmin = cpdmin;\r
-        cmax = len - cpdmin + 1;\r
-    }\r
+\r
+    int onlycpdrule;\r
+    int affixed = 0;\r
+    hentry ** oldwords = words;\r
+\r
+    setcminmax(&cmin, &cmax, word, len);\r
 \r
     strcpy(st, word);\r
 \r
@@ -1942,54 +2062,73 @@ int AffixMgr::compound_check_morph(const char * word, int len,
             for (; (st[i] & 0xc0) == 0x80; i++);\r
             if (i >= cmax) return 0;\r
         }\r
-        \r
+\r
+        words = oldwords;\r
+        onlycpdrule = (words) ? 1 : 0;\r
+\r
+        do { // onlycpdrule loop\r
+\r
+        oldnumsyllable = numsyllable;\r
+        oldwordnum = wordnum;\r
+        checked_prefix = 0;\r
+\r
         ch = st[i];\r
         st[i] = '\0';\r
         sfx = NULL;\r
 \r
         // FIRST WORD\r
+\r
+        affixed = 1;\r
+\r
         *presult = '\0';\r
-        if (partresult) strcat(presult, partresult);\r
-        \r
+        if (partresult) mystrcat(presult, partresult, MAXLNLEN);\r
+\r
         rv = lookup(st); // perhaps without prefix\r
 \r
         // search homonym with compound flag\r
         while ((rv) && !hu_mov_rule && \r
-            ((pseudoroot && TESTAFF(rv->astr, pseudoroot, rv->alen)) ||\r
-                !((compoundflag && !words && TESTAFF(rv->astr, compoundflag, rv->alen)) ||\r
-                (compoundbegin && !wordnum &&\r
+            ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||\r
+                !((compoundflag && !words && !onlycpdrule && TESTAFF(rv->astr, compoundflag, rv->alen)) ||\r
+                (compoundbegin && !wordnum && !onlycpdrule &&\r
                         TESTAFF(rv->astr, compoundbegin, rv->alen)) ||\r
-                (compoundmiddle && wordnum && !words &&\r
+                (compoundmiddle && wordnum && !words && !onlycpdrule &&\r
                     TESTAFF(rv->astr, compoundmiddle, rv->alen)) ||\r
-                  (numdefcpd &&\r
+                  (numdefcpd && onlycpdrule &&\r
                     ((!words && !wordnum && defcpd_check(&words, wnum, rv, (hentry **) &rwords, 0)) ||\r
                     (words && defcpd_check(&words, wnum, rv, (hentry **) &rwords, 0))))\r
                   ))) {\r
             rv = rv->next_homonym;\r
         }\r
 \r
+        if (rv) affixed = 0;\r
+\r
         if (rv)  {\r
-            if (rv->description) {\r
-                if ((!rv->astr) || !TESTAFF(rv->astr, lemma_present, rv->alen))\r
-                                        strcat(presult, st);\r
-                strcat(presult, rv->description);\r
+            sprintf(presult + strlen(presult), "%c%s%s", MSEP_FLD, MORPH_PART, st);\r
+            if (!HENTRY_FIND(rv, MORPH_STEM)) {\r
+                sprintf(presult + strlen(presult), "%c%s%s", MSEP_FLD, MORPH_STEM, st);\r
             }\r
-        }\r
-        \r
+            // store the pointer of the hash entry\r
+//            sprintf(presult + strlen(presult), "%c%s%p", MSEP_FLD, MORPH_HENTRY, rv);\r
+            if (HENTRY_DATA(rv)) {\r
+                sprintf(presult + strlen(presult), "%c%s", MSEP_FLD, HENTRY_DATA2(rv));\r
+            }\r
+        }        \r
+\r
         if (!rv) {\r
-            if (compoundflag && \r
+            if (onlycpdrule) break;\r
+            if (compoundflag &&\r
              !(rv = prefix_check(st, i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundflag))) {\r
                 if ((rv = suffix_check(st, i, 0, NULL, NULL, 0, NULL,\r
                         FLAG_NULL, compoundflag, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) && !hu_mov_rule &&\r
-                    ((SfxEntry*)sfx)->getCont() &&\r
-                        ((compoundforbidflag && TESTAFF(((SfxEntry*)sfx)->getCont(), compoundforbidflag, \r
-                            ((SfxEntry*)sfx)->getContLen())) || (compoundend &&\r
-                        TESTAFF(((SfxEntry*)sfx)->getCont(), compoundend, \r
-                            ((SfxEntry*)sfx)->getContLen())))) {\r
+                    sfx->getCont() &&\r
+                        ((compoundforbidflag && TESTAFF(sfx->getCont(), compoundforbidflag, \r
+                            sfx->getContLen())) || (compoundend &&\r
+                        TESTAFF(sfx->getCont(), compoundend, \r
+                            sfx->getContLen())))) {\r
                         rv = NULL;\r
                 }\r
             }\r
-            \r
+\r
             if (rv ||\r
               (((wordnum == 0) && compoundbegin &&\r
                 ((rv = suffix_check(st, i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundbegin, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||\r
@@ -1998,74 +2137,69 @@ int AffixMgr::compound_check_morph(const char * word, int len,
                 ((rv = suffix_check(st, i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundmiddle, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||\r
                 (rv = prefix_check(st, i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN, compoundmiddle)))))\r
               ) {\r
-                //char * p = prefix_check_morph(st, i, 0, compound);\r
+                // char * p = prefix_check_morph(st, i, 0, compound);\r
                 char * p = NULL;\r
                 if (compoundflag) p = affix_check_morph(st, i, compoundflag);\r
                 if (!p || (*p == '\0')) {\r
+                   if (p) free(p);\r
+                   p = NULL;\r
                    if ((wordnum == 0) && compoundbegin) {\r
                      p = affix_check_morph(st, i, compoundbegin);\r
                    } else if ((wordnum > 0) && compoundmiddle) {\r
                      p = affix_check_morph(st, i, compoundmiddle);                   \r
                    }\r
                 }\r
-                if (*p != '\0') {\r
-                    line_uniq(p);\r
-                    if (strchr(p, '\n')) {\r
-                        strcat(presult, "(");\r
-                        strcat(presult, line_join(p, '|'));\r
-                        strcat(presult, ")");\r
-                      } else {\r
-                        strcat(presult, p);\r
-                      }\r
-                }\r
-                if (presult[strlen(presult) - 1] == '\n') {\r
-                    presult[strlen(presult) - 1] = '\0';\r
+                if (p && (*p != '\0')) {\r
+                    sprintf(presult + strlen(presult), "%c%s%s%s", MSEP_FLD,\r
+                        MORPH_PART, st, line_uniq_app(&p, MSEP_REC));\r
                 }\r
+                if (p) free(p);\r
                 checked_prefix = 1;\r
-                //strcat(presult, "+");\r
             }\r
         // else check forbiddenwords\r
         } else if (rv->astr && (TESTAFF(rv->astr, forbiddenword, rv->alen) ||\r
-            TESTAFF(rv->astr, pseudoroot, rv->alen))) {\r
+            TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) ||\r
+            TESTAFF(rv->astr, needaffix, rv->alen))) {\r
                 st[i] = ch;\r
                 continue;\r
         }\r
 \r
             // check non_compound flag in suffix and prefix\r
             if ((rv) && !hu_mov_rule &&\r
-                ((pfx && ((PfxEntry*)pfx)->getCont() &&\r
-                    TESTAFF(((PfxEntry*)pfx)->getCont(), compoundforbidflag, \r
-                        ((PfxEntry*)pfx)->getContLen())) ||\r
-                (sfx && ((SfxEntry*)sfx)->getCont() &&\r
-                    TESTAFF(((SfxEntry*)sfx)->getCont(), compoundforbidflag, \r
-                        ((SfxEntry*)sfx)->getContLen())))) {\r
+                ((pfx && pfx->getCont() &&\r
+                    TESTAFF(pfx->getCont(), compoundforbidflag, \r
+                        pfx->getContLen())) ||\r
+                (sfx && sfx->getCont() &&\r
+                    TESTAFF(sfx->getCont(), compoundforbidflag, \r
+                        sfx->getContLen())))) {\r
                     continue;\r
             }\r
 \r
             // check compoundend flag in suffix and prefix\r
             if ((rv) && !checked_prefix && compoundend && !hu_mov_rule &&\r
-                ((pfx && ((PfxEntry*)pfx)->getCont() &&\r
-                    TESTAFF(((PfxEntry*)pfx)->getCont(), compoundend, \r
-                        ((PfxEntry*)pfx)->getContLen())) ||\r
-                (sfx && ((SfxEntry*)sfx)->getCont() &&\r
-                    TESTAFF(((SfxEntry*)sfx)->getCont(), compoundend, \r
-                        ((SfxEntry*)sfx)->getContLen())))) {\r
+                ((pfx && pfx->getCont() &&\r
+                    TESTAFF(pfx->getCont(), compoundend, \r
+                        pfx->getContLen())) ||\r
+                (sfx && sfx->getCont() &&\r
+                    TESTAFF(sfx->getCont(), compoundend, \r
+                        sfx->getContLen())))) {\r
                     continue;\r
             }\r
 \r
             // check compoundmiddle flag in suffix and prefix\r
             if ((rv) && !checked_prefix && (wordnum==0) && compoundmiddle && !hu_mov_rule &&\r
-                ((pfx && ((PfxEntry*)pfx)->getCont() &&\r
-                    TESTAFF(((PfxEntry*)pfx)->getCont(), compoundmiddle, \r
-                        ((PfxEntry*)pfx)->getContLen())) ||\r
-                (sfx && ((SfxEntry*)sfx)->getCont() &&\r
-                    TESTAFF(((SfxEntry*)sfx)->getCont(), compoundmiddle, \r
-                        ((SfxEntry*)sfx)->getContLen())))) {\r
+                ((pfx && pfx->getCont() &&\r
+                    TESTAFF(pfx->getCont(), compoundmiddle, \r
+                        pfx->getContLen())) ||\r
+                (sfx && sfx->getCont() &&\r
+                    TESTAFF(sfx->getCont(), compoundmiddle, \r
+                        sfx->getContLen())))) {\r
                     rv = NULL;\r
             }       \r
 \r
         // check forbiddenwords\r
-        if ((rv) && (rv->astr) && TESTAFF(rv->astr, forbiddenword, rv->alen)) continue;\r
+        if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen)\r
+            || TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen))) continue;\r
 \r
         // increment word number, if the second root has a compoundroot flag\r
         if ((rv) && (compoundroot) && \r
@@ -2089,7 +2223,7 @@ int AffixMgr::compound_check_morph(const char * word, int len,
               )\r
 // END of LANG_hu section\r
           )\r
-          && ! (( checkcompoundtriple && // test triple letters\r
+          && ! (( checkcompoundtriple && !words && // test triple letters\r
                    (word[i-1]==word[i]) && (\r
                       ((i>1) && (word[i-1]==word[i-2])) || \r
                       ((word[i-1]==word[i+1])) // may be word[i+1] == '\0'\r
@@ -2097,17 +2231,17 @@ int AffixMgr::compound_check_morph(const char * word, int len,
                ) ||\r
                (\r
                    // test CHECKCOMPOUNDPATTERN\r
-                   numcheckcpd && cpdpat_check(word, i)\r
+                   numcheckcpd && !words && cpdpat_check(word, i, rv, NULL, affixed)\r
                ) ||\r
                ( \r
-                 checkcompoundcase && cpdcase_check(word, i)\r
+                 checkcompoundcase && !words && cpdcase_check(word, i)\r
                ))\r
          )\r
 // LANG_hu section: spec. Hungarian rule\r
          || ((!rv) && (langnum == LANG_hu) && hu_mov_rule && (rv = affix_check(st,i)) &&\r
-              (sfx && ((SfxEntry*)sfx)->getCont() && (\r
-                        TESTAFF(((SfxEntry*)sfx)->getCont(), (unsigned short) 'x', ((SfxEntry*)sfx)->getContLen()) ||\r
-                        TESTAFF(((SfxEntry*)sfx)->getCont(), (unsigned short) '%', ((SfxEntry*)sfx)->getContLen())\r
+              (sfx && sfx->getCont() && (\r
+                        TESTAFF(sfx->getCont(), (unsigned short) 'x', sfx->getContLen()) ||\r
+                        TESTAFF(sfx->getCont(), (unsigned short) '%', sfx->getContLen())\r
                     )                \r
                )\r
              )\r
@@ -2120,7 +2254,7 @@ int AffixMgr::compound_check_morph(const char * word, int len,
                 numsyllable += get_syllable(st, i);\r
 \r
                 // + 1 word, if syllable number of the prefix > 1 (hungarian convention)\r
-                if (pfx && (get_syllable(((PfxEntry *)pfx)->getKey(),strlen(((PfxEntry *)pfx)->getKey())) > 1)) wordnum++;\r
+                if (pfx && (get_syllable(pfx->getKey(),strlen(pfx->getKey())) > 1)) wordnum++;\r
             }\r
 // END of LANG_hu section\r
 \r
@@ -2129,21 +2263,31 @@ int AffixMgr::compound_check_morph(const char * word, int len,
             rv = lookup((word+i)); // perhaps without prefix\r
 \r
         // search homonym with compound flag\r
-        while ((rv) && ((pseudoroot && TESTAFF(rv->astr, pseudoroot, rv->alen)) ||\r
+        while ((rv) && ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||\r
                         !((compoundflag && !words && TESTAFF(rv->astr, compoundflag, rv->alen)) ||\r
                           (compoundend && !words && TESTAFF(rv->astr, compoundend, rv->alen)) ||\r
-                           (numdefcpd && defcpd_check(&words, wnum + 1, rv, NULL,1))))) {\r
+                           (numdefcpd && words && defcpd_check(&words, wnum + 1, rv, NULL,1))))) {\r
             rv = rv->next_homonym;\r
         }\r
 \r
             if (rv && words && words[wnum + 1]) {\r
-                  strcat(*result, presult);\r
-                  if (complexprefixes && rv->description) strcat(*result, rv->description);\r
-                  if (rv->description && ((!rv->astr) || \r
-                     !TESTAFF(rv->astr, lemma_present, rv->alen)))\r
-                        strcat(*result, rv->word);\r
-                  if (!complexprefixes && rv->description) strcat(*result, rv->description);\r
-                  strcat(*result, "\n");\r
+                  mystrcat(*result, presult, MAXLNLEN);\r
+                  mystrcat(*result, " ", MAXLNLEN);\r
+                  mystrcat(*result, MORPH_PART, MAXLNLEN);\r
+                  mystrcat(*result, word+i, MAXLNLEN);\r
+                  if (complexprefixes && HENTRY_DATA(rv)) mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);\r
+                  if (!HENTRY_FIND(rv, MORPH_STEM)) {\r
+                    mystrcat(*result, " ", MAXLNLEN);\r
+                    mystrcat(*result, MORPH_STEM, MAXLNLEN);\r
+                    mystrcat(*result, HENTRY_WORD(rv), MAXLNLEN);\r
+                  }\r
+                  // store the pointer of the hash entry\r
+//                  sprintf(*result + strlen(*result), " %s%p", MORPH_HENTRY, rv);\r
+                  if (!complexprefixes && HENTRY_DATA(rv)) {\r
+                    mystrcat(*result, " ", MAXLNLEN);\r
+                    mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);\r
+                  }\r
+                  mystrcat(*result, "\n", MAXLNLEN);\r
                   ok = 1;\r
                   return 0;\r
             }\r
@@ -2163,11 +2307,12 @@ int AffixMgr::compound_check_morph(const char * word, int len,
             }\r
 \r
             // check forbiddenwords\r
-            if ((rv) && (rv->astr) && TESTAFF(rv->astr, forbiddenword, rv->alen)) {\r
+            if ((rv) && (rv->astr) && (TESTAFF(rv->astr, forbiddenword, rv->alen) ||\r
+                TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen))) {\r
                 st[i] = ch;\r
                 continue;\r
             }\r
-                    \r
+\r
             // second word is acceptable, as a root?\r
             // hungarian conventions: compounding is acceptable,\r
             // when compound forms consist of 2 words, or if more,\r
@@ -2178,8 +2323,8 @@ int AffixMgr::compound_check_morph(const char * word, int len,
                     )\r
                 && (\r
                       ((cpdwordmax==-1) || (wordnum+1<cpdwordmax)) || \r
-                      ((cpdmaxsyllable==0) || \r
-                          (numsyllable+get_syllable(rv->word,rv->wlen)<=cpdmaxsyllable))\r
+                      ((cpdmaxsyllable!=0) &&\r
+                          (numsyllable+get_syllable(HENTRY_WORD(rv),rv->blen)<=cpdmaxsyllable))\r
                     )\r
                 && (\r
                      (!checkcompounddup || (rv != rv_first))\r
@@ -2187,15 +2332,26 @@ int AffixMgr::compound_check_morph(const char * word, int len,
                 )\r
                  {\r
                       // bad compound word\r
-                      strcat(*result, presult);\r
-                                          \r
-                      if (rv->description) {\r
-                        if (complexprefixes) strcat(*result, rv->description);\r
-                        if ((!rv->astr) || !TESTAFF(rv->astr, lemma_present, rv->alen))\r
-                                               strcat(*result, rv->word);\r
-                        if (!complexprefixes) strcat(*result, rv->description);\r
+                      mystrcat(*result, presult, MAXLNLEN);\r
+                      mystrcat(*result, " ", MAXLNLEN);\r
+                      mystrcat(*result, MORPH_PART, MAXLNLEN);\r
+                      mystrcat(*result, word+i, MAXLNLEN);\r
+\r
+                      if (HENTRY_DATA(rv)) {\r
+                        if (complexprefixes) mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);\r
+                        if (! HENTRY_FIND(rv, MORPH_STEM)) {\r
+                           mystrcat(*result, " ", MAXLNLEN);\r
+                           mystrcat(*result, MORPH_STEM, MAXLNLEN);\r
+                           mystrcat(*result, HENTRY_WORD(rv), MAXLNLEN);\r
+                        }\r
+                        // store the pointer of the hash entry\r
+//                        sprintf(*result + strlen(*result), " %s%p", MORPH_HENTRY, rv);\r
+                        if (!complexprefixes) {\r
+                            mystrcat(*result, " ", MAXLNLEN);\r
+                            mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);\r
+                        }\r
                       }\r
-                      strcat(*result, "\n");\r
+                      mystrcat(*result, "\n", MAXLNLEN);\r
                               ok = 1;\r
             }\r
 \r
@@ -2206,9 +2362,9 @@ int AffixMgr::compound_check_morph(const char * word, int len,
             sfx = NULL;\r
             sfxflag = FLAG_NULL;\r
 \r
-            if (compoundflag) rv = affix_check((word+i),strlen(word+i), compoundflag); else rv = NULL;\r
+            if (compoundflag && !onlycpdrule) rv = affix_check((word+i),strlen(word+i), compoundflag); else rv = NULL;\r
 \r
-            if (!rv && compoundend) {\r
+            if (!rv && compoundend && !onlycpdrule) {\r
                 sfx = NULL;\r
                 pfx = NULL;\r
                 rv = affix_check((word+i),strlen(word+i), compoundend);\r
@@ -2219,39 +2375,36 @@ int AffixMgr::compound_check_morph(const char * word, int len,
                 if (rv && words && defcpd_check(&words, wnum + 1, rv, NULL, 1)) {\r
                       char * m = NULL;\r
                       if (compoundflag) m = affix_check_morph((word+i),strlen(word+i), compoundflag);\r
-                      if ((!m || *m == '\0') && compoundend)\r
+                      if ((!m || *m == '\0') && compoundend) {\r
+                            if (m) free(m);\r
                             m = affix_check_morph((word+i),strlen(word+i), compoundend);\r
-                      strcat(*result, presult);\r
-                      if (m) {\r
-                        line_uniq(m);\r
-                        if (strchr(m, '\n')) {\r
-                            strcat(*result, "(");\r
-                            strcat(*result, line_join(m, '|'));\r
-                            strcat(*result, ")");\r
-                        } else {\r
-                            strcat(*result, m);\r
-                        }\r
-                        free(m);\r
                       }\r
-                      strcat(*result, "\n");\r
+                      mystrcat(*result, presult, MAXLNLEN);\r
+                      if (m || (*m != '\0')) {\r
+                        sprintf(*result + strlen(*result), "%c%s%s%s", MSEP_FLD,\r
+                            MORPH_PART, word + i, line_uniq_app(&m, MSEP_REC));\r
+                      }\r
+                      if (m) free(m);\r
+                      mystrcat(*result, "\n", MAXLNLEN);\r
                       ok = 1;\r
                 }\r
             }\r
 \r
             // check non_compound flag in suffix and prefix\r
             if ((rv) && \r
-                ((pfx && ((PfxEntry*)pfx)->getCont() &&\r
-                    TESTAFF(((PfxEntry*)pfx)->getCont(), compoundforbidflag, \r
-                        ((PfxEntry*)pfx)->getContLen())) ||\r
-                (sfx && ((SfxEntry*)sfx)->getCont() &&\r
-                    TESTAFF(((SfxEntry*)sfx)->getCont(), compoundforbidflag, \r
-                        ((SfxEntry*)sfx)->getContLen())))) {\r
+                ((pfx && pfx->getCont() &&\r
+                    TESTAFF(pfx->getCont(), compoundforbidflag, \r
+                        pfx->getContLen())) ||\r
+                (sfx && sfx->getCont() &&\r
+                    TESTAFF(sfx->getCont(), compoundforbidflag, \r
+                        sfx->getContLen())))) {\r
                     rv = NULL;\r
             }\r
 \r
             // check forbiddenwords\r
-            if ((rv) && (rv->astr) && (TESTAFF(rv->astr,forbiddenword,rv->alen))\r
-                    && (! TESTAFF(rv->astr, pseudoroot, rv->alen))) {\r
+            if ((rv) && (rv->astr) && (TESTAFF(rv->astr,forbiddenword,rv->alen) ||\r
+                    TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen))\r
+                    && (! TESTAFF(rv->astr, needaffix, rv->alen))) {\r
                         st[i] = ch;\r
                         continue;\r
                     }\r
@@ -2269,7 +2422,7 @@ int AffixMgr::compound_check_morph(const char * word, int len,
                 }\r
 \r
                 // + 1 word, if syllable number of the prefix > 1 (hungarian convention)\r
-                if (pfx && (get_syllable(((PfxEntry *)pfx)->getKey(),strlen(((PfxEntry *)pfx)->getKey())) > 1)) wordnum++;\r
+                if (pfx && (get_syllable(pfx->getKey(),strlen(pfx->getKey())) > 1)) wordnum++;\r
 \r
                 // increment syllable num, if last word has a SYLLABLENUM flag\r
                 // and the suffix is beginning `s'\r
@@ -2295,7 +2448,7 @@ int AffixMgr::compound_check_morph(const char * word, int len,
             if ((rv) && \r
                     (\r
                       ((cpdwordmax==-1) || (wordnum+1<cpdwordmax)) || \r
-                      ((cpdmaxsyllable==0) || \r
+                      ((cpdmaxsyllable!=0) &&\r
                           (numsyllable <= cpdmaxsyllable))\r
                     )\r
                 && (\r
@@ -2303,21 +2456,17 @@ int AffixMgr::compound_check_morph(const char * word, int len,
                    )) {\r
                       char * m = NULL;\r
                       if (compoundflag) m = affix_check_morph((word+i),strlen(word+i), compoundflag);\r
-                      if ((!m || *m == '\0') && compoundend)\r
+                      if ((!m || *m == '\0') && compoundend) {\r
+                            if (m) free(m);\r
                             m = affix_check_morph((word+i),strlen(word+i), compoundend);\r
-                      strcat(*result, presult);\r
-                      if (m) {\r
-                        line_uniq(m);\r
-                        if (strchr(m, '\n')) {\r
-                            strcat(*result, "(");\r
-                            strcat(*result, line_join(m, '|'));\r
-                            strcat(*result, ")");\r
-                        } else {\r
-                            strcat(*result, m);\r
-                        }\r
-                        free(m);\r
                       }\r
-                      strcat(*result, "\n");\r
+                      mystrcat(*result, presult, MAXLNLEN);\r
+                      if (m && (*m != '\0')) {\r
+                        sprintf(*result + strlen(*result), "%c%s%s%s", MSEP_FLD,\r
+                            MORPH_PART, word + i, line_uniq_app(&m, MSEP_REC));\r
+                      }\r
+                      if (m) free(m);\r
+                      sprintf(*result + strlen(*result), "%c", MSEP_REC);\r
                       ok = 1;\r
             }\r
 \r
@@ -2335,10 +2484,12 @@ int AffixMgr::compound_check_morph(const char * word, int len,
         st[i] = ch;\r
         wordnum = oldwordnum;\r
         numsyllable = oldnumsyllable;\r
+\r
+        } while (numdefcpd && oldwordnum == 0 && !onlycpdrule && (onlycpdrule = 1)); // end of onlycpd loop\r
+\r
     }\r
     return 0;\r
 }    \r
-#endif // END OF HUNSPELL_EXPERIMENTAL CODE\r
 \r
  // return 1 if s1 (reversed) is a leading subset of end of s2\r
 /* inline int AffixMgr::isRevSubset(const char * s1, const char * end_of_s2, int len)\r
@@ -2365,16 +2516,14 @@ inline int AffixMgr::isRevSubset(const char * s1, const char * end_of_s2, int le
 // check word for suffixes\r
 \r
 struct hentry * AffixMgr::suffix_check (const char * word, int len, \r
-       int sfxopts, AffEntry * ppfx, char ** wlst, int maxSug, int * ns, \r
+       int sfxopts, PfxEntry * ppfx, char ** wlst, int maxSug, int * ns, \r
        const FLAG cclass, const FLAG needflag, char in_compound)\r
 {\r
     struct hentry * rv = NULL;\r
-    char result[MAXLNLEN];\r
-\r
-    PfxEntry* ep = (PfxEntry *) ppfx;\r
+    PfxEntry* ep = ppfx;\r
 \r
     // first handle the special case of 0 length suffixes\r
-    SfxEntry * se = (SfxEntry *) sStart[0];\r
+    SfxEntry * se = sStart[0];\r
 \r
     while (se) {\r
         if (!cclass || se->getCont()) {\r
@@ -2393,29 +2542,29 @@ struct hentry * AffixMgr::suffix_check (const char * word, int len,
                (se->getCont() && (TESTAFF(se->getCont(),circumfix,se->getContLen())))))  &&\r
             // fogemorpheme\r
               (in_compound || \r
-                 !((se->getCont() && (TESTAFF(se->getCont(), onlyincompound, se->getContLen()))))) &&\r
-            // pseudoroot on prefix or first suffix\r
+                 !(se->getCont() && (TESTAFF(se->getCont(), onlyincompound, se->getContLen())))) &&\r
+            // needaffix on prefix or first suffix\r
               (cclass || \r
-                   !(se->getCont() && TESTAFF(se->getCont(), pseudoroot, se->getContLen())) ||\r
+                   !(se->getCont() && TESTAFF(se->getCont(), needaffix, se->getContLen())) ||\r
                    (ppfx && !((ep->getCont()) &&\r
-                     TESTAFF(ep->getCont(), pseudoroot,\r
+                     TESTAFF(ep->getCont(), needaffix,\r
                        ep->getContLen())))\r
-              )\r
-            ) {\r
+              )) {\r
                 rv = se->checkword(word,len, sfxopts, ppfx, wlst, maxSug, ns, (FLAG) cclass, \r
                     needflag, (in_compound ? 0 : onlyincompound));\r
                 if (rv) {\r
-                    sfx=(AffEntry *)se; // BUG: sfx not stateless\r
+                    sfx=se; // BUG: sfx not stateless\r
                     return rv;\r
                 }\r
             }\r
         }\r
        se = se->getNext();\r
     }\r
-  \r
+\r
     // now handle the general case\r
-    unsigned char sp = *((const unsigned char *)(word + len - 1));\r
-    SfxEntry * sptr = (SfxEntry *) sStart[sp];\r
+    if (len == 0) return NULL; // FULLSTRIP\r
+    unsigned char sp= *((const unsigned char *)(word + len - 1));\r
+    SfxEntry * sptr = sStart[sp];\r
 \r
     while (sptr) {\r
         if (isRevSubset(sptr->getKey(), word + len - 1, len)\r
@@ -2436,31 +2585,20 @@ struct hentry * AffixMgr::suffix_check (const char * word, int len,
             // fogemorpheme\r
               (in_compound || \r
                  !((sptr->getCont() && (TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))))) &&\r
-            // pseudoroot on prefix or first suffix\r
+            // needaffix on prefix or first suffix\r
               (cclass || \r
-                  !(sptr->getCont() && TESTAFF(sptr->getCont(), pseudoroot, sptr->getContLen())) ||\r
+                  !(sptr->getCont() && TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) ||\r
                   (ppfx && !((ep->getCont()) &&\r
-                     TESTAFF(ep->getCont(), pseudoroot,\r
+                     TESTAFF(ep->getCont(), needaffix,\r
                        ep->getContLen())))\r
               )\r
-            ) {\r
+            ) if (in_compound != IN_CPD_END || ppfx || !(sptr->getCont() && TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))) {\r
                 rv = sptr->checkword(word,len, sfxopts, ppfx, wlst,\r
                     maxSug, ns, cclass, needflag, (in_compound ? 0 : onlyincompound));\r
                 if (rv) {\r
-                    sfx=(AffEntry *)sptr; // BUG: sfx not stateless\r
+                    sfx=sptr; // BUG: sfx not stateless\r
                     sfxflag = sptr->getFlag(); // BUG: sfxflag not stateless\r
                     if (!sptr->getCont()) sfxappnd=sptr->getKey(); // BUG: sfxappnd not stateless\r
-                    if (cclass || sptr->getCont()) {\r
-                                if (!derived) {\r
-                                        derived = mystrdup(word);\r
-                                } else {\r
-                                        strcpy(result, derived); // XXX check size\r
-                                        strcat(result, "\n");\r
-                                        strcat(result, word);\r
-                                        free(derived);\r
-                                        derived = mystrdup(result);\r
-                                }\r
-                    }\r
                     return rv;\r
                 }\r
              }\r
@@ -2476,12 +2614,12 @@ struct hentry * AffixMgr::suffix_check (const char * word, int len,
 // check word for two-level suffixes\r
 \r
 struct hentry * AffixMgr::suffix_check_twosfx(const char * word, int len, \r
-       int sfxopts, AffEntry * ppfx, const FLAG needflag)\r
+       int sfxopts, PfxEntry * ppfx, const FLAG needflag)\r
 {\r
     struct hentry * rv = NULL;\r
 \r
     // first handle the special case of 0 length suffixes\r
-    SfxEntry * se = (SfxEntry *) sStart[0];\r
+    SfxEntry * se = sStart[0];\r
     while (se) {\r
         if (contclasses[se->getFlag()])\r
         {\r
@@ -2490,10 +2628,11 @@ struct hentry * AffixMgr::suffix_check_twosfx(const char * word, int len,
         }\r
         se = se->getNext();\r
     }\r
-  \r
+\r
     // now handle the general case\r
+    if (len == 0) return NULL; // FULLSTRIP\r
     unsigned char sp = *((const unsigned char *)(word + len - 1));\r
-    SfxEntry * sptr = (SfxEntry *) sStart[sp];\r
+    SfxEntry * sptr = sStart[sp];\r
 \r
     while (sptr) {\r
         if (isRevSubset(sptr->getKey(), word + len - 1, len)) {\r
@@ -2515,9 +2654,8 @@ struct hentry * AffixMgr::suffix_check_twosfx(const char * word, int len,
     return NULL;\r
 }\r
 \r
-#ifdef HUNSPELL_EXPERIMENTAL\r
 char * AffixMgr::suffix_check_twosfx_morph(const char * word, int len, \r
-       int sfxopts, AffEntry * ppfx, const FLAG needflag)\r
+       int sfxopts, PfxEntry * ppfx, const FLAG needflag)\r
 {\r
     char result[MAXLNLEN];\r
     char result2[MAXLNLEN];\r
@@ -2530,27 +2668,34 @@ char * AffixMgr::suffix_check_twosfx_morph(const char * word, int len,
     result3[0] = '\0';\r
 \r
     // first handle the special case of 0 length suffixes\r
-    SfxEntry * se = (SfxEntry *) sStart[0];\r
+    SfxEntry * se = sStart[0];\r
     while (se) {\r
         if (contclasses[se->getFlag()])\r
         {\r
             st = se->check_twosfx_morph(word,len, sfxopts, ppfx, needflag);\r
             if (st) {\r
                 if (ppfx) {\r
-                    if (((PfxEntry *) ppfx)->getMorph()) strcat(result, ((PfxEntry *) ppfx)->getMorph());\r
+                    if (ppfx->getMorph()) {\r
+                        mystrcat(result, ppfx->getMorph(), MAXLNLEN);\r
+                        mystrcat(result, " ", MAXLNLEN);\r
+                    } else debugflag(result, ppfx->getFlag());\r
                 }\r
-                strcat(result, st);\r
+                mystrcat(result, st, MAXLNLEN);\r
                 free(st);\r
-                if (se->getMorph()) strcat(result, se->getMorph());\r
-                strcat(result, "\n");\r
+                if (se->getMorph()) {\r
+                    mystrcat(result, " ", MAXLNLEN);\r
+                    mystrcat(result, se->getMorph(), MAXLNLEN);\r
+                } else debugflag(result, se->getFlag());\r
+                mystrcat(result, "\n", MAXLNLEN);\r
             }\r
         }\r
         se = se->getNext();\r
     }\r
-  \r
+\r
     // now handle the general case\r
+    if (len == 0) return NULL; // FULLSTRIP\r
     unsigned char sp = *((const unsigned char *)(word + len - 1));\r
-    SfxEntry * sptr = (SfxEntry *) sStart[sp];\r
+    SfxEntry * sptr = sStart[sp];\r
 \r
     while (sptr) {\r
         if (isRevSubset(sptr->getKey(), word + len - 1, len)) {\r
@@ -2564,19 +2709,14 @@ char * AffixMgr::suffix_check_twosfx_morph(const char * word, int len,
                     free(st);\r
 \r
                 result3[0] = '\0';\r
-#ifdef DEBUG\r
-                unsigned short flag = sptr->getFlag();\r
-                if (flag_mode == FLAG_NUM) {\r
-                    sprintf(result3, "<%d>", sptr->getKey());\r
-                } else if (flag_mode == FLAG_LONG) {\r
-                    sprintf(result3, "<%c%c>", flag >> 8, (flag << 8) >>8);\r
-                } else sprintf(result3, "<%c>", flag);\r
-                strcat(result3, ":");\r
-#endif\r
-                if (sptr->getMorph()) strcat(result3, sptr->getMorph());\r
+\r
+                if (sptr->getMorph()) {\r
+                    mystrcat(result3, " ", MAXLNLEN);\r
+                    mystrcat(result3, sptr->getMorph(), MAXLNLEN);\r
+                } else debugflag(result3, sptr->getFlag());\r
                 strlinecat(result2, result3);\r
-                strcat(result2, "\n");\r
-                strcat(result,  result2);\r
+                mystrcat(result2, "\n", MAXLNLEN);\r
+                mystrcat(result,  result2, MAXLNLEN);\r
                 }\r
             }\r
             sptr = sptr->getNextEQ();\r
@@ -2584,12 +2724,12 @@ char * AffixMgr::suffix_check_twosfx_morph(const char * word, int len,
              sptr = sptr->getNextNE();\r
         }\r
     }\r
-    if (result) return mystrdup(result);\r
+    if (*result) return mystrdup(result);\r
     return NULL;\r
 }\r
 \r
 char * AffixMgr::suffix_check_morph(const char * word, int len, \r
-       int sfxopts, AffEntry * ppfx, const FLAG cclass, const FLAG needflag, char in_compound)\r
+       int sfxopts, PfxEntry * ppfx, const FLAG cclass, const FLAG needflag, char in_compound)\r
 {\r
     char result[MAXLNLEN];\r
     \r
@@ -2597,10 +2737,10 @@ char * AffixMgr::suffix_check_morph(const char * word, int len,
 \r
     result[0] = '\0';\r
 \r
-    PfxEntry* ep = (PfxEntry *) ppfx;\r
+    PfxEntry* ep = ppfx;\r
 \r
     // first handle the special case of 0 length suffixes\r
-    SfxEntry * se = (SfxEntry *) sStart[0];\r
+    SfxEntry * se = sStart[0];\r
     while (se) {\r
         if (!cclass || se->getCont()) {\r
             // suffixes are not allowed in beginning of compounds\r
@@ -2619,35 +2759,50 @@ char * AffixMgr::suffix_check_morph(const char * word, int len,
             // fogemorpheme\r
               (in_compound || \r
                  !((se->getCont() && (TESTAFF(se->getCont(), onlyincompound, se->getContLen()))))) &&\r
-            // pseudoroot on prefix or first suffix\r
+            // needaffix on prefix or first suffix\r
               (cclass || \r
-                   !(se->getCont() && TESTAFF(se->getCont(), pseudoroot, se->getContLen())) ||\r
+                   !(se->getCont() && TESTAFF(se->getCont(), needaffix, se->getContLen())) ||\r
                    (ppfx && !((ep->getCont()) &&\r
-                     TESTAFF(ep->getCont(), pseudoroot,\r
+                     TESTAFF(ep->getCont(), needaffix,\r
                        ep->getContLen())))\r
               )\r
             ))\r
-            rv = se->checkword(word,len, sfxopts, ppfx, NULL, 0, 0, cclass, needflag);\r
+            rv = se->checkword(word, len, sfxopts, ppfx, NULL, 0, 0, cclass, needflag);\r
          while (rv) {\r
            if (ppfx) {\r
-                if (((PfxEntry *) ppfx)->getMorph()) strcat(result, ((PfxEntry *) ppfx)->getMorph());\r
+                if (ppfx->getMorph()) {\r
+                    mystrcat(result, ppfx->getMorph(), MAXLNLEN);\r
+                    mystrcat(result, " ", MAXLNLEN);\r
+                } else debugflag(result, ppfx->getFlag());\r
+            }\r
+            if (complexprefixes && HENTRY_DATA(rv)) mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);\r
+            if (! HENTRY_FIND(rv, MORPH_STEM)) {\r
+                mystrcat(result, " ", MAXLNLEN);                                \r
+                mystrcat(result, MORPH_STEM, MAXLNLEN);\r
+                mystrcat(result, HENTRY_WORD(rv), MAXLNLEN);\r
             }\r
-            if (complexprefixes && rv->description) strcat(result, rv->description);\r
-            if (rv->description && ((!rv->astr) || \r
-                                        !TESTAFF(rv->astr, lemma_present, rv->alen)))\r
-                                               strcat(result, rv->word);\r
-            if (!complexprefixes && rv->description) strcat(result, rv->description);\r
-            if (se->getMorph()) strcat(result, se->getMorph());\r
-            strcat(result, "\n");\r
+            // store the pointer of the hash entry\r
+//            sprintf(result + strlen(result), " %s%p", MORPH_HENTRY, rv);\r
+            \r
+            if (!complexprefixes && HENTRY_DATA(rv)) {\r
+                    mystrcat(result, " ", MAXLNLEN);                                \r
+                    mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);\r
+            }\r
+            if (se->getMorph()) {\r
+                mystrcat(result, " ", MAXLNLEN);                                \r
+                mystrcat(result, se->getMorph(), MAXLNLEN);\r
+            } else debugflag(result, se->getFlag());\r
+            mystrcat(result, "\n", MAXLNLEN);\r
             rv = se->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag);\r
          }\r
        }\r
        se = se->getNext();\r
     }\r
-  \r
+\r
     // now handle the general case\r
+    if (len == 0) return NULL; // FULLSTRIP\r
     unsigned char sp = *((const unsigned char *)(word + len - 1));\r
-    SfxEntry * sptr = (SfxEntry *) sStart[sp];\r
+    SfxEntry * sptr = sStart[sp];\r
 \r
     while (sptr) {\r
         if (isRevSubset(sptr->getKey(), word + len - 1, len)\r
@@ -2668,30 +2823,36 @@ char * AffixMgr::suffix_check_morph(const char * word, int len,
             // fogemorpheme\r
               (in_compound || \r
                  !((sptr->getCont() && (TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))))) &&\r
-            // pseudoroot on first suffix\r
+            // needaffix on first suffix\r
               (cclass || !(sptr->getCont() && \r
-                   TESTAFF(sptr->getCont(), pseudoroot, sptr->getContLen())))\r
+                   TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())))\r
             )) rv = sptr->checkword(word,len, sfxopts, ppfx, NULL, 0, 0, cclass, needflag);\r
             while (rv) {\r
                     if (ppfx) {\r
-                        if (((PfxEntry *) ppfx)->getMorph()) strcat(result, ((PfxEntry *) ppfx)->getMorph());\r
+                        if (ppfx->getMorph()) {\r
+                            mystrcat(result, ppfx->getMorph(), MAXLNLEN);\r
+                            mystrcat(result, " ", MAXLNLEN);\r
+                        } else debugflag(result, ppfx->getFlag());\r
                     }    \r
-                    if (complexprefixes && rv->description) strcat(result, rv->description);\r
-                    if (rv->description && ((!rv->astr) || \r
-                        !TESTAFF(rv->astr, lemma_present, rv->alen))) strcat(result, rv->word);\r
-                    if (!complexprefixes && rv->description) strcat(result, rv->description);\r
-#ifdef DEBUG\r
-                unsigned short flag = sptr->getFlag();\r
-                if (flag_mode == FLAG_NUM) {\r
-                    sprintf(result, "<%d>", sptr->getKey());\r
-                } else if (flag_mode == FLAG_LONG) {\r
-                    sprintf(result, "<%c%c>", flag >> 8, (flag << 8) >>8);\r
-                } else sprintf(result, "<%c>", flag);\r
-                strcat(result, ":");\r
-#endif\r
+                    if (complexprefixes && HENTRY_DATA(rv)) mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);\r
+                    if (! HENTRY_FIND(rv, MORPH_STEM)) {\r
+                            mystrcat(result, " ", MAXLNLEN);                                \r
+                            mystrcat(result, MORPH_STEM, MAXLNLEN);\r
+                            mystrcat(result, HENTRY_WORD(rv), MAXLNLEN);\r
+                    }\r
+                    // store the pointer of the hash entry\r
+//                    sprintf(result + strlen(result), " %s%p", MORPH_HENTRY, rv);\r
+\r
+                    if (!complexprefixes && HENTRY_DATA(rv)) {\r
+                        mystrcat(result, " ", MAXLNLEN);                                \r
+                        mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);\r
+                    }\r
 \r
-                if (sptr->getMorph()) strcat(result, sptr->getMorph());\r
-                strcat(result, "\n");\r
+                if (sptr->getMorph()) {\r
+                    mystrcat(result, " ", MAXLNLEN);\r
+                    mystrcat(result, sptr->getMorph(), MAXLNLEN);\r
+                } else debugflag(result, sptr->getFlag());\r
+                mystrcat(result, "\n", MAXLNLEN);\r
                 rv = sptr->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag);\r
             }\r
              sptr = sptr->getNextEQ();\r
@@ -2703,15 +2864,11 @@ char * AffixMgr::suffix_check_morph(const char * word, int len,
     if (*result) return mystrdup(result);\r
     return NULL;\r
 }\r
-#endif // END OF HUNSPELL_EXPERIMENTAL CODE\r
-\r
 \r
 // check if word with affixes is correctly spelled\r
 struct hentry * AffixMgr::affix_check (const char * word, int len, const FLAG needflag, char in_compound)\r
 {\r
     struct hentry * rv= NULL;\r
-    if (derived) free(derived);\r
-    derived =  NULL;\r
 \r
     // check all prefixes (also crossed with suffixes if allowed) \r
     rv = prefix_check(word, len, in_compound, needflag);\r
@@ -2723,17 +2880,19 @@ struct hentry * AffixMgr::affix_check (const char * word, int len, const FLAG ne
     if (havecontclass) {\r
         sfx = NULL;\r
         pfx = NULL;\r
+\r
         if (rv) return rv;\r
         // if still not found check all two-level suffixes\r
         rv = suffix_check_twosfx(word, len, 0, NULL, needflag);\r
+\r
         if (rv) return rv;\r
         // if still not found check all two-level suffixes\r
         rv = prefix_check_twosfx(word, len, IN_CPD_NOT, needflag);\r
     }\r
+\r
     return rv;\r
 }\r
 \r
-#ifdef HUNSPELL_EXPERIMENTAL\r
 // check if word with affixes is correctly spelled\r
 char * AffixMgr::affix_check_morph(const char * word, int len, const FLAG needflag, char in_compound)\r
 {\r
@@ -2745,14 +2904,14 @@ char * AffixMgr::affix_check_morph(const char * word, int len, const FLAG needfl
     // check all prefixes (also crossed with suffixes if allowed) \r
     st = prefix_check_morph(word, len, in_compound);\r
     if (st) {\r
-        strcat(result, st);\r
+        mystrcat(result, st, MAXLNLEN);\r
         free(st);\r
     }\r
 \r
     // if still not found check all suffixes    \r
     st = suffix_check_morph(word, len, 0, NULL, '\0', needflag, in_compound);\r
     if (st) {\r
-        strcat(result, st);\r
+        mystrcat(result, st, MAXLNLEN);\r
         free(st);\r
     }\r
 \r
@@ -2762,47 +2921,134 @@ char * AffixMgr::affix_check_morph(const char * word, int len, const FLAG needfl
         // if still not found check all two-level suffixes\r
         st = suffix_check_twosfx_morph(word, len, 0, NULL, needflag);\r
         if (st) {\r
-            strcat(result, st);\r
+            mystrcat(result, st, MAXLNLEN);\r
             free(st);\r
         }\r
 \r
         // if still not found check all two-level suffixes\r
         st = prefix_check_twosfx_morph(word, len, IN_CPD_NOT, needflag);\r
         if (st) {\r
-            strcat(result, st);\r
+            mystrcat(result, st, MAXLNLEN);\r
             free(st);\r
         }\r
     }\r
-    \r
+\r
     return mystrdup(result);\r
 }\r
-#endif // END OF HUNSPELL_EXPERIMENTAL CODE\r
+\r
+char * AffixMgr::morphgen(char * ts, int wl, const unsigned short * ap,\r
+    unsigned short al, char * morph, char * targetmorph, int level)\r
+{\r
+    // handle suffixes\r
+    char * stemmorph;\r
+    char * stemmorphcatpos;\r
+    char mymorph[MAXLNLEN];\r
+\r
+    if (!morph) return NULL;\r
+\r
+    // check substandard flag\r
+    if (TESTAFF(ap, substandard, al)) return NULL;\r
+\r
+    if (morphcmp(morph, targetmorph) == 0) return mystrdup(ts);\r
+\r
+//    int targetcount = get_sfxcount(targetmorph);\r
+\r
+    // use input suffix fields, if exist\r
+    if (strstr(morph, MORPH_INFL_SFX) || strstr(morph, MORPH_DERI_SFX)) {\r
+        stemmorph = mymorph;\r
+        strcpy(stemmorph, morph);\r
+        mystrcat(stemmorph, " ", MAXLNLEN);\r
+        stemmorphcatpos = stemmorph + strlen(stemmorph);\r
+    } else {\r
+        stemmorph = morph;\r
+        stemmorphcatpos = NULL;\r
+    }\r
+\r
+    for (int i = 0; i < al; i++) {\r
+        const unsigned char c = (unsigned char) (ap[i] & 0x00FF);\r
+        SfxEntry * sptr = sFlag[c];\r
+        while (sptr) {\r
+            if (sptr->getFlag() == ap[i] && sptr->getMorph() && ((sptr->getContLen() == 0) || \r
+                // don't generate forms with substandard affixes\r
+                !TESTAFF(sptr->getCont(), substandard, sptr->getContLen()))) {\r
+\r
+                if (stemmorphcatpos) strcpy(stemmorphcatpos, sptr->getMorph());\r
+                else stemmorph = (char *) sptr->getMorph();\r
+\r
+                int cmp = morphcmp(stemmorph, targetmorph);\r
+\r
+                if (cmp == 0) {\r
+                    char * newword = sptr->add(ts, wl);\r
+                    if (newword) {\r
+                        hentry * check = pHMgr->lookup(newword); // XXX extra dic\r
+                        if (!check || !check->astr || \r
+                            !(TESTAFF(check->astr, forbiddenword, check->alen) || \r
+                              TESTAFF(check->astr, ONLYUPCASEFLAG, check->alen))) {\r
+                                return newword;\r
+                        }\r
+                        free(newword);\r
+                    }\r
+                }\r
+                \r
+                // recursive call for secondary suffixes\r
+                if ((level == 0) && (cmp == 1) && (sptr->getContLen() > 0) &&\r
+//                    (get_sfxcount(stemmorph) < targetcount) &&\r
+                    !TESTAFF(sptr->getCont(), substandard, sptr->getContLen())) {\r
+                    char * newword = sptr->add(ts, wl);\r
+                    if (newword) {\r
+                        char * newword2 = morphgen(newword, strlen(newword), sptr->getCont(),\r
+                            sptr->getContLen(), stemmorph, targetmorph, 1);\r
+\r
+                        if (newword2) {\r
+                            free(newword);\r
+                            return newword2;\r
+                        }\r
+                        free(newword);\r
+                        newword = NULL;\r
+                    }\r
+                }\r
+            }\r
+            sptr = sptr->getFlgNxt();\r
+        }\r
+    }\r
+   return NULL;\r
+}\r
 \r
 \r
 int AffixMgr::expand_rootword(struct guessword * wlst, int maxn, const char * ts,\r
-    int wl, const unsigned short * ap, unsigned short al, char * bad, int badl)\r
+    int wl, const unsigned short * ap, unsigned short al, char * bad, int badl,\r
+    char * phon)\r
 {\r
-\r
     int nh=0;\r
-\r
     // first add root word to list\r
-    if ((nh < maxn) && !(al && ((pseudoroot && TESTAFF(ap, pseudoroot, al)) ||\r
+    if ((nh < maxn) && !(al && ((needaffix && TESTAFF(ap, needaffix, al)) ||\r
          (onlyincompound && TESTAFF(ap, onlyincompound, al))))) {\r
        wlst[nh].word = mystrdup(ts);\r
+       if (!wlst[nh].word) return 0;\r
        wlst[nh].allow = (1 == 0);\r
+       wlst[nh].orig = NULL;\r
        nh++;\r
+       // add special phonetic version\r
+       if (phon && (nh < maxn)) {\r
+           wlst[nh].word = mystrdup(phon);\r
+            if (!wlst[nh].word) return nh - 1;\r
+           wlst[nh].allow = (1 == 0);\r
+           wlst[nh].orig = mystrdup(ts);\r
+            if (!wlst[nh].orig) return nh - 1;\r
+           nh++;\r
+       }\r
     }\r
 \r
     // handle suffixes\r
     for (int i = 0; i < al; i++) {\r
-       unsigned short c = (unsigned short) ap[i];\r
-       SfxEntry * sptr = (SfxEntry *)sFlag[c];\r
+       const unsigned char c = (unsigned char) (ap[i] & 0x00FF);\r
+       SfxEntry * sptr = sFlag[c];\r
        while (sptr) {\r
-         if (!sptr->getKeyLen() || ((badl > sptr->getKeyLen()) &&\r
-                (strcmp(sptr->getAffix(), bad + badl - sptr->getKeyLen()) == 0)) &&\r
-                // check pseudoroot flag\r
-                !(sptr->getCont() && ((pseudoroot && \r
-                      TESTAFF(sptr->getCont(), pseudoroot, sptr->getContLen())) ||\r
+         if ((sptr->getFlag() == ap[i]) && (!sptr->getKeyLen() || ((badl > sptr->getKeyLen()) &&\r
+                (strcmp(sptr->getAffix(), bad + badl - sptr->getKeyLen()) == 0))) &&\r
+                // check needaffix flag\r
+                !(sptr->getCont() && ((needaffix && \r
+                      TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) ||\r
                   (circumfix && \r
                       TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())) ||\r
                   (onlyincompound && \r
@@ -2812,14 +3058,28 @@ int AffixMgr::expand_rootword(struct guessword * wlst, int maxn, const char * ts
             if (newword) {\r
                 if (nh < maxn) {\r
                     wlst[nh].word = newword;\r
-                    wlst[nh].allow = sptr->allowCross();              \r
-                nh++;\r
+                    wlst[nh].allow = sptr->allowCross();\r
+                    wlst[nh].orig = NULL;\r
+                    nh++;\r
+                    // add special phonetic version\r
+                   if (phon && (nh < maxn)) {\r
+                       char st[MAXWORDUTF8LEN];\r
+                       strcpy(st, phon);\r
+                       strcat(st, sptr->getKey());\r
+                       reverseword(st + strlen(phon));\r
+                       wlst[nh].word = mystrdup(st);\r
+                       if (!wlst[nh].word) return nh - 1;\r
+                       wlst[nh].allow = (1 == 0);\r
+                       wlst[nh].orig = mystrdup(newword);\r
+                        if (!wlst[nh].orig) return nh - 1;\r
+                       nh++;\r
+                   }\r
                 } else {\r
                     free(newword);\r
                 }\r
             }\r
          }\r
-         sptr = (SfxEntry *)sptr ->getFlgNxt();\r
+         sptr = sptr->getFlgNxt();\r
        }\r
     }\r
 \r
@@ -2829,10 +3089,10 @@ int AffixMgr::expand_rootword(struct guessword * wlst, int maxn, const char * ts
     for (int j=1;j<n ;j++)\r
        if (wlst[j].allow) {\r
           for (int k = 0; k < al; k++) {\r
-             unsigned short c = (unsigned short) ap[k];\r
-             PfxEntry * cptr = (PfxEntry *) pFlag[c];\r
+             const unsigned char c = (unsigned char) (ap[k] & 0x00FF);\r
+             PfxEntry * cptr = pFlag[c];\r
              while (cptr) {\r
-                if (cptr->allowCross() && (!cptr->getKeyLen() || ((badl > cptr->getKeyLen()) &&\r
+                if ((cptr->getFlag() == ap[k]) && cptr->allowCross() && (!cptr->getKeyLen() || ((badl > cptr->getKeyLen()) &&\r
                         (strncmp(cptr->getKey(), bad, cptr->getKeyLen()) == 0)))) {\r
                     int l1 = strlen(wlst[j].word);\r
                     char * newword = cptr->add(wlst[j].word, l1);\r
@@ -2840,13 +3100,14 @@ int AffixMgr::expand_rootword(struct guessword * wlst, int maxn, const char * ts
                        if (nh < maxn) {\r
                           wlst[nh].word = newword;\r
                           wlst[nh].allow = cptr->allowCross();\r
+                          wlst[nh].orig = NULL;\r
                           nh++;\r
                        } else {\r
                           free(newword);\r
                        }\r
                     }\r
                 }\r
-                cptr = (PfxEntry *)cptr ->getFlgNxt();\r
+                cptr = cptr->getFlgNxt();\r
              }\r
           }\r
        }\r
@@ -2854,14 +3115,14 @@ int AffixMgr::expand_rootword(struct guessword * wlst, int maxn, const char * ts
 \r
     // now handle pure prefixes\r
     for (int m = 0; m < al; m ++) {\r
-       unsigned short c = (unsigned short) ap[m];\r
-       PfxEntry * ptr = (PfxEntry *) pFlag[c];\r
+       const unsigned char c = (unsigned char) (ap[m] & 0x00FF);\r
+       PfxEntry * ptr = pFlag[c];\r
        while (ptr) {\r
-         if (!ptr->getKeyLen() || ((badl > ptr->getKeyLen()) &&\r
-                (strncmp(ptr->getKey(), bad, ptr->getKeyLen()) == 0)) &&\r
-                // check pseudoroot flag\r
-                !(ptr->getCont() && ((pseudoroot && \r
-                      TESTAFF(ptr->getCont(), pseudoroot, ptr->getContLen())) ||\r
+         if ((ptr->getFlag() == ap[m]) && (!ptr->getKeyLen() || ((badl > ptr->getKeyLen()) &&\r
+                (strncmp(ptr->getKey(), bad, ptr->getKeyLen()) == 0))) &&\r
+                // check needaffix flag\r
+                !(ptr->getCont() && ((needaffix && \r
+                      TESTAFF(ptr->getCont(), needaffix, ptr->getContLen())) ||\r
                      (circumfix && \r
                       TESTAFF(ptr->getCont(), circumfix, ptr->getContLen())) ||                      \r
                   (onlyincompound && \r
@@ -2872,55 +3133,75 @@ int AffixMgr::expand_rootword(struct guessword * wlst, int maxn, const char * ts
                 if (nh < maxn) {\r
                     wlst[nh].word = newword;\r
                     wlst[nh].allow = ptr->allowCross();\r
+                    wlst[nh].orig = NULL;\r
                     nh++;\r
                 } else {\r
                     free(newword);\r
                 } \r
             }\r
          }\r
-         ptr = (PfxEntry *)ptr ->getFlgNxt();\r
+         ptr = ptr->getFlgNxt();\r
        }\r
     }\r
 \r
     return nh;\r
 }\r
 \r
-\r
-\r
 // return length of replacing table\r
-int AffixMgr::get_numrep()\r
+int AffixMgr::get_numrep() const\r
 {\r
   return numrep;\r
 }\r
 \r
 // return replacing table\r
-struct replentry * AffixMgr::get_reptable()\r
+struct replentry * AffixMgr::get_reptable() const\r
 {\r
   if (! reptable ) return NULL;\r
   return reptable;\r
 }\r
 \r
+// return iconv table\r
+RepList * AffixMgr::get_iconvtable() const\r
+{\r
+  if (! iconvtable ) return NULL;\r
+  return iconvtable;\r
+}\r
+\r
+// return oconv table\r
+RepList * AffixMgr::get_oconvtable() const\r
+{\r
+  if (! oconvtable ) return NULL;\r
+  return oconvtable;\r
+}\r
+\r
+// return replacing table\r
+struct phonetable * AffixMgr::get_phonetable() const\r
+{\r
+  if (! phone ) return NULL;\r
+  return phone;\r
+}\r
+\r
 // return length of character map table\r
-int AffixMgr::get_nummap()\r
+int AffixMgr::get_nummap() const\r
 {\r
   return nummap;\r
 }\r
 \r
 // return character map table\r
-struct mapentry * AffixMgr::get_maptable()\r
+struct mapentry * AffixMgr::get_maptable() const\r
 {\r
   if (! maptable ) return NULL;\r
   return maptable;\r
 }\r
 \r
 // return length of word break table\r
-int AffixMgr::get_numbreak()\r
+int AffixMgr::get_numbreak() const\r
 {\r
   return numbreak;\r
 }\r
 \r
 // return character map table\r
-char ** AffixMgr::get_breaktable()\r
+char ** AffixMgr::get_breaktable() const\r
 {\r
   if (! breaktable ) return NULL;\r
   return breaktable;\r
@@ -2929,148 +3210,180 @@ char ** AffixMgr::get_breaktable()
 // return text encoding of dictionary\r
 char * AffixMgr::get_encoding()\r
 {\r
-  if (! encoding ) {\r
-      encoding = mystrdup("ISO8859-1");\r
-  }\r
+  if (! encoding ) encoding = mystrdup(SPELL_ENCODING);\r
   return mystrdup(encoding);\r
 }\r
 \r
 // return text encoding of dictionary\r
-int AffixMgr::get_langnum()\r
+int AffixMgr::get_langnum() const\r
 {\r
   return langnum;\r
 }\r
 \r
 // return double prefix option\r
-int AffixMgr::get_complexprefixes()\r
+int AffixMgr::get_complexprefixes() const\r
 {\r
   return complexprefixes;\r
 }\r
 \r
-FLAG AffixMgr::get_keepcase()\r
+// return FULLSTRIP option\r
+int AffixMgr::get_fullstrip() const\r
+{\r
+  return fullstrip;\r
+}\r
+\r
+FLAG AffixMgr::get_keepcase() const\r
 {\r
   return keepcase;\r
 }\r
 \r
-int AffixMgr::get_checksharps()\r
+FLAG AffixMgr::get_forceucase() const\r
+{\r
+  return forceucase;\r
+}\r
+\r
+FLAG AffixMgr::get_warn() const\r
+{\r
+  return warn;\r
+}\r
+\r
+int AffixMgr::get_forbidwarn() const\r
+{\r
+  return forbidwarn;\r
+}\r
+\r
+int AffixMgr::get_checksharps() const\r
 {\r
   return checksharps;\r
 }\r
 \r
+char * AffixMgr::encode_flag(unsigned short aflag) const\r
+{\r
+  return pHMgr->encode_flag(aflag);\r
+}\r
+\r
+\r
 // return the preferred ignore string for suggestions\r
-char * AffixMgr::get_ignore()\r
+char * AffixMgr::get_ignore() const\r
 {\r
   if (!ignorechars) return NULL;\r
-  return mystrdup(ignorechars);\r
+  return ignorechars;\r
 }\r
 \r
 // return the preferred ignore string for suggestions\r
-unsigned short * AffixMgr::get_ignore_utf16(int * len)\r
+unsigned short * AffixMgr::get_ignore_utf16(int * len) const\r
 {\r
   *len = ignorechars_utf16_len;\r
   return ignorechars_utf16;\r
 }\r
 \r
+// return the keyboard string for suggestions\r
+char * AffixMgr::get_key_string()\r
+{\r
+  if (! keystring ) keystring = mystrdup(SPELL_KEYSTRING);\r
+  return mystrdup(keystring);\r
+}\r
+\r
 // return the preferred try string for suggestions\r
-char * AffixMgr::get_try_string()\r
+char * AffixMgr::get_try_string() const\r
 {\r
   if (! trystring ) return NULL;\r
   return mystrdup(trystring);\r
 }\r
 \r
 // return the preferred try string for suggestions\r
-const char * AffixMgr::get_wordchars()\r
+const char * AffixMgr::get_wordchars() const\r
 {\r
   return wordchars;\r
 }\r
 \r
-unsigned short * AffixMgr::get_wordchars_utf16(int * len)\r
+unsigned short * AffixMgr::get_wordchars_utf16(int * len) const\r
 {\r
   *len = wordchars_utf16_len;\r
   return wordchars_utf16;\r
 }\r
 \r
 // is there compounding?\r
-int AffixMgr::get_compound()\r
+int AffixMgr::get_compound() const\r
 {\r
   return compoundflag || compoundbegin || numdefcpd;\r
 }\r
 \r
 // return the compound words control flag\r
-FLAG AffixMgr::get_compoundflag()\r
+FLAG AffixMgr::get_compoundflag() const\r
 {\r
   return compoundflag;\r
 }\r
 \r
 // return the forbidden words control flag\r
-FLAG AffixMgr::get_forbiddenword()\r
+FLAG AffixMgr::get_forbiddenword() const\r
 {\r
   return forbiddenword;\r
 }\r
 \r
 // return the forbidden words control flag\r
-FLAG AffixMgr::get_nosuggest()\r
+FLAG AffixMgr::get_nosuggest() const\r
 {\r
   return nosuggest;\r
 }\r
 \r
+// return the forbidden words control flag\r
+FLAG AffixMgr::get_nongramsuggest() const\r
+{\r
+  return nongramsuggest;\r
+}\r
+\r
 // return the forbidden words flag modify flag\r
-FLAG AffixMgr::get_pseudoroot()\r
+FLAG AffixMgr::get_needaffix() const\r
 {\r
-  return pseudoroot;\r
+  return needaffix;\r
 }\r
 \r
 // return the onlyincompound flag\r
-FLAG AffixMgr::get_onlyincompound()\r
+FLAG AffixMgr::get_onlyincompound() const\r
 {\r
   return onlyincompound;\r
 }\r
 \r
 // return the compound word signal flag\r
-FLAG AffixMgr::get_compoundroot()\r
+FLAG AffixMgr::get_compoundroot() const\r
 {\r
   return compoundroot;\r
 }\r
 \r
 // return the compound begin signal flag\r
-FLAG AffixMgr::get_compoundbegin()\r
+FLAG AffixMgr::get_compoundbegin() const\r
 {\r
   return compoundbegin;\r
 }\r
 \r
 // return the value of checknum\r
-int AffixMgr::get_checknum()\r
+int AffixMgr::get_checknum() const\r
 {\r
   return checknum;\r
 }\r
 \r
 // return the value of prefix\r
-const char * AffixMgr::get_prefix()\r
+const char * AffixMgr::get_prefix() const\r
 {\r
-  if (pfx) return ((PfxEntry *)pfx)->getKey();\r
+  if (pfx) return pfx->getKey();\r
   return NULL;\r
 }\r
 \r
 // return the value of suffix\r
-const char * AffixMgr::get_suffix()\r
+const char * AffixMgr::get_suffix() const\r
 {\r
   return sfxappnd;\r
 }\r
 \r
-// return the value of derived form (base word with first suffix).\r
-const char * AffixMgr::get_derived()\r
-{\r
-  return derived;\r
-}\r
-\r
 // return the value of suffix\r
-const char * AffixMgr::get_version()\r
+const char * AffixMgr::get_version() const\r
 {\r
   return version;\r
 }\r
 \r
 // return lemma_present flag\r
-FLAG AffixMgr::get_lemma_present()\r
+FLAG AffixMgr::get_lemma_present() const\r
 {\r
   return lemma_present;\r
 }\r
@@ -3078,68 +3391,86 @@ FLAG AffixMgr::get_lemma_present()
 // utility method to look up root words in hash table\r
 struct hentry * AffixMgr::lookup(const char * word)\r
 {\r
-  if (! pHMgr) return NULL;\r
-  return pHMgr->lookup(word);\r
+  int i;\r
+  struct hentry * he = NULL;\r
+  for (i = 0; i < *maxdic && !he; i++) {\r
+    he = (alldic[i])->lookup(word);\r
+  }\r
+  return he;\r
 }\r
 \r
 // return the value of suffix\r
-const int AffixMgr::have_contclass()\r
+int AffixMgr::have_contclass() const\r
 {\r
   return havecontclass;\r
 }\r
 \r
 // return utf8\r
-int AffixMgr::get_utf8()\r
+int AffixMgr::get_utf8() const\r
 {\r
   return utf8;\r
 }\r
 \r
-// return nosplitsugs\r
-int AffixMgr::get_maxngramsugs(void)\r
+int AffixMgr::get_maxngramsugs(void) const\r
 {\r
   return maxngramsugs;\r
 }\r
 \r
+int AffixMgr::get_maxcpdsugs(void) const\r
+{\r
+  return maxcpdsugs;\r
+}\r
+\r
+int AffixMgr::get_maxdiff(void) const\r
+{\r
+  return maxdiff;\r
+}\r
+\r
+int AffixMgr::get_onlymaxdiff(void) const\r
+{\r
+  return onlymaxdiff;\r
+}\r
+\r
 // return nosplitsugs\r
-int AffixMgr::get_nosplitsugs(void)\r
+int AffixMgr::get_nosplitsugs(void) const\r
 {\r
   return nosplitsugs;\r
 }\r
 \r
 // return sugswithdots\r
-int AffixMgr::get_sugswithdots(void)\r
+int AffixMgr::get_sugswithdots(void) const\r
 {\r
   return sugswithdots;\r
 }\r
 \r
 /* parse flag */\r
-int AffixMgr::parse_flag(char * line, unsigned short * out, const char * name) {\r
+int AffixMgr::parse_flag(char * line, unsigned short * out, FileMgr * af) {\r
    char * s = NULL;\r
-   if (*out != FLAG_NULL) {\r
-      HUNSPELL_WARNING(stderr, "error: duplicate %s line\n", name);\r
+   if (*out != FLAG_NULL && !(*out >= DEFAULTFLAGS)) {\r
+      HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions of an affix file parameter\n", af->getlinenum());\r
       return 1;\r
    }\r
-   if (parse_string(line, &s, name)) return 1;\r
+   if (parse_string(line, &s, af->getlinenum())) return 1;\r
    *out = pHMgr->decode_flag(s);\r
    free(s);\r
    return 0;\r
 }\r
 \r
 /* parse num */\r
-int AffixMgr::parse_num(char * line, int * out, const char * name) {\r
+int AffixMgr::parse_num(char * line, int * out, FileMgr * af) {\r
    char * s = NULL;\r
    if (*out != -1) {\r
-      HUNSPELL_WARNING(stderr, "error: duplicate %s line\n", name);\r
+      HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions of an affix file parameter\n", af->getlinenum());\r
       return 1;\r
    }\r
-   if (parse_string(line, &s, name)) return 1;\r
+   if (parse_string(line, &s, af->getlinenum())) return 1;\r
    *out = atoi(s);\r
    free(s);\r
    return 0;\r
 }\r
 \r
 /* parse in the max syllablecount of compound words and  */\r
-int  AffixMgr::parse_cpdsyllable(char * line)\r
+int  AffixMgr::parse_cpdsyllable(char * line, FileMgr * af)\r
 {\r
    char * tp = line;\r
    char * piece;\r
@@ -3172,11 +3503,10 @@ int  AffixMgr::parse_cpdsyllable(char * line)
           }\r
           i++;\r
       }\r
-      free(piece);\r
       piece = mystrsep(&tp, 0);\r
    }\r
    if (np < 2) {\r
-      HUNSPELL_WARNING(stderr, "error: missing compoundsyllable information\n");\r
+      HUNSPELL_WARNING(stderr, "error: line %d: missing compoundsyllable information\n", af->getlinenum());\r
       return 1;\r
    }\r
    if (np == 2) cpdvowels = mystrdup("aeiouAEIOU");\r
@@ -3184,10 +3514,10 @@ int  AffixMgr::parse_cpdsyllable(char * line)
 }\r
 \r
 /* parse in the typical fault correcting table */\r
-int  AffixMgr::parse_reptable(char * line, FILE * af)\r
+int  AffixMgr::parse_reptable(char * line, FileMgr * af)\r
 {\r
    if (numrep != 0) {\r
-      HUNSPELL_WARNING(stderr, "error: duplicate REP tables used\n");\r
+      HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum());\r
       return 1;\r
    }\r
    char * tp = line;\r
@@ -3202,15 +3532,11 @@ int  AffixMgr::parse_reptable(char * line, FILE * af)
              case 1: { \r
                        numrep = atoi(piece);\r
                        if (numrep < 1) {\r
-                          HUNSPELL_WARNING(stderr, "incorrect number of entries in replacement table\n");\r
-                          free(piece);\r
+                          HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n", af->getlinenum());\r
                           return 1;\r
                        }\r
                        reptable = (replentry *) malloc(numrep * sizeof(struct replentry));\r
-                       if (!reptable) {\r
-                         free(piece);\r
-                         return 1;\r
-                       }\r
+                       if (!reptable) return 1;\r
                        np++;\r
                        break;\r
                      }\r
@@ -3218,18 +3544,17 @@ int  AffixMgr::parse_reptable(char * line, FILE * af)
           }\r
           i++;\r
        }\r
-       free(piece);\r
        piece = mystrsep(&tp, 0);\r
    }\r
    if (np != 2) {\r
-      HUNSPELL_WARNING(stderr, "error: missing replacement table information\n");\r
+      HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum());\r
       return 1;\r
    } \r
  \r
    /* now parse the numrep lines to read in the remainder of the table */\r
-   char * nl = line;\r
+   char * nl;\r
    for (int j=0; j < numrep; j++) {\r
-        if (!fgets(nl,MAXLNLEN,af)) return 1;\r
+        if (!(nl = af->getline())) return 1;\r
         mychomp(nl);\r
         tp = nl;\r
         i = 0;\r
@@ -3241,34 +3566,216 @@ int  AffixMgr::parse_reptable(char * line, FILE * af)
                switch(i) {\r
                   case 0: {\r
                              if (strncmp(piece,"REP",3) != 0) {\r
-                                 HUNSPELL_WARNING(stderr, "error: replacement table is corrupt\n");\r
-                                 free(piece);\r
+                                 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+                                 numrep = 0;\r
                                  return 1;\r
                              }\r
                              break;\r
                           }\r
-                  case 1: { reptable[j].pattern = mystrrep(mystrdup(piece),"_"," "); break; }\r
+                  case 1: {\r
+                            if (*piece == '^') reptable[j].start = true; else reptable[j].start = false;\r
+                            reptable[j].pattern = mystrrep(mystrdup(piece + int(reptable[j].start)),"_"," ");\r
+                            int lr = strlen(reptable[j].pattern) - 1;\r
+                            if (reptable[j].pattern[lr] == '$') {\r
+                                reptable[j].end = true;\r
+                                reptable[j].pattern[lr] = '\0';\r
+                            } else reptable[j].end = false;\r
+                            break;\r
+                          }\r
                   case 2: { reptable[j].pattern2 = mystrrep(mystrdup(piece),"_"," "); break; }\r
                   default: break;\r
                }\r
                i++;\r
            }\r
-           free(piece);\r
            piece = mystrsep(&tp, 0);\r
         }\r
         if ((!(reptable[j].pattern)) || (!(reptable[j].pattern2))) {\r
-             HUNSPELL_WARNING(stderr, "error: replacement table is corrupt\n");\r
+             HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+             numrep = 0;\r
+             return 1;\r
+        }\r
+   }\r
+   return 0;\r
+}\r
+\r
+/* parse in the typical fault correcting table */\r
+int  AffixMgr::parse_convtable(char * line, FileMgr * af, RepList ** rl, const char * keyword)\r
+{\r
+   if (*rl) {\r
+      HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum());\r
+      return 1;\r
+   }\r
+   char * tp = line;\r
+   char * piece;\r
+   int i = 0;\r
+   int np = 0;\r
+   int numrl = 0;\r
+   piece = mystrsep(&tp, 0);\r
+   while (piece) {\r
+       if (*piece != '\0') {\r
+          switch(i) {\r
+             case 0: { np++; break; }\r
+             case 1: { \r
+                       numrl = atoi(piece);\r
+                       if (numrl < 1) {\r
+                          HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n", af->getlinenum());\r
+                          return 1;\r
+                       }\r
+                       *rl = new RepList(numrl);\r
+                       if (!*rl) return 1;\r
+                       np++;\r
+                       break;\r
+                     }\r
+             default: break;\r
+          }\r
+          i++;\r
+       }\r
+       piece = mystrsep(&tp, 0);\r
+   }\r
+   if (np != 2) {\r
+      HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum());\r
+      return 1;\r
+   } \r
\r
+   /* now parse the num lines to read in the remainder of the table */\r
+   char * nl;\r
+   for (int j=0; j < numrl; j++) {\r
+        if (!(nl = af->getline())) return 1;\r
+        mychomp(nl);\r
+        tp = nl;\r
+        i = 0;\r
+        char * pattern = NULL;\r
+        char * pattern2 = NULL;\r
+        piece = mystrsep(&tp, 0);\r
+        while (piece) {\r
+           if (*piece != '\0') {\r
+               switch(i) {\r
+                  case 0: {\r
+                             if (strncmp(piece, keyword, sizeof(keyword)) != 0) {\r
+                                 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+                                 delete *rl;\r
+                                 *rl = NULL;\r
+                                 return 1;\r
+                             }\r
+                             break;\r
+                          }\r
+                  case 1: { pattern = mystrrep(mystrdup(piece),"_"," "); break; }\r
+                  case 2: { \r
+                    pattern2 = mystrrep(mystrdup(piece),"_"," ");\r
+                    break; \r
+                  }\r
+                  default: break;\r
+               }\r
+               i++;\r
+           }\r
+           piece = mystrsep(&tp, 0);\r
+        }\r
+        if (!pattern || !pattern2) {\r
+            if (pattern)\r
+                free(pattern);\r
+            if (pattern2)\r
+                free(pattern2);\r
+            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+            return 1;\r
+        }\r
+        (*rl)->add(pattern, pattern2);\r
+   }\r
+   return 0;\r
+}\r
+\r
+\r
+/* parse in the typical fault correcting table */\r
+int  AffixMgr::parse_phonetable(char * line, FileMgr * af)\r
+{\r
+   if (phone) {\r
+      HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum());\r
+      return 1;\r
+   }\r
+   char * tp = line;\r
+   char * piece;\r
+   int i = 0;\r
+   int np = 0;\r
+   piece = mystrsep(&tp, 0);\r
+   while (piece) {\r
+       if (*piece != '\0') {\r
+          switch(i) {\r
+             case 0: { np++; break; }\r
+             case 1: { \r
+                       phone = (phonetable *) malloc(sizeof(struct phonetable));\r
+                       if (!phone) return 1;\r
+                       phone->num = atoi(piece);\r
+                       phone->rules = NULL;\r
+                       phone->utf8 = (char) utf8;\r
+                       if (phone->num < 1) {\r
+                          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum());\r
+                          return 1;\r
+                       }\r
+                       phone->rules = (char * *) malloc(2 * (phone->num + 1) * sizeof(char *));\r
+                       if (!phone->rules) {\r
+                          free(phone);\r
+                          phone = NULL;\r
+                          return 1;\r
+                       }\r
+                       np++;\r
+                       break;\r
+                     }\r
+             default: break;\r
+          }\r
+          i++;\r
+       }\r
+       piece = mystrsep(&tp, 0);\r
+   }\r
+   if (np != 2) {\r
+      HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum());\r
+      return 1;\r
+   } \r
\r
+   /* now parse the phone->num lines to read in the remainder of the table */\r
+   char * nl;\r
+   for (int j=0; j < phone->num; j++) {\r
+        if (!(nl = af->getline())) return 1;\r
+        mychomp(nl);\r
+        tp = nl;\r
+        i = 0;\r
+        phone->rules[j * 2] = NULL;\r
+        phone->rules[j * 2 + 1] = NULL;\r
+        piece = mystrsep(&tp, 0);\r
+        while (piece) {\r
+           if (*piece != '\0') {\r
+               switch(i) {\r
+                  case 0: {\r
+                             if (strncmp(piece,"PHONE",5) != 0) {\r
+                                 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+                                 phone->num = 0;\r
+                                 return 1;\r
+                             }\r
+                             break;\r
+                          }\r
+                  case 1: { phone->rules[j * 2] = mystrrep(mystrdup(piece),"_",""); break; }\r
+                  case 2: { phone->rules[j * 2 + 1] = mystrrep(mystrdup(piece),"_",""); break; }\r
+                  default: break;\r
+               }\r
+               i++;\r
+           }\r
+           piece = mystrsep(&tp, 0);\r
+        }\r
+        if ((!(phone->rules[j * 2])) || (!(phone->rules[j * 2 + 1]))) {\r
+             HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+             phone->num = 0;\r
              return 1;\r
         }\r
    }\r
+   phone->rules[phone->num * 2] = mystrdup("");\r
+   phone->rules[phone->num * 2 + 1] = mystrdup("");\r
+   init_phonet_hash(*phone);\r
    return 0;\r
 }\r
 \r
 /* parse in the checkcompoundpattern table */\r
-int  AffixMgr::parse_checkcpdtable(char * line, FILE * af)\r
+int  AffixMgr::parse_checkcpdtable(char * line, FileMgr * af)\r
 {\r
    if (numcheckcpd != 0) {\r
-      HUNSPELL_WARNING(stderr, "error: duplicate compound pattern tables used\n");\r
+      HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum());\r
       return 1;\r
    }\r
    char * tp = line;\r
@@ -3283,15 +3790,11 @@ int  AffixMgr::parse_checkcpdtable(char * line, FILE * af)
              case 1: { \r
                        numcheckcpd = atoi(piece);\r
                        if (numcheckcpd < 1) {\r
-                          HUNSPELL_WARNING(stderr, "incorrect number of entries in compound pattern table\n");\r
-                          free(piece);\r
+                          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum());\r
                           return 1;\r
                        }\r
-                       checkcpdtable = (replentry *) malloc(numcheckcpd * sizeof(struct replentry));\r
-                       if (!checkcpdtable) {\r
-                         free(piece);\r
-                         return 1;\r
-                       }\r
+                       checkcpdtable = (patentry *) malloc(numcheckcpd * sizeof(struct patentry));\r
+                       if (!checkcpdtable) return 1;\r
                        np++;\r
                        break;\r
                      }\r
@@ -3299,46 +3802,64 @@ int  AffixMgr::parse_checkcpdtable(char * line, FILE * af)
           }\r
           i++;\r
        }\r
-       free(piece);\r
        piece = mystrsep(&tp, 0);\r
    }\r
    if (np != 2) {\r
-      HUNSPELL_WARNING(stderr, "error: missing compound pattern table information\n");\r
+      HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",  af->getlinenum());\r
       return 1;\r
-   } \r
\r
+   }\r
+\r
    /* now parse the numcheckcpd lines to read in the remainder of the table */\r
-   char * nl = line;\r
+   char * nl;\r
    for (int j=0; j < numcheckcpd; j++) {\r
-        if (!fgets(nl,MAXLNLEN,af)) return 1;\r
+        if (!(nl = af->getline())) return 1;\r
         mychomp(nl);\r
         tp = nl;\r
         i = 0;\r
         checkcpdtable[j].pattern = NULL;\r
         checkcpdtable[j].pattern2 = NULL;\r
+        checkcpdtable[j].pattern3 = NULL;\r
+        checkcpdtable[j].cond = FLAG_NULL;\r
+        checkcpdtable[j].cond2 = FLAG_NULL;\r
         piece = mystrsep(&tp, 0);\r
         while (piece) {\r
            if (*piece != '\0') {\r
                switch(i) {\r
                   case 0: {\r
                              if (strncmp(piece,"CHECKCOMPOUNDPATTERN",20) != 0) {\r
-                                 HUNSPELL_WARNING(stderr, "error: compound pattern table is corrupt\n");\r
-                                 free(piece);\r
+                                 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+                                 numcheckcpd = 0;\r
                                  return 1;\r
                              }\r
                              break;\r
                           }\r
-                  case 1: { checkcpdtable[j].pattern = mystrdup(piece); break; }\r
-                  case 2: { checkcpdtable[j].pattern2 = mystrdup(piece); break; }\r
+                  case 1: { \r
+                    checkcpdtable[j].pattern = mystrdup(piece); \r
+                    char * p = strchr(checkcpdtable[j].pattern, '/');\r
+                    if (p) {\r
+                      *p = '\0';\r
+                    checkcpdtable[j].cond = pHMgr->decode_flag(p + 1);\r
+                    }\r
+                    break; }\r
+                  case 2: { \r
+                    checkcpdtable[j].pattern2 = mystrdup(piece);\r
+                    char * p = strchr(checkcpdtable[j].pattern2, '/');\r
+                    if (p) {\r
+                      *p = '\0';\r
+                      checkcpdtable[j].cond2 = pHMgr->decode_flag(p + 1);\r
+                    }\r
+                    break;\r
+                    }\r
+                  case 3: { checkcpdtable[j].pattern3 = mystrdup(piece); simplifiedcpd = 1; break; }\r
                   default: break;\r
                }\r
                i++;\r
            }\r
-           free(piece);\r
            piece = mystrsep(&tp, 0);\r
         }\r
         if ((!(checkcpdtable[j].pattern)) || (!(checkcpdtable[j].pattern2))) {\r
-             HUNSPELL_WARNING(stderr, "error: compound pattern table is corrupt\n");\r
+             HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+             numcheckcpd = 0;\r
              return 1;\r
         }\r
    }\r
@@ -3346,10 +3867,10 @@ int  AffixMgr::parse_checkcpdtable(char * line, FILE * af)
 }\r
 \r
 /* parse in the compound rule table */\r
-int  AffixMgr::parse_defcpdtable(char * line, FILE * af)\r
+int  AffixMgr::parse_defcpdtable(char * line, FileMgr * af)\r
 {\r
    if (numdefcpd != 0) {\r
-      HUNSPELL_WARNING(stderr, "error: duplicate compound rule tables used\n");\r
+      HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum());\r
       return 1;\r
    }\r
    char * tp = line;\r
@@ -3364,15 +3885,11 @@ int  AffixMgr::parse_defcpdtable(char * line, FILE * af)
              case 1: { \r
                        numdefcpd = atoi(piece);\r
                        if (numdefcpd < 1) {\r
-                          HUNSPELL_WARNING(stderr, "incorrect number of entries in compound rule table\n");\r
-                          free(piece);\r
+                          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum());\r
                           return 1;\r
                        }\r
                        defcpdtable = (flagentry *) malloc(numdefcpd * sizeof(flagentry));\r
-                       if (!defcpdtable) {\r
-                           free(piece);\r
-                           return 1;\r
-                       }\r
+                       if (!defcpdtable) return 1;\r
                        np++;\r
                        break;\r
                      }\r
@@ -3380,18 +3897,17 @@ int  AffixMgr::parse_defcpdtable(char * line, FILE * af)
           }\r
           i++;\r
        }\r
-       free(piece);\r
        piece = mystrsep(&tp, 0);\r
    }\r
    if (np != 2) {\r
-      HUNSPELL_WARNING(stderr, "error: missing compound rule table information\n");\r
+      HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum());\r
       return 1;\r
    } \r
  \r
    /* now parse the numdefcpd lines to read in the remainder of the table */\r
-   char * nl = line;\r
+   char * nl;\r
    for (int j=0; j < numdefcpd; j++) {\r
-        if (!fgets(nl,MAXLNLEN,af)) return 1;\r
+        if (!(nl = af->getline())) return 1;\r
         mychomp(nl);\r
         tp = nl;\r
         i = 0;\r
@@ -3402,26 +3918,46 @@ int  AffixMgr::parse_defcpdtable(char * line, FILE * af)
                switch(i) {\r
                   case 0: {\r
                              if (strncmp(piece, "COMPOUNDRULE", 12) != 0) {\r
-                                 HUNSPELL_WARNING(stderr, "error: compound rule table is corrupt\n");\r
-                                 free(piece);\r
+                                 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+                                 numdefcpd = 0;\r
                                  return 1;\r
                              }\r
                              break;\r
                           }\r
-                  case 1: { \r
-                            defcpdtable[j].len = \r
-                                pHMgr->decode_flags(&(defcpdtable[j].def), piece);\r
+                  case 1: { // handle parenthesized flags\r
+                            if (strchr(piece, '(')) {\r
+                                defcpdtable[j].def = (FLAG *) malloc(strlen(piece) * sizeof(FLAG));\r
+                                defcpdtable[j].len = 0;\r
+                                int end = 0;\r
+                                FLAG * conv;\r
+                                while (!end) {\r
+                                    char * par = piece + 1;\r
+                                    while (*par != '(' && *par != ')' && *par != '\0') par++;\r
+                                    if (*par == '\0') end = 1; else *par = '\0';\r
+                                    if (*piece == '(') piece++;\r
+                                    if (*piece == '*' || *piece == '?') {\r
+                                        defcpdtable[j].def[defcpdtable[j].len++] = (FLAG) *piece;\r
+                                    } else if (*piece != '\0') {\r
+                                        int l = pHMgr->decode_flags(&conv, piece, af);\r
+                                        for (int k = 0; k < l; k++) defcpdtable[j].def[defcpdtable[j].len++] = conv[k];\r
+                                        free(conv);\r
+                                    }\r
+                                    piece = par + 1;\r
+                                }\r
+                            } else {\r
+                                defcpdtable[j].len = pHMgr->decode_flags(&(defcpdtable[j].def), piece, af);\r
+                            }\r
                             break; \r
                            }\r
                   default: break;\r
                }\r
                i++;\r
            }\r
-           free(piece);\r
            piece = mystrsep(&tp, 0);\r
         }\r
         if (!defcpdtable[j].len) {\r
-             HUNSPELL_WARNING(stderr, "error: compound rule table is corrupt\n");\r
+             HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+             numdefcpd = 0;\r
              return 1;\r
         }\r
    }\r
@@ -3430,10 +3966,10 @@ int  AffixMgr::parse_defcpdtable(char * line, FILE * af)
 \r
 \r
 /* parse in the character map table */\r
-int  AffixMgr::parse_maptable(char * line, FILE * af)\r
+int  AffixMgr::parse_maptable(char * line, FileMgr * af)\r
 {\r
    if (nummap != 0) {\r
-      HUNSPELL_WARNING(stderr, "error: duplicate MAP tables used\n");\r
+      HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum());\r
       return 1;\r
    }\r
    char * tp = line;\r
@@ -3448,15 +3984,11 @@ int  AffixMgr::parse_maptable(char * line, FILE * af)
              case 1: { \r
                        nummap = atoi(piece);\r
                        if (nummap < 1) {\r
-                          HUNSPELL_WARNING(stderr, "incorrect number of entries in map table\n");\r
-                          free(piece);\r
+                          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum());\r
                           return 1;\r
                        }\r
                        maptable = (mapentry *) malloc(nummap * sizeof(struct mapentry));\r
-                       if (!maptable) {\r
-                         free(piece);\r
-                         return 1;\r
-                       }\r
+                       if (!maptable) return 1;\r
                        np++;\r
                        break;\r
                      }\r
@@ -3464,18 +3996,17 @@ int  AffixMgr::parse_maptable(char * line, FILE * af)
           }\r
           i++;\r
        }\r
-       free(piece);\r
        piece = mystrsep(&tp, 0);\r
    }\r
    if (np != 2) {\r
-      HUNSPELL_WARNING(stderr, "error: missing map table information\n");\r
+      HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum());\r
       return 1;\r
    } \r
  \r
    /* now parse the nummap lines to read in the remainder of the table */\r
-   char * nl = line;\r
+   char * nl;\r
    for (int j=0; j < nummap; j++) {\r
-        if (!fgets(nl,MAXLNLEN,af)) return 1;\r
+        if (!(nl = af->getline())) return 1;\r
         mychomp(nl);\r
         tp = nl;\r
         i = 0;\r
@@ -3487,40 +4018,51 @@ int  AffixMgr::parse_maptable(char * line, FILE * af)
                switch(i) {\r
                   case 0: {\r
                              if (strncmp(piece,"MAP",3) != 0) {\r
-                                 HUNSPELL_WARNING(stderr, "error: map table is corrupt\n");\r
-                                 free(piece);\r
+                                 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+                                 nummap = 0;\r
                                  return 1;\r
                              }\r
                              break;\r
                           }\r
                   case 1: {\r
-                            maptable[j].len = 0;\r
-                            maptable[j].set = NULL;\r
-                            maptable[j].set_utf16 = NULL;\r
-                            if (!utf8) {\r
-                                maptable[j].set = mystrdup(piece); \r
-                                maptable[j].len = strlen(maptable[j].set);\r
-                            } else {\r
-                                w_char w[MAXWORDLEN];\r
-                                int n = u8_u16(w, MAXWORDLEN, piece);\r
-                                if (n > 0) {\r
-                                    flag_qsort((unsigned short *) w, 0, n);\r
-                                    maptable[j].set_utf16 = (w_char *) malloc(n * sizeof(w_char));\r
-                                    if (!maptable[j].set_utf16) return 1;\r
-                                    memcpy(maptable[j].set_utf16, w, n * sizeof(w_char));\r
-                                }\r
-                                maptable[j].len = n;\r
-                            }\r
+                           int setn = 0;\r
+                            maptable[j].len = strlen(piece);\r
+                            maptable[j].set = (char **) malloc(maptable[j].len * sizeof(char*));\r
+                            if (!maptable[j].set) return 1;\r
+                           for (int k = 0; k < maptable[j].len; k++) {\r
+                               int chl = 1;\r
+                               int chb = k;\r
+                               if (piece[k] == '(') {\r
+                                   char * parpos = strchr(piece + k, ')');\r
+                                   if (parpos != NULL) {\r
+                                       chb = k + 1;\r
+                                       chl = (int)(parpos - piece) - k - 1;\r
+                                       k = k + chl + 1;\r
+                                   }\r
+                               } else {\r
+                                   if (utf8 && (piece[k] & 0xc0) == 0xc0) {\r
+                                       for (k++; utf8 && (piece[k] & 0xc0) == 0x80; k++);\r
+                                       chl = k - chb;\r
+                                       k--;\r
+                                   }\r
+                               }\r
+                               maptable[j].set[setn] = (char *) malloc(chl + 1);\r
+                               if (!maptable[j].set[setn]) return 1;\r
+                               strncpy(maptable[j].set[setn], piece + chb, chl);\r
+                               maptable[j].set[setn][chl] = '\0';\r
+                               setn++;\r
+                           }\r
+                            maptable[j].len = setn;\r
                             break; }\r
                   default: break;\r
                }\r
                i++;\r
            }\r
-           free(piece);\r
            piece = mystrsep(&tp, 0);\r
         }\r
-        if ((!(maptable[j].set || maptable[j].set_utf16)) || (!(maptable[j].len))) {\r
-             HUNSPELL_WARNING(stderr, "error: map table is corrupt\n");\r
+        if (!maptable[j].set || !maptable[j].len) {\r
+             HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+             nummap = 0;\r
              return 1;\r
         }\r
    }\r
@@ -3528,10 +4070,10 @@ int  AffixMgr::parse_maptable(char * line, FILE * af)
 }\r
 \r
 /* parse in the word breakpoint table */\r
-int  AffixMgr::parse_breaktable(char * line, FILE * af)\r
+int  AffixMgr::parse_breaktable(char * line, FileMgr * af)\r
 {\r
-   if (numbreak != 0) {\r
-      HUNSPELL_WARNING(stderr, "error: duplicate word breakpoint tables used\n");\r
+   if (numbreak > -1) {\r
+      HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum());\r
       return 1;\r
    }\r
    char * tp = line;\r
@@ -3545,16 +4087,13 @@ int  AffixMgr::parse_breaktable(char * line, FILE * af)
              case 0: { np++; break; }\r
              case 1: { \r
                        numbreak = atoi(piece);\r
-                       if (numbreak < 1) {\r
-                          HUNSPELL_WARNING(stderr, "incorrect number of entries in BREAK table\n");\r
-                          free(piece);\r
+                       if (numbreak < 0) {\r
+                          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum());\r
                           return 1;\r
                        }\r
+                       if (numbreak == 0) return 0;\r
                        breaktable = (char **) malloc(numbreak * sizeof(char *));\r
-                       if (!breaktable) {\r
-                         free(piece);\r
-                         return 1;\r
-                       }\r
+                       if (!breaktable) return 1;\r
                        np++;\r
                        break;\r
                      }\r
@@ -3562,18 +4101,17 @@ int  AffixMgr::parse_breaktable(char * line, FILE * af)
           }\r
           i++;\r
        }\r
-       free(piece);\r
        piece = mystrsep(&tp, 0);\r
    }\r
    if (np != 2) {\r
-      HUNSPELL_WARNING(stderr, "error: missing word breakpoint table information\n");\r
+      HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum());\r
       return 1;\r
    } \r
  \r
    /* now parse the numbreak lines to read in the remainder of the table */\r
-   char * nl = line;\r
+   char * nl;\r
    for (int j=0; j < numbreak; j++) {\r
-        if (!fgets(nl,MAXLNLEN,af)) return 1;\r
+        if (!(nl = af->getline())) return 1;\r
         mychomp(nl);\r
         tp = nl;\r
         i = 0;\r
@@ -3583,8 +4121,8 @@ int  AffixMgr::parse_breaktable(char * line, FILE * af)
                switch(i) {\r
                   case 0: {\r
                              if (strncmp(piece,"BREAK",5) != 0) {\r
-                                 HUNSPELL_WARNING(stderr, "error: BREAK table is corrupt\n");\r
-                                 free(piece);\r
+                                 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+                                 numbreak = 0;\r
                                  return 1;\r
                              }\r
                              break;\r
@@ -3597,26 +4135,50 @@ int  AffixMgr::parse_breaktable(char * line, FILE * af)
                }\r
                i++;\r
            }\r
-           free(piece);\r
            piece = mystrsep(&tp, 0);\r
         }\r
         if (!breaktable) {\r
-             HUNSPELL_WARNING(stderr, "error: BREAK table is corrupt\n");\r
+             HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());\r
+             numbreak = 0;\r
              return 1;\r
         }\r
    }\r
    return 0;\r
 }\r
 \r
-int  AffixMgr::parse_affix(char * line, const char at, FILE * af, char * dupflags)\r
+void AffixMgr::reverse_condition(char * piece) {\r
+    int neg = 0;\r
+    for (char * k = piece + strlen(piece) - 1; k >= piece; k--) {\r
+        switch(*k) {\r
+          case '[': {\r
+                if (neg) *(k+1) = '['; else *k = ']';\r
+                    break;\r
+            }\r
+          case ']': {\r
+                *k = '[';\r
+                if (neg) *(k+1) = '^';\r
+                neg = 0;\r
+                break;\r
+            }\r
+          case '^': {\r
+               if (*(k+1) == ']') neg = 1; else *(k+1) = *k;\r
+               break;\r
+                }\r
+          default: {\r
+            if (neg) *(k+1) = *k;\r
+          }\r
+       }\r
+    }\r
+}\r
+\r
+int  AffixMgr::parse_affix(char * line, const char at, FileMgr * af, char * dupflags)\r
 {\r
    int numents = 0;      // number of affentry structures to parse\r
 \r
    unsigned short aflag = 0;      // affix char identifier\r
 \r
    char ff=0;\r
-   struct affentry * ptr= NULL;\r
-   struct affentry * nptr= NULL;\r
+   std::vector<affentry> affentries;\r
 \r
    char * tp = line;\r
    char * nl = line;\r
@@ -3631,6 +4193,7 @@ int  AffixMgr::parse_affix(char * line, const char at, FILE * af, char * dupflag
    // split affix header line into pieces\r
 \r
    int np = 0;\r
+\r
    piece = mystrsep(&tp, 0);\r
    while (piece) {\r
       if (*piece != '\0') {\r
@@ -3644,10 +4207,11 @@ int  AffixMgr::parse_affix(char * line, const char at, FILE * af, char * dupflag
                     aflag = pHMgr->decode_flag(piece);\r
                     if (((at == 'S') && (dupflags[aflag] & dupSFX)) ||\r
                         ((at == 'P') && (dupflags[aflag] & dupPFX))) {\r
-                        HUNSPELL_WARNING(stderr, "error: duplicate affix flag %s in line %s\n", piece, nl);\r
+                        HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions of an affix flag\n",\r
+                            af->getlinenum());\r
                         // return 1; XXX permissive mode for bad dictionaries\r
                     }\r
-                    dupflags[aflag] += ((at == 'S') ? dupSFX : dupPFX);\r
+                    dupflags[aflag] += (char) ((at == 'S') ? dupSFX : dupPFX);\r
                     break; \r
                     }\r
              // piece 3 - is cross product indicator \r
@@ -3659,44 +4223,42 @@ int  AffixMgr::parse_affix(char * line, const char at, FILE * af, char * dupflag
                        numents = atoi(piece); \r
                        if (numents == 0) {\r
                            char * err = pHMgr->encode_flag(aflag);\r
-                           HUNSPELL_WARNING(stderr, "error: affix %s header has incorrect entry count in line %s\n",\r
-                                   err, nl);\r
-                           free(err);\r
+                           if (err) {\r
+                                HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",\r
+                                   af->getlinenum());\r
+                                free(err);\r
+                           }\r
                            return 1;\r
                        }\r
-                       ptr = (struct affentry *) malloc(numents * sizeof(struct affentry));\r
-                       if (!ptr) return 1;\r
-                       ptr->opts = ff;\r
-                       if (utf8) ptr->opts += aeUTF8;\r
-                       if (pHMgr->is_aliasf()) ptr->opts += aeALIASF;\r
-#ifdef HUNSPELL_EXPERIMENTAL\r
-                       if (pHMgr->is_aliasm()) ptr->opts += aeALIASM;\r
-#endif\r
-                       ptr->aflag = aflag;\r
+                       affentries.resize(numents);\r
+                       affentries[0].opts = ff;\r
+                       if (utf8) affentries[0].opts += aeUTF8;\r
+                       if (pHMgr->is_aliasf()) affentries[0].opts += aeALIASF;\r
+                       if (pHMgr->is_aliasm()) affentries[0].opts += aeALIASM;\r
+                       affentries[0].aflag = aflag;\r
                      }\r
 \r
              default: break;\r
           }\r
           i++;\r
       }\r
-      free(piece);\r
       piece = mystrsep(&tp, 0);\r
    }\r
    // check to make sure we parsed enough pieces\r
    if (np != 4) {\r
-       char * err = pHMgr->encode_flag(aflag); \r
-       HUNSPELL_WARNING(stderr, "error: affix %s header has insufficient data in line %s\n", err, nl);\r
-       free(err);\r
-       free(ptr);\r
+       char * err = pHMgr->encode_flag(aflag);\r
+       if (err) {\r
+            HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum());\r
+            free(err);\r
+       }\r
        return 1;\r
    }\r
  \r
-   // store away ptr to first affentry\r
-   nptr = ptr;\r
-\r
    // now parse numents affentries for this affix\r
-   for (int j=0; j < numents; j++) {\r
-      if (!fgets(nl,MAXLNLEN,af)) return 1;\r
+   std::vector<affentry>::iterator start = affentries.begin();\r
+   std::vector<affentry>::iterator end = affentries.end();\r
+   for (std::vector<affentry>::iterator entry = start; entry != end; ++entry) {\r
+      if (!(nl = af->getline())) return 1;\r
       mychomp(nl);\r
       tp = nl;\r
       i = 0;\r
@@ -3710,7 +4272,8 @@ int  AffixMgr::parse_affix(char * line, const char at, FILE * af, char * dupflag
                 // piece 1 - is type\r
                 case 0: { \r
                           np++;\r
-                          if (nptr != ptr) nptr->opts = ptr->opts;\r
+                          if (entry != start) entry->opts = start->opts &\r
+                             (char) (aeXPRODUCT + aeUTF8 + aeALIASF + aeALIASM);\r
                           break;\r
                         }\r
 \r
@@ -3719,14 +4282,15 @@ int  AffixMgr::parse_affix(char * line, const char at, FILE * af, char * dupflag
                           np++;\r
                           if (pHMgr->decode_flag(piece) != aflag) {\r
                               char * err = pHMgr->encode_flag(aflag);\r
-                              HUNSPELL_WARNING(stderr, "error: affix %s is corrupt near line %s\n", err, nl);\r
-                              HUNSPELL_WARNING(stderr, "error: possible incorrect count\n");\r
-                              free(err);\r
-                              free(piece);\r
+                              if (err) {\r
+