~efargaspro/+junk/codeblocks-16.01-release

« back to all changes in this revision

Viewing changes to src/plugins/contrib/SpellChecker/wxspellchecker/MySpell/affentry.cxx

  • Committer: damienlmoore at gmail
  • Date: 2016-02-02 02:43:22 UTC
  • Revision ID: damienlmoore@gmail.com-20160202024322-yql5qmtbwdyamdwd
Code::BlocksĀ 16.01

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "license.readme"
 
2
 
 
3
 
 
4
#include <cctype>
 
5
#include <cstring>
 
6
#include <cstdlib>
 
7
#include <cstdio>
 
8
#include <vector>
 
9
 
 
10
#include "affentry.hxx"
 
11
 
 
12
using namespace std;
 
13
 
 
14
extern char * mystrdup(const char * s);
 
15
extern char *  myrevstrdup(const char * s);
 
16
 
 
17
PfxEntry::PfxEntry(AffixMgr* pmgr, affentry* dp)
 
18
{
 
19
  // register affix manager
 
20
  pmyMgr = pmgr;
 
21
 
 
22
  // set up its intial values
 
23
  achar = dp->achar;         // char flag 
 
24
  strip = dp->strip;         // string to strip
 
25
  appnd = dp->appnd;         // string to append
 
26
  stripl = dp->stripl;       // length of strip string
 
27
  appndl = dp->appndl;       // length of append string
 
28
  numconds = dp->numconds;   // number of conditions to match
 
29
  xpflg = dp->xpflg;         // cross product flag
 
30
  // then copy over all of the conditions
 
31
  memcpy(&conds[0],&dp->conds[0],SETSIZE*sizeof(conds[0]));
 
32
  next = NULL;
 
33
  nextne = NULL;
 
34
  nexteq = NULL;
 
35
}
 
36
 
 
37
 
 
38
PfxEntry::~PfxEntry()
 
39
{
 
40
    achar = '\0';
 
41
    if (appnd) free(appnd);
 
42
    if (strip)free(strip);
 
43
    pmyMgr = NULL;
 
44
    appnd = NULL;
 
45
    strip = NULL;    
 
46
}
 
47
 
 
48
 
 
49
 
 
50
// add prefix to this word assuming conditions hold
 
51
char * PfxEntry::add(const char * word, int len)
 
52
{
 
53
    int                 cond;
 
54
    char                tword[MAXWORDLEN+1];
 
55
 
 
56
     /* make sure all conditions match */
 
57
     if ((len > stripl) && (len >= numconds)) {
 
58
            unsigned char * cp = (unsigned char *) word;
 
59
            for (cond = 0;  cond < numconds;  cond++) {
 
60
               if ((conds[*cp++] & (1 << cond)) == 0)
 
61
                  break;
 
62
            }
 
63
            if (cond >= numconds) {
 
64
              /* we have a match so add prefix */
 
65
              int tlen = 0;
 
66
              if (appndl) {
 
67
                  strcpy(tword,appnd);
 
68
                  tlen += appndl;
 
69
               } 
 
70
               char * pp = tword + tlen;
 
71
               strcpy(pp, (word + stripl));
 
72
               return mystrdup(tword);
 
73
            }
 
74
     }
 
75
     return NULL;    
 
76
}
 
77
 
 
78
 
 
79
 
 
80
 
 
81
// check if this prefix entry matches 
 
82
struct hentry * PfxEntry::check(const char * word, int len)
 
