allbery@ncoast.UUCP (05/31/87)
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# munchlist.X
# term.c
# tree.c
# version.h
# xgets.c
# This archive created: Sat May 30 17:13:43 1987
export PATH; PATH=/bin:$PATH
echo shar: extracting "'munchlist.X'" '(5932 characters)'
if test -f 'munchlist.X'
then
echo shar: will not over-write existing file "'munchlist.X'"
else
sed 's/^X //' << \SHAR_EOF > 'munchlist.X'
X : Use /bin/sh
X #
X # Given a list of words for ispell, generate a reduced list
X # in which all possible suffixes have been collapsed. The reduced
X # list will match the same list as the original.
X #
X # Usage:
X #
X # munchlist [ -d hashfile ] [ -e ] [ -w chars ] [ file ] ...
X #
X # Options:
X #
X # -d hashfile
X # Remove any words that are covered by 'hashfile'. The
X # default is the default ispell dictionary. The words
X # will be removed only if all suffixes are covered by
X # the hash file. A hashfile of /dev/null should be
X # specified when the main dictionary is being munched.
X # -e Economical algorithm. This will use much less temporary
X # disk space, at the expense of time. Useful with large files
X # (such as complete dictionaries).
X # -w Passed on to ispell (specify chars that are part of a word)
X #
X # The given input files are merged, then processed by 'ispell -c'
X # to generate possible suffix lists; these are then combined
X # and reduced. The final result is written to standard output.
X #
X # For portability to older systems, I have avoided getopt.
X #
X # Geoff Kuenning
X # 2/28/87
X #
X LIBDIR=!!LIBDIR!!
X COMBINE=${LIBDIR}/icombine
X EXPAND1=${LIBDIR}/isexp1.sed
X EXPAND2=${LIBDIR}/isexp2.sed
X EXPAND3=${LIBDIR}/isexp3.sed
X EXPAND4=${LIBDIR}/isexp4.sed
X TDIR=${TMPDIR:-/usr/tmp}
X TMP=${TDIR}/munch$$
X
X cheap=no
X dictopt=
X wchars=
X while [ $# != 0 ]
X do
X case "$1" in
X -d)
X case "$2" in
X /dev/null)
X dictopt=NONE
X ;;
X *)
X dictopt="-d $2"
X ;;
X esac
X shift
X ;;
X -e)
X cheap=yes
X ;;
X -w)
X wchars="-w $2"
X shift
X ;;
X *)
X break
X esac
X shift
X done
X trap "/bin/rm -f ${TMP}*; exit 1" 1 2 15
X #
X # Collect all the input and expand all the suffix options (four sed's),
X # and preserve (sorted) for later joining in ${TMP}a.
X #
X if [ $# -eq 0 ]
X then
X sed -f $EXPAND1 | sed -f $EXPAND2 \
X | sed -f $EXPAND3 | sed -f $EXPAND4 | sort -u > ${TMP}a
X else
X sed -f $EXPAND1 "$@" | sed -f $EXPAND2 \
X | sed -f $EXPAND3 | sed -f $EXPAND4 | sort -u > ${TMP}a
X fi
X #
X # Unless an explicitly null dictionary was specified, remove all
X # expanded words that are covered by the dictionary. This produces
X # the final list of expanded words that this dictionary must cover.
X # Leave the list in ${TMP}b.
X #
X if [ "X$dictopt" = "XNONE" ]
X then
X ln ${TMP}a ${TMP}b
X else
X ispell -l $dictopt -p /dev/null < ${TMP}a > ${TMP}b
X fi
X #
X # Munch the input to generate roots and suffixes (ispell -c). We are
X # only interested in words that have at least one suffix (egrep /); the
X # next step will pick up the rest. Some of the roots are illegal. We
X # use join to restrict the output to those root words that are found
X # in the original dictionary. In cheap mode, we re-sort this for
X # icombine's benefit, and then use icombine to scrunch them together.
X #
X # Note: one disadvantage of this pipeline is that for a large file,
X # the join and icombine may be sitting around for a long time while ispell
X # and sorts run. You can get rid of this by splitting the pipe, at
X # the expense of more temp file space.
X #
X if [ $cheap = yes ]
X then
X ispell $wchars -c -d /dev/null -p /dev/null < ${TMP}b \
X | egrep / | sort -u -t/ +0 -1 +1 \
X | join -t/ - ${TMP}a \
X | sort -u -t/ +0f -1 +0 -1 +1 | $COMBINE > ${TMP}c
X else
X ispell $wchars -c -d /dev/null -p /dev/null < ${TMP}b \
X | egrep / | sort -u -t/ +0 -1 +1 \
X | join -t/ - ${TMP}a > ${TMP}c
X fi
X #
X # There is now one slight problem: the suffix flags X, J, and Z
X # are simply the addition of an "S" to the suffixes N, G, and R,
X # respectively. This produces redundant entries in the output file;
X # for example, ABBREVIATE/N/X and ABBREVIATION/S. We must get rid
X # of the unnecessary duplicates. The candidates are those words that
X # have only an "S" flag (egrep). We strip off the "S" (sed), and
X # generate a list of roots that might have made these words (ispell -c).
X # Of these roots, we select those that have the N, G, or R flags,
X # replacing each with the plural equivalent X, J, or Z (sed -n).
X # Using join once again, we select those that have legal roots
X # and put them in ${TMP}d.
X #
X if [ $cheap = yes ]
X then
X egrep '^[^/]*/S$' ${TMP}c | sed 's@/S$@@' \
X | ispell $wchars -c -d /dev/null -p /dev/null \
X | sed -n -e '/\/N/s/N$/X/p' -e '/\/G/s/G$/J/p' -e '/\/R/s/R$/Z/p' \
X | sort -u -t/ +0 -1 +1 \
X | join -t/ - ${TMP}a \
X | sort -u -t/ +0f -1 +0 -1 +1 \
X | $COMBINE > ${TMP}d
X else
X egrep '^[^/]*/S$' ${TMP}c | sed 's@/S$@@' \
X | ispell $wchars -c -d /dev/null -p /dev/null \
X | sed -n -e '/\/N/s/N$/X/p' -e '/\/G/s/G$/J/p' -e '/\/R/s/R$/Z/p' \
X | sort -u -t/ +0 -1 +1 \
X | join -t/ - ${TMP}a > ${TMP}d
X fi
X /bin/rm -f ${TMP}a
X #
X # Now we have to eliminate the stuff covered by ${TMP}d from ${TMP}c.
X # First, we re-expand the suffixes we just made (four sed's), and let
X # ispell re-create the /S version (ispell -c). We select the /S versions
X # only (egrep), sort them (sort) for comm, and use comm to delete these
X # from ${TMP}c. The output of comm (i.e., the trimmed version of
X # ${TMP}c) is combined with our special-suffixes file ${TMP}d (sort again)
X # and reduced in size (icombine) to produce a final list of all words
X # that have at least one suffix.
X #
X sed -f $EXPAND1 ${TMP}d | sed -f $EXPAND2 | sed -f $EXPAND3 | sed -f $EXPAND4 \
X | ispell $wchars -c -d /dev/null -p /dev/null \
X | egrep '\/S$' | sort -u -t/ +0 -1 +1 | comm -13 - ${TMP}c \
X | sort -u -t/ +0f -1 +0 -1 +1 - ${TMP}d \
X | $COMBINE > ${TMP}e
X /bin/rm -f ${TMP}[cd]
X #
X # Now a slick trick. Use ispell to select those (root) words from the original
X # list (${TMP}b) that are not covered by the suffix list (${TMP}e). Then we
X # merge these with the suffix list, sort it, and use icombine to strip out
X # unnecessary capitalizations and produce the final output.
X #
X ispell $wchars -d /dev/null -p ${TMP}e -l < ${TMP}b \
X | sort -t/ +0f -1 +0 -1 +1 - ${TMP}e \
X | $COMBINE
X /bin/rm -f ${TMP}*
SHAR_EOF
chmod +x 'munchlist.X'
fi # end of overwriting check
echo shar: extracting "'term.c'" '(4678 characters)'
if test -f 'term.c'
then
echo shar: will not over-write existing file "'term.c'"
else
sed 's/^X //' << \SHAR_EOF > 'term.c'
X /* -*- Mode:Text -*- */
X
X /*
X * term.c - deal with termcap, and unix terminal mode settings
X *
X * Pace Willisson, 1983
X */
X
X #include <stdio.h>
X #ifdef USG
X #include <termio.h>
X #else
X #include <sgtty.h>
X #endif
X #include <signal.h>
X #include "config.h"
X #include "ispell.h"
X
X int putch();
X
X erase ()
X {
X if (cl)
X tputs(cl, li, putch);
X else {
X if (ho)
X tputs(ho, 100, putch);
X else if (cm)
X tputs(tgoto(cm, 0, 0), 100, putch);
X tputs(cd, li, putch);
X }
X }
X
X move (row, col)
X {
X tputs (tgoto (cm, col, row), 100, putch);
X }
X
X inverse ()
X {
X tputs (so, 10, putch);
X }
X
X normal ()
X {
X tputs (se, 10, putch);
X }
X
X backup ()
X {
X if (BC)
X tputs (BC, 1, putch);
X else
X putchar ('\b');
X }
X
X putch (c)
X {
X putchar (c);
X }
X
X #ifdef USG
X struct termio sbuf, osbuf;
X #else
X struct sgttyb sbuf, osbuf;
X struct ltchars ltc, oltc;
X #endif
X static termchanged = 0;
X static int (*oldint) ();
X static int (*oldterm) ();
X
X terminit ()
X {
X int done();
X
X #ifdef USG
X if (!isatty(0)) {
X fprintf (stderr, "Can't deal with non interactive use yet.\n");
X exit (1);
X }
X ioctl (0, TCGETA, &osbuf);
X termchanged = 1;
X
X sbuf = osbuf;
X sbuf.c_lflag &= ~(ECHO | ECHOK | ECHONL | ICANON);
X sbuf.c_oflag &= ~(OPOST);
X sbuf.c_iflag &= ~(INLCR | IGNCR | ICRNL);
X sbuf.c_cc[VMIN] = 1;
X sbuf.c_cc[VTIME] = 1;
X ioctl (0, TCSETAW, &sbuf);
X
X erasechar = osbuf.c_cc[VERASE];
X killchar = osbuf.c_cc[VKILL];
X
X #else
X int tpgrp;
X int onstop();
X extern short ospeed;
X
X retry:
X #ifdef SIGTSTP
X sigsetmask(1<<(SIGTSTP-1) | 1<<(SIGTTIN-1) | 1<<(SIGTTOU-1));
X #endif
X #ifdef TIOCGPGRP
X if (ioctl(0, TIOCGPGRP, &tpgrp) != 0) {
X fprintf (stderr, "Can't deal with non interactive use yet.\n");
X exit (1);
X }
X #endif
X #ifdef SIGTSTP
X if (tpgrp != getpgrp(0)) { /* not in foreground */
X sigsetmask(1<<(SIGTSTP-1) | 1<<(SIGTTIN-1));
X signal(SIGTTOU, SIG_DFL);
X kill(0, SIGTTOU);
X /* job stops here waiting for SIGCONT */
X goto retry;
X }
X #endif
X
X ioctl (0, TIOCGETP, &osbuf);
X ioctl (0, TIOCGLTC, &oltc);
X termchanged = 1;
X
X sbuf = osbuf;
X sbuf.sg_flags &= ~ECHO;
X sbuf.sg_flags |= TERM_MODE;
X ioctl (0, TIOCSETP, &sbuf);
X
X erasechar = sbuf.sg_erase;
X killchar = sbuf.sg_kill;
X ospeed = sbuf.sg_ospeed;
X
X ltc = oltc;
X ltc.t_suspc = -1;
X ioctl (0, TIOCSLTC, <c);
X
X if ((oldint = signal (SIGINT, SIG_IGN)) != SIG_IGN)
X signal (SIGINT, done);
X if ((oldterm = signal (SIGTERM, SIG_IGN)) != SIG_IGN)
X signal (SIGTERM, done);
X
X #ifdef SIGTTIN
X sigsetmask(0);
X if (signal (SIGTTIN, SIG_IGN) != SIG_IGN)
X signal(SIGTTIN, onstop);
X if (signal (SIGTTOU, SIG_IGN) != SIG_IGN)
X signal(SIGTTOU, onstop);
X if (signal (SIGTSTP, SIG_IGN) != SIG_IGN)
X signal(SIGTSTP, onstop);
X #endif
X #endif
X
X tgetent(termcap, getenv("TERM"));
X termptr = termstr;
X bs = tgetflag("bs");
X BC = tgetstr("bc", &termptr);
X UP = tgetstr("up", &termptr);
X cd = tgetstr("cd", &termptr);
X ce = tgetstr("ce", &termptr);
X cl = tgetstr("cl", &termptr);
X cm = tgetstr("cm", &termptr);
X dc = tgetstr("dc", &termptr);
X dl = tgetstr("dl", &termptr);
X dm = tgetstr("dm", &termptr);
X ed = tgetstr("ed", &termptr);
X ei = tgetstr("ei", &termptr);
X ho = tgetstr("ho", &termptr);
X ic = tgetstr("ic", &termptr);
X il = tgetstr("al", &termptr);
X im = tgetstr("im", &termptr);
X ip = tgetstr("ip", &termptr);
X nd = tgetstr("nd", &termptr);
X vb = tgetstr("vb", &termptr);
X so = tgetstr("so", &termptr); /* inverse video on */
X se = tgetstr("se", &termptr); /* inverse video off */
X co = tgetnum("co");
X li = tgetnum("li");
X
X }
X
X done ()
X {
X unlink (tempfile);
X if (termchanged)
X #ifdef USG
X ioctl (0, TCSETAW, &osbuf);
X #else
X ioctl (0, TIOCSETP, &osbuf);
X ioctl (0, TIOCSLTC, &oltc);
X #endif
X exit (0);
X }
X
X #ifndef USG
X onstop(signo)
X int signo;
X {
X ioctl (0, TIOCSETP, &osbuf);
X ioctl (0, TIOCSLTC, &oltc);
X signal(signo, SIG_DFL);
X sigsetmask(sigblock(0) & ~(1 << (signo-1)));
X kill(0, signo);
X /* stop here until continued */
X signal(signo, onstop);
X ioctl (0, TIOCSETP, &sbuf);
X ioctl (0, TIOCSLTC, <c);
X }
X
X stop ()
X {
X #ifdef SIGTSTP
X onstop (SIGTSTP);
X #endif
X ;
X }
X #endif
X
X shellescape (buf)
X char *buf;
X {
X
X #ifdef USG
X ioctl (0, TCSETAW, &osbuf);
X #else
X ioctl (0, TIOCSETP, &osbuf);
X ioctl (0, TIOCSLTC, &oltc);
X #endif
X signal (SIGINT, oldint);
X signal (SIGTERM, oldterm);
X #ifdef SIGTTIN
X signal(SIGTTIN, SIG_DFL);
X signal(SIGTTOU, SIG_DFL);
X signal(SIGTSTP, SIG_DFL);
X #endif
X
X system (buf);
X
X if (signal (SIGINT, SIG_IGN) != SIG_IGN)
X signal (SIGINT, done);
X if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
X signal (SIGTERM, done);
X
X #ifdef SIGTTIN
X signal(SIGTTIN, oldttin);
X signal(SIGTTOU, oldttou);
X signal(SIGTSTP, oldtstp);
X #endif
X
X #ifdef USG
X ioctl (0, TCSETAW, &sbuf);
X #else
X ioctl (0, TIOCSETP, &sbuf);
X ioctl (0, TIOCSLTC, <c);
X #endif
X printf ("\n-- Type space to continue --");
X fflush (stdout);
X getchar ();
X }
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'tree.c'" '(16179 characters)'
if test -f 'tree.c'
then
echo shar: will not over-write existing file "'tree.c'"
else
sed 's/^X //' << \SHAR_EOF > 'tree.c'
X /* -*- Mode:Text -*- */
X
X /*
X * tree.c - a hash style dictionary for user's personal words
X *
X * Pace Willisson, 1983
X * Hash support added by Geoff Kuenning, 1987
X */
X
X #include <stdio.h>
X #include <ctype.h>
X #include <sys/param.h>
X #include "config.h"
X #include "ispell.h"
X
X char *getenv();
X struct dent *lookup();
X char *upcase();
X
X static int cantexpand = 0; /* NZ if an expansion fails */
X static struct dent *htab = NULL; /* Hash table for our stuff */
X static int hsize = 0; /* Space available in hash table */
X static int hcount = 0; /* Number of items in hash table */
X
X /*
X * Hash table sizes. Prime is probably a good idea, though in truth I
X * whipped the algorithm up on the spot rather than looking it up, so
X * who knows what's really best? If we overflow the table, we just
X * use a double-and-add-1 algorithm.
X *
X * The strange pattern in the table is because this table is sometimes
X * used with huge dictionaries, and we want to get the table bigger fast.
X * 23003 just happens to be such that the original dict.191 will fill
X * the table to just under 70%. 31469 is similarly selected for dict.191
X * combined with /usr/dict/words. The other numbers are on 10000-word
X * intervals starting at 30000. (The table is still valid if MAXPCT
X * is changed, but the dictionary sizes will no longer fall on neat
X * boundaries).
X */
X static int goodsizes[] = {
X 53, 223, 907,
X #if ((BIG_DICT * 100) / MAXPCT) <= 23003
X 23003, /* ~16000 words */
X #endif
X #if ((BIG_DICT * 100) / MAXPCT) <= 31469
X 31469, /* ~22000 words */
X #endif
X #if ((BIG_DICT * 100) / MAXPCT) <= 42859
X 42859, /* ~30000 words */
X #endif
X #if ((BIG_DICT * 100) / MAXPCT) <= 57143
X 57143, /* ~40000 words */
X #endif
X 71429 /* ~50000 words */
X };
X
X struct dent *treeinsert();
X struct dent *tinsert();
X struct dent *treelookup();
X char *upcase ();
X char *lowcase ();
X
X static char personaldict[MAXPATHLEN];
X static FILE *dictf;
X static newwords = 0;
X
X extern char *index ();
X extern char *calloc ();
X extern char *malloc ();
X extern char *realloc ();
X
X extern struct dent *hashtbl;
X extern int hashsize;
X
X treeinit (p)
X char *p;
X {
X register char *h;
X char *orig;
X char buf[BUFSIZ];
X register struct dent *dp;
X
X /*
X ** if p exists and begins with '/' we don't really need HOME,
X ** but it's not very likely that HOME isn't set anyway.
X */
X orig = p;
X if (p == NULL)
X p = getenv (PDICTVAR);
X if ((h = getenv ("HOME")) == NULL)
X return;
X
X if (p == NULL)
X sprintf(personaldict,"%s/%s",h,DEFPDICT);
X else {
X if (*p == '/')
X strcpy(personaldict,p);
X else {
X /*
X ** The user gave us a relative pathname. How we
X ** interpret it depends on how it was given:
X **
X ** -p switch: as-is first, then $HOME/name
X ** PDICTVAR: $HOME/name first, then as-is
X **/
X if (orig == NULL)
X sprintf (personaldict, "%s/%s", h, p);
X else /* -p switch */
X strcpy (personaldict, p);
X }
X }
X
X if ((dictf = fopen (personaldict, "r")) == NULL) {
X /* The file doesn't exist. */
X if (p != NULL) {
X /* If pathname is relative, try another place */
X if (*p != '/') {
X if (orig == NULL)
X strcpy (personaldict, p);
X else /* -p switch */
X sprintf (personaldict, "%s/%s", h, p);
X dictf = fopen (personaldict, "r");
X }
X if (dictf == NULL) {
X (void) fprintf (stderr, "Couldn't open ");
X perror (p);
X if (*p != '/') {
X /*
X ** Restore the preferred default, so
X ** that output will go th the right
X ** place.
X */
X if (orig == NULL)
X sprintf (personaldict,
X "%s/%s", h, p);
X else /* -p switch */
X strcpy (personaldict, p);
X }
X }
X }
X /* If the name wasn't specified explicitly, we don't object */
X return;
X }
X
X while (fgets (buf, sizeof buf, dictf) != NULL) {
X int len = strlen (buf) - 1;
X
X if (buf [ len ] == '\n')
X buf [ len-- ] = '\0';
X if ((h = index (buf, '/')) != NULL)
X *h++ = '\0';
X dp = treeinsert (buf, 1);
X if (h != NULL) {
X while (*h != '\0' && *h != '\n') {
X switch (*h++) {
X case 'D':
X case 'd':
X dp->d_flag = 1;
X break;
X case 'G':
X case 'g':
X dp->g_flag = 1;
X break;
X case 'H':
X case 'h':
X dp->h_flag = 1;
X break;
X case 'J':
X case 'j':
X dp->j_flag = 1;
X break;
X case 'M':
X case 'm':
X dp->m_flag = 1;
X break;
X case 'N':
X case 'n':
X dp->n_flag = 1;
X break;
X case 'P':
X case 'p':
X dp->p_flag = 1;
X break;
X case 'R':
X case 'r':
X dp->r_flag = 1;
X break;
X case 'S':
X case 's':
X dp->s_flag = 1;
X break;
X case 'T':
X case 't':
X dp->t_flag = 1;
X break;
X case 'V':
X case 'v':
X dp->v_flag = 1;
X break;
X case 'X':
X case 'x':
X dp->x_flag = 1;
X break;
X case 'Y':
X case 'y':
X dp->y_flag = 1;
X break;
X case 'Z':
X case 'z':
X dp->z_flag = 1;
X break;
X default:
X fprintf (stderr,
X "Illegal flag in personal dictionary - %c (word %s)\n",
X h[-1], buf);
X break;
X }
X /* Accept old-format dicts with extra slashes */
X if (*h == '/')
X h++;
X }
X }
X }
X
X fclose (dictf);
X
X newwords = 0;
X
X if (!lflag && !aflag && access (personaldict, 2) < 0)
X fprintf (stderr,
X "Warning: Cannot update personal dictionary (%s)\r\n",
X personaldict);
X }
X
X struct dent *
X treeinsert (word, keep)
X char *word;
X {
X register int i;
X register struct dent *dp;
X struct dent *olddp;
X struct dent *oldhtab;
X int oldhsize;
X char nword[BUFSIZ];
X #ifdef CAPITALIZE
X register char *cp;
X char *saveword;
X int capspace;
X #endif
X
X strcpy (nword, word);
X upcase (nword);
X if ((dp = lookup (nword, strlen (nword), 0)) != NULL)
X dp->keep = keep;
X /*
X * Expand hash table when it is MAXPCT % full.
X */
X else if (!cantexpand && (hcount * 100) / MAXPCT >= hsize) {
X oldhsize = hsize;
X oldhtab = htab;
X for (i = 0; i < sizeof goodsizes / sizeof (goodsizes[0]); i++)
X if (goodsizes[i] > hsize)
X break;
X if (i >= sizeof goodsizes / sizeof goodsizes[0])
X hsize += hsize + 1;
X else
X hsize = goodsizes[i];
X htab = (struct dent *) calloc (hsize, sizeof (struct dent));
X if (htab == NULL) {
X (void) fprintf (stderr,
X "Ran out of space for personal dictionary\n");
X /*
X * Try to continue anyway, since our overflow
X * algorithm can handle an overfull (100%+) table,
X * and the malloc very likely failed because we
X * already have such a huge table, so small mallocs
X * for overflow entries will still work.
X */
X if (oldhtab == NULL)
X exit (1); /* No old table, can't go on */
X (void) fprintf (stderr,
X "Continuing anyway (with reduced performance).\n");
X cantexpand = 1; /* Suppress further messages */
X hsize = oldhsize; /* Put this back how the were */
X htab = oldhtab; /* ... */
X newwords = 1; /* And pretend it worked */
X return tinsert (nword, (struct dent *) NULL, keep);
X }
X /*
X * Re-insert old entries into new table
X */
X for (i = 0; i < oldhsize; i++) {
X dp = &oldhtab[i];
X if (oldhtab[i].used) {
X tinsert ((char *) NULL, dp, 0);
X dp = dp->next;
X while (dp != NULL) {
X tinsert ((char *) NULL, dp, 0);
X olddp = dp;
X dp = dp->next;
X free ((char *) olddp);
X }
X }
X }
X if (oldhtab != NULL)
X free ((char *) oldhtab);
X dp = NULL; /* This will force the insert below */
X }
X newwords |= keep;
X if (dp == NULL)
X dp = tinsert (nword, (struct dent *) NULL, keep);
X #ifdef CAPITALIZE
X if (dp == NULL)
X return NULL;
X /*
X ** Figure out the capitalization rules from the
X ** capitalization of the sample entry. If the sample is
X ** all caps, we don't change the existing flags, since
X ** all-caps gives us no information. Tinsert initializes
X ** new entries with "allcaps" set, so if the word is truly
X ** required to appear in capitals, the correct result
X ** will be achieved.
X */
X for (cp = word; *cp; cp++) {
X if (mylower (*cp))
X break;
X }
X if (*cp) {
X /*
X ** Sample entry has at least some lowercase. See if
X ** the case is mixed.
X */
X for (cp = word; *cp; cp++) {
X if (myupper (*cp))
X break;
X }
X if (*cp == '\0' && !dp->followcase) {
X /*
X ** Sample entry is all lowercase, and word is not
X ** followcase. Clear all of the capitalization flags.
X */
X dp->allcaps = 0;
X dp->capitalize = 0;
X if (keep) {
X dp->k_allcaps = 0;
X dp->k_capitalize = 0;
X dp->k_followcase = 0;
X }
X }
X else {
X /*
X ** The sample entry is mixed case (or all-lower and the
X ** entry is already followcase). If it's simply
X ** capitalized, set the capitalize flag and that's that.
X */
X for (cp = word + 1; *cp && !myupper (*cp); )
X cp++;
X if (*cp == 0 && myupper (*word)) {
X dp->allcaps = 0;
X dp->capitalize = 1;
X if (keep) {
X dp->k_allcaps = 0;
X dp->k_capitalize = 1;
X }
X }
X else {
X /*
X ** The sample entry is followcase. Make the
X ** dictionary entry followcase if necessary.
X */
X if (!dp->followcase) {
X dp->followcase = 1;
X if (keep)
X dp->k_followcase = 1;
X capspace = 2 * (strlen (dp->word) + 2);
X if (dp->word >= hashstrings
X && dp->word <=
X hashstrings
X + hashheader.stringsize) {
X cp = dp->word;
X dp->word = malloc (capspace);
X if (dp->word)
X strcpy (dp->word, cp);
X }
X else
X dp->word = realloc (dp->word,
X capspace);
X if (dp->word == NULL) {
X fprintf (stderr,
X "Ran out of space for personal dictionary\n");
X exit (1);
X }
X cp = dp->word + strlen (dp->word) + 1;
X if (dp->capitalize || dp->allcaps)
X *cp++ = 0;
X else {
X *cp++ = 1;
X strcpy (cp + 1, dp->word);
X lowcase (cp + 1);
X }
X *cp = dp->keep ? '+' : '-';
X }
X dp->allcaps = 0;
X if (keep)
X dp->k_allcaps = 0;
X cp = dp->word + strlen (dp->word) + 1;
X /* Add a new capitalization */
X (*cp)++;
X capspace = (cp - dp->word + 1)
X * ((*cp & 0xFF) + 1);
X if (dp->word >= hashstrings
X && dp->word <=
X hashstrings + hashheader.stringsize) {
X saveword = dp->word;
X dp->word = malloc (capspace);
X if (dp->word) {
X cp = dp->word;
X while (--capspace >= 0)
X *cp++ = *saveword++;
X }
X }
X else
X dp->word = realloc (dp->word, capspace);
X if (dp->word == NULL) {
X fprintf (stderr,
X "Ran out of space for personal dictionary\n");
X exit (1);
X }
X cp = dp->word + strlen (dp->word) + 1;
X cp +=
X ((*cp & 0xFF) - 1) * (cp - dp->word + 1) + 1;
X *cp++ = keep ? '+' : '-';
X strcpy (cp, word);
X }
X }
X }
X #endif
X return dp;
X }
X
X static
X struct dent *
X tinsert (word, proto, keep)
X char *word; /* One of word/proto must be null */
X struct dent *proto;
X {
X register int hcode;
X register struct dent *hp; /* Next trial entry in hash table */
X register struct dent *php; /* Previous value of hp, for chaining */
X register char *cp;
X
X if (word == NULL)
X word = proto->word;
X hcode = hash (word, strlen (word), hsize);
X php = NULL;
X hp = &htab[hcode];
X if (hp->used) {
X while (hp != NULL) {
X if (strcmp (word, hp->word) == 0) {
X if (keep)
X hp->keep = 1;
X return hp;
X }
X php = hp;
X hp = hp->next;
X }
X hp = (struct dent *) calloc (1, sizeof (struct dent));
X if (hp == NULL) {
X (void) fprintf (stderr,
X "Ran out of space for personal dictionary\n");
X exit (1);
X }
X }
X if (proto != NULL) {
X *hp = *proto;
X if (php != NULL)
X php->next = hp;
X hp->next = NULL;
X return &htab[hcode];
X } else {
X if (php != NULL)
X php->next = hp;
X hp->word = (char *) malloc (strlen (word) + 1);
X if (hp->word == NULL) {
X (void) fprintf (stderr,
X "Ran out of space for personal dictionary\n");
X exit (1);
X }
X strcpy (hp->word, word);
X hp->used = 1;
X hp->next = NULL;
X hp->d_flag = 0;
X hp->g_flag = 0;
X hp->h_flag = 0;
X hp->j_flag = 0;
X hp->m_flag = 0;
X hp->n_flag = 0;
X hp->p_flag = 0;
X hp->r_flag = 0;
X hp->s_flag = 0;
X hp->t_flag = 0;
X hp->v_flag = 0;
X hp->x_flag = 0;
X hp->y_flag = 0;
X hp->z_flag = 0;
X #ifdef CAPITALIZE
X hp->allcaps = 1; /* Assume word is all-caps */
X hp->k_allcaps = 1;
X hp->capitalize = 0;
X hp->k_capitalize = 0;
X hp->followcase = 0;
X hp->k_followcase = 0;
X #endif
X hp->keep = keep;
X hcount++;
X return (hp);
X }
X }
X
X struct dent *
X treelookup (word)
X char *word;
X {
X register int hcode;
X register struct dent *hp;
X char nword[BUFSIZ];
X
X if (hsize <= 0)
X return NULL;
X strcpy (nword, word);
X hcode = hash (nword, strlen (nword), hsize);
X hp = &htab[hcode];
X while (hp != NULL && hp->used) {
X if (strcmp (nword, hp->word) == 0)
X break;
X hp = hp->next;
X }
X if (hp != NULL && hp->used)
X return hp;
X else
X return NULL;
X }
X
X treeoutput ()
X {
X register struct dent *cent; /* Current entry */
X register struct dent *lent; /* Linked entry */
X #ifdef SORTPERSONAL
X register struct dent *lowent; /* Alphabetically lowest entry */
X struct dent *firstent; /* First entry to be kept */
X #endif
X if (newwords == 0)
X return;
X
X if ((dictf = fopen (personaldict, "w")) == NULL) {
X fprintf (stderr, "Can't create %s\r\n", personaldict);
X return;
X }
X
X #ifdef SORTPERSONAL
X if (hcount >= SORTPERSONAL) {
X #endif
X for (cent = htab; cent - htab < hsize; cent++) {
X for (lent = cent; lent != NULL; lent = lent->next) {
X if (lent->used && lent->keep)
X toutent (lent);
X }
X }
X for (cent = hashtbl, lent = hashtbl + hashsize;
X cent < lent;
X cent++) {
X if (cent->used && cent->keep)
X toutent (cent);
X }
X #ifdef SORTPERSONAL
X return;
X }
X /*
X ** Produce dictionary in sorted order. We use a selection sort,
X ** which is moderately inefficient, but easy to do in our hash table.
X ** We start by linking all "keep" entries together to save time.
X */
X for (lowent = NULL, cent = hashtbl, lent = hashtbl + hashsize;
X cent < lent;
X cent++) {
X if (cent->keep && cent->used) {
X cent->next = lowent;
X lowent = cent;
X }
X }
X firstent = lowent;
X for (cent = htab; cent - htab < hsize; cent++) {
X for (lent = cent; lent != NULL; lent = lowent) {
X lowent = lent->next;
X if (lent->keep && lent->used) {
X lent->next = firstent;
X firstent = lent;
X }
X }
X }
X /* Now do the sort. */
X while (1) {
X lowent = NULL;
X for (cent = firstent; cent != NULL; cent = cent->next) {
X if (cent->used && cent->keep) {
X if (lowent != NULL) {
X if (casecmp (cent->word,
X lowent->word) < 0)
X lowent = cent;
X }
X else
X lowent = cent;
X }
X }
X if (lowent == NULL)
X break;
X else {
X toutent (lowent);
X lowent->used = 0;
X }
X }
X #endif
X
X newwords = 0;
X
X fclose (dictf);
X }
X
X static int hasslash;
X
X static
X toutent (cent)
X register struct dent *cent;
X {
X register char *cp;
X int len;
X register int wcount;
X
X if (cent->k_followcase) {
X if (cent->k_capitalize) {
X lowcase (cent->word);
X if (mylower (cent->word[0]))
X cent->word[0] = toupper (cent->word[0]);
X toutword (cent->word, cent);
X }
X len = strlen (cent->word) + 1;
X cp = cent->word + len;
X wcount = *cp++ & 0xFF;
X while (--wcount >= 0) {
X if (*cp++ == '+')
X toutword (cp, cent);
X cp += len;
X }
X }
X else {
X if (!cent->k_allcaps)
X lowcase (cent->word);
X if (cent->k_capitalize && mylower (cent->word[0]))
X cent->word[0] = toupper (cent->word[0]);
X toutword (cent->word, cent);
X }
X }
X
X static
X toutword (word, cent)
X char *word;
X register struct dent *cent;
X {
X hasslash = 0;
X fprintf (dictf, "%s", word);
X if (cent->d_flag)
X flagout ('D');
X if (cent->g_flag)
X flagout ('G');
X if (cent->h_flag)
X flagout ('H');
X if (cent->j_flag)
X flagout ('J');
X if (cent->m_flag)
X flagout ('M');
X if (cent->n_flag)
X flagout ('N');
X if (cent->p_flag)
X flagout ('P');
X if (cent->r_flag)
X flagout ('R');
X if (cent->s_flag)
X flagout ('S');
X if (cent->t_flag)
X flagout ('T');
X if (cent->v_flag)
X flagout ('V');
X if (cent->x_flag)
X flagout ('X');
X if (cent->y_flag)
X flagout ('Y');
X if (cent->z_flag)
X flagout ('Z');
X fprintf (dictf, "\n");
X }
X
X static
X flagout (flag)
X {
X if (!hasslash)
X putc ('/', dictf);
X hasslash = 1;
X putc (flag, dictf);
X }
X
X char *
X upcase (s)
X register char *s;
X {
X register char *os = s;
X
X while (*s) {
X if (mylower (*s))
X *s = toupper (*s);
X s++;
X }
X return (os);
X }
X
X char *
X lowcase (s)
X register char *s;
X {
X register char *os = s;
X
X while (*s) {
X if (myupper (*s))
X *s = tolower (*s);
X s++;
X }
X return (os);
X }
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'version.h'" '(81 characters)'
if test -f 'version.h'
then
echo shar: will not over-write existing file "'version.h'"
else
sed 's/^X //' << \SHAR_EOF > 'version.h'
X static char Version_ID[] =
X "@(#) Ispell Version 2.0, May 1987 Beta posting";
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'xgets.c'" '(1775 characters)'
if test -f 'xgets.c'
then
echo shar: will not over-write existing file "'xgets.c'"
else
sed 's/^X //' << \SHAR_EOF > 'xgets.c'
X
X #include "config.h"
X #include <stdio.h>
X
X #ifndef MAXINCLUDEFILES
X #define MAXINCLUDEFILES 1 /* maximum number of new files in stack */
X #endif
X
X /*
X * xgets () acts just like gets () except that if a line matches
X * "&Include_File&<something>" xgets () will start reading from the
X * file <something>.
X *
X * Andrew Vignaux -- andrew@vuwcomp Fri May 8 16:40:23 NZST 1987
X * modified
X * Mark Davies -- mark@vuwcomp Mon May 11 22:38:10 NZST 1987
X */
X
X extern int incfileflag; /* whether xgets() acts exactly like gets() */
X
X char *
X xgets (str)
X char str [];
X {
X #if MAXINCLUDFILES == 0
X return gets (str);
X #else
X static char * Include_File = DEFINCSTR;
X static int Include_Len = 0, strlen ();
X static FILE * F [MAXINCLUDEFILES+1], ** current_F = F;
X char * s = str;
X int c;
X
X /* read the environment variable if we havent already */
X if (Include_Len == 0) {
X char * env_variable, * getenv ();
X
X if ((env_variable = getenv (INCSTRVAR) != NULL)
X Include_File = env_variable;
X Include_Len = strlen (Include_File);
X
X /* initialise the file stack */
X *current_F = stdin;
X }
X
X while (1) {
X if ((c = getc (*current_F)) != EOF && c != '\n') {
X *s++ = c;
X continue;
X }
X *s = '\0'; /* end of line */
X if (c == EOF)
X if (current_F == F) { /* if end of standard input */
X if (s == str) return (NULL);
X } else {
X (void) fclose (*(current_F--));
X if (s == str) continue;
X }
X
X if (incfileflag != 0 && strncmp (str, Include_File, Include_Len) == 0) {
X char * file_name = str + Include_Len;
X if (current_F - F < MAX_FILES && strlen (file_name) > 0) {
X FILE * f;
X if (f = fopen (file_name, "r"))
X *(++current_F) = f;
X }
X s = str;
X continue;
X }
X break;
X }
X
X return (str);
X #endif
X }
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0
--
Brandon S. Allbery {decvax,cbatt,cbosgd}!cwruecmp!ncoast!allbery
Tridelta Industries {ames,mit-eddie,talcott}!necntc!ncoast!allbery
7350 Corporate Blvd. necntc!ncoast!allbery@harvard.HARVARD.EDU
Mentor, OH 44060 +01 216 255 1080 (also eddie.MIT.EDU)