LCOV - app.info - extensions/spellcheck/hunspell/src/hunspell.cpp

LCOV - code coverage report
| Current view: | directory - extensions/spellcheck/hunspell/src - hunspell.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 1029 | 303 | 29.4 %
| Date: | 2012-04-21 | Functions: | 55 | 11 | 20.0 %

           1                 : /******* BEGIN LICENSE BLOCK *******
           2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           3                 :  *
           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/
           8                 :  *
           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
          12                 :  * License.
          13                 :  *
          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.
          17                 :  *
          18                 :  * Contributor(s): Kevin Hendricks (kevin.hendricks@sympatico.ca)
          19                 :  *                 David Einstein (deinst@world.std.com)
          20                 :  *                 László Németh (nemethl@gyorsposta.hu)
          21                 :  *                 Caolan McNamara (caolanm@redhat.com)
          22                 :  *                 Davide Prina
          23                 :  *                 Giuseppe Modugno
          24                 :  *                 Gianluca Turconi
          25                 :  *                 Simon Brouwer
          26                 :  *                 Noll Janos
          27                 :  *                 Biro Arpad
          28                 :  *                 Goldman Eleonora
          29                 :  *                 Sarlos Tamas
          30                 :  *                 Bencsath Boldizsar
          31                 :  *                 Halacsy Peter
          32                 :  *                 Dvornik Laszlo
          33                 :  *                 Gefferth Andras
          34                 :  *                 Nagy Viktor
          35                 :  *                 Varga Daniel
          36                 :  *                 Chris Halls
          37                 :  *                 Rene Engelhard
          38                 :  *                 Bram Moolenaar
          39                 :  *                 Dafydd Jones
          40                 :  *                 Harri Pitkanen
          41                 :  *                 Andras Timar
          42                 :  *                 Tor Lillqvist
          43                 :  *
          44                 :  * Alternatively, the contents of this file may be used under the terms of
          45                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          46                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          47                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          48                 :  * of those above. If you wish to allow use of your version of this file only
          49                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          50                 :  * use your version of this file under the terms of the MPL, indicate your
          51                 :  * decision by deleting the provisions above and replace them with the notice
          52                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          53                 :  * the provisions above, a recipient may use your version of this file under
          54                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          55                 :  *
          56                 :  ******* END LICENSE BLOCK *******/
          57                 :
          58                 : #include <stdlib.h>
          59                 : #include <string.h>
          60                 : #include <stdio.h>
          61                 :
          62                 : #include "hunspell.hxx"
          63                 : #include "hunspell.h"
          64                 : #ifndef MOZILLA_CLIENT
          65                 : #    include "config.h"
          66                 : #endif
          67                 : #include "csutil.hxx"
          68                 :
          69             110 : Hunspell::Hunspell(const char * affpath, const char * dpath, const char * key)
          70                 : {
          71             110 :     encoding = NULL;
          72             110 :     csconv = NULL;
          73             110 :     utf8 = 0;
          74             110 :     complexprefixes = 0;
          75             110 :     affixpath = mystrdup(affpath);
          76             110 :     maxdic = 0;
          77                 :
          78                 :     /* first set up the hash manager */
          79             110 :     pHMgr[0] = new HashMgr(dpath, affpath, key);
          80             110 :     if (pHMgr[0]) maxdic = 1;
          81                 :
          82                 :     /* next set up the affix manager */
          83                 :     /* it needs access to the hash manager lookup methods */
          84             110 :     pAMgr = new AffixMgr(affpath, pHMgr, &maxdic, key);
          85                 :
          86                 :     /* get the preferred try string and the dictionary */
          87                 :     /* encoding from the Affix Manager for that dictionary */
          88             110 :     char * try_string = pAMgr->get_try_string();
          89             110 :     encoding = pAMgr->get_encoding();
          90             110 :     langnum = pAMgr->get_langnum();
          91             110 :     utf8 = pAMgr->get_utf8();
          92             110 :     if (!utf8)
          93              82 :         csconv = get_current_cs(encoding);
          94             110 :     complexprefixes = pAMgr->get_complexprefixes();
          95             110 :     wordbreak = pAMgr->get_breaktable();
          96                 :
          97                 :     /* and finally set up the suggestion manager */
          98             110 :     pSMgr = new SuggestMgr(try_string, MAXSUGGESTION, pAMgr);
          99             110 :     if (try_string) free(try_string);
         100             110 : }
         101                 :
         102             110 : Hunspell::~Hunspell()
         103                 : {
         104             110 :     if (pSMgr) delete pSMgr;
         105             110 :     if (pAMgr) delete pAMgr;
         106             220 :     for (int i = 0; i < maxdic; i++) delete pHMgr[i];
         107             110 :     maxdic = 0;
         108             110 :     pSMgr = NULL;
         109             110 :     pAMgr = NULL;
         110                 : #ifdef MOZILLA_CLIENT
         111             110 :     delete [] csconv;
         112                 : #endif
         113             110 :     csconv= NULL;
         114             110 :     if (encoding) free(encoding);
         115             110 :     encoding = NULL;
         116             110 :     if (affixpath) free(affixpath);
         117             110 :     affixpath = NULL;
         118             110 : }
         119                 :
         120                 : // load extra dictionaries
         121               0 : int Hunspell::add_dic(const char * dpath, const char * key) {
         122               0 :     if (maxdic == MAXDIC || !affixpath) return 1;
         123               0 :     pHMgr[maxdic] = new HashMgr(dpath, affixpath, key);
         124               0 :     if (pHMgr[maxdic]) maxdic++; else return 1;
         125               0 :     return 0;
         126                 : }
         127                 :
         128                 : // make a copy of src at destination while removing all leading
         129                 : // blanks and removing any trailing periods after recording
         130                 : // their presence with the abbreviation flag
         131                 : // also since already going through character by character,
         132                 : // set the capitalization type
         133                 : // return the length of the "cleaned" (and UTF-8 encoded) word
         134                 :
         135            1083 : int Hunspell::cleanword2(char * dest, const char * src,
         136                 :     w_char * dest_utf, int * nc, int * pcaptype, int * pabbrev)
         137                 : {
         138            1083 :    unsigned char * p = (unsigned char *) dest;
         139            1083 :    const unsigned char * q = (const unsigned char * ) src;
         140                 :
         141                 :    // first skip over any leading blanks
         142            1083 :    while ((*q != '\0') && (*q == ' ')) q++;
         143                 :
         144                 :    // now strip off any trailing periods (recording their presence)
         145            1083 :    *pabbrev = 0;
         146            1083 :    int nl = strlen((const char *)q);
         147            2188 :    while ((nl > 0) && (*(q+nl-1)=='.')) {
         148              22 :        nl--;
         149              22 :        (*pabbrev)++;
         150                 :    }
         151                 :
         152                 :    // if no characters are left it can't be capitalized
         153            1083 :    if (nl <= 0) {
         154               2 :        *pcaptype = NOCAP;
         155               2 :        *p = '\0';
         156               2 :        return 0;
         157                 :    }
         158                 :
         159            1081 :    strncpy(dest, (char *) q, nl);
         160            1081 :    *(dest + nl) = '\0';
         161            1081 :    nl = strlen(dest);
         162            1081 :    if (utf8) {
         163             236 :       *nc = u8_u16(dest_utf, MAXWORDLEN, dest);
         164                 :       // don't check too long words
         165             236 :       if (*nc >= MAXWORDLEN) return 0;
         166             236 :       if (*nc == -1) { // big Unicode character (non BMP area)
         167               5 :          *pcaptype = NOCAP;
         168               5 :          return nl;
         169                 :       }
         170             231 :      *pcaptype = get_captype_utf8(dest_utf, *nc, langnum);
         171                 :    } else {
         172             845 :      *pcaptype = get_captype(dest, nl, csconv);
         173             845 :      *nc = nl;
         174                 :    }
         175            1076 :    return nl;
         176                 : }
         177                 :
         178               0 : int Hunspell::cleanword(char * dest, const char * src,
         179                 :     int * pcaptype, int * pabbrev)
         180                 : {
         181               0 :    unsigned char * p = (unsigned char *) dest;
         182               0 :    const unsigned char * q = (const unsigned char * ) src;
         183               0 :    int firstcap = 0;
         184                 :
         185                 :    // first skip over any leading blanks
         186               0 :    while ((*q != '\0') && (*q == ' ')) q++;
         187                 :
         188                 :    // now strip off any trailing periods (recording their presence)
         189               0 :    *pabbrev = 0;
         190               0 :    int nl = strlen((const char *)q);
         191               0 :    while ((nl > 0) && (*(q+nl-1)=='.')) {
         192               0 :        nl--;
         193               0 :        (*pabbrev)++;
         194                 :    }
         195                 :
         196                 :    // if no characters are left it can't be capitalized
         197               0 :    if (nl <= 0) {
         198               0 :        *pcaptype = NOCAP;
         199               0 :        *p = '\0';
         200               0 :        return 0;
         201                 :    }
         202                 :
         203                 :    // now determine the capitalization type of the first nl letters
         204               0 :    int ncap = 0;
         205               0 :    int nneutral = 0;
         206               0 :    int nc = 0;
         207                 :
         208               0 :    if (!utf8) {
         209               0 :       while (nl > 0) {
         210               0 :          nc++;
         211               0 :          if (csconv[(*q)].ccase) ncap++;
         212               0 :          if (csconv[(*q)].cupper == csconv[(*q)].clower) nneutral++;
         213               0 :          *p++ = *q++;
         214               0 :          nl--;
         215                 :       }
         216                 :       // remember to terminate the destination string
         217               0 :       *p = '\0';
         218               0 :       firstcap = csconv[(unsigned char)(*dest)].ccase;
         219                 :    } else {
         220                 :       unsigned short idx;
         221                 :       w_char t[MAXWORDLEN];
         222               0 :       nc = u8_u16(t, MAXWORDLEN, src);
         223               0 :       for (int i = 0; i < nc; i++) {
         224               0 :          idx = (t[i].h << 8) + t[i].l;
         225               0 :          unsigned short low = unicodetolower(idx, langnum);
         226               0 :          if (idx != low) ncap++;
         227               0 :          if (unicodetoupper(idx, langnum) == low) nneutral++;
         228                 :       }
         229               0 :       u16_u8(dest, MAXWORDUTF8LEN, t, nc);
         230               0 :       if (ncap) {
         231               0 :          idx = (t[0].h << 8) + t[0].l;
         232               0 :          firstcap = (idx != unicodetolower(idx, langnum));
         233                 :       }
         234                 :    }
         235                 :
         236                 :    // now finally set the captype
         237               0 :    if (ncap == 0) {
         238               0 :         *pcaptype = NOCAP;
         239               0 :    } else if ((ncap == 1) && firstcap) {
         240               0 :         *pcaptype = INITCAP;
         241               0 :    } else if ((ncap == nc) || ((ncap + nneutral) == nc)){
         242               0 :         *pcaptype = ALLCAP;
         243               0 :    } else if ((ncap > 1) && firstcap) {
         244               0 :         *pcaptype = HUHINITCAP;
         245                 :    } else {
         246               0 :         *pcaptype = HUHCAP;
         247                 :    }
         248               0 :    return strlen(dest);
         249                 : }
         250                 :
         251               0 : void Hunspell::mkallcap(char * p)
         252                 : {
         253               0 :   if (utf8) {
         254                 :       w_char u[MAXWORDLEN];
         255               0 :       int nc = u8_u16(u, MAXWORDLEN, p);
         256                 :       unsigned short idx;
         257               0 :       for (int i = 0; i < nc; i++) {
         258               0 :          idx = (u[i].h << 8) + u[i].l;
         259               0 :          if (idx != unicodetoupper(idx, langnum)) {
         260               0 :             u[i].h = (unsigned char) (unicodetoupper(idx, langnum) >> 8);
         261               0 :             u[i].l = (unsigned char) (unicodetoupper(idx, langnum) & 0x00FF);
         262                 :          }
         263                 :       }
         264               0 :       u16_u8(p, MAXWORDUTF8LEN, u, nc);
         265                 :   } else {
         266               0 :     while (*p != '\0') {
         267               0 :         *p = csconv[((unsigned char) *p)].cupper;
         268               0 :         p++;
         269                 :     }
         270                 :   }
         271               0 : }
         272                 :
         273               0 : int Hunspell::mkallcap2(char * p, w_char * u, int nc)
         274                 : {
         275               0 :   if (utf8) {
         276                 :       unsigned short idx;
         277               0 :       for (int i = 0; i < nc; i++) {
         278               0 :          idx = (u[i].h << 8) + u[i].l;
         279               0 :          unsigned short up = unicodetoupper(idx, langnum);
         280               0 :          if (idx != up) {
         281               0 :             u[i].h = (unsigned char) (up >> 8);
         282               0 :             u[i].l = (unsigned char) (up & 0x00FF);
         283                 :          }
         284                 :       }
         285               0 :       u16_u8(p, MAXWORDUTF8LEN, u, nc);
         286               0 :       return strlen(p);
         287                 :   } else {
         288               0 :     while (*p != '\0') {
         289               0 :         *p = csconv[((unsigned char) *p)].cupper;
         290               0 :         p++;
         291                 :     }
         292                 :   }
         293               0 :   return nc;
         294                 : }
         295                 :
         296                 :
         297               0 : void Hunspell::mkallsmall(char * p)
         298                 : {
         299               0 :     while (*p != '\0') {
         300               0 :         *p = csconv[((unsigned char) *p)].clower;
         301               0 :         p++;
         302                 :     }
         303               0 : }
         304                 :
         305             145 : int Hunspell::mkallsmall2(char * p, w_char * u, int nc)
         306                 : {
         307             145 :   if (utf8) {
         308                 :       unsigned short idx;
         309             288 :       for (int i = 0; i < nc; i++) {
         310             256 :          idx = (u[i].h << 8) + u[i].l;
         311             256 :          unsigned short low = unicodetolower(idx, langnum);
         312             256 :          if (idx != low) {
         313             104 :             u[i].h = (unsigned char) (low >> 8);
         314             104 :             u[i].l = (unsigned char) (low & 0x00FF);
         315                 :          }
         316                 :       }
         317              32 :       u16_u8(p, MAXWORDUTF8LEN, u, nc);
         318              32 :       return strlen(p);
         319                 :   } else {
         320            1446 :     while (*p != '\0') {
         321            1220 :         *p = csconv[((unsigned char) *p)].clower;
         322            1220 :         p++;
         323                 :     }
         324                 :   }
         325             113 :   return nc;
         326                 : }
         327                 :
         328                 : // convert UTF-8 sharp S codes to latin 1
         329              30 : char * Hunspell::sharps_u8_l1(char * dest, char * source) {
         330              30 :     char * p = dest;
         331              30 :     *p = *source;
         332             441 :     for (p++, source++; *(source - 1); p++, source++) {
         333             411 :         *p = *source;
         334             411 :         if (*source == '\x9F') *--p = '\xDF';
         335                 :     }
         336              30 :     return dest;
         337                 : }
         338                 :
         339                 : // recursive search for right ss - sharp s permutations
         340             132 : hentry * Hunspell::spellsharps(char * base, char * pos, int n,
         341                 :         int repnum, char * tmp, int * info, char **root) {
         342             132 :     pos = strstr(pos, "ss");
         343             132 :     if (pos && (n < MAXSHARPS)) {
         344              60 :         *pos = '\xC3';
         345              60 :         *(pos + 1) = '\x9F';
         346              60 :         hentry * h = spellsharps(base, pos + 2, n + 1, repnum + 1, tmp, info, root);
         347              60 :         if (h) return h;
         348              50 :         *pos = 's';
         349              50 :         *(pos + 1) = 's';
         350              50 :         h = spellsharps(base, pos + 2, n + 1, repnum, tmp, info, root);
         351              50 :         if (h) return h;
         352              72 :     } else if (repnum > 0) {
         353              60 :         if (utf8) return checkword(base, info, root);
         354              30 :         return checkword(sharps_u8_l1(tmp, base), info, root);
         355                 :     }
         356              54 :     return NULL;
         357                 : }
         358                 :
         359              85 : int Hunspell::is_keepcase(const hentry * rv) {
         360              51 :     return pAMgr && rv->astr && pAMgr->get_keepcase() &&
         361             136 :         TESTAFF(rv->astr, pAMgr->get_keepcase(), rv->alen);
         362                 : }
         363                 :
         364                 : /* insert a word to the beginning of the suggestion array and return ns */
         365               0 : int Hunspell::insert_sug(char ***slst, char * word, int ns) {
         366               0 :     char * dup = mystrdup(word);
         367               0 :     if (!dup) return ns;
         368               0 :     if (ns == MAXSUGGESTION) {
         369               0 :         ns--;
         370               0 :         free((*slst)[ns]);
         371                 :     }
         372               0 :     for (int k = ns; k > 0; k--) (*slst)[k] = (*slst)[k - 1];
         373               0 :     (*slst)[0] = dup;
         374               0 :     return ns + 1;
         375                 : }
         376                 :
         377            1083 : int Hunspell::spell(const char * word, int * info, char ** root)
         378                 : {
         379            1083 :   struct hentry * rv=NULL;
         380                 :   // need larger vector. For example, Turkish capital letter I converted a
         381                 :   // 2-byte UTF-8 character (dotless i) by mkallsmall.
         382                 :   char cw[MAXWORDUTF8LEN];
         383                 :   char wspace[MAXWORDUTF8LEN];
         384                 :   w_char unicw[MAXWORDLEN];
         385                 :   // Hunspell supports XML input of the simplified API (see manual)
         386            1083 :   if (strcmp(word, SPELL_XML) == 0) return 1;
         387            1083 :   int nc = strlen(word);
         388            1083 :   int wl2 = 0;
         389            1083 :   if (utf8) {
         390             236 :     if (nc >= MAXWORDUTF8LEN) return 0;
         391                 :   } else {
         392             847 :     if (nc >= MAXWORDLEN) return 0;
         393                 :   }
         394            1083 :   int captype = 0;
         395            1083 :   int abbv = 0;
         396            1083 :   int wl = 0;
         397                 :
         398                 :   // input conversion
         399            1083 :   RepList * rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL;
         400            1083 :   if (rl && rl->conv(word, wspace)) wl = cleanword2(cw, wspace, unicw, &nc, &captype, &abbv);
         401            1080 :   else wl = cleanword2(cw, word, unicw, &nc, &captype, &abbv);
         402                 :
         403            1083 :   int info2 = 0;
         404            1083 :   if (wl == 0 || maxdic == 0) return 1;
         405            1081 :   if (root) *root = NULL;
         406                 :
         407                 :   // allow numbers with dots, dashes and commas (but forbid double separators: "..", "--" etc.)
         408                 :   enum { NBEGIN, NNUM, NSEP };
         409            1081 :   int nstate = NBEGIN;
         410                 :   int i;
         411                 :
         412            1395 :   for (i = 0; (i < wl); i++) {
         413            1375 :     if ((cw[i] <= '9') && (cw[i] >= '0')) {
         414             297 :         nstate = NNUM;
         415            1078 :     } else if ((cw[i] == ',') || (cw[i] == '.') || (cw[i] == '-')) {
         416              23 :         if ((nstate == NSEP) || (i == 0)) break;
         417              17 :         nstate = NSEP;
         418            1055 :     } else break;
         419                 :   }
         420            1081 :   if ((i == wl) && (nstate == NNUM)) return 1;
         421            1061 :   if (!info) info = &info2; else *info = 0;
         422                 :
         423            1061 :   switch(captype) {
         424                 :      case HUHCAP:
         425                 :      case HUHINITCAP:
         426              69 :             *info += SPELL_ORIGCAP;
         427                 :      case NOCAP: {
         428             909 :             rv = checkword(cw, info, root);
         429             909 :             if ((abbv) && !(rv)) {
         430               2 :                 memcpy(wspace,cw,wl);
         431               2 :                 *(wspace+wl) = '.';
         432               2 :                 *(wspace+wl+1) = '\0';
         433               2 :                 rv = checkword(wspace, info, root);
         434                 :             }
         435             909 :             break;
         436                 :          }
         437                 :      case ALLCAP: {
         438              36 :             *info += SPELL_ORIGCAP;
         439              36 :             rv = checkword(cw, info, root);
         440              36 :             if (rv) break;
         441              27 :             if (abbv) {
         442               5 :                 memcpy(wspace,cw,wl);
         443               5 :                 *(wspace+wl) = '.';
         444               5 :                 *(wspace+wl+1) = '\0';
         445               5 :                 rv = checkword(wspace, info, root);
         446               5 :                 if (rv) break;
         447                 :             }
         448                 :             // Spec. prefix handling for Catalan, French, Italian:
         449                 :             // prefixes separated by apostrophe (SANT'ELIA -> Sant'+Elia).
         450              27 :             if (pAMgr && strchr(cw, '\'')) {
         451               2 :                 wl = mkallsmall2(cw, unicw, nc);
         452                 :                 //There are no really sane circumstances where this could fail,
         453                 :                 //but anyway...
         454               2 :                 if (char * apostrophe = strchr(cw, '\'')) {
         455               2 :                     if (utf8) {
         456                 :                         w_char tmpword[MAXWORDLEN];
         457               0 :                         *apostrophe = '\0';
         458               0 :                         wl2 = u8_u16(tmpword, MAXWORDLEN, cw);
         459               0 :                         *apostrophe = '\'';
         460               0 :                         if (wl2 < nc) {
         461               0 :                             mkinitcap2(apostrophe + 1, unicw + wl2 + 1, nc - wl2 - 1);
         462               0 :                             rv = checkword(cw, info, root);
         463               0 :                             if (rv) break;
         464                 :                         }
         465                 :                     } else {
         466               2 :                         mkinitcap2(apostrophe + 1, unicw, nc);
         467               2 :                         rv = checkword(cw, info, root);
         468               2 :                         if (rv) break;
         469                 :                     }
         470                 :                 }
         471               2 :                 mkinitcap2(cw, unicw, nc);
         472               2 :                 rv = checkword(cw, info, root);
         473               2 :                 if (rv) break;
         474                 :             }
         475              27 :             if (pAMgr && pAMgr->get_checksharps() && strstr(cw, "SS")) {
         476                 :                 char tmpword[MAXWORDUTF8LEN];
         477              10 :                 wl = mkallsmall2(cw, unicw, nc);
         478              10 :                 memcpy(wspace,cw,(wl+1));
         479              10 :                 rv = spellsharps(wspace, wspace, 0, 0, tmpword, info, root);
         480              10 :                 if (!rv) {
         481               8 :                     wl2 = mkinitcap2(cw, unicw, nc);
         482               8 :                     rv = spellsharps(cw, cw, 0, 0, tmpword, info, root);
         483                 :                 }
         484              10 :                 if ((abbv) && !(rv)) {
         485               2 :                     *(wspace+wl) = '.';
         486               2 :                     *(wspace+wl+1) = '\0';
         487               2 :                     rv = spellsharps(wspace, wspace, 0, 0, tmpword, info, root);
         488               2 :                     if (!rv) {
         489               2 :                         memcpy(wspace, cw, wl2);
         490               2 :                         *(wspace+wl2) = '.';
         491               2 :                         *(wspace+wl2+1) = '\0';
         492               2 :                         rv = spellsharps(wspace, wspace, 0, 0, tmpword, info, root);
         493                 :                     }
         494                 :                 }
         495              10 :                 if (rv) break;
         496                 :             }
         497                 :         }
         498                 :      case INITCAP: {
         499             133 :              *info += SPELL_ORIGCAP;
         500             133 :              wl = mkallsmall2(cw, unicw, nc);
         501             133 :              memcpy(wspace,cw,(wl+1));
         502             133 :              wl2 = mkinitcap2(cw, unicw, nc);
         503             133 :              if (captype == INITCAP) *info += SPELL_INITCAP;
         504             133 :              rv = checkword(cw, info, root);
         505             133 :              if (captype == INITCAP) *info -= SPELL_INITCAP;
         506                 :              // forbid bad capitalization
         507                 :              // (for example, ijs -> Ijs instead of IJs in Dutch)
         508                 :              // use explicit forms in dic: Ijs/F (F = FORBIDDENWORD flag)
         509             133 :              if (*info & SPELL_FORBIDDEN) {
         510               2 :                 rv = NULL;
         511               2 :                 break;
         512                 :              }
         513             131 :              if (rv && is_keepcase(rv) && (captype == ALLCAP)) rv = NULL;
         514             131 :              if (rv) break;
         515                 :
         516              73 :              rv = checkword(wspace, info, root);
         517              73 :              if (abbv && !rv) {
         518                 :
         519               4 :                  *(wspace+wl) = '.';
         520               4 :                  *(wspace+wl+1) = '\0';
         521               4 :                  rv = checkword(wspace, info, root);
         522               4 :                  if (!rv) {
         523               2 :                     memcpy(wspace, cw, wl2);
         524               2 :                     *(wspace+wl2) = '.';
         525               2 :                     *(wspace+wl2+1) = '\0';
         526               2 :                     if (captype == INITCAP) *info += SPELL_INITCAP;
         527               2 :                     rv = checkword(wspace, info, root);
         528               2 :                     if (captype == INITCAP) *info -= SPELL_INITCAP;
         529               2 :                     if (rv && is_keepcase(rv) && (captype == ALLCAP)) rv = NULL;
         530               2 :                     break;
         531                 :                  }
         532                 :              }
         533              81 :              if (rv && is_keepcase(rv) &&
         534                 :                 ((captype == ALLCAP) ||
         535                 :                    // if CHECKSHARPS: KEEPCASE words with \xDF  are allowed
         536                 :                    // in INITCAP form, too.
         537               5 :                    !(pAMgr->get_checksharps() &&
         538               1 :                       ((utf8 && strstr(wspace, "\xC3\x9F")) ||
         539               8 :                       (!utf8 && strchr(wspace, '\xDF')))))) rv = NULL;
         540              71 :              break;
         541                 :            }
         542                 :   }
         543                 :
         544            1061 :   if (rv) {
         545             557 :       if (pAMgr && pAMgr->get_warn() && rv->astr &&
         546               1 :           TESTAFF(rv->astr, pAMgr->get_warn(), rv->alen)) {
         547               1 :               *info += SPELL_WARN;
         548               1 :               if (pAMgr->get_forbidwarn()) return 0;
         549               1 :               return HUNSPELL_OK_WARN;
         550                 :       }
         551             555 :       return HUNSPELL_OK;
         552                 :   }
         553                 :
         554                 :   // recursive breaking at break points
         555             505 :   if (wordbreak) {
         556                 :     char * s;
         557                 :     char r;
         558             501 :     int nbr = 0;
         559             501 :     wl = strlen(cw);
         560             501 :     int numbreak = pAMgr ? pAMgr->get_numbreak() : 0;
         561                 :
         562                 :     // calculate break points for recursion limit
         563            1957 :     for (int j = 0; j < numbreak; j++) {
         564            1456 :       s = cw;
         565            1504 :       do {
         566            1504 :         s = (char *) strstr(s, wordbreak[j]);
         567            1504 :         if (s) {
         568              48 :                 nbr++;
         569              48 :                 s++;
         570                 :         }
         571                 :       } while (s);
         572                 :     }
         573             501 :     if (nbr >= 10) return 0;
         574                 :
         575                 :     // check boundary patterns (^begin and end$)
         576            1954 :     for (int j = 0; j < numbreak; j++) {
         577            1455 :       int plen = strlen(wordbreak[j]);
         578            1455 :       if (plen == 1 || plen > wl) continue;
         579             947 :       if (wordbreak[j][0] == '^' && strncmp(cw, wordbreak[j] + 1, plen - 1) == 0
         580               2 :         && spell(cw + plen - 1)) return 1;
         581            1401 :       if (wordbreak[j][plen - 1] == '$' &&
         582             456 :         strncmp(cw + wl - plen + 1, wordbreak[j], plen - 1) == 0) {
         583               5 :             r = cw[wl - plen + 1];
         584               5 :             cw[wl - plen + 1] = '\0';
         585               5 :             if (spell(cw)) return 1;
         586               4 :             cw[wl - plen + 1] = r;
         587                 :         }
         588                 :     }
         589                 :
         590                 :     // other patterns
         591            1935 :     for (int j = 0; j < numbreak; j++) {
         592            1443 :       int plen = strlen(wordbreak[j]);
         593            1443 :       s=(char *) strstr(cw, wordbreak[j]);
         594            1443 :       if (s && (s > cw) && (s < cw + wl - plen)) {
         595              30 :         if (!spell(s + plen)) continue;
         596              17 :         r = *s;
         597              17 :         *s = '\0';
         598                 :         // examine 2 sides of the break point
         599              17 :         if (spell(cw)) return 1;
         600              10 :         *s = r;
         601                 :
         602                 :         // LANG_hu: spec. dash rule
         603              10 :         if (langnum == LANG_hu && strcmp(wordbreak[j], "-") == 0) {
         604               0 :           r = s[1];
         605               0 :           s[1] = '\0';
         606               0 :           if (spell(cw)) return 1; // check the first part with dash
         607               0 :           s[1] = r;
         608                 :         }
         609                 :         // end of LANG speficic region
         610                 :
         611                 :       }
         612                 :     }
         613                 :   }
         614                 :
         615             496 :   return 0;
         616                 : }
         617                 :
         618            1228 : struct hentry * Hunspell::checkword(const char * w, int * info, char ** root)
         619                 : {
         620            1228 :   struct hentry * he = NULL;
         621                 :   int len, i;
         622                 :   char w2[MAXWORDUTF8LEN];
         623                 :   const char * word;
         624                 :
         625            1228 :   char * ignoredchars = pAMgr->get_ignore();
         626            1228 :   if (ignoredchars != NULL) {
         627              15 :      strcpy(w2, w);
         628              15 :      if (utf8) {
         629                 :         int ignoredchars_utf16_len;
         630              10 :         unsigned short * ignoredchars_utf16 = pAMgr->get_ignore_utf16(&ignoredchars_utf16_len);
         631              10 :         remove_ignored_chars_utf(w2, ignoredchars_utf16, ignoredchars_utf16_len);
         632                 :      } else {
         633               5 :         remove_ignored_chars(w2,ignoredchars);
         634                 :      }
         635              15 :      word = w2;
         636            1213 :   } else word = w;
         637                 :
         638            1228 :   len = strlen(word);
         639                 :
         640            1228 :   if (!len)
         641               0 :       return NULL;
         642                 :
         643                 :   // word reversing wrapper for complex prefixes
         644            1228 :   if (complexprefixes) {
         645              12 :     if (word != w2) {
         646              12 :       strcpy(w2, word);
         647              12 :       word = w2;
         648                 :     }
         649              12 :     if (utf8) reverseword_utf(w2); else reverseword(w2);
         650                 :   }
         651                 :
         652                 :   // look word in hash table
         653            2450 :   for (i = 0; (i < maxdic) && !he; i ++) {
         654            1228 :   he = (pHMgr[i])->lookup(word);
         655                 :
         656                 :   // check forbidden and onlyincompound words
         657            1228 :   if ((he) && (he->astr) && (pAMgr) && TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) {
         658               6 :     if (info) *info += SPELL_FORBIDDEN;
         659                 :     // LANG_hu section: set dash information for suggestions
         660               6 :     if (langnum == LANG_hu) {
         661               0 :         if (pAMgr->get_compoundflag() &&
         662               0 :             TESTAFF(he->astr, pAMgr->get_compoundflag(), he->alen)) {
         663               0 :                 if (info) *info += SPELL_COMPOUND;
         664                 :         }
         665                 :     }
         666               6 :     return NULL;
         667                 :   }
         668                 :
         669                 :   // he = next not needaffix, onlyincompound homonym or onlyupcase word
         670            2810 :   while (he && (he->astr) &&
         671             146 :     ((pAMgr->get_needaffix() && TESTAFF(he->astr, pAMgr->get_needaffix(), he->alen)) ||
         672             183 :        (pAMgr->get_onlyincompound() && TESTAFF(he->astr, pAMgr->get_onlyincompound(), he->alen)) ||
         673              16 :        (info && (*info & SPELL_INITCAP) && TESTAFF(he->astr, ONLYUPCASEFLAG, he->alen))
         674              21 :     )) he = he->next_homonym;
         675                 :   }
         676                 :
         677                 :   // check with affixes
         678            1222 :   if (!he && pAMgr) {
         679                 :      // try stripping off affixes */
         680             992 :      he = pAMgr->affix_check(word, len, 0);
         681                 :
         682                 :      // check compound restriction and onlyupcase
         683            1142 :      if (he && he->astr && (
         684             144 :         (pAMgr->get_onlyincompound() &&
         685               2 :             TESTAFF(he->astr, pAMgr->get_onlyincompound(), he->alen)) ||
         686                 :         (info && (*info & SPELL_INITCAP) &&
         687               4 :             TESTAFF(he->astr, ONLYUPCASEFLAG, he->alen)))) {
         688               0 :             he = NULL;
         689                 :      }
         690                 :
         691             992 :      if (he) {
         692             144 :         if ((he->astr) && (pAMgr) && TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) {
         693               2 :             if (info) *info += SPELL_FORBIDDEN;
         694               2 :             return NULL;
         695                 :         }
         696             142 :         if (root) {
         697               0 :             *root = mystrdup(he->word);
         698               0 :             if (*root && complexprefixes) {
         699               0 :                 if (utf8) reverseword_utf(*root); else reverseword(*root);
         700                 :             }
         701                 :         }
         702                 :      // try check compound word
         703             848 :      } else if (pAMgr->get_compound()) {
         704             470 :           he = pAMgr->compound_check(word, len, 0, 0, 100, 0, NULL, 0, 0, info);
         705                 :           // LANG_hu section: `moving rule' with last dash
         706             470 :           if ((!he) && (langnum == LANG_hu) && (word[len-1] == '-')) {
         707               0 :              char * dup = mystrdup(word);
         708               0 :              if (!dup) return NULL;
         709               0 :              dup[len-1] = '\0';
         710               0 :              he = pAMgr->compound_check(dup, len-1, -5, 0, 100, 0, NULL, 1, 0, info);
         711               0 :              free(dup);
         712                 :           }
         713                 :           // end of LANG speficic region
         714             470 :           if (he) {
         715             190 :                 if (root) {
         716               0 :                     *root = mystrdup(he->word);
         717               0 :                     if (*root && complexprefixes) {
         718               0 :                         if (utf8) reverseword_utf(*root); else reverseword(*root);
         719                 :                     }
         720                 :                 }
         721             190 :                 if (info) *info += SPELL_COMPOUND;
         722                 :           }
         723                 :      }
         724                 :
         725                 :   }
         726                 :
         727            1220 :   return he;
         728                 : }
         729                 :
         730               0 : int Hunspell::suggest(char*** slst, const char * word)
         731                 : {
         732               0 :   int onlycmpdsug = 0;
         733                 :   char cw[MAXWORDUTF8LEN];
         734                 :   char wspace[MAXWORDUTF8LEN];
         735               0 :   if (!pSMgr || maxdic == 0) return 0;
         736                 :   w_char unicw[MAXWORDLEN];
         737               0 :   *slst = NULL;
         738                 :   // process XML input of the simplified API (see manual)
         739               0 :   if (strncmp(word, SPELL_XML, sizeof(SPELL_XML) - 3) == 0) {
         740               0 :      return spellml(slst, word);
         741                 :   }
         742               0 :   int nc = strlen(word);
         743               0 :   if (utf8) {
         744               0 :     if (nc >= MAXWORDUTF8LEN) return 0;
         745                 :   } else {
         746               0 :     if (nc >= MAXWORDLEN) return 0;
         747                 :   }
         748               0 :   int captype = 0;
         749               0 :   int abbv = 0;
         750               0 :   int wl = 0;
         751                 :
         752                 :   // input conversion
         753               0 :   RepList * rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL;
         754               0 :   if (rl && rl->conv(word, wspace)) wl = cleanword2(cw, wspace, unicw, &nc, &captype, &abbv);
         755               0 :   else wl = cleanword2(cw, word, unicw, &nc, &captype, &abbv);
         756                 :
         757               0 :   if (wl == 0) return 0;
         758               0 :   int ns = 0;
         759               0 :   int capwords = 0;
         760                 :
         761                 :   // check capitalized form for FORCEUCASE
         762               0 :   if (pAMgr && captype == NOCAP && pAMgr->get_forceucase()) {
         763               0 :     int info = SPELL_ORIGCAP;
         764                 :     char ** wlst;
         765               0 :     if (checkword(cw, &info, NULL)) {
         766               0 :         if (*slst) {
         767               0 :             wlst = *slst;
         768                 :         } else {
         769               0 :             wlst = (char **) malloc(MAXSUGGESTION * sizeof(char *));
         770               0 :             if (wlst == NULL) return -1;
         771               0 :             *slst = wlst;
         772               0 :             for (int i = 0; i < MAXSUGGESTION; i++) {
         773               0 :                 wlst[i] = NULL;
         774                 :             }
         775                 :         }
         776               0 :         wlst[0] = mystrdup(cw);
         777               0 :         mkinitcap(wlst[0]);
         778               0 :         return 1;
         779                 :     }
         780                 :   }
         781                 :
         782               0 :   switch(captype) {
         783                 :      case NOCAP:   {
         784               0 :                      ns = pSMgr->suggest(slst, cw, ns, &onlycmpdsug);
         785               0 :                      break;
         786                 :                    }
         787                 :
         788                 :      case INITCAP: {
         789               0 :                      capwords = 1;
         790               0 :                      ns = pSMgr->suggest(slst, cw, ns, &onlycmpdsug);
         791               0 :                      if (ns == -1) break;
         792               0 :                      memcpy(wspace,cw,(wl+1));
         793               0 :                      mkallsmall2(wspace, unicw, nc);
         794               0 :                      ns = pSMgr->suggest(slst, wspace, ns, &onlycmpdsug);
         795               0 :                      break;
         796                 :                    }
         797                 :      case HUHINITCAP:
         798               0 :                     capwords = 1;
         799                 :      case HUHCAP: {
         800               0 :                      ns = pSMgr->suggest(slst, cw, ns, &onlycmpdsug);
         801               0 :                      if (ns != -1) {
         802                 :                         int prevns;
         803                 :                         // something.The -> something. The
         804               0 :                         char * dot = strchr(cw, '.');
         805               0 :                         if (dot && (dot > cw)) {
         806                 :                             int captype_;
         807               0 :                             if (utf8) {
         808                 :                                w_char w_[MAXWORDLEN];
         809               0 :                                int wl_ = u8_u16(w_, MAXWORDLEN, dot + 1);
         810               0 :                                captype_ = get_captype_utf8(w_, wl_, langnum);
         811               0 :                             } else captype_ = get_captype(dot+1, strlen(dot+1), csconv);
         812               0 :                             if (captype_ == INITCAP) {
         813               0 :                                 char * st = mystrdup(cw);
         814               0 :                                 if (st) st = (char *) realloc(st, wl + 2);
         815               0 :                                 if (st) {
         816               0 :                                         st[(dot - cw) + 1] = ' ';
         817               0 :                                         strcpy(st + (dot - cw) + 2, dot + 1);
         818               0 :                                         ns = insert_sug(slst, st, ns);
         819               0 :                                         free(st);
         820                 :                                 }
         821                 :                             }
         822                 :                         }
         823               0 :                         if (captype == HUHINITCAP) {
         824                 :                             // TheOpenOffice.org -> The OpenOffice.org
         825               0 :                             memcpy(wspace,cw,(wl+1));
         826               0 :                             mkinitsmall2(wspace, unicw, nc);
         827               0 :                             ns = pSMgr->suggest(slst, wspace, ns, &onlycmpdsug);
         828                 :                         }
         829               0 :                         memcpy(wspace,cw,(wl+1));
         830               0 :                         mkallsmall2(wspace, unicw, nc);
         831               0 :                         if (spell(wspace)) ns = insert_sug(slst, wspace, ns);
         832               0 :                         prevns = ns;
         833               0 :                         ns = pSMgr->suggest(slst, wspace, ns, &onlycmpdsug);
         834               0 :                         if (captype == HUHINITCAP) {
         835               0 :                             mkinitcap2(wspace, unicw, nc);
         836               0 :                             if (spell(wspace)) ns = insert_sug(slst, wspace, ns);
         837               0 :                             ns = pSMgr->suggest(slst, wspace, ns, &onlycmpdsug);
         838                 :                         }
         839                 :                         // aNew -> "a New" (instead of "a new")
         840               0 :                         for (int j = prevns; j < ns; j++) {
         841               0 :                            char * space = strchr((*slst)[j],' ');
         842               0 :                            if (space) {
         843               0 :                                 int slen = strlen(space + 1);
         844                 :                                 // different case after space (need capitalisation)
         845               0 :                                 if ((slen < wl) && strcmp(cw + wl - slen, space + 1)) {
         846                 :                                     w_char w[MAXWORDLEN];
         847               0 :                                     int wc = 0;
         848               0 :                                     char * r = (*slst)[j];
         849               0 :                                     if (utf8) wc = u8_u16(w, MAXWORDLEN, space + 1);
         850               0 :                                     mkinitcap2(space + 1, w, wc);
         851                 :                                     // set as first suggestion
         852               0 :                                     for (int k = j; k > 0; k--) (*slst)[k] = (*slst)[k - 1];
         853               0 :                                     (*slst)[0] = r;
         854                 :                                 }
         855                 :                            }
         856                 :                         }
         857                 :                      }
         858               0 :                      break;
         859                 :                    }
         860                 :
         861                 :      case ALLCAP: {
         862               0 :                      memcpy(wspace, cw, (wl+1));
         863               0 :                      mkallsmall2(wspace, unicw, nc);
         864               0 :                      ns = pSMgr->suggest(slst, wspace, ns, &onlycmpdsug);
         865               0 :                      if (ns == -1) break;
         866               0 :                      if (pAMgr && pAMgr->get_keepcase() && spell(wspace))
         867               0 :                         ns = insert_sug(slst, wspace, ns);
         868               0 :                      mkinitcap2(wspace, unicw, nc);
         869               0 :                      ns = pSMgr->suggest(slst, wspace, ns, &onlycmpdsug);
         870               0 :                      for (int j=0; j < ns; j++) {
         871               0 :                         mkallcap((*slst)[j]);
         872               0 :                         if (pAMgr && pAMgr->get_checksharps()) {
         873                 :                             char * pos;
         874               0 :                             if (utf8) {
         875               0 :                                 pos = strstr((*slst)[j], "\xC3\x9F");
         876               0 :                                 while (pos) {
         877               0 :                                     *pos = 'S';
         878               0 :                                     *(pos+1) = 'S';
         879               0 :                                     pos = strstr(pos+2, "\xC3\x9F");
         880                 :                                 }
         881                 :                             } else {
         882               0 :                                 pos = strchr((*slst)[j], '\xDF');
         883               0 :                                 while (pos) {
         884               0 :                                     (*slst)[j] = (char *) realloc((*slst)[j], strlen((*slst)[j]) + 2);
         885               0 :                                     mystrrep((*slst)[j], "\xDF", "SS");
         886               0 :                                     pos = strchr((*slst)[j], '\xDF');
         887                 :                                 }
         888                 :                             }
         889                 :                         }
         890                 :                      }
         891               0 :                      break;
         892                 :                    }
         893                 :   }
         894                 :
         895                 :  // LANG_hu section: replace '-' with ' ' in Hungarian
         896               0 :   if (langnum == LANG_hu) {
         897               0 :       for (int j=0; j < ns; j++) {
         898               0 :           char * pos = strchr((*slst)[j],'-');
         899               0 :           if (pos) {
         900                 :               int info;
         901                 :               char w[MAXWORDUTF8LEN];
         902               0 :               *pos = '\0';
         903               0 :               strcpy(w, (*slst)[j]);
         904               0 :               strcat(w, pos + 1);
         905               0 :               spell(w, &info, NULL);
         906               0 :               if ((info & SPELL_COMPOUND) && (info & SPELL_FORBIDDEN)) {
         907               0 :                   *pos = ' ';
         908               0 :               } else *pos = '-';
         909                 :           }
         910                 :       }
         911                 :   }
         912                 :   // END OF LANG_hu section
         913                 :
         914                 :   // try ngram approach since found nothing or only compound words
         915               0 :   if (pAMgr && (ns == 0 || onlycmpdsug) && (pAMgr->get_maxngramsugs() != 0) && (*slst)) {
         916               0 :       switch(captype) {
         917                 :           case NOCAP: {
         918               0 :               ns = pSMgr->ngsuggest(*slst, cw, ns, pHMgr, maxdic);
         919               0 :               break;
         920                 :           }
         921                 :           case HUHINITCAP:
         922               0 :               capwords = 1;
         923                 :           case HUHCAP: {
         924               0 :               memcpy(wspace,cw,(wl+1));
         925               0 :               mkallsmall2(wspace, unicw, nc);
         926               0 :               ns = pSMgr->ngsuggest(*slst, wspace, ns, pHMgr, maxdic);
         927               0 :               break;
         928                 :           }
         929                 :          case INITCAP: {
         930               0 :               capwords = 1;
         931               0 :               memcpy(wspace,cw,(wl+1));
         932               0 :               mkallsmall2(wspace, unicw, nc);
         933               0 :               ns = pSMgr->ngsuggest(*slst, wspace, ns, pHMgr, maxdic);
         934               0 :               break;
         935                 :           }
         936                 :           case ALLCAP: {
         937               0 :               memcpy(wspace,cw,(wl+1));
         938               0 :               mkallsmall2(wspace, unicw, nc);
         939               0 :               int oldns = ns;
         940               0 :               ns = pSMgr->ngsuggest(*slst, wspace, ns, pHMgr, maxdic);
         941               0 :               for (int j = oldns; j < ns; j++)
         942               0 :                   mkallcap((*slst)[j]);
         943               0 :               break;
         944                 :          }
         945                 :       }
         946                 :   }
         947                 :
         948                 :   // try dash suggestion (Afo-American -> Afro-American)
         949               0 :   if (char * pos = strchr(cw, '-')) {
         950               0 :      char * ppos = cw;
         951               0 :      int nodashsug = 1;
         952               0 :      char ** nlst = NULL;
         953               0 :      int nn = 0;
         954               0 :      int last = 0;
         955               0 :      if (*slst) {
         956               0 :         for (int j = 0; j < ns && nodashsug == 1; j++) {
         957               0 :            if (strchr((*slst)[j], '-')) nodashsug = 0;
         958                 :         }
         959                 :      }
         960               0 :      while (nodashsug && !last) {
         961               0 :         if (*pos == '\0') last = 1; else *pos = '\0';
         962               0 :         if (!spell(ppos)) {
         963               0 :           nn = suggest(&nlst, ppos);
         964               0 :           for (int j = nn - 1; j >= 0; j--) {
         965               0 :             strncpy(wspace, cw, ppos - cw);
         966               0 :             strcpy(wspace + (ppos - cw), nlst[j]);
         967               0 :             if (!last) {
         968               0 :                 strcat(wspace, "-");
         969               0 :                 strcat(wspace, pos + 1);
         970                 :             }
         971               0 :             ns = insert_sug(slst, wspace, ns);
         972               0 :             free(nlst[j]);
         973                 :           }
         974               0 :           if (nlst != NULL) free(nlst);
         975               0 :           nodashsug = 0;
         976                 :         }
         977               0 :         if (!last) {
         978               0 :           *pos = '-';
         979               0 :           ppos = pos + 1;
         980               0 :           pos = strchr(ppos, '-');
         981                 :         }
         982               0 :         if (!pos) pos = cw + strlen(cw);
         983                 :      }
         984                 :   }
         985                 :
         986                 :   // word reversing wrapper for complex prefixes
         987               0 :   if (complexprefixes) {
         988               0 :     for (int j = 0; j < ns; j++) {
         989               0 :       if (utf8) reverseword_utf((*slst)[j]); else reverseword((*slst)[j]);
         990                 :     }
         991                 :   }
         992                 :
         993                 :   // capitalize
         994               0 :   if (capwords) for (int j=0; j < ns; j++) {
         995               0 :       mkinitcap((*slst)[j]);
         996                 :   }
         997                 :
         998                 :   // expand suggestions with dot(s)
         999               0 :   if (abbv && pAMgr && pAMgr->get_sugswithdots()) {
        1000               0 :     for (int j = 0; j < ns; j++) {
        1001               0 :       (*slst)[j] = (char *) realloc((*slst)[j], strlen((*slst)[j]) + 1 + abbv);
        1002               0 :       strcat((*slst)[j], word + strlen(word) - abbv);
        1003                 :     }
        1004                 :   }
        1005                 :
        1006                 :   // remove bad capitalized and forbidden forms
        1007               0 :   if (pAMgr && (pAMgr->get_keepcase() || pAMgr->get_forbiddenword())) {
        1008               0 :   switch (captype) {
        1009                 :     case INITCAP:
        1010                 :     case ALLCAP: {
        1011               0 :       int l = 0;
        1012               0 :       for (int j=0; j < ns; j++) {
        1013               0 :         if (!strchr((*slst)[j],' ') && !spell((*slst)[j])) {
        1014                 :           char s[MAXSWUTF8L];
        1015                 :           w_char w[MAXSWL];
        1016                 :           int len;
        1017               0 :           if (utf8) {
        1018               0 :             len = u8_u16(w, MAXSWL, (*slst)[j]);
        1019                 :           } else {
        1020               0 :             strcpy(s, (*slst)[j]);
        1021               0 :             len = strlen(s);
        1022                 :           }
        1023               0 :           mkallsmall2(s, w, len);
        1024               0 :           free((*slst)[j]);
        1025               0 :           if (spell(s)) {
        1026               0 :             (*slst)[l] = mystrdup(s);
        1027               0 :             if ((*slst)[l]) l++;
        1028                 :           } else {
        1029               0 :             mkinitcap2(s, w, len);
        1030               0 :             if (spell(s)) {
        1031               0 :               (*slst)[l] = mystrdup(s);
        1032               0 :               if ((*slst)[l]) l++;
        1033                 :             }
        1034                 :           }
        1035                 :         } else {
        1036               0 :           (*slst)[l] = (*slst)[j];
        1037               0 :           l++;
        1038                 :         }
        1039                 :       }
        1040               0 :       ns = l;
        1041                 :     }
        1042                 :   }
        1043                 :   }
        1044                 :
        1045                 :   // remove duplications
        1046               0 :   int l = 0;
        1047               0 :   for (int j = 0; j < ns; j++) {
        1048               0 :     (*slst)[l] = (*slst)[j];
        1049               0 :     for (int k = 0; k < l; k++) {
        1050               0 :       if (strcmp((*slst)[k], (*slst)[j]) == 0) {
        1051               0 :         free((*slst)[j]);
        1052               0 :         l--;
        1053               0 :         break;
        1054                 :       }
        1055                 :     }
        1056               0 :     l++;
        1057                 :   }
        1058               0 :   ns = l;
        1059                 :
        1060                 :   // output conversion
        1061               0 :   rl = (pAMgr) ? pAMgr->get_oconvtable() : NULL;
        1062               0 :   for (int j = 0; rl && j < ns; j++) {
        1063               0 :     if (rl->conv((*slst)[j], wspace)) {
        1064               0 :       free((*slst)[j]);
        1065               0 :       (*slst)[j] = mystrdup(wspace);
        1066                 :     }
        1067                 :   }
        1068                 :
        1069                 :   // if suggestions removed by nosuggest, onlyincompound parameters
        1070               0 :   if (l == 0 && *slst) {
        1071               0 :     free(*slst);
        1072               0 :     *slst = NULL;
        1073                 :   }
        1074               0 :   return l;
        1075                 : }
        1076                 :
        1077               0 : void Hunspell::free_list(char *** slst, int n) {
        1078               0 :         freelist(slst, n);
        1079               0 : }
        1080                 :
        1081             220 : char * Hunspell::get_dic_encoding()
        1082                 : {
        1083             220 :   return encoding;
        1084                 : }
        1085                 :
        1086                 : #ifdef HUNSPELL_EXPERIMENTAL
        1087                 : // XXX need UTF-8 support
        1088                 : int Hunspell::suggest_auto(char*** slst, const char * word)
        1089                 : {
        1090                 :   char cw[MAXWORDUTF8LEN];
        1091                 :   char wspace[MAXWORDUTF8LEN];
        1092                 :   if (!pSMgr || maxdic == 0) return 0;
        1093                 :   int wl = strlen(word);
        1094                 :   if (utf8) {
        1095                 :     if (wl >= MAXWORDUTF8LEN) return 0;
        1096                 :   } else {
        1097                 :     if (wl >= MAXWORDLEN) return 0;
        1098                 :   }
        1099                 :   int captype = 0;
        1100                 :   int abbv = 0;
        1101                 :   wl = cleanword(cw, word, &captype, &abbv);
        1102                 :   if (wl == 0) return 0;
        1103                 :   int ns = 0;
        1104                 :   *slst = NULL; // HU, nsug in pSMgr->suggest
        1105                 :
        1106                 :   switch(captype) {
        1107                 :      case NOCAP:   {
        1108                 :                      ns = pSMgr->suggest_auto(slst, cw, ns);
        1109                 :                      if (ns>0) break;
        1110                 :                      break;
        1111                 :                    }
        1112                 :
        1113                 :      case INITCAP: {
        1114                 :                      memcpy(wspace,cw,(wl+1));
        1115                 :                      mkallsmall(wspace);
        1116                 :                      ns = pSMgr->suggest_auto(slst, wspace, ns);
        1117                 :                      for (int j=0; j < ns; j++)
        1118                 :                        mkinitcap((*slst)[j]);
        1119                 :                      ns = pSMgr->suggest_auto(slst, cw, ns);
        1120                 :                      break;
        1121                 :
        1122                 :                    }
        1123                 :
        1124                 :      case HUHINITCAP:
        1125                 :      case HUHCAP: {
        1126                 :                      ns = pSMgr->suggest_auto(slst, cw, ns);
        1127                 :                      if (ns == 0) {
        1128                 :                         memcpy(wspace,cw,(wl+1));
        1129                 :                         mkallsmall(wspace);
        1130                 :                         ns = pSMgr->suggest_auto(slst, wspace, ns);
        1131                 :                      }
        1132                 :                      break;
        1133                 :                    }
        1134                 :
        1135                 :      case ALLCAP: {
        1136                 :                      memcpy(wspace,cw,(wl+1));
        1137                 :                      mkallsmall(wspace);
        1138                 :                      ns = pSMgr->suggest_auto(slst, wspace, ns);
        1139                 :
        1140                 :                      mkinitcap(wspace);
        1141                 :                      ns = pSMgr->suggest_auto(slst, wspace, ns);
        1142                 :
        1143                 :                      for (int j=0; j < ns; j++)
        1144                 :                        mkallcap((*slst)[j]);
        1145                 :                      break;
        1146                 :                    }
        1147                 :   }
        1148                 :
        1149                 :   // word reversing wrapper for complex prefixes
        1150                 :   if (complexprefixes) {
        1151                 :     for (int j = 0; j < ns; j++) {
        1152                 :       if (utf8) reverseword_utf((*slst)[j]); else reverseword((*slst)[j]);
        1153                 :     }
        1154                 :   }
        1155                 :
        1156                 :   // expand suggestions with dot(s)
        1157                 :   if (abbv && pAMgr && pAMgr->get_sugswithdots()) {
        1158                 :     for (int j = 0; j < ns; j++) {
        1159                 :       (*slst)[j] = (char *) realloc((*slst)[j], strlen((*slst)[j]) + 1 + abbv);
        1160                 :       strcat((*slst)[j], word + strlen(word) - abbv);
        1161                 :     }
        1162                 :   }
        1163                 :
        1164                 :   // LANG_hu section: replace '-' with ' ' in Hungarian
        1165                 :   if (langnum == LANG_hu) {
        1166                 :       for (int j=0; j < ns; j++) {
        1167                 :           char * pos = strchr((*slst)[j],'-');
        1168                 :           if (pos) {
        1169                 :               int info;
        1170                 :               char w[MAXWORDUTF8LEN];
        1171                 :               *pos = '\0';
        1172                 :               strcpy(w, (*slst)[j]);
        1173                 :               strcat(w, pos + 1);
        1174                 :               spell(w, &info, NULL);
        1175                 :               if ((info & SPELL_COMPOUND) && (info & SPELL_FORBIDDEN)) {
        1176                 :                   *pos = ' ';
        1177                 :               } else *pos = '-';
        1178                 :           }
        1179                 :       }
        1180                 :   }
        1181                 :   // END OF LANG_hu section
        1182                 :   return ns;
        1183                 : }
        1184                 : #endif
        1185                 :
        1186               0 : int Hunspell::stem(char*** slst, char ** desc, int n)
        1187                 : {
        1188                 :   char result[MAXLNLEN];
        1189                 :   char result2[MAXLNLEN];
        1190               0 :   *slst = NULL;
        1191               0 :   if (n == 0) return 0;
        1192               0 :   *result2 = '\0';
        1193               0 :   for (int i = 0; i < n; i++) {
        1194               0 :     *result = '\0';
        1195                 :     // add compound word parts (except the last one)
        1196               0 :     char * s = (char *) desc[i];
        1197               0 :     char * part = strstr(s, MORPH_PART);
        1198               0 :     if (part) {
        1199               0 :         char * nextpart = strstr(part + 1, MORPH_PART);
        1200               0 :         while (nextpart) {
        1201               0 :             copy_field(result + strlen(result), part, MORPH_PART);
        1202               0 :             part = nextpart;
        1203               0 :             nextpart = strstr(part + 1, MORPH_PART);
        1204                 :         }
        1205               0 :         s = part;
        1206                 :     }
        1207                 :
        1208                 :     char **pl;
        1209                 :     char tok[MAXLNLEN];
        1210               0 :     strcpy(tok, s);
        1211               0 :     char * alt = strstr(tok, " | ");
        1212               0 :     while (alt) {
        1213               0 :         alt[1] = MSEP_ALT;
        1214               0 :         alt = strstr(alt, " | ");
        1215                 :     }
        1216               0 :     int pln = line_tok(tok, &pl, MSEP_ALT);
        1217               0 :     for (int k = 0; k < pln; k++) {
        1218                 :         // add derivational suffixes
        1219               0 :         if (strstr(pl[k], MORPH_DERI_SFX)) {
        1220                 :             // remove inflectional suffixes
        1221               0 :             char * is = strstr(pl[k], MORPH_INFL_SFX);
        1222               0 :             if (is) *is = '\0';
        1223               0 :             char * sg = pSMgr->suggest_gen(&(pl[k]), 1, pl[k]);
        1224               0 :             if (sg) {
        1225                 :                 char ** gen;
        1226               0 :                 int genl = line_tok(sg, &gen, MSEP_REC);
        1227               0 :                 free(sg);
        1228               0 :                 for (int j = 0; j < genl; j++) {
        1229               0 :                     sprintf(result2 + strlen(result2), "%c%s%s",
        1230               0 :                             MSEP_REC, result, gen[j]);
        1231                 :                 }
        1232               0 :                 freelist(&gen, genl);
        1233                 :             }
        1234                 :         } else {
        1235               0 :             sprintf(result2 + strlen(result2), "%c%s", MSEP_REC, result);
        1236               0 :             if (strstr(pl[k], MORPH_SURF_PFX)) {
        1237               0 :                 copy_field(result2 + strlen(result2), pl[k], MORPH_SURF_PFX);
        1238                 :             }
        1239               0 :             copy_field(result2 + strlen(result2), pl[k], MORPH_STEM);
        1240                 :         }
        1241                 :     }
        1242               0 :     freelist(&pl, pln);
        1243                 :   }
        1244               0 :   int sln = line_tok(result2, slst, MSEP_REC);
        1245               0 :   return uniqlist(*slst, sln);
        1246                 :
        1247                 : }
        1248                 :
        1249               0 : int Hunspell::stem(char*** slst, const char * word)
        1250                 : {
        1251                 :   char ** pl;
        1252               0 :   int pln = analyze(&pl, word);
        1253               0 :   int pln2 = stem(slst, pl, pln);
        1254               0 :   freelist(&pl, pln);
        1255               0 :   return pln2;
        1256                 : }
        1257                 :
        1258                 : #ifdef HUNSPELL_EXPERIMENTAL
        1259                 : int Hunspell::suggest_pos_stems(char*** slst, const char * word)
        1260                 : {
        1261                 :   char cw[MAXWORDUTF8LEN];
        1262                 :   char wspace[MAXWORDUTF8LEN];
        1263                 :   if (! pSMgr || maxdic == 0) return 0;
        1264                 :   int wl = strlen(word);
        1265                 :   if (utf8) {
        1266                 :     if (wl >= MAXWORDUTF8LEN) return 0;
        1267                 :   } else {
        1268                 :     if (wl >= MAXWORDLEN) return 0;
        1269                 :   }
        1270                 :   int captype = 0;
        1271                 :   int abbv = 0;
        1272                 :   wl = cleanword(cw, word, &captype, &abbv);
        1273                 :   if (wl == 0) return 0;
        1274                 :
        1275                 :   int ns = 0; // ns=0 = normalized input
        1276                 :
        1277                 :   *slst = NULL; // HU, nsug in pSMgr->suggest
        1278                 :
        1279                 :   switch(captype) {
        1280                 :      case HUHCAP:
        1281                 :      case NOCAP:   {
        1282                 :                      ns = pSMgr->suggest_pos_stems(slst, cw, ns);
        1283                 :
        1284                 :                      if ((abbv) && (ns == 0)) {
        1285                 :                          memcpy(wspace,cw,wl);
        1286                 :                          *(wspace+wl) = '.';
        1287                 :                          *(wspace+wl+1) = '\0';
        1288                 :                          ns = pSMgr->suggest_pos_stems(slst, wspace, ns);
        1289                 :                      }
        1290                 :
        1291                 :                      break;
        1292                 :                    }
        1293                 :
        1294                 :      case INITCAP: {
        1295                 :
        1296                 :                      ns = pSMgr->suggest_pos_stems(slst, cw, ns);
        1297                 :
        1298                 :                      if (ns == 0 || ((*slst)[0][0] == '#')) {
        1299                 :                         memcpy(wspace,cw,(wl+1));
        1300                 :                         mkallsmall(wspace);
        1301                 :                         ns = pSMgr->suggest_pos_stems(slst, wspace, ns);
        1302                 :                      }
        1303                 :
        1304                 :                      break;
        1305                 :
        1306                 :                    }
        1307                 :
        1308                 :      case ALLCAP: {
        1309                 :                      ns = pSMgr->suggest_pos_stems(slst, cw, ns);
        1310                 :                      if (ns != 0) break;
        1311                 :
        1312                 :                      memcpy(wspace,cw,(wl+1));
        1313                 :                      mkallsmall(wspace);
        1314                 :                      ns = pSMgr->suggest_pos_stems(slst, wspace, ns);
        1315                 :
        1316                 :                      if (ns == 0) {
        1317                 :                          mkinitcap(wspace);
        1318                 :                          ns = pSMgr->suggest_pos_stems(slst, wspace, ns);
        1319                 :                      }
        1320                 :                      break;
        1321                 :                    }
        1322                 :   }
        1323                 :
        1324                 :   return ns;
        1325                 : }
        1326                 : #endif // END OF HUNSPELL_EXPERIMENTAL CODE
        1327                 :
        1328               0 : const char * Hunspell::get_wordchars()
        1329                 : {
        1330               0 :   return pAMgr->get_wordchars();
        1331                 : }
        1332                 :
        1333               0 : unsigned short * Hunspell::get_wordchars_utf16(int * len)
        1334                 : {
        1335               0 :   return pAMgr->get_wordchars_utf16(len);
        1336                 : }
        1337                 :
        1338               0 : void Hunspell::mkinitcap(char * p)
        1339                 : {
        1340               0 :   if (!utf8) {
        1341               0 :     if (*p != '\0') *p = csconv[((unsigned char)*p)].cupper;
        1342                 :   } else {
        1343                 :       int len;
        1344                 :       w_char u[MAXWORDLEN];
        1345               0 :       len = u8_u16(u, MAXWORDLEN, p);
        1346               0 :       unsigned short i = unicodetoupper((u[0].h << 8) + u[0].l, langnum);
        1347               0 :       u[0].h = (unsigned char) (i >> 8);
        1348               0 :       u[0].l = (unsigned char) (i & 0x00FF);
        1349               0 :       u16_u8(p, MAXWORDUTF8LEN, u, len);
        1350                 :   }
        1351               0 : }
        1352                 :
        1353             145 : int Hunspell::mkinitcap2(char * p, w_char * u, int nc)
        1354                 : {
        1355             145 :   if (!utf8) {
        1356             114 :     if (*p != '\0') *p = csconv[((unsigned char)*p)].cupper;
        1357              31 :   } else if (nc > 0) {
        1358              31 :       unsigned short i = unicodetoupper((u[0].h << 8) + u[0].l, langnum);
        1359              31 :       u[0].h = (unsigned char) (i >> 8);
        1360              31 :       u[0].l = (unsigned char) (i & 0x00FF);
        1361              31 :       u16_u8(p, MAXWORDUTF8LEN, u, nc);
        1362              31 :       return strlen(p);
        1363                 :   }
        1364             114 :   return nc;
        1365                 : }
        1366                 :
        1367               0 : int Hunspell::mkinitsmall2(char * p, w_char * u, int nc)
        1368                 : {
        1369               0 :   if (!utf8) {
        1370               0 :     if (*p != '\0') *p = csconv[((unsigned char)*p)].clower;
        1371               0 :   } else if (nc > 0) {
        1372               0 :       unsigned short i = unicodetolower((u[0].h << 8) + u[0].l, langnum);
        1373               0 :       u[0].h = (unsigned char) (i >> 8);
        1374               0 :       u[0].l = (unsigned char) (i & 0x00FF);
        1375               0 :       u16_u8(p, MAXWORDUTF8LEN, u, nc);
        1376               0 :       return strlen(p);
        1377                 :   }
        1378               0 :   return nc;
        1379                 : }
        1380                 :
        1381               0 : int Hunspell::add(const char * word)
        1382                 : {
        1383               0 :     if (pHMgr[0]) return (pHMgr[0])->add(word);
        1384               0 :     return 0;
        1385                 : }
        1386                 :
        1387               0 : int Hunspell::add_with_affix(const char * word, const char * example)
        1388                 : {
        1389               0 :     if (pHMgr[0]) return (pHMgr[0])->add_with_affix(word, example);
        1390               0 :     return 0;
        1391                 : }
        1392                 :
        1393               0 : int Hunspell::remove(const char * word)
        1394                 : {
        1395               0 :     if (pHMgr[0]) return (pHMgr[0])->remove(word);
        1396               0 :     return 0;
        1397                 : }
        1398                 :
        1399               0 : const char * Hunspell::get_version()
        1400                 : {
        1401               0 :   return pAMgr->get_version();
        1402                 : }
        1403                 :
        1404               0 : struct cs_info * Hunspell::get_csconv()
        1405                 : {
        1406               0 :   return csconv;
        1407                 : }
        1408                 :
        1409               0 : void Hunspell::cat_result(char * result, char * st)
        1410                 : {
        1411               0 :     if (st) {
        1412               0 :         if (*result) mystrcat(result, "\n", MAXLNLEN);
        1413               0 :         mystrcat(result, st, MAXLNLEN);
        1414               0 :         free(st);
        1415                 :     }
        1416               0 : }
        1417                 :
        1418               0 : int Hunspell::analyze(char*** slst, const char * word)
        1419                 : {
        1420                 :   char cw[MAXWORDUTF8LEN];
        1421                 :   char wspace[MAXWORDUTF8LEN];
        1422                 :   w_char unicw[MAXWORDLEN];
        1423               0 :   int wl2 = 0;
        1424               0 :   *slst = NULL;
        1425               0 :   if (! pSMgr || maxdic == 0) return 0;
        1426               0 :   int nc = strlen(word);
        1427               0 :   if (utf8) {
        1428               0 :     if (nc >= MAXWORDUTF8LEN) return 0;
        1429                 :   } else {
        1430               0 :     if (nc >= MAXWORDLEN) return 0;
        1431                 :   }
        1432               0 :   int captype = 0;
        1433               0 :   int abbv = 0;
        1434               0 :   int wl = 0;
        1435                 :
        1436                 :   // input conversion
        1437               0 :   RepList * rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL;
        1438               0 :   if (rl && rl->conv(word, wspace)) wl = cleanword2(cw, wspace, unicw, &nc, &captype, &abbv);
        1439               0 :   else wl = cleanword2(cw, word, unicw, &nc, &captype, &abbv);
        1440                 :
        1441               0 :   if (wl == 0) {
        1442               0 :       if (abbv) {
        1443               0 :           for (wl = 0; wl < abbv; wl++) cw[wl] = '.';
        1444               0 :           cw[wl] = '\0';
        1445               0 :           abbv = 0;
        1446               0 :       } else return 0;
        1447                 :   }
        1448                 :
        1449                 :   char result[MAXLNLEN];
        1450               0 :   char * st = NULL;
        1451                 :
        1452               0 :   *result = '\0';
        1453                 :
        1454               0 :   int n = 0;
        1455               0 :   int n2 = 0;
        1456               0 :   int n3 = 0;
        1457                 :
        1458                 :   // test numbers
        1459                 :   // LANG_hu section: set dash information for suggestions
        1460               0 :   if (langnum == LANG_hu) {
        1461               0 :   while ((n < wl) &&
        1462               0 :         (((cw[n] <= '9') && (cw[n] >= '0')) || (((cw[n] == '.') || (cw[n] == ',')) && (n > 0)))) {
        1463               0 :         n++;
        1464               0 :         if ((cw[n] == '.') || (cw[n] == ',')) {
        1465               0 :                 if (((n2 == 0) && (n > 3)) ||
        1466               0 :                         ((n2 > 0) && ((cw[n-1] == '.') || (cw[n-1] == ',')))) break;
        1467               0 :                 n2++;
        1468               0 :                 n3 = n;
        1469                 :         }
        1470                 :   }
        1471                 :
        1472               0 :   if ((n == wl) && (n3 > 0) && (n - n3 > 3)) return 0;
        1473               0 :   if ((n == wl) || ((n>0) && ((cw[n]=='%') || (cw[n]=='\xB0')) && checkword(cw+n, NULL, NULL))) {
        1474               0 :         mystrcat(result, cw, MAXLNLEN);
        1475               0 :         result[n - 1] = '\0';
        1476               0 :         if (n == wl) cat_result(result, pSMgr->suggest_morph(cw + n - 1));
        1477                 :         else {
        1478               0 :                 char sign = cw[n];
        1479               0 :                 cw[n] = '\0';
        1480               0 :                 cat_result(result, pSMgr->suggest_morph(cw + n - 1));
        1481               0 :                 mystrcat(result, "+", MAXLNLEN); // XXX SPEC. MORPHCODE
        1482               0 :                 cw[n] = sign;
        1483               0 :                 cat_result(result, pSMgr->suggest_morph(cw + n));
        1484                 :         }
        1485               0 :         return line_tok(result, slst, MSEP_REC);
        1486                 :   }
        1487                 :   }
        1488                 :   // END OF LANG_hu section
        1489                 :
        1490               0 :   switch(captype) {
        1491                 :      case HUHCAP:
        1492                 :      case HUHINITCAP:
        1493                 :      case NOCAP:  {
        1494               0 :                     cat_result(result, pSMgr->suggest_morph(cw));
        1495               0 :                     if (abbv) {
        1496               0 :                         memcpy(wspace,cw,wl);
        1497               0 :                         *(wspace+wl) = '.';
        1498               0 :                         *(wspace+wl+1) = '\0';
        1499               0 :                         cat_result(result, pSMgr->suggest_morph(wspace));
        1500                 :                     }
        1501               0 :                     break;
        1502                 :                 }
        1503                 :      case INITCAP: {
        1504               0 :                      wl = mkallsmall2(cw, unicw, nc);
        1505               0 :                      memcpy(wspace,cw,(wl+1));
        1506               0 :                      wl2 = mkinitcap2(cw, unicw, nc);
        1507               0 :                      cat_result(result, pSMgr->suggest_morph(wspace));
        1508               0 :                      cat_result(result, pSMgr->suggest_morph(cw));
        1509               0 :                      if (abbv) {
        1510               0 :                          *(wspace+wl) = '.';
        1511               0 :                          *(wspace+wl+1) = '\0';
        1512               0 :                          cat_result(result, pSMgr->suggest_morph(wspace));
        1513                 :
        1514               0 :                          memcpy(wspace, cw, wl2);
        1515               0 :                          *(wspace+wl2) = '.';
        1516               0 :                          *(wspace+wl2+1) = '\0';
        1517                 :
        1518               0 :                          cat_result(result, pSMgr->suggest_morph(wspace));
        1519                 :                      }
        1520               0 :                      break;
        1521                 :                    }
        1522                 :      case ALLCAP: {
        1523               0 :                      cat_result(result, pSMgr->suggest_morph(cw));
        1524               0 :                      if (abbv) {
        1525               0 :                          memcpy(wspace,cw,wl);
        1526               0 :                          *(wspace+wl) = '.';
        1527               0 :                          *(wspace+wl+1) = '\0';
        1528               0 :                          cat_result(result, pSMgr->suggest_morph(cw));
        1529                 :                      }
        1530               0 :                      wl = mkallsmall2(cw, unicw, nc);
        1531               0 :                      memcpy(wspace,cw,(wl+1));
        1532               0 :                      wl2 = mkinitcap2(cw, unicw, nc);
        1533                 :
        1534               0 :                      cat_result(result, pSMgr->suggest_morph(wspace));
        1535               0 :                      cat_result(result, pSMgr->suggest_morph(cw));
        1536               0 :                      if (abbv) {
        1537               0 :                          *(wspace+wl) = '.';
        1538               0 :                          *(wspace+wl+1) = '\0';
        1539               0 :                          cat_result(result, pSMgr->suggest_morph(wspace));
        1540                 :
        1541               0 :                          memcpy(wspace, cw, wl2);
        1542               0 :                          *(wspace+wl2) = '.';
        1543               0 :                          *(wspace+wl2+1) = '\0';
        1544                 :
        1545               0 :                          cat_result(result, pSMgr->suggest_morph(wspace));
        1546                 :                      }
        1547               0 :                      break;
        1548                 :                    }
        1549                 :   }
        1550                 :
        1551               0 :   if (*result) {
        1552                 :     // word reversing wrapper for complex prefixes
        1553               0 :     if (complexprefixes) {
        1554               0 :       if (utf8) reverseword_utf(result); else reverseword(result);
        1555                 :     }
        1556               0 :     return line_tok(result, slst, MSEP_REC);
        1557                 :   }
        1558                 :
        1559                 :   // compound word with dash (HU) I18n
        1560               0 :   char * dash = NULL;
        1561               0 :   int nresult = 0;
        1562                 :   // LANG_hu section: set dash information for suggestions
        1563               0 :   if (langnum == LANG_hu) dash = (char *) strchr(cw,'-');
        1564               0 :   if ((langnum == LANG_hu) && dash) {
        1565               0 :       *dash='\0';
        1566                 :       // examine 2 sides of the dash
        1567               0 :       if (dash[1] == '\0') { // base word ending with dash
        1568               0 :         if (spell(cw)) {
        1569               0 :                 char * p = pSMgr->suggest_morph(cw);
        1570               0 :                 if (p) {
        1571               0 :                     int ret = line_tok(p, slst, MSEP_REC);
        1572               0 :                     free(p);
        1573               0 :                     return ret;
        1574                 :                 }
        1575                 :
        1576                 :         }
        1577               0 :       } else if ((dash[1] == 'e') && (dash[2] == '\0')) { // XXX (HU) -e hat.
        1578               0 :         if (spell(cw) && (spell("-e"))) {
        1579               0 :                         st = pSMgr->suggest_morph(cw);
        1580               0 :                         if (st) {
        1581               0 :                                 mystrcat(result, st, MAXLNLEN);
        1582               0 :                                 free(st);
        1583                 :                         }
        1584               0 :                         mystrcat(result,"+", MAXLNLEN); // XXX spec. separator in MORPHCODE
        1585               0 :                         st = pSMgr->suggest_morph("-e");
        1586               0 :                         if (st) {
        1587               0 :                                 mystrcat(result, st, MAXLNLEN);
        1588               0 :                                 free(st);
        1589                 :                         }
        1590               0 :                         return line_tok(result, slst, MSEP_REC);
        1591                 :                 }
        1592                 :       } else {
        1593                 :       // first word ending with dash: word- XXX ???
        1594               0 :         char r2 = *(dash + 1);
        1595               0 :         dash[0]='-';
        1596               0 :         dash[1]='\0';
        1597               0 :         nresult = spell(cw);
        1598               0 :         dash[1] = r2;
        1599               0 :         dash[0]='\0';
        1600               0 :         if (nresult && spell(dash+1) && ((strlen(dash+1) > 1) ||
        1601               0 :                 ((dash[1] > '0') && (dash[1] < '9')))) {
        1602               0 :                             st = pSMgr->suggest_morph(cw);
        1603               0 :                             if (st) {
        1604               0 :                                 mystrcat(result, st, MAXLNLEN);
        1605               0 :                                     free(st);
        1606               0 :                                 mystrcat(result,"+", MAXLNLEN); // XXX spec. separator in MORPHCODE
        1607                 :                             }
        1608               0 :                             st = pSMgr->suggest_morph(dash+1);
        1609               0 :                             if (st) {
        1610               0 :                                     mystrcat(result, st, MAXLNLEN);
        1611               0 :                                     free(st);
        1612                 :                             }
        1613               0 :                             return line_tok(result, slst, MSEP_REC);
        1614                 :                         }
        1615                 :       }
        1616                 :       // affixed number in correct word
        1617               0 :      if (nresult && (dash > cw) && (((*(dash-1)<='9') &&
        1618               0 :                         (*(dash-1)>='0')) || (*(dash-1)=='.'))) {
        1619               0 :          *dash='-';
        1620               0 :          n = 1;
        1621               0 :          if (*(dash - n) == '.') n++;
        1622                 :          // search first not a number character to left from dash
        1623               0 :          while (((dash - n)>=cw) && ((*(dash - n)=='0') || (n < 3)) && (n < 6)) {
        1624               0 :             n++;
        1625                 :          }
        1626               0 :          if ((dash - n) < cw) n--;
        1627                 :          // numbers: valami1000000-hoz
        1628                 :          // examine 100000-hoz, 10000-hoz 1000-hoz, 10-hoz,
        1629                 :          // 56-hoz, 6-hoz
        1630               0 :          for(; n >= 1; n--) {
        1631               0 :             if ((*(dash - n) >= '0') && (*(dash - n) <= '9') && checkword(dash - n, NULL, NULL)) {
        1632               0 :                     mystrcat(result, cw, MAXLNLEN);
        1633               0 :                     result[dash - cw - n] = '\0';
        1634               0 :                         st = pSMgr->suggest_morph(dash - n);
        1635               0 :                         if (st) {
        1636               0 :                         mystrcat(result, st, MAXLNLEN);
        1637               0 :                                 free(st);
        1638                 :                         }
        1639               0 :                         return line_tok(result, slst, MSEP_REC);
        1640                 :             }
        1641                 :          }
        1642                 :      }
        1643                 :   }
        1644               0 :   return 0;
        1645                 : }
        1646                 :
        1647               0 : int Hunspell::generate(char*** slst, const char * word, char ** pl, int pln)
        1648                 : {
        1649               0 :   *slst = NULL;
        1650               0 :   if (!pSMgr || !pln) return 0;
        1651                 :   char **pl2;
        1652               0 :   int pl2n = analyze(&pl2, word);
        1653               0 :   int captype = 0;
        1654               0 :   int abbv = 0;
        1655                 :   char cw[MAXWORDUTF8LEN];
        1656               0 :   cleanword(cw, word, &captype, &abbv);
        1657                 :   char result[MAXLNLEN];
        1658               0 :   *result = '\0';
        1659                 :
        1660               0 :   for (int i = 0; i < pln; i++) {
        1661               0 :     cat_result(result, pSMgr->suggest_gen(pl2, pl2n, pl[i]));
        1662                 :   }
        1663               0 :   freelist(&pl2, pl2n);
        1664                 :
        1665               0 :   if (*result) {
        1666                 :     // allcap
        1667               0 :     if (captype == ALLCAP) mkallcap(result);
        1668                 :
        1669                 :     // line split
        1670               0 :     int linenum = line_tok(result, slst, MSEP_REC);
        1671                 :
        1672                 :     // capitalize
        1673               0 :     if (captype == INITCAP || captype == HUHINITCAP) {
        1674               0 :         for (int j=0; j < linenum; j++) mkinitcap((*slst)[j]);
        1675                 :     }
        1676                 :
        1677                 :     // temporary filtering of prefix related errors (eg.
        1678                 :     // generate("undrinkable", "eats") --> "undrinkables" and "*undrinks")
        1679                 :
        1680               0 :     int r = 0;
        1681               0 :     for (int j=0; j < linenum; j++) {
        1682               0 :         if (!spell((*slst)[j])) {
        1683               0 :             free((*slst)[j]);
        1684               0 :             (*slst)[j] = NULL;
        1685                 :         } else {
        1686               0 :             if (r < j) (*slst)[r] = (*slst)[j];
        1687               0 :             r++;
        1688                 :         }
        1689                 :     }
        1690               0 :     if (r > 0) return r;
        1691               0 :     free(*slst);
        1692               0 :     *slst = NULL;
        1693                 :   }
        1694               0 :   return 0;
        1695                 : }
        1696                 :
        1697               0 : int Hunspell::generate(char*** slst, const char * word, const char * pattern)
        1698                 : {
        1699                 :   char **pl;
        1700               0 :   int pln = analyze(&pl, pattern);
        1701               0 :   int n = generate(slst, word, pl, pln);
        1702               0 :   freelist(&pl, pln);
        1703               0 :   return uniqlist(*slst, n);
        1704                 : }
        1705                 :
        1706                 : // minimal XML parser functions
        1707               0 : int Hunspell::get_xml_par(char * dest, const char * par, int max)
        1708                 : {
        1709               0 :    char * d = dest;
        1710               0 :    if (!par) return 0;
        1711               0 :    char end = *par;
        1712               0 :    char * dmax = dest + max;
        1713               0 :    if (end == '>') end = '<';
        1714               0 :    else if (end != '\'' && end != '"') return 0; // bad XML
        1715               0 :    for (par++; d < dmax && *par != '\0' && *par != end; par++, d++) *d = *par;
        1716               0 :    *d = '\0';
        1717               0 :    mystrrep(dest, "&lt;", "<");
        1718               0 :    mystrrep(dest, "&amp;", "&");
        1719               0 :    return (int)(d - dest);
        1720                 : }
        1721                 :
        1722               0 : int Hunspell::get_langnum() const
        1723                 : {
        1724               0 :    return langnum;
        1725                 : }
        1726                 :
        1727                 : // return the beginning of the element (attr == NULL) or the attribute
        1728               0 : const char * Hunspell::get_xml_pos(const char * s, const char * attr)
        1729                 : {
        1730               0 :   const char * end = strchr(s, '>');
        1731               0 :   const char * p = s;
        1732               0 :   if (attr == NULL) return end;
        1733               0 :   do {
        1734               0 :     p = strstr(p, attr);
        1735               0 :     if (!p || p >= end) return 0;
        1736               0 :   } while (*(p-1) != ' ' &&  *(p-1) != '\n');
        1737               0 :   return p + strlen(attr);
        1738                 : }
        1739                 :
        1740               0 : int Hunspell::check_xml_par(const char * q, const char * attr, const char * value) {
        1741                 :   char cw[MAXWORDUTF8LEN];
        1742               0 :   if (get_xml_par(cw, get_xml_pos(q, attr), MAXWORDUTF8LEN - 1) &&
        1743               0 :     strcmp(cw, value) == 0) return 1;
        1744               0 :   return 0;
        1745                 : }
        1746                 :
        1747               0 : int Hunspell::get_xml_list(char ***slst, char * list, const char * tag) {
        1748               0 :     int n = 0;
        1749                 :     char * p;
        1750               0 :     if (!list) return 0;
        1751               0 :     for (p = list; (p = strstr(p, tag)); p++) n++;
        1752               0 :     if (n == 0) return 0;
        1753               0 :     *slst = (char **) malloc(sizeof(char *) * n);
        1754               0 :     if (!*slst) return 0;
        1755               0 :     for (p = list, n = 0; (p = strstr(p, tag)); p++, n++) {
        1756               0 :         int l = strlen(p);
        1757               0 :         (*slst)[n] = (char *) malloc(l + 1);
        1758               0 :         if (!(*slst)[n]) return n;
        1759               0 :         if (!get_xml_par((*slst)[n], p + strlen(tag) - 1, l)) {
        1760               0 :             free((*slst)[n]);
        1761               0 :             break;
        1762                 :         }
        1763                 :     }
        1764               0 :     return n;
        1765                 : }
        1766                 :
        1767               0 : int Hunspell::spellml(char*** slst, const char * word)
        1768                 : {
        1769                 :   char *q, *q2;
        1770                 :   char cw[MAXWORDUTF8LEN], cw2[MAXWORDUTF8LEN];
        1771               0 :   q = (char *) strstr(word, "<query");
        1772               0 :   if (!q) return 0; // bad XML input
        1773               0 :   q2 = strchr(q, '>');
        1774               0 :   if (!q2) return 0; // bad XML input
        1775               0 :   q2 = strstr(q2, "<word");
        1776               0 :   if (!q2) return 0; // bad XML input
        1777               0 :   if (check_xml_par(q, "type=", "analyze")) {
        1778               0 :       int n = 0, s = 0;
        1779               0 :       if (get_xml_par(cw, strchr(q2, '>'), MAXWORDUTF8LEN - 10)) n = analyze(slst, cw);
        1780               0 :       if (n == 0) return 0;
        1781                 :       // convert the result to <code><a>ana1</a><a>ana2</a></code> format
        1782               0 :       for (int i = 0; i < n; i++) s+= strlen((*slst)[i]);
        1783               0 :       char * r = (char *) malloc(6 + 5 * s + 7 * n + 7 + 1); // XXX 5*s->&->&amp;
        1784               0 :       if (!r) return 0;
        1785               0 :       strcpy(r, "<code>");
        1786               0 :       for (int i = 0; i < n; i++) {
        1787               0 :         int l = strlen(r);
        1788               0 :         strcpy(r + l, "<a>");
        1789               0 :         strcpy(r + l + 3, (*slst)[i]);
        1790               0 :         mystrrep(r + l + 3, "\t", " ");
        1791               0 :         mystrrep(r + l + 3, "<", "&lt;");
        1792               0 :         mystrrep(r + l + 3, "&", "&amp;");
        1793               0 :         strcat(r, "</a>");
        1794               0 :         free((*slst)[i]);
        1795                 :       }
        1796               0 :       strcat(r, "</code>");
        1797               0 :       (*slst)[0] = r;
        1798               0 :       return 1;
        1799               0 :   } else if (check_xml_par(q, "type=", "stem")) {
        1800               0 :       if (get_xml_par(cw, strchr(q2, '>'), MAXWORDUTF8LEN - 1)) return stem(slst, cw);
        1801               0 :   } else if (check_xml_par(q, "type=", "generate")) {
        1802               0 :       int n = get_xml_par(cw, strchr(q2, '>'), MAXWORDUTF8LEN - 1);
        1803               0 :       if (n == 0) return 0;
        1804               0 :       char * q3 = strstr(q2 + 1, "<word");
        1805               0 :       if (q3) {
        1806               0 :         if (get_xml_par(cw2, strchr(q3, '>'), MAXWORDUTF8LEN - 1)) {
        1807               0 :             return generate(slst, cw, cw2);
        1808                 :         }
        1809                 :       } else {
        1810               0 :         if ((q2 = strstr(q2 + 1, "<code"))) {
        1811                 :           char ** slst2;
        1812               0 :           if ((n = get_xml_list(&slst2, strchr(q2, '>'), "<a>"))) {
        1813               0 :             int n2 = generate(slst, cw, slst2, n);
        1814               0 :             freelist(&slst2, n);
        1815               0 :             return uniqlist(*slst, n2);
        1816                 :           }
        1817               0 :           freelist(&slst2, n);
        1818                 :         }
        1819                 :       }
        1820                 :   }
        1821               0 :   return 0;
        1822                 : }
        1823                 :
        1824                 :
        1825                 : #ifdef HUNSPELL_EXPERIMENTAL
        1826                 : // XXX need UTF-8 support
        1827                 : char * Hunspell::morph_with_correction(const char * word)
        1828                 : {
        1829                 :   char cw[MAXWORDUTF8LEN];
        1830                 :   char wspace[MAXWORDUTF8LEN];
        1831                 :   if (! pSMgr || maxdic == 0) return NULL;
        1832                 :   int wl = strlen(word);
        1833                 :   if (utf8) {
        1834                 :     if (wl >= MAXWORDUTF8LEN) return NULL;
        1835                 :   } else {
        1836                 :     if (wl >= MAXWORDLEN) return NULL;
        1837                 :   }
        1838                 :   int captype = 0;
        1839                 :   int abbv = 0;
        1840                 :   wl = cleanword(cw, word, &captype, &abbv);
        1841                 :   if (wl == 0) return NULL;
        1842                 :
        1843                 :   char result[MAXLNLEN];
        1844                 :   char * st = NULL;
        1845                 :
        1846                 :   *result = '\0';
        1847                 :
        1848                 :
        1849                 :   switch(captype) {
        1850                 :      case NOCAP:   {
        1851                 :                      st = pSMgr->suggest_morph_for_spelling_error(cw);
        1852                 :                      if (st) {
        1853                 :                         mystrcat(result, st, MAXLNLEN);
        1854                 :                         free(st);
        1855                 :                      }
        1856                 :                      if (abbv) {
        1857                 :                          memcpy(wspace,cw,wl);
        1858                 :                          *(wspace+wl) = '.';
        1859                 :                          *(wspace+wl+1) = '\0';
        1860                 :                          st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1861                 :                          if (st) {
        1862                 :                             if (*result) mystrcat(result, "\n", MAXLNLEN);
        1863                 :                             mystrcat(result, st, MAXLNLEN);
        1864                 :                             free(st);
        1865                 :                                                  }
        1866                 :                      }
        1867                 :                                          break;
        1868                 :                    }
        1869                 :      case INITCAP: {
        1870                 :                      memcpy(wspace,cw,(wl+1));
        1871                 :                      mkallsmall(wspace);
        1872                 :                      st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1873                 :                      if (st) {
        1874                 :                         mystrcat(result, st, MAXLNLEN);
        1875                 :                         free(st);
        1876                 :                      }
        1877                 :                      st = pSMgr->suggest_morph_for_spelling_error(cw);
        1878                 :                      if (st) {
        1879                 :                         if (*result) mystrcat(result, "\n", MAXLNLEN);
        1880                 :                         mystrcat(result, st, MAXLNLEN);
        1881                 :                         free(st);
        1882                 :                      }
        1883                 :                      if (abbv) {
        1884                 :                          memcpy(wspace,cw,wl);
        1885                 :                          *(wspace+wl) = '.';
        1886                 :                          *(wspace+wl+1) = '\0';
        1887                 :                          mkallsmall(wspace);
        1888                 :                          st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1889                 :                          if (st) {
        1890                 :                             if (*result) mystrcat(result, "\n", MAXLNLEN);
        1891                 :                             mystrcat(result, st, MAXLNLEN);
        1892                 :                             free(st);
        1893                 :                          }
        1894                 :                          mkinitcap(wspace);
        1895                 :                          st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1896                 :                          if (st) {
        1897                 :                             if (*result) mystrcat(result, "\n", MAXLNLEN);
        1898                 :                             mystrcat(result, st, MAXLNLEN);
        1899                 :                             free(st);
        1900                 :                          }
        1901                 :                      }
        1902                 :                      break;
        1903                 :                    }
        1904                 :      case HUHCAP: {
        1905                 :                      st = pSMgr->suggest_morph_for_spelling_error(cw);
        1906                 :                      if (st) {
        1907                 :                         mystrcat(result, st, MAXLNLEN);
        1908                 :                         free(st);
        1909                 :                      }
        1910                 :                      memcpy(wspace,cw,(wl+1));
        1911                 :                      mkallsmall(wspace);
        1912                 :                      st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1913                 :                      if (st) {
        1914                 :                         if (*result) mystrcat(result, "\n", MAXLNLEN);
        1915                 :                         mystrcat(result, st, MAXLNLEN);
        1916                 :                         free(st);
        1917                 :                      }
        1918                 :                      break;
        1919                 :                  }
        1920                 :      case ALLCAP: {
        1921                 :                      memcpy(wspace,cw,(wl+1));
        1922                 :                      st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1923                 :                      if (st) {
        1924                 :                         mystrcat(result, st, MAXLNLEN);
        1925                 :                         free(st);
        1926                 :                      }
        1927                 :                      mkallsmall(wspace);
        1928                 :                      st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1929                 :                      if (st) {
        1930                 :                         if (*result) mystrcat(result, "\n", MAXLNLEN);
        1931                 :                         mystrcat(result, st, MAXLNLEN);
        1932                 :                         free(st);
        1933                 :                      }
        1934                 :                      mkinitcap(wspace);
        1935                 :                      st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1936                 :                      if (st) {
        1937                 :                         if (*result) mystrcat(result, "\n", MAXLNLEN);
        1938                 :                         mystrcat(result, st, MAXLNLEN);
        1939                 :                         free(st);
        1940                 :                      }
        1941                 :                      if (abbv) {
        1942                 :                         memcpy(wspace,cw,(wl+1));
        1943                 :                         *(wspace+wl) = '.';
        1944                 :                         *(wspace+wl+1) = '\0';
        1945                 :                         if (*result) mystrcat(result, "\n", MAXLNLEN);
        1946                 :                         st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1947                 :                         if (st) {
        1948                 :                             mystrcat(result, st, MAXLNLEN);
        1949                 :                             free(st);
        1950                 :                         }
        1951                 :                         mkallsmall(wspace);
        1952                 :                         st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1953                 :                         if (st) {
        1954                 :                           if (*result) mystrcat(result, "\n", MAXLNLEN);
        1955                 :                           mystrcat(result, st, MAXLNLEN);
        1956                 :                           free(st);
        1957                 :                         }
        1958                 :                         mkinitcap(wspace);
        1959                 :                         st = pSMgr->suggest_morph_for_spelling_error(wspace);
        1960                 :                         if (st) {
        1961                 :                           if (*result) mystrcat(result, "\n", MAXLNLEN);
        1962                 :                           mystrcat(result, st, MAXLNLEN);
        1963                 :                           free(st);
        1964                 :                         }
        1965                 :                      }
        1966                 :                      break;
        1967                 :                    }
        1968                 :   }
        1969                 :
        1970                 :   if (*result) return mystrdup(result);
        1971                 :   return NULL;
        1972                 : }
        1973                 :
        1974                 : #endif // END OF HUNSPELL_EXPERIMENTAL CODE
        1975                 :
        1976               0 : Hunhandle *Hunspell_create(const char * affpath, const char * dpath)
        1977                 : {
        1978               0 :         return (Hunhandle*)(new Hunspell(affpath, dpath));
        1979                 : }
        1980                 :
        1981               0 : Hunhandle *Hunspell_create_key(const char * affpath, const char * dpath,
        1982                 :     const char * key)
        1983                 : {
        1984               0 :         return (Hunhandle*)(new Hunspell(affpath, dpath, key));
        1985                 : }
        1986                 :
        1987               0 : void Hunspell_destroy(Hunhandle *pHunspell)
        1988                 : {
        1989               0 :         delete (Hunspell*)(pHunspell);
        1990               0 : }
        1991                 :
        1992               0 : int Hunspell_spell(Hunhandle *pHunspell, const char *word)
        1993                 : {
        1994               0 :         return ((Hunspell*)pHunspell)->spell(word);
        1995                 : }
        1996                 :
        1997               0 : char *Hunspell_get_dic_encoding(Hunhandle *pHunspell)
        1998                 : {
        1999               0 :         return ((Hunspell*)pHunspell)->get_dic_encoding();
        2000                 : }
        2001                 :
        2002               0 : int Hunspell_suggest(Hunhandle *pHunspell, char*** slst, const char * word)
        2003                 : {
        2004               0 :         return ((Hunspell*)pHunspell)->suggest(slst, word);
        2005                 : }
        2006                 :
        2007               0 : int Hunspell_analyze(Hunhandle *pHunspell, char*** slst, const char * word)
        2008                 : {
        2009               0 :         return ((Hunspell*)pHunspell)->analyze(slst, word);
        2010                 : }
        2011                 :
        2012               0 : int Hunspell_stem(Hunhandle *pHunspell, char*** slst, const char * word)
        2013                 : {
        2014               0 :         return ((Hunspell*)pHunspell)->stem(slst, word);
        2015                 : }
        2016                 :
        2017               0 : int Hunspell_stem2(Hunhandle *pHunspell, char*** slst, char** desc, int n)
        2018                 : {
        2019               0 :         return ((Hunspell*)pHunspell)->stem(slst, desc, n);
        2020                 : }
        2021                 :
        2022               0 : int Hunspell_generate(Hunhandle *pHunspell, char*** slst, const char * word,
        2023                 :     const char * word2)
        2024                 : {
        2025               0 :         return ((Hunspell*)pHunspell)->generate(slst, word, word2);
        2026                 : }
        2027                 :
        2028               0 : int Hunspell_generate2(Hunhandle *pHunspell, char*** slst, const char * word,
        2029                 :     char** desc, int n)
        2030                 : {
        2031               0 :         return ((Hunspell*)pHunspell)->generate(slst, word, desc, n);
        2032                 : }
        2033                 :
        2034                 :   /* functions for run-time modification of the dictionary */
        2035                 :
        2036                 :   /* add word to the run-time dictionary */
        2037                 :
        2038               0 : int Hunspell_add(Hunhandle *pHunspell, const char * word) {
        2039               0 :         return ((Hunspell*)pHunspell)->add(word);
        2040                 : }
        2041                 :
        2042                 :   /* add word to the run-time dictionary with affix flags of
        2043                 :    * the example (a dictionary word): Hunspell will recognize
        2044                 :    * affixed forms of the new word, too.
        2045                 :    */
        2046                 :
        2047               0 : int Hunspell_add_with_affix(Hunhandle *pHunspell, const char * word,
        2048                 :         const char * example) {
        2049               0 :         return ((Hunspell*)pHunspell)->add_with_affix(word, example);
        2050                 : }
        2051                 :
        2052                 :   /* remove word from the run-time dictionary */
        2053                 :
        2054               0 : int Hunspell_remove(Hunhandle *pHunspell, const char * word) {
        2055               0 :         return ((Hunspell*)pHunspell)->remove(word);
        2056                 : }
        2057                 :
        2058               0 : void Hunspell_free_list(Hunhandle *, char *** slst, int n) {
        2059               0 :         freelist(slst, n);
        2060               0 : }

Generated by: LCOV version 1.7