83
{
 
84
    int                 cond;   // condition number being examined
 
85
    int                 tmpl;   // length of tmpword
 
86
    struct hentry *     he;     // hash entry of root word or NULL
 
87
    unsigned char *     cp;             
 
88
    char                tmpword[MAXWORDLEN+1];
 
89
 
 
90
 
 
91
    // on entry prefix is 0 length or already matches the beginning of the word.
 
92
    // So if the remaining root word has positive length
 
93
    // and if there are enough chars in root word and added back strip chars
 
94
    // to meet the number of characters conditions, then test it
 
95
 
 
96
     tmpl = len - appndl;
 
97
 
 
98
     if ((tmpl > 0) &&  (tmpl + stripl >= numconds)) {
 
99
 
 
100
            // generate new root word by removing prefix and adding
 
101
            // back any characters that would have been stripped
 
102
 
 
103
            if (stripl) strcpy (tmpword, strip);
 
104
            strcpy ((tmpword + stripl), (word + appndl));
 
105
 
 
106
            // now make sure all of the conditions on characters
 
107
            // are met.  Please see the appendix at the end of
 
108
            // this file for more info on exactly what is being
 
109
            // tested
 
110
 
 
111
            cp = (unsigned char *)tmpword;
 
112
            for (cond = 0;  cond < numconds;  cond++) {
 
113
                if ((conds[*cp++] & (1 << cond)) == 0) break;
 
114
            }
 
115
 
 
116
            // if all conditions are met then check if resulting
 
117
            // root word in the dictionary
 
118
 
 
119
            if (cond >= numconds) {
 
120
                tmpl += stripl;
 
121
                if ((he = pmyMgr->lookup(tmpword)) != NULL) {
 
122
                   if (TESTAFF(he->astr, achar, he->alen)) return he;
 
123
                }
 
124
 
 
125
                // prefix matched but no root word was found 
 
126
                // if XPRODUCT is allowed, try again but now 
 
127
                // ross checked combined with a suffix
 
128
 
 
129
                if (xpflg & XPRODUCT) {
 
130
                   he = pmyMgr->suffix_check(tmpword, tmpl, XPRODUCT, (AffEntry *)this);
 
131
                   if (he) return he;
 
132
                }
 
133
            }
 
134
     }
 
135
    return NULL;
 
136
}
 
137
 
 
138
 
 
139
 
 
140
SfxEntry::SfxEntry(AffixMgr * pmgr, affentry* dp)
 
141
{
 
142
  // register affix manager
 
143
  pmyMgr = pmgr;
 
144
 
 
145
  // set up its intial values
 
146
  achar = dp->achar;         // char flag 
 
147
  strip = dp->strip;         // string to strip
 
148
  appnd = dp->appnd;         // string to append
 
149
  stripl = dp->stripl;       // length of strip string
 
150
  appndl = dp->appndl;       // length of append string
 
151
  numconds = dp->numconds;   // number of conditions to match
 
152
  xpflg = dp->xpflg;         // cross product flag
 
153
 
 
154
  // then copy over all of the conditions
 
155
  memcpy(&conds[0],&dp->conds[0],SETSIZE*sizeof(conds[0]));
 
156
 
 
157
  rappnd = myrevstrdup(appnd);
 
158
}
 
159
 
 
160
 
 
161
SfxEntry::~SfxEntry()
 
162
{
 
163
    achar = '\0';
 
164
    if (appnd) free(appnd);
 
165
    if (rappnd) free(rappnd);
 
166
    if (strip) free(strip);
 
167
    pmyMgr = NULL;
 
168
    appnd = NULL;
 
169
    strip = NULL;    
 
170
}
 
171
 
 
172
 
 
173
 
 
174
// add suffix to this word assuming conditions hold
 
175
char * SfxEntry::add(const char * word, int len)
 
176
{
 
177
    int                 cond;
 
178
    char                tword[MAXWORDLEN+1];
 
179
 
 
180
     /* make sure all conditions match */
 
181
     if ((len > stripl) && (len >= numconds)) {
 
182
            unsigned char * cp = (unsigned char *) (word + len);
 
183
            for (cond = numconds; --cond >=0; ) {
 
184
               if ((conds[*--cp] & (1 << cond)) == 0)
 
185
                  break;
 
186
            }
 
187
            if (cond < 0) {
 
188
              /* we have a match so add suffix */
 
189
              strcpy(tword,word);
 
190
              int tlen = len;
 
191
              if (stripl) {
 
192
                 tlen -= stripl;
 
193
              }
 
194
              char * pp = (tword + tlen);
 
195
              if (appndl) {
 
196
                  strcpy(pp,appnd);
 
197
                  tlen += appndl;
 
198
              } else *pp = '\0';
 
199
               return mystrdup(tword);
 
200
            }
 
201
     }
 
202
     return NULL;
 
203
}
 
