OSDN Git Service

Commit DialogBox compile Okay
[tortoisegit/TortoiseGitJp.git] / ext / hunspell / hashmgr.cxx
diff --git a/ext/hunspell/hashmgr.cxx b/ext/hunspell/hashmgr.cxx
new file mode 100644 (file)
index 0000000..1d01cbf
--- /dev/null
@@ -0,0 +1,741 @@
+#include "license.hunspell"\r
+#include "license.myspell"\r
+\r
+#ifndef MOZILLA_CLIENT\r
+#include <cstdlib>\r
+#include <cstring>\r
+#include <cstdio>\r
+#include <cctype>\r
+#else\r
+#include <stdlib.h> \r
+#include <string.h>\r
+#include <stdio.h> \r
+#include <ctype.h>\r
+#endif\r
+\r
+#include "hashmgr.hxx"\r
+#include "csutil.hxx"\r
+#include "atypes.hxx"\r
+\r
+#ifdef MOZILLA_CLIENT\r
+#ifdef __SUNPRO_CC // for SunONE Studio compiler\r
+using namespace std;\r
+#endif\r
+#else\r
+#ifndef W32\r
+using namespace std;\r
+#endif\r
+#endif\r
+\r
+// build a hash table from a munched word list\r
+\r
+HashMgr::HashMgr(const char * tpath, const char * apath)\r
+{\r
+  tablesize = 0;\r
+  tableptr = NULL;\r
+  flag_mode = FLAG_CHAR;\r
+  complexprefixes = 0;\r
+  utf8 = 0;\r
+  ignorechars = NULL;\r
+  ignorechars_utf16 = NULL;\r
+  ignorechars_utf16_len = 0;\r
+  numaliasf = 0;\r
+  aliasf = NULL;\r
+  numaliasm = 0;\r
+  aliasm = NULL;\r
+  load_config(apath);  \r
+  int ec = load_tables(tpath);\r
+  if (ec) {\r
+    /* error condition - what should we do here */\r
+    HUNSPELL_WARNING(stderr, "Hash Manager Error : %d\n",ec);\r
+    if (tableptr) {\r
+      free(tableptr);\r
+    }\r
+    tablesize = 0;\r
+  }\r
+}\r
+\r
+\r
+HashMgr::~HashMgr()\r
+{\r
+  if (tableptr) {\r
+    // now pass through hash table freeing up everything\r
+    // go through column by column of the table\r
+    for (int i=0; i < tablesize; i++) {\r
+      struct hentry * pt = &tableptr[i];\r
+      struct hentry * nt = NULL;\r
+      if (pt) {\r
+        if (pt->astr && !aliasf) free(pt->astr);\r
+        if (pt->word) free(pt->word);\r
+#ifdef HUNSPELL_EXPERIMENTAL\r
+        if (pt->description && !aliasm) free(pt->description);\r
+#endif\r
+        pt = pt->next;\r
+      }\r
+      while(pt) {\r
+        nt = pt->next;\r
+        if (pt->astr && !aliasf) free(pt->astr);\r
+        if (pt->word) free(pt->word);\r
+#ifdef HUNSPELL_EXPERIMENTAL\r
+        if (pt->description && !aliasm) free(pt->description);\r
+#endif\r
+        free(pt);\r
+        pt = nt;\r
+      }\r
+    }\r
+    free(tableptr);\r
+  }\r
+  tablesize = 0;\r
+\r
+  if (aliasf) {\r
+    for (int j = 0; j < (numaliasf); j++) free(aliasf[j]);\r
+    free(aliasf);\r
+    aliasf = NULL;\r
+    if (aliasflen) {\r
+      free(aliasflen);\r
+      aliasflen = NULL;\r
+    }\r
+  }\r
+  if (aliasm) {\r
+    for (int j = 0; j < (numaliasm); j++) free(aliasm[j]);\r
+    free(aliasm);\r
+    aliasm = NULL;\r
+  }  \r
+  \r
+  if (ignorechars) free(ignorechars);\r
+  if (ignorechars_utf16) free(ignorechars_utf16);\r
+}\r
+\r
+// lookup a root word in the hashtable\r
+\r
+struct hentry * HashMgr::lookup(const char *word) const\r
+{\r
+    struct hentry * dp;\r
+    if (tableptr) {\r
+       dp = &tableptr[hash(word)];\r
+       if (dp->word == NULL) return NULL;\r
+       for (  ;  dp != NULL;  dp = dp->next) {\r
+          if (strcmp(word,dp->word) == 0) return dp;\r
+       }\r
+    }\r
+    return NULL;\r
+}\r
+\r
+// add a word to the hash table (private)\r
+\r
+int HashMgr::add_word(const char * word, int wl, unsigned short * aff, int al, const char * desc)\r
+{\r
+    char * st = mystrdup(word);\r
+    if (wl && !st) return 1;\r
+    if (ignorechars != NULL) {\r
+      if (utf8) {\r
+        remove_ignored_chars_utf(st, ignorechars_utf16, ignorechars_utf16_len);\r
+      } else {\r
+        remove_ignored_chars(st, ignorechars);\r
+      }\r
+    }\r
+    if (complexprefixes) {\r
+        if (utf8) reverseword_utf(st); else reverseword(st);\r
+    }\r
+    int i = hash(st);\r
+    struct hentry * dp = &tableptr[i];\r
+    if (dp->word == NULL) {\r
+       dp->wlen = (short) wl;\r
+       dp->alen = (short) al;\r
+       dp->word = st;\r
+       dp->astr = aff;\r
+       dp->next = NULL;\r
+       dp->next_homonym = NULL;\r
+#ifdef HUNSPELL_EXPERIMENTAL\r
+       if (aliasm) {\r
+            dp->description = (desc) ? get_aliasm(atoi(desc)) : mystrdup(desc);\r
+       } else {\r
+            dp->description = mystrdup(desc);\r
+            if (desc && !dp->description) return 1;\r
+            if (dp->description && complexprefixes) {\r
+                if (utf8) reverseword_utf(dp->description); else reverseword(dp->description);\r
+            }\r
+       }\r
+#endif\r
+    } else {\r
+       struct hentry* hp = (struct hentry *) malloc (sizeof(struct hentry));\r
+       if (!hp) return 1;\r
+       hp->wlen = (short) wl;\r
+       hp->alen = (short) al;\r
+       hp->word = st;\r
+       hp->astr = aff;\r
+       hp->next = NULL;      \r
+       hp->next_homonym = NULL;\r
+#ifdef HUNSPELL_EXPERIMENTAL       \r
+       if (aliasm) {\r
+            hp->description = (desc) ? get_aliasm(atoi(desc)) : mystrdup(desc);\r
+       } else {\r
+            hp->description = mystrdup(desc);\r
+            if (desc && !hp->description) return 1;\r
+            if (dp->description && complexprefixes) {\r
+                if (utf8) reverseword_utf(hp->description); else reverseword(hp->description);\r
+            }\r
+       }\r
+#endif\r
+       while (dp->next != NULL) {\r
+         if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) dp->next_homonym = hp;\r
+         dp=dp->next;\r
+       }\r
+       if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) dp->next_homonym = hp;\r
+       dp->next = hp;\r
+    }\r
+    return 0;\r
+}     \r
+\r
+// add a custom dic. word to the hash table (public)\r
+int HashMgr::put_word(const char * word, int wl, char * aff)\r
+{\r
+    unsigned short * flags;\r
+    int al = 0;\r
+    if (aff) {\r
+        al = decode_flags(&flags, aff);\r
+        flag_qsort(flags, 0, al);\r
+    } else {\r
+        flags = NULL;\r
+    }\r
+    add_word(word, wl, flags, al, NULL);\r
+    return 0;\r
+}\r
+\r
+int HashMgr::put_word_pattern(const char * word, int wl, const char * pattern)\r
+{\r
+    unsigned short * flags;\r
+    struct hentry * dp = lookup(pattern);\r
+    if (!dp || !dp->astr) return 1;\r
+    flags = (unsigned short *) malloc (dp->alen * sizeof(short));\r
+    memcpy((void *) flags, (void *) dp->astr, dp->alen * sizeof(short));\r
+    add_word(word, wl, flags, dp->alen, NULL);\r
+    return 0;\r
+}\r
+\r
+// walk the hash table entry by entry - null at end\r
+struct hentry * HashMgr::walk_hashtable(int &col, struct hentry * hp) const\r
+{\r
+  //reset to start\r
+  if ((col < 0) || (hp == NULL)) {\r
+    col = -1;\r
+    hp = NULL;\r
+  }\r
+\r
+  if (hp && hp->next != NULL) {\r
+    hp = hp->next;\r
+  } else {\r
+    col++;\r
+    hp = (col < tablesize) ? &tableptr[col] : NULL;\r
+    // search for next non-blank column entry\r
+    while (hp && (hp->word == NULL)) {\r
+        col ++;\r
+        hp = (col < tablesize) ? &tableptr[col] : NULL;\r
+    }\r
+    if (col < tablesize) return hp;\r
+    hp = NULL;\r
+    col = -1;\r
+  }\r
+  return hp;\r
+}\r
+\r
+// load a munched word list and build a hash table on the fly\r
+int HashMgr::load_tables(const char * tpath)\r
+{\r
+  int wl, al;\r
+  char * ap;\r
+  char * dp;\r
+  unsigned short * flags;\r
+\r
+  // raw dictionary - munched file\r
+  FILE * rawdict = fopen(tpath, "r");\r
+  if (rawdict == NULL) return 1;\r
+\r
+  // first read the first line of file to get hash table size */\r
+  char ts[MAXDELEN];\r
+  if (! fgets(ts, MAXDELEN-1,rawdict)) return 2;\r
+  mychomp(ts);\r
+  \r
+  /* remove byte order mark */\r
+  if (strncmp(ts,"",3) == 0) {\r
+    memmove(ts, ts+3, strlen(ts+3)+1);\r
+    HUNSPELL_WARNING(stderr, "warning: dic file begins with byte order mark: possible incompatibility with old Hunspell versions\n");\r
+  }\r
+  \r
+  if ((*ts < '1') || (*ts > '9')) HUNSPELL_WARNING(stderr, "error - missing word count in dictionary file\n");\r
+  tablesize = atoi(ts);\r
+  if (!tablesize) return 4; \r
+  tablesize = tablesize + 5 + USERWORD;\r
+  if ((tablesize %2) == 0) tablesize++;\r
+\r
+  // allocate the hash table\r
+  tableptr = (struct hentry *) calloc(tablesize, sizeof(struct hentry));\r
+  if (! tableptr) return 3;\r
+  for (int i=0; i<tablesize; i++) tableptr[i].word = NULL;\r
+\r
+  // loop through all words on much list and add to hash\r
+  // table and create word and affix strings\r
+\r
+  while (fgets(ts,MAXDELEN-1,rawdict)) {\r
+    mychomp(ts);\r
+    // split each line into word and morphological description\r
+    dp = strchr(ts,'\t');\r
+\r
+    if (dp) {\r
+      *dp = '\0';\r
+      dp++;\r
+    } else {\r
+      dp = NULL;\r
+    }\r
+\r
+    // split each line into word and affix char strings\r
+    // "\/" signs slash in words (not affix separator)\r
+    // "/" at beginning of the line is word character (not affix separator)\r
+    ap = strchr(ts,'/');\r
+    while (ap) {\r
+        if (ap == ts) {\r
+            ap++;\r
+            continue;\r
+        } else if (*(ap - 1) != '\\') break;\r
+        // replace "\/" with "/"\r
+        for (char * sp = ap - 1; *sp; *sp = *(sp + 1), sp++);\r
+        ap = strchr(ap,'/');\r
+    }\r
+\r
+    if (ap) {\r
+      *ap = '\0';\r
+      if (aliasf) {\r
+        int index = atoi(ap + 1);\r
+        al = get_aliasf(index, &flags);\r
+        if (!al) {\r
+            HUNSPELL_WARNING(stderr, "error - bad flag vector alias: %s\n", ts);\r
+            *ap = '\0';\r
+        }\r
+      } else {\r
+        al = decode_flags(&flags, ap + 1);\r
+        flag_qsort(flags, 0, al);\r
+      }\r
+    } else {\r
+      al = 0;\r
+      ap = NULL;\r
+      flags = NULL;\r
+    }\r
+\r
+    wl = strlen(ts);\r
+\r
+    // add the word and its index\r
+    if (add_word(ts,wl,flags,al,dp)) return 5;\r
+\r
+  }\r
\r
+  fclose(rawdict);\r
+  return 0;\r
+}\r
+\r
+\r
+// the hash function is a simple load and rotate\r
+// algorithm borrowed\r
+\r
+int HashMgr::hash(const char * word) const\r
+{\r
+    long  hv = 0;\r
+    for (int i=0; i < 4  &&  *word != 0; i++)\r
+        hv = (hv << 8) | (*word++);\r
+    while (*word != 0) {\r
+      ROTATE(hv,ROTATE_LEN);\r
+      hv ^= (*word++);\r
+    }\r
+    return (unsigned long) hv % tablesize;\r
+}\r
+\r
+int HashMgr::decode_flags(unsigned short ** result, char * flags) {\r
+    int len;\r
+    switch (flag_mode) {\r
+      case FLAG_LONG: { // two-character flags (1x2yZz -> 1x 2y Zz)\r
+        len = strlen(flags);\r
+        if (len%2 == 1) HUNSPELL_WARNING(stderr, "error: length of FLAG_LONG flagvector is odd: %s\n", flags);\r
+        len = len/2;\r
+        *result = (unsigned short *) malloc(len * sizeof(short));\r
+        for (int i = 0; i < len; i++) {\r
+            (*result)[i] = (((unsigned short) flags[i * 2]) << 8) + (unsigned short) flags[i * 2 + 1]; \r
+        }\r
+        break;\r
+      }\r
+      case FLAG_NUM: { // decimal numbers separated by comma (4521,23,233 -> 4521 23 233)\r
+        len = 1;\r
+        char * src = flags; \r
+        unsigned short * dest;\r
+        char * p;\r
+        for (p = flags; *p; p++) {\r
+          if (*p == ',') len++;\r
+        }\r
+        *result = (unsigned short *) malloc(len * sizeof(short));\r
+        dest = *result;\r
+        for (p = flags; *p; p++) {\r
+          if (*p == ',') {\r
+            *dest = (unsigned short) atoi(src);\r
+            if (*dest == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n");\r
+            src = p + 1;\r
+            dest++;\r
+          }\r
+        }\r
+        *dest = (unsigned short) atoi(src);\r
+        if (*dest == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n");\r
+        break;\r
+      }    \r
+      case FLAG_UNI: { // UTF-8 characters\r
+        w_char w[MAXDELEN/2];\r
+        len = u8_u16(w, MAXDELEN/2, flags);\r
+        *result = (unsigned short *) malloc(len * sizeof(short));\r
+        memcpy(*result, w, len * sizeof(short));\r
+        break;\r
+      }\r
+      default: { // Ispell's one-character flags (erfg -> e r f g)\r
+        unsigned short * dest;\r
+        len = strlen(flags);\r
+        *result = (unsigned short *) malloc(len * sizeof(short));\r
+        dest = *result;\r
+        for (unsigned char * p = (unsigned char *) flags; *p; p++) {\r
+          *dest = (unsigned short) *p;\r
+          dest++;\r
+        }\r
+      }\r
+    }      \r
+    return len;\r
+}\r
+\r
+unsigned short HashMgr::decode_flag(const char * f) {\r
+    unsigned short s = 0;\r
+    switch (flag_mode) {\r
+      case FLAG_LONG:\r
+        s = ((unsigned short) f[0] << 8) + (unsigned short) f[1];\r
+        break;\r
+      case FLAG_NUM:\r
+        s = (unsigned short) atoi(f);\r
+        break;\r
+      case FLAG_UNI:\r
+        u8_u16((w_char *) &s, 1, f);\r
+        break;\r
+      default:\r
+        s = (unsigned short) *((unsigned char *)f);\r
+    }\r
+    if (!s) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n");\r
+    return s;\r
+}\r
+\r
+char * HashMgr::encode_flag(unsigned short f) {\r
+    unsigned char ch[10];\r
+    if (f==0) return mystrdup("(NULL)");\r
+    if (flag_mode == FLAG_LONG) {\r
+        ch[0] = (unsigned char) (f >> 8);\r
+        ch[1] = (unsigned char) (f - ((f >> 8) << 8));\r
+        ch[2] = '\0';\r
+    } else if (flag_mode == FLAG_NUM) {\r
+        sprintf((char *) ch, "%d", f);\r
+    } else if (flag_mode == FLAG_UNI) {\r
+        u16_u8((char *) &ch, 10, (w_char *) &f, 1);\r
+    } else {\r
+        ch[0] = (unsigned char) (f);\r
+        ch[1] = '\0';\r
+    }\r
+    return mystrdup((char *) ch);\r
+}\r
+\r
+// read in aff file and set flag mode\r
+int  HashMgr::load_config(const char * affpath)\r
+{\r
+  int firstline = 1;\r
+  \r
+  // io buffers\r
+  char line[MAXDELEN+1];\r
\r
+  // open the affix file\r
+  FILE * afflst;\r
+  afflst = fopen(affpath,"r");\r
+  if (!afflst) {\r
+    HUNSPELL_WARNING(stderr, "Error - could not open affix description file %s\n",affpath);\r
+    return 1;\r
+  }\r
+\r
+    // read in each line ignoring any that do not\r
+    // start with a known line type indicator\r
+\r
+    while (fgets(line,MAXDELEN,afflst)) {\r
+        mychomp(line);\r
+\r
+       /* remove byte order mark */\r
+       if (firstline) {\r
+         firstline = 0;\r
+                if (strncmp(line,"",3) == 0) memmove(line, line+3, strlen(line+3)+1);\r
+       }\r
+\r
+        /* parse in the try string */\r
+        if ((strncmp(line,"FLAG",4) == 0) && isspace(line[4])) {\r
+            if (flag_mode != FLAG_CHAR) {\r
+                HUNSPELL_WARNING(stderr, "error: duplicate FLAG parameter\n");\r
+            }\r
+            if (strstr(line, "long")) flag_mode = FLAG_LONG;\r
+            if (strstr(line, "num")) flag_mode = FLAG_NUM;\r
+            if (strstr(line, "UTF-8")) flag_mode = FLAG_UNI;\r
+            if (flag_mode == FLAG_CHAR) {\r
+                HUNSPELL_WARNING(stderr, "error: FLAG need `num', `long' or `UTF-8' parameter: %s\n", line);\r
+            }\r
+        }\r
+        if ((strncmp(line,"SET",3) == 0) && isspace(line[3]) && strstr(line, "UTF-8")) utf8 = 1;\r
+\r
+       /* parse in the ignored characters (for example, Arabic optional diacritics characters */\r
+       if (strncmp(line,"IGNORE",6) == 0) {\r
+          if (parse_array(line, &ignorechars, &ignorechars_utf16, &ignorechars_utf16_len, "IGNORE", utf8)) {\r
+             fclose(afflst);\r
+             return 1;\r
+          }\r
+       }\r
+\r
+       if ((strncmp(line,"AF",2) == 0) && isspace(line[2])) {\r
+          if (parse_aliasf(line, afflst)) {\r
+             fclose(afflst);\r
+             return 1;\r
+          }\r
+       }\r
+\r
+#ifdef HUNSPELL_EXPERIMENTAL\r
+       if ((strncmp(line,"AM",2) == 0) && isspace(line[2])) {\r
+          if (parse_aliasm(line, afflst)) {\r
+             fclose(afflst);\r
+             return 1;\r
+          }\r
+       }\r
+#endif\r
+        if (strncmp(line,"COMPLEXPREFIXES",15) == 0) complexprefixes = 1;\r
+        if (((strncmp(line,"SFX",3) == 0) || (strncmp(line,"PFX",3) == 0)) && isspace(line[3])) break;\r
+    }\r
+    fclose(afflst);\r
+    return 0;\r
+}\r
+\r
+/* parse in the ALIAS table */\r
+int  HashMgr::parse_aliasf(char * line, FILE * af)\r
+{\r
+   if (numaliasf != 0) {\r
+      HUNSPELL_WARNING(stderr, "error: duplicate AF (alias for flag vector) tables used\n");\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
+                       numaliasf = atoi(piece);\r
+                       if (numaliasf < 1) {\r
+                          numaliasf = 0;\r
+                          aliasf = NULL;\r
+                          aliasflen = NULL;\r
+                          HUNSPELL_WARNING(stderr, "incorrect number of entries in AF table\n");\r
+                          free(piece);\r
+                          return 1;\r
+                       }\r
+                       aliasf = (unsigned short **) malloc(numaliasf * sizeof(unsigned short *));\r
+                       aliasflen = (unsigned short *) malloc(numaliasf * sizeof(short));\r
+                       if (!aliasf || !aliasflen) {\r
+                          numaliasf = 0;\r
+                          if (aliasf) free(aliasf);\r
+                          if (aliasflen) free(aliasflen);\r
+                          aliasf = NULL;\r
+                          aliasflen = NULL;\r
+                          return 1;\r
+                       }\r
+                       np++;\r
+                       break;\r
+                     }\r
+             default: break;\r
+          }\r
+          i++;\r
+       }\r
+       free(piece);\r
+       piece = mystrsep(&tp, 0);\r
+   }\r
+   if (np != 2) {\r
+      numaliasf = 0;\r
+      free(aliasf);\r
+      free(aliasflen);\r
+      aliasf = NULL;\r
+      aliasflen = NULL;\r
+      HUNSPELL_WARNING(stderr, "error: missing AF table information\n");\r
+      return 1;\r
+   } \r
\r
+   /* now parse the numaliasf lines to read in the remainder of the table */\r
+   char * nl = line;\r
+   for (int j=0; j < numaliasf; j++) {\r
+        if (!fgets(nl,MAXDELEN,af)) return 1;\r
+        mychomp(nl);\r
+        tp = nl;\r
+        i = 0;\r
+        aliasf[j] = NULL;\r
+        aliasflen[j] = 0;\r
+        piece = mystrsep(&tp, 0);\r
+        while (piece) {\r
+           if (*piece != '\0') {\r
+               switch(i) {\r
+                  case 0: {\r
+                             if (strncmp(piece,"AF",2) != 0) {\r
+                                 numaliasf = 0;\r
+                                 free(aliasf);\r
+                                 free(aliasflen);\r
+                                 aliasf = NULL;\r
+                                 aliasflen = NULL;\r
+                                 HUNSPELL_WARNING(stderr, "error: AF table is corrupt\n");\r
+                                 free(piece);\r
+                                 return 1;\r
+                             }\r
+                             break;\r
+                          }\r
+                  case 1: {\r
+                            aliasflen[j] = (unsigned short) decode_flags(&(aliasf[j]), piece);\r
+                            flag_qsort(aliasf[j], 0, aliasflen[j]);\r
+                            break; \r
+                          }\r
+                  default: break;\r
+               }\r
+               i++;\r
+           }\r
+           free(piece);\r
+           piece = mystrsep(&tp, 0);\r
+        }\r
+        if (!aliasf[j]) {\r
+             free(aliasf);\r
+             free(aliasflen);\r
+             aliasf = NULL;\r
+             aliasflen = NULL;\r
+             numaliasf = 0;\r
+             HUNSPELL_WARNING(stderr, "error: AF table is corrupt\n");\r
+             return 1;\r
+        }\r
+   }\r
+   return 0;\r
+}\r
+\r
+int HashMgr::is_aliasf() {\r
+    return (aliasf != NULL);\r
+}\r
+\r
+int HashMgr::get_aliasf(int index, unsigned short ** fvec) {\r
+    if ((index > 0) && (index <= numaliasf)) {\r
+        *fvec = aliasf[index - 1];\r
+        return aliasflen[index - 1];\r
+    }\r
+    HUNSPELL_WARNING(stderr, "error: bad flag alias index: %d\n", index);\r
+    *fvec = NULL;\r
+    return 0;\r
+}\r
+\r
+#ifdef HUNSPELL_EXPERIMENTAL\r
+/* parse morph alias definitions */\r
+int  HashMgr::parse_aliasm(char * line, FILE * af)\r
+{\r
+   if (numaliasm != 0) {\r
+      HUNSPELL_WARNING(stderr, "error: duplicate AM (aliases for morphological descriptions) tables used\n");\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
+                       numaliasm = atoi(piece);\r
+                       if (numaliasm < 1) {\r
+                          HUNSPELL_WARNING(stderr, "incorrect number of entries in AM table\n");\r
+                          free(piece);\r
+                          return 1;\r
+                       }\r
+                       aliasm = (char **) malloc(numaliasm * sizeof(char *));\r
+                       if (!aliasm) {\r
+                          numaliasm = 0;\r
+                          return 1;\r
+                       }\r
+                       np++;\r
+                       break;\r
+                     }\r
+             default: break;\r
+          }\r
+          i++;\r
+       }\r
+       free(piece);\r
+       piece = mystrsep(&tp, 0);\r
+   }\r
+   if (np != 2) {\r
+      numaliasm = 0;\r
+      free(aliasm);\r
+      aliasm = NULL;\r
+      HUNSPELL_WARNING(stderr, "error: missing AM alias information\n");\r
+      return 1;\r
+   } \r
+\r
+   /* now parse the numaliasm lines to read in the remainder of the table */\r
+   char * nl = line;\r
+   for (int j=0; j < numaliasm; j++) {\r
+        if (!fgets(nl,MAXDELEN,af)) return 1;\r
+        mychomp(nl);\r
+        tp = nl;\r
+        i = 0;\r
+        aliasm[j] = NULL;\r
+        piece = mystrsep(&tp, 0);\r
+        while (piece) {\r
+           if (*piece != '\0') {\r
+               switch(i) {\r
+                  case 0: {\r
+                             if (strncmp(piece,"AM",2) != 0) {\r
+                                 HUNSPELL_WARNING(stderr, "error: AM table is corrupt\n");\r
+                                 free(piece);\r
+                                 numaliasm = 0;\r
+                                 free(aliasm);\r
+                                 aliasm = NULL;\r
+                                 return 1;\r
+                             }\r
+                             break;\r
+                          }\r
+                  case 1: {\r
+                            if (complexprefixes) {\r
+                                if (utf8) reverseword_utf(piece);\r
+                                    else reverseword(piece);\r
+                            }\r
+                            aliasm[j] = mystrdup(piece);\r
+                            break; }\r
+                  default: break;\r
+               }\r
+               i++;\r
+           }\r
+           free(piece);\r
+           piece = mystrsep(&tp, 0);\r
+        }\r
+        if (!aliasm[j]) {\r
+             numaliasm = 0;\r
+             free(aliasm);\r
+             aliasm = NULL;\r
+             HUNSPELL_WARNING(stderr, "error: map table is corrupt\n");\r
+             return 1;\r
+        }\r
+   }\r
+   return 0;\r
+}\r
+\r
+int HashMgr::is_aliasm() {\r
+    return (aliasm != NULL);\r
+}\r
+\r
+char * HashMgr::get_aliasm(int index) {\r
+    if ((index > 0) && (index <= numaliasm)) return aliasm[index - 1];\r
+    HUNSPELL_WARNING(stderr, "error: bad morph. alias index: %d\n", index);\r
+    return NULL;\r
+}\r
+#endif\r