source: trunk/third/ispell/tgood.c @ 10334

Revision 10334, 20.7 KB checked in by ghudson, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10333, which included commits to RCS files with non-trunk default branches.
Line 
1#ifndef lint
2static 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
78void            chk_aff P ((ichar_t * word, ichar_t * ucword, int len,
79                  int ignoreflagbits, int allhits, int pfxopts, int sfxopts));
80static 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));
83static void     chk_suf P ((ichar_t * word, ichar_t * ucword, int len,
84                  int optflags, struct flagent * pfxent, int ignoreflagbits,
85                  int allhits));
86static 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));
89int             expand_pre P ((char * croot, ichar_t * rootword,
90                  MASKTYPE mask[], int option, char * extra));
91static int      pr_pre_expansion P ((char * croot, ichar_t * rootword,
92                  struct flagent * flent, MASKTYPE mask[], int option,
93                  char * extra));
94int             expand_suf P ((char * croot, ichar_t * rootword,
95                  MASKTYPE mask[], int optflags, int option, char * extra));
96static int      pr_suf_expansion P ((char * croot, ichar_t * rootword,
97                  struct flagent * flent, int option, char * extra));
98static void     forcelc P ((ichar_t * dst, int len));
99
100/* Check possible affixes */
101void 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 */
139static 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 */
269static 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   
303static 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 */
463int 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 */
487static 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 */
580int 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 */
609static 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
654static 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    }
Note: See TracBrowser for help on using the repository browser.