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