Bug #319778 --> upgrade our version of hunspell to 1.1.8
authorscott@scott-macgregor.org
Wed, 18 Jul 2007 15:22:33 -0700
changeset 3648 229f9f53d03a83f6a7942879bac0ede2aa029b41
parent 3647 308c28579a3a2b16fdf02a5a583bbdec5f2eac82
child 3649 48436c1e4467c3a3bbbe550bd3f7354336e07a05
push idunknown
push userunknown
push dateunknown
bugs319778
milestone1.9a7pre
Bug #319778 --> upgrade our version of hunspell to 1.1.8 NPOTB sr=mscott patch by ryanvm & nemeth
extensions/spellcheck/hunspell/src/README.hunspell
extensions/spellcheck/hunspell/src/affentry.cpp
extensions/spellcheck/hunspell/src/affixmgr.cpp
extensions/spellcheck/hunspell/src/atypes.hxx
extensions/spellcheck/hunspell/src/csutil.cpp
extensions/spellcheck/hunspell/src/hashmgr.cpp
extensions/spellcheck/hunspell/src/hunspell.cpp
extensions/spellcheck/hunspell/src/hunspell.hxx
extensions/spellcheck/hunspell/src/suggestmgr.cpp
--- a/extensions/spellcheck/hunspell/src/README.hunspell
+++ b/extensions/spellcheck/hunspell/src/README.hunspell
@@ -29,17 +29,17 @@
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 ******* END LICENSE BLOCK *******
 
-Hunspell Version: 1.1.6
+Hunspell Version: 1.1.8
 
 Hunspell Author: László Németh
 MySpell Author: Kevin Hendricks & David Einstein
 
 Hunspell is a spell checker and morphological analyser library. Hunspell
 is based on OpenOffice.org's Myspell. Documentation, tests, and examples
 are available at http://hunspell.sourceforge.net.
 
--- a/extensions/spellcheck/hunspell/src/affentry.cpp
+++ b/extensions/spellcheck/hunspell/src/affentry.cpp
@@ -770,24 +770,25 @@ char * SfxEntry::check_twosfx_morph(cons
 }
 #endif // END OF HUNSPELL_EXPERIMENTAL CODE
 
 // get next homonym with same affix
 struct hentry * SfxEntry::get_next_homonym(struct hentry * he, int optflags, AffEntry* ppfx, 
     const FLAG cclass, const FLAG needflag)
 {
     PfxEntry* ep = (PfxEntry *) ppfx;
+    FLAG eFlag = ep ? ep->getFlag() : FLAG_NULL;
 
     while (he->next_homonym) {
         he = he->next_homonym;
         if ((TESTAFF(he->astr, aflag, he->alen) || (ep && ep->getCont() && TESTAFF(ep->getCont(), aflag, ep->getContLen()))) && 
                             ((optflags & aeXPRODUCT) == 0 || 
-                            TESTAFF(he->astr, ep->getFlag(), he->alen) ||
+                            TESTAFF(he->astr, eFlag, he->alen) ||
                              // handle conditional suffix
-                            ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen))
+                            ((contclass) && TESTAFF(contclass, eFlag, contclasslen))
                             ) &&
                             // handle cont. class
                             ((!cclass) || 
                                 ((contclass) && TESTAFF(contclass, cclass, contclasslen))
                             ) &&
                             // handle required flag
                             ((!needflag) || 
                               (TESTAFF(he->astr, needflag, he->alen) ||
--- a/extensions/spellcheck/hunspell/src/affixmgr.cpp
+++ b/extensions/spellcheck/hunspell/src/affixmgr.cpp
@@ -2988,17 +2988,17 @@ int AffixMgr::get_checksharps()
 {
   return checksharps;
 }
 
 // return the preferred ignore string for suggestions
 char * AffixMgr::get_ignore()
 {
   if (!ignorechars) return NULL;
-  return mystrdup(ignorechars);
+  return ignorechars;
 }
 
 // return the preferred ignore string for suggestions
 unsigned short * AffixMgr::get_ignore_utf16(int * len)
 {
   *len = ignorechars_utf16_len;
   return ignorechars_utf16;
 }
@@ -3931,72 +3931,72 @@ int  AffixMgr::parse_affix(char * line, 
           build_sfxtree((AffEntry *)sfxptr); 
       }
       nptr++;
    }      
    free(ptr);
    return 0;
 }
 
-int AffixMgr::redundant_condition(char ft, char * strip, int stripl, const char * cond, char * line) {
+int AffixMgr::redundant_condition(char ft, char * strip, int stripl, const char * cond, char * WARNVAR) {
   int condl = strlen(cond);
   int i;
   int j;
   int neg;
   int in;
   if (ft == 'P') { // prefix
     if (strncmp(strip, cond, condl) == 0) return 1;
     if (utf8) {
     } else {
       for (i = 0, j = 0; (i < stripl) && (j < condl); i++, j++) {
         if (cond[j] != '[') {
           if (cond[j] != strip[i]) {
-            HUNSPELL_WARNING(stderr, "warning: incompatible stripping characters and condition:\n%s\n", line);
+            HUNSPELL_WARNING(stderr, "warning: incompatible stripping characters and condition:\n%s\n", warnvar);
           }
         } else {
           neg = (cond[j+1] == '^') ? 1 : 0;
           in = 0;
           do {
             j++;
             if (strip[i] == cond[j]) in = 1;
           } while ((j < (condl - 1)) && (cond[j] != ']'));
           if (j == (condl - 1) && (cond[j] != ']')) {
-            HUNSPELL_WARNING(stderr, "error: missing ] in condition:\n%s\n", line);
+            HUNSPELL_WARNING(stderr, "error: missing ] in condition:\n%s\n", warnvar);
             return 0;
           }
           if ((!neg && !in) || (neg && in)) {
-            HUNSPELL_WARNING(stderr, "warning: incompatible stripping characters and condition:\n%s\n", line);
+            HUNSPELL_WARNING(stderr, "warning: incompatible stripping characters and condition:\n%s\n", warnvar);
             return 0;          
           }
         }
       }
       if (j >= condl) return 1;
     }
   } else { // suffix
     if ((stripl >= condl) && strcmp(strip + stripl - condl, cond) == 0) return 1;
     if (utf8) {
     } else {
       for (i = stripl - 1, j = condl - 1; (i >= 0) && (j >= 0); i--, j--) {
         if (cond[j] != ']') {
           if (cond[j] != strip[i]) {
-            HUNSPELL_WARNING(stderr, "warning: incompatible stripping characters and condition:\n%s\n", line);
+            HUNSPELL_WARNING(stderr, "warning: incompatible stripping characters and condition:\n%s\n", warnvar);
           }
         } else {
           in = 0;
           do {
             j--;
             if (strip[i] == cond[j]) in = 1;
           } while ((j > 0) && (cond[j] != '['));
           if ((j == 0) && (cond[j] != '[')) {
-            HUNSPELL_WARNING(stderr, "error: missing ] in condition:\n%s\n", line);
+            HUNSPELL_WARNING(stderr, "error: missing ] in condition:\n%s\n", warnvar);
             return 0;
           }
           neg = (cond[j+1] == '^') ? 1 : 0;
           if ((!neg && !in) || (neg && in)) {
-            HUNSPELL_WARNING(stderr, "warning: incompatible stripping characters and condition:\n%s\n", line);
+            HUNSPELL_WARNING(stderr, "warning: incompatible stripping characters and condition:\n%s\n", warnvar);
             return 0;          
           }
         }
       }
       if (j < 0) return 1;
     }    
   }
   return 0;
--- a/extensions/spellcheck/hunspell/src/atypes.hxx
+++ b/extensions/spellcheck/hunspell/src/atypes.hxx
@@ -55,18 +55,20 @@
  ******* END LICENSE BLOCK *******/
 
 #ifndef _ATYPES_HXX_
 #define _ATYPES_HXX_
 
 #ifndef HUNSPELL_WARNING
 #ifdef HUNSPELL_WARNING_ON
 #define HUNSPELL_WARNING fprintf
+#define WARNVAR warnvar
 #else
-#define HUNSPELL_WARNING
+#define HUNSPELL_WARNING(a,b,...) {}
+#define WARNVAR
 #endif
 #endif
 
 // HUNSTEM def.
 #define HUNSTEM
 
 #include "csutil.hxx"
 #include "hashmgr.hxx"
--- a/extensions/spellcheck/hunspell/src/csutil.cpp
+++ b/extensions/spellcheck/hunspell/src/csutil.cpp
@@ -96,18 +96,18 @@ static NS_DEFINE_CID(kUnicharUtilCID, NS
 using namespace std;
 #endif
 #else
 #ifndef W32
 using namespace std;
 #endif
 #endif
 
-struct unicode_info2 * utf_tbl = NULL;
-int utf_tbl_count = 0; // utf_tbl can be used by multiple Hunspell instances
+static struct unicode_info2 * utf_tbl = NULL;
+static int utf_tbl_count = 0; // utf_tbl can be used by multiple Hunspell instances
 
 /* only UTF-16 (BMP) implementation */
 char * u16_u8(char * dest, int size, const w_char * src, int srclen) {
     char * u8 = dest;
     char * u8_max = u8 + size;
     const w_char * u2 = src;
     const w_char * u2_max = src + srclen;
     while ((u2 < u2_max) && (u8 < u8_max)) {
@@ -153,17 +153,17 @@ char * u16_u8(char * dest, int size, con
 
 
 /* only UTF-16 (BMP) implementation */
 int u8_u16(w_char * dest, int size, const char * src) {
     const char * u8 = src;
     w_char * u2 = dest;
     w_char * u2_max = u2 + size;
     
-    while (*u8 && (u2 < u2_max)) {
+    while ((u2 < u2_max) && *u8) {
     switch ((*u8) & 0xf0) {
         case 0x00:
         case 0x10:
         case 0x20:
         case 0x30:
         case 0x40:
         case 0x50:
         case 0x60:
@@ -284,25 +284,29 @@ int flag_bsearch(unsigned short flags[],
         // that's way different than the locale's
         for (dp = mp; (*dp && *dp != ' ' && *dp != '\t'); dp++);
         if (!*dp) dp = NULL;
       }
       if (dp) {
          *stringp = dp+1;
          int nc = (int)((unsigned long)dp - (unsigned long)mp);
          rv = (char *) malloc(nc+1);
-         memcpy(rv,mp,nc);
-         *(rv+nc) = '\0';
-         return rv;
+	 if (rv) {
+            memcpy(rv,mp,nc);
+            *(rv+nc) = '\0';
+            return rv;
+	 }
       } else {
-        rv = (char *) malloc(n+1);
-        memcpy(rv, mp, n);
-        *(rv+n) = '\0';
-        *stringp = mp + n;
-        return rv;
+         rv = (char *) malloc(n+1);
+         if (rv) {
+    	    memcpy(rv, mp, n);
+            *(rv+n) = '\0';
+            *stringp = mp + n;
+            return rv;
+         }
       }
    }
    return NULL;
  }
 
  
  // replaces strdup with ansi version
  char * mystrdup(const char * s)
@@ -5181,17 +5185,17 @@ int initialize_utf_tbl() {
     }
   } else return 1;
   return 0;
 }
 #endif
 #endif
 
 void free_utf_tbl() {
-  if (utf_tbl_count > 0) utf_tbl--;
+  if (utf_tbl_count > 0) utf_tbl_count--;
   if (utf_tbl && (utf_tbl_count == 0)) {
     free(utf_tbl);
     utf_tbl = NULL;
   }
 }
 
 #ifdef MOZILLA_CLIENT
 static nsCOMPtr<nsICaseConversion>& getcaseConv()
@@ -5339,24 +5343,24 @@ void remove_ignored_chars(char * word, c
       if (!strchr(ignored_chars, *p)) {
         *word = *p;
         word++;
       }
    }
    *word = '\0';
 }
 
-int parse_string(char * line, char ** out, const char * name)
+int parse_string(char * line, char ** out, const char * WARNVAR)
 {
    char * tp = line;
    char * piece;
    int i = 0;
    int np = 0;
    if (*out) {
-      HUNSPELL_WARNING(stderr, "error: duplicate %s line\n", name);
+      HUNSPELL_WARNING(stderr, "error: duplicate %s line\n", warnvar);
       return 1;
    }
    piece = mystrsep(&tp, 0);
    while (piece) {
       if (*piece != '\0') {
           switch(i) {
               case 0: { np++; break; }
               case 1: { 
@@ -5367,17 +5371,17 @@ int parse_string(char * line, char ** ou
               default: break;
           }
           i++;
       }
       free(piece);
       piece = mystrsep(&tp, 0);
    }
    if (np != 2) {
-      HUNSPELL_WARNING(stderr, "error: missing %s information\n", name);
+      HUNSPELL_WARNING(stderr, "error: missing %s information\n", warnvar);
       return 1;
    } 
    return 0;
 }
 
 int parse_array(char * line, char ** out,
         unsigned short ** out_utf16, int * out_utf16_len, const char * name, int utf8) {
    if (parse_string(line, out, name)) return 1;
--- a/extensions/spellcheck/hunspell/src/hashmgr.cpp
+++ b/extensions/spellcheck/hunspell/src/hashmgr.cpp
@@ -155,16 +155,22 @@ HashMgr::~HashMgr()
     }
   }
   if (aliasm) {
     for (int j = 0; j < (numaliasm); j++) free(aliasm[j]);
     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);
 }
 
 // lookup a root word in the hashtable
@@ -180,17 +186,21 @@ struct hentry * HashMgr::lookup(const ch
        }
     }
     return NULL;
 }
 
 // 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, bool onlyupcase)
+    int al, const char *
+#ifdef HUNSPELL_EXPERIMENTAL
+desc
+#endif
+, bool onlyupcase)
 {
     char * st = mystrdup(word);
     bool upcasehomonym = false;
     if (wl && !st) return 1;
     if (ignorechars != NULL) {
       if (utf8) {
         remove_ignored_chars_utf(st, ignorechars_utf16, ignorechars_utf16_len);
       } else {
@@ -217,41 +227,53 @@ int HashMgr::add_word(const char * word,
             if (desc && !dp->description) return 1;
             if (dp->description && complexprefixes) {
                 if (utf8) reverseword_utf(dp->description); else reverseword(dp->description);
             }
        }
 #endif
     } else {
        struct hentry* hp = (struct hentry *) malloc (sizeof(struct hentry));
-       if (!hp) return 1;
+       if (!hp)
+       {
+           if (st) free(st);
+           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 (desc && !hp->description)
+            {
+                free(hp->word);
+                free(hp->astr);
+                free(hp);
+                return 1;
+            }
             if (dp->description && complexprefixes) {
                 if (utf8) reverseword_utf(hp->description); else reverseword(hp->description);
             }
        }
 #endif
        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;
+		    dp->alen = hp->alen;
 		    free(hp->word);
 		    free(hp);
 		    return 0;
 		} else {
     		    dp->next_homonym = hp;
     		}
             } else {
         	upcasehomonym = true;
@@ -303,19 +325,22 @@ int HashMgr::put_word(const char * word,
 }
 
 int HashMgr::put_word_pattern(const char * word, int wl, const char * pattern)
 {
     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, false);
-    return 0;
+    if (flags) {
+	memcpy((void *) flags, (void *) dp->astr, dp->alen * sizeof(short));
+	add_word(word, wl, flags, dp->alen, NULL, false);
+        return 0;
+    }
+    return 1;
 }
 
 // walk the hash table entry by entry - null at end
 struct hentry * HashMgr::walk_hashtable(int &col, struct hentry * hp) const
 {
   //reset to start
   if ((col < 0) || (hp == NULL)) {
     col = -1;
@@ -435,25 +460,26 @@ int HashMgr::load_tables(const char * tp
     wl = strlen(ts);
 
     // add the word and its index
     if (add_word(ts,wl,flags,al,dp, false)) {
 	fclose(rawdict);
 	return 5;
     }
 
-    // add decapizatalized forms to handle following cases
-    // OpenOffice.org -> OPENOFFICE.ORG
-    // CIA's -> CIA'S
+    // add inner capitalized forms to handle the following allcap forms:
+    // Mixed caps: OpenOffice.org -> OPENOFFICE.ORG
+    // Allcaps with suffixes: CIA's -> CIA'S
     captype = utf8 ? get_captype_utf8(ts, wl, langnum) : get_captype(ts, wl, csconv);
     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));
-          memcpy(flags2, flags, al * sizeof(unsigned short *));
+          unsigned short * flags2 = (unsigned short *) malloc (sizeof(unsigned short) * (al+1));
+	  if (!flags2) return 6;
+          if (al) memcpy(flags2, flags, al * sizeof(unsigned short));
           flags2[al] = ONLYUPCASEFLAG;
           if (utf8) {
               char st[MAXDELEN];
               w_char w[MAXDELEN];
               int wlen = u8_u16(w, MAXDELEN, ts);
               mkallsmall_utf(w, wlen, langnum);
               mkallcap_utf(w, 1, langnum);
               u16_u8(st, MAXDELEN, w, wlen);
@@ -493,32 +519,34 @@ int HashMgr::hash(const char * word) con
 }
 
 int HashMgr::decode_flags(unsigned short ** result, char * flags) {
     int len;
     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;
+        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)
         len = 1;
         char * src = flags; 
         unsigned short * dest;
         char * p;
         for (p = flags; *p; p++) {
           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);
             if (*dest == 0) HUNSPELL_WARNING(stderr, "error: 0 is wrong flag id\n");
             src = p + 1;
             dest++;
           }
@@ -526,23 +554,25 @@ int HashMgr::decode_flags(unsigned short
         *dest = (unsigned short) atoi(src);
         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);
         *result = (unsigned short *) malloc(len * sizeof(short));
+        if (!*result) return -1;
         memcpy(*result, w, len * sizeof(short));
         break;
       }
       default: { // Ispell's one-character flags (erfg -> e r f g)
         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;
--- a/extensions/spellcheck/hunspell/src/hunspell.cpp
+++ b/extensions/spellcheck/hunspell/src/hunspell.cpp
@@ -127,17 +127,16 @@ Hunspell::~Hunspell()
 // set the capitalization type
 // return the length of the "cleaned" (and UTF-8 encoded) word
 
 int Hunspell::cleanword2(char * dest, const char * src, 
     w_char * dest_utf, int * nc, int * pcaptype, int * pabbrev)
 { 
    unsigned char * p = (unsigned char *) dest;
    const unsigned char * q = (const unsigned char * ) src;
-   int firstcap = 0;
 
    // first skip over any leading blanks
    while ((*q != '\0') && (*q == ' ')) q++;
    
    // now strip off any trailing periods (recording their presence)
    *pabbrev = 0;
    int nl = strlen((const char *)q);
    while ((nl > 0) && (*(q+nl-1)=='.')) {
@@ -151,17 +150,17 @@ int Hunspell::cleanword2(char * dest, co
        *p = '\0';
        return 0;
    }
    
    strncpy(dest, (char *) q, nl);
    *(dest + nl) = '\0';
    nl = strlen(dest);
    if (utf8) {
-      *nc = u8_u16(dest_utf, MAXWORDLEN, (const char *) q);
+      *nc = u8_u16(dest_utf, MAXWORDLEN, dest);
       // don't check too long words
       if (*nc >= MAXWORDLEN) return 0;
       if (*nc == -1) { // big Unicode character (non BMP area)
          *pcaptype = NOCAP;
          return nl;
       }
      *pcaptype = get_captype_utf8(dest, nl, langnum);
    } else {
@@ -431,17 +430,18 @@ int Hunspell::spell(const char * word, i
             if (rv) break;
             if (abbv) {
                 memcpy(wspace,cw,wl);
                 *(wspace+wl) = '.';
                 *(wspace+wl+1) = '\0';
                 rv = checkword(wspace, info, root);
                 if (rv) break;
             }
-            // spec. prefix handling for Italian, etc. (SANT'ELIA -> Sant'+Elia)
+            // Spec. prefix handling for Catalan, French, Italian:
+	    // prefixes separated by apostrophe (SANT'ELIA -> Sant'+Elia).
             if (pAMgr && strchr(cw, '\'')) {
                 wl = mkallsmall2(cw, unicw, nc);
         	char * apostrophe = strchr(cw, '\'');
                 if (utf8) {
             	    w_char tmpword[MAXWORDLEN];
             	    *apostrophe = '\0';
             	    wl2 = u8_u16(tmpword, MAXWORDLEN, cw);
             	    *apostrophe = '\'';
@@ -493,18 +493,20 @@ int Hunspell::spell(const char * word, i
              // (for example, ijs -> Ijs instead of IJs in Dutch)
              // use explicit forms in dic: Ijs/F (F = FORBIDDENWORD flag)
              if (*info & SPELL_FORBIDDEN) {
                 rv = NULL;
                 break;
              }             
              if (rv && is_keepcase(rv) && (captype == ALLCAP)) rv = NULL;
              if (rv) break;
+
              rv = checkword(wspace, info, root);
              if (abbv && !rv) {
+
                  *(wspace+wl) = '.';
                  *(wspace+wl+1) = '\0';
                  rv = checkword(wspace, info, root);
                  if (!rv) {
                     memcpy(wspace, cw, wl2);
                     *(wspace+wl2) = '.';
                     *(wspace+wl2+1) = '\0';
     	    	    if (captype == INITCAP) *info += SPELL_INITCAP;
@@ -520,31 +522,27 @@ int Hunspell::spell(const char * word, i
                    // in INITCAP form, too.
                    !(pAMgr->get_checksharps() &&
                       ((utf8 && strstr(wspace, "\xC3\x9F")) ||
                       (!utf8 && strchr(wspace, '\xDF')))))) rv = NULL;             
              break;
            }               
   }
   
-  // check ONLYUPCASE and return
-//  if (rv && !((captype==INITCAP) && (rv->astr) && (pAMgr) &&
-//	TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen))) {
-//    return 1;
-//  }
   if (rv) return 1;
 
   // recursive breaking at break points (not good for morphological analysis)
   if (wordbreak) {
     char * s;
     char r;
     int corr = 0;
     // German words beginning with "-" are not accepted
     if (langnum == LANG_de) corr = 1;
-    for (int j = 0; j < pAMgr->get_numbreak(); j++) {
+    int numbreak = pAMgr ? pAMgr->get_numbreak() : 0;
+    for (int j = 0; j < numbreak; j++) {
       s=(char *) strstr(cw + corr, wordbreak[j]);
       if (s) {
         r = *s;
         *s = '\0';
         // examine 2 sides of the break point
         if (spell(cw) && spell(s + strlen(wordbreak[j]))) {
             *s = r;
             return 1;
@@ -756,24 +754,27 @@ int Hunspell::suggest(char*** slst, cons
                     capwords = 1;
      case HUHCAP: { 
                      ns = pSMgr->suggest(slst, cw, ns);
                      if (ns != -1) {
                         int prevns;
     		        // something.The -> something. The
                         char * dot = strchr(cw, '.');
 		        if (dot && (dot > cw)) {
-		    	    int captype = utf8 ? get_captype_utf8(dot+1, strlen(dot+1), langnum) :
+		    	    int captype_ = utf8 ? get_captype_utf8(dot+1, strlen(dot+1), langnum) :
 		        	get_captype(dot+1, strlen(dot+1), csconv);
-		    	    if (captype == INITCAP) {
+		    	    if (captype_ == INITCAP) {
                         	char * st = mystrdup(cw);
-                        	st = (char *) realloc(st, wl + 1);
-                        	st[(dot - cw) + 1] = ' ';
-                        	strcpy(st + (dot - cw) + 2, dot + 1);
-                    		ns = insert_sug(slst, st, ns);
+                        	st = (char *) realloc(st, wl + 2);
+				if (st) {
+                        		st[(dot - cw) + 1] = ' ';
+                        		strcpy(st + (dot - cw) + 2, dot + 1);
+                    			ns = insert_sug(slst, st, ns);
+					free(st);
+				}
 		    	    }
 		        }
                         if (captype == HUHINITCAP) {
                             // TheOpenOffice.org -> The OpenOffice.org
                             memcpy(wspace,cw,(wl+1));
                             mkinitsmall2(wspace, unicw, nc);
                             ns = pSMgr->suggest(slst, wspace, ns);
                         }
@@ -910,17 +911,17 @@ int Hunspell::suggest(char*** slst, cons
   if (abbv && pAMgr && pAMgr->get_sugswithdots()) {
     for (int j = 0; j < ns; j++) {
       (*slst)[j] = (char *) realloc((*slst)[j], strlen((*slst)[j]) + 1 + abbv);
       strcat((*slst)[j], word + strlen(word) - abbv);
     }
   }
 
   // remove bad capitalized and forbidden forms
-  if (pAMgr->get_keepcase() || pAMgr->get_forbiddenword()) {
+  if (pAMgr && (pAMgr->get_keepcase() || pAMgr->get_forbiddenword())) {
   switch (captype) {
     case INITCAP:
     case ALLCAP: {
       int l = 0;
       for (int j=0; j < ns; j++) {
         if (!strchr((*slst)[j],' ') && !spell((*slst)[j])) {
           char s[MAXSWUTF8L];
           w_char w[MAXSWL];
@@ -1753,17 +1754,22 @@ char * Hunspell::morph_with_correction(c
 /* analyze word
  * return line count 
  * XXX need a better data structure for morphological analysis */
 int Hunspell::analyze(char ***out, const char *word) {
   int  n = 0;
   if (!word) return 0;
   char * m = morph(word);
   if(!m) return 0;
-  if (!out) return line_tok(m, out);
+  if (!out)
+  {
+     n = line_tok(m, out);
+     free(m);
+     return n;
+  }
 
   // without memory allocation
   /* BUG missing buffer size checking */
   int i, p;
   for(p = 0, i = 0; m[i]; i++) {
      if(m[i] == '\n' || !m[i+1]) {
        n++;
        strncpy((*out)[n++], m + p, i - p + 1);
--- a/extensions/spellcheck/hunspell/src/hunspell.hxx
+++ b/extensions/spellcheck/hunspell/src/hunspell.hxx
@@ -64,25 +64,31 @@
 #define  SPELL_FORBIDDEN (1 << 1)
 #define  SPELL_ALLCAP    (1 << 2)
 #define  SPELL_NOCAP     (1 << 3)
 #define  SPELL_INITCAP   (1 << 4)
 
 #define MAXSUGGESTION 15
 #define MAXSHARPS 5
 
-#ifdef W32
-#define DLLTEST2_API __declspec(dllexport)
-#endif
-
 #ifndef _MYSPELLMGR_HXX_
 #define _MYSPELLMGR_HXX_
 
+#ifdef HUNSPELL_STATIC
+	#define DLLEXPORT
+#else
+	#ifdef HUNSPELL_EXPORTS
+		#define DLLEXPORT  __declspec( dllexport )
+	#else
+		#define DLLEXPORT  __declspec( dllimport )
+	#endif
+#endif
+
 #ifdef W32
-class DLLTEST2_API Hunspell
+class DLLEXPORT Hunspell
 #else
 class Hunspell
 #endif
 {
   AffixMgr*       pAMgr;
   HashMgr*        pHMgr;
   SuggestMgr*     pSMgr;
   char *          encoding;
--- a/extensions/spellcheck/hunspell/src/suggestmgr.cpp
+++ b/extensions/spellcheck/hunspell/src/suggestmgr.cpp
@@ -104,17 +104,17 @@ SuggestMgr::SuggestMgr(const char * trym
         complexprefixes = pAMgr->get_complexprefixes();
   }
 
   if (tryme) {  
     if (utf8) {
         w_char t[MAXSWL];    
         ctryl = u8_u16(t, MAXSWL, tryme);
         ctry_utf = (w_char *) malloc(ctryl * sizeof(w_char));
-        memcpy(ctry_utf, t, ctryl * sizeof(w_char));
+        if (ctry_utf) memcpy(ctry_utf, t, ctryl * sizeof(w_char));
     } else {
         ctry = mystrdup(tryme);
         ctryl = strlen(ctry);
     }
   }
 }
 
 
@@ -497,17 +497,16 @@ int SuggestMgr::doubletwochars(char** wl
       }
   }
   return ns;
 }
 
 // perhaps we doubled two characters (pattern aba -> ababa, for example vacation -> vacacation)
 int SuggestMgr::doubletwochars_utf(char ** wlst, const w_char * word, int wl, int ns, int cpdsuggest)
 {
-  w_char        tmpc;
   w_char        candidate_utf[MAXSWL];
   char          candidate[MAXSWUTF8L];
   int state=0;
   if (wl < 5 || ! pAMgr) return ns;
   for (int i=2; i < wl; i++) {
       if ((word[i].l==word[i-2].l) && (word[i].h==word[i-2].h))  {
           state++;
           if (state==3) {
@@ -615,17 +614,16 @@ int SuggestMgr::extrachar(char** wlst, c
 
 
 // error is missing a letter it needs
 int SuggestMgr::forgotchar(char ** wlst, const char * word, int ns, int cpdsuggest)
 {
    char candidate[MAXSWUTF8L];
    const char * p;
    char *       q;
-   int cwrd;
    time_t timelimit = time(NULL);
    int timer = MINTIMER;
    int wl = strlen(word);
    // try inserting a tryme character before every letter
    strcpy(candidate + 1, word);
    for (p = word, q = candidate;  *p != 0;  )  {
       for (int i = 0;  i < ctryl;  i++) {
          *q = ctry[i];
@@ -816,16 +814,17 @@ int SuggestMgr::longswapchar_utf(char **
    // try swapping not adjacent chars
    memcpy (candidate_utf, word, wl * sizeof(w_char));
    for (p = candidate_utf;  p < (candidate_utf + wl);  p++) {
      for (q = candidate_utf;  q < (candidate_utf + wl);  q++) {
        if (abs(p-q) > 1) {
          tmpc = *p;
          *p = *q;
          *q = tmpc;
+         u16_u8(candidate, MAXSWUTF8L, candidate_utf, wl);
          ns = testsug(wlst, candidate, strlen(candidate), ns, cpdsuggest, NULL, NULL);
          if (ns == -1) return -1;
          *q = *p;
          *p = tmpc;
        }
      }
    }
    return ns;
@@ -1463,25 +1462,26 @@ char * SuggestMgr::suggest_morph(const c
     
     return (*result) ? mystrdup(line_uniq(delete_zeros(result))) : NULL;
 }
 
 char * SuggestMgr::suggest_morph_for_spelling_error(const char * word)
 {
     char * p = NULL;
     char ** wlst = (char **) calloc(maxSug, sizeof(char *));
+    if (!**wlst) return NULL;
     // we will use only the first suggestion
     for (int i = 0; i < maxSug - 1; i++) wlst[i] = "";
     int ns = suggest(&wlst, word, maxSug - 1);
     if (ns == maxSug) {
         p = suggest_morph(wlst[maxSug - 1]);
         free(wlst[maxSug - 1]);
     }
     if (wlst) free(wlst);
-    return p;    
+    return p;
 }
 #endif // END OF HUNSPELL_EXPERIMENTAL CODE
 
 
 // generate an n-gram score comparing s1 and s2
 int SuggestMgr::ngram(int n, char * s1, const char * s2, int uselen)
 {
   int nscore = 0;
@@ -1664,16 +1664,22 @@ void SuggestMgr::lcs(const char * s, con
     m = u8_u16(su, MAXSWL, s);
     n = u8_u16(su2, MAXSWL, s2);
   } else {
     m = strlen(s);
     n = strlen(s2);
   }
   c = (char *) malloc((m + 1) * (n + 1));
   b = (char *) malloc((m + 1) * (n + 1));
+  if (!c || !b) {
+    if (c) free(c);
+    if (b) free(b);
+    *result = NULL;
+    return;
+  }
   for (i = 1; i <= m; i++) c[i*(n+1)] = 0;
   for (j = 0; j <= n; j++) c[j] = 0;
   for (i = 1; i <= m; i++) {
     for (j = 1; j <= n; j++) {
       if ((utf8) && (*((short *) su+i-1) == *((short *)su2+j-1))
           || (!utf8) && ((*(s+i-1)) == (*(s2+j-1)))) {
         c[i*(n+1) + j] = c[(i-1)*(n+1) + j-1]+1;
         b[i*(n+1) + j] = LCS_UPLEFT;
@@ -1695,22 +1701,23 @@ void SuggestMgr::lcs(const char * s, con
 int SuggestMgr::lcslen(const char * s, const char* s2) {
   int m;
   int n;
   int i;
   int j;
   char * result;
   int len = 0;
   lcs(s, s2, &m, &n, &result);
+  if (!result) return 0;
   i = m;
   j = n;
   while ((i != 0) && (j != 0)) {
     if (result[i*(n+1) + j] == LCS_UPLEFT) {
       len++;
       i--;
       j--;
     } else if (result[i*(n+1) + j] == LCS_UP) {
       i--;
     } else j--;
   }
-  if (result) free(result);
+  free(result);
   return len;
 }