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

Revision 10334, 20.6 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: tree.c,v 1.1.1.1 1997-09-03 21:08:12 ghudson Exp $";
4#endif
5
6/*
7 * tree.c - a hash style dictionary for user's personal words
8 *
9 * Pace Willisson, 1983
10 * Hash support added by Geoff Kuenning, 1987
11 *
12 * Copyright 1987, 1988, 1989, 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.56  1995/01/08  23:23:49  geoff
52 * Support PDICTHOME for DOS purposes.
53 *
54 * Revision 1.55  1994/10/25  05:46:27  geoff
55 * Fix a comment that looked to some compilers like it might be nested.
56 *
57 * Revision 1.54  1994/01/25  07:12:15  geoff
58 * Get rid of all old RCS log lines in preparation for the 3.1 release.
59 *
60 */
61
62#include <ctype.h>
63#include <errno.h>
64#include "config.h"
65#include "ispell.h"
66#include "proto.h"
67#include "msgs.h"
68
69void            treeinit P ((char * p, char * LibDict));
70static FILE *   trydict P ((char * dictname, char * home,
71                  char * prefix, char * suffix));
72static void     treeload P ((FILE * dictf));
73void            treeinsert P ((char * word, int wordlen, int keep));
74static struct dent * tinsert P ((struct dent * proto));
75struct dent *   treelookup P ((ichar_t * word));
76#if SORTPERSONAL != 0
77static int      pdictcmp P ((struct dent ** enta, struct dent **entb));
78#endif /* SORTPERSONAL != 0 */
79void            treeoutput P ((void));
80VOID *          mymalloc P ((unsigned int size));
81void            myfree P ((VOID * ptr));
82#ifdef REGEX_LOOKUP
83char *          do_regex_lookup P ((char * expr, int whence));
84#endif /* REGEX_LOOKUP */
85
86static int              cantexpand = 0; /* NZ if an expansion fails */
87static struct dent *    pershtab;       /* Aux hash table for personal dict */
88static int              pershsize = 0;  /* Space available in aux hash table */
89static int              hcount = 0;     /* Number of items in hash table */
90
91/*
92 * Hash table sizes.  Prime is probably a good idea, though in truth I
93 * whipped the algorithm up on the spot rather than looking it up, so
94 * who knows what's really best?  If we overflow the table, we just
95 * use a double-and-add-1 algorithm.
96 */
97static int goodsizes[] =
98    {
99    53, 223, 907, 3631
100    };
101
102static char             personaldict[MAXPATHLEN];
103static FILE *           dictf;
104static                  newwords = 0;
105
106void treeinit (p, LibDict)
107    char *              p;              /* Value specified in -p switch */
108    char *              LibDict;        /* Root of default dict name */
109    {
110    int                 abspath;        /* NZ if p is abs path name */
111    char *              h;              /* Home directory name */
112    char                seconddict[MAXPATHLEN]; /* Name of secondary dict */
113    FILE *              secondf;        /* Access to second dict file */
114
115    /*
116    ** If -p was not specified, try to get a default name from the
117    ** environment.  After this point, if p is null, the the value in
118    ** personaldict is the only possible name for the personal dictionary.
119    ** If p is non-null, then there is a possibility that we should
120    ** prepend HOME to get the correct dictionary name.
121    */
122    if (p == NULL)
123        p = getenv (PDICTVAR);
124    /*
125    ** if p exists and begins with '/' we don't really need HOME,
126    ** but it's not very likely that HOME isn't set anyway (on non-DOS
127    ** systems).
128    */
129    if ((h = getenv (HOME)) == NULL)
130        {
131#ifdef PDICTHOME
132        h = PDICTHOME;
133#else /* PDICTHOME */
134        return;
135#endif /* PDICTHOME */
136        }
137
138    if (p == NULL)
139        {
140        /*
141         * No -p and no PDICTVAR.  We will use LibDict and DEFPAFF to
142         * figure out the name of the personal dictionary and where it
143         * is.  The rules are as follows:
144         *
145         * (1) If there is a local dictionary and a HOME dictionary,
146         *     both are loaded, but changes are saved in the local one.
147         *     The dictionary to save changes in is named "personaldict".
148         * (2) Dictionaries named after the affix file take precedence
149         *     over dictionaries with the default suffix (DEFPAFF).
150         * (3) Dictionaries named with the new default names
151         *     (DEFPDICT/DEFPAFF) take precedence over the old ones
152         *     (OLDPDICT/OLDPAFF).
153         * (4) Dictionaries aren't combined unless they follow the same
154         *     naming scheme.
155         * (5) If no dictionary can be found, a new one is created in
156         *     the home directory, named after DEFPDICT and the affix
157         *     file.
158         */
159        dictf = trydict (personaldict, (char *) NULL, DEFPDICT, LibDict);
160        secondf = trydict (seconddict, h, DEFPDICT, LibDict);
161        if (dictf == NULL  &&  secondf == NULL)
162            {
163            dictf = trydict (personaldict, (char *) NULL, DEFPDICT, DEFPAFF);
164            secondf = trydict (seconddict, h, DEFPDICT, DEFPAFF);
165            }
166        if (dictf == NULL  &&  secondf == NULL)
167            {
168            dictf = trydict (personaldict, (char *) NULL, OLDPDICT, LibDict);
169            secondf = trydict (seconddict, h, OLDPDICT, LibDict);
170            }
171        if (dictf == NULL  &&  secondf == NULL)
172            {
173            dictf = trydict (personaldict, (char *) NULL, OLDPDICT, OLDPAFF);
174            secondf = trydict (seconddict, h, OLDPDICT, OLDPAFF);
175            }
176        if (personaldict[0] == '\0')
177            {
178            if (seconddict[0] != '\0')
179                (void) strcpy (personaldict, seconddict);
180            else
181                (void) sprintf (personaldict, "%s/%s%s", h, DEFPDICT, LibDict);
182            }
183        if (dictf != NULL)
184            {
185            treeload (dictf);
186            (void) fclose (dictf);
187            }
188        if (secondf != NULL)
189            {
190            treeload (secondf);
191            (void) fclose (secondf);
192            }
193        }
194    else
195        {
196        /*
197        ** Figure out if p is an absolute path name.  Note that beginning
198        ** with "./" and "../" is considered an absolute path, since this
199        ** still means we can't prepend HOME.
200        */
201        abspath = (*p == '/'  ||  strncmp (p, "./", 2) == 0
202          ||  strncmp (p, "../", 3) == 0);
203        if (abspath)
204            {
205            (void) strcpy (personaldict, p);
206            if ((dictf = fopen (personaldict, "r")) != NULL)
207                {
208                treeload (dictf);
209                (void) fclose (dictf);
210                }
211            }
212        else
213            {
214            /*
215            ** The user gave us a relative pathname.  We will try it
216            ** locally, and if that doesn't work, we'll try the home
217            ** directory.  If neither exists, it will be created in
218            ** the home directory if words are added.
219            */
220            (void) strcpy (personaldict, p);
221            if ((dictf = fopen (personaldict, "r")) != NULL)
222                {
223                treeload (dictf);
224                (void) fclose (dictf);
225                }
226            else if (!abspath)
227                {
228                /* Try the home */
229                (void) sprintf (personaldict, "%s/%s", h, p);
230                if ((dictf = fopen (personaldict, "r")) != NULL)
231                    {
232                    treeload (dictf);
233                    (void) fclose (dictf);
234                    }
235                }
236            /*
237             * If dictf is null, we couldn't open the dictionary
238             * specified in the -p switch.  Complain.
239             */
240            if (dictf == NULL)
241                {
242                (void) fprintf (stderr, CANT_OPEN, p);
243                perror ("");
244                return;
245                }
246            }
247        }
248
249    if (!lflag  &&  !aflag
250      &&  access (personaldict, 2) < 0  &&  errno != ENOENT)
251        {
252        (void) fprintf (stderr, TREE_C_CANT_UPDATE, personaldict);
253        (void) sleep ((unsigned) 2);
254        }
255    }
256
257/*
258 * Try to open a dictionary.  As a side effect, leaves the dictionary
259 * name in "filename" if one is found, and leaves a null string there
260 * otherwise.
261 */
262static FILE * trydict (filename, home, prefix, suffix)
263    char *              filename;       /* Where to store the file name */
264    char *              home;           /* Home directory */
265    char *              prefix;         /* Prefix for dictionary */
266    char *              suffix;         /* Suffix for dictionary */
267    {
268    FILE *              dictf;          /* Access to dictionary file */
269
270    if (home == NULL)
271        (void) sprintf (filename, "%s%s", prefix, suffix);
272    else
273        (void) sprintf (filename, "%s/%s%s", home, prefix, suffix);
274    dictf = fopen (filename, "r");
275    if (dictf == NULL)
276        filename[0] = '\0';
277    return dictf;
278    }
279
280static void treeload (loadfile)
281    register FILE *     loadfile;       /* File to load words from */
282    {
283    char                buf[BUFSIZ];    /* Buffer for reading pers dict */
284
285    while (fgets (buf, sizeof buf, loadfile) != NULL)
286        treeinsert (buf, sizeof buf, 1);
287    newwords = 0;
288    }
289
290void treeinsert (word, wordlen, keep)
291    char *              word;   /* Word to insert - must be canonical */
292    int                 wordlen; /* Length of the word buffer */
293    int                 keep;
294    {
295    register int        i;
296    struct dent         wordent;
297    register struct dent * dp;
298    struct dent *       olddp;
299#ifndef NO_CAPITALIZATION_SUPPORT
300    struct dent *       newdp;
301#endif
302    struct dent *       oldhtab;
303    int                 oldhsize;
304    ichar_t             nword[INPUTWORDLEN + MAXAFFIXLEN];
305#ifndef NO_CAPITALIZATION_SUPPORT
306    int                 isvariant;
307#endif
308
309    /*
310     * Expand hash table when it is MAXPCT % full.
311     */
312    if (!cantexpand  &&  (hcount * 100) / MAXPCT >= pershsize)
313        {
314        oldhsize = pershsize;
315        oldhtab = pershtab;
316        for (i = 0;  i < sizeof goodsizes / sizeof (goodsizes[0]);  i++)
317            {
318            if (goodsizes[i] > pershsize)
319                break;
320            }
321        if (i >= sizeof goodsizes / sizeof goodsizes[0])
322            pershsize += pershsize + 1;
323        else
324            pershsize = goodsizes[i];
325        pershtab =
326          (struct dent *) calloc ((unsigned) pershsize, sizeof (struct dent));
327        if (pershtab == NULL)
328            {
329            (void) fprintf (stderr, TREE_C_NO_SPACE);
330            /*
331             * Try to continue anyway, since our overflow
332             * algorithm can handle an overfull (100%+) table,
333             * and the malloc very likely failed because we
334             * already have such a huge table, so small mallocs
335             * for overflow entries will still work.
336             */
337            if (oldhtab == NULL)
338                exit (1);               /* No old table, can't go on */
339            (void) fprintf (stderr, TREE_C_TRY_ANYWAY);
340            cantexpand = 1;             /* Suppress further messages */
341            pershsize = oldhsize;       /* Put things back */
342            pershtab = oldhtab;         /* ... */
343            newwords = 1;               /* And pretend it worked */
344            }
345        else
346            {
347            /*
348             * Re-insert old entries into new table
349             */
350            for (i = 0;  i < oldhsize;  i++)
351                {
352                dp = &oldhtab[i];
353                if (dp->flagfield & USED)
354                    {
355#ifdef NO_CAPITALIZATION_SUPPORT
356                    (void) tinsert (dp);
357#else
358                    newdp = tinsert (dp);
359                    isvariant = (dp->flagfield & MOREVARIANTS);
360#endif
361                    dp = dp->next;
362#ifdef NO_CAPITALIZATION_SUPPORT
363                    while (dp != NULL)
364                        {
365                        (void) tinsert (dp);
366                        olddp = dp;
367                        dp = dp->next;
368                        free ((char *) olddp);
369                        }
370#else
371                    while (dp != NULL)
372                        {
373                        if (isvariant)
374                            {
375                            isvariant = dp->flagfield & MOREVARIANTS;
376                            olddp = newdp->next;
377                            newdp->next = dp;
378                            newdp = dp;
379                            dp = dp->next;
380                            newdp->next = olddp;
381                            }
382                        else
383                            {
384                            isvariant = dp->flagfield & MOREVARIANTS;
385                            newdp = tinsert (dp);
386                            olddp = dp;
387                            dp = dp->next;
388                            free ((char *) olddp);
389                            }
390                        }
391#endif
392                    }
393                }
394            if (oldhtab != NULL)
395                free ((char *) oldhtab);
396            }
397        }
398
399    /*
400    ** We're ready to do the insertion.  Start by creating a sample
401    ** entry for the word.
402    */
403    if (makedent (word, wordlen, &wordent) < 0)
404        return;                 /* Word must be too big or something */
405    if (keep)
406        wordent.flagfield |= KEEP;
407    /*
408    ** Now see if word or a variant is already in the table.  We use the
409    ** capitalized version so we'll find the header, if any.
410    **/
411    (void) strtoichar (nword, word, sizeof nword, 1);
412    upcase (nword);
413    if ((dp = lookup (nword, 1)) != NULL)
414        {
415        /* It exists.  Combine caps and set the keep flag. */
416        if (combinecaps (dp, &wordent) < 0)
417            {
418            free (wordent.word);
419            return;
420            }
421        }
422    else
423        {
424        /* It's new. Insert the word. */
425        dp = tinsert (&wordent);
426#ifndef NO_CAPITALIZATION_SUPPORT
427        if (captype (dp->flagfield) == FOLLOWCASE)
428           (void) addvheader (dp);
429#endif
430        }
431    newwords |= keep;
432    }
433
434static struct dent * tinsert (proto)
435    struct dent *       proto;          /* Prototype entry to copy */
436    {
437    ichar_t             iword[INPUTWORDLEN + MAXAFFIXLEN];
438    register int        hcode;
439    register struct dent * hp;          /* Next trial entry in hash table */
440    register struct dent * php;         /* Prev. value of hp, for chaining */
441
442    if (strtoichar (iword, proto->word, sizeof iword, 1))
443        (void) fprintf (stderr, WORD_TOO_LONG (proto->word));
444#ifdef NO_CAPITALIZATION_SUPPORT
445    upcase (iword);
446#endif
447    hcode = hash (iword, pershsize);
448    php = NULL;
449    hp = &pershtab[hcode];
450    if (hp->flagfield & USED)
451        {
452        while (hp != NULL)
453            {
454            php = hp;
455            hp = hp->next;
456            }
457        hp = (struct dent *) calloc (1, sizeof (struct dent));
458        if (hp == NULL)
459            {
460            (void) fprintf (stderr, TREE_C_NO_SPACE);
461            exit (1);
462            }
463        }
464    *hp = *proto;
465    if (php != NULL)
466        php->next = hp;
467    hp->next = NULL;
468    return hp;
469    }
470
471struct dent * treelookup (word)
472    register ichar_t *  word;
473    {
474    register int        hcode;
475    register struct dent * hp;
476    char                chword[INPUTWORDLEN + MAXAFFIXLEN];
477
478    if (pershsize <= 0)
479        return NULL;
480    (void) ichartostr (chword, word, sizeof chword, 1);
481    hcode = hash (word, pershsize);
482    hp = &pershtab[hcode];
483    while (hp != NULL  &&  (hp->flagfield & USED))
484        {
485        if (strcmp (chword, hp->word) == 0)
486            break;
487#ifndef NO_CAPITALIZATION_SUPPORT
488        while (hp->flagfield & MOREVARIANTS)
489            hp = hp->next;
490#endif
491        hp = hp->next;
492        }
493    if (hp != NULL  &&  (hp->flagfield & USED))
494        return hp;
495    else
496        return NULL;
497    }
498
499#if SORTPERSONAL != 0
500/* Comparison routine for sorting the personal dictionary with qsort */
501static int pdictcmp (enta, entb)
502    struct dent **      enta;
503    struct dent **      entb;
504    {
505
506    /* The parentheses around *enta and *entb below are NECESSARY!
507    ** Otherwise the compiler reads it as *(enta->word), or
508    ** enta->word[0], which is illegal (but pcc takes it and
509    ** produces wrong code).
510    **/
511    return casecmp ((*enta)->word, (*entb)->word, 1);
512    }
513#endif
514
515void treeoutput ()
516    {
517    register struct dent *      cent;   /* Current entry */
518    register struct dent *      lent;   /* Linked entry */
519#if SORTPERSONAL != 0
520    int                         pdictsize; /* Number of entries to write */
521    struct dent **              sortlist; /* List of entries to be sorted */
522    register struct dent **     sortptr; /* Handy pointer into sortlist */
523#endif
524    register struct dent *      ehtab;  /* End of pershtab, for fast looping */
525
526    if (newwords == 0)
527        return;
528
529    if ((dictf = fopen (personaldict, "w")) == NULL)
530        {
531        (void) fprintf (stderr, CANT_CREATE, personaldict);
532        return;
533        }
534
535#if SORTPERSONAL != 0
536    /*
537    ** If we are going to sort the personal dictionary, we must know
538    ** how many items are going to be sorted.
539    */
540    pdictsize = 0;
541    if (hcount >= SORTPERSONAL)
542        sortlist = NULL;
543    else
544        {
545        for (cent = pershtab, ehtab = pershtab + pershsize;
546          cent < ehtab;
547          cent++)
548            {
549            for (lent = cent;  lent != NULL;  lent = lent->next)
550                {
551                if ((lent->flagfield & (USED | KEEP)) == (USED | KEEP))
552                    pdictsize++;
553#ifndef NO_CAPITALIZATION_SUPPORT
554                while (lent->flagfield & MOREVARIANTS)
555                  lent = lent->next;
556#endif
557                }
558            }
559        for (cent = hashtbl, ehtab = hashtbl + hashsize;
560          cent < ehtab;
561          cent++)
562            {
563            if ((cent->flagfield & (USED | KEEP)) == (USED | KEEP))
564                {
565                /*
566                ** We only want to count variant headers
567                ** and standalone entries.  These happen
568                ** to share the characteristics in the
569                ** test below.  This test will appear
570                ** several more times in this routine.
571                */
572#ifndef NO_CAPITALIZATION_SUPPORT
573                if (captype (cent->flagfield) != FOLLOWCASE
574                  &&  cent->word != NULL)
575#endif
576                    pdictsize++;
577                }
578            }
579        sortlist = (struct dent **) malloc (pdictsize * sizeof (struct dent));
580        }
581    if (sortlist == NULL)
582        {
583#endif
584        for (cent = pershtab, ehtab = pershtab + pershsize;
585          cent < ehtab;
586          cent++)
587            {
588            for (lent = cent;  lent != NULL;  lent = lent->next)
589                {
590                if ((lent->flagfield & (USED | KEEP)) == (USED | KEEP))
591                    {
592                    toutent (dictf, lent, 1);
593#ifndef NO_CAPITALIZATION_SUPPORT
594                    while (lent->flagfield & MOREVARIANTS)
595                        lent = lent->next;
596#endif
597                    }
598                }
599            }
600        for (cent = hashtbl, ehtab = hashtbl + hashsize;
601          cent < ehtab;
602          cent++)
603            {
604            if ((cent->flagfield & (USED | KEEP)) == (USED | KEEP))
605                {
606#ifndef NO_CAPITALIZATION_SUPPORT
607                if (captype (cent->flagfield) != FOLLOWCASE
608                  &&  cent->word != NULL)
609#endif
610                    toutent (dictf, cent, 1);
611                }
612            }
613#if SORTPERSONAL != 0
614        return;
615        }
616    /*
617    ** Produce dictionary in sorted order.  We used to do this
618    ** destructively, but that turns out to fail because in some modes
619    ** the dictionary is written more than once.  So we build an
620    ** auxiliary pointer table (in sortlist) and sort that.  This
621    ** is faster anyway, though it uses more memory.
622    */
623    sortptr = sortlist;
624    for (cent = pershtab, ehtab = pershtab + pershsize;  cent < ehtab;  cent++)
625        {
626        for (lent = cent;  lent != NULL;  lent = lent->next)
627            {
628            if ((lent->flagfield & (USED | KEEP)) == (USED | KEEP))
629                {
630                *sortptr++ = lent;
631#ifndef NO_CAPITALIZATION_SUPPORT
632                while (lent->flagfield & MOREVARIANTS)
633                    lent = lent->next;
634#endif
635                }
636            }
637        }
638    for (cent = hashtbl, ehtab = hashtbl + hashsize;  cent < ehtab;  cent++)
639        {
640        if ((cent->flagfield & (USED | KEEP)) == (USED | KEEP))
641            {
642#ifndef NO_CAPITALIZATION_SUPPORT
643            if (captype (cent->flagfield) != FOLLOWCASE
644              &&  cent->word != NULL)
645#endif
646                *sortptr++ = cent;
647            }
648        }
649    /* Sort the list */
650    qsort ((char *) sortlist, (unsigned) pdictsize,
651      sizeof (sortlist[0]),
652      (int (*) P ((const void *, const void *))) pdictcmp);
653    /* Write it out */
654    for (sortptr = sortlist;  --pdictsize >= 0;  )
655        toutent (dictf, *sortptr++, 1);
656    free ((char *) sortlist);
657#endif
658
659    newwords = 0;
660
661    (void) fclose (dictf);
662    }
663
664VOID * mymalloc (size)
665    unsigned int        size;
666    {
667
668    return malloc ((unsigned) size);
669    }
670
671void myfree (ptr)
672    VOID * ptr;
673    {
674    if (hashstrings != NULL  &&  (char *) ptr >= hashstrings
675      &&  (char *) ptr <= hashstrings + hashheader.stringsize)
676        return;                 /* Can't free stuff in hashstrings */
677    free (ptr);
678    }
679
680#ifdef REGEX_LOOKUP
681
682/* check the hashed dictionary for words matching the regex. return the */
683/* a matching string if found else return NULL */
684char * do_regex_lookup (expr, whence)
685    char *      expr;   /* regular expression to use in the match   */
686    int         whence; /* 0 = start at the beg with new regx, else */
687                        /* continue from cur point w/ old regex     */
688    {
689    static struct dent *    curent;
690    static int              curindex;
691    static struct dent *    curpersent;
692    static int              curpersindex;
693    static char *           cmp_expr;
694    char                    dummy[INPUTWORDLEN + MAXAFFIXLEN];
695    ichar_t *               is;
696
697    if (whence == 0)
698        {
699        is = strtosichar (expr, 0);
700        upcase (is);
701        expr = ichartosstr (is, 1);
702        cmp_expr = REGCMP (expr);
703        curent = hashtbl;
704        curindex = 0;
705        curpersent = pershtab;
706        curpersindex = 0;
707        }
708   
709    /* search the dictionary until the word is found or the words run out */
710    for (  ; curindex < hashsize;  curent++, curindex++)
711        {
712        if (curent->word != NULL
713          &&  REGEX (cmp_expr, curent->word, dummy) != NULL)
714            {
715            curindex++;
716            /* Everybody's gotta write a wierd expression once in a while! */
717            return curent++->word;
718            }
719        }
720    /* Try the personal dictionary too */
721    for (  ; curpersindex < pershsize;  curpersent++, curpersindex++)
722        {
723        if ((curpersent->flagfield & USED) != 0
724          &&  curpersent->word != NULL
725          &&  REGEX (cmp_expr, curpersent->word, dummy) != NULL)
726            {
727            curpersindex++;
728            /* Everybody's gotta write a wierd expression once in a while! */
729            return curpersent++->word;
730            }
731        }
732    return NULL;
733    }
734#endif /* REGEX_LOOKUP */
Note: See TracBrowser for help on using the repository browser.