| #ifndef lint |
| static char Rcs_Id[] = |
| "$Id$"; |
| #endif |
| |
| /* |
| * Copyright 1987, 1988, 1989, 1992, 1993, Geoff Kuenning, Granada Hills, CA |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. All modifications to the source code must be clearly marked as |
| * such. Binary redistributions based on modified source code |
| * must be clearly marked as modified versions in the documentation |
| * and/or other materials provided with the distribution. |
| * 4. All advertising materials mentioning features or use of this software |
| * must display the following acknowledgment: |
| * This product includes software developed by Geoff Kuenning and |
| * other unpaid contributors. |
| * 5. The name of Geoff Kuenning may not be used to endorse or promote |
| * products derived from this software without specific prior |
| * written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| */ |
| |
| /* |
| * Table-driven version of good.c. |
| * |
| * Geoff Kuenning, July 1987 |
| */ |
| |
| /* |
| * $Log$ |
| * Revision 1.1 2007/01/09 23:57:18 lattner |
| * initial recheckin of mibench |
| * |
| * Revision 1.1.1.1 2007/01/09 02:59:05 evancheng |
| * Add selected tests from MiBench 1.0 to LLVM test suite. |
| * |
| * Revision 1.32 1994/11/02 06:56:16 geoff |
| * Remove the anyword feature, which I've decided is a bad idea. |
| * |
| * Revision 1.31 1994/10/25 05:46:25 geoff |
| * Add support for the FF_ANYWORD (affix applies to all words, even if |
| * flag bit isn't set) flag option. |
| * |
| * Revision 1.30 1994/05/24 06:23:08 geoff |
| * Don't create a hit if "allhits" is clear and capitalization |
| * mismatches. This cures a bug where a word could be in the dictionary |
| * and yet not found. |
| * |
| * Revision 1.29 1994/05/17 06:44:21 geoff |
| * Add support for controlled compound formation and the COMPOUNDONLY |
| * option to affix flags. |
| * |
| * Revision 1.28 1994/01/25 07:12:13 geoff |
| * Get rid of all old RCS log lines in preparation for the 3.1 release. |
| * |
| */ |
| |
| #include <ctype.h> |
| #include "config.h" |
| #include "ispell.h" |
| #include "proto.h" |
| |
| void chk_aff P ((ichar_t * word, ichar_t * ucword, int len, |
| int ignoreflagbits, int allhits, int pfxopts, int sfxopts)); |
| static void pfx_list_chk P ((ichar_t * word, ichar_t * ucword, |
| int len, int optflags, int sfxopts, struct flagptr * ind, |
| int ignoreflagbits, int allhits)); |
| static void chk_suf P ((ichar_t * word, ichar_t * ucword, int len, |
| int optflags, struct flagent * pfxent, int ignoreflagbits, |
| int allhits)); |
| static void suf_list_chk P ((ichar_t * word, ichar_t * ucword, int len, |
| struct flagptr * ind, int optflags, struct flagent * pfxent, |
| int ignoreflagbits, int allhits)); |
| int expand_pre P ((char * croot, ichar_t * rootword, |
| MASKTYPE mask[], int option, char * extra)); |
| static int pr_pre_expansion P ((char * croot, ichar_t * rootword, |
| struct flagent * flent, MASKTYPE mask[], int option, |
| char * extra)); |
| int expand_suf P ((char * croot, ichar_t * rootword, |
| MASKTYPE mask[], int optflags, int option, char * extra)); |
| static int pr_suf_expansion P ((char * croot, ichar_t * rootword, |
| struct flagent * flent, int option, char * extra)); |
| static void forcelc P ((ichar_t * dst, int len)); |
| |
| /* Check possible affixes */ |
| void chk_aff (word, ucword, len, ignoreflagbits, allhits, pfxopts, sfxopts) |
| ichar_t * word; /* Word to be checked */ |
| ichar_t * ucword; /* Upper-case-only copy of word */ |
| int len; /* The length of word/ucword */ |
| int ignoreflagbits; /* Ignore whether affix is legal */ |
| int allhits; /* Keep going after first hit */ |
| int pfxopts; /* Options to apply to prefixes */ |
| int sfxopts; /* Options to apply to suffixes */ |
| { |
| register ichar_t * cp; /* Pointer to char to index on */ |
| struct flagptr * ind; /* Flag index table to test */ |
| |
| pfx_list_chk (word, ucword, len, pfxopts, sfxopts, &pflagindex[0], |
| ignoreflagbits, allhits); |
| cp = ucword; |
| ind = &pflagindex[*cp++]; |
| while (ind->numents == 0 && ind->pu.fp != NULL) |
| { |
| if (*cp == 0) |
| return; |
| if (ind->pu.fp[0].numents) |
| { |
| pfx_list_chk (word, ucword, len, pfxopts, sfxopts, &ind->pu.fp[0], |
| ignoreflagbits, allhits); |
| if (numhits && !allhits && !cflag && !ignoreflagbits) |
| return; |
| } |
| ind = &ind->pu.fp[*cp++]; |
| } |
| pfx_list_chk (word, ucword, len, pfxopts, sfxopts, ind, ignoreflagbits, |
| allhits); |
| if (numhits && !allhits && !cflag && !ignoreflagbits) |
| return; |
| chk_suf (word, ucword, len, sfxopts, (struct flagent *) NULL, |
| ignoreflagbits, allhits); |
| } |
| |
| /* Check some prefix flags */ |
| static void pfx_list_chk (word, ucword, len, optflags, sfxopts, ind, |
| ignoreflagbits, allhits) |
| ichar_t * word; /* Word to be checked */ |
| ichar_t * ucword; /* Upper-case-only word */ |
| int len; /* The length of ucword */ |
| int optflags; /* Options to apply */ |
| int sfxopts; /* Options to apply to suffixes */ |
| struct flagptr * ind; /* Flag index table */ |
| int ignoreflagbits; /* Ignore whether affix is legal */ |
| int allhits; /* Keep going after first hit */ |
| { |
| int cond; /* Condition number */ |
| register ichar_t * cp; /* Pointer into end of ucword */ |
| struct dent * dent; /* Dictionary entry we found */ |
| int entcount; /* Number of entries to process */ |
| register struct flagent * |
| flent; /* Current table entry */ |
| int preadd; /* Length added to tword2 as prefix */ |
| register int tlen; /* Length of tword */ |
| ichar_t tword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4]; /* Tmp cpy */ |
| ichar_t tword2[sizeof tword]; /* 2nd copy for ins_root_cap */ |
| |
| for (flent = ind->pu.ent, entcount = ind->numents; |
| entcount > 0; |
| flent++, entcount--) |
| { |
| /* |
| * If this is a compound-only affix, ignore it unless we're |
| * looking for that specific thing. |
| */ |
| if ((flent->flagflags & FF_COMPOUNDONLY) != 0 |
| && (optflags & FF_COMPOUNDONLY) == 0) |
| continue; |
| /* |
| * In COMPOUND_CONTROLLED mode, the FF_COMPOUNDONLY bit must |
| * match exactly. |
| */ |
| if (compoundflag == COMPOUND_CONTROLLED |
| && ((flent->flagflags ^ optflags) & FF_COMPOUNDONLY) != 0) |
| continue; |
| /* |
| * See if the prefix matches. |
| */ |
| tlen = len - flent->affl; |
| if (tlen > 0 |
| && (flent->affl == 0 |
| || icharncmp (flent->affix, ucword, flent->affl) == 0) |
| && tlen + flent->stripl >= flent->numconds) |
| { |
| /* |
| * The prefix matches. Remove it, replace it by the "strip" |
| * string (if any), and check the original conditions. |
| */ |
| if (flent->stripl) |
| (void) icharcpy (tword, flent->strip); |
| (void) icharcpy (tword + flent->stripl, ucword + flent->affl); |
| cp = tword; |
| for (cond = 0; cond < flent->numconds; cond++) |
| { |
| if ((flent->conds[*cp++] & (1 << cond)) == 0) |
| break; |
| } |
| if (cond >= flent->numconds) |
| { |
| /* |
| * The conditions match. See if the word is in the |
| * dictionary. |
| */ |
| tlen += flent->stripl; |
| if (cflag) |
| flagpr (tword, BITTOCHAR (flent->flagbit), flent->stripl, |
| flent->affl, -1, 0); |
| else if (ignoreflagbits) |
| { |
| if ((dent = lookup (tword, 1)) != NULL) |
| { |
| cp = tword2; |
| if (flent->affl) |
| { |
| (void) icharcpy (cp, flent->affix); |
| cp += flent->affl; |
| *cp++ = '+'; |
| } |
| preadd = cp - tword2; |
| (void) icharcpy (cp, tword); |
| cp += tlen; |
| if (flent->stripl) |
| { |
| *cp++ = '-'; |
| (void) icharcpy (cp, flent->strip); |
| } |
| (void) ins_root_cap (tword2, word, |
| flent->stripl, preadd, |
| 0, (cp - tword2) - tlen - preadd, |
| dent, flent, (struct flagent *) NULL); |
| } |
| } |
| else if ((dent = lookup (tword, 1)) != NULL |
| && TSTMASKBIT (dent->mask, flent->flagbit)) |
| { |
| if (numhits < MAX_HITS) |
| { |
| hits[numhits].dictent = dent; |
| hits[numhits].prefix = flent; |
| hits[numhits].suffix = NULL; |
| numhits++; |
| } |
| if (!allhits) |
| { |
| #ifndef NO_CAPITALIZATION_SUPPORT |
| if (cap_ok (word, &hits[0], len)) |
| return; |
| numhits = 0; |
| #else /* NO_CAPITALIZATION_SUPPORT */ |
| return; |
| #endif /* NO_CAPITALIZATION_SUPPORT */ |
| } |
| } |
| /* |
| * Handle cross-products. |
| */ |
| if (flent->flagflags & FF_CROSSPRODUCT) |
| chk_suf (word, tword, tlen, sfxopts | FF_CROSSPRODUCT, |
| flent, ignoreflagbits, allhits); |
| } |
| } |
| } |
| } |
| |
| /* Check possible suffixes */ |
| static void chk_suf (word, ucword, len, optflags, pfxent, ignoreflagbits, |
| allhits) |
| ichar_t * word; /* Word to be checked */ |
| ichar_t * ucword; /* Upper-case-only word */ |
| int len; /* The length of ucword */ |
| int optflags; /* Affix option flags */ |
| struct flagent * pfxent; /* Prefix flag entry if cross-prod */ |
| int ignoreflagbits; /* Ignore whether affix is legal */ |
| int allhits; /* Keep going after first hit */ |
| { |
| register ichar_t * cp; /* Pointer to char to index on */ |
| struct flagptr * ind; /* Flag index table to test */ |
| |
| suf_list_chk (word, ucword, len, &sflagindex[0], optflags, pfxent, |
| ignoreflagbits, allhits); |
| cp = ucword + len - 1; |
| ind = &sflagindex[*cp]; |
| while (ind->numents == 0 && ind->pu.fp != NULL) |
| { |
| if (cp == ucword) |
| return; |
| if (ind->pu.fp[0].numents) |
| { |
| suf_list_chk (word, ucword, len, &ind->pu.fp[0], |
| optflags, pfxent, ignoreflagbits, allhits); |
| if (numhits != 0 && !allhits && !cflag && !ignoreflagbits) |
| return; |
| } |
| ind = &ind->pu.fp[*--cp]; |
| } |
| suf_list_chk (word, ucword, len, ind, optflags, pfxent, |
| ignoreflagbits, allhits); |
| } |
| |
| static void suf_list_chk (word, ucword, len, ind, optflags, pfxent, |
| ignoreflagbits, allhits) |
| ichar_t * word; /* Word to be checked */ |
| ichar_t * ucword; /* Upper-case-only word */ |
| int len; /* The length of ucword */ |
| struct flagptr * ind; /* Flag index table */ |
| int optflags; /* Affix option flags */ |
| struct flagent * pfxent; /* Prefix flag entry if crossonly */ |
| int ignoreflagbits; /* Ignore whether affix is legal */ |
| int allhits; /* Keep going after first hit */ |
| { |
| register ichar_t * cp; /* Pointer into end of ucword */ |
| int cond; /* Condition number */ |
| struct dent * dent; /* Dictionary entry we found */ |
| int entcount; /* Number of entries to process */ |
| register struct flagent * |
| flent; /* Current table entry */ |
| int preadd; /* Length added to tword2 as prefix */ |
| register int tlen; /* Length of tword */ |
| ichar_t tword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4]; /* Tmp cpy */ |
| ichar_t tword2[sizeof tword]; /* 2nd copy for ins_root_cap */ |
| |
| (void) icharcpy (tword, ucword); |
| for (flent = ind->pu.ent, entcount = ind->numents; |
| entcount > 0; |
| flent++, entcount--) |
| { |
| if ((optflags & FF_CROSSPRODUCT) != 0 |
| && (flent->flagflags & FF_CROSSPRODUCT) == 0) |
| continue; |
| /* |
| * If this is a compound-only affix, ignore it unless we're |
| * looking for that specific thing. |
| */ |
| if ((flent->flagflags & FF_COMPOUNDONLY) != 0 |
| && (optflags & FF_COMPOUNDONLY) == 0) |
| continue; |
| /* |
| * In COMPOUND_CONTROLLED mode, the FF_COMPOUNDONLY bit must |
| * match exactly. |
| */ |
| if (compoundflag == COMPOUND_CONTROLLED |
| && ((flent->flagflags ^ optflags) & FF_COMPOUNDONLY) != 0) |
| continue; |
| /* |
| * See if the suffix matches. |
| */ |
| tlen = len - flent->affl; |
| if (tlen > 0 |
| && (flent->affl == 0 |
| || icharcmp (flent->affix, ucword + tlen) == 0) |
| && tlen + flent->stripl >= flent->numconds) |
| { |
| /* |
| * The suffix matches. Remove it, replace it by the "strip" |
| * string (if any), and check the original conditions. |
| */ |
| (void) icharcpy (tword, ucword); |
| cp = tword + tlen; |
| if (flent->stripl) |
| { |
| (void) icharcpy (cp, flent->strip); |
| tlen += flent->stripl; |
| cp = tword + tlen; |
| } |
| else |
| *cp = '\0'; |
| for (cond = flent->numconds; --cond >= 0; ) |
| { |
| if ((flent->conds[*--cp] & (1 << cond)) == 0) |
| break; |
| } |
| if (cond < 0) |
| { |
| /* |
| * The conditions match. See if the word is in the |
| * dictionary. |
| */ |
| if (cflag) |
| { |
| if (optflags & FF_CROSSPRODUCT) |
| flagpr (tword, BITTOCHAR (pfxent->flagbit), |
| pfxent->stripl, pfxent->affl, |
| BITTOCHAR (flent->flagbit), flent->affl); |
| else |
| flagpr (tword, -1, 0, 0, |
| BITTOCHAR (flent->flagbit), flent->affl); |
| } |
| else if (ignoreflagbits) |
| { |
| if ((dent = lookup (tword, 1)) != NULL) |
| { |
| cp = tword2; |
| if ((optflags & FF_CROSSPRODUCT) |
| && pfxent->affl != 0) |
| { |
| (void) icharcpy (cp, pfxent->affix); |
| cp += pfxent->affl; |
| *cp++ = '+'; |
| } |
| preadd = cp - tword2; |
| (void) icharcpy (cp, tword); |
| cp += tlen; |
| if ((optflags & FF_CROSSPRODUCT) |
| && pfxent->stripl != 0) |
| { |
| *cp++ = '-'; |
| (void) icharcpy (cp, pfxent->strip); |
| cp += pfxent->stripl; |
| } |
| if (flent->stripl) |
| { |
| *cp++ = '-'; |
| (void) icharcpy (cp, flent->strip); |
| cp += flent->stripl; |
| } |
| if (flent->affl) |
| { |
| *cp++ = '+'; |
| (void) icharcpy (cp, flent->affix); |
| cp += flent->affl; |
| } |
| (void) ins_root_cap (tword2, word, |
| (optflags & FF_CROSSPRODUCT) ? pfxent->stripl : 0, |
| preadd, |
| flent->stripl, (cp - tword2) - tlen - preadd, |
| dent, pfxent, flent); |
| } |
| } |
| else if ((dent = lookup (tword, 1)) != NULL |
| && TSTMASKBIT (dent->mask, flent->flagbit) |
| && ((optflags & FF_CROSSPRODUCT) == 0 |
| || TSTMASKBIT (dent->mask, pfxent->flagbit))) |
| { |
| if (numhits < MAX_HITS) |
| { |
| hits[numhits].dictent = dent; |
| hits[numhits].prefix = pfxent; |
| hits[numhits].suffix = flent; |
| numhits++; |
| } |
| if (!allhits) |
| { |
| #ifndef NO_CAPITALIZATION_SUPPORT |
| if (cap_ok (word, &hits[0], len)) |
| return; |
| numhits = 0; |
| #else /* NO_CAPITALIZATION_SUPPORT */ |
| return; |
| #endif /* NO_CAPITALIZATION_SUPPORT */ |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /* |
| * Expand a dictionary prefix entry |
| */ |
| int expand_pre (croot, rootword, mask, option, extra) |
| char * croot; /* Char version of rootword */ |
| ichar_t * rootword; /* Root word to expand */ |
| register MASKTYPE mask[]; /* Mask bits to expand on */ |
| int option; /* Option, see expandmode */ |
| char * extra; /* Extra info to add to line */ |
| { |
| int entcount; /* No. of entries to process */ |
| int explength; /* Length of expansions */ |
| register struct flagent * |
| flent; /* Current table entry */ |
| |
| for (flent = pflaglist, entcount = numpflags, explength = 0; |
| entcount > 0; |
| flent++, entcount--) |
| { |
| if (TSTMASKBIT (mask, flent->flagbit)) |
| explength += |
| pr_pre_expansion (croot, rootword, flent, mask, option, extra); |
| } |
| return explength; |
| } |
| |
| /* Print a prefix expansion */ |
| static int pr_pre_expansion (croot, rootword, flent, mask, option, extra) |
| char * croot; /* Char version of rootword */ |
| register ichar_t * rootword; /* Root word to expand */ |
| register struct flagent * flent; /* Current table entry */ |
| MASKTYPE mask[]; /* Mask bits to expand on */ |
| int option; /* Option, see expandmode */ |
| char * extra; /* Extra info to add to line */ |
| { |
| int cond; /* Current condition number */ |
| register ichar_t * nextc; /* Next case choice */ |
| int tlen; /* Length of tword */ |
| ichar_t tword[INPUTWORDLEN + MAXAFFIXLEN]; /* Temp */ |
| |
| tlen = icharlen (rootword); |
| if (flent->numconds > tlen) |
| return 0; |
| tlen -= flent->stripl; |
| if (tlen <= 0) |
| return 0; |
| tlen += flent->affl; |
| for (cond = 0, nextc = rootword; cond < flent->numconds; cond++) |
| { |
| if ((flent->conds[mytoupper (*nextc++)] & (1 << cond)) == 0) |
| return 0; |
| } |
| /* |
| * The conditions are satisfied. Copy the word, add the prefix, |
| * and make it the proper case. This code is carefully written |
| * to match that ins_cap and cap_ok. Note that the affix, as |
| * inserted, is uppercase. |
| * |
| * There is a tricky bit here: if the root is capitalized, we |
| * want a capitalized result. If the root is followcase, however, |
| * we want to duplicate the case of the first remaining letter |
| * of the root. In other words, "Loved/U" should generate "Unloved", |
| * but "LOved/U" should generate "UNLOved" and "lOved/U" should |
| * produce "unlOved". |
| */ |
| if (flent->affl) |
| { |
| (void) icharcpy (tword, flent->affix); |
| nextc = tword + flent->affl; |
| } |
| (void) icharcpy (nextc, rootword + flent->stripl); |
| if (myupper (rootword[0])) |
| { |
| /* We must distinguish followcase from capitalized and all-upper */ |
| for (nextc = rootword + 1; *nextc; nextc++) |
| { |
| if (!myupper (*nextc)) |
| break; |
| } |
| if (*nextc) |
| { |
| /* It's a followcase or capitalized word. Figure out which. */ |
| for ( ; *nextc; nextc++) |
| { |
| if (myupper (*nextc)) |
| break; |
| } |
| if (*nextc) |
| { |
| /* It's followcase. */ |
| if (!myupper (tword[flent->affl])) |
| forcelc (tword, flent->affl); |
| } |
| else |
| { |
| /* It's capitalized */ |
| forcelc (tword + 1, tlen - 1); |
| } |
| } |
| } |
| else |
| { |
| /* Followcase or all-lower, we don't care which */ |
| if (!myupper (*nextc)) |
| forcelc (tword, flent->affl); |
| } |
| if (option == 3) |
| (void) printf ("\n%s", croot); |
| if (option != 4) |
| (void) printf (" %s%s", ichartosstr (tword, 1), extra); |
| if (flent->flagflags & FF_CROSSPRODUCT) |
| return tlen |
| + expand_suf (croot, tword, mask, FF_CROSSPRODUCT, option, extra); |
| else |
| return tlen; |
| } |
| |
| /* |
| * Expand a dictionary suffix entry |
| */ |
| int expand_suf (croot, rootword, mask, optflags, option, extra) |
| char * croot; /* Char version of rootword */ |
| ichar_t * rootword; /* Root word to expand */ |
| register MASKTYPE mask[]; /* Mask bits to expand on */ |
| int optflags; /* Affix option flags */ |
| int option; /* Option, see expandmode */ |
| char * extra; /* Extra info to add to line */ |
| { |
| int entcount; /* No. of entries to process */ |
| int explength; /* Length of expansions */ |
| register struct flagent * |
| flent; /* Current table entry */ |
| |
| for (flent = sflaglist, entcount = numsflags, explength = 0; |
| entcount > 0; |
| flent++, entcount--) |
| { |
| if (TSTMASKBIT (mask, flent->flagbit)) |
| { |
| if ((optflags & FF_CROSSPRODUCT) == 0 |
| || (flent->flagflags & FF_CROSSPRODUCT)) |
| explength += |
| pr_suf_expansion (croot, rootword, flent, option, extra); |
| } |
| } |
| return explength; |
| } |
| |
| /* Print a suffix expansion */ |
| static int pr_suf_expansion (croot, rootword, flent, option, extra) |
| char * croot; /* Char version of rootword */ |
| register ichar_t * rootword; /* Root word to expand */ |
| register struct flagent * flent; /* Current table entry */ |
| int option; /* Option, see expandmode */ |
| char * extra; /* Extra info to add to line */ |
| { |
| int cond; /* Current condition number */ |
| register ichar_t * nextc; /* Next case choice */ |
| int tlen; /* Length of tword */ |
| ichar_t tword[INPUTWORDLEN + MAXAFFIXLEN]; /* Temp */ |
| |
| tlen = icharlen (rootword); |
| cond = flent->numconds; |
| if (cond > tlen) |
| return 0; |
| if (tlen - flent->stripl <= 0) |
| return 0; |
| for (nextc = rootword + tlen; --cond >= 0; ) |
| { |
| if ((flent->conds[mytoupper (*--nextc)] & (1 << cond)) == 0) |
| return 0; |
| } |
| /* |
| * The conditions are satisfied. Copy the word, add the suffix, |
| * and make it match the case of the last remaining character of the |
| * root. Again, this code carefully matches ins_cap and cap_ok. |
| */ |
| (void) icharcpy (tword, rootword); |
| nextc = tword + tlen - flent->stripl; |
| if (flent->affl) |
| { |
| (void) icharcpy (nextc, flent->affix); |
| if (!myupper (nextc[-1])) |
| forcelc (nextc, flent->affl); |
| } |
| else |
| *nextc = 0; |
| if (option == 3) |
| (void) printf ("\n%s", croot); |
| if (option != 4) |
| (void) printf (" %s%s", ichartosstr (tword, 1), extra); |
| return tlen + flent->affl - flent->stripl; |
| } |
| |
| static void forcelc (dst, len) /* Force to lowercase */ |
| register ichar_t * dst; /* Destination to modify */ |
| register int len; /* Length to copy */ |
| { |
| |
| for ( ; --len >= 0; dst++) |
| *dst = mytolower (*dst); |
| } |