1 /******* BEGIN LICENSE BLOCK *******
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Initial Developers of the Original Code are Kevin Hendricks (MySpell)
15 * and László Németh (Hunspell). Portions created by the Initial Developers
16 * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved.
18 * Contributor(s): Kevin Hendricks (kevin.hendricks@sympatico.ca)
19 * David Einstein (deinst@world.std.com)
20 * László Németh (nemethl@gyorsposta.hu)
43 * Alternatively, the contents of this file may be used under the terms of
44 * either the GNU General Public License Version 2 or later (the "GPL"), or
45 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
46 * in which case the provisions of the GPL or the LGPL are applicable instead
47 * of those above. If you wish to allow use of your version of this file only
48 * under the terms of either the GPL or the LGPL, and not to allow others to
49 * use your version of this file under the terms of the MPL, indicate your
50 * decision by deleting the provisions above and replace them with the notice
51 * and other provisions required by the GPL or the LGPL. If you do not delete
52 * the provisions above, a recipient may use your version of this file under
53 * the terms of any one of the MPL, the GPL or the LGPL.
55 ******* END LICENSE BLOCK *******/
57 #ifndef MOZILLA_CLIENT
71 #include "hashmgr.hxx"
74 #ifdef __SUNPRO_CC // for SunONE Studio compiler
83 // build a hash table from a munched word list
85 HashMgr::HashMgr(const char * tpath
, const char * apath
, const char * key
)
89 flag_mode
= FLAG_CHAR
;
97 ignorechars_utf16
= NULL
;
98 ignorechars_utf16_len
= 0;
103 forbiddenword
= FORBIDDENWORD
; // forbidden word signing flag
104 load_config(apath
, key
);
105 int ec
= load_tables(tpath
, key
);
107 /* error condition - what should we do here */
108 HUNSPELL_WARNING(stderr
, "Hash Manager Error : %d\n",ec
);
121 // now pass through hash table freeing up everything
122 // go through column by column of the table
123 for (int i
=0; i
< tablesize
; i
++) {
124 struct hentry
* pt
= tableptr
[i
];
125 struct hentry
* nt
= NULL
;
128 if (pt
->astr
&& (!aliasf
|| TESTAFF(pt
->astr
, ONLYUPCASEFLAG
, pt
->alen
))) free(pt
->astr
);
138 for (int j
= 0; j
< (numaliasf
); j
++) free(aliasf
[j
]);
147 for (int j
= 0; j
< (numaliasm
); j
++) free(aliasm
[j
]);
152 #ifndef OPENOFFICEORG
153 #ifndef MOZILLA_CLIENT
154 if (utf8
) free_utf_tbl();
159 if (lang
) free(lang
);
161 if (ignorechars
) free(ignorechars
);
162 if (ignorechars_utf16
) free(ignorechars_utf16
);
165 // lookup a root word in the hashtable
167 struct hentry
* HashMgr::lookup(const char *word
) const
171 dp
= tableptr
[hash(word
)];
172 if (!dp
) return NULL
;
173 for ( ; dp
!= NULL
; dp
= dp
->next
) {
174 if (strcmp(word
,&(dp
->word
)) == 0) return dp
;
180 // add a word to the hash table (private)
181 int HashMgr::add_word(const char * word
, int wbl
, int wcl
, unsigned short * aff
,
182 int al
, const char * desc
, bool onlyupcase
)
184 bool upcasehomonym
= false;
185 int descl
= desc
? (aliasm
? sizeof(short) : strlen(desc
) + 1) : 0;
186 // variable-length hash record with word and optional fields
188 (struct hentry
*) malloc (sizeof(struct hentry
) + wbl
+ descl
);
190 char * hpw
= &(hp
->word
);
192 if (ignorechars
!= NULL
) {
194 remove_ignored_chars_utf(hpw
, ignorechars_utf16
, ignorechars_utf16_len
);
196 remove_ignored_chars(hpw
, ignorechars
);
199 if (complexprefixes
) {
200 if (utf8
) reverseword_utf(hpw
); else reverseword(hpw
);
205 hp
->blen
= (unsigned char) wbl
;
206 hp
->clen
= (unsigned char) wcl
;
207 hp
->alen
= (short) al
;
210 hp
->next_homonym
= NULL
;
212 // store the description string or its pointer
216 hp
->var
+= H_OPT_ALIASM
;
217 store_pointer(hpw
+ wbl
+ 1, get_aliasm(atoi(desc
)));
219 strcpy(hpw
+ wbl
+ 1, desc
);
220 if (complexprefixes
) {
221 if (utf8
) reverseword_utf(HENTRY_DATA(hp
));
222 else reverseword(HENTRY_DATA(hp
));
225 if (strstr(HENTRY_DATA(hp
), MORPH_PHON
)) hp
->var
+= H_OPT_PHON
;
228 struct hentry
* dp
= tableptr
[i
];
233 while (dp
->next
!= NULL
) {
234 if ((!dp
->next_homonym
) && (strcmp(&(hp
->word
), &(dp
->word
)) == 0)) {
235 // remove hidden onlyupcase homonym
237 if ((dp
->astr
) && TESTAFF(dp
->astr
, ONLYUPCASEFLAG
, dp
->alen
)) {
244 dp
->next_homonym
= hp
;
247 upcasehomonym
= true;
252 if (strcmp(&(hp
->word
), &(dp
->word
)) == 0) {
253 // remove hidden onlyupcase homonym
255 if ((dp
->astr
) && TESTAFF(dp
->astr
, ONLYUPCASEFLAG
, dp
->alen
)) {
262 dp
->next_homonym
= hp
;
265 upcasehomonym
= true;
268 if (!upcasehomonym
) {
271 // remove hidden onlyupcase homonym
272 if (hp
->astr
) free(hp
->astr
);
278 int HashMgr::add_hidden_capitalized_word(char * word
, int wbl
, int wcl
,
279 unsigned short * flags
, int al
, char * dp
, int captype
)
281 // add inner capitalized forms to handle the following allcap forms:
282 // Mixed caps: OpenOffice.org -> OPENOFFICE.ORG
283 // Allcaps with suffixes: CIA's -> CIA'S
284 if (((captype
== HUHCAP
) || (captype
== HUHINITCAP
) ||
285 ((captype
== ALLCAP
) && (flags
!= NULL
))) &&
286 !((flags
!= NULL
) && TESTAFF(flags
, forbiddenword
, al
))) {
287 unsigned short * flags2
= (unsigned short *) malloc (sizeof(unsigned short) * (al
+1));
288 if (!flags2
) return 1;
289 if (al
) memcpy(flags2
, flags
, al
* sizeof(unsigned short));
290 flags2
[al
] = ONLYUPCASEFLAG
;
294 int wlen
= u8_u16(w
, BUFSIZE
, word
);
295 mkallsmall_utf(w
, wlen
, langnum
);
296 mkallcap_utf(w
, 1, langnum
);
297 u16_u8(st
, BUFSIZE
, w
, wlen
);
298 return add_word(st
,wbl
,wcl
,flags2
,al
+1,dp
, true);
300 mkallsmall(word
, csconv
);
301 mkinitcap(word
, csconv
);
302 return add_word(word
,wbl
,wcl
,flags2
,al
+1,dp
, true);
308 // detect captype and modify word length for UTF-8 encoding
309 int HashMgr::get_clen_and_captype(const char * word
, int wbl
, int * captype
) {
312 w_char dest_utf
[BUFSIZE
];
313 len
= u8_u16(dest_utf
, BUFSIZE
, word
);
314 *captype
= get_captype_utf8(dest_utf
, len
, langnum
);
317 *captype
= get_captype((char *) word
, len
, csconv
);
322 // remove word (personal dictionary function for standalone applications)
323 int HashMgr::remove(const char * word
)
325 struct hentry
* dp
= lookup(word
);
327 if (dp
->alen
== 0 || !TESTAFF(dp
->astr
, forbiddenword
, dp
->alen
)) {
328 unsigned short * flags
=
329 (unsigned short *) malloc(sizeof(short *) * (dp
->alen
+ 1));
330 if (!flags
) return 1;
331 for (int i
= 0; i
< dp
->alen
; i
++) flags
[i
] = dp
->astr
[i
];
332 flags
[dp
->alen
] = forbiddenword
;
335 flag_qsort(flags
, 0, dp
->alen
);
337 dp
= dp
->next_homonym
;
342 /* remove forbidden flag to add a personal word to the hash */
343 int HashMgr::remove_forbidden_flag(const char * word
) {
344 struct hentry
* dp
= lookup(word
);
347 if (dp
->astr
&& TESTAFF(dp
->astr
, forbiddenword
, dp
->alen
)) {
348 if (dp
->alen
== 1) dp
->alen
= 0; // XXX forbidden words of personal dic.
350 unsigned short * flags2
=
351 (unsigned short *) malloc(sizeof(short *) * (dp
->alen
- 1));
352 if (!flags2
) return 1;
354 for (i
= 0; i
< dp
->alen
; i
++) {
355 if (dp
->astr
[i
] != forbiddenword
) flags2
[j
++] = dp
->astr
[i
];
358 dp
->astr
= flags2
; // XXX allowed forbidden words
361 dp
= dp
->next_homonym
;
366 // add a custom dic. word to the hash table (public)
367 int HashMgr::add(const char * word
)
369 unsigned short * flags
= NULL
;
371 if (remove_forbidden_flag(word
)) {
373 int wbl
= strlen(word
);
374 int wcl
= get_clen_and_captype(word
, wbl
, &captype
);
375 add_word(word
, wbl
, wcl
, flags
, al
, NULL
, false);
376 return add_hidden_capitalized_word((char *) word
, wbl
, wcl
, flags
, al
, NULL
, captype
);
381 int HashMgr::add_with_affix(const char * word
, const char * example
)
383 // detect captype and modify word length for UTF-8 encoding
384 struct hentry
* dp
= lookup(example
);
385 remove_forbidden_flag(word
);
386 if (dp
&& dp
->astr
) {
388 int wbl
= strlen(word
);
389 int wcl
= get_clen_and_captype(word
, wbl
, &captype
);
391 add_word(word
, wbl
, wcl
, dp
->astr
, dp
->alen
, NULL
, false);
393 unsigned short * flags
= (unsigned short *) malloc (dp
->alen
* sizeof(short));
395 memcpy((void *) flags
, (void *) dp
->astr
, dp
->alen
* sizeof(short));
396 add_word(word
, wbl
, wcl
, flags
, dp
->alen
, NULL
, false);
399 return add_hidden_capitalized_word((char *) word
, wbl
, wcl
, dp
->astr
, dp
->alen
, NULL
, captype
);
404 // walk the hash table entry by entry - null at end
405 // initialize: col=-1; hp = NULL; hp = walk_hashtable(&col, hp);
406 struct hentry
* HashMgr::walk_hashtable(int &col
, struct hentry
* hp
) const
408 if (hp
&& hp
->next
!= NULL
) return hp
->next
;
409 for (col
++; col
< tablesize
; col
++) {
410 if (tableptr
[col
]) return tableptr
[col
];
412 // null at end and reset to start
417 // load a munched word list and build a hash table on the fly
418 int HashMgr::load_tables(const char * tpath
, const char * key
)
424 unsigned short * flags
;
427 // open dictionary file
428 FileMgr
* dict
= new FileMgr(tpath
, key
);
429 if (dict
== NULL
) return 1;
431 // first read the first line of file to get hash table size */
432 if (!(ts
= dict
->getline())) {
433 HUNSPELL_WARNING(stderr
, "error: empty dic file\n");
439 /* remove byte order mark */
440 if (strncmp(ts
,"\xEF\xBB\xBF",3) == 0) {
441 memmove(ts
, ts
+3, strlen(ts
+3)+1);
442 HUNSPELL_WARNING(stderr
, "warning: dic file begins with byte order mark: possible incompatibility with old Hunspell versions\n");
445 tablesize
= atoi(ts
);
446 if (tablesize
== 0) {
447 HUNSPELL_WARNING(stderr
, "error: line 1: missing or bad word count in the dic file\n");
451 tablesize
= tablesize
+ 5 + USERWORD
;
452 if ((tablesize
%2) == 0) tablesize
++;
454 // allocate the hash table
455 tableptr
= (struct hentry
**) malloc(tablesize
* sizeof(struct hentry
*));
460 for (int i
=0; i
<tablesize
; i
++) tableptr
[i
] = NULL
;
462 // loop through all words on much list and add to hash
463 // table and create word and affix strings
465 while ((ts
= dict
->getline())) {
467 // split each line into word and morphological description
469 while ((dp
= strchr(dp
, ':'))) {
470 if ((dp
> ts
+ 3) && (*(dp
- 3) == ' ' || *(dp
- 3) == '\t')) {
471 for (dp
-= 4; dp
>= ts
&& (*dp
== ' ' || *dp
== '\t'); dp
--);
472 if (dp
< ts
) { // missing word
483 // tabulator is the old morphological field separator
484 dp2
= strchr(ts
, '\t');
485 if (dp2
&& (!dp
|| dp2
< dp
)) {
490 // split each line into word and affix char strings
491 // "\/" signs slash in words (not affix separator)
492 // "/" at beginning of the line is word character (not affix separator)
498 } else if (*(ap
- 1) != '\\') break;
499 // replace "\/" with "/"
500 for (char * sp
= ap
- 1; *sp
; *sp
= *(sp
+ 1), sp
++);
507 int index
= atoi(ap
+ 1);
508 al
= get_aliasf(index
, &flags
, dict
);
510 HUNSPELL_WARNING(stderr
, "error: line %d: bad flag vector alias\n", dict
->getlinenum());
514 al
= decode_flags(&flags
, ap
+ 1, dict
);
515 flag_qsort(flags
, 0, al
);
524 int wbl
= strlen(ts
);
525 int wcl
= get_clen_and_captype(ts
, wbl
, &captype
);
526 // add the word and its index plus its capitalized form optionally
527 if (add_word(ts
,wbl
,wcl
,flags
,al
,dp
, false) ||
528 add_hidden_capitalized_word(ts
, wbl
, wcl
, flags
, al
, dp
, captype
)) {
538 // the hash function is a simple load and rotate
539 // algorithm borrowed
541 int HashMgr::hash(const char * word
) const
544 for (int i
=0; i
< 4 && *word
!= 0; i
++)
545 hv
= (hv
<< 8) | (*word
++);
547 ROTATE(hv
,ROTATE_LEN
);
550 return (unsigned long) hv
% tablesize
;
553 int HashMgr::decode_flags(unsigned short ** result
, char * flags
, FileMgr
* af
) {
556 case FLAG_LONG
: { // two-character flags (1x2yZz -> 1x 2y Zz)
558 if (len
%2 == 1) HUNSPELL_WARNING(stderr
, "error: line %d: bad flagvector\n", af
->getlinenum());
560 *result
= (unsigned short *) malloc(len
* sizeof(short));
561 if (!*result
) return -1;
562 for (int i
= 0; i
< len
; i
++) {
563 (*result
)[i
] = (((unsigned short) flags
[i
* 2]) << 8) + (unsigned short) flags
[i
* 2 + 1];
567 case FLAG_NUM
: { // decimal numbers separated by comma (4521,23,233 -> 4521 23 233)
571 unsigned short * dest
;
573 for (p
= flags
; *p
; p
++) {
574 if (*p
== ',') len
++;
576 *result
= (unsigned short *) malloc(len
* sizeof(short));
577 if (!*result
) return -1;
579 for (p
= flags
; *p
; p
++) {
582 if (i
>= DEFAULTFLAGS
) HUNSPELL_WARNING(stderr
, "error: line %d: flag id %d is too large (max: %d)\n",
583 af
->getlinenum(), i
, DEFAULTFLAGS
- 1);
584 *dest
= (unsigned short) i
;
585 if (*dest
== 0) HUNSPELL_WARNING(stderr
, "error: line %d: 0 is wrong flag id\n", af
->getlinenum());
591 if (i
>= DEFAULTFLAGS
) HUNSPELL_WARNING(stderr
, "error: line %d: flag id %d is too large (max: %d)\n",
592 af
->getlinenum(), i
, DEFAULTFLAGS
- 1);
593 *dest
= (unsigned short) i
;
594 if (*dest
== 0) HUNSPELL_WARNING(stderr
, "error: line %d: 0 is wrong flag id\n", af
->getlinenum());
597 case FLAG_UNI
: { // UTF-8 characters
599 len
= u8_u16(w
, BUFSIZE
/2, flags
);
600 *result
= (unsigned short *) malloc(len
* sizeof(short));
601 if (!*result
) return -1;
602 memcpy(*result
, w
, len
* sizeof(short));
605 default: { // Ispell's one-character flags (erfg -> e r f g)
606 unsigned short * dest
;
608 *result
= (unsigned short *) malloc(len
* sizeof(short));
609 if (!*result
) return -1;
611 for (unsigned char * p
= (unsigned char *) flags
; *p
; p
++) {
612 *dest
= (unsigned short) *p
;
620 unsigned short HashMgr::decode_flag(const char * f
) {
621 unsigned short s
= 0;
625 s
= ((unsigned short) f
[0] << 8) + (unsigned short) f
[1];
629 if (i
>= DEFAULTFLAGS
) HUNSPELL_WARNING(stderr
, "error: flag id %d is too large (max: %d)\n", i
, DEFAULTFLAGS
- 1);
630 s
= (unsigned short) i
;
633 u8_u16((w_char
*) &s
, 1, f
);
636 s
= (unsigned short) *((unsigned char *)f
);
638 if (s
== 0) HUNSPELL_WARNING(stderr
, "error: 0 is wrong flag id\n");
642 char * HashMgr::encode_flag(unsigned short f
) {
643 unsigned char ch
[10];
644 if (f
==0) return mystrdup("(NULL)");
645 if (flag_mode
== FLAG_LONG
) {
646 ch
[0] = (unsigned char) (f
>> 8);
647 ch
[1] = (unsigned char) (f
- ((f
>> 8) << 8));
649 } else if (flag_mode
== FLAG_NUM
) {
650 sprintf((char *) ch
, "%d", f
);
651 } else if (flag_mode
== FLAG_UNI
) {
652 u16_u8((char *) &ch
, 10, (w_char
*) &f
, 1);
654 ch
[0] = (unsigned char) (f
);
657 return mystrdup((char *) ch
);
660 // read in aff file and set flag mode
661 int HashMgr::load_config(const char * affpath
, const char * key
)
663 char * line
; // io buffers
666 // open the affix file
667 FileMgr
* afflst
= new FileMgr(affpath
, key
);
669 HUNSPELL_WARNING(stderr
, "Error - could not open affix description file %s\n",affpath
);
673 // read in each line ignoring any that do not
674 // start with a known line type indicator
676 while ((line
= afflst
->getline())) {
679 /* remove byte order mark */
682 if (strncmp(line
,"\xEF\xBB\xBF",3) == 0) memmove(line
, line
+3, strlen(line
+3)+1);
685 /* parse in the try string */
686 if ((strncmp(line
,"FLAG",4) == 0) && isspace(line
[4])) {
687 if (flag_mode
!= FLAG_CHAR
) {
688 HUNSPELL_WARNING(stderr
, "error: line %d: multiple definitions of the FLAG affix file parameter\n", afflst
->getlinenum());
690 if (strstr(line
, "long")) flag_mode
= FLAG_LONG
;
691 if (strstr(line
, "num")) flag_mode
= FLAG_NUM
;
692 if (strstr(line
, "UTF-8")) flag_mode
= FLAG_UNI
;
693 if (flag_mode
== FLAG_CHAR
) {
694 HUNSPELL_WARNING(stderr
, "error: line %d: FLAG needs `num', `long' or `UTF-8' parameter\n", afflst
->getlinenum());
697 if (strncmp(line
,"FORBIDDENWORD",13) == 0) {
699 if (parse_string(line
, &st
, afflst
->getlinenum())) {
703 forbiddenword
= decode_flag(st
);
706 if (strncmp(line
, "SET", 3) == 0) {
707 if (parse_string(line
, &enc
, afflst
->getlinenum())) {
711 if (strcmp(enc
, "UTF-8") == 0) {
713 #ifndef OPENOFFICEORG
714 #ifndef MOZILLA_CLIENT
715 initialize_utf_tbl();
718 } else csconv
= get_current_cs(enc
);
720 if (strncmp(line
, "LANG", 4) == 0) {
721 if (parse_string(line
, &lang
, afflst
->getlinenum())) {
725 langnum
= get_lang_num(lang
);
728 /* parse in the ignored characters (for example, Arabic optional diacritics characters */
729 if (strncmp(line
,"IGNORE",6) == 0) {
730 if (parse_array(line
, &ignorechars
, &ignorechars_utf16
,
731 &ignorechars_utf16_len
, utf8
, afflst
->getlinenum())) {
737 if ((strncmp(line
,"AF",2) == 0) && isspace(line
[2])) {
738 if (parse_aliasf(line
, afflst
)) {
744 if ((strncmp(line
,"AM",2) == 0) && isspace(line
[2])) {
745 if (parse_aliasm(line
, afflst
)) {
751 if (strncmp(line
,"COMPLEXPREFIXES",15) == 0) complexprefixes
= 1;
752 if (((strncmp(line
,"SFX",3) == 0) || (strncmp(line
,"PFX",3) == 0)) && isspace(line
[3])) break;
754 if (csconv
== NULL
) csconv
= get_current_cs(SPELL_ENCODING
);
759 /* parse in the ALIAS table */
760 int HashMgr::parse_aliasf(char * line
, FileMgr
* af
)
762 if (numaliasf
!= 0) {
763 HUNSPELL_WARNING(stderr
, "error: line %d: multiple table definitions\n", af
->getlinenum());
770 piece
= mystrsep(&tp
, 0);
772 if (*piece
!= '\0') {
774 case 0: { np
++; break; }
776 numaliasf
= atoi(piece
);
781 HUNSPELL_WARNING(stderr
, "error: line %d: bad entry number\n", af
->getlinenum());
784 aliasf
= (unsigned short **) malloc(numaliasf
* sizeof(unsigned short *));
785 aliasflen
= (unsigned short *) malloc(numaliasf
* sizeof(short));
786 if (!aliasf
|| !aliasflen
) {
788 if (aliasf
) free(aliasf
);
789 if (aliasflen
) free(aliasflen
);
801 piece
= mystrsep(&tp
, 0);
809 HUNSPELL_WARNING(stderr
, "error: line %d: missing data\n", af
->getlinenum());
813 /* now parse the numaliasf lines to read in the remainder of the table */
815 for (int j
=0; j
< numaliasf
; j
++) {
816 if (!(nl
= af
->getline())) return 1;
822 piece
= mystrsep(&tp
, 0);
824 if (*piece
!= '\0') {
827 if (strncmp(piece
,"AF",2) != 0) {
833 HUNSPELL_WARNING(stderr
, "error: line %d: table is corrupt\n", af
->getlinenum());
839 aliasflen
[j
] = (unsigned short) decode_flags(&(aliasf
[j
]), piece
, af
);
840 flag_qsort(aliasf
[j
], 0, aliasflen
[j
]);
847 piece
= mystrsep(&tp
, 0);
855 HUNSPELL_WARNING(stderr
, "error: line %d: table is corrupt\n", af
->getlinenum());
862 int HashMgr::is_aliasf() {
863 return (aliasf
!= NULL
);
866 int HashMgr::get_aliasf(int index
, unsigned short ** fvec
, FileMgr
* af
) {
867 if ((index
> 0) && (index
<= numaliasf
)) {
868 *fvec
= aliasf
[index
- 1];
869 return aliasflen
[index
- 1];
871 HUNSPELL_WARNING(stderr
, "error: line %d: bad flag alias index: %d\n", af
->getlinenum(), index
);
876 /* parse morph alias definitions */
877 int HashMgr::parse_aliasm(char * line
, FileMgr
* af
)
879 if (numaliasm
!= 0) {
880 HUNSPELL_WARNING(stderr
, "error: line %d: multiple table definitions\n", af
->getlinenum());
887 piece
= mystrsep(&tp
, 0);
889 if (*piece
!= '\0') {
891 case 0: { np
++; break; }
893 numaliasm
= atoi(piece
);
895 HUNSPELL_WARNING(stderr
, "error: line %d: bad entry number\n", af
->getlinenum());
898 aliasm
= (char **) malloc(numaliasm
* sizeof(char *));
910 piece
= mystrsep(&tp
, 0);
916 HUNSPELL_WARNING(stderr
, "error: line %d: missing data\n", af
->getlinenum());
920 /* now parse the numaliasm lines to read in the remainder of the table */
922 for (int j
=0; j
< numaliasm
; j
++) {
923 if (!(nl
= af
->getline())) return 1;
928 piece
= mystrsep(&tp
, ' ');
930 if (*piece
!= '\0') {
933 if (strncmp(piece
,"AM",2) != 0) {
934 HUNSPELL_WARNING(stderr
, "error: line %d: table is corrupt\n", af
->getlinenum());
943 // add the remaining of the line
946 tp
= tp
+ strlen(tp
);
948 if (complexprefixes
) {
949 if (utf8
) reverseword_utf(piece
);
950 else reverseword(piece
);
952 aliasm
[j
] = mystrdup(piece
);
964 piece
= mystrsep(&tp
, ' ');
970 HUNSPELL_WARNING(stderr
, "error: line %d: table is corrupt\n", af
->getlinenum());
977 int HashMgr::is_aliasm() {
978 return (aliasm
!= NULL
);
981 char * HashMgr::get_aliasm(int index
) {
982 if ((index
> 0) && (index
<= numaliasm
)) return aliasm
[index
- 1];
983 HUNSPELL_WARNING(stderr
, "error: bad morph. alias index: %d\n", index
);