1 | #ifndef lint |
---|
2 | static char Rcs_Id[] = |
---|
3 | "$Id: good.c,v 1.1.1.1 1997-09-03 21:08:10 ghudson Exp $"; |
---|
4 | #endif |
---|
5 | |
---|
6 | /* |
---|
7 | * good.c - see if a word or its root word |
---|
8 | * is in the dictionary. |
---|
9 | * |
---|
10 | * Pace Willisson, 1983 |
---|
11 | * |
---|
12 | * Copyright 1992, 1993, Geoff Kuenning, Granada Hills, CA |
---|
13 | * All rights reserved. |
---|
14 | * |
---|
15 | * Redistribution and use in source and binary forms, with or without |
---|
16 | * modification, are permitted provided that the following conditions |
---|
17 | * are met: |
---|
18 | * |
---|
19 | * 1. Redistributions of source code must retain the above copyright |
---|
20 | * notice, this list of conditions and the following disclaimer. |
---|
21 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
22 | * notice, this list of conditions and the following disclaimer in the |
---|
23 | * documentation and/or other materials provided with the distribution. |
---|
24 | * 3. All modifications to the source code must be clearly marked as |
---|
25 | * such. Binary redistributions based on modified source code |
---|
26 | * must be clearly marked as modified versions in the documentation |
---|
27 | * and/or other materials provided with the distribution. |
---|
28 | * 4. All advertising materials mentioning features or use of this software |
---|
29 | * must display the following acknowledgment: |
---|
30 | * This product includes software developed by Geoff Kuenning and |
---|
31 | * other unpaid contributors. |
---|
32 | * 5. The name of Geoff Kuenning may not be used to endorse or promote |
---|
33 | * products derived from this software without specific prior |
---|
34 | * written permission. |
---|
35 | * |
---|
36 | * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND |
---|
37 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
38 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
39 | * ARE DISCLAIMED. IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE |
---|
40 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
41 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
42 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
43 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
44 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
45 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
46 | * SUCH DAMAGE. |
---|
47 | */ |
---|
48 | |
---|
49 | /* |
---|
50 | * $Log: not supported by cvs2svn $ |
---|
51 | * Revision 1.43 1994/11/02 06:56:05 geoff |
---|
52 | * Remove the anyword feature, which I've decided is a bad idea. |
---|
53 | * |
---|
54 | * Revision 1.42 1994/10/25 05:45:59 geoff |
---|
55 | * Add support for an affix that will work with any word, even if there's |
---|
56 | * no explicit flag. |
---|
57 | * |
---|
58 | * Revision 1.41 1994/05/24 06:23:06 geoff |
---|
59 | * Let tgood decide capitalization questions, rather than doing it ourselves. |
---|
60 | * |
---|
61 | * Revision 1.40 1994/05/17 06:44:10 geoff |
---|
62 | * Add support for controlled compound formation and the COMPOUNDONLY |
---|
63 | * option to affix flags. |
---|
64 | * |
---|
65 | * Revision 1.39 1994/01/25 07:11:31 geoff |
---|
66 | * Get rid of all old RCS log lines in preparation for the 3.1 release. |
---|
67 | * |
---|
68 | */ |
---|
69 | |
---|
70 | #include <ctype.h> |
---|
71 | #include "config.h" |
---|
72 | #include "ispell.h" |
---|
73 | #include "proto.h" |
---|
74 | |
---|
75 | int good P ((ichar_t * word, int ignoreflagbits, int allhits, |
---|
76 | int pfxopts, int sfxopts)); |
---|
77 | #ifndef NO_CAPITALIZATION_SUPPORT |
---|
78 | int cap_ok P ((ichar_t * word, struct success * hit, int len)); |
---|
79 | static int entryhasaffixes P ((struct dent * dent, struct success * hit)); |
---|
80 | #endif /* NO_CAPITALIZATION_SUPPORT */ |
---|
81 | void flagpr P ((ichar_t * word, int preflag, int prestrip, |
---|
82 | int preadd, int sufflag, int sufadd)); |
---|
83 | |
---|
84 | static ichar_t * orig_word; |
---|
85 | |
---|
86 | #ifndef NO_CAPITALIZATION_SUPPORT |
---|
87 | int good (w, ignoreflagbits, allhits, pfxopts, sfxopts) |
---|
88 | ichar_t * w; /* Word to look up */ |
---|
89 | int ignoreflagbits; /* NZ to ignore affix flags in dict */ |
---|
90 | int allhits; /* NZ to ignore case, get every hit */ |
---|
91 | int pfxopts; /* Options to apply to prefixes */ |
---|
92 | int sfxopts; /* Options to apply to suffixes */ |
---|
93 | #else |
---|
94 | /* ARGSUSED */ |
---|
95 | int good (w, ignoreflagbits, dummy, pfxopts, sfxopts) |
---|
96 | ichar_t * w; /* Word to look up */ |
---|
97 | int ignoreflagbits; /* NZ to ignore affix flags in dict */ |
---|
98 | int dummy; |
---|
99 | #define allhits 0 /* Never actually need more than one hit */ |
---|
100 | int pfxopts; /* Options to apply to prefixes */ |
---|
101 | int sfxopts; /* Options to apply to suffixes */ |
---|
102 | #endif |
---|
103 | { |
---|
104 | ichar_t nword[INPUTWORDLEN + MAXAFFIXLEN]; |
---|
105 | register ichar_t * p; |
---|
106 | register ichar_t * q; |
---|
107 | register n; |
---|
108 | register struct dent * dp; |
---|
109 | |
---|
110 | /* |
---|
111 | ** Make an uppercase copy of the word we are checking. |
---|
112 | */ |
---|
113 | for (p = w, q = nword; *p; ) |
---|
114 | *q++ = mytoupper (*p++); |
---|
115 | *q = 0; |
---|
116 | n = q - nword; |
---|
117 | |
---|
118 | numhits = 0; |
---|
119 | |
---|
120 | if (cflag) |
---|
121 | { |
---|
122 | (void) printf ("%s", ichartosstr (w, 0)); |
---|
123 | orig_word = w; |
---|
124 | } |
---|
125 | else if ((dp = lookup (nword, 1)) != NULL) |
---|
126 | { |
---|
127 | hits[0].dictent = dp; |
---|
128 | hits[0].prefix = NULL; |
---|
129 | hits[0].suffix = NULL; |
---|
130 | #ifndef NO_CAPITALIZATION_SUPPORT |
---|
131 | if (allhits || cap_ok (w, &hits[0], n)) |
---|
132 | numhits = 1; |
---|
133 | #else |
---|
134 | numhits = 1; |
---|
135 | #endif |
---|
136 | /* |
---|
137 | * If we're looking for compounds, and this root doesn't |
---|
138 | * participate in compound formation, undo the hit. |
---|
139 | */ |
---|
140 | if (compoundflag == COMPOUND_CONTROLLED |
---|
141 | && ((pfxopts | sfxopts) & FF_COMPOUNDONLY) != 0 |
---|
142 | && hashheader.compoundbit >= 0 |
---|
143 | && TSTMASKBIT (dp->mask, hashheader.compoundbit) == 0) |
---|
144 | numhits = 0; |
---|
145 | } |
---|
146 | if (numhits && !allhits) |
---|
147 | return 1; |
---|
148 | |
---|
149 | /* try stripping off affixes */ |
---|
150 | |
---|
151 | #if 0 |
---|
152 | numchars = icharlen (nword); |
---|
153 | if (numchars < 4) |
---|
154 | { |
---|
155 | if (cflag) |
---|
156 | (void) putchar ('\n'); |
---|
157 | return numhits || (numchars == 1); |
---|
158 | } |
---|
159 | #endif |
---|
160 | |
---|
161 | chk_aff (w, nword, n, ignoreflagbits, allhits, pfxopts, sfxopts); |
---|
162 | |
---|
163 | if (cflag) |
---|
164 | (void) putchar ('\n'); |
---|
165 | |
---|
166 | return numhits; |
---|
167 | } |
---|
168 | |
---|
169 | #ifndef NO_CAPITALIZATION_SUPPORT |
---|
170 | int cap_ok (word, hit, len) |
---|
171 | register ichar_t * word; |
---|
172 | register struct success * hit; |
---|
173 | int len; |
---|
174 | { |
---|
175 | register ichar_t * dword; |
---|
176 | register ichar_t * w; |
---|
177 | register struct dent * dent; |
---|
178 | ichar_t dentword[INPUTWORDLEN + MAXAFFIXLEN]; |
---|
179 | int preadd; |
---|
180 | int prestrip; |
---|
181 | int sufadd; |
---|
182 | ichar_t * limit; |
---|
183 | long thiscap; |
---|
184 | long dentcap; |
---|
185 | |
---|
186 | thiscap = whatcap (word); |
---|
187 | /* |
---|
188 | ** All caps is always legal, regardless of affixes. |
---|
189 | */ |
---|
190 | preadd = prestrip = sufadd = 0; |
---|
191 | if (thiscap == ALLCAPS) |
---|
192 | return 1; |
---|
193 | else if (thiscap == FOLLOWCASE) |
---|
194 | { |
---|
195 | /* Set up some constants for the while(1) loop below */ |
---|
196 | if (hit->prefix) |
---|
197 | { |
---|
198 | preadd = hit->prefix->affl; |
---|
199 | prestrip = hit->prefix->stripl; |
---|
200 | } |
---|
201 | else |
---|
202 | preadd = prestrip = 0; |
---|
203 | sufadd = hit->suffix ? hit->suffix->affl : 0; |
---|
204 | } |
---|
205 | /* |
---|
206 | ** Search the variants for one that matches what we have. Note |
---|
207 | ** that thiscap can't be ALLCAPS, since we already returned |
---|
208 | ** for that case. |
---|
209 | */ |
---|
210 | dent = hit->dictent; |
---|
211 | for ( ; ; ) |
---|
212 | { |
---|
213 | dentcap = captype (dent->flagfield); |
---|
214 | if (dentcap != thiscap) |
---|
215 | { |
---|
216 | if (dentcap == ANYCASE && thiscap == CAPITALIZED |
---|
217 | && entryhasaffixes (dent, hit)) |
---|
218 | return 1; |
---|
219 | } |
---|
220 | else /* captypes match */ |
---|
221 | { |
---|
222 | if (thiscap != FOLLOWCASE) |
---|
223 | { |
---|
224 | if (entryhasaffixes (dent, hit)) |
---|
225 | return 1; |
---|
226 | } |
---|
227 | else |
---|
228 | { |
---|
229 | /* |
---|
230 | ** Make sure followcase matches exactly. |
---|
231 | ** Life is made more difficult by the |
---|
232 | ** possibility of affixes. Start with |
---|
233 | ** the prefix. |
---|
234 | */ |
---|
235 | (void) strtoichar (dentword, dent->word, INPUTWORDLEN, 1); |
---|
236 | dword = dentword; |
---|
237 | limit = word + preadd; |
---|
238 | if (myupper (dword[prestrip])) |
---|
239 | { |
---|
240 | for (w = word; w < limit; w++) |
---|
241 | { |
---|
242 | if (mylower (*w)) |
---|
243 | goto doublecontinue; |
---|
244 | } |
---|
245 | } |
---|
246 | else |
---|
247 | { |
---|
248 | for (w = word; w < limit; w++) |
---|
249 | { |
---|
250 | if (myupper (*w)) |
---|
251 | goto doublecontinue; |
---|
252 | } |
---|
253 | } |
---|
254 | dword += prestrip; |
---|
255 | /* Do root part of word */ |
---|
256 | limit = dword + len - preadd - sufadd; |
---|
257 | while (dword < limit) |
---|
258 | { |
---|
259 | if (*dword++ != *w++) |
---|
260 | goto doublecontinue; |
---|
261 | } |
---|
262 | /* Do suffix */ |
---|
263 | dword = limit - 1; |
---|
264 | if (myupper (*dword)) |
---|
265 | { |
---|
266 | for ( ; *w; w++) |
---|
267 | { |
---|
268 | if (mylower (*w)) |
---|
269 | goto doublecontinue; |
---|
270 | } |
---|
271 | } |
---|
272 | else |
---|
273 | { |
---|
274 | for ( ; *w; w++) |
---|
275 | { |
---|
276 | if (myupper (*w)) |
---|
277 | goto doublecontinue; |
---|
278 | } |
---|
279 | } |
---|
280 | /* |
---|
281 | ** All failure paths go to "doublecontinue," |
---|
282 | ** so if we get here it must match. |
---|
283 | */ |
---|
284 | if (entryhasaffixes (dent, hit)) |
---|
285 | return 1; |
---|
286 | doublecontinue: ; |
---|
287 | } |
---|
288 | } |
---|
289 | if ((dent->flagfield & MOREVARIANTS) == 0) |
---|
290 | break; |
---|
291 | dent = dent->next; |
---|
292 | } |
---|
293 | |
---|
294 | /* No matches found */ |
---|
295 | return 0; |
---|
296 | } |
---|
297 | |
---|
298 | /* |
---|
299 | ** See if this particular capitalization (dent) is legal with these |
---|
300 | ** particular affixes. |
---|
301 | */ |
---|
302 | static int entryhasaffixes (dent, hit) |
---|
303 | register struct dent * dent; |
---|
304 | register struct success * hit; |
---|
305 | { |
---|
306 | |
---|
307 | if (hit->prefix && !TSTMASKBIT (dent->mask, hit->prefix->flagbit)) |
---|
308 | return 0; |
---|
309 | if (hit->suffix && !TSTMASKBIT (dent->mask, hit->suffix->flagbit)) |
---|
310 | return 0; |
---|
311 | return 1; /* Yes, these affixes are legal */ |
---|
312 | } |
---|
313 | #endif |
---|
314 | |
---|
315 | /* |
---|
316 | * Print a word and its flag, making sure the case of the output matches |
---|
317 | * the case of the original found in "orig_word". |
---|
318 | */ |
---|
319 | void flagpr (word, preflag, prestrip, preadd, sufflag, sufadd) |
---|
320 | register ichar_t * word; /* (Modified) word to print */ |
---|
321 | int preflag; /* Prefix flag (if any) */ |
---|
322 | int prestrip; /* Lth of pfx stripped off orig_word */ |
---|
323 | int preadd; /* Length of prefix added to w */ |
---|
324 | int sufflag; /* Suffix flag (if any) */ |
---|
325 | int sufadd; /* Length of suffix added to w */ |
---|
326 | { |
---|
327 | register ichar_t * origp; /* Pointer into orig_word */ |
---|
328 | int orig_len; /* Length of orig_word */ |
---|
329 | |
---|
330 | orig_len = icharlen (orig_word); |
---|
331 | /* |
---|
332 | * We refuse to print if the cases outside the modification |
---|
333 | * points don't match those just inside. This prevents things |
---|
334 | * like "OEM's" from being turned into "OEM/S" which expands |
---|
335 | * only to "OEM'S". |
---|
336 | */ |
---|
337 | if (preflag > 0) |
---|
338 | { |
---|
339 | origp = orig_word + preadd; |
---|
340 | if (myupper (*origp)) |
---|
341 | { |
---|
342 | for (origp = orig_word; origp < orig_word + preadd; origp++) |
---|
343 | { |
---|
344 | if (mylower (*origp)) |
---|
345 | return; |
---|
346 | } |
---|
347 | } |
---|
348 | else |
---|
349 | { |
---|
350 | for (origp = orig_word; origp < orig_word + preadd; origp++) |
---|
351 | { |
---|
352 | if (myupper (*origp)) |
---|
353 | return; |
---|
354 | } |
---|
355 | } |
---|
356 | } |
---|
357 | if (sufflag > 0) |
---|
358 | { |
---|
359 | origp = orig_word + orig_len - sufadd; |
---|
360 | if (myupper (origp[-1])) |
---|
361 | { |
---|
362 | for ( ; *origp != 0; origp++) |
---|
363 | { |
---|
364 | if (mylower (*origp)) |
---|
365 | return; |
---|
366 | } |
---|
367 | } |
---|
368 | else |
---|
369 | { |
---|
370 | origp = orig_word + orig_len - sufadd; |
---|
371 | for ( ; *origp != 0; origp++) |
---|
372 | { |
---|
373 | if (myupper (*origp)) |
---|
374 | return; |
---|
375 | } |
---|
376 | } |
---|
377 | } |
---|
378 | /* |
---|
379 | * The cases are ok. Put out the word, being careful that the |
---|
380 | * prefix/suffix cases match those in the original, and that the |
---|
381 | * unchanged characters from the original actually match it. |
---|
382 | */ |
---|
383 | (void) putchar (' '); |
---|
384 | origp = orig_word + preadd; |
---|
385 | if (myupper (*origp)) |
---|
386 | { |
---|
387 | while (--prestrip >= 0) |
---|
388 | (void) fputs (printichar ((int) *word++), stdout); |
---|
389 | } |
---|
390 | else |
---|
391 | { |
---|
392 | while (--prestrip >= 0) |
---|
393 | (void) fputs (printichar ((int) mytolower (*word++)), stdout); |
---|
394 | } |
---|
395 | for (prestrip = orig_len - preadd - sufadd; --prestrip >= 0; word++) |
---|
396 | (void) fputs (printichar ((int) *origp++), stdout); |
---|
397 | if (origp > orig_word) |
---|
398 | origp--; |
---|
399 | if (myupper (*origp)) |
---|
400 | (void) fputs (ichartosstr (word, 0), stdout); |
---|
401 | else |
---|
402 | { |
---|
403 | while (*word) |
---|
404 | { |
---|
405 | (void) fputs (printichar ((int) mytolower (*word++)), stdout); |
---|
406 | } |
---|
407 | } |
---|
408 | /* |
---|
409 | * Now put out the flags |
---|
410 | */ |
---|
411 | (void) putchar (hashheader.flagmarker); |
---|
412 | if (preflag > 0) |
---|
413 | (void) putchar (preflag); |
---|
414 | if (sufflag > 0) |
---|
415 | (void) putchar (sufflag); |
---|
416 | } |
---|