204
 
 
205
 
 
206
 
 
207
// see if this suffix is present in the word 
 
208
struct hentry * SfxEntry::check(const char * word, int len, int optflags, AffEntry* ppfx)
 
209
{
 
210
    int                 tmpl;            // length of tmpword 
 
211
    int                 cond;            // condition beng examined
 
212
    struct hentry *     he;              // hash entry pointer
 
213
    unsigned char *     cp;
 
214
    char                tmpword[MAXWORDLEN+1];
 
215
    PfxEntry* ep = (PfxEntry *) ppfx;
 
216
 
 
217
 
 
218
    // if this suffix is being cross checked with a prefix
 
219
    // but it does not support cross products skip it
 
220
 
 
221
    if ((optflags & XPRODUCT) != 0 &&  (xpflg & XPRODUCT) == 0)
 
222
        return NULL;
 
223
 
 
224
    // upon entry suffix is 0 length or already matches the end of the word.
 
225
    // So if the remaining root word has positive length
 
226
    // and if there are enough chars in root word and added back strip chars
 
227
    // to meet the number of characters conditions, then test it
 
228
 
 
229
    tmpl = len - appndl;
 
230
 
 
231
    if ((tmpl > 0)  &&  (tmpl + stripl >= numconds)) {
 
232
 
 
233
            // generate new root word by removing suffix and adding
 
234
            // back any characters that would have been stripped or
 
235
            // or null terminating the shorter string
 
236
 
 
237
            strcpy (tmpword, word);
 
238
            cp = (unsigned char *)(tmpword + tmpl);
 
239
            if (stripl) {
 
240
                strcpy ((char *)cp, strip);
 
241
                tmpl += stripl;
 
242
                cp = (unsigned char *)(tmpword + tmpl);
 
243
            } else *cp = '\0';
 
244
 
 
245
            // now make sure all of the conditions on characters
 
246
            // are met.  Please see the appendix at the end of
 
247
            // this file for more info on exactly what is being
 
248
            // tested
 
249
 
 
250
            for (cond = numconds;  --cond >= 0; ) {
 
251
                if ((conds[*--cp] & (1 << cond)) == 0) break;
 
252
            }
 
253
 
 
254
            // if all conditions are met then check if resulting
 
255
            // root word in the dictionary
 
256
 
 
257
            if (cond < 0) {
 
258
                if ((he = pmyMgr->lookup(tmpword)) != NULL) {
 
259
                     if (TESTAFF(he->astr, achar , he->alen) && 
 
260
                           ((optflags & XPRODUCT) == 0 || 
 
261
                           TESTAFF(he->astr, ep->getFlag(), he->alen))) return he;
 
262
                }  
 
263
            }
 
264
    }
 
265
    return NULL;
 
266
}
 
267
 
 
268
 
 
269
 
 
270
 
 
271
#if 0
 
272
 
 
273
Appendix:  Understanding Affix Code
 
274
 
 
275
 
 
276
An affix is either a  prefix or a suffix attached to root words to make 
 
277
other words.
 
278
 
 
279
Basically a Prefix or a Suffix is set of AffEntry objects
 
280
which store information about the prefix or suffix along 
 
281
with supporting routines to check if a word has a particular 
 
282
prefix or suffix or a combination.
 
283
 
 
284
The structure affentry is defined as follows:
 
285
 
 
286
struct affentry
 
287
{
 
288
   unsigned char achar;   // char used to represent the affix
 
289
   char * strip;          // string to strip before adding affix
 
290
   char * appnd;          // the affix string to add
 
291
   short  stripl;         // length of the strip string
 
292
   short  appndl;         // length of the affix string
 
293
   short  numconds;       // the number of conditions that must be met
 
294
   short  xpflg;          // flag: XPRODUCT- combine both prefix and suffix 
 
295
   char   conds[SETSIZE]; // array which encodes the conditions to be met
 
296
};
 
297
 
 
298
 
 
299
Here is a suffix borrowed from the en_US.aff file.  This file 
 
300
is whitespace delimited.
 
301
 
 
302
SFX D Y 4 
 
303
SFX D   0     e          d
 
304
SFX D   y     ied        [^aeiou]y
 
305
SFX D   0     ed         [^ey]
 
306
SFX D   0     ed         [aeiou]y
 
307
 
 
308
This information can be interpreted as follows:
 
309
 
 
310
In the first line has 4 fields
 
311
 
 
312
Field
 
313
-----
 
314
1     SFX - indicates this is a suffix
 
315
2     D   - is the name of the character flag which represents this suffix
 
316
3     Y   - indicates it can be combined with prefixes (cross product)
 
317
4     4   - indicates that sequence of 4 affentry structures are needed to
 
318
               properly store the affix information
 
319
 
 
320
The remaining lines describe the unique information for the 4 SfxEntry 
 
321
objects that make up this affix.  Each line can be interpreted
 
322
as follows: (note fields 1 and 2 are as a check against line 1 info)
 
323
 
 
324
Field
 
325
-----
 
326
1     SFX         - indicates this is a suffix
 
327
2     D           - is the name of the character flag for this affix
 
328
3     y           - the string of chars to strip off before adding affix
 
329
                         (a 0 here indicates the NULL string)
 
330
4     ied         - the string of affix characters to add
 
331
5     [^aeiou]y   - the conditions which must be met before the affix
 
332
                    can be applied
 
333
 
 
334
Field 5 is interesting.  Since this is a suffix, field 5 tells us that
 
335
there are 2 conditions that must be met.  The first condition is that 
 
336
the next to the last character in the word must *NOT* be any of the 
 
337
following "a", "e", "i", "o" or "u".  The second condition is that
 
338
the last character of the word must end in "y".
 
339
 
 
340
So how can we encode this information concisely and be able to 
 
341
test for both conditions in a fast manner?  The answer is found
 
342
but studying the wonderful ispell code of Geoff Kuenning, et.al. 
 
343
(now available under a normal BSD license).
 
344
 
 
345
If we set up a conds array of 256 bytes indexed (0 to 255) and access it
 
346
using a character (cast to an unsigned char) of a string, we have 8 bits
 
347
of information we can store about that character.  Specifically we
 
348
could use each bit to say if that character is allowed in any of the 
 
349
last (or first for prefixes) 8 characters of the word.
 
350
 
 
351
Basically, each character at one end of the word (up to the number 
 
352
of conditions) is used to index into the conds array and the resulting 
 
353
value found there says whether the that character is valid for a 
 
354
specific character position in the word.  
 
355
 
 
356
For prefixes, it does this by setting bit 0 if that char is valid 
 
357
in the first position, bit 1 if valid in the second position, and so on. 
 
358
 
 
359
If a bit is not set, then that char is not valid for that postion in the
 
360
word.
 
361
 
 
362
If working with suffixes bit 0 is used for the character closest 
 
363
to the front, bit 1 for the next character towards the end, ..., 
 
364
with bit numconds-1 representing the last char at the end of the string. 
 
365
 
 
366
Note: since entries in the conds[] are 8 bits, only 8 conditions 
 
367
(read that only 8 character positions) can be examined at one
 
368
end of a word (the beginning for prefixes and the end for suffixes.
 
369
 
 
370
So to make this clearer, lets encode the conds array values for the 
 
371
first two affentries for the suffix D described earlier.
 
372
 
 
373
 
 
374
  For the first affentry:    
 
375
     numconds = 1             (only examine the last character)
 
376
 
 
377
     conds['e'] =  (1 << 0)   (the word must end in an E)
 
378
     all others are all 0
 
379
 
 
380
  For the second affentry:
 
381
     numconds = 2             (only examine the last two characters)     
 
382
 
 
383
     conds[X] = conds[X] | (1 << 0)     (aeiou are not allowed)
 
384
         where X is all characters *but* a, e, i, o, or u
 
385
         
 
386
 
 
387
     conds['y'] = (1 << 1)     (the last char must be a y)
 
388
     all other bits for all other entries in the conds array are zero
 
389
 
 
390
 
 
391
#endif
 
392