--- /dev/null
+#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