• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kspell2
 

kspell2

  • kspell2
  • plugins
  • ispell
ispell_checker.cpp
1 /* vim: set sw=8: -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* kspell2 - adopted from Enchant
3  * Copyright (C) 2003 Dom Lachowicz
4  * Copyright (C) 2004 Zack Rusin <zack@kde.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * In addition, as a special exception, Dom Lachowicz
22  * gives permission to link the code of this program with
23  * non-LGPL Spelling Provider libraries (eg: a MSFT Office
24  * spell checker backend) and distribute linked combinations including
25  * the two. You must obey the GNU Lesser General Public License in all
26  * respects for all of the code used other than said providers. If you modify
27  * this file, you may extend this exception to your version of the
28  * file, but you are not obligated to do so. If you do not wish to
29  * do so, delete this exception statement from your version.
30  */
31 
32 #include <config.h>
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include <string>
39 #include <vector>
40 
41 #include "sp_spell.h"
42 #include "ispell_checker.h"
43 
44 #include <tqmap.h>
45 #include <tqdir.h>
46 #include <tqfileinfo.h>
47 
48 /***************************************************************************/
49 
50 typedef struct str_ispell_map
51 {
52  const char * lang;
53  const char * dict;
54  const char * enc;
55 } IspellMap;
56 
57 static const char *ispell_dirs [] = {
58 #ifdef ISPELL_LIBDIR
59  ISPELL_LIBDIR,
60 #else
61  "/usr/" SYSTEM_LIBDIR "/ispell",
62  "/usr/lib/ispell",
63  "/usr/local/" SYSTEM_LIBDIR "/ispell",
64  "/usr/local/lib/ispell",
65  "/usr/local/share/ispell",
66  "/usr/share/ispell",
67  "/usr/pkg/lib",
68 #endif
69  0
70 };
71 static const IspellMap ispell_map [] = {
72  {"ca" ,"catala.hash" ,"iso-8859-1" },
73  {"ca_ES" ,"catala.hash" ,"iso-8859-1" },
74  {"cs" ,"czech.hash" ,"iso-8859-2" },
75  {"cs_CZ" ,"czech.hash" ,"iso-8859-2" },
76  {"da" ,"dansk.hash" ,"iso-8859-1" },
77  {"da_DK" ,"dansk.hash" ,"iso-8859-1" },
78  {"de" ,"deutsch.hash" ,"iso-8859-1" },
79  {"de_CH" ,"swiss.hash" ,"iso-8859-1" },
80  {"de_AT" ,"deutsch.hash" ,"iso-8859-1" },
81  {"de_DE" ,"deutsch.hash" ,"iso-8859-1" },
82  {"el" ,"ellhnika.hash" ,"iso-8859-7" },
83  {"el_GR" ,"ellhnika.hash" ,"iso-8859-7" },
84  {"en" ,"british.hash" ,"iso-8859-1" },
85  {"en_AU" ,"british.hash" ,"iso-8859-1" },
86  {"en_BZ" ,"british.hash" ,"iso-8859-1" },
87  {"en_CA" ,"british.hash" ,"iso-8859-1" },
88  {"en_GB" ,"british.hash" ,"iso-8859-1" },
89  {"en_IE" ,"british.hash" ,"iso-8859-1" },
90  {"en_JM" ,"british.hash" ,"iso-8859-1" },
91  {"en_NZ" ,"british.hash" ,"iso-8859-1" },
92  {"en_TT" ,"british.hash" ,"iso-8859-1" },
93  {"en_ZA" ,"british.hash" ,"iso-8859-1" },
94  {"en_ZW" ,"british.hash" ,"iso-8859-1" },
95  {"en_PH" ,"american.hash" ,"iso-8859-1" },
96  {"en_US" ,"american.hash" ,"iso-8859-1" },
97  {"eo" ,"esperanto.hash" ,"iso-8859-3" },
98  {"es" ,"espanol.hash" ,"iso-8859-1" },
99  {"es_AR" ,"espanol.hash" ,"iso-8859-1" },
100  {"es_BO" ,"espanol.hash" ,"iso-8859-1" },
101  {"es_CL" ,"espanol.hash" ,"iso-8859-1" },
102  {"es_CO" ,"espanol.hash" ,"iso-8859-1" },
103  {"es_CR" ,"espanol.hash" ,"iso-8859-1" },
104  {"es_DO" ,"espanol.hash" ,"iso-8859-1" },
105  {"es_EC" ,"espanol.hash" ,"iso-8859-1" },
106  {"es_ES" ,"espanol.hash" ,"iso-8859-1" },
107  {"es_GT" ,"espanol.hash" ,"iso-8859-1" },
108  {"es_HN" ,"espanol.hash" ,"iso-8859-1" },
109  {"es_MX" ,"espanol.hash" ,"iso-8859-1" },
110  {"es_NI" ,"espanol.hash" ,"iso-8859-1" },
111  {"es_PA" ,"espanol.hash" ,"iso-8859-1" },
112  {"es_PE" ,"espanol.hash" ,"iso-8859-1" },
113  {"es_PR" ,"espanol.hash" ,"iso-8859-1" },
114  {"es_PY" ,"espanol.hash" ,"iso-8859-1" },
115  {"es_SV" ,"espanol.hash" ,"iso-8859-1" },
116  {"es_UY" ,"espanol.hash" ,"iso-8859-1" },
117  {"es_VE" ,"espanol.hash" ,"iso-8859-1" },
118  {"fi" ,"finnish.hash" ,"iso-8859-1" },
119  {"fi_FI" ,"finnish.hash" ,"iso-8859-1" },
120  {"fr" ,"francais.hash" ,"iso-8859-1" },
121  {"fr_BE" ,"francais.hash" ,"iso-8859-1" },
122  {"fr_CA" ,"francais.hash" ,"iso-8859-1" },
123  {"fr_CH" ,"francais.hash" ,"iso-8859-1" },
124  {"fr_FR" ,"francais.hash" ,"iso-8859-1" },
125  {"fr_LU" ,"francais.hash" ,"iso-8859-1" },
126  {"fr_MC" ,"francais.hash" ,"iso-8859-1" },
127  {"hu" ,"hungarian.hash" ,"iso-8859-2" },
128  {"hu_HU" ,"hungarian.hash" ,"iso-8859-2" },
129  {"ga" ,"irish.hash" ,"iso-8859-1" },
130  {"ga_IE" ,"irish.hash" ,"iso-8859-1" },
131  {"gl" ,"galician.hash" ,"iso-8859-1" },
132  {"gl_ES" ,"galician.hash" ,"iso-8859-1" },
133  {"ia" ,"interlingua.hash" ,"iso-8859-1" },
134  {"it" ,"italian.hash" ,"iso-8859-1" },
135  {"it_IT" ,"italian.hash" ,"iso-8859-1" },
136  {"it_CH" ,"italian.hash" ,"iso-8859-1" },
137  {"la" ,"mlatin.hash" ,"iso-8859-1" },
138  {"la_IT" ,"mlatin.hash" ,"iso-8859-1" },
139  {"lt" ,"lietuviu.hash" ,"iso-8859-13" },
140  {"lt_LT" ,"lietuviu.hash" ,"iso-8859-13" },
141  {"nl" ,"nederlands.hash" ,"iso-8859-1" },
142  {"nl_NL" ,"nederlands.hash" ,"iso-8859-1" },
143  {"nl_BE" ,"nederlands.hash" ,"iso-8859-1" },
144  {"nb" ,"norsk.hash" ,"iso-8859-1" },
145  {"nb_NO" ,"norsk.hash" ,"iso-8859-1" },
146  {"nn" ,"nynorsk.hash" ,"iso-8859-1" },
147  {"nn_NO" ,"nynorsk.hash" ,"iso-8859-1" },
148  {"no" ,"norsk.hash" ,"iso-8859-1" },
149  {"no_NO" ,"norsk.hash" ,"iso-8859-1" },
150  {"pl" ,"polish.hash" ,"iso-8859-2" },
151  {"pl_PL" ,"polish.hash" ,"iso-8859-2" },
152  {"pt" ,"brazilian.hash" ,"iso-8859-1" },
153  {"pt_BR" ,"brazilian.hash" ,"iso-8859-1" },
154  {"pt_PT" ,"portugues.hash" ,"iso-8859-1" },
155  {"ru" ,"russian.hash" ,"koi8-r" },
156  {"ru_MD" ,"russian.hash" ,"koi8-r" },
157  {"ru_RU" ,"russian.hash" ,"koi8-r" },
158  {"sc" ,"sardinian.hash" ,"iso-8859-1" },
159  {"sc_IT" ,"sardinian.hash" ,"iso-8859-1" },
160  {"sk" ,"slovak.hash" ,"iso-8859-2" },
161  {"sk_SK" ,"slovak.hash" ,"iso-8859-2" },
162  {"sl" ,"slovensko.hash" ,"iso-8859-2" },
163  {"sl_SI" ,"slovensko.hash" ,"iso-8859-2" },
164  {"sv" ,"svenska.hash" ,"iso-8859-1" },
165  {"sv_SE" ,"svenska.hash" ,"iso-8859-1" },
166  {"uk" ,"ukrainian.hash" ,"koi8-u" },
167  {"uk_UA" ,"ukrainian.hash" ,"koi8-u" },
168  {"yi" ,"yiddish-yivo.hash" ,"utf-8" }
169 };
170 
171 static const size_t size_ispell_map = ( sizeof(ispell_map) / sizeof((ispell_map)[0]) );
172 static TQMap<TQString, TQString> ispell_dict_map;
173 
174 
175 void
176 ISpellChecker::try_autodetect_charset(const char * const inEncoding)
177 {
178  if (inEncoding && strlen(inEncoding))
179  {
180  m_translate_in = TQTextCodec::codecForName(inEncoding);
181  }
182 }
183 
184 /***************************************************************************/
185 /***************************************************************************/
186 
187 ISpellChecker::ISpellChecker()
188  : deftflag(-1),
189  prefstringchar(-1),
190  m_bSuccessfulInit(false),
191  m_BC(NULL),
192  m_cd(NULL),
193  m_cl(NULL),
194  m_cm(NULL),
195  m_ho(NULL),
196  m_nd(NULL),
197  m_so(NULL),
198  m_se(NULL),
199  m_ti(NULL),
200  m_te(NULL),
201  m_hashstrings(NULL),
202  m_hashtbl(NULL),
203  m_pflaglist(NULL),
204  m_sflaglist(NULL),
205  m_chartypes(NULL),
206  m_infile(NULL),
207  m_outfile(NULL),
208  m_askfilename(NULL),
209  m_Trynum(0),
210  m_translate_in(0)
211 {
212  memset(m_sflagindex,0,sizeof(m_sflagindex));
213  memset(m_pflagindex,0,sizeof(m_pflagindex));
214 }
215 
216 #ifndef FREEP
217 #define FREEP(p) do { if (p) free(p); } while (0)
218 #endif
219 
220 ISpellChecker::~ISpellChecker()
221 {
222  if (m_bSuccessfulInit) {
223  // only cleanup our mess if we were successfully initialized
224 
225  clearindex (m_pflagindex);
226  clearindex (m_sflagindex);
227  }
228 
229  FREEP(m_hashtbl);
230  FREEP(m_hashstrings);
231  FREEP(m_sflaglist);
232  FREEP(m_chartypes);
233 
234  delete m_translate_in;
235  m_translate_in = 0;
236 }
237 
238 bool
239 ISpellChecker::checkWord( const TQString& utf8Word )
240 {
241  ichar_t iWord[INPUTWORDLEN + MAXAFFIXLEN];
242  if (!m_bSuccessfulInit)
243  return false;
244 
245  if (!utf8Word || utf8Word.length() >= (INPUTWORDLEN + MAXAFFIXLEN) || utf8Word.isEmpty())
246  return false;
247 
248  bool retVal = false;
249  TQCString out;
250  if (!m_translate_in)
251  return false;
252  else {
253  /* convert to 8bit string and null terminate */
254  int len_out = utf8Word.length();
255 
256  out = m_translate_in->fromUnicode( utf8Word, len_out );
257  }
258 
259  if (!strtoichar(iWord, out.data(), INPUTWORDLEN + MAXAFFIXLEN, 0))
260  {
261  if (good(iWord, 0, 0, 1, 0) == 1 ||
262  compoundgood(iWord, 1) == 1)
263  {
264  retVal = true;
265  }
266  }
267 
268  return retVal;
269 }
270 
271 TQStringList
272 ISpellChecker::suggestWord(const TQString& utf8Word)
273 {
274  ichar_t iWord[INPUTWORDLEN + MAXAFFIXLEN];
275  int c;
276 
277  if (!m_bSuccessfulInit)
278  return TQStringList();
279 
280  if (utf8Word.isEmpty() || utf8Word.length() >= (INPUTWORDLEN + MAXAFFIXLEN) ||
281  utf8Word.length() == 0)
282  return TQStringList();
283 
284  TQCString out;
285  if (!m_translate_in)
286  return TQStringList();
287  else
288  {
289  /* convert to 8bit string and null terminate */
290 
291  int len_out = utf8Word.length();
292  out = m_translate_in->fromUnicode( utf8Word, len_out );
293  }
294 
295  if (!strtoichar(iWord, out.data(), INPUTWORDLEN + MAXAFFIXLEN, 0))
296  makepossibilities(iWord);
297  else
298  return TQStringList();
299 
300  TQStringList sugg_arr;
301  for (c = 0; c < m_pcount; c++)
302  {
303  TQString utf8Word;
304 
305  if (!m_translate_in)
306  {
307  /* copy to 8bit string and null terminate */
308  utf8Word = TQString::fromUtf8( m_possibilities[c] );
309  }
310  else
311  {
312  /* convert to 32bit string and null terminate */
313  utf8Word = m_translate_in->toUnicode( m_possibilities[c] );
314  }
315 
316  sugg_arr.append( utf8Word );
317  }
318 
319  return sugg_arr;
320 }
321 
322 static void
323 s_buildHashNames (std::vector<std::string> & names, const char * dict)
324 {
325  const char * tmp = 0;
326  int i = 0;
327 
328  names.clear ();
329 
330  while ( (tmp = ispell_dirs[i++]) ) {
331  TQCString maybeFile = TQCString( tmp ) + '/';
332  maybeFile += dict;
333  names.push_back( maybeFile.data() );
334  }
335 }
336 
337 static void
338 s_allDics()
339 {
340  const char * tmp = 0;
341  int i = 0;
342 
343  while ( (tmp = ispell_dirs[i++]) ) {
344  TQDir dir( tmp );
345  TQStringList lst = dir.entryList( "*.hash" );
346  for ( TQStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) {
347  TQFileInfo info( *it );
348  for (size_t i = 0; i < size_ispell_map; i++)
349  {
350  const IspellMap * mapping = (const IspellMap *)(&(ispell_map[i]));
351  if (!strcmp (info.fileName().latin1(), mapping->dict))
352  {
353  ispell_dict_map.insert( mapping->lang, *it );
354  }
355  }
356  }
357  }
358 }
359 
360 TQValueList<TQString>
361 ISpellChecker::allDics()
362 {
363  if ( ispell_dict_map.empty() )
364  s_allDics();
365 
366  return ispell_dict_map.keys();
367 }
368 
369 TQString
370 ISpellChecker::loadDictionary (const char * szdict)
371 {
372  std::vector<std::string> dict_names;
373 
374  s_buildHashNames (dict_names, szdict);
375 
376  for (size_t i = 0; i < dict_names.size(); i++)
377  {
378  if (linit(const_cast<char*>(dict_names[i].c_str())) >= 0)
379  return dict_names[i].c_str();
380  }
381 
382  return TQString::null;
383 }
384 
391 bool
392 ISpellChecker::loadDictionaryForLanguage ( const char * szLang )
393 {
394  TQString hashname;
395 
396  const char * encoding = NULL;
397  const char * szFile = NULL;
398 
399  for (size_t i = 0; i < size_ispell_map; i++)
400  {
401  const IspellMap * mapping = (const IspellMap *)(&(ispell_map[i]));
402  if (!strcmp (szLang, mapping->lang))
403  {
404  szFile = mapping->dict;
405  encoding = mapping->enc;
406  break;
407  }
408  }
409 
410  if (!szFile || !strlen(szFile))
411  return false;
412 
413  alloc_ispell_struct();
414 
415  hashname = loadDictionary(szFile);
416  if (hashname.isEmpty())
417  return false;
418 
419  // one of the two above calls succeeded
420  setDictionaryEncoding (hashname, encoding);
421 
422  return true;
423 }
424 
425 void
426 ISpellChecker::setDictionaryEncoding( const TQString& hashname, const char * encoding )
427 {
428  /* Get Hash encoding from XML file. This should always work! */
429  try_autodetect_charset(encoding);
430 
431  if (m_translate_in)
432  {
433  /* We still have to setup prefstringchar*/
434  prefstringchar = findfiletype("utf8", 1, deftflag < 0 ? &deftflag
435  : static_cast<int *>(NULL));
436 
437  if (prefstringchar < 0)
438  {
439  std::string teststring;
440  for(int n1 = 1; n1 <= 15; n1++)
441  {
442  teststring = "latin" + n1;
443  prefstringchar = findfiletype(teststring.c_str(), 1,
444  deftflag < 0 ? &deftflag : static_cast<int *>(NULL));
445  if (prefstringchar >= 0)
446  break;
447  }
448  }
449 
450  return; /* success */
451  }
452 
453  /* Test for UTF-8 first */
454  prefstringchar = findfiletype("utf8", 1, deftflag < 0 ? &deftflag : static_cast<int *>(NULL));
455  if (prefstringchar >= 0)
456  {
457  m_translate_in = TQTextCodec::codecForName("utf8");
458  }
459 
460  if (m_translate_in)
461  return; /* success */
462 
463  /* Test for "latinN" */
464  if (!m_translate_in)
465  {
466  /* Look for "altstringtype" names from latin1 to latin15 */
467  for(int n1 = 1; n1 <= 15; n1++)
468  {
469  TQString teststring = TQString("latin%1").arg(n1);
470  prefstringchar = findfiletype(teststring.latin1(), 1,
471  deftflag < 0 ? &deftflag : static_cast<int *>(NULL));
472  if (prefstringchar >= 0)
473  {
474  //FIXME: latin1 might be wrong
475  m_translate_in = TQTextCodec::codecForName( teststring.latin1() );
476  break;
477  }
478  }
479  }
480 
481  /* If nothing found, use latin1 */
482  if (!m_translate_in)
483  {
484  m_translate_in = TQTextCodec::codecForName("latin1");
485  }
486 }
487 
488 bool
489 ISpellChecker::requestDictionary(const char *szLang)
490 {
491  if (!loadDictionaryForLanguage (szLang))
492  {
493  // handle a shortened version of the language tag: en_US => en
494  std::string shortened_dict (szLang);
495  size_t uscore_pos;
496 
497  if ((uscore_pos = shortened_dict.rfind ('_')) != ((size_t)-1)) {
498  shortened_dict = shortened_dict.substr(0, uscore_pos);
499  if (!loadDictionaryForLanguage (shortened_dict.c_str()))
500  return false;
501  } else
502  return false;
503  }
504 
505  m_bSuccessfulInit = true;
506 
507  if (prefstringchar < 0)
508  m_defdupchar = 0;
509  else
510  m_defdupchar = prefstringchar;
511 
512  return true;
513 }

kspell2

Skip menu "kspell2"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kspell2

Skip menu "kspell2"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kspell2 by doxygen 1.8.1.2
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |