1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Mozilla Public License Version
6
* 1.1 (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is Mozilla Spellchecker Component.
17
* The Initial Developer of the Original Code is
19
* Portions created by the Initial Developer are Copyright (C) 2001
20
* the Initial Developer. All Rights Reserved.
22
* Contributor(s): David Einstein <Deinst@world.std.com>
23
* Kevin Hendricks <kevin.hendricks@sympatico.ca>
25
* Alternatively, the contents of this file may be used under the terms of
26
* either the GNU General Public License Version 2 or later (the "GPL"), or
27
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
* in which case the provisions of the GPL or the LGPL are applicable instead
29
* of those above. If you wish to allow use of your version of this file only
30
* under the terms of either the GPL or the LGPL, and not to allow others to
31
* use your version of this file under the terms of the MPL, indicate your
32
* decision by deleting the provisions above and replace them with the notice
33
* and other provisions required by the GPL or the LGPL. If you do not delete
34
* the provisions above, a recipient may use your version of this file under
35
* the terms of any one of the MPL, the GPL or the LGPL.
37
* This spellchecker is based on the MySpell spellchecker made for Open Office
38
* by Kevin Hendricks. Although the algorithms and code, have changed
39
* slightly, the architecture is still the same. The Mozilla implementation
40
* is designed to be compatible with the Open Office dictionaries.
41
* Please do not make changes to the affix or dictionary file formats
42
* without attempting to coordinate with Kevin. For more information
43
* on the original MySpell see
44
* http://whiteboard.openoffice.org/source/browse/whiteboard/lingucomponent/source/spellcheck/myspell/
46
* A special thanks and credit goes to Geoff Kuenning
47
* the creator of ispell. MySpell's affix algorithms were
48
* based on those of ispell which should be noted is
49
* copyright Geoff Kuenning et.al. and now available
50
* under a BSD style license. For more information on ispell
51
* and affix compression in general, please see:
52
* http://www.cs.ucla.edu/ficus-members/geoff/ispell.html
53
* (the home page for ispell)
55
* ***** END LICENSE BLOCK ***** */
56
#include "myspSuggestmgr.h"
58
#include "nsReadableUtils.h"
60
#include "nsUnicharUtils.h"
62
myspSuggestMgr::myspSuggestMgr()
67
myspSuggestMgr::~myspSuggestMgr()
74
myspSuggestMgr::setup(const nsAFlatString &tryme, int maxn, myspAffixMgr *aptr)
76
// register affix manager and check in string of chars to
77
// try when building candidate suggestions
84
// generate suggestions for a mispelled word
85
// pass in address of array of char * pointers
87
nsresult myspSuggestMgr::suggest(PRUnichar ***slst,const nsAFlatString &word, PRUint32 *num)
89
NS_ENSURE_ARG_POINTER(num);
90
NS_ENSURE_ARG_POINTER(slst);
98
wlst=(PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * maxSug);
100
return NS_ERROR_OUT_OF_MEMORY;
101
memset(wlst, nsnull, sizeof(PRUnichar*) * maxSug);
108
// perhaps we made a typical fault of spelling
109
res = replchars(wlst, word, &nsug);
111
// did we forget to add a char
112
if ((nsug < maxSug) && NS_SUCCEEDED(res)){
113
res = forgotchar(wlst, word, &nsug);
116
// did we swap the order of chars by mistake
117
if ((nsug < maxSug) && NS_SUCCEEDED(res)){
118
res = swapchar(wlst, word, &nsug);
121
// did we add a char that should not be there
122
if ((nsug < maxSug) && NS_SUCCEEDED(res)){
123
res = extrachar(wlst, word, &nsug);
126
// did we just hit the wrong key in place of a good char
127
if ((nsug < maxSug) && NS_SUCCEEDED(res)){
128
res = badchar(wlst, word, &nsug);
131
// perhaps we forgot to hit space and two words ran together
132
if ((nsug < maxSug) && NS_SUCCEEDED(res)){
133
res = twowords(wlst, word, &nsug);
136
for (i=0;i<maxSug; i++)
137
if (wlst[i] != NULL) nsMemory::Free(wlst[i]);
138
nsMemory::Free(wlst);
150
// suggestions for a typical fault of spelling, that
151
// differs with more, than 1 letter from the right form.
152
nsresult myspSuggestMgr::replchars(PRUnichar ** wlst,const nsAFlatString &word, PRUint32 *ns)
157
PRUint32 startOffset, findOffset;
159
if (word.Length() < 2 || ! pAMgr) return NS_OK;
161
PRUint32 replaceTableLength = pAMgr->getReplaceTableLength();
162
struct mozReplaceTable *replaceTable = pAMgr->getReplaceTable();
164
if (replaceTable == nsnull) return NS_OK;
166
for (i=0; i < replaceTableLength; i++ ) {
169
candidate.Assign(word);
170
ToLowerCase(candidate);
172
while ((findOffset = candidate.Find(replaceTable[i].pattern, startOffset)) != -1) {
173
candidate.Assign(word);
174
ToLowerCase(candidate);
175
candidate.Replace(findOffset, replaceTable[i].pattern.Length(), replaceTable[i].replacement);
178
for(k=0;k < *ns;k++){
179
if (candidate.Equals(wlst[k]) ){
185
if (cwrd && pAMgr->check(candidate)) {
187
wlst[*ns] = ToNewUnicode(candidate);
189
return NS_ERROR_OUT_OF_MEMORY;
194
startOffset = findOffset + replaceTable[i].pattern.Length();
201
// error is wrong char in place of correct one
202
nsresult myspSuggestMgr::badchar(PRUnichar ** wlst,const nsAFlatString &word, PRUint32 *ns)
205
nsAutoString candidate;
208
PRUint32 wl = word.Length();
209
candidate.Assign(word);
210
nsASingleFragmentString::char_iterator candIt;
211
for (i=0,candidate.BeginWriting(candIt); i < wl; i++,candIt++) {
213
for (j=0; j < ctry.Length(); j++) {
214
if (ctry[j] == tmpc) continue;
217
for(k=0;k < *ns;k++){
218
if (candidate.Equals(wlst[k]) ){
223
if (cwrd && pAMgr->check(candidate)) {
225
wlst[*ns] = ToNewUnicode(candidate);
227
return NS_ERROR_OUT_OF_MEMORY;
238
// error is word has an extra letter it does not need
239
nsresult myspSuggestMgr::extrachar(PRUnichar ** wlst,const nsAFlatString &word, PRUint32 *ns)
243
nsAutoString candidate;
245
PRUint32 wl = word.Length();
246
if (wl < 2) return 0;
248
// try omitting one char of word at a time
249
candidate.Assign(Substring(word,1,wl-1));
250
nsASingleFragmentString::char_iterator r;
251
nsASingleFragmentString::const_char_iterator p,end;
252
word.EndReading(end);
254
for (word.BeginReading(p),candidate.BeginWriting(r); p != end; ) {
256
for(k=0;k < *ns;k++){
257
if (candidate.Equals(wlst[k])){
262
if (cwrd && pAMgr->check(candidate)) {
264
wlst[*ns] = ToNewUnicode(candidate);
266
return NS_ERROR_OUT_OF_MEMORY;
276
// error is mising a letter it needs
277
nsresult myspSuggestMgr::forgotchar(PRUnichar **wlst,const nsAFlatString &word, PRUint32 *ns)
281
nsAutoString candidate;
283
candidate = NS_LITERAL_STRING(" ") + word;
284
nsASingleFragmentString::char_iterator q;
285
nsASingleFragmentString::const_char_iterator p,end;
286
word.EndReading(end);
288
// try inserting a tryme character before every letter
289
for (word.BeginReading(p), candidate.BeginWriting(q); p != end; ) {
290
for ( i = 0; i < ctry.Length(); i++) {
293
for(k=0;k < *ns;k++){
294
if (candidate.Equals(wlst[k]) ){
299
if (cwrd && pAMgr->check(candidate)) {
301
wlst[*ns] = ToNewUnicode(candidate);
303
return NS_ERROR_OUT_OF_MEMORY;
311
// now try adding one to end */
312
for ( i = 0; i < ctry.Length(); i++) {
315
for(k=0;k < *ns;k++){
316
if (candidate.Equals(wlst[k])){
321
if (cwrd && pAMgr->check(candidate)) {
323
wlst[*ns] = ToNewUnicode(candidate);
325
return NS_ERROR_OUT_OF_MEMORY;
334
/* error is should have been two words */
335
nsresult myspSuggestMgr::twowords(PRUnichar ** wlst,const nsAFlatString &word, PRUint32 *ns)
337
nsAutoString candidate;
339
PRUint32 wl=word.Length();
340
if (wl < 3) return NS_OK;
341
candidate.Assign(word);
344
// split the string into two pieces after every char
345
// if both pieces are good words make them a suggestion
346
for (pos = 1; pos < wl; pos++) {
347
temp.Assign(Substring(candidate,0,pos));
348
if (pAMgr->check(temp)) {
349
temp.Assign(Substring(candidate,pos,wl-pos));
350
if (pAMgr->check(temp)) {
352
candidate.Insert(PRUnichar(' '),pos);
353
wlst[*ns] = ToNewUnicode(candidate);
355
return NS_ERROR_OUT_OF_MEMORY;
365
// error is adjacent letter were swapped
366
nsresult myspSuggestMgr::swapchar(PRUnichar **wlst,const nsAFlatString &word, PRUint32 *ns)
368
nsAutoString candidate;
372
candidate.Assign(word);
373
nsASingleFragmentString::char_iterator p,q,end;
374
candidate.EndWriting(end);
376
for (candidate.BeginWriting(p),q=p, q++; q != end; p++,q++) {
381
for(k=0;k < *ns;k++){
382
if (candidate.Equals(wlst[k])){
387
if (cwrd && pAMgr->check(candidate)) {
389
wlst[*ns] = ToNewUnicode(candidate);
391
return NS_ERROR_OUT_OF_MEMORY;