home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode:Text -*- */
- #ifndef lint
- static char Rcs_Id[] =
- "$Id: tree.c,v 1.44 91/08/10 14:09:49 geoff Exp $";
- #endif
-
- /*
- * tree.c - a hash style dictionary for user's personal words
- *
- * Pace Willisson, 1983
- * Hash support added by Geoff Kuenning, 1987
- *
- * Copyright 1987, 1988, 1989, by Geoff Kuenning, Manhattan Beach, CA
- * Permission for non-profit use is hereby granted.
- * All other rights reserved.
- * See "version.h" for a more complete copyright notice.
- */
-
- /*
- * $Log: tree.c,v $
- * Revision 1.44 91/08/10 14:09:49 geoff
- * Don't issue TREE_C_CANT_UPDATE if the personal dictionary doesn't
- * exist at all. Sleep for 2 seconds after issuing the message, so that
- * the user has a chance to see it before ispell clears the screen.
- *
- * Revision 1.43 91/07/27 20:48:39 geoff
- * Major rewrite of the personal-dictionary initialization to support a
- * personal dictionary in the local directory, and to merge it with the
- * one from the home directory if possible. Fix a compile error and a
- * bug in the REGEX_LOOKUP code.
- *
- * Revision 1.42 91/07/15 19:27:14 geoff
- * Make tinsert static. Mention that the argument to treeinsert must be
- * canonical. Provide the "canonical" parameter to all strtoichar,
- * strtosichar, and casecmp calls. Make sure the argument to casecmp is
- * canonical.
- *
- * Revision 1.41 91/07/11 19:52:29 geoff
- * Remove the include of stdio.h, since ispell.h now does this.
- *
- * Revision 1.40 91/07/05 20:32:00 geoff
- * Fix some more lint complaints.
- *
- * Revision 1.39 91/07/03 18:21:14 geoff
- * Don't include types.h, dir.h, or param.h, since config.h now does that.
- *
- * Revision 1.38 91/06/23 22:01:04 geoff
- * On non-USG systems, include sys/dir.h for MAXNAMLEN
- *
- * Revision 1.37 91/01/24 02:28:12 geoff
- * Modify dictionary-finding code to be more consistent and predictable
- * about where it looks, to create nonexistent dictionaries in $HOME, and
- * to fix a bug that caused private dictionaries in the home to be clobbered.
- *
- * Revision 1.36 90/12/31 00:59:34 geoff
- * Reformat to follow a consistent convention throughout ispell
- *
- * Revision 1.35 90/04/26 22:44:31 geoff
- * Add the canonicalize parameter to the call to ichartostr.
- *
- * Revision 1.34 89/12/27 03:19:02 geoff
- * Move all messages to msgs.h so they can be reconfigured
- *
- * Revision 1.33 89/07/11 00:25:41 geoff
- * Add REGEX_LOOKUP support and Amiga support, based on that from
- * luis@rice.edu. Also change the name of the personal hash table to better
- * distinguish it from the main one.
- *
- * Revision 1.32 89/06/09 15:56:53 geoff
- * Add support for the internal "character" type, ichar_t.
- *
- * Revision 1.31 89/04/28 01:17:36 geoff
- * Change Header to Id; nobody cares about my pathnames.
- *
- * Revision 1.30 89/04/03 01:59:15 geoff
- * Fix a bunch of lint complaints.
- *
- * Revision 1.29 88/12/26 02:33:53 geoff
- * Add a copyright notice.
- *
- * Revision 1.28 88/10/20 20:53:27 geoff
- * Add support for getting a different personal dictionary when the -d
- * switch is specified, for multilingual use of ispell.
- *
- * Revision 1.27 88/04/30 22:16:25 geoff
- * Fix some lint complaints.
- *
- * Revision 1.26 88/03/27 01:06:03 geoff
- * Fix a whole bunch of problems with the CAPITALIZATION option.
- *
- * Revision 1.25 88/03/12 02:46:03 geoff
- * Check the return status from makedent, and don't idiotically try to
- * continue if it fails.
- *
- * Revision 1.24 88/02/20 23:15:06 geoff
- * Major changes to support the new capitalization handling, and to use
- * the new subroutines in the "makedent.c" module.
- *
- * Revision 1.23 87/09/30 23:32:04 geoff
- * Move some globals to ispell.h.
- *
- * Revision 1.22 87/09/26 15:53:07 geoff
- * Make buffer sizes be more consistent.
- *
- * Revision 1.21 87/09/24 23:24:35 geoff
- * When changing a lowercase word to followcase, remember to set the
- * capitalize flags. (Bart Schaefer).
- *
- * Revision 1.20 87/09/09 00:20:10 geoff
- * Fix treeoutput() to be nondestructive (Doug Lind, Michael Wester). It's
- * faster too, since it now uses qsort. Also fix several bugs in
- * treeinsert: capitalization information wasn't checked on memory
- * overflow, and duplicate followcase entries weren't detected.
- *
- * Revision 1.19 87/09/03 19:26:59 geoff
- * Simplify the hash-size table now that we don't read entire dictionaries
- * into the personal-hash tree.
- *
- * Revision 1.18 87/07/20 23:23:27 geoff
- * Modify to support the new flag format used with language tables.
- *
- * Revision 1.17 87/06/07 15:04:25 geoff
- * Don't refer to capitalization flags if CAPITALIZE is off (Gary Johnson)
- *
- * Revision 1.16 87/05/27 23:28:40 geoff
- * Reset hasslash in toutword so every word gets a slash
- *
- * Revision 1.15 87/05/11 11:50:35 geoff
- * Speed up SORTPERSONAL dramatically by not scanning unkept words repeatedly.
- *
- * Revision 1.14 87/04/19 22:53:55 geoff
- * Add SORTPERSONAL and capitalization support.
- *
- * Revision 1.13 87/04/02 12:25:55 geoff
- * Remove the obsolete treeprint() routine. Put the "can't update
- * personal dict" error message onto stderr, not stdout.
- *
- * Revision 1.12 87/04/01 15:23:06 geoff
- * Integrate Joe Orost's V7/register changes into the main branch
- *
- * Revision 1.11 87/03/28 19:33:24 geoff
- * Put the personal dictionary out in compressed (no extra slashes) form
- *
- * Revision 1.10 87/03/27 17:21:48 geoff
- * Accept (but don't require) new-format dictionaries without extra slashes.
- * However, don't generate them on dumps yet.
- *
- * Revision 1.9 87/03/22 23:28:03 geoff
- * Integrate Perry Smith's changes into the main branch
- *
- * Revision 1.8 87/03/12 23:36:54 geoff
- * Fix treeprint, which didn't catch up to the latest changes. Remove the
- * list-link following in the main hash table in treeoutput, since the
- * entries will eventually be found by the linear search.
- *
- * Revision 1.7 87/03/10 23:33:13 geoff
- * Add code to deal gracefully with memory allocation failures. If small
- * allocations fail, put out a message and exit. If a big hash table allocation
- * fails, put out a message, but continue anyway, just filling the existing
- * table overfull.
- *
- * Revision 1.6 87/03/08 20:31:27 geoff
- * Improve the hash sizes table to be appropriate to really big dictionaries.
- * Change the personal-dictionary opening code to be more flexible about
- * where it looks, so that relative pathnames will work sensibly.
- * Make lots of changes in the hashing so it works better and faster.
- *
- * Revision 1.5 87/03/01 00:57:17 geoff
- * Major changes to use a hash table instead of a binary tree, allow
- * user dictionaries to have suffixes, and integrate the user dictionary
- * with the main one.
- *
- * Revision 1.4 87/02/28 14:58:44 geoff
- * Modify to support suffix flags in the user dictionary.
- *
- * Revision 1.3 87/02/26 00:25:23 geoff
- * Integrate McQueer's enhancements into the main branch
- *
- * Revision 1.2 87/01/17 13:12:28 geoff
- * Add RCS ID keywords
- *
- */
-
- #include <ctype.h>
- #include <errno.h>
- #include "config.h"
- #include "ispell.h"
- #include "msgs.h"
-
- static int cantexpand = 0; /* NZ if an expansion fails */
- static struct dent * pershtab; /* Aux hash table for personal dict */
- static int pershsize = 0; /* Space available in aux hash table */
- static int hcount = 0; /* Number of items in hash table */
-
- /*
- * Hash table sizes. Prime is probably a good idea, though in truth I
- * whipped the algorithm up on the spot rather than looking it up, so
- * who knows what's really best? If we overflow the table, we just
- * use a double-and-add-1 algorithm.
- */
- static int goodsizes[] =
- {
- 53, 223, 907, 3631
- };
-
- static void treeload ();
- void treeinsert ();
- static struct dent * tinsert ();
- struct dent * treelookup ();
-
- static char personaldict[MAXPATHLEN];
- static FILE * dictf;
- static newwords = 0;
-
- extern struct dent * lookup();
- extern void upcase();
-
- void myfree ();
-
- extern char * index ();
- extern char * calloc ();
- extern char * malloc ();
- extern char * realloc ();
- extern void free ();
- extern void exit ();
- extern void perror ();
- extern char * getenv();
- extern char * strcpy ();
- extern void qsort ();
-
- treeinit (p, LibDict)
- char * p; /* Value specified in -p switch */
- char * LibDict; /* Root of default dict name */
- {
- int abspath; /* NZ if p is abs path name */
- char * h; /* Home directory name */
- char seconddict[MAXPATHLEN]; /* Name of secondary dict */
-
- /*
- ** If -p was not specified, try to get a default name from the
- ** configuration file settings, and next from the
- ** environment. After this point, if p is null, the the value in
- ** personaldict is the only possible name for the personal dictionary.
- ** If p is non-null, then there is a possibility that we should
- ** prepend HOME to get the correct dictionary name.
- */
-
- #ifdef OS2 /* try to get config file info 8/24/92 */
- if ( (p == NULL) && (cfpersonaldict[0] != NULL) )
- p = cfpersonaldict;
- #endif /* OS2 */
-
- if (p == NULL)
- p = getenv (PDICTVAR);
- /*
- ** if p exists and begins with '/' we don't really need HOME,
- ** but it's not very likely that HOME isn't set anyway.
- ** The HOME environment variable will not be sought under os/2.
- ** jbh 8/26/92
- */
-
- #ifdef OS2
- h=cflibdir; /* For os/2 home is going to be where ispell.exe is located */
- #else
- if ((h = getenv ("HOME")) == NULL)
- #ifdef AMIGA
- h = LIBDIR;
- #else /* AMIGA */
- return;
- #endif /* AMIGA */
- #endif /* OS2 */
-
- if (p == NULL)
- {
- /*
- * No -p and no PDICTVAR. We will use LibDict and DEFPAFF to
- * figure out the name of the personal dictionary and where it
- * is. The rules are as follows:
- *
- * (1) If there is a dictionary in the local directory which
- * is named after the hash file, this will become
- * "personaldict", which is where any changes will be saved.
- * (2) If there is also a dictionary in $HOME, we will load
- * it, regardless of whether the dictionary listed in (1)
- * exists. If step (1) failed, this will also become
- * "personaldict".
- * (3) If both previous steps fail, we will try them again,
- * using DEFPAFF as the suffix.
- */
- (void) sprintf (personaldict, "%s%s", DEFPDICT, LibDict);
- (void) sprintf (seconddict, "%s/%s%s", h, DEFPDICT, LibDict);
- if ((dictf = fopen (personaldict, "r")) == NULL)
- personaldict[0] = '\0';
- else
- {
- treeload (dictf);
- (void) fclose (dictf);
- }
- if ((dictf = fopen (seconddict, "r")) == NULL)
- seconddict[0] = '\0';
- else
- {
- treeload (dictf);
- (void) fclose (dictf);
- }
- if (personaldict[0] == '\0')
- {
- if (seconddict[0] != '\0')
- (void) strcpy (personaldict, seconddict);
- else
- {
- (void) sprintf (personaldict, "%s%s", DEFPDICT, DEFPAFF);
- (void) sprintf (seconddict, "%s/%s%s", h, DEFPDICT, DEFPAFF);
- if ((dictf = fopen (personaldict, "r")) == NULL)
- (void) strcpy (personaldict, seconddict);
- else
- {
- treeload (dictf);
- (void) fclose (dictf);
- }
- if ((dictf = fopen (seconddict, "r")) != NULL)
- {
- treeload (dictf);
- (void) fclose (dictf);
- }
- }
- }
- }
- else
- {
- /*
- ** Figure out if p is an absolute path name. Note that beginning
- ** with "./" and "../" is considered an absolute path, since this
- ** still means we can't prepend HOME.
- **
- ** added by jbh 8/15/92: Must also look for drive specifiers
- ** as an indicator of absolute path under os/2. The filename is
- ** searched for the ":" character, since this indicates an
- ** absolute path
- */
- #ifdef OS2
- abspath = (*p == '/' || strncmp (p, "./", 2) == 0
- || strncmp (p, "../", 3) == 0 || strchr (p , ':') != NULL );
- #else
- abspath = (*p == '/' || strncmp (p, "./", 2) == 0
- || strncmp (p, "../", 3) == 0);
- #endif /* OS2 */
-
- if (abspath)
- {
- (void) strcpy (personaldict, p);
- if ((dictf = fopen (personaldict, "r")) != NULL)
- {
- treeload (dictf);
- (void) fclose (dictf);
- }
- }
- else
- {
- /*
- ** The user gave us a relative pathname. We will try it
- ** locally, and if that doesn't work, we'll try the home
- ** directory. If neither exists, it will be created in
- ** the home directory if words are added.
- */
- (void) strcpy (personaldict, p);
- if ((dictf = fopen (personaldict, "r")) != NULL)
- {
- treeload (dictf);
- (void) fclose (dictf);
- }
- else if (!abspath)
- {
- /* Try the home */
- (void) sprintf (personaldict, "%s/%s", h, p);
- if ((dictf = fopen (personaldict, "r")) != NULL)
- {
- treeload (dictf);
- (void) fclose (dictf);
- }
- }
- /*
- * If dictf is null, we couldn't open the dictionary
- * specified in the -p switch. Complain.
- */
- if (dictf == NULL)
- {
- (void) fprintf (stderr, CANT_OPEN, p);
- perror ("");
- return;
- }
- }
- }
-
- if (!lflag && !aflag
- && access (personaldict, 2) < 0 && errno != ENOENT)
- {
- (void) fprintf (stderr, TREE_C_CANT_UPDATE, personaldict);
- (void) sleep (2);
- }
- }
-
- static void treeload (dictf)
- register FILE * dictf; /* File to load words from */
- {
- char buf[BUFSIZ]; /* Buffer for reading pers dict */
-
- while (fgets (buf, sizeof buf, dictf) != NULL)
- treeinsert (buf, 1);
- newwords = 0;
- }
-
- void treeinsert (word, keep)
- char * word; /* Word to insert - must be canonical */
- int keep;
- {
- register int i;
- struct dent wordent;
- register struct dent * dp;
- struct dent * olddp;
- #ifdef CAPITALIZATION
- struct dent * newdp;
- #endif
- struct dent * oldhtab;
- int oldhsize;
- ichar_t nword[INPUTWORDLEN + MAXAFFIXLEN];
- #ifdef CAPITALIZATION
- int isvariant;
- #endif
-
- /*
- * Expand hash table when it is MAXPCT % full.
- */
- if (!cantexpand && (hcount * 100) / MAXPCT >= pershsize)
- {
- oldhsize = pershsize;
- oldhtab = pershtab;
- for (i = 0; i < sizeof goodsizes / sizeof (goodsizes[0]); i++)
- {
- if (goodsizes[i] > pershsize)
- break;
- }
- if (i >= sizeof goodsizes / sizeof goodsizes[0])
- pershsize += pershsize + 1;
- else
- pershsize = goodsizes[i];
- pershtab =
- (struct dent *) calloc ((unsigned) pershsize, sizeof (struct dent));
- if (pershtab == NULL)
- {
- (void) fprintf (stderr, TREE_C_NO_SPACE);
- /*
- * Try to continue anyway, since our overflow
- * algorithm can handle an overfull (100%+) table,
- * and the malloc very likely failed because we
- * already have such a huge table, so small mallocs
- * for overflow entries will still work.
- */
- if (oldhtab == NULL)
- exit (1); /* No old table, can't go on */
- (void) fprintf (stderr, TREE_C_TRY_ANYWAY);
- cantexpand = 1; /* Suppress further messages */
- pershsize = oldhsize; /* Put things back */
- pershtab = oldhtab; /* ... */
- newwords = 1; /* And pretend it worked */
- }
- else
- {
- /*
- * Re-insert old entries into new table
- */
- for (i = 0; i < oldhsize; i++)
- {
- dp = &oldhtab[i];
- if (dp->flagfield & USED)
- {
- #ifdef CAPITALIZATION
- newdp = tinsert (dp);
- isvariant = (dp->flagfield & MOREVARIANTS);
- #else
- (void) tinsert (dp);
- #endif
- dp = dp->next;
- #ifdef CAPITALIZATION
- while (dp != NULL)
- {
- if (isvariant)
- {
- isvariant = dp->flagfield & MOREVARIANTS;
- olddp = newdp->next;
- newdp->next = dp;
- newdp = dp;
- dp = dp->next;
- newdp->next = olddp;
- }
- else
- {
- isvariant = dp->flagfield & MOREVARIANTS;
- newdp = tinsert (dp);
- olddp = dp;
- dp = dp->next;
- free ((char *) olddp);
- }
- }
- #else
- while (dp != NULL)
- {
- (void) tinsert (dp);
- olddp = dp;
- dp = dp->next;
- free ((char *) olddp);
- }
- #endif
- }
- }
- if (oldhtab != NULL)
- free ((char *) oldhtab);
- }
- }
-
- /*
- ** We're ready to do the insertion. Start by creating a sample
- ** entry for the word.
- */
- if (makedent (word, &wordent) < 0)
- return; /* Word must be too big or something */
- if (keep)
- wordent.flagfield |= KEEP;
- /*
- ** Now see if word or a variant is already in the table. We use the
- ** capitalized version so we'll find the header, if any.
- **/
- strtoichar (nword, word, 1);
- upcase (nword);
- if ((dp = lookup (nword, 1)) != NULL)
- {
- /* It exists. Combine caps and set the keep flag. */
- if (combinecaps (dp, &wordent) < 0)
- {
- free (wordent.word);
- return;
- }
- }
- else
- {
- /* It's new. Insert the word. */
- dp = tinsert (&wordent);
- #ifdef CAPITALIZATION
- if (captype (dp->flagfield) == FOLLOWCASE)
- (void) addvheader (dp);
- #endif
- }
- newwords |= keep;
- }
-
- static struct dent * tinsert (proto)
- struct dent * proto; /* Prototype entry to copy */
- {
- ichar_t iword[INPUTWORDLEN + MAXAFFIXLEN];
- register int hcode;
- register struct dent * hp; /* Next trial entry in hash table */
- register struct dent * php; /* Prev. value of hp, for chaining */
-
- strtoichar (iword, proto->word, 1);
- #ifndef CAPITALIZATION
- upcase (iword);
- #endif
- hcode = hash (iword, pershsize);
- php = NULL;
- hp = &pershtab[hcode];
- if (hp->flagfield & USED)
- {
- while (hp != NULL)
- {
- php = hp;
- hp = hp->next;
- }
- hp = (struct dent *) calloc (1, sizeof (struct dent));
- if (hp == NULL)
- {
- (void) fprintf (stderr, TREE_C_NO_SPACE);
- exit (1);
- }
- }
- *hp = *proto;
- if (php != NULL)
- php->next = hp;
- hp->next = NULL;
- return hp;
- }
-
- struct dent * treelookup (word)
- register ichar_t * word;
- {
- register int hcode;
- register struct dent * hp;
- char chword[INPUTWORDLEN + MAXAFFIXLEN];
-
- if (pershsize <= 0)
- return NULL;
- (void) ichartostr (chword, word, 1);
- hcode = hash (word, pershsize);
- hp = &pershtab[hcode];
- while (hp != NULL && (hp->flagfield & USED))
- {
- if (strcmp (chword, hp->word) == 0)
- break;
- #ifdef CAPITALIZATION
- while (hp->flagfield & MOREVARIANTS)
- hp = hp->next;
- #endif
- hp = hp->next;
- }
- if (hp != NULL && (hp->flagfield & USED))
- return hp;
- else
- return NULL;
- }
-
- #if SORTPERSONAL != 0
- /* Comparison routine for sorting the personal dictionary with qsort */
- pdictcmp (enta, entb)
- struct dent ** enta;
- struct dent ** entb;
- {
-
- /* The parentheses around *enta/*entb below are NECESSARY!
- ** Otherwise the compiler reads it as *(enta->word), or
- ** enta->word[0], which is illegal (but pcc takes it and
- ** produces wrong code).
- **/
- return casecmp ((*enta)->word, (*entb)->word, 1);
- }
- #endif
-
- treeoutput ()
- {
- register struct dent * cent; /* Current entry */
- register struct dent * lent; /* Linked entry */
- #if SORTPERSONAL != 0
- int pdictsize; /* Number of entries to write */
- struct dent ** sortlist; /* List of entries to be sorted */
- register struct dent ** sortptr; /* Handy pointer into sortlist */
- #endif
- register struct dent * ehtab; /* End of pershtab, for fast looping */
-
- if (newwords == 0)
- return;
-
- if ((dictf = fopen (personaldict, "w")) == NULL)
- {
- (void) fprintf (stderr, CANT_CREATE, personaldict);
- return;
- }
-
- #if SORTPERSONAL != 0
- /*
- ** If we are going to sort the personal dictionary, we must know
- ** how many items are going to be sorted.
- */
- if (hcount >= SORTPERSONAL)
- sortlist = NULL;
- else
- {
- pdictsize = 0;
- for (cent = pershtab, ehtab = pershtab + pershsize;
- cent < ehtab;
- cent++)
- {
- for (lent = cent; lent != NULL; lent = lent->next)
- {
- if ((lent->flagfield & (USED | KEEP)) == (USED | KEEP))
- pdictsize++;
- #ifdef CAPITALIZATION
- while (lent->flagfield & MOREVARIANTS)
- lent = lent->next;
- #endif
- }
- }
- for (cent = hashtbl, ehtab = hashtbl + hashsize;
- cent < ehtab;
- cent++)
- {
- if ((cent->flagfield & (USED | KEEP)) == (USED | KEEP))
- {
- /*
- ** We only want to count variant headers
- ** and standalone entries. These happen
- ** to share the characteristics in the
- ** test below. This test will appear
- ** several more times in this routine.
- */
- #ifdef CAPITALIZATION
- if (captype (cent->flagfield) != FOLLOWCASE
- && cent->word != NULL)
- #endif
- pdictsize++;
- }
- }
- sortlist = (struct dent **) malloc (pdictsize * sizeof (struct dent));
- }
- if (sortlist == NULL)
- {
- #endif
- for (cent = pershtab, ehtab = pershtab + pershsize;
- cent < ehtab;
- cent++)
- {
- for (lent = cent; lent != NULL; lent = lent->next)
- {
- if ((lent->flagfield & (USED | KEEP)) == (USED | KEEP))
- {
- toutent (dictf, lent, 1);
- #ifdef CAPITALIZATION
- while (lent->flagfield & MOREVARIANTS)
- lent = lent->next;
- #endif
- }
- }
- }
- for (cent = hashtbl, ehtab = hashtbl + hashsize;
- cent < ehtab;
- cent++)
- {
- if ((cent->flagfield & (USED | KEEP)) == (USED | KEEP))
- {
- #ifdef CAPITALIZATION
- if (captype (cent->flagfield) != FOLLOWCASE
- && cent->word != NULL)
- #endif
- toutent (dictf, cent, 1);
- }
- }
- #if SORTPERSONAL != 0
- return;
- }
- /*
- ** Produce dictionary in sorted order. We used to do this
- ** destructively, but that turns out to fail because in some modes
- ** the dictionary is written more than once. So we build an
- ** auxiliary pointer table (in sortlist) and sort that. This
- ** is faster anyway, though it uses more memory.
- */
- sortptr = sortlist;
- for (cent = pershtab, ehtab = pershtab + pershsize; cent < ehtab; cent++)
- {
- for (lent = cent; lent != NULL; lent = lent->next)
- {
- if ((lent->flagfield & (USED | KEEP)) == (USED | KEEP))
- {
- *sortptr++ = lent;
- #ifdef CAPITALIZATION
- while (lent->flagfield & MOREVARIANTS)
- lent = lent->next;
- #endif
- }
- }
- }
- for (cent = hashtbl, ehtab = hashtbl + hashsize; cent < ehtab; cent++)
- {
- if ((cent->flagfield & (USED | KEEP)) == (USED | KEEP))
- {
- #ifdef CAPITALIZATION
- if (captype (cent->flagfield) != FOLLOWCASE
- && cent->word != NULL)
- #endif
- *sortptr++ = cent;
- }
- }
- /* Sort the list */
- qsort ((char *) sortlist, (unsigned) pdictsize,
- sizeof (sortlist[0]), pdictcmp);
- /* Write it out */
- for (sortptr = sortlist; --pdictsize >= 0; )
- toutent (dictf, *sortptr++, 1);
- free ((char *) sortlist);
- #endif
-
- newwords = 0;
-
- (void) fclose (dictf);
- }
-
- char * mymalloc (size)
- {
-
- return malloc ((unsigned) size);
- }
-
- void myfree (ptr)
- char * ptr;
- {
- if (hashstrings != NULL && ptr >= hashstrings
- && ptr <= hashstrings + hashheader.stringsize)
- return; /* Can't free stuff in hashstrings */
- free (ptr);
- }
-
- #ifdef REGEX_LOOKUP
-
- /* check the hashed dictionary for words matching the regex. return the */
- /* a matching string if found else return NULL */
- char * do_regex_lookup (expr, whence)
- char * expr; /* regular expression to use in the match */
- int whence; /* 0 = start at the beg with new regx, else */
- /* continue from cur point w/ old regex */
- {
- static struct dent * curent;
- static int curindex;
- static struct dent * curpersent;
- static int curpersindex;
- static char * cmp_expr;
- char dummy[INPUTWORDLEN + MAXAFFIXLEN];
- ichar_t * is;
-
- if (whence == 0)
- {
- is = strtosichar (expr, 0);
- upcase (is);
- expr = ichartosstr (is, 1);
- cmp_expr = REGCMP (expr);
- curent = hashtbl;
- curindex = 0;
- curpersent = pershtab;
- curpersindex = 0;
- }
-
- /* search the dictionary until the word is found or the words run out */
- for ( ; curindex < hashsize; curent++, curindex++)
- {
- if (curent->word != NULL
- && REGEX (cmp_expr, curent->word, dummy) != NULL)
- {
- curindex++;
- /* Everybody's gotta write a wierd expression once in a while! */
- return curent++->word;
- }
- }
- /* Try the personal dictionary too */
- for ( ; curpersindex < pershsize; curpersent++, curpersindex++)
- {
- if ((curpersent->flagfield & USED) != 0
- & curpersent->word != NULL
- && REGEX (cmp_expr, curpersent->word, dummy) != NULL)
- {
- curpersindex++;
- /* Everybody's gotta write a wierd expression once in a while! */
- return curpersent++->word;
- }
- }
- return NULL;
- }
-
- #endif /* REGEX_LOOKUP */
-