Updated hunspell to 1.3.2
[TortoiseGit.git] / ext / hunspell / hashmgr.cxx
blobfdf3f26ca63dbc4508c85323883cd35d8e39330b
1 #include "license.hunspell"
2 #include "license.myspell"
4 #include <stdlib.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <ctype.h>
9 #include "hashmgr.hxx"
10 #include "csutil.hxx"
11 #include "atypes.hxx"
13 // build a hash table from a munched word list
15 HashMgr::HashMgr(const char * tpath, const char * apath, const char * key)
17 tablesize = 0;
18 tableptr = NULL;
19 flag_mode = FLAG_CHAR;
20 complexprefixes = 0;
21 utf8 = 0;
22 langnum = 0;
23 lang = NULL;
24 enc = NULL;
25 csconv = 0;
26 ignorechars = NULL;
27 ignorechars_utf16 = NULL;
28 ignorechars_utf16_len = 0;
29 numaliasf = 0;
30 aliasf = NULL;
31 numaliasm = 0;
32 aliasm = NULL;
33 forbiddenword = FORBIDDENWORD; // forbidden word signing flag
34 load_config(apath, key);
35 int ec = load_tables(tpath, key);
36 if (ec) {
37 /* error condition - what should we do here */
38 HUNSPELL_WARNING(stderr, "Hash Manager Error : %d\n",ec);
39 if (tableptr) {
40 free(tableptr);
41 tableptr = NULL;
43 tablesize = 0;
48 HashMgr::~HashMgr()
50 if (tableptr) {
51 // now pass through hash table freeing up everything
52 // go through column by column of the table
53 for (int i=0; i < tablesize; i++) {
54 struct hentry * pt = tableptr[i];
55 struct hentry * nt = NULL;
56 while(pt) {
57 nt = pt->next;
58 if (pt->astr && (!aliasf || TESTAFF(pt->astr, ONLYUPCASEFLAG, pt->alen))) free(pt->astr);
59 free(pt);
60 pt = nt;
63 free(tableptr);
65 tablesize = 0;
67 if (aliasf) {
68 for (int j = 0; j < (numaliasf); j++) free(aliasf[j]);
69 free(aliasf);
70 aliasf = NULL;
71 if (aliasflen) {
72 free(aliasflen);
73 aliasflen = NULL;
76 if (aliasm) {
77 for (int j = 0; j < (numaliasm); j++) free(aliasm[j]);
78 free(aliasm);
79 aliasm = NULL;
82 #ifndef OPENOFFICEORG
83 #ifndef MOZILLA_CLIENT
84 if (utf8) free_utf_tbl();
85 #endif
86 #endif
88 if (enc) free(enc);
89 if (lang) free(lang);
91 if (ignorechars) free(ignorechars);
92 if (ignorechars_utf16) free(ignorechars_utf16);
94 #ifdef MOZILLA_CLIENT
95 delete [] csconv;
96 #endif
99 // lookup a root word in the hashtable
101 struct hentry * HashMgr::lookup(const char *word) const
103 struct hentry * dp;
104 if (tableptr) {
105 dp = tableptr[hash(word)];
106 if (!dp) return NULL;
107 for ( ; dp != NULL; dp = dp->next) {
108 if (strcmp(word, dp->word) == 0) return dp;
111 return NULL;
114 // add a word to the hash table (private)
115 int HashMgr::add_word(const char * word, int wbl, int wcl, unsigned short * aff,
116 int al, const char * desc, bool onlyupcase)
118 bool upcasehomonym = false;
119 int descl = desc ? (aliasm ? sizeof(short) : strlen(desc) + 1) : 0;
120 // variable-length hash record with word and optional fields
121 struct hentry* hp =
122 (struct hentry *) malloc (sizeof(struct hentry) + wbl + descl);
123 if (!hp) return 1;
124 char * hpw = hp->word;
125 strcpy(hpw, word);
126 if (ignorechars != NULL) {
127 if (utf8) {
128 remove_ignored_chars_utf(hpw, ignorechars_utf16, ignorechars_utf16_len);
129 } else {
130 remove_ignored_chars(hpw, ignorechars);
133 if (complexprefixes) {
134 if (utf8) reverseword_utf(hpw); else reverseword(hpw);
137 int i = hash(hpw);
139 hp->blen = (unsigned char) wbl;
140 hp->clen = (unsigned char) wcl;
141 hp->alen = (short) al;
142 hp->astr = aff;
143 hp->next = NULL;
144 hp->next_homonym = NULL;
146 // store the description string or its pointer
147 if (desc) {
148 hp->var = H_OPT;
149 if (aliasm) {
150 hp->var += H_OPT_ALIASM;
151 store_pointer(hpw + wbl + 1, get_aliasm(atoi(desc)));
152 } else {
153 strcpy(hpw + wbl + 1, desc);
154 if (complexprefixes) {
155 if (utf8) reverseword_utf(HENTRY_DATA(hp));
156 else reverseword(HENTRY_DATA(hp));
159 if (strstr(HENTRY_DATA(hp), MORPH_PHON)) hp->var += H_OPT_PHON;
160 } else hp->var = 0;
162 struct hentry * dp = tableptr[i];
163 if (!dp) {
164 tableptr[i] = hp;
165 return 0;
167 while (dp->next != NULL) {
168 if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) {
169 // remove hidden onlyupcase homonym
170 if (!onlyupcase) {
171 if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) {
172 free(dp->astr);
173 dp->astr = hp->astr;
174 dp->alen = hp->alen;
175 free(hp);
176 return 0;
177 } else {
178 dp->next_homonym = hp;
180 } else {
181 upcasehomonym = true;
184 dp=dp->next;
186 if (strcmp(hp->word, dp->word) == 0) {
187 // remove hidden onlyupcase homonym
188 if (!onlyupcase) {
189 if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) {
190 free(dp->astr);
191 dp->astr = hp->astr;
192 dp->alen = hp->alen;
193 free(hp);
194 return 0;
195 } else {
196 dp->next_homonym = hp;
198 } else {
199 upcasehomonym = true;
202 if (!upcasehomonym) {
203 dp->next = hp;
204 } else {
205 // remove hidden onlyupcase homonym
206 if (hp->astr) free(hp->astr);
207 free(hp);
209 return 0;
212 int HashMgr::add_hidden_capitalized_word(char * word, int wbl, int wcl,
213 unsigned short * flags, int al, char * dp, int captype)
215 // add inner capitalized forms to handle the following allcap forms:
216 // Mixed caps: OpenOffice.org -> OPENOFFICE.ORG
217 // Allcaps with suffixes: CIA's -> CIA'S
218 if (((captype == HUHCAP) || (captype == HUHINITCAP) ||
219 ((captype == ALLCAP) && (flags != NULL))) &&
220 !((flags != NULL) && TESTAFF(flags, forbiddenword, al))) {
221 unsigned short * flags2 = (unsigned short *) malloc (sizeof(unsigned short) * (al+1));
222 if (!flags2) return 1;
223 if (al) memcpy(flags2, flags, al * sizeof(unsigned short));
224 flags2[al] = ONLYUPCASEFLAG;
225 if (utf8) {
226 char st[BUFSIZE];
227 w_char w[BUFSIZE];
228 int wlen = u8_u16(w, BUFSIZE, word);
229 mkallsmall_utf(w, wlen, langnum);
230 mkallcap_utf(w, 1, langnum);
231 u16_u8(st, BUFSIZE, w, wlen);
232 return add_word(st,wbl,wcl,flags2,al+1,dp, true);
233 } else {
234 mkallsmall(word, csconv);
235 mkinitcap(word, csconv);
236 return add_word(word,wbl,wcl,flags2,al+1,dp, true);
239 return 0;
242 // detect captype and modify word length for UTF-8 encoding
243 int HashMgr::get_clen_and_captype(const char * word, int wbl, int * captype) {
244 int len;
245 if (utf8) {
246 w_char dest_utf[BUFSIZE];
247 len = u8_u16(dest_utf, BUFSIZE, word);
248 *captype = get_captype_utf8(dest_utf, len, langnum);
249 } else {
250 len = wbl;
251 *captype = get_captype((char *) word, len, csconv);
253 return len;
256 // remove word (personal dictionary function for standalone applications)
257 int HashMgr::remove(const char * word)
259 struct hentry * dp = lookup(word);
260 while (dp) {
261 if (dp->alen == 0 || !TESTAFF(dp->astr, forbiddenword, dp->alen)) {
262 unsigned short * flags =
263 (unsigned short *) malloc(sizeof(short) * (dp->alen + 1));
264 if (!flags) return 1;
265 for (int i = 0; i < dp->alen; i++) flags[i] = dp->astr[i];
266 flags[dp->alen] = forbiddenword;
267 dp->astr = flags;
268 dp->alen++;
269 flag_qsort(flags, 0, dp->alen);
271 dp = dp->next_homonym;
273 return 0;
276 /* remove forbidden flag to add a personal word to the hash */
277 int HashMgr::remove_forbidden_flag(const char * word) {
278 struct hentry * dp = lookup(word);
279 if (!dp) return 1;
280 while (dp) {
281 if (dp->astr && TESTAFF(dp->astr, forbiddenword, dp->alen)) {
282 if (dp->alen == 1) dp->alen = 0; // XXX forbidden words of personal dic.
283 else {
284 unsigned short * flags2 =
285 (unsigned short *) malloc(sizeof(short) * (dp->alen - 1));
286 if (!flags2) return 1;
287 int i, j = 0;
288 for (i = 0; i < dp->alen; i++) {
289 if (dp->astr[i] != forbiddenword) flags2[j++] = dp->astr[i];
291 dp->alen--;
292 dp->astr = flags2; // XXX allowed forbidden words
295 dp = dp->next_homonym;
297 return 0;
300 // add a custom dic. word to the hash table (public)
301 int HashMgr::add(const char * word)
303 unsigned short * flags = NULL;
304 int al = 0;
305 if (remove_forbidden_flag(word)) {
306 int captype;
307 int wbl = strlen(word);
308 int wcl = get_clen_and_captype(word, wbl, &captype);
309 add_word(word, wbl, wcl, flags, al, NULL, false);
310 return add_hidden_capitalized_word((char *) word, wbl, wcl, flags, al, NULL, captype);
312 return 0;
315 int HashMgr::add_with_affix(const char * word, const char * example)
317 // detect captype and modify word length for UTF-8 encoding
318 struct hentry * dp = lookup(example);
319 remove_forbidden_flag(word);
320 if (dp && dp->astr) {
321 int captype;
322 int wbl = strlen(word);
323 int wcl = get_clen_and_captype(word, wbl, &captype);
324 if (aliasf) {
325 add_word(word, wbl, wcl, dp->astr, dp->alen, NULL, false);
326 } else {
327 unsigned short * flags = (unsigned short *) malloc (dp->alen * sizeof(short));
328 if (flags) {
329 memcpy((void *) flags, (void *) dp->astr, dp->alen * sizeof(short));
330 add_word(word, wbl, wcl, flags, dp->alen, NULL, false);
331 } else return 1;
333 return add_hidden_capitalized_word((char *) word, wbl, wcl, dp->astr, dp->alen, NULL, captype);
335 return 1;
338 // walk the hash table entry by entry - null at end
339 // initialize: col=-1; hp = NULL; hp = walk_hashtable(&col, hp);
340 struct hentry * HashMgr::walk_hashtable(int &col, struct hentry * hp) const
342 if (hp && hp->next != NULL) return hp->next;
343 for (col++; col < tablesize; col++) {
344 if (tableptr[col]) return tableptr[col];
346 // null at end and reset to start
347 col = -1;
348 return NULL;
351 // load a munched word list and build a hash table on the fly
352 int HashMgr::load_tables(const char * tpath, const char * key)
354 int al;
355 char * ap;
356 char * dp;
357 char * dp2;
358 unsigned short * flags;
359 char * ts;
361 // open dictionary file
362 FileMgr * dict = new FileMgr(tpath, key);
363 if (dict == NULL) return 1;
365 // first read the first line of file to get hash table size */
366 if (!(ts = dict->getline())) {
367 HUNSPELL_WARNING(stderr, "error: empty dic file\n");
368 delete dict;
369 return 2;
371 mychomp(ts);
373 /* remove byte order mark */
374 if (strncmp(ts,"\xEF\xBB\xBF",3) == 0) {
375 memmove(ts, ts+3, strlen(ts+3)+1);
376 // warning: dic file begins with byte order mark: possible incompatibility with old Hunspell versions
379 tablesize = atoi(ts);
380 if (tablesize == 0) {
381 HUNSPELL_WARNING(stderr, "error: line 1: missing or bad word count in the dic file\n");
382 delete dict;
383 return 4;
385 tablesize = tablesize + 5 + USERWORD;
386 if ((tablesize %2) == 0) tablesize++;
388 // allocate the hash table
389 tableptr = (struct hentry **) malloc(tablesize * sizeof(struct hentry *));
390 if (! tableptr) {
391 delete dict;
392 return 3;
394 for (int i=0; i<tablesize; i++) tableptr[i] = NULL;
396 // loop through all words on much list and add to hash
397 // table and create word and affix strings
399 while ((ts = dict->getline())) {
400 mychomp(ts);
401 // split each line into word and morphological description
402 dp = ts;
403 while ((dp = strchr(dp, ':'))) {
404 if ((dp > ts + 3) && (*(dp - 3) == ' ' || *(dp - 3) == '\t')) {
405 for (dp -= 4; dp >= ts && (*dp == ' ' || *dp == '\t'); dp--);
406 if (dp < ts) { // missing word
407 dp = NULL;
408 } else {
409 *(dp + 1) = '\0';
410 dp = dp + 2;
412 break;
414 dp++;
417 // tabulator is the old morphological field separator
418 dp2 = strchr(ts, '\t');
419 if (dp2 && (!dp || dp2 < dp)) {
420 *dp2 = '\0';
421 dp = dp2 + 1;
424 // split each line into word and affix char strings
425 // "\/" signs slash in words (not affix separator)
426 // "/" at beginning of the line is word character (not affix separator)
427 ap = strchr(ts,'/');
428 while (ap) {
429 if (ap == ts) {
430 ap++;
431 continue;
432 } else if (*(ap - 1) != '\\') break;
433 // replace "\/" with "/"
434 for (char * sp = ap - 1; *sp; *sp = *(sp + 1), sp++);
435 ap = strchr(ap,'/');
438 if (ap) {
439 *ap = '\0';
440 if (aliasf) {
441 int index = atoi(ap + 1);
442 al = get_aliasf(index, &flags, dict);
443 if (!al) {
444 HUNSPELL_WARNING(stderr, "error: line %d: bad flag vector alias\n", dict->getlinenum());
445 *ap = '\0';
447 } else {
448 al = decode_flags(&flags, ap + 1, dict);
449 if (al == -1) {
450 HUNSPELL_WARNING(stderr, "Can't allocate memory.\n");
451 delete dict;
452 return 6;
454 flag_qsort(flags, 0, al);
456 } else {
457 al = 0;
458 ap = NULL;
459 flags = NULL;
462 int captype;
463 int wbl = strlen(ts);
464 int wcl = get_clen_and_captype(ts, wbl, &captype);
465 // add the word and its index plus its capitalized form optionally
466 if (add_word(ts,wbl,wcl,flags,al,dp, false) ||
467 add_hidden_capitalized_word(ts, wbl, wcl, flags, al, dp, captype)) {
468 delete dict;
469 return 5;
473 delete dict;
474 return 0;
477 // the hash function is a simple load and rotate
478 // algorithm borrowed
480 int HashMgr::hash(const char * word) const
482 long hv = 0;
483 for (int i=0; i < 4 && *word != 0; i++)
484 hv = (hv << 8) | (*word++);
485 while (*word != 0) {
486 ROTATE(hv,ROTATE_LEN);
487 hv ^= (*word++);
489 return (unsigned long) hv % tablesize;
492 int HashMgr::decode_flags(unsigned short ** result, char * flags, FileMgr * af) {
493 int len;
494 if (*flags == '\0') {
495 *result = NULL;
496 return 0;
498 switch (flag_mode) {
499 case FLAG_LONG: { // two-character flags (1x2yZz -> 1x 2y Zz)
500 len = strlen(flags);
501 if (len%2 == 1) HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n", af->getlinenum());
502 len /= 2;
503 *result = (unsigned short *) malloc(len * sizeof(short));
504 if (!*result) return -1;
505 for (int i = 0; i < len; i++) {
506 (*result)[i] = (((unsigned short) flags[i * 2]) << 8) + (unsigned short) flags[i * 2 + 1];
508 break;
510 case FLAG_NUM: { // decimal numbers separated by comma (4521,23,233 -> 4521 23 233)
511 int i;
512 len = 1;
513 char * src = flags;
514 unsigned short * dest;
515 char * p;
516 for (p = flags; *p; p++) {
517 if (*p == ',') len++;
519 *result = (unsigned short *) malloc(len * sizeof(short));
520 if (!*result) return -1;
521 dest = *result;
522 for (p = flags; *p; p++) {
523 if (*p == ',') {
524 i = atoi(src);
525 if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: line %d: flag id %d is too large (max: %d)\n",
526 af->getlinenum(), i, DEFAULTFLAGS - 1);
527 *dest = (unsigned short) i;
528 if (*dest == 0) HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", af->getlinenum());
529 src = p + 1;
530 dest++;
533 i = atoi(src);
534 if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: line %d: flag id %d is too large (max: %d)\n",
535 af->getlinenum(), i, DEFAULTFLAGS - 1);
536 *dest = (unsigned short) i;
537 if (*dest == 0) HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n", af->getlinenum());
538 break;
540 case FLAG_UNI: { // UTF-8 characters
541 w_char w[BUFSIZE/2];
542 len = u8_u16(w, BUFSIZE/2, flags);
543 *result = (unsigned short *) malloc(len * sizeof(short));
544 if (!*result) return -1;
545 memcpy(*result, w, len * sizeof(short));
546 break;
548 default: { // Ispell's one-character flags (erfg -> e r f g)
549 unsigned short * dest;
550 len = strlen(flags);
551 *result = (unsigned short *) malloc(len * sizeof(short));
552 if (!*result) return -1;
553 dest = *result;
554 for (unsigned char * p = (unsigned char *) flags; *p; p++) {
555 *dest = (unsigned short) *p;
556 dest++;
560 return len;
563 unsigned short HashMgr::decode_flag(const char * f) {
564 unsigned short s = 0;
565 int i;
566 switch (flag_mode) {
567 case FLAG_LONG:
568 s = ((unsigned short) f[0] << 8) + (unsigned short) f[1];
569 break;
570 case FLAG_NUM:
571 i = atoi(f);
572 if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: flag id %d is too large (max: %d)\n", i, DEFAULTFLAGS - 1);
573 s = (unsigned short) i;
574 break;
575 case FLAG_UNI:
576 u8_u16((w_char *) &s, 1, f);
577 break;
578 default:
579 s = (unsigned short) *((unsigned char *)f);
581 if (s == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n");
582 return s;
585 char * HashMgr::encode_flag(unsigned short f) {
586 unsigned char ch[10];
587 if (f==0) return mystrdup("(NULL)");
588 if (flag_mode == FLAG_LONG) {
589 ch[0] = (unsigned char) (f >> 8);
590 ch[1] = (unsigned char) (f - ((f >> 8) << 8));
591 ch[2] = '\0';
592 } else if (flag_mode == FLAG_NUM) {
593 sprintf((char *) ch, "%d", f);
594 } else if (flag_mode == FLAG_UNI) {
595 u16_u8((char *) &ch, 10, (w_char *) &f, 1);
596 } else {
597 ch[0] = (unsigned char) (f);
598 ch[1] = '\0';
600 return mystrdup((char *) ch);
603 // read in aff file and set flag mode
604 int HashMgr::load_config(const char * affpath, const char * key)
606 char * line; // io buffers
607 int firstline = 1;
609 // open the affix file
610 FileMgr * afflst = new FileMgr(affpath, key);
611 if (!afflst) {
612 HUNSPELL_WARNING(stderr, "Error - could not open affix description file %s\n",affpath);
613 return 1;
616 // read in each line ignoring any that do not
617 // start with a known line type indicator
619 while ((line = afflst->getline())) {
620 mychomp(line);
622 /* remove byte order mark */
623 if (firstline) {
624 firstline = 0;
625 if (strncmp(line,"\xEF\xBB\xBF",3) == 0) memmove(line, line+3, strlen(line+3)+1);
628 /* parse in the try string */
629 if ((strncmp(line,"FLAG",4) == 0) && isspace(line[4])) {
630 if (flag_mode != FLAG_CHAR) {
631 HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions of the FLAG affix file parameter\n", afflst->getlinenum());
633 if (strstr(line, "long")) flag_mode = FLAG_LONG;
634 if (strstr(line, "num")) flag_mode = FLAG_NUM;
635 if (strstr(line, "UTF-8")) flag_mode = FLAG_UNI;
636 if (flag_mode == FLAG_CHAR) {
637 HUNSPELL_WARNING(stderr, "error: line %d: FLAG needs `num', `long' or `UTF-8' parameter\n", afflst->getlinenum());
640 if (strncmp(line,"FORBIDDENWORD",13) == 0) {
641 char * st = NULL;
642 if (parse_string(line, &st, afflst->getlinenum())) {
643 delete afflst;
644 return 1;
646 forbiddenword = decode_flag(st);
647 free(st);
649 if (strncmp(line, "SET", 3) == 0) {
650 if (parse_string(line, &enc, afflst->getlinenum())) {
651 delete afflst;
652 return 1;
654 if (strcmp(enc, "UTF-8") == 0) {
655 utf8 = 1;
656 #ifndef OPENOFFICEORG
657 #ifndef MOZILLA_CLIENT
658 initialize_utf_tbl();
659 #endif
660 #endif
661 } else csconv = get_current_cs(enc);
663 if (strncmp(line, "LANG", 4) == 0) {
664 if (parse_string(line, &lang, afflst->getlinenum())) {
665 delete afflst;
666 return 1;
668 langnum = get_lang_num(lang);
671 /* parse in the ignored characters (for example, Arabic optional diacritics characters */
672 if (strncmp(line,"IGNORE",6) == 0) {
673 if (parse_array(line, &ignorechars, &ignorechars_utf16,
674 &ignorechars_utf16_len, utf8, afflst->getlinenum())) {
675 delete afflst;
676 return 1;
680 if ((strncmp(line,"AF",2) == 0) && isspace(line[2])) {
681 if (parse_aliasf(line, afflst)) {
682 delete afflst;
683 return 1;
687 if ((strncmp(line,"AM",2) == 0) && isspace(line[2])) {
688 if (parse_aliasm(line, afflst)) {
689 delete afflst;
690 return 1;
694 if (strncmp(line,"COMPLEXPREFIXES",15) == 0) complexprefixes = 1;
695 if (((strncmp(line,"SFX",3) == 0) || (strncmp(line,"PFX",3) == 0)) && isspace(line[3])) break;
697 if (csconv == NULL) csconv = get_current_cs(SPELL_ENCODING);
698 delete afflst;
699 return 0;
702 /* parse in the ALIAS table */
703 int HashMgr::parse_aliasf(char * line, FileMgr * af)
705 if (numaliasf != 0) {
706 HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum());
707 return 1;
709 char * tp = line;
710 char * piece;
711 int i = 0;
712 int np = 0;
713 piece = mystrsep(&tp, 0);
714 while (piece) {
715 if (*piece != '\0') {
716 switch(i) {
717 case 0: { np++; break; }
718 case 1: {
719 numaliasf = atoi(piece);
720 if (numaliasf < 1) {
721 numaliasf = 0;
722 aliasf = NULL;
723 aliasflen = NULL;
724 HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum());
725 return 1;
727 aliasf = (unsigned short **) malloc(numaliasf * sizeof(unsigned short *));
728 aliasflen = (unsigned short *) malloc(numaliasf * sizeof(short));
729 if (!aliasf || !aliasflen) {
730 numaliasf = 0;
731 if (aliasf) free(aliasf);
732 if (aliasflen) free(aliasflen);
733 aliasf = NULL;
734 aliasflen = NULL;
735 return 1;
737 np++;
738 break;
740 default: break;
742 i++;
744 piece = mystrsep(&tp, 0);
746 if (np != 2) {
747 numaliasf = 0;
748 free(aliasf);
749 free(aliasflen);
750 aliasf = NULL;
751 aliasflen = NULL;
752 HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum());
753 return 1;
756 /* now parse the numaliasf lines to read in the remainder of the table */
757 char * nl;
758 for (int j=0; j < numaliasf; j++) {
759 if (!(nl = af->getline())) return 1;
760 mychomp(nl);
761 tp = nl;
762 i = 0;
763 aliasf[j] = NULL;
764 aliasflen[j] = 0;
765 piece = mystrsep(&tp, 0);
766 while (piece) {
767 if (*piece != '\0') {
768 switch(i) {
769 case 0: {
770 if (strncmp(piece,"AF",2) != 0) {
771 numaliasf = 0;
772 free(aliasf);
773 free(aliasflen);
774 aliasf = NULL;
775 aliasflen = NULL;
776 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());
777 return 1;
779 break;
781 case 1: {
782 aliasflen[j] = (unsigned short) decode_flags(&(aliasf[j]), piece, af);
783 flag_qsort(aliasf[j], 0, aliasflen[j]);
784 break;
786 default: break;
788 i++;
790 piece = mystrsep(&tp, 0);
792 if (!aliasf[j]) {
793 free(aliasf);
794 free(aliasflen);
795 aliasf = NULL;
796 aliasflen = NULL;
797 numaliasf = 0;
798 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());
799 return 1;
802 return 0;
805 int HashMgr::is_aliasf() {
806 return (aliasf != NULL);
809 int HashMgr::get_aliasf(int index, unsigned short ** fvec, FileMgr * af) {
810 if ((index > 0) && (index <= numaliasf)) {
811 *fvec = aliasf[index - 1];
812 return aliasflen[index - 1];
814 HUNSPELL_WARNING(stderr, "error: line %d: bad flag alias index: %d\n", af->getlinenum(), index);
815 *fvec = NULL;
816 return 0;
819 /* parse morph alias definitions */
820 int HashMgr::parse_aliasm(char * line, FileMgr * af)
822 if (numaliasm != 0) {
823 HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n", af->getlinenum());
824 return 1;
826 char * tp = line;
827 char * piece;
828 int i = 0;
829 int np = 0;
830 piece = mystrsep(&tp, 0);
831 while (piece) {
832 if (*piece != '\0') {
833 switch(i) {
834 case 0: { np++; break; }
835 case 1: {
836 numaliasm = atoi(piece);
837 if (numaliasm < 1) {
838 HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum());
839 return 1;
841 aliasm = (char **) malloc(numaliasm * sizeof(char *));
842 if (!aliasm) {
843 numaliasm = 0;
844 return 1;
846 np++;
847 break;
849 default: break;
851 i++;
853 piece = mystrsep(&tp, 0);
855 if (np != 2) {
856 numaliasm = 0;
857 free(aliasm);
858 aliasm = NULL;
859 HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum());
860 return 1;
863 /* now parse the numaliasm lines to read in the remainder of the table */
864 char * nl = line;
865 for (int j=0; j < numaliasm; j++) {
866 if (!(nl = af->getline())) return 1;
867 mychomp(nl);
868 tp = nl;
869 i = 0;
870 aliasm[j] = NULL;
871 piece = mystrsep(&tp, ' ');
872 while (piece) {
873 if (*piece != '\0') {
874 switch(i) {
875 case 0: {
876 if (strncmp(piece,"AM",2) != 0) {
877 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());
878 numaliasm = 0;
879 free(aliasm);
880 aliasm = NULL;
881 return 1;
883 break;
885 case 1: {
886 // add the remaining of the line
887 if (*tp) {
888 *(tp - 1) = ' ';
889 tp = tp + strlen(tp);
891 if (complexprefixes) {
892 if (utf8) reverseword_utf(piece);
893 else reverseword(piece);
895 aliasm[j] = mystrdup(piece);
896 if (!aliasm[j]) {
897 numaliasm = 0;
898 free(aliasm);
899 aliasm = NULL;
900 return 1;
902 break; }
903 default: break;
905 i++;
907 piece = mystrsep(&tp, ' ');
909 if (!aliasm[j]) {
910 numaliasm = 0;
911 free(aliasm);
912 aliasm = NULL;
913 HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum());
914 return 1;
917 return 0;
920 int HashMgr::is_aliasm() {
921 return (aliasm != NULL);
924 char * HashMgr::get_aliasm(int index) {
925 if ((index > 0) && (index <= numaliasm)) return aliasm[index - 1];
926 HUNSPELL_WARNING(stderr, "error: bad morph. alias index: %d\n", index);
927 return NULL;