Index: chrome/third_party/hunspell/src/hunspell/hashmgr.cxx |
=================================================================== |
--- chrome/third_party/hunspell/src/hunspell/hashmgr.cxx (revision 21721) |
+++ chrome/third_party/hunspell/src/hunspell/hashmgr.cxx (working copy) |
@@ -22,18 +22,19 @@ |
using namespace std; |
#endif |
#else |
-#ifndef W32 |
+#ifndef WIN32 |
using namespace std; |
#endif |
#endif |
// build a hash table from a munched word list |
+ |
#ifdef HUNSPELL_CHROME_CLIENT |
HashMgr::HashMgr(hunspell::BDictReader* reader) |
{ |
bdict_reader = reader; |
#else |
-HashMgr::HashMgr(FILE* dic_handle, FILE* aff_handle) |
+HashMgr::HashMgr(FILE* dic_handle, FILE* aff_handle, const char * key) |
{ |
#endif |
tablesize = 0; |
@@ -41,6 +42,10 @@ |
flag_mode = FLAG_CHAR; |
complexprefixes = 0; |
utf8 = 0; |
+ langnum = 0; |
+ lang = NULL; |
+ enc = NULL; |
+ csconv = 0; |
ignorechars = NULL; |
ignorechars_utf16 = NULL; |
ignorechars_utf16_len = 0; |
@@ -48,12 +53,13 @@ |
aliasf = NULL; |
numaliasm = 0; |
aliasm = NULL; |
+ forbiddenword = FORBIDDENWORD; // forbidden word signing flag |
#ifdef HUNSPELL_CHROME_CLIENT |
// No tables to load, just the AF config. |
int ec = load_config(); |
#else |
load_config(aff_handle); |
- int ec = load_tables(dic_handle); |
+ int ec = load_tables(dic_handle, key); |
#endif |
if (ec) { |
/* error condition - what should we do here */ |
@@ -73,29 +79,16 @@ |
// now pass through hash table freeing up everything |
// go through column by column of the table |
for (int i=0; i < tablesize; i++) { |
- struct hentry * pt = &tableptr[i]; |
+ struct hentry * pt = tableptr[i]; |
struct hentry * nt = NULL; |
- if (pt) { |
- if (pt->astr && !aliasf) free(pt->astr); |
- if (pt->word) free(pt->word); |
-#ifdef HUNSPELL_EXPERIMENTAL |
- if (pt->description && !aliasm) free(pt->description); |
-#endif |
- pt = pt->next; |
- } |
while(pt) { |
nt = pt->next; |
- if (pt->astr && !aliasf) free(pt->astr); |
- if (pt->word) free(pt->word); |
-#ifdef HUNSPELL_EXPERIMENTAL |
- if (pt->description && !aliasm) free(pt->description); |
-#endif |
+ if (pt->astr && (!aliasf || TESTAFF(pt->astr, ONLYUPCASEFLAG, pt->alen))) free(pt->astr); |
free(pt); |
pt = nt; |
} |
} |
free(tableptr); |
- tableptr = NULL; |
} |
tablesize = 0; |
@@ -113,6 +106,15 @@ |
free(aliasm); |
aliasm = NULL; |
} |
+ |
+#ifndef OPENOFFICEORG |
+#ifndef MOZILLA_CLIENT |
+ if (utf8) free_utf_tbl(); |
+#endif |
+#endif |
+ |
+ if (enc) free(enc); |
+ if (lang) free(lang); |
if (ignorechars) free(ignorechars); |
if (ignorechars_utf16) free(ignorechars_utf16); |
@@ -144,7 +146,6 @@ |
#endif |
// lookup a root word in the hashtable |
- |
struct hentry * HashMgr::lookup(const char *word) const |
{ |
#ifdef HUNSPELL_CHROME_CLIENT |
@@ -167,10 +168,10 @@ |
#else |
struct hentry * dp; |
if (tableptr) { |
- dp = &tableptr[hash(word)]; |
- if (dp->word == NULL) return NULL; |
+ dp = tableptr[hash(word)]; |
+ if (!dp) return NULL; |
for ( ; dp != NULL; dp = dp->next) { |
- if (strcmp(word,dp->word) == 0) return dp; |
+ if (strcmp(word,&(dp->word)) == 0) return dp; |
} |
} |
return NULL; |
@@ -178,69 +179,101 @@ |
} |
// add a word to the hash table (private) |
- |
-int HashMgr::add_word(const char * word, int wl, unsigned short * aff, int al, const char * desc) |
+int HashMgr::add_word(const char * word, int wbl, int wcl, unsigned short * aff, |
+ int al, const char * desc, bool onlyupcase) |
{ |
#ifndef HUNSPELL_CHROME_CLIENT |
- char * st = mystrdup(word); |
- if (wl && !st) return 1; |
+ bool upcasehomonym = false; |
+ int descl = desc ? (aliasm ? sizeof(short) : strlen(desc) + 1) : 0; |
+ // variable-length hash record with word and optional fields |
+ struct hentry* hp = |
+ (struct hentry *) malloc (sizeof(struct hentry) + wbl + descl); |
+ if (!hp) return 1; |
+ char * hpw = &(hp->word); |
+ strcpy(hpw, word); |
if (ignorechars != NULL) { |
if (utf8) { |
- remove_ignored_chars_utf(st, ignorechars_utf16, ignorechars_utf16_len); |
+ remove_ignored_chars_utf(hpw, ignorechars_utf16, ignorechars_utf16_len); |
} else { |
- remove_ignored_chars(st, ignorechars); |
+ remove_ignored_chars(hpw, ignorechars); |
} |
} |
if (complexprefixes) { |
- if (utf8) reverseword_utf(st); else reverseword(st); |
+ if (utf8) reverseword_utf(hpw); else reverseword(hpw); |
} |
- int i = hash(st); |
- struct hentry * dp = &tableptr[i]; |
- if (dp->word == NULL) { |
- dp->wlen = (short) wl; |
- dp->alen = (short) al; |
- dp->word = st; |
- dp->astr = aff; |
- dp->next = NULL; |
- dp->next_homonym = NULL; |
-#ifdef HUNSPELL_EXPERIMENTAL |
- if (aliasm) { |
- dp->description = (desc) ? get_aliasm(atoi(desc)) : mystrdup(desc); |
- } else { |
- dp->description = mystrdup(desc); |
- if (desc && !dp->description) return 1; |
- if (dp->description && complexprefixes) { |
- if (utf8) reverseword_utf(dp->description); else reverseword(dp->description); |
+ |
+ int i = hash(hpw); |
+ |
+ hp->blen = (unsigned char) wbl; |
+ hp->clen = (unsigned char) wcl; |
+ hp->alen = (short) al; |
+ hp->astr = aff; |
+ hp->next = NULL; |
+ hp->next_homonym = NULL; |
+ |
+ // store the description string or its pointer |
+ if (desc) { |
+ hp->var = H_OPT; |
+ if (aliasm) { |
+ hp->var += H_OPT_ALIASM; |
+ store_pointer(hpw + wbl + 1, get_aliasm(atoi(desc))); |
+ } else { |
+ strcpy(hpw + wbl + 1, desc); |
+ if (complexprefixes) { |
+ if (utf8) reverseword_utf(HENTRY_DATA(hp)); |
+ else reverseword(HENTRY_DATA(hp)); |
} |
+ } |
+ if (strstr(HENTRY_DATA(hp), MORPH_PHON)) hp->var += H_OPT_PHON; |
+ } else hp->var = 0; |
+ |
+ struct hentry * dp = tableptr[i]; |
+ if (!dp) { |
+ tableptr[i] = hp; |
+ return 0; |
} |
-#endif |
- } else { |
- struct hentry* hp = (struct hentry *) malloc (sizeof(struct hentry)); |
- if (!hp) return 1; |
- hp->wlen = (short) wl; |
- hp->alen = (short) al; |
- hp->word = st; |
- hp->astr = aff; |
- hp->next = NULL; |
- hp->next_homonym = NULL; |
-#ifdef HUNSPELL_EXPERIMENTAL |
- if (aliasm) { |
- hp->description = (desc) ? get_aliasm(atoi(desc)) : mystrdup(desc); |
- } else { |
- hp->description = mystrdup(desc); |
- if (desc && !hp->description) return 1; |
- if (dp->description && complexprefixes) { |
- if (utf8) reverseword_utf(hp->description); else reverseword(hp->description); |
+ while (dp->next != NULL) { |
+ if ((!dp->next_homonym) && (strcmp(&(hp->word), &(dp->word)) == 0)) { |
+ // remove hidden onlyupcase homonym |
+ if (!onlyupcase) { |
+ if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) { |
+ free(dp->astr); |
+ dp->astr = hp->astr; |
+ dp->alen = hp->alen; |
+ free(hp); |
+ return 0; |
+ } else { |
+ dp->next_homonym = hp; |
+ } |
+ } else { |
+ upcasehomonym = true; |
} |
- } |
-#endif |
- while (dp->next != NULL) { |
- if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) dp->next_homonym = hp; |
+ } |
dp=dp->next; |
} |
- if ((!dp->next_homonym) && (strcmp(hp->word, dp->word) == 0)) dp->next_homonym = hp; |
- dp->next = hp; |
- } |
+ if (strcmp(&(hp->word), &(dp->word)) == 0) { |
+ // remove hidden onlyupcase homonym |
+ if (!onlyupcase) { |
+ if ((dp->astr) && TESTAFF(dp->astr, ONLYUPCASEFLAG, dp->alen)) { |
+ free(dp->astr); |
+ dp->astr = hp->astr; |
+ dp->alen = hp->alen; |
+ free(hp); |
+ return 0; |
+ } else { |
+ dp->next_homonym = hp; |
+ } |
+ } else { |
+ upcasehomonym = true; |
+ } |
+ } |
+ if (!upcasehomonym) { |
+ dp->next = hp; |
+ } else { |
+ // remove hidden onlyupcase homonym |
+ if (hp->astr) free(hp->astr); |
+ free(hp); |
+ } |
#endif // HUNSPELL_CHROME_CLIENT |
std::map<StringPiece, int>::iterator iter = |
custom_word_to_affix_id_map_.find(word); |
@@ -255,33 +288,134 @@ |
return 0; |
} |
-// add a custom dic. word to the hash table (public) |
-int HashMgr::put_word(const char * word, int wl, char * aff) |
+int HashMgr::add_hidden_capitalized_word(char * word, int wbl, int wcl, |
+ unsigned short * flags, int al, char * dp, int captype) |
{ |
- unsigned short * flags; |
- int al = 0; |
- if (aff) { |
- al = decode_flags(&flags, aff); |
- flag_qsort(flags, 0, al); |
+ // add inner capitalized forms to handle the following allcap forms: |
+ // Mixed caps: OpenOffice.org -> OPENOFFICE.ORG |
+ // Allcaps with suffixes: CIA's -> CIA'S |
+ if (((captype == HUHCAP) || (captype == HUHINITCAP) || |
+ ((captype == ALLCAP) && (flags != NULL))) && |
+ !((flags != NULL) && TESTAFF(flags, forbiddenword, al))) { |
+ unsigned short * flags2 = (unsigned short *) malloc (sizeof(unsigned short) * (al+1)); |
+ if (!flags2) return 1; |
+ if (al) memcpy(flags2, flags, al * sizeof(unsigned short)); |
+ flags2[al] = ONLYUPCASEFLAG; |
+ if (utf8) { |
+ char st[BUFSIZE]; |
+ w_char w[BUFSIZE]; |
+ int wlen = u8_u16(w, BUFSIZE, word); |
+ mkallsmall_utf(w, wlen, langnum); |
+ mkallcap_utf(w, 1, langnum); |
+ u16_u8(st, BUFSIZE, w, wlen); |
+ return add_word(st,wbl,wcl,flags2,al+1,dp, true); |
+ } else { |
+ mkallsmall(word, csconv); |
+ mkinitcap(word, csconv); |
+ return add_word(word,wbl,wcl,flags2,al+1,dp, true); |
+ } |
+ } |
+ return 0; |
+} |
+ |
+// detect captype and modify word length for UTF-8 encoding |
+int HashMgr::get_clen_and_captype(const char * word, int wbl, int * captype) { |
+ int len; |
+ if (utf8) { |
+ w_char dest_utf[BUFSIZE]; |
+ len = u8_u16(dest_utf, BUFSIZE, word); |
+ *captype = get_captype_utf8(dest_utf, len, langnum); |
} else { |
- flags = NULL; |
+ len = wbl; |
+ *captype = get_captype((char *) word, len, csconv); |
} |
- add_word(word, wl, flags, al, NULL); |
+ return len; |
+} |
+ |
+// remove word (personal dictionary function for standalone applications) |
+int HashMgr::remove(const char * word) |
+{ |
+ struct hentry * dp = lookup(word); |
+ while (dp) { |
+ if (dp->alen == 0 || !TESTAFF(dp->astr, forbiddenword, dp->alen)) { |
+ unsigned short * flags = |
+ (unsigned short *) malloc(sizeof(short *) * (dp->alen + 1)); |
+ if (!flags) return 1; |
+ for (int i = 0; i < dp->alen; i++) flags[i] = dp->astr[i]; |
+ flags[dp->alen] = forbiddenword; |
+ dp->astr = flags; |
+ dp->alen++; |
+ flag_qsort(flags, 0, dp->alen); |
+ } |
+ dp = dp->next_homonym; |
+ } |
return 0; |
} |
-int HashMgr::put_word_pattern(const char * word, int wl, const char * pattern) |
+/* remove forbidden flag to add a personal word to the hash */ |
+int HashMgr::remove_forbidden_flag(const char * word) { |
+ struct hentry * dp = lookup(word); |
+ if (!dp) return 1; |
+ while (dp) { |
+ if (dp->astr && TESTAFF(dp->astr, forbiddenword, dp->alen)) { |
+ if (dp->alen == 1) dp->alen = 0; // XXX forbidden words of personal dic. |
+ else { |
+ unsigned short * flags2 = |
+ (unsigned short *) malloc(sizeof(short *) * (dp->alen - 1)); |
+ if (!flags2) return 1; |
+ int i, j = 0; |
+ for (i = 0; i < dp->alen; i++) { |
+ if (dp->astr[i] != forbiddenword) flags2[j++] = dp->astr[i]; |
+ } |
+ dp->alen--; |
+ dp->astr = flags2; // XXX allowed forbidden words |
+ } |
+ } |
+ dp = dp->next_homonym; |
+ } |
+ return 0; |
+} |
+ |
+// add a custom dic. word to the hash table (public) |
+int HashMgr::add(const char * word) |
{ |
- unsigned short * flags; |
- struct hentry * dp = lookup(pattern); |
- if (!dp || !dp->astr) return 1; |
- flags = (unsigned short *) malloc (dp->alen * sizeof(short)); |
- memcpy((void *) flags, (void *) dp->astr, dp->alen * sizeof(short)); |
- add_word(word, wl, flags, dp->alen, NULL); |
+ unsigned short * flags = NULL; |
+ int al = 0; |
+ if (remove_forbidden_flag(word)) { |
+ int captype; |
+ int wbl = strlen(word); |
+ int wcl = get_clen_and_captype(word, wbl, &captype); |
+ add_word(word, wbl, wcl, flags, al, NULL, false); |
+ return add_hidden_capitalized_word((char *) word, wbl, wcl, flags, al, NULL, captype); |
+ } |
return 0; |
} |
+int HashMgr::add_with_affix(const char * word, const char * example) |
+{ |
+ // detect captype and modify word length for UTF-8 encoding |
+ struct hentry * dp = lookup(example); |
+ remove_forbidden_flag(word); |
+ if (dp && dp->astr) { |
+ int captype; |
+ int wbl = strlen(word); |
+ int wcl = get_clen_and_captype(word, wbl, &captype); |
+ if (aliasf) { |
+ add_word(word, wbl, wcl, dp->astr, dp->alen, NULL, false); |
+ } else { |
+ unsigned short * flags = (unsigned short *) malloc (dp->alen * sizeof(short)); |
+ if (flags) { |
+ memcpy((void *) flags, (void *) dp->astr, dp->alen * sizeof(short)); |
+ add_word(word, wbl, wcl, flags, dp->alen, NULL, false); |
+ } else return 1; |
+ } |
+ return add_hidden_capitalized_word((char *) word, wbl, wcl, dp->astr, dp->alen, NULL, captype); |
+ } |
+ return 1; |
+} |
+ |
// walk the hash table entry by entry - null at end |
+// initialize: col=-1; hp = NULL; hp = walk_hashtable(&col, hp); |
struct hentry * HashMgr::walk_hashtable(int &col, struct hentry * hp) const |
{ |
#ifdef HUNSPELL_CHROME_CLIENT |
@@ -312,88 +446,99 @@ |
// lists for the extra affixes. If hp is NULL, create it here. |
if (!hp) |
hp = new hentry; |
- hp->word = word; |
- hp->wlen = word_len; |
+ hp->word = *word; |
+ hp->blen = word_len; |
hp->alen = (short)const_cast<HashMgr*>(this)->get_aliasf(affix_ids[0], |
&hp->astr); |
hp->next = NULL; |
hp->next_homonym = NULL; |
- |
+ hp->var = 0; |
+ hp->clen = 0; |
return hp; |
#else |
- //reset to start |
- if ((col < 0) || (hp == NULL)) { |
- col = -1; |
- hp = NULL; |
+ |
+ if (hp && hp->next != NULL) return hp->next; |
+ for (col++; col < tablesize; col++) { |
+ if (tableptr[col]) return tableptr[col]; |
} |
- |
- if (hp && hp->next != NULL) { |
- hp = hp->next; |
- } else { |
- col++; |
- hp = (col < tablesize) ? &tableptr[col] : NULL; |
- // search for next non-blank column entry |
- while (hp && (hp->word == NULL)) { |
- col ++; |
- hp = (col < tablesize) ? &tableptr[col] : NULL; |
- } |
- if (col < tablesize) return hp; |
- hp = NULL; |
- col = -1; |
- } |
- return hp; |
+ // null at end and reset to start |
+ col = -1; |
+ return NULL; |
#endif |
} |
// load a munched word list and build a hash table on the fly |
-int HashMgr::load_tables(FILE* t_handle) |
+int HashMgr::load_tables(FILE* t_handle, const char * key) |
{ |
#ifndef HUNSPELL_CHROME_CLIENT |
- int wl, al; |
+ int al; |
char * ap; |
char * dp; |
+ char * dp2; |
unsigned short * flags; |
+ char * ts; |
- // raw dictionary - munched file |
- FILE * rawdict = _fdopen(_dup(_fileno(t_handle)), "r"); |
- if (rawdict == NULL) return 1; |
- fseek(rawdict, 0, SEEK_SET); |
+ // open dictionary file |
+ FileMgr * dict = new FileMgr(tpath, key); |
+ if (dict == NULL) return 1; |
// first read the first line of file to get hash table size */ |
- char ts[MAXDELEN]; |
- if (! fgets(ts, MAXDELEN-1,rawdict)) return 2; |
+ if (!(ts = dict->getline())) { |
+ HUNSPELL_WARNING(stderr, "error: empty dic file\n"); |
+ delete dict; |
+ return 2; |
+ } |
mychomp(ts); |
- |
+ |
/* remove byte order mark */ |
- if (strncmp(ts,"\xef\xbb\xbf",3) == 0) { |
+ if (strncmp(ts,"\xEF\xBB\xBF",3) == 0) { |
memmove(ts, ts+3, strlen(ts+3)+1); |
HUNSPELL_WARNING(stderr, "warning: dic file begins with byte order mark: possible incompatibility with old Hunspell versions\n"); |
} |
- |
- if ((*ts < '1') || (*ts > '9')) HUNSPELL_WARNING(stderr, "error - missing word count in dictionary file\n"); |
+ |
tablesize = atoi(ts); |
- if (!tablesize) return 4; |
+ if (tablesize == 0) { |
+ HUNSPELL_WARNING(stderr, "error: line 1: missing or bad word count in the dic file\n"); |
+ delete dict; |
+ return 4; |
+ } |
tablesize = tablesize + 5 + USERWORD; |
if ((tablesize %2) == 0) tablesize++; |
// allocate the hash table |
- tableptr = (struct hentry *) calloc(tablesize, sizeof(struct hentry)); |
- if (! tableptr) return 3; |
- for (int i=0; i<tablesize; i++) tableptr[i].word = NULL; |
+ tableptr = (struct hentry **) malloc(tablesize * sizeof(struct hentry *)); |
+ if (! tableptr) { |
+ delete dict; |
+ return 3; |
+ } |
+ for (int i=0; i<tablesize; i++) tableptr[i] = NULL; |
// loop through all words on much list and add to hash |
// table and create word and affix strings |
- while (fgets(ts,MAXDELEN-1,rawdict)) { |
+ while ((ts = dict->getline())) { |
mychomp(ts); |
// split each line into word and morphological description |
- dp = strchr(ts,'\t'); |
+ dp = ts; |
+ while ((dp = strchr(dp, ':'))) { |
+ if ((dp > ts + 3) && (*(dp - 3) == ' ' || *(dp - 3) == '\t')) { |
+ for (dp -= 4; dp >= ts && (*dp == ' ' || *dp == '\t'); dp--); |
+ if (dp < ts) { // missing word |
+ dp = NULL; |
+ } else { |
+ *(dp + 1) = '\0'; |
+ dp = dp + 2; |
+ } |
+ break; |
+ } |
+ dp++; |
+ } |
- if (dp) { |
- *dp = '\0'; |
- dp++; |
- } else { |
- dp = NULL; |
+ // tabulator is the old morphological field separator |
+ dp2 = strchr(ts, '\t'); |
+ if (dp2 && (!dp || dp2 < dp)) { |
+ *dp2 = '\0'; |
+ dp = dp2 + 1; |
} |
// split each line into word and affix char strings |
@@ -414,13 +559,13 @@ |
*ap = '\0'; |
if (aliasf) { |
int index = atoi(ap + 1); |
- al = get_aliasf(index, &flags); |
+ al = get_aliasf(index, &flags, dict); |
if (!al) { |
- HUNSPELL_WARNING(stderr, "error - bad flag vector alias: %s\n", ts); |
+ HUNSPELL_WARNING(stderr, "error: line %d: bad flag vector alias\n", dict->getlinenum()); |
*ap = '\0'; |
} |
} else { |
- al = decode_flags(&flags, ap + 1); |
+ al = decode_flags(&flags, ap + 1, dict); |
flag_qsort(flags, 0, al); |
} |
} else { |
@@ -429,19 +574,22 @@ |
flags = NULL; |
} |
- wl = strlen(ts); |
+ int captype; |
+ int wbl = strlen(ts); |
+ int wcl = get_clen_and_captype(ts, wbl, &captype); |
+ // add the word and its index plus its capitalized form optionally |
+ if (add_word(ts,wbl,wcl,flags,al,dp, false) || |
+ add_hidden_capitalized_word(ts, wbl, wcl, flags, al, dp, captype)) { |
+ delete dict; |
+ return 5; |
+ } |
+ } |
- // add the word and its index |
- if (add_word(ts,wl,flags,al,dp)) return 5; |
- |
- } |
- |
- fclose(rawdict); |
+ delete dict; |
#endif |
return 0; |
} |
- |
// the hash function is a simple load and rotate |
// algorithm borrowed |
@@ -466,15 +614,17 @@ |
switch (flag_mode) { |
case FLAG_LONG: { // two-character flags (1x2yZz -> 1x 2y Zz) |
len = strlen(flags); |
- if (len%2 == 1) HUNSPELL_WARNING(stderr, "error: length of FLAG_LONG flagvector is odd: %s\n", flags); |
- len = len/2; |
+ if (len%2 == 1) HUNSPELL_WARNING(stderr, "error: bad flagvector\n"); |
+ len /= 2; |
*result = (unsigned short *) malloc(len * sizeof(short)); |
+ if (!*result) return -1; |
for (int i = 0; i < len; i++) { |
(*result)[i] = (((unsigned short) flags[i * 2]) << 8) + (unsigned short) flags[i * 2 + 1]; |
} |
break; |
} |
case FLAG_NUM: { // decimal numbers separated by comma (4521,23,233 -> 4521 23 233) |
+ int i; |
len = 1; |
char * src = flags; |
unsigned short * dest; |
@@ -483,23 +633,29 @@ |
if (*p == ',') len++; |
} |
*result = (unsigned short *) malloc(len * sizeof(short)); |
+ if (!*result) return -1; |
dest = *result; |
for (p = flags; *p; p++) { |
if (*p == ',') { |
- *dest = (unsigned short) atoi(src); |
+ i = atoi(src); |
+ if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: flag id %d is too large (max: %d)\n", i, DEFAULTFLAGS - 1); |
+ *dest = (unsigned short) i; |
if (*dest == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n"); |
src = p + 1; |
dest++; |
} |
} |
- *dest = (unsigned short) atoi(src); |
+ i = atoi(src); |
+ if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: flag id %d is too large (max: %d)\n", i, DEFAULTFLAGS - 1); |
+ *dest = (unsigned short) i; |
if (*dest == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n"); |
break; |
} |
case FLAG_UNI: { // UTF-8 characters |
- w_char w[MAXDELEN/2]; |
- len = u8_u16(w, MAXDELEN/2, flags); |
+ w_char w[BUFSIZE/2]; |
+ len = u8_u16(w, BUFSIZE/2, flags); |
*result = (unsigned short *) malloc(len * sizeof(short)); |
+ if (!*result) return -1; |
memcpy(*result, w, len * sizeof(short)); |
break; |
} |
@@ -507,24 +663,28 @@ |
unsigned short * dest; |
len = strlen(flags); |
*result = (unsigned short *) malloc(len * sizeof(short)); |
+ if (!*result) return -1; |
dest = *result; |
for (unsigned char * p = (unsigned char *) flags; *p; p++) { |
*dest = (unsigned short) *p; |
dest++; |
} |
} |
- } |
+ } |
return len; |
} |
unsigned short HashMgr::decode_flag(const char * f) { |
unsigned short s = 0; |
+ int i; |
switch (flag_mode) { |
case FLAG_LONG: |
s = ((unsigned short) f[0] << 8) + (unsigned short) f[1]; |
break; |
case FLAG_NUM: |
- s = (unsigned short) atoi(f); |
+ i = atoi(f); |
+ if (i >= DEFAULTFLAGS) HUNSPELL_WARNING(stderr, "error: flag id %d is too large (max: %d)\n", i, DEFAULTFLAGS - 1); |
+ s = (unsigned short) i; |
break; |
case FLAG_UNI: |
u8_u16((w_char *) &s, 1, f); |
@@ -532,7 +692,7 @@ |
default: |
s = (unsigned short) *((unsigned char *)f); |
} |
- if (!s) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n"); |
+ if (s == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n"); |
return s; |
} |
@@ -569,7 +729,7 @@ |
// diacritics characters. |
if (strncmp(line,"IGNORE",6) == 0) { |
parse_array(line, &ignorechars, &ignorechars_utf16, |
- &ignorechars_utf16_len, "IGNORE", utf8); |
+ &ignorechars_utf16_len, utf8, 0); |
} |
// Retrieve the format of an AF line. |
if ((strncmp(line,"FLAG",4) == 0) && isspace(line[4])) { |
@@ -591,75 +751,101 @@ |
} |
#else |
// read in aff file and set flag mode |
-int HashMgr::load_config(FILE* aff_handle) |
+int HashMgr::load_config(FILE* aff_handle, const char * key) |
{ |
+ char * line; // io buffers |
int firstline = 1; |
- |
- // io buffers |
- char line[MAXDELEN+1]; |
// open the affix file |
- FILE * afflst; |
- afflst = _fdopen(_dup(_fileno(aff_handle)), "r"); |
+ FileMgr * afflst = new FileMgr(affpath, key); |
if (!afflst) { |
HUNSPELL_WARNING(stderr, "Error - could not open affix description file\n"); |
return 1; |
} |
- fseek(afflst, 0, SEEK_SET); |
// read in each line ignoring any that do not |
// start with a known line type indicator |
- while (fgets(line,MAXDELEN,afflst)) { |
+ while ((line = afflst->getline())) { |
mychomp(line); |
/* remove byte order mark */ |
if (firstline) { |
firstline = 0; |
- if (strncmp(line,"\xef\xbb\xbf",3) == 0) memmove(line, line+3, strlen(line+3)+1); |
+ if (strncmp(line,"\xEF\xBB\xBF",3) == 0) memmove(line, line+3, strlen(line+3)+1); |
} |
/* parse in the try string */ |
if ((strncmp(line,"FLAG",4) == 0) && isspace(line[4])) { |
if (flag_mode != FLAG_CHAR) { |
- HUNSPELL_WARNING(stderr, "error: duplicate FLAG parameter\n"); |
+ HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions of the FLAG affix file parameter\n", afflst->getlinenum()); |
} |
if (strstr(line, "long")) flag_mode = FLAG_LONG; |
if (strstr(line, "num")) flag_mode = FLAG_NUM; |
if (strstr(line, "UTF-8")) flag_mode = FLAG_UNI; |
if (flag_mode == FLAG_CHAR) { |
- HUNSPELL_WARNING(stderr, "error: FLAG need `num', `long' or `UTF-8' parameter: %s\n", line); |
+ HUNSPELL_WARNING(stderr, "error: line %d: FLAG needs `num', `long' or `UTF-8' parameter\n", afflst->getlinenum()); |
} |
} |
- if ((strncmp(line,"SET",3) == 0) && isspace(line[3]) && strstr(line, "UTF-8")) utf8 = 1; |
+ if (strncmp(line,"FORBIDDENWORD",13) == 0) { |
+ char * st = NULL; |
+ if (parse_string(line, &st, afflst->getlinenum())) { |
+ delete afflst; |
+ return 1; |
+ } |
+ forbiddenword = decode_flag(st); |
+ free(st); |
+ } |
+ if (strncmp(line, "SET", 3) == 0) { |
+ if (parse_string(line, &enc, afflst->getlinenum())) { |
+ delete afflst; |
+ return 1; |
+ } |
+ if (strcmp(enc, "UTF-8") == 0) { |
+ utf8 = 1; |
+#ifndef OPENOFFICEORG |
+#ifndef MOZILLA_CLIENT |
+ initialize_utf_tbl(); |
+#endif |
+#endif |
+ } else csconv = get_current_cs(enc); |
+ } |
+ if (strncmp(line, "LANG", 4) == 0) { |
+ if (parse_string(line, &lang, afflst->getlinenum())) { |
+ delete afflst; |
+ return 1; |
+ } |
+ langnum = get_lang_num(lang); |
+ } |
/* parse in the ignored characters (for example, Arabic optional diacritics characters */ |
if (strncmp(line,"IGNORE",6) == 0) { |
- if (parse_array(line, &ignorechars, &ignorechars_utf16, &ignorechars_utf16_len, "IGNORE", utf8)) { |
- fclose(afflst); |
+ if (parse_array(line, &ignorechars, &ignorechars_utf16, |
+ &ignorechars_utf16_len, utf8, afflst->getlinenum())) { |
+ delete afflst; |
return 1; |
} |
} |
if ((strncmp(line,"AF",2) == 0) && isspace(line[2])) { |
if (parse_aliasf(line, afflst)) { |
- fclose(afflst); |
+ delete afflst; |
return 1; |
} |
} |
-#ifdef HUNSPELL_EXPERIMENTAL |
if ((strncmp(line,"AM",2) == 0) && isspace(line[2])) { |
if (parse_aliasm(line, afflst)) { |
- fclose(afflst); |
+ delete afflst; |
return 1; |
} |
} |
-#endif |
- if (strncmp(line,"COMPLEXPREFIXES",15) == 0) complexprefixes = 1; |
- if (((strncmp(line,"SFX",3) == 0) || (strncmp(line,"PFX",3) == 0)) && isspace(line[3])) break; |
+ |
+ if (strncmp(line,"COMPLEXPREFIXES",15) == 0) complexprefixes = 1; |
+ if (((strncmp(line,"SFX",3) == 0) || (strncmp(line,"PFX",3) == 0)) && isspace(line[3])) break; |
} |
- fclose(afflst); |
+ if (csconv == NULL) csconv = get_current_cs(SPELL_ENCODING); |
+ delete afflst; |
return 0; |
} |
#endif // HUNSPELL_CHROME_CLIENT |
@@ -669,11 +855,11 @@ |
int HashMgr::parse_aliasf(char* line, hunspell::LineIterator* iterator) |
{ |
#else |
-int HashMgr::parse_aliasf(char * line, FILE * af) |
+int HashMgr::parse_aliasf(char * line, FileMgr * af) |
{ |
#endif |
if (numaliasf != 0) { |
- HUNSPELL_WARNING(stderr, "error: duplicate AF (alias for flag vector) tables used\n"); |
+ HUNSPELL_WARNING(stderr, "error: multiple table definitions\n"); |
return 1; |
} |
char * tp = line; |
@@ -691,8 +877,7 @@ |
numaliasf = 0; |
aliasf = NULL; |
aliasflen = NULL; |
- HUNSPELL_WARNING(stderr, "incorrect number of entries in AF table\n"); |
- free(piece); |
+ HUNSPELL_WARNING(stderr, "error: bad entry number\n"); |
return 1; |
} |
aliasf = (unsigned short **) malloc(numaliasf * sizeof(unsigned short *)); |
@@ -712,7 +897,6 @@ |
} |
i++; |
} |
- free(piece); |
piece = mystrsep(&tp, 0); |
} |
if (np != 2) { |
@@ -721,7 +905,7 @@ |
free(aliasflen); |
aliasf = NULL; |
aliasflen = NULL; |
- HUNSPELL_WARNING(stderr, "error: missing AF table information\n"); |
+ HUNSPELL_WARNING(stderr, "error: missing data\n"); |
return 1; |
} |
@@ -732,9 +916,9 @@ |
if (!iterator->AdvanceAndCopy(nl, MAXDELEN)) |
return 1; |
#else |
- if (!fgets(nl,MAXDELEN,af)) return 1; |
+ if (!(nl = af->getline())) return 1; |
#endif |
- mychomp(nl); |
+ mychomp(nl); |
tp = nl; |
i = 0; |
aliasf[j] = NULL; |
@@ -750,8 +934,7 @@ |
free(aliasflen); |
aliasf = NULL; |
aliasflen = NULL; |
- HUNSPELL_WARNING(stderr, "error: AF table is corrupt\n"); |
- free(piece); |
+ HUNSPELL_WARNING(stderr, "error: table is corrupt\n"); |
return 1; |
} |
break; |
@@ -765,7 +948,6 @@ |
} |
i++; |
} |
- free(piece); |
piece = mystrsep(&tp, 0); |
} |
if (!aliasf[j]) { |
@@ -774,7 +956,7 @@ |
aliasf = NULL; |
aliasflen = NULL; |
numaliasf = 0; |
- HUNSPELL_WARNING(stderr, "error: AF table is corrupt\n"); |
+ HUNSPELL_WARNING(stderr, "error: table is corrupt\n"); |
return 1; |
} |
} |
@@ -810,8 +992,8 @@ |
struct hentry* he = new hentry; |
if (i == 0) |
first_he = he; |
- he->word = word; |
- he->wlen = word_len; |
+ he->word = *word; |
+ he->blen = word_len; |
he->alen = (short)const_cast<HashMgr*>(this)->get_aliasf(affix_ids[i], |
&he->astr); |
he->next = NULL; |
@@ -854,12 +1036,11 @@ |
return 0; |
} |
-#ifdef HUNSPELL_EXPERIMENTAL |
/* parse morph alias definitions */ |
-int HashMgr::parse_aliasm(char * line, FILE * af) |
+int HashMgr::parse_aliasm(char * line, FileMgr * af) |
{ |
if (numaliasm != 0) { |
- HUNSPELL_WARNING(stderr, "error: duplicate AM (aliases for morphological descriptions) tables used\n"); |
+ HUNSPELL_WARNING(stderr, "error: multiple table definitions\n"); |
return 1; |
} |
char * tp = line; |
@@ -874,8 +1055,7 @@ |
case 1: { |
numaliasm = atoi(piece); |
if (numaliasm < 1) { |
- HUNSPELL_WARNING(stderr, "incorrect number of entries in AM table\n"); |
- free(piece); |
+ HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n", af->getlinenum()); |
return 1; |
} |
aliasm = (char **) malloc(numaliasm * sizeof(char *)); |
@@ -890,33 +1070,31 @@ |
} |
i++; |
} |
- free(piece); |
piece = mystrsep(&tp, 0); |
} |
if (np != 2) { |
numaliasm = 0; |
free(aliasm); |
aliasm = NULL; |
- HUNSPELL_WARNING(stderr, "error: missing AM alias information\n"); |
+ HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", af->getlinenum()); |
return 1; |
} |
/* now parse the numaliasm lines to read in the remainder of the table */ |
char * nl = line; |
for (int j=0; j < numaliasm; j++) { |
- if (!fgets(nl,MAXDELEN,af)) return 1; |
+ if (!(nl = af->getline())) return 1; |
mychomp(nl); |
tp = nl; |
i = 0; |
aliasm[j] = NULL; |
- piece = mystrsep(&tp, 0); |
+ piece = mystrsep(&tp, ' '); |
while (piece) { |
if (*piece != '\0') { |
switch(i) { |
case 0: { |
if (strncmp(piece,"AM",2) != 0) { |
- HUNSPELL_WARNING(stderr, "error: AM table is corrupt\n"); |
- free(piece); |
+ HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n", af->getlinenum()); |
numaliasm = 0; |
free(aliasm); |
aliasm = NULL; |
@@ -925,24 +1103,34 @@ |
break; |
} |
case 1: { |
+ // add the remaining of the line |
+ if (*tp) { |
+ *(tp - 1) = ' '; |
+ tp = tp + strlen(tp); |
+ } |
if (complexprefixes) { |
if (utf8) reverseword_utf(piece); |
else reverseword(piece); |
} |
aliasm[j] = mystrdup(piece); |
+ if (!aliasm[j]) { |
+ numaliasm = 0; |
+ free(aliasm); |
+ aliasm = NULL; |
+ return 1; |
+ } |
break; } |
default: break; |
} |
i++; |
} |
- free(piece); |
- piece = mystrsep(&tp, 0); |
+ piece = mystrsep(&tp, ' '); |
} |
if (!aliasm[j]) { |
numaliasm = 0; |
free(aliasm); |
aliasm = NULL; |
- HUNSPELL_WARNING(stderr, "error: map table is corrupt\n"); |
+ HUNSPELL_WARNING(stderr, "error: table is corrupt\n"); |
return 1; |
} |
} |
@@ -958,4 +1146,3 @@ |
HUNSPELL_WARNING(stderr, "error: bad morph. alias index: %d\n", index); |
return NULL; |
} |
-#endif |