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

Revision 10334, 11.1 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: 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
75int             good P ((ichar_t * word, int ignoreflagbits, int allhits,
76                  int pfxopts, int sfxopts));
77#ifndef NO_CAPITALIZATION_SUPPORT
78int             cap_ok P ((ichar_t * word, struct success * hit, int len));
79static int      entryhasaffixes P ((struct dent * dent, struct success * hit));
80#endif /* NO_CAPITALIZATION_SUPPORT */
81void            flagpr P ((ichar_t * word, int preflag, int prestrip,
82                  int preadd, int sufflag, int sufadd));
83
84static ichar_t *        orig_word;
85
86#ifndef NO_CAPITALIZATION_SUPPORT
87int 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 */
95int 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
170int 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;
286doublecontinue: ;
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*/
302static 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 */
319void 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    }
Note: See TracBrowser for help on using the repository browser.