1 | #ifndef lint |
---|
2 | static char Rcs_Id[] = |
---|
3 | "$Id: tgood.c,v 1.1.1.1 1997-09-03 21:08:10 ghudson Exp $"; |
---|
4 | #endif |
---|
5 | |
---|
6 | /* |
---|
7 | * Copyright 1987, 1988, 1989, 1992, 1993, Geoff Kuenning, Granada Hills, CA |
---|
8 | * All rights reserved. |
---|
9 | * |
---|
10 | * Redistribution and use in source and binary forms, with or without |
---|
11 | * modification, are permitted provided that the following conditions |
---|
12 | * are met: |
---|
13 | * |
---|
14 | * 1. Redistributions of source code must retain the above copyright |
---|
15 | * notice, this list of conditions and the following disclaimer. |
---|
16 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
17 | * notice, this list of conditions and the following disclaimer in the |
---|
18 | * documentation and/or other materials provided with the distribution. |
---|
19 | * 3. All modifications to the source code must be clearly marked as |
---|
20 | * such. Binary redistributions based on modified source code |
---|
21 | * must be clearly marked as modified versions in the documentation |
---|
22 | * and/or other materials provided with the distribution. |
---|
23 | * 4. All advertising materials mentioning features or use of this software |
---|
24 | * must display the following acknowledgment: |
---|
25 | * This product includes software developed by Geoff Kuenning and |
---|
26 | * other unpaid contributors. |
---|
27 | * 5. The name of Geoff Kuenning may not be used to endorse or promote |
---|
28 | * products derived from this software without specific prior |
---|
29 | * written permission. |
---|
30 | * |
---|
31 | * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND |
---|
32 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
33 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
34 | * ARE DISCLAIMED. IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE |
---|
35 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
39 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
40 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
41 | * SUCH DAMAGE. |
---|
42 | */ |
---|
43 | |
---|
44 | /* |
---|
45 | * Table-driven version of good.c. |
---|
46 | * |
---|
47 | * Geoff Kuenning, July 1987 |
---|
48 | */ |
---|
49 | |
---|
50 | /* |
---|
51 | * $Log: not supported by cvs2svn $ |
---|
52 | * Revision 1.32 1994/11/02 06:56:16 geoff |
---|
53 | * Remove the anyword feature, which I've decided is a bad idea. |
---|
54 | * |
---|
55 | * Revision 1.31 1994/10/25 05:46:25 geoff |
---|
56 | * Add support for the FF_ANYWORD (affix applies to all words, even if |
---|
57 | * flag bit isn't set) flag option. |
---|
58 | * |
---|
59 | * Revision 1.30 1994/05/24 06:23:08 geoff |
---|
60 | * Don't create a hit if "allhits" is clear and capitalization |
---|
61 | * mismatches. This cures a bug where a word could be in the dictionary |
---|
62 | * and yet not found. |
---|
63 | * |
---|
64 | * Revision 1.29 1994/05/17 06:44:21 geoff |
---|
65 | * Add support for controlled compound formation and the COMPOUNDONLY |
---|
66 | * option to affix flags. |
---|
67 | * |
---|
68 | * Revision 1.28 1994/01/25 07:12:13 geoff |
---|
69 | * Get rid of all old RCS log lines in preparation for the 3.1 release. |
---|
70 | * |
---|
71 | */ |
---|
72 | |
---|
73 | #include <ctype.h> |
---|
74 | #include "config.h" |
---|
75 | #include "ispell.h" |
---|
76 | #include "proto.h" |
---|
77 | |
---|
78 | void chk_aff P ((ichar_t * word, ichar_t * ucword, int len, |
---|
79 | int ignoreflagbits, int allhits, int pfxopts, int sfxopts)); |
---|
80 | static void pfx_list_chk P ((ichar_t * word, ichar_t * ucword, |
---|
81 | int len, int optflags, int sfxopts, struct flagptr * ind, |
---|
82 | int ignoreflagbits, int allhits)); |
---|
83 | static void chk_suf P ((ichar_t * word, ichar_t * ucword, int len, |
---|
84 | int optflags, struct flagent * pfxent, int ignoreflagbits, |
---|
85 | int allhits)); |
---|
86 | static void suf_list_chk P ((ichar_t * word, ichar_t * ucword, int len, |
---|
87 | struct flagptr * ind, int optflags, struct flagent * pfxent, |
---|
88 | int ignoreflagbits, int allhits)); |
---|
89 | int expand_pre P ((char * croot, ichar_t * rootword, |
---|
90 | MASKTYPE mask[], int option, char * extra)); |
---|
91 | static int pr_pre_expansion P ((char * croot, ichar_t * rootword, |
---|
92 | struct flagent * flent, MASKTYPE mask[], int option, |
---|
93 | char * extra)); |
---|
94 | int expand_suf P ((char * croot, ichar_t * rootword, |
---|
95 | MASKTYPE mask[], int optflags, int option, char * extra)); |
---|
96 | static int pr_suf_expansion P ((char * croot, ichar_t * rootword, |
---|
97 | struct flagent * flent, int option, char * extra)); |
---|
98 | static void forcelc P ((ichar_t * dst, int len)); |
---|
99 | |
---|
100 | /* Check possible affixes */ |
---|
101 | void chk_aff (word, ucword, len, ignoreflagbits, allhits, pfxopts, sfxopts) |
---|
102 | ichar_t * word; /* Word to be checked */ |
---|
103 | ichar_t * ucword; /* Upper-case-only copy of word */ |
---|
104 | int len; /* The length of word/ucword */ |
---|
105 | int ignoreflagbits; /* Ignore whether affix is legal */ |
---|
106 | int allhits; /* Keep going after first hit */ |
---|
107 | int pfxopts; /* Options to apply to prefixes */ |
---|
108 | int sfxopts; /* Options to apply to suffixes */ |
---|
109 | { |
---|
110 | register ichar_t * cp; /* Pointer to char to index on */ |
---|
111 | struct flagptr * ind; /* Flag index table to test */ |
---|
112 | |
---|
113 | pfx_list_chk (word, ucword, len, pfxopts, sfxopts, &pflagindex[0], |
---|
114 | ignoreflagbits, allhits); |
---|
115 | cp = ucword; |
---|
116 | ind = &pflagindex[*cp++]; |
---|
117 | while (ind->numents == 0 && ind->pu.fp != NULL) |
---|
118 | { |
---|
119 | if (*cp == 0) |
---|
120 | return; |
---|
121 | if (ind->pu.fp[0].numents) |
---|
122 | { |
---|
123 | pfx_list_chk (word, ucword, len, pfxopts, sfxopts, &ind->pu.fp[0], |
---|
124 | ignoreflagbits, allhits); |
---|
125 | if (numhits && !allhits && !cflag && !ignoreflagbits) |
---|
126 | return; |
---|
127 | } |
---|
128 | ind = &ind->pu.fp[*cp++]; |
---|
129 | } |
---|
130 | pfx_list_chk (word, ucword, len, pfxopts, sfxopts, ind, ignoreflagbits, |
---|
131 | allhits); |
---|
132 | if (numhits && !allhits && !cflag && !ignoreflagbits) |
---|
133 | return; |
---|
134 | chk_suf (word, ucword, len, sfxopts, (struct flagent *) NULL, |
---|
135 | ignoreflagbits, allhits); |
---|
136 | } |
---|
137 | |
---|
138 | /* Check some prefix flags */ |
---|
139 | static void pfx_list_chk (word, ucword, len, optflags, sfxopts, ind, |
---|
140 | ignoreflagbits, allhits) |
---|
141 | ichar_t * word; /* Word to be checked */ |
---|
142 | ichar_t * ucword; /* Upper-case-only word */ |
---|
143 | int len; /* The length of ucword */ |
---|
144 | int optflags; /* Options to apply */ |
---|
145 | int sfxopts; /* Options to apply to suffixes */ |
---|
146 | struct flagptr * ind; /* Flag index table */ |
---|
147 | int ignoreflagbits; /* Ignore whether affix is legal */ |
---|
148 | int allhits; /* Keep going after first hit */ |
---|
149 | { |
---|
150 | int cond; /* Condition number */ |
---|
151 | register ichar_t * cp; /* Pointer into end of ucword */ |
---|
152 | struct dent * dent; /* Dictionary entry we found */ |
---|
153 | int entcount; /* Number of entries to process */ |
---|
154 | register struct flagent * |
---|
155 | flent; /* Current table entry */ |
---|
156 | int preadd; /* Length added to tword2 as prefix */ |
---|
157 | register int tlen; /* Length of tword */ |
---|
158 | ichar_t tword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4]; /* Tmp cpy */ |
---|
159 | ichar_t tword2[sizeof tword]; /* 2nd copy for ins_root_cap */ |
---|
160 | |
---|
161 | for (flent = ind->pu.ent, entcount = ind->numents; |
---|
162 | entcount > 0; |
---|
163 | flent++, entcount--) |
---|
164 | { |
---|
165 | /* |
---|
166 | * If this is a compound-only affix, ignore it unless we're |
---|
167 | * looking for that specific thing. |
---|
168 | */ |
---|
169 | if ((flent->flagflags & FF_COMPOUNDONLY) != 0 |
---|
170 | && (optflags & FF_COMPOUNDONLY) == 0) |
---|
171 | continue; |
---|
172 | /* |
---|
173 | * In COMPOUND_CONTROLLED mode, the FF_COMPOUNDONLY bit must |
---|
174 | * match exactly. |
---|
175 | */ |
---|
176 | if (compoundflag == COMPOUND_CONTROLLED |
---|
177 | && ((flent->flagflags ^ optflags) & FF_COMPOUNDONLY) != 0) |
---|
178 | continue; |
---|
179 | /* |
---|
180 | * See if the prefix matches. |
---|
181 | */ |
---|
182 | tlen = len - flent->affl; |
---|
183 | if (tlen > 0 |
---|
184 | && (flent->affl == 0 |
---|
185 | || icharncmp (flent->affix, ucword, flent->affl) == 0) |
---|
186 | && tlen + flent->stripl >= flent->numconds) |
---|
187 | { |
---|
188 | /* |
---|
189 | * The prefix matches. Remove it, replace it by the "strip" |
---|
190 | * string (if any), and check the original conditions. |
---|
191 | */ |
---|
192 | if (flent->stripl) |
---|
193 | (void) icharcpy (tword, flent->strip); |
---|
194 | (void) icharcpy (tword + flent->stripl, ucword + flent->affl); |
---|
195 | cp = tword; |
---|
196 | for (cond = 0; cond < flent->numconds; cond++) |
---|
197 | { |
---|
198 | if ((flent->conds[*cp++] & (1 << cond)) == 0) |
---|
199 | break; |
---|
200 | } |
---|
201 | if (cond >= flent->numconds) |
---|
202 | { |
---|
203 | /* |
---|
204 | * The conditions match. See if the word is in the |
---|
205 | * dictionary. |
---|
206 | */ |
---|
207 | tlen += flent->stripl; |
---|
208 | if (cflag) |
---|
209 | flagpr (tword, BITTOCHAR (flent->flagbit), flent->stripl, |
---|
210 | flent->affl, -1, 0); |
---|
211 | else if (ignoreflagbits) |
---|
212 | { |
---|
213 | if ((dent = lookup (tword, 1)) != NULL) |
---|
214 | { |
---|
215 | cp = tword2; |
---|
216 | if (flent->affl) |
---|
217 | { |
---|
218 | (void) icharcpy (cp, flent->affix); |
---|
219 | cp += flent->affl; |
---|
220 | *cp++ = '+'; |
---|
221 | } |
---|
222 | preadd = cp - tword2; |
---|
223 | (void) icharcpy (cp, tword); |
---|
224 | cp += tlen; |
---|
225 | if (flent->stripl) |
---|
226 | { |
---|
227 | *cp++ = '-'; |
---|
228 | (void) icharcpy (cp, flent->strip); |
---|
229 | } |
---|
230 | (void) ins_root_cap (tword2, word, |
---|
231 | flent->stripl, preadd, |
---|
232 | 0, (cp - tword2) - tlen - preadd, |
---|
233 | dent, flent, (struct flagent *) NULL); |
---|
234 | } |
---|
235 | } |
---|
236 | else if ((dent = lookup (tword, 1)) != NULL |
---|
237 | && TSTMASKBIT (dent->mask, flent->flagbit)) |
---|
238 | { |
---|
239 | if (numhits < MAX_HITS) |
---|
240 | { |
---|
241 | hits[numhits].dictent = dent; |
---|
242 | hits[numhits].prefix = flent; |
---|
243 | hits[numhits].suffix = NULL; |
---|
244 | numhits++; |
---|
245 | } |
---|
246 | if (!allhits) |
---|
247 | { |
---|
248 | #ifndef NO_CAPITALIZATION_SUPPORT |
---|
249 | if (cap_ok (word, &hits[0], len)) |
---|
250 | return; |
---|
251 | numhits = 0; |
---|
252 | #else /* NO_CAPITALIZATION_SUPPORT */ |
---|
253 | return; |
---|
254 | #endif /* NO_CAPITALIZATION_SUPPORT */ |
---|
255 | } |
---|
256 | } |
---|
257 | /* |
---|
258 | * Handle cross-products. |
---|
259 | */ |
---|
260 | if (flent->flagflags & FF_CROSSPRODUCT) |
---|
261 | chk_suf (word, tword, tlen, sfxopts | FF_CROSSPRODUCT, |
---|
262 | flent, ignoreflagbits, allhits); |
---|
263 | } |
---|
264 | } |
---|
265 | } |
---|
266 | } |
---|
267 | |
---|
268 | /* Check possible suffixes */ |
---|
269 | static void chk_suf (word, ucword, len, optflags, pfxent, ignoreflagbits, |
---|
270 | allhits) |
---|
271 | ichar_t * word; /* Word to be checked */ |
---|
272 | ichar_t * ucword; /* Upper-case-only word */ |
---|
273 | int len; /* The length of ucword */ |
---|
274 | int optflags; /* Affix option flags */ |
---|
275 | struct flagent * pfxent; /* Prefix flag entry if cross-prod */ |
---|
276 | int ignoreflagbits; /* Ignore whether affix is legal */ |
---|
277 | int allhits; /* Keep going after first hit */ |
---|
278 | { |
---|
279 | register ichar_t * cp; /* Pointer to char to index on */ |
---|
280 | struct flagptr * ind; /* Flag index table to test */ |
---|
281 | |
---|
282 | suf_list_chk (word, ucword, len, &sflagindex[0], optflags, pfxent, |
---|
283 | ignoreflagbits, allhits); |
---|
284 | cp = ucword + len - 1; |
---|
285 | ind = &sflagindex[*cp]; |
---|
286 | while (ind->numents == 0 && ind->pu.fp != NULL) |
---|
287 | { |
---|
288 | if (cp == ucword) |
---|
289 | return; |
---|
290 | if (ind->pu.fp[0].numents) |
---|
291 | { |
---|
292 | suf_list_chk (word, ucword, len, &ind->pu.fp[0], |
---|
293 | optflags, pfxent, ignoreflagbits, allhits); |
---|
294 | if (numhits != 0 && !allhits && !cflag && !ignoreflagbits) |
---|
295 | return; |
---|
296 | } |
---|
297 | ind = &ind->pu.fp[*--cp]; |
---|
298 | } |
---|
299 | suf_list_chk (word, ucword, len, ind, optflags, pfxent, |
---|
300 | ignoreflagbits, allhits); |
---|
301 | } |
---|
302 | |
---|
303 | static void suf_list_chk (word, ucword, len, ind, optflags, pfxent, |
---|
304 | ignoreflagbits, allhits) |
---|
305 | ichar_t * word; /* Word to be checked */ |
---|
306 | ichar_t * ucword; /* Upper-case-only word */ |
---|
307 | int len; /* The length of ucword */ |
---|
308 | struct flagptr * ind; /* Flag index table */ |
---|
309 | int optflags; /* Affix option flags */ |
---|
310 | struct flagent * pfxent; /* Prefix flag entry if crossonly */ |
---|
311 | int ignoreflagbits; /* Ignore whether affix is legal */ |
---|
312 | int allhits; /* Keep going after first hit */ |
---|
313 | { |
---|
314 | register ichar_t * cp; /* Pointer into end of ucword */ |
---|
315 | int cond; /* Condition number */ |
---|
316 | struct dent * dent; /* Dictionary entry we found */ |
---|
317 | int entcount; /* Number of entries to process */ |
---|
318 | register struct flagent * |
---|
319 | flent; /* Current table entry */ |
---|
320 | int preadd; /* Length added to tword2 as prefix */ |
---|
321 | register int tlen; /* Length of tword */ |
---|
322 | ichar_t tword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4]; /* Tmp cpy */ |
---|
323 | ichar_t tword2[sizeof tword]; /* 2nd copy for ins_root_cap */ |
---|
324 | |
---|
325 | (void) icharcpy (tword, ucword); |
---|
326 | for (flent = ind->pu.ent, entcount = ind->numents; |
---|
327 | entcount > 0; |
---|
328 | flent++, entcount--) |
---|
329 | { |
---|
330 | if ((optflags & FF_CROSSPRODUCT) != 0 |
---|
331 | && (flent->flagflags & FF_CROSSPRODUCT) == 0) |
---|
332 | continue; |
---|
333 | /* |
---|
334 | * If this is a compound-only affix, ignore it unless we're |
---|
335 | * looking for that specific thing. |
---|
336 | */ |
---|
337 | if ((flent->flagflags & FF_COMPOUNDONLY) != 0 |
---|
338 | && (optflags & FF_COMPOUNDONLY) == 0) |
---|
339 | continue; |
---|
340 | /* |
---|
341 | * In COMPOUND_CONTROLLED mode, the FF_COMPOUNDONLY bit must |
---|
342 | * match exactly. |
---|
343 | */ |
---|
344 | if (compoundflag == COMPOUND_CONTROLLED |
---|
345 | && ((flent->flagflags ^ optflags) & FF_COMPOUNDONLY) != 0) |
---|
346 | continue; |
---|
347 | /* |
---|
348 | * See if the suffix matches. |
---|
349 | */ |
---|
350 | tlen = len - flent->affl; |
---|
351 | if (tlen > 0 |
---|
352 | && (flent->affl == 0 |
---|
353 | || icharcmp (flent->affix, ucword + tlen) == 0) |
---|
354 | && tlen + flent->stripl >= flent->numconds) |
---|
355 | { |
---|
356 | /* |
---|
357 | * The suffix matches. Remove it, replace it by the "strip" |
---|
358 | * string (if any), and check the original conditions. |
---|
359 | */ |
---|
360 | (void) icharcpy (tword, ucword); |
---|
361 | cp = tword + tlen; |
---|
362 | if (flent->stripl) |
---|
363 | { |
---|
364 | (void) icharcpy (cp, flent->strip); |
---|
365 | tlen += flent->stripl; |
---|
366 | cp = tword + tlen; |
---|
367 | } |
---|
368 | else |
---|
369 | *cp = '\0'; |
---|
370 | for (cond = flent->numconds; --cond >= 0; ) |
---|
371 | { |
---|
372 | if ((flent->conds[*--cp] & (1 << cond)) == 0) |
---|
373 | break; |
---|
374 | } |
---|
375 | if (cond < 0) |
---|
376 | { |
---|
377 | /* |
---|
378 | * The conditions match. See if the word is in the |
---|
379 | * dictionary. |
---|
380 | */ |
---|
381 | if (cflag) |
---|
382 | { |
---|
383 | if (optflags & FF_CROSSPRODUCT) |
---|
384 | flagpr (tword, BITTOCHAR (pfxent->flagbit), |
---|
385 | pfxent->stripl, pfxent->affl, |
---|
386 | BITTOCHAR (flent->flagbit), flent->affl); |
---|
387 | else |
---|
388 | flagpr (tword, -1, 0, 0, |
---|
389 | BITTOCHAR (flent->flagbit), flent->affl); |
---|
390 | } |
---|
391 | else if (ignoreflagbits) |
---|
392 | { |
---|
393 | if ((dent = lookup (tword, 1)) != NULL) |
---|
394 | { |
---|
395 | cp = tword2; |
---|
396 | if ((optflags & FF_CROSSPRODUCT) |
---|
397 | && pfxent->affl != 0) |
---|
398 | { |
---|
399 | (void) icharcpy (cp, pfxent->affix); |
---|
400 | cp += pfxent->affl; |
---|
401 | *cp++ = '+'; |
---|
402 | } |
---|
403 | preadd = cp - tword2; |
---|
404 | (void) icharcpy (cp, tword); |
---|
405 | cp += tlen; |
---|
406 | if ((optflags & FF_CROSSPRODUCT) |
---|
407 | && pfxent->stripl != 0) |
---|
408 | { |
---|
409 | *cp++ = '-'; |
---|
410 | (void) icharcpy (cp, pfxent->strip); |
---|
411 | cp += pfxent->stripl; |
---|
412 | } |
---|
413 | if (flent->stripl) |
---|
414 | { |
---|
415 | *cp++ = '-'; |
---|
416 | (void) icharcpy (cp, flent->strip); |
---|
417 | cp += flent->stripl; |
---|
418 | } |
---|
419 | if (flent->affl) |
---|
420 | { |
---|
421 | *cp++ = '+'; |
---|
422 | (void) icharcpy (cp, flent->affix); |
---|
423 | cp += flent->affl; |
---|
424 | } |
---|
425 | (void) ins_root_cap (tword2, word, |
---|
426 | (optflags & FF_CROSSPRODUCT) ? pfxent->stripl : 0, |
---|
427 | preadd, |
---|
428 | flent->stripl, (cp - tword2) - tlen - preadd, |
---|
429 | dent, pfxent, flent); |
---|
430 | } |
---|
431 | } |
---|
432 | else if ((dent = lookup (tword, 1)) != NULL |
---|
433 | && TSTMASKBIT (dent->mask, flent->flagbit) |
---|
434 | && ((optflags & FF_CROSSPRODUCT) == 0 |
---|
435 | || TSTMASKBIT (dent->mask, pfxent->flagbit))) |
---|
436 | { |
---|
437 | if (numhits < MAX_HITS) |
---|
438 | { |
---|
439 | hits[numhits].dictent = dent; |
---|
440 | hits[numhits].prefix = pfxent; |
---|
441 | hits[numhits].suffix = flent; |
---|
442 | numhits++; |
---|
443 | } |
---|
444 | if (!allhits) |
---|
445 | { |
---|
446 | #ifndef NO_CAPITALIZATION_SUPPORT |
---|
447 | if (cap_ok (word, &hits[0], len)) |
---|
448 | return; |
---|
449 | numhits = 0; |
---|
450 | #else /* NO_CAPITALIZATION_SUPPORT */ |
---|
451 | return; |
---|
452 | #endif /* NO_CAPITALIZATION_SUPPORT */ |
---|
453 | } |
---|
454 | } |
---|
455 | } |
---|
456 | } |
---|
457 | } |
---|
458 | } |
---|
459 | |
---|
460 | /* |
---|
461 | * Expand a dictionary prefix entry |
---|
462 | */ |
---|
463 | int expand_pre (croot, rootword, mask, option, extra) |
---|
464 | char * croot; /* Char version of rootword */ |
---|
465 | ichar_t * rootword; /* Root word to expand */ |
---|
466 | register MASKTYPE mask[]; /* Mask bits to expand on */ |
---|
467 | int option; /* Option, see expandmode */ |
---|
468 | char * extra; /* Extra info to add to line */ |
---|
469 | { |
---|
470 | int entcount; /* No. of entries to process */ |
---|
471 | int explength; /* Length of expansions */ |
---|
472 | register struct flagent * |
---|
473 | flent; /* Current table entry */ |
---|
474 | |
---|
475 | for (flent = pflaglist, entcount = numpflags, explength = 0; |
---|
476 | entcount > 0; |
---|
477 | flent++, entcount--) |
---|
478 | { |
---|
479 | if (TSTMASKBIT (mask, flent->flagbit)) |
---|
480 | explength += |
---|
481 | pr_pre_expansion (croot, rootword, flent, mask, option, extra); |
---|
482 | } |
---|
483 | return explength; |
---|
484 | } |
---|
485 | |
---|
486 | /* Print a prefix expansion */ |
---|
487 | static int pr_pre_expansion (croot, rootword, flent, mask, option, extra) |
---|
488 | char * croot; /* Char version of rootword */ |
---|
489 | register ichar_t * rootword; /* Root word to expand */ |
---|
490 | register struct flagent * flent; /* Current table entry */ |
---|
491 | MASKTYPE mask[]; /* Mask bits to expand on */ |
---|
492 | int option; /* Option, see expandmode */ |
---|
493 | char * extra; /* Extra info to add to line */ |
---|
494 | { |
---|
495 | int cond; /* Current condition number */ |
---|
496 | register ichar_t * nextc; /* Next case choice */ |
---|
497 | int tlen; /* Length of tword */ |
---|
498 | ichar_t tword[INPUTWORDLEN + MAXAFFIXLEN]; /* Temp */ |
---|
499 | |
---|
500 | tlen = icharlen (rootword); |
---|
501 | if (flent->numconds > tlen) |
---|
502 | return 0; |
---|
503 | tlen -= flent->stripl; |
---|
504 | if (tlen <= 0) |
---|
505 | return 0; |
---|
506 | tlen += flent->affl; |
---|
507 | for (cond = 0, nextc = rootword; cond < flent->numconds; cond++) |
---|
508 | { |
---|
509 | if ((flent->conds[mytoupper (*nextc++)] & (1 << cond)) == 0) |
---|
510 | return 0; |
---|
511 | } |
---|
512 | /* |
---|
513 | * The conditions are satisfied. Copy the word, add the prefix, |
---|
514 | * and make it the proper case. This code is carefully written |
---|
515 | * to match that ins_cap and cap_ok. Note that the affix, as |
---|
516 | * inserted, is uppercase. |
---|
517 | * |
---|
518 | * There is a tricky bit here: if the root is capitalized, we |
---|
519 | * want a capitalized result. If the root is followcase, however, |
---|
520 | * we want to duplicate the case of the first remaining letter |
---|
521 | * of the root. In other words, "Loved/U" should generate "Unloved", |
---|
522 | * but "LOved/U" should generate "UNLOved" and "lOved/U" should |
---|
523 | * produce "unlOved". |
---|
524 | */ |
---|
525 | if (flent->affl) |
---|
526 | { |
---|
527 | (void) icharcpy (tword, flent->affix); |
---|
528 | nextc = tword + flent->affl; |
---|
529 | } |
---|
530 | (void) icharcpy (nextc, rootword + flent->stripl); |
---|
531 | if (myupper (rootword[0])) |
---|
532 | { |
---|
533 | /* We must distinguish followcase from capitalized and all-upper */ |
---|
534 | for (nextc = rootword + 1; *nextc; nextc++) |
---|
535 | { |
---|
536 | if (!myupper (*nextc)) |
---|
537 | break; |
---|
538 | } |
---|
539 | if (*nextc) |
---|
540 | { |
---|
541 | /* It's a followcase or capitalized word. Figure out which. */ |
---|
542 | for ( ; *nextc; nextc++) |
---|
543 | { |
---|
544 | if (myupper (*nextc)) |
---|
545 | break; |
---|
546 | } |
---|
547 | if (*nextc) |
---|
548 | { |
---|
549 | /* It's followcase. */ |
---|
550 | if (!myupper (tword[flent->affl])) |
---|
551 | forcelc (tword, flent->affl); |
---|
552 | } |
---|
553 | else |
---|
554 | { |
---|
555 | /* It's capitalized */ |
---|
556 | forcelc (tword + 1, tlen - 1); |
---|
557 | } |
---|
558 | } |
---|
559 | } |
---|
560 | else |
---|
561 | { |
---|
562 | /* Followcase or all-lower, we don't care which */ |
---|
563 | if (!myupper (*nextc)) |
---|
564 | forcelc (tword, flent->affl); |
---|
565 | } |
---|
566 | if (option == 3) |
---|
567 | (void) printf ("\n%s", croot); |
---|
568 | if (option != 4) |
---|
569 | (void) printf (" %s%s", ichartosstr (tword, 1), extra); |
---|
570 | if (flent->flagflags & FF_CROSSPRODUCT) |
---|
571 | return tlen |
---|
572 | + expand_suf (croot, tword, mask, FF_CROSSPRODUCT, option, extra); |
---|
573 | else |
---|
574 | return tlen; |
---|
575 | } |
---|
576 | |
---|
577 | /* |
---|
578 | * Expand a dictionary suffix entry |
---|
579 | */ |
---|
580 | int expand_suf (croot, rootword, mask, optflags, option, extra) |
---|
581 | char * croot; /* Char version of rootword */ |
---|
582 | ichar_t * rootword; /* Root word to expand */ |
---|
583 | register MASKTYPE mask[]; /* Mask bits to expand on */ |
---|
584 | int optflags; /* Affix option flags */ |
---|
585 | int option; /* Option, see expandmode */ |
---|
586 | char * extra; /* Extra info to add to line */ |
---|
587 | { |
---|
588 | int entcount; /* No. of entries to process */ |
---|
589 | int explength; /* Length of expansions */ |
---|
590 | register struct flagent * |
---|
591 | flent; /* Current table entry */ |
---|
592 | |
---|
593 | for (flent = sflaglist, entcount = numsflags, explength = 0; |
---|
594 | entcount > 0; |
---|
595 | flent++, entcount--) |
---|
596 | { |
---|
597 | if (TSTMASKBIT (mask, flent->flagbit)) |
---|
598 | { |
---|
599 | if ((optflags & FF_CROSSPRODUCT) == 0 |
---|
600 | || (flent->flagflags & FF_CROSSPRODUCT)) |
---|
601 | explength += |
---|
602 | pr_suf_expansion (croot, rootword, flent, option, extra); |
---|
603 | } |
---|
604 | } |
---|
605 | return explength; |
---|
606 | } |
---|
607 | |
---|
608 | /* Print a suffix expansion */ |
---|
609 | static int pr_suf_expansion (croot, rootword, flent, option, extra) |
---|
610 | char * croot; /* Char version of rootword */ |
---|
611 | register ichar_t * rootword; /* Root word to expand */ |
---|
612 | register struct flagent * flent; /* Current table entry */ |
---|
613 | int option; /* Option, see expandmode */ |
---|
614 | char * extra; /* Extra info to add to line */ |
---|
615 | { |
---|
616 | int cond; /* Current condition number */ |
---|
617 | register ichar_t * nextc; /* Next case choice */ |
---|
618 | int tlen; /* Length of tword */ |
---|
619 | ichar_t tword[INPUTWORDLEN + MAXAFFIXLEN]; /* Temp */ |
---|
620 | |
---|
621 | tlen = icharlen (rootword); |
---|
622 | cond = flent->numconds; |
---|
623 | if (cond > tlen) |
---|
624 | return 0; |
---|
625 | if (tlen - flent->stripl <= 0) |
---|
626 | return 0; |
---|
627 | for (nextc = rootword + tlen; --cond >= 0; ) |
---|
628 | { |
---|
629 | if ((flent->conds[mytoupper (*--nextc)] & (1 << cond)) == 0) |
---|
630 | return 0; |
---|
631 | } |
---|
632 | /* |
---|
633 | * The conditions are satisfied. Copy the word, add the suffix, |
---|
634 | * and make it match the case of the last remaining character of the |
---|
635 | * root. Again, this code carefully matches ins_cap and cap_ok. |
---|
636 | */ |
---|
637 | (void) icharcpy (tword, rootword); |
---|
638 | nextc = tword + tlen - flent->stripl; |
---|
639 | if (flent->affl) |
---|
640 | { |
---|
641 | (void) icharcpy (nextc, flent->affix); |
---|
642 | if (!myupper (nextc[-1])) |
---|
643 | forcelc (nextc, flent->affl); |
---|
644 | } |
---|
645 | else |
---|
646 | *nextc = 0; |
---|
647 | if (option == 3) |
---|
648 | (void) printf ("\n%s", croot); |
---|
649 | if (option != 4) |
---|
650 | (void) printf (" %s%s", ichartosstr (tword, 1), extra); |
---|
651 | return tlen + flent->affl - flent->stripl; |
---|
652 | } |
---|
653 | |
---|
654 | static void forcelc (dst, len) /* Force to lowercase */ |
---|
655 | register ichar_t * dst; /* Destination to modify */ |
---|
656 | register int len; /* Length to copy */ |
---|
657 | { |
---|
658 | |
---|
659 | for ( ; --len >= 0; dst++) |
---|
660 | *dst = mytolower (*dst); |
---|
661 | } |
---|