OSDN Git Service

PushDlg: Fix: Wrong remote selected after selection via ref-browser.
[tortoisegit/TortoiseGitJp.git] / ext / hunspell / hashmgr.cxx
1 #include "license.hunspell"\r
2 #include "license.myspell"\r
3 \r
4 #ifndef MOZILLA_CLIENT\r
5 #include <cstdlib>\r
6 #include <cstring>\r
7 #include <cstdio>\r
8 #include <cctype>\r
9 #else\r
10 #include <stdlib.h> \r
11 #include <string.h>\r
12 #include <stdio.h> \r
13 #include <ctype.h>\r
14 #endif\r
15 \r
16 #include "hashmgr.hxx"\r
17 #include "csutil.hxx"\r
18 #include "atypes.hxx"\r
19 \r
20 #ifdef MOZILLA_CLIENT\r
21 #ifdef __SUNPRO_CC // for SunONE Studio compiler\r
22 using namespace std;\r
23 #endif\r
24 #else\r
25 #ifndef W32\r
26 using namespace std;\r
27 #endif\r
28 #endif\r
29 \r
30 // build a hash table from a munched word list\r
31 \r
32 HashMgr::HashMgr(const char * tpath, const char * apath)\r
33 {\r
34   tablesize = 0;\r
35   tableptr = NULL;\r
36   flag_mode = FLAG_CHAR;\r
37   complexprefixes = 0;\r
38   utf8 = 0;\r
39   ignorechars = NULL;\r
40   ignorechars_utf16 = NULL;\r
41   ignorechars_utf16_len = 0;\r
42   numaliasf = 0;\r
43   aliasf = NULL;\r
44   numaliasm = 0;\r
45   aliasm = NULL;\r
46   load_config(apath);  \r
47   int ec = load_tables(tpath);\r
48   if (ec) {\r
49     /* error condition - what should we do here */\r
50     HUNSPELL_WARNING(stderr, "Hash Manager Error : %d\n",ec);\r
51     if (tableptr) {\r
52       free(tableptr);\r
53     }\r
54     tablesize = 0;\r
55   }\r
56 }\r
57 \r
58 \r
59 HashMgr::~HashMgr()\r
60 {\r
61   if (tableptr) {\r
62     // now pass through hash table freeing up everything\r
63     // go through column by column of the table\r
64     for (int i=0; i < tablesize; i++) {\r
65       struct hentry * pt = &tableptr[i];\r
66       struct hentry * nt = NULL;\r
67       if (pt) {\r
68         if (pt->astr && !aliasf) free(pt->astr);\r
69         if (pt->word) free(pt->word);\r
70 #ifdef HUNSPELL_EXPERIMENTAL\r
71         if (pt->description && !aliasm) free(pt->description);\r
72 #endif\r
73         pt = pt->next;\r
74       }\r
75       while(pt) {\r
76         nt = pt->next;\r
77         if (pt->astr && !aliasf) free(pt->astr);\r
78         if (pt->word) free(pt->word);\r
79 #ifdef HUNSPELL_EXPERIMENTAL\r
80         if (pt->description && !aliasm) free(pt->description);\r
81 #endif\r
82         free(pt);\r
83         pt = nt;\r
84       }\r
85     }\r
86     free(tableptr);\r
87   }\r
88   tablesize = 0;\r
89 \r
90   if (aliasf) {\r
91     for (int j = 0; j < (numaliasf); j++) free(aliasf[j]);\r
92     free(aliasf);\r
93     aliasf = NULL;\r
94     if (aliasflen) {\r
95       free(aliasflen);\r
96       aliasflen = NULL;\r
97     }\r
98   }\r
99   if (aliasm) {\r
100     for (int j = 0; j < (numaliasm); j++) free(aliasm[j]);\r
101     free(aliasm);\r
102     aliasm = NULL;\r
103   }  \r
104   \r
105   if (ignorechars) free(ignorechars);\r
106   if (ignorechars_utf16) free(ignorechars_utf16);\r
107 }\r
108 \r
109 // lookup a root word in the hashtable\r
110 \r
111 struct hentry * HashMgr::lookup(const char *word) const\r
112 {\r
113     struct hentry * dp;\r
114     if (tableptr) {\r
115        dp = &tableptr[hash(word)];\r
116        if (dp->word == NULL) return NULL;\r
117        for (  ;  dp != NULL;  dp = dp->next) {\r
118           if (strcmp(word,dp->word) == 0) return dp;\r
119        }\r
120     }\r
121     return NULL;\r
122 }\r
123 \r
124 // add a word to the hash table (private)\r
125 \r
126 int HashMgr::add_word(const char * word, int wl, unsigned short * aff, int al, const char * desc)\r
127 {\r
128     char * st = mystrdup(word);\r
129     if (wl && !st) return 1;\r
130     if (ignorechars != NULL) {\r
131       if (utf8) {\r
132         remove_ignored_chars_utf(st, ignorechars_utf16, ignorechars_utf16_len);\r
133       } else {\r
134         remove_ignored_chars(st, ignorechars);\r
135       }\r
136     }\r
137     if (complexprefixes) {\r
138         if (utf8) reverseword_utf(st); else reverseword(st);\r
139     }\r
140     int i = hash(st);\r
141     struct hentry * dp = &tableptr[i];\r
142     if (dp->word == NULL) {\r
143        dp->wlen = (short) wl;\r
144        dp->alen = (short) al;\r
145        dp->word = st;\r
146        dp->astr = aff;\r
147        dp->next = NULL;\r
148        dp->next_homonym = NULL;\r
149 #ifdef HUNSPELL_EXPERIMENTAL\r
150        if (aliasm) {\r
151             dp->description = (desc) ? get_aliasm(atoi(desc)) : mystrdup(desc);\r
152        } else {\r
153             dp->description = mystrdup(desc);\r
154             if (desc && !dp->description) return 1;\r
155             if (dp->description && complexprefixes) {\r
156                 if (utf8) reverseword_utf(dp->description); else reverseword(dp->description);\r
157             }\r
158        }\r
159 #endif\r
160     } else {\r
161        struct hentry* hp = (struct hentry *) malloc (sizeof(struct hentry));\r
162        if (!hp) return 1;\r
163        hp->wlen = (short) wl;\r
164        hp->alen = (short) al;\r
165        hp->word = st;\r
166        hp->astr = aff;\r
167        hp->next = NULL;      \r
168        hp->next_homonym = NULL;\r
169 #ifdef HUNSPELL_EXPERIMENTAL       \r
170        if (aliasm) {\r
171             hp->description = (desc) ? get_aliasm(atoi(desc)) : mystrdup(desc);\r
172        } else {\r
173             hp->description = mystrdup(desc);\r
174             if (desc && !hp->description) return 1;\r
175             if (dp->description && complexprefixes) {\r
176                 if (utf8) reverseword_utf(hp->description); else reverseword(hp->description);\r
177             }\r
178        }\r
179 #endif\r
180        while (dp->next != NULL) {\r
181          if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) dp->next_homonym = hp;\r
182          dp=dp->next;\r
183        }\r
184        if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) dp->next_homonym = hp;\r
185        dp->next = hp;\r
186     }\r
187     return 0;\r
188 }     \r
189 \r
190 // add a custom dic. word to the hash table (public)\r
191 int HashMgr::put_word(const char * word, int wl, char * aff)\r
192 {\r
193     unsigned short * flags;\r
194     int al = 0;\r
195     if (aff) {\r
196         al = decode_flags(&flags, aff);\r
197         flag_qsort(flags, 0, al);\r
198     } else {\r
199         flags = NULL;\r
200     }\r
201     add_word(word, wl, flags, al, NULL);\r
202     return 0;\r
203 }\r
204 \r
205 int HashMgr::put_word_pattern(const char * word, int wl, const char * pattern)\r
206 {\r
207     unsigned short * flags;\r
208     struct hentry * dp = lookup(pattern);\r
209     if (!dp || !dp->astr) return 1;\r
210     flags = (unsigned short *) malloc (dp->alen * sizeof(short));\r
211     memcpy((void *) flags, (void *) dp->astr, dp->alen * sizeof(short));\r
212     add_word(word, wl, flags, dp->alen, NULL);\r
213     return 0;\r
214 }\r
215 \r
216 // walk the hash table entry by entry - null at end\r
217 struct hentry * HashMgr::walk_hashtable(int &col, struct hentry * hp) const\r
218 {\r
219   //reset to start\r
220   if ((col < 0) || (hp == NULL)) {\r
221     col = -1;\r
222     hp = NULL;\r
223   }\r
224 \r
225   if (hp && hp->next != NULL) {\r
226     hp = hp->next;\r
227   } else {\r
228     col++;\r
229     hp = (col < tablesize) ? &tableptr[col] : NULL;\r
230     // search for next non-blank column entry\r
231     while (hp && (hp->word == NULL)) {\r
232         col ++;\r
233         hp = (col < tablesize) ? &tableptr[col] : NULL;\r
234     }\r
235     if (col < tablesize) return hp;\r
236     hp = NULL;\r
237     col = -1;\r
238   }\r
239   return hp;\r
240 }\r
241 \r
242 // load a munched word list and build a hash table on the fly\r
243 int HashMgr::load_tables(const char * tpath)\r
244 {\r
245   int wl, al;\r
246   char * ap;\r
247   char * dp;\r
248   unsigned short * flags;\r
249 \r
250   // raw dictionary - munched file\r
251   FILE * rawdict = fopen(tpath, "r");\r
252   if (rawdict == NULL) return 1;\r
253 \r
254   // first read the first line of file to get hash table size */\r
255   char ts[MAXDELEN];\r
256   if (! fgets(ts, MAXDELEN-1,rawdict)) return 2;\r
257   mychomp(ts);\r
258   \r
259   /* remove byte order mark */\r
260   if (strncmp(ts,"",3) == 0) {\r
261     memmove(ts, ts+3, strlen(ts+3)+1);\r
262     HUNSPELL_WARNING(stderr, "warning: dic file begins with byte order mark: possible incompatibility with old Hunspell versions\n");\r
263   }\r
264   \r
265   if ((*ts < '1') || (*ts > '9')) HUNSPELL_WARNING(stderr, "error - missing word count in dictionary file\n");\r
266   tablesize = atoi(ts);\r
267   if (!tablesize) return 4; \r
268   tablesize = tablesize + 5 + USERWORD;\r
269   if ((tablesize %2) == 0) tablesize++;\r
270 \r
271   // allocate the hash table\r
272   tableptr = (struct hentry *) calloc(tablesize, sizeof(struct hentry));\r
273   if (! tableptr) return 3;\r
274   for (int i=0; i<tablesize; i++) tableptr[i].word = NULL;\r
275 \r
276   // loop through all words on much list and add to hash\r
277   // table and create word and affix strings\r
278 \r
279   while (fgets(ts,MAXDELEN-1,rawdict)) {\r
280     mychomp(ts);\r
281     // split each line into word and morphological description\r
282     dp = strchr(ts,'\t');\r
283 \r
284     if (dp) {\r
285       *dp = '\0';\r
286       dp++;\r
287     } else {\r
288       dp = NULL;\r
289     }\r
290 \r
291     // split each line into word and affix char strings\r
292     // "\/" signs slash in words (not affix separator)\r
293     // "/" at beginning of the line is word character (not affix separator)\r
294     ap = strchr(ts,'/');\r
295     while (ap) {\r
296         if (ap == ts) {\r
297             ap++;\r
298             continue;\r
299         } else if (*(ap - 1) != '\\') break;\r
300         // replace "\/" with "/"\r
301         for (char * sp = ap - 1; *sp; *sp = *(sp + 1), sp++);\r
302         ap = strchr(ap,'/');\r
303     }\r
304 \r
305     if (ap) {\r
306       *ap = '\0';\r
307       if (aliasf) {\r
308         int index = atoi(ap + 1);\r
309         al = get_aliasf(index, &flags);\r
310         if (!al) {\r
311             HUNSPELL_WARNING(stderr, "error - bad flag vector alias: %s\n", ts);\r
312             *ap = '\0';\r
313         }\r
314       } else {\r
315         al = decode_flags(&flags, ap + 1);\r
316         flag_qsort(flags, 0, al);\r
317       }\r
318     } else {\r
319       al = 0;\r
320       ap = NULL;\r
321       flags = NULL;\r
322     }\r
323 \r
324     wl = strlen(ts);\r
325 \r
326     // add the word and its index\r
327     if (add_word(ts,wl,flags,al,dp)) return 5;\r
328 \r
329   }\r
330  \r
331   fclose(rawdict);\r
332   return 0;\r
333 }\r
334 \r
335 \r
336 // the hash function is a simple load and rotate\r
337 // algorithm borrowed\r
338 \r
339 int HashMgr::hash(const char * word) const\r
340 {\r
341     long  hv = 0;\r
342     for (int i=0; i < 4  &&  *word != 0; i++)\r
343         hv = (hv << 8) | (*word++);\r
344     while (*word != 0) {\r
345       ROTATE(hv,ROTATE_LEN);\r
346       hv ^= (*word++);\r
347     }\r
348     return (unsigned long) hv % tablesize;\r
349 }\r
350 \r
351 int HashMgr::decode_flags(unsigned short ** result, char * flags) {\r
352     int len;\r
353     switch (flag_mode) {\r
354       case FLAG_LONG: { // two-character flags (1x2yZz -> 1x 2y Zz)\r
355         len = strlen(flags);\r
356         if (len%2 == 1) HUNSPELL_WARNING(stderr, "error: length of FLAG_LONG flagvector is odd: %s\n", flags);\r
357         len = len/2;\r
358         *result = (unsigned short *) malloc(len * sizeof(short));\r
359         for (int i = 0; i < len; i++) {\r
360             (*result)[i] = (((unsigned short) flags[i * 2]) << 8) + (unsigned short) flags[i * 2 + 1]; \r
361         }\r
362         break;\r
363       }\r
364       case FLAG_NUM: { // decimal numbers separated by comma (4521,23,233 -> 4521 23 233)\r
365         len = 1;\r
366         char * src = flags; \r
367         unsigned short * dest;\r
368         char * p;\r
369         for (p = flags; *p; p++) {\r
370           if (*p == ',') len++;\r
371         }\r
372         *result = (unsigned short *) malloc(len * sizeof(short));\r
373         dest = *result;\r
374         for (p = flags; *p; p++) {\r
375           if (*p == ',') {\r
376             *dest = (unsigned short) atoi(src);\r
377             if (*dest == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n");\r
378             src = p + 1;\r
379             dest++;\r
380           }\r
381         }\r
382         *dest = (unsigned short) atoi(src);\r
383         if (*dest == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n");\r
384         break;\r
385       }    \r
386       case FLAG_UNI: { // UTF-8 characters\r
387         w_char w[MAXDELEN/2];\r
388         len = u8_u16(w, MAXDELEN/2, flags);\r
389         *result = (unsigned short *) malloc(len * sizeof(short));\r
390         memcpy(*result, w, len * sizeof(short));\r
391         break;\r
392       }\r
393       default: { // Ispell's one-character flags (erfg -> e r f g)\r
394         unsigned short * dest;\r
395         len = strlen(flags);\r
396         *result = (unsigned short *) malloc(len * sizeof(short));\r
397         dest = *result;\r
398         for (unsigned char * p = (unsigned char *) flags; *p; p++) {\r
399           *dest = (unsigned short) *p;\r
400           dest++;\r
401         }\r
402       }\r
403     }      \r
404     return len;\r
405 }\r
406 \r
407 unsigned short HashMgr::decode_flag(const char * f) {\r
408     unsigned short s = 0;\r
409     switch (flag_mode) {\r
410       case FLAG_LONG:\r
411         s = ((unsigned short) f[0] << 8) + (unsigned short) f[1];\r
412         break;\r
413       case FLAG_NUM:\r
414         s = (unsigned short) atoi(f);\r
415         break;\r
416       case FLAG_UNI:\r
417         u8_u16((w_char *) &s, 1, f);\r
418         break;\r
419       default:\r
420         s = (unsigned short) *((unsigned char *)f);\r
421     }\r
422     if (!s) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n");\r
423     return s;\r
424 }\r
425 \r
426 char * HashMgr::encode_flag(unsigned short f) {\r
427     unsigned char ch[10];\r
428     if (f==0) return mystrdup("(NULL)");\r
429     if (flag_mode == FLAG_LONG) {\r
430         ch[0] = (unsigned char) (f >> 8);\r
431         ch[1] = (unsigned char) (f - ((f >> 8) << 8));\r
432         ch[2] = '\0';\r
433     } else if (flag_mode == FLAG_NUM) {\r
434         sprintf((char *) ch, "%d", f);\r
435     } else if (flag_mode == FLAG_UNI) {\r
436         u16_u8((char *) &ch, 10, (w_char *) &f, 1);\r
437     } else {\r
438         ch[0] = (unsigned char) (f);\r
439         ch[1] = '\0';\r
440     }\r
441     return mystrdup((char *) ch);\r
442 }\r
443 \r
444 // read in aff file and set flag mode\r
445 int  HashMgr::load_config(const char * affpath)\r
446 {\r
447   int firstline = 1;\r
448   \r
449   // io buffers\r
450   char line[MAXDELEN+1];\r
451  \r
452   // open the affix file\r
453   FILE * afflst;\r
454   afflst = fopen(affpath,"r");\r
455   if (!afflst) {\r
456     HUNSPELL_WARNING(stderr, "Error - could not open affix description file %s\n",affpath);\r
457     return 1;\r
458   }\r
459 \r
460     // read in each line ignoring any that do not\r
461     // start with a known line type indicator\r
462 \r
463     while (fgets(line,MAXDELEN,afflst)) {\r
464         mychomp(line);\r
465 \r
466        /* remove byte order mark */\r
467        if (firstline) {\r
468          firstline = 0;\r
469                  if (strncmp(line,"",3) == 0) memmove(line, line+3, strlen(line+3)+1);\r
470        }\r
471 \r
472         /* parse in the try string */\r
473         if ((strncmp(line,"FLAG",4) == 0) && isspace(line[4])) {\r
474             if (flag_mode != FLAG_CHAR) {\r
475                 HUNSPELL_WARNING(stderr, "error: duplicate FLAG parameter\n");\r
476             }\r
477             if (strstr(line, "long")) flag_mode = FLAG_LONG;\r
478             if (strstr(line, "num")) flag_mode = FLAG_NUM;\r
479             if (strstr(line, "UTF-8")) flag_mode = FLAG_UNI;\r
480             if (flag_mode == FLAG_CHAR) {\r
481                 HUNSPELL_WARNING(stderr, "error: FLAG need `num', `long' or `UTF-8' parameter: %s\n", line);\r
482             }\r
483         }\r
484         if ((strncmp(line,"SET",3) == 0) && isspace(line[3]) && strstr(line, "UTF-8")) utf8 = 1;\r
485 \r
486        /* parse in the ignored characters (for example, Arabic optional diacritics characters */\r
487        if (strncmp(line,"IGNORE",6) == 0) {\r
488           if (parse_array(line, &ignorechars, &ignorechars_utf16, &ignorechars_utf16_len, "IGNORE", utf8)) {\r
489              fclose(afflst);\r
490              return 1;\r
491           }\r
492        }\r
493 \r
494        if ((strncmp(line,"AF",2) == 0) && isspace(line[2])) {\r
495           if (parse_aliasf(line, afflst)) {\r
496              fclose(afflst);\r
497              return 1;\r
498           }\r
499        }\r
500 \r
501 #ifdef HUNSPELL_EXPERIMENTAL\r
502        if ((strncmp(line,"AM",2) == 0) && isspace(line[2])) {\r
503           if (parse_aliasm(line, afflst)) {\r
504              fclose(afflst);\r
505              return 1;\r
506           }\r
507        }\r
508 #endif\r
509         if (strncmp(line,"COMPLEXPREFIXES",15) == 0) complexprefixes = 1;\r
510         if (((strncmp(line,"SFX",3) == 0) || (strncmp(line,"PFX",3) == 0)) && isspace(line[3])) break;\r
511     }\r
512     fclose(afflst);\r
513     return 0;\r
514 }\r
515 \r
516 /* parse in the ALIAS table */\r
517 int  HashMgr::parse_aliasf(char * line, FILE * af)\r
518 {\r
519    if (numaliasf != 0) {\r
520       HUNSPELL_WARNING(stderr, "error: duplicate AF (alias for flag vector) tables used\n");\r
521       return 1;\r
522    }\r
523    char * tp = line;\r
524    char * piece;\r
525    int i = 0;\r
526    int np = 0;\r
527    piece = mystrsep(&tp, 0);\r
528    while (piece) {\r
529        if (*piece != '\0') {\r
530           switch(i) {\r
531              case 0: { np++; break; }\r
532              case 1: { \r
533                        numaliasf = atoi(piece);\r
534                        if (numaliasf < 1) {\r
535                           numaliasf = 0;\r
536                           aliasf = NULL;\r
537                           aliasflen = NULL;\r
538                           HUNSPELL_WARNING(stderr, "incorrect number of entries in AF table\n");\r
539                           free(piece);\r
540                           return 1;\r
541                        }\r
542                        aliasf = (unsigned short **) malloc(numaliasf * sizeof(unsigned short *));\r
543                        aliasflen = (unsigned short *) malloc(numaliasf * sizeof(short));\r
544                        if (!aliasf || !aliasflen) {\r
545                           numaliasf = 0;\r
546                           if (aliasf) free(aliasf);\r
547                           if (aliasflen) free(aliasflen);\r
548                           aliasf = NULL;\r
549                           aliasflen = NULL;\r
550                           return 1;\r
551                        }\r
552                        np++;\r
553                        break;\r
554                      }\r
555              default: break;\r
556           }\r
557           i++;\r
558        }\r
559        free(piece);\r
560        piece = mystrsep(&tp, 0);\r
561    }\r
562    if (np != 2) {\r
563       numaliasf = 0;\r
564       free(aliasf);\r
565       free(aliasflen);\r
566       aliasf = NULL;\r
567       aliasflen = NULL;\r
568       HUNSPELL_WARNING(stderr, "error: missing AF table information\n");\r
569       return 1;\r
570    } \r
571  \r
572    /* now parse the numaliasf lines to read in the remainder of the table */\r
573    char * nl = line;\r
574    for (int j=0; j < numaliasf; j++) {\r
575         if (!fgets(nl,MAXDELEN,af)) return 1;\r
576         mychomp(nl);\r
577         tp = nl;\r
578         i = 0;\r
579         aliasf[j] = NULL;\r
580         aliasflen[j] = 0;\r
581         piece = mystrsep(&tp, 0);\r
582         while (piece) {\r
583            if (*piece != '\0') {\r
584                switch(i) {\r
585                   case 0: {\r
586                              if (strncmp(piece,"AF",2) != 0) {\r
587                                  numaliasf = 0;\r
588                                  free(aliasf);\r
589                                  free(aliasflen);\r
590                                  aliasf = NULL;\r
591                                  aliasflen = NULL;\r
592                                  HUNSPELL_WARNING(stderr, "error: AF table is corrupt\n");\r
593                                  free(piece);\r
594                                  return 1;\r
595                              }\r
596                              break;\r
597                           }\r
598                   case 1: {\r
599                             aliasflen[j] = (unsigned short) decode_flags(&(aliasf[j]), piece);\r
600                             flag_qsort(aliasf[j], 0, aliasflen[j]);\r
601                             break; \r
602                           }\r
603                   default: break;\r
604                }\r
605                i++;\r
606            }\r
607            free(piece);\r
608            piece = mystrsep(&tp, 0);\r
609         }\r
610         if (!aliasf[j]) {\r
611              free(aliasf);\r
612              free(aliasflen);\r
613              aliasf = NULL;\r
614              aliasflen = NULL;\r
615              numaliasf = 0;\r
616              HUNSPELL_WARNING(stderr, "error: AF table is corrupt\n");\r
617              return 1;\r
618         }\r
619    }\r
620    return 0;\r
621 }\r
622 \r
623 int HashMgr::is_aliasf() {\r
624     return (aliasf != NULL);\r
625 }\r
626 \r
627 int HashMgr::get_aliasf(int index, unsigned short ** fvec) {\r
628     if ((index > 0) && (index <= numaliasf)) {\r
629         *fvec = aliasf[index - 1];\r
630         return aliasflen[index - 1];\r
631     }\r
632     HUNSPELL_WARNING(stderr, "error: bad flag alias index: %d\n", index);\r
633     *fvec = NULL;\r
634     return 0;\r
635 }\r
636 \r
637 #ifdef HUNSPELL_EXPERIMENTAL\r
638 /* parse morph alias definitions */\r
639 int  HashMgr::parse_aliasm(char * line, FILE * af)\r
640 {\r
641    if (numaliasm != 0) {\r
642       HUNSPELL_WARNING(stderr, "error: duplicate AM (aliases for morphological descriptions) tables used\n");\r
643       return 1;\r
644    }\r
645    char * tp = line;\r
646    char * piece;\r
647    int i = 0;\r
648    int np = 0;\r
649    piece = mystrsep(&tp, 0);\r
650    while (piece) {\r
651        if (*piece != '\0') {\r
652           switch(i) {\r
653              case 0: { np++; break; }\r
654              case 1: { \r
655                        numaliasm = atoi(piece);\r
656                        if (numaliasm < 1) {\r
657                           HUNSPELL_WARNING(stderr, "incorrect number of entries in AM table\n");\r
658                           free(piece);\r
659                           return 1;\r
660                        }\r
661                        aliasm = (char **) malloc(numaliasm * sizeof(char *));\r
662                        if (!aliasm) {\r
663                           numaliasm = 0;\r
664                           return 1;\r
665                        }\r
666                        np++;\r
667                        break;\r
668                      }\r
669              default: break;\r
670           }\r
671           i++;\r
672        }\r
673        free(piece);\r
674        piece = mystrsep(&tp, 0);\r
675    }\r
676    if (np != 2) {\r
677       numaliasm = 0;\r
678       free(aliasm);\r
679       aliasm = NULL;\r
680       HUNSPELL_WARNING(stderr, "error: missing AM alias information\n");\r
681       return 1;\r
682    } \r
683 \r
684    /* now parse the numaliasm lines to read in the remainder of the table */\r
685    char * nl = line;\r
686    for (int j=0; j < numaliasm; j++) {\r
687         if (!fgets(nl,MAXDELEN,af)) return 1;\r
688         mychomp(nl);\r
689         tp = nl;\r
690         i = 0;\r
691         aliasm[j] = NULL;\r
692         piece = mystrsep(&tp, 0);\r
693         while (piece) {\r
694            if (*piece != '\0') {\r
695                switch(i) {\r
696                   case 0: {\r
697                              if (strncmp(piece,"AM",2) != 0) {\r
698                                  HUNSPELL_WARNING(stderr, "error: AM table is corrupt\n");\r
699                                  free(piece);\r
700                                  numaliasm = 0;\r
701                                  free(aliasm);\r
702                                  aliasm = NULL;\r
703                                  return 1;\r
704                              }\r
705                              break;\r
706                           }\r
707                   case 1: {\r
708                             if (complexprefixes) {\r
709                                 if (utf8) reverseword_utf(piece);\r
710                                     else reverseword(piece);\r
711                             }\r
712                             aliasm[j] = mystrdup(piece);\r
713                             break; }\r
714                   default: break;\r
715                }\r
716                i++;\r
717            }\r
718            free(piece);\r
719            piece = mystrsep(&tp, 0);\r
720         }\r
721         if (!aliasm[j]) {\r
722              numaliasm = 0;\r
723              free(aliasm);\r
724              aliasm = NULL;\r
725              HUNSPELL_WARNING(stderr, "error: map table is corrupt\n");\r
726              return 1;\r
727         }\r
728    }\r
729    return 0;\r
730 }\r
731 \r
732 int HashMgr::is_aliasm() {\r
733     return (aliasm != NULL);\r
734 }\r
735 \r
736 char * HashMgr::get_aliasm(int index) {\r
737     if ((index > 0) && (index <= numaliasm)) return aliasm[index - 1];\r
738     HUNSPELL_WARNING(stderr, "error: bad morph. alias index: %d\n", index);\r
739     return NULL;\r
740 }\r
741 #endif\r