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)