[net.sources] ispell repost

geoff@desint.UUCP (03/14/87)

: This is a definitive integrated/enhanced ispell (except the dictionary).
: Everybody else's work has been installed, and many other bugs have
: been fixed.  I have also written a spelling-list suffix muncher.
: See the first file in the shar (UPDATE) for more details.
:
: Also, don't forget to pick up my three companion postings of dictionary
: diff's in net.sources.bugs.
:
:	Geoff Kuenning
:	{hplabs,ihnp4}!trwrb!desint!geoff
:
#! /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:
#	UPDATE
#	Makefile
#	ispell.man
#	README
#	WISHES
#	expand.awk
#	expand1.sed
#	expand2.sed
#	munchlist.sh
#	ispell.el
#	buildhash.c
# This archive created: Sat Mar 14 00:58:44 1987
export PATH; PATH=/bin:$PATH
echo shar: extracting "'UPDATE'" '(5252 characters)'
if test -f 'UPDATE'
then
	echo shar: will not over-write existing file "'UPDATE'"
else
sed 's/^X //' << \SHAR_EOF > 'UPDATE'
X 		Ispell enhancements - 3/13/87
X 
X (See three companion postings in net.sources.bugs).
X 
X Here are the enhancements to ispell that I mentioned a couple of days ago.
X Because of the number of changes, several of the context diff's are bigger
X than the original files.  In addition, many people have gotten confused
X about versions, since enhancements/fixes have been made by six different
X people, counting myself (for the list, see the end of ispell.man).  I
X have integrated all of these fixes and enhancements in one place.
X 
X For these reasons, I have decided to repost all of the sources for ispell,
X with one exception -- the dictionary.  (A couple of small files, such
X as ispell.el, are unchanged, but I decided to repost them any for
X completeness.  If you didn't have ispell before, you now need only the
X dictionary).
X 
X The dictionary is a special case:  if you think about it, even ordinary
X diff's will always work with "patch" on that each-line-is-unique file.
X An out-of-place insertion can be corrected by sorting the dictionary
X after patching (something that is done anyway as a side effect of the
X new "munchlist" script).  Because of this, I have decided not to repost
X the sizable dictionary.  In the process of testing this code, it occurred
X to me to run dict.191 through UNIX "spell";  the results of that are
X given in three companion postings in net.sources.bugs, which seemed
X like a more appropriate place for the diffs.  (The postings are not
X divided because of their size;  see comments in the postings for my
X reasons).
X 
X Now, here's what I've done:
X 
X In ispell itself:
X 
X 	- The personal dictionary is now hashed, just like the main one, and
X 	  supports suffixes just like the main one.  (It's not actually
X 	  integrated with the main one, because expanding the main one
X 	  is inefficient and poses a minor but troublesome technical
X 	  problem).  A personal dictionary of 28000+ words can be read in
X 	  within a few minutes (hey, nobody's perfect -- whatcha doing
X 	  with such a big dictionary anyway? :-).
X 	- New option "-c" is used by the new munchlist script to generate
X 	  suggested root/suffix combinations.
X 	- The -d option can now specify /dev/null, if you want to use
X 	  only your personal dictionary (this also saves startup time
X 	  with -c, and is used by the "munchlist" script, which is why
X 	  I put it in).
X 	- The -p option is now more flexible about its handling of pathnames.
X 	  An absolute pathname is always interpreted literally.  A
X 	  relative pathname from WORDLIST is looked up in $HOME first,
X 	  then in the current directory.  The -p option behaves in the
X 	  reverse fashion:  current directory first, then $HOME.  This
X 	  behavior seems more intuitive to me;  I'd be interested in
X 	  opinions of others if you don't find it intuitive.
X 	- Perhaps most important, I have completely overhauled the logic
X 	  in good.c, so that it (I think) matches what the README file
X 	  says it should, no more, no less.  The code has been extensively
X 	  tested, notably by interaction with the new expansion scripts;
X 	  nevertheless because of the extent of the changes and the
X 	  nature of the logic, I'd suggest a bit of suspicion for a while.
X 	  A technique we've found useful here is to do your normal work
X 	  with ispell, and then do a final check with UNIX spell or some
X 	  other slow, inconvenient program to make sure ispell didn't
X 	  screw up.
X 
X New scripts:
X 
X 	- expand.awk:  an obsolete (but correct) awk script that does
X 	  the same thing as expand[12].sed, except slower.  The awk
X 	  script is also much easier to understand than the sed scripts.
X 	  Superseded by the sed scripts, except for very short input.
X 	- expand[12].sed:  the sed pipe
X 
X 	    "sed -f expand1.sed $file | sed -f expand2.sed"
X 
X 	  where "$file" is a raw dictionary file with suffixes
X 	  (e.g., dict.191), generates a list of each root alone, plus
X 	  the root expanded with each possible suffix (e.g.,
X 	  "BOTH/R/Z" produces "BOTH", "BOTHER", and "BOTHERS").  The
X 	  output should usually be sorted with the -u switch before
X 	  further processing.  These scripts are used by 'munchlist';
X 	  they are also useful for (a) checking an ispell dictionary
X 	  with some other spell-checking program and (b) figuring
X 	  out what a particular suffix does to a certain word without
X 	  reading the README file.
X 	- munchlist.sh:  a slow, but effective, shell script that takes
X 	  lists of expanded or unexpanded words as input and reduces
X 	  them to a (usually smaller) list of roots and suffixes.  The
X 	  result is written to standard output.  I think the documentation
X 	  forgot to mention the input must be one word per line.  I
X 	  have successfully used this script to combine dict.191 with
X 	  /usr/dict/words;  it's also useful (and a lot faster) on
X 	  private dictionaries.  For private dictionaries. it will also
X 	  remove any word that has since been added to the main dictionary.
X 
X Oh yes, I almost forgot:  the original documentation didn't mention
X that ispell is a long-name program.  If your "File:" display on the
X top line actually contains the misspelled word, you have long-name problems.
X My fixes don't address long names, because I finally have a way to
X compile long-name programs, thanks to "hash8".
X 
X 	Geoff Kuenning
X 	geoff@ITcorp.COM
X 	...!trwrb!desint!geoff
SHAR_EOF
if test 5252 -ne "`wc -c < 'UPDATE'`"
then
	echo shar: error transmitting "'UPDATE'" '(should have been 5252 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(1198 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X //' << \SHAR_EOF > 'Makefile'
X # -*- Mode: Text -*-
X 
X # Look over config.h before building.
X #
X # LIBDIR, DEFHASH, DEFDICT should match definitions in config.h.
X #
X # The ifdef NO8BIT may be used if 8 bit extended text characters
X # cause problems, or you simply don't wish to allow the feature.
X #
X # the argument syntax for buildhash to make alternate dictionary files
X # is simply:
X #
X #   buildhash <infile> <outfile>
X 
X CFLAGS = -O
X BINDIR = /usr/local/bin
X LIBDIR = /usr/local/lib
X DEFHASH = ispell.hash
X DEFDICT = dict.191
X 
X # TERMLIB = -lcurses
X TERMLIB = -ltermlib
X all: buildhash ispell $(DEFHASH)
X 
X ispell.hash: buildhash $(DEFDICT)
X 	buildhash
X 
X install: buildhash ispell $(DEFHASH)
X 	cp ispell ${BINDIR}/ispell
X 	cp munchlist.sh $(BINDIR)/munchlist
X 	cp ispell.hash ${LIBDIR}/${DEFHASH}
X 	cp expand1.sed expand2.sed $(LIBDIR)
X 	chmod 755 ${BINDIR}/ispell $(BINDIR)/munchlist
X 	chmod 644 ${LIBDIR}/$(DEFHASH) $(LIBDIR)/expand1.sed \
X 	  $(LIBDIR)/expand2.sed
X 
X buildhash: buildhash.o hash.o
X 	cc -o buildhash buildhash.o hash.o
X 
X ispell: ispell.o term.o good.o lookup.o hash.o tree.o
X 	cc $(CFLAGS) -o ispell ispell.o term.o good.o lookup.o \
X 		hash.o tree.o $(TERMLIB)
X 
X clean:
X 	rm -f *.o buildhash ispell core a.out mon.out hash.out \
X 		*.stat *.cnt
SHAR_EOF
if test 1198 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 1198 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ispell.man'" '(8455 characters)'
if test -f 'ispell.man'
then
	echo shar: will not over-write existing file "'ispell.man'"
else
sed 's/^X //' << \SHAR_EOF > 'ispell.man'
X .\" -*- Mode:Text -*-
X .\"
X .TH ISPELL local MIT
X .SH NAME
X ispell \- Correct spelling for a file
X .br
X munchlist \- Combine suffixes in a spelling list
X .SH SYNOPSIS
X .B ispell
X [
X .B \-x
X |
X .B \-d
X file |
X .B \-p
X file |
X .B \-w
X chars ] file .....
X .br
X .B ispell
X [
X .B \-d
X file |
X .B \-p
X file |
X .B \-w
X chars ]
X .B \-l
X .br
X .B ispell
X [
X .B \-d
X file |
X .B \-p
X file
X ]
X .B \-a
X .br
X .B ispell
X [
X .B \-d
X file |
X .B \-p
X file |
X .B \-w
X chars ]
X .B \-c
X .br
X .B munchlist
X [
X .B \-d
X file |
X .B \-e
X |
X .B \-w
X chars ]
X [ files ]
X .SH DESCRIPTION
X .PP
X .I Ispell
X is fashioned after the
X .I spell
X program from ITS (called
X .I ispell
X on Twenex systems.)  The most common usage is "ispell filename".  In this
X case,
X .I ispell
X will display each word which does not appear in the dictionary, and
X allow you to change it.  If there are "near misses" in the dictionary
X (words which differ by only a single letter, a missing or extra letter,
X or a pair of transposed letters), then they are also displayed.  If you
X think the word is correct as it stands, you can type either "Space" to
X accept it this one time, or "I" to accept it and put it in your private
X dictionary.  If one of the near misses is the word you want, type the
X corresponding number.  Finally, if none of these choices is right, you
X can type "R" and you will be prompted for a replacement word.
X If you want to see a list of words that might be close using wildcard
X characters, type "L" to lookup a word in the system dictionary.
X .PP
X When a misspelled word is found, it is printed at the top of the screen.
X Any near misses will be printed on the following lines, and finally, two
X lines containing the word are printed at the bottom of the screen.  If
X your terminal can type in reverse video, the word itself is highlighted.
X .PP
X The
X .B \-l
X or "list" option to
X .I ispell
X is used to produce a list of misspelled words from the standard input.
X .PP
X The
X .B \-a
X is intended to be used from other programs through a pipe.  In this
X mode,
X .I ispell
X expects the standard input to consist of single words.  Each word is
X read, and a single line is written to the standard output.  If the word
X was found in the main dictionary, or your personal dictionary, then the
X line contains only a '*'.  If the word was found through suffix removal,
X then the line contains a '+', a space, and the root word.  If the word
X is not in the dictionary, but there are near misses, then the line
X contains an '&', a space, and a list of the near misses separated by
X spaces.  Also, each near miss is capitalized the same as the input
X words.  Finally, if the word neither appears in the dictionary, and
X there are no near misses, then the line contains only a '#'.  This mode
X is also suitable for interactive use when you want to figure out the
X spelling of a single word.  (These characters are the same as the codes
X that the real spell program uses.)
X .PP
X The
X .B \-x
X option causes
X .I ispell
X to remove the .bak file that it normally leaves.  The .bak file contains
X the pre-corrected text.  If there are file opening / writing errors,
X the .bak file may be left for recovery purposes even with the -x option.
X .PP
X The
X .B \-d
X option is used to specify an alternate hashed dictionary file,
X other than the default.  If the filename does not begin with a "/",
X the library directory for the default dictionary file is prefixed.
X This is useful to allow dictionaries which prefer alternate british
X spellings ("centre", "tyre", etc), or add lists of special-purpose
X jargon and acronyms for subclasses of documents.  There are some shortcomings
X in attempting to provide foreign-language dictionaries, but something
X like "-dfrench" could be made to work somewhat.
X The
X .B \-d
X option may specify
X .IR /dev/null ,
X in which case the dictionary is limited to the personal one.
X This may be useful for certain private dictionaries.
X .PP
X The
X .B \-p
X option is used to specify an alternate personal dictionary file.
X If the file name does not begin with "/", $HOME is prefixed.  Also, the
X shell variable WORDLIST may be set, which renames the personal dictionary
X in the same manner.  The command line overrides WORDLIST setting.  If
X neither is present "ispell.words" is used.
X .PP
X The
X .B \-w
X option may be used to specify characters other than alphabetics
X which may also appear in words.  For instance,
X .B \-w
X "&" will allow "AT&T"
X to be picked up.  Underscores are useful in many technical documents.
X There is an admittedly crude provision in this option for 8-bit international
X characters.  If "n" appears in the character string, the three characters
X following are a DECIMAL code 0 - 255, for the character.  There must be
X three decimal characters in all cases, so you have to prepend with 0's,
X for instance, to include bells and formfeeds in your words (an admittedly
X silly thing to do, but aren't most pedagogical examples):
X .PP
X n007n012
X .PP
X Numeric digits other than the three following "n" are simply numeric
X characters.  Use of "n" does not conflict with anything because actual
X alphabetics have no meaning - alphabetics are already accepted.
X .I Ispell
X will typically be used with input from a file, meaning that preserving
X parity for possible 8 bit characters from the input text is OK.  If you
X specify the -l option, and actually type text from the terminal, this may
X create problems if your stty settings preserve parity.
X .PP
X The
X .B \-c
X option is primarily intended for use by the
X .I munchlist
X shell script.
X In this mode, a list of words is read from the standard input.
X For each word, a list of possible root words and suffixes will be
X written to the standard output.
X Some of the root words will be illegal and must be filtered from the
X output by other means;
X the
X .I munchlist
X script does this.
X As an example, the command "echo BOTHER | ispell -c" produces:
X .PP
X .RS
X .nf
X BOTH
X BOTHE/R
X BOTH/R
X .fi
X .RE
X .PP
X The
X .I munchlist
X shell script is used to reduce the size of dictionary files,
X primarily personal dictionary files.
X It is also capable of combining dictionaries from various sources.
X The given
X .I files
X are read (standard input if no arguments are given),
X reduced to a minimal set of roots and suffixes that will match the
X same list of words, and written to standard output.
X .PP
X Normally, words that are in the default dictionary are removed by
X .I munchlist
X during processing.
X If the list is to be used with a different dictionary, the
X .B \-d
X option can be used to specify an alternate (hashed) dictionary file
X containing words to be removed from the output list.
X If a dictionary file of
X .I /dev/null
X is specified, no words will be removed from the output;
X this is useful when munching the primary dictionary file.
X .PP
X The
X .B \-w
X option is passed on to
X .IR ispell .
X The
X .B \-e
X ("efficient") option causes the script to use a slower algorithm that uses
X somewhat less space in TMPDIR (normally
X .IR /usr/tmp ")."
X .PP
X It is possible to install
X .I ispell
X in such a way as to only support ASCII range text if desired.
X .SH DEFAULT FILES
X /usr/public/lib/ispell.hash
X .br
X /usr/dict/web2		for the Lookup function
X .br
X $HOME/ispell.words	user's private dictionary
X .br
X /usr/public/lib/expand[12].sed		sed scripts for expanding suffixes
X .SH SEE ALSO
X spell(1), egrep(1), look(1)
X .SH BUGS
X It takes about five seconds for
X .I ispell
X to read in the hash table.
X .sp
X Perhaps more than ten choices should be allowed for near misses.
X .sp
X The hash table is stored as a quarter-megabyte array, so a PDP-11
X version does not seem likely.
X .sp
X .I Ispell
X should understand more
X .I troff
X syntax, and deal more intelligently with contractions.
X .sp
X While alternate dictionaries for foreign languages could be defined, and
X the international characters included in words, rules concerning
X word endings / pluralization accommodate english only.
X .sp
X .I Munchlist
X is very slow, and requires tremendous amounts of temporary file space for
X large dictionaries.
X It does respect the TMPDIR environment variable, so this space can be
X redirected.
X However, a lot of the temporary space it needs is for sorting, so TMPDIR
X is only a partial help on systems with an uncooperative
X .IR sort (1).
X As a benchmark, the 15000-word
X .I dict.191
X takes about 1200 blocks in TMPDIR, and 2000 in
X .IR sort "'s"
X temporary directories.
X On a 68000 workstation, it runs for the better part of an hour.
X Munching
X .I dict.191
X with
X .I /usr/dict/words
X (28000 words output)
X took another 1500 blocks or so, and ran for about three hours.
X .SH AUTHOR
X Pace Willisson (pace@mit-vax)
X .br
X Enhanced by James Woods, Bob McQueer, Bill Randle, Marc Ries, Rob McMahon,
X and Geoff Kuenning.
SHAR_EOF
if test 8455 -ne "`wc -c < 'ispell.man'`"
then
	echo shar: error transmitting "'ispell.man'" '(should have been 8455 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README'" '(6256 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X //' << \SHAR_EOF > 'README'
X -*- Mode:Text -*-
X 
X Ispell consists of two programs: the actual spelling checker, "ispell",
X and the hash table builder, "buildhash".  Everything is set up so you
X can just say "make install" and have everything happen.  You might want
X to edit the makefile, and ispell.h to change the destination of the
X program and the hash table.
X 
X The dictionary comes from the ITS spell dictionary.  I got it from
X "ml:wba;dict 191", although I don't know that this is the copy currenty
X in use on the 20's around MIT.
X 
X ----------------------------------------------------------------------
X 
X Addendum:
X 
X My eternal gratitude to the author of ispell -- I don't know how I
X ever lived without it.  I received his permission to post ispell to
X the net and have added a GNU EMACS interface.  Look in the file
X ispell.el for installation instructions.
X 
X As far as I know, no one informally "supports" this program.  If you
X would like to "adopt" it (collect fixes/enhancements and post a new
X version periodically), feel free to do so.
X 
X I volunteer to collect dictionary diffs and post a composite diff
X periodically.  If you add a lot of words to the main dictionary, send
X me the diffs between the the modified dictionary and the posted one.
X Also, if you have access to a TOPS20 system with a more complete
X dictionary in ispell format, send me the diffs if you can.  Just
X PLEASE don't dump an entire dictionary to our site!
X 
X The dictionary posted is one I snarfed from around here -- after
X comparison with the one originally supplied, ours appears a tad more
X complete and accurate.
X 
X Walt Buehring
X Texas Instruments - Computer Science Center
X 
X ARPA:  Buehring%TI-CSL@CSNet-Relay
X UUCP:  {smu, texsun, im4u, rice} ! ti-csl ! buehring
X 
X ----------------------------------------------------------------------
X 
X The following is the only documentation I could find about the format
X of the dictionary.  It was written for the TOPS20 speller that ispell
X mimics, so I believe most the information is applicable.  It should be
X useful if you want to add words to the main dictionary by hand.  -WB
X 
X ----------------------------------------------------------------------
X 
X 11.6  Dictionary flags
X 
X      Words  in SPELL's main dictionary (but not the other dictionaries) may
X have flags associated with  them  to  indicate  the  legality  of  suffixes
X without  the  need  to keep the full suffixed words in the dictionary.  The
X flags have "names" consisting of single  letters.    Their  meaning  is  as
X follows:
X 
X Let  #  and  @  be  "variables"  that can stand for any letter.  Upper case
X letters are constants.  "..."  stands  for  any  string  of  zero  or  more
X letters,  but note that no word may exist in the dictionary which is not at
X least 2 letters long, so, for example, FLY may not be produced  by  placing
X the  "Y"  flag  on "F".  Also, no flag is effective unless the word that it
X creates is at least 4 letters  long,  so,  for  example,  WED  may  not  be
X produced by placing the "D" flag on "WE".
X 
X "V" flag:
X         ...E --> ...IVE  as in CREATE --> CREATIVE
X         if # .ne. E, ...# --> ...#IVE  as in PREVENT --> PREVENTIVE
X 
X "N" flag:
X         ...E --> ...ION  as in CREATE --> CREATION
X         ...Y --> ...ICATION  as in MULTIPLY --> MULTIPLICATION
X         if # .ne. E or Y, ...# --> ...#EN  as in FALL --> FALLEN
X 
X "X" flag:
X         ...E --> ...IONS  as in CREATE --> CREATIONS
X         ...Y --> ...ICATIONS  as in MULTIPLY --> MULTIPLICATIONS
X         if # .ne. E or Y, ...# --> ...#ENS  as in WEAK --> WEAKENS
X 
X "H" flag:
X         ...Y --> ...IETH  as in TWENTY --> TWENTIETH
X         if # .ne. Y, ...# --> ...#TH  as in HUNDRED --> HUNDREDTH
X 
X "Y" FLAG:
X         ... --> ...LY  as in QUICK --> QUICKLY
X 
X "G" FLAG:
X         ...E --> ...ING  as in FILE --> FILING
X         if # .ne. E, ...# --> ...#ING  as in CROSS --> CROSSING
X 
X "J" FLAG"
X         ...E --> ...INGS  as in FILE --> FILINGS
X         if # .ne. E, ...# --> ...#INGS  as in CROSS --> CROSSINGS
X 
X "D" FLAG:
X         ...E --> ...ED  as in CREATE --> CREATED
X         if @ .ne. A, E, I, O, or U,
X                 ...@Y --> ...@IED  as in IMPLY --> IMPLIED
X         if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X                 ...@# --> ...@#ED  as in CROSS --> CROSSED
X                                 or CONVEY --> CONVEYED
X "T" FLAG:
X         ...E --> ...EST  as in LATE --> LATEST
X         if @ .ne. A, E, I, O, or U,
X                 ...@Y --> ...@IEST  as in DIRTY --> DIRTIEST
X         if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X                 ...@# --> ...@#EST  as in SMALL --> SMALLEST
X                                 or GRAY --> GRAYEST
X 
X "R" FLAG:
X         ...E --> ...ER  as in SKATE --> SKATER
X         if @ .ne. A, E, I, O, or U,
X                 ...@Y --> ...@IER  as in MULTIPLY --> MULTIPLIER
X         if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X                 ...@# --> ...@#ER  as in BUILD --> BUILDER
X                                 or CONVEY --> CONVEYER
X 
X "Z FLAG:
X         ...E --> ...ERS  as in SKATE --> SKATERS
X         if @ .ne. A, E, I, O, or U,
X                 ...@Y --> ...@IERS  as in MULTIPLY --> MULTIPLIERS
X         if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X                 ...@# --> ...@#ERS  as in BUILD --> BUILDERS
X                                 or SLAY --> SLAYERS
X 
X "S" FLAG:
X         if @ .ne. A, E, I, O, or U,
X                 ...@Y --> ...@IES  as in IMPLY --> IMPLIES
X         if # .eq. S, X, Z, or H,
X                 ...# --> ...#ES  as in FIX --> FIXES
X         if # .ne. S, X, Z, H, or Y, or (# = Y and @ = A, E, I, O, or U)
X                 ...@# --> ...@#S  as in BAT --> BATS
X                                 or CONVEY --> CONVEYS
X 
X "P" FLAG:
X         if @ .ne. A, E, I, O, or U,
X                 ...@Y --> ...@INESS  as in CLOUDY --> CLOUDINESS
X         if # .ne. Y, or @ = A, E, I, O, or U,
X                 ...@# --> ...@#NESS  as in LATE --> LATENESS
X                                 or GRAY --> GRAYNESS
X 
X "M" FLAG:
X         ... --> ...'S  as in DOG --> DOG'S
X 
X ----------------------------------------------------------------------
X 
X [Whew!  That's all very nice, but how about a quick reference...  -WB]
X 
X V -  ive
X N -  ion, tion, en
X X -  ions, ications, ens
X H -  th, ieth
X Y -  ly
X G -  ing
X J -  ings
X D -  ed
X T -  est
X R -  er
X Z -  ers
X S -  s, es, ies
X P -  ness, iness
X M -  's
SHAR_EOF
if test 6256 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 6256 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'WISHES'" '(1211 characters)'
if test -f 'WISHES'
then
	echo shar: will not over-write existing file "'WISHES'"
else
sed 's/^X //' << \SHAR_EOF > 'WISHES'
X Things remaining to be done to ispell:
X 
X 	- The single biggest remaining deficiency (in my opinion) is the
X 	  extensive misuse of 'strlen'.  Strlen is often called repeatedly
X 	  on the same string within a few lines of code.  Worse, many
X 	  routines accept a "length" parameter (which is usually passed
X 	  by running 'strlen' within the arglist) but ignore it and
X 	  actually require the string to be null-terminated.  Somebody
X 	  should do a systematic edit and clean this up.  I wouldn't
X 	  be surprised to learn that ispell spends 50% of its time in
X 	  strlen.
X 	- The "munchlist" script can actually increase the size of a
X 	  dictionary.  For example, munching dict.191 (after my bugfixes
X 	  to it) reduced the number of words by about 40, but increased
X 	  the number of characters by a small percentage.  This is
X 	  because munchlist doesn't recognize duplicate suffixes that
X 	  generate the same result, except for the three special
X 	  "s-ending" suffixes J, Z, and X.  For example, right now
X 	  munchlist will make BATHER by adding the R suffix to both
X 	  BATH and BATHE.  It would be nice if munchlist could recognize
X 	  the redundancy and reduce its output so that each word was made
X 	  in only one way.
SHAR_EOF
if test 1211 -ne "`wc -c < 'WISHES'`"
then
	echo shar: error transmitting "'WISHES'" '(should have been 1211 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'expand.awk'" '(5769 characters)'
if test -f 'expand.awk'
then
	echo shar: will not over-write existing file "'expand.awk'"
else
sed 's/^X //' << \SHAR_EOF > 'expand.awk'
X BEGIN {FS = "/"}
X     {
X     print $1
X #Let  #  and  @  be  "variables"  that can stand for any letter.  Upper case
X #letters are constants.  "..."  stands  for  any  string  of  zero  or  more
X #letters,  but note that no word may exist in the dictionary which is not at
X #least 2 letters long, so, for example, FLY may not be produced  by  placing
X #the  "Y"  flag  on "F".  Also, no flag is effective unless the word that it
X #creates is at least 4 letters  long,  so,  for  example,  WED  may  not  be
X #produced by placing the "D" flag on "WE".
X     size = length ($1)
X     #
X     # Break out the last two letters into "tail", and put
X     # corresponding versions of the root with the tail trimmed
X     # off into "trimmed".  If they are vowels, set vowel[i].
X     # (Actually, only vowel[2] is used).
X     #
X     for (i = 1;  i < 3;  i++)
X 	{
X 	tail[i] = substr ($1, size - i + 1, 1)
X 	if (tail[i] == "A"  ||  tail[i] == "E" ||  tail[i] == "I" \
X 	  ||  tail[i] == "O"  ||  tail[i] == "U")
X 	    vowel[i] = 1
X 	else
X 	    vowel[i] = 0
X 	trimmed[i] = substr ($1, 1, size - i)
X 	}
X     for (i = 2;  i <= NF;  i++)
X 	{
X 	if ($i == "V")
X 	    {
X #		...E --> ...IVE  as in CREATE --> CREATIVE
X #		if # .ne. E, ...# --> ...#IVE  as in PREVENT --> PREVENTIVE
X 	    if (tail[1] == "E")
X 		print trimmed[1] "IVE"
X 	    else
X 		print $1 "IVE"
X 	    }
X 	else if ($i == "N"  ||  $i == "X")
X 	    {
X #	        ...E --> ...ION  as in CREATE --> CREATION
X #	        ...Y --> ...ICATION  as in MULTIPLY --> MULTIPLICATION
X #	        if # .ne. E or Y, ...# --> ...#EN  as in FALL --> FALLEN
X #	    "X" flag:
X #	        ...E --> ...IONS  as in CREATE --> CREATIONS
X #	        ...Y --> ...ICATIONS  as in MULTIPLY --> MULTIPLICATIONS
X #	        if # .ne. E or Y, ...# --> ...#ENS  as in WEAK --> WEAKENS
X 	    if ($i == "N")
X 		plural = ""
X 	    else
X 		plural = "S"
X 	    if (tail[1] == "E")
X 		print trimmed[1] "ION" plural
X 	    else if (tail[1] == "Y")
X 		print trimmed[1] "ICATION" plural
X 	    else
X 		print $1 "EN" plural
X 	    }
X 	else if ($i == "H")
X 	    {
X #	        ...Y --> ...IETH  as in TWENTY --> TWENTIETH
X #	        if # .ne. Y, ...# --> ...#TH  as in HUNDRED --> HUNDREDTH
X 	    if (tail[1] == "Y")
X 		print trimmed[1] "IETH"
X 	    else
X 		print $1 "TH"
X 	    }
X 	else if ($i == "Y")
X 	    {
X #	        ... --> ...LY  as in QUICK --> QUICKLY
X 	    print $1 "LY"
X 	    }
X 	else if ($i == "G"  ||  $i == "G")
X 	    {
X #	        ...E --> ...ING  as in FILE --> FILING
X #	        if # .ne. E, ...# --> ...#ING  as in CROSS --> CROSSING
X #	    "J" flag:
X #	        ...E --> ...INGS  as in FILE --> FILINGS
X #	        if # .ne. E, ...# --> ...#INGS  as in CROSS --> CROSSINGS
X 	    if ($i == "G")
X 		plural = ""
X 	    else
X 		plural = "S"
X 	    if (tail[1] == "E")
X 		print trimmed[1] "ING" plural
X 	    else
X 		print $1 "ING" plural
X 	    }
X 	else if ($i == "D")
X 	    {
X #	        ...E --> ...ED  as in CREATE --> CREATED
X #	        if @ .ne. A, E, I, O, or U,
X #	                ...@Y --> ...@IED  as in IMPLY --> IMPLIED
X #	        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X #	                ...@# --> ...@#ED  as in CROSS --> CROSSED
X #	                                or CONVEY --> CONVEYED
X 	    if (tail[1] == "E")
X 		print $1 "D"
X 	    else if (tail[1] == "Y"  && !vowel[2])
X 		print trimmed[1] "IED"
X 	    else
X 		print $1 "ED"
X 	    }
X 	else if ($i == "T")
X 	    {
X #	        ...E --> ...EST  as in LATE --> LATEST
X #	        if @ .ne. A, E, I, O, or U,
X #	                ...@Y --> ...@IEST  as in DIRTY --> DIRTIEST
X #	        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X #	                ...@# --> ...@#EST  as in SMALL --> SMALLEST
X #                                or GRAY --> GRAYEST
X 	    if (tail[1] == "E")
X 		print $1 "ST"
X 	    else if (tail[1] == "Y"  &&  !vowel[2])
X 		print trimmed[1] "IEST"
X 	    else
X 		print $1 "EST"
X 	    }
X 	else if ($i == "R"  ||  $i == "Z")
X 	    {
X #	        ...E --> ...ER  as in SKATE --> SKATER
X #	        if @ .ne. A, E, I, O, or U,
X #	                ...@Y --> ...@IER  as in MULTIPLY --> MULTIPLIER
X #	        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X #	                ...@# --> ...@#ER  as in BUILD --> BUILDER
X #	                                or CONVEY --> CONVEYER
X #	   "Z" flag:
X #	        ...E --> ...ERS  as in SKATE --> SKATERS
X #	        if @ .ne. A, E, I, O, or U,
X #	                ...@Y --> ...@IERS  as in MULTIPLY --> MULTIPLIERS
X #	        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X #	                ...@# --> ...@#ERS  as in BUILD --> BUILDERS
X #	                                or SLAY --> SLAYERS
X 	    if ($i == "R")
X 		plural = ""
X 	    else
X 		plural = "S"
X 	    if (tail[1] == "E")
X 		print $1 "R" plural
X 	    else if (tail[1] == "Y"  &&  !vowel[2])
X 		print trimmed[1] "IER" plural
X 	    else
X 		print $1 "ER" plural
X 	    }
X 	else if ($i == "S")
X 	    {
X #	        if @ .ne. A, E, I, O, or U,
X #	                ...@Y --> ...@IES  as in IMPLY --> IMPLIES
X #	        if # .eq. S, X, Z, or H,
X #	                ...# --> ...#ES  as in FIX --> FIXES
X #	        if # .ne. S, X, Z, H, or Y, or (# = Y and @ = A, E, I, O, or U)
X #	                ...@# --> ...@#S  as in BAT --> BATS
X #	                                or CONVEY --> CONVEYS
X 	    if (tail[1] == "Y"  &&  !vowel[2])
X 		print trimmed[1] "IES"
X 	    else if (tail[1] == "S")
X 		print $1 "ES"
X 	    else
X 		print $1 "S"
X 	    }
X 	else if ($i == "P")
X 	    {
X #	        if @ .ne. A, E, I, O, or U,
X #	                ...@Y --> ...@INESS  as in CLOUDY --> CLOUDINESS
X #	        if # .ne. Y, or @ = A, E, I, O, or U,
X #	                ...@# --> ...@#NESS  as in LATE --> LATENESS
X #	                                or GRAY --> GRAYNESS
X 	    if (tail[1] == "Y"  &&  !vowel[2])
X 		print trimmed[1] "INESS"
X 	    else
X 		print $1 "NESS"
X 	    }
X 	else if ($i == "M")
X 	    {
X #	        ... --> ...'S  as in DOG --> DOG'S
X 		print $1 "'S"
X 	    }
X 	}
X     }
SHAR_EOF
if test 5769 -ne "`wc -c < 'expand.awk'`"
then
	echo shar: error transmitting "'expand.awk'" '(should have been 5769 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'expand1.sed'" '(1607 characters)'
if test -f 'expand1.sed'
then
	echo shar: will not over-write existing file "'expand1.sed'"
else
sed 's/^X //' << \SHAR_EOF > 'expand1.sed'
X /^[^/]*$/n
X /\/V/ {
X     /^[^/]*E\// {
X 	s@\([^/]*\)E\([/A-Z]*\)/V@\1IVE\
X \1E\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/V@\1IVE\
X \1\2@; P; D
X }
X /\/N/ {
X     /^[^/]*E\// {
X 	s@\([^/]*\)E\([/A-Z]*\)/N@\1ION\
X \1E\2@; P; D
X     }
X     /^[^/]*Y\// {
X 	s@\([^/]*\)Y\([/A-Z]*\)/N@\1ICATION\
X \1Y\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/N@\1EN\
X \1\2@; P; D
X }
X /\/X/ {
X     /^[^/]*E\// {
X 	s@\([^/]*\)E\([/A-Z]*\)/X@\1IONS\
X \1E\2@; P; D
X     }
X     /^[^/]*Y\// {
X 	s@\([^/]*\)Y\([/A-Z]*\)/X@\1ICATIONS\
X \1Y\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/X@\1ENS\
X \1\2@; P; D
X }
X /\/H/ {
X     /^[^/]*Y\// {
X 	s@\([^/]*\)Y\([/A-Z]*\)/H@\1IETH\
X \1Y\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/H@\1TH\
X \1\2@; P; D
X }
X /\/Y/ {
X     s@\([^/]*\)\([/A-Z]*\)/Y@\1LY\
X \1\2@; P; D
X }
X /\/G/ {
X     /^[^/]*E\// {
X 	s@\([^/]*\)E\([/A-Z]*\)/G@\1ING\
X \1E\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/G@\1ING\
X \1\2@; P; D
X }
X /\/J/ {
X     /^[^/]*E\// {
X 	s@\([^/]*\)E\([/A-Z]*\)/J@\1INGS\
X \1E\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/J@\1INGS\
X \1\2@; P; D
X }
X /\/D/ {
X     /^[^/]*E\// {
X 	s@\([^/]*\)\([/A-Z]*\)/D@\1D\
X \1\2@; P; D
X     }
X     /^[^/]*[^AEIOU]Y\// {
X 	s@\([^/]*\)Y\([/A-Z]*\)/D@\1IED\
X \1Y\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/D@\1ED\
X \1\2@; P; D
X }
X /\/T/ {
X     /^[^/]*E\// {
X 	s@\([^/]*\)\([/A-Z]*\)/T@\1ST\
X \1\2@; P; D
X     }
X     /^[^/]*[^AEIOU]Y\// {
X 	s@\([^/]*\)Y\([/A-Z]*\)/T@\1IEST\
X \1Y\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/T@\1EST\
X \1\2@; P; D
X }
X /\/R/ {
X     /^[^/]*E\// {
X 	s@\([^/]*\)\([/A-Z]*\)/R@\1R\
X \1\2@; P; D
X     }
X     /^[^/]*[^AEIOU]Y\// {
X 	s@\([^/]*\)Y\([/A-Z]*\)/R@\1IER\
X \1Y\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/R@\1ER\
X \1\2@; P; D
X }
SHAR_EOF
if test 1607 -ne "`wc -c < 'expand1.sed'`"
then
	echo shar: error transmitting "'expand1.sed'" '(should have been 1607 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'expand2.sed'" '(622 characters)'
if test -f 'expand2.sed'
then
	echo shar: will not over-write existing file "'expand2.sed'"
else
sed 's/^X //' << \SHAR_EOF > 'expand2.sed'
X /^[^/]*$/n
X /\/Z/ {
X     /^[^/]*E\// {
X 	s@\([^/]*\)\([/A-Z]*\)/Z@\1RS\
X \1\2@; P; D
X     }
X     /^[^/]*[^AEIOU]Y\// {
X 	s@\([^/]*\)Y\([/A-Z]*\)/Z@\1IERS\
X \1Y\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/Z@\1ERS\
X \1\2@; P; D
X }
X /\/S/ {
X     /^[^/]*[^AEIOU]Y\// {
X 	s@\([^/]*\)Y\([/A-Z]*\)/S@\1IES\
X \1Y\2@; P; D
X     }
X     /^[^/]*[SXZH]\// {
X 	s@\([^/]*\)\([/A-Z]*\)/S@\1ES\
X \1\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/S@\1S\
X \1\2@; P; D
X }
X /\/P/ {
X     /^[^/]*[^AEIOU]Y\// {
X 	s@\([^/]*\)Y\([/A-Z]*\)/P@\1INESS\
X \1Y\2@; P; D
X     }
X     s@\([^/]*\)\([/A-Z]*\)/P@\1NESS\
X \1\2@; P; D
X }
X /\/M/ {
X     s@\([^/]*\)\([/A-Z]*\)/M@\1'S\
X \1\2@; P; D
X }
SHAR_EOF
if test 622 -ne "`wc -c < 'expand2.sed'`"
then
	echo shar: error transmitting "'expand2.sed'" '(should have been 622 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'munchlist.sh'" '(6218 characters)'
if test -f 'munchlist.sh'
then
	echo shar: will not over-write existing file "'munchlist.sh'"
else
sed 's/^X //' << \SHAR_EOF > 'munchlist.sh'
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=/tmp2/lib			# Must match config.h
X DEFDICT=dict.191			# Must match config.h
X EXPAND1=${LIBDIR}/expand1.sed
X EXPAND2=${LIBDIR}/expand2.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 #
X # Awk program to combine suffixes onto one line
X #
X AWKMUNCH='
X     {
X     if ($1 != old1  &&  old1 != "")
X 	{
X 	print old1 suffixes
X 	suffixes = ""
X 	}
X     old1 = $1
X     for (i = 2;  i <= NF;  i++)
X 	suffixes = suffixes "/" $i
X     }
X     END { if (old1 != "") print old1 suffixes }'
X #
X # Awk program to break suffixes up into one per line
X #
X AWKUNMUNCH='
X     {
X     print $1
X     for (i = 2;  i <= NF;  i++)
X 	print $1 "/" $i
X     }'
X trap "/bin/rm -f ${TMP}*; exit 1" 1 2 15
X #
X # Collect all the input (cat), convert to uppercase (tr), expand all
X # the suffix options (two sed's), and preserve (sorted) for later
X # joining.  Unless an explicitly null dictionary was specified, remove
X # all expanded words that are covered by the dictionary (ispell).
X #
X if [ "X$dictopt" = "XNONE" ]
X then
X     cat "$@" | tr '[a-z]' '[A-Z]' \
X       | sed -f $EXPAND1 | sed -f $EXPAND2 | sort -u > ${TMP}a
X else
X     cat "$@" | tr '[a-z]' '[A-Z]' \
X       | sed -f $EXPAND1 | sed -f $EXPAND2 | sort -u \
X       | ispell -l $dictopt -p /dev/null > ${TMP}a
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.
X #
X # Note:  one disadvantage of this pipeline is that for a large file,
X # the join and awk may be sitting around for a long time while ispell
X # and sort 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}a \
X       | egrep / | sort -u -t/ +0 -1 +1 \
X       | join -t/ - ${TMP}a | awk -F/ "$AWKMUNCH" > ${TMP}b
X else
X     ispell $wchars -c -d /dev/null -p /dev/null < ${TMP}a \
X       | egrep / | sort -u -t/ +0 -1 +1 \
X       | join -t/ - ${TMP}a > ${TMP}b
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}c.
X #
X if [ $cheap = yes ]
X then
X     egrep '^[^/]*/S$' ${TMP}b | sed 's@/S$@@' \
X       | ispell -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       | awk -F/ "$AWKMUNCH" > ${TMP}c
X else
X     egrep '^[^/]*/S$' ${TMP}b | sed 's@/S$@@' \
X       | ispell -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}c
X fi
X #
X # Now we have to eliminate the stuff covered by ${TMP}c from ${TMP}.
X # First, we re-expand the suffixes we just made (sed -f pair), 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}b.  The output of comm (i.e., the trimmed version of
X # ${TMP}b) is combined with our special-suffixes file ${TMP}c (sort,
X # with preceding awk, if $cheap) and reduced in size (AWKMUNCH) to
X # produce a final list of all words that have at least one suffix.
X #
X if [ $cheap = yes ]
X then
X     sed -f $EXPAND1 < ${TMP}c | sed -f $EXPAND2 \
X       | ispell -c -d /dev/null -p /dev/null \
X       | egrep '\/S$' | sort -u -t/ +0 -1 +1 | comm -13 - ${TMP}b \
X       | awk -F/ "$AWKUNMUNCH" - ${TMP}c \
X       | sort -u -t/ +0 -1 +1 - \
X       | awk -F/ "$AWKMUNCH" > ${TMP}d
X else
X     sed -f $EXPAND1 < ${TMP}c | sed -f $EXPAND2 \
X       | ispell -c -d /dev/null -p /dev/null \
X       | egrep '\/S$' | sort -u -t/ +0 -1 +1 | comm -13 - ${TMP}b \
X       | sort -u -t/ +0 -1 +1 - ${TMP}c \
X       | awk -F/ "$AWKMUNCH" > ${TMP}d
X fi
X /bin/rm -f ${TMP}[bc]
X #
X # Now a slick trick.  Use ispell to select those (root) words from the original
X # list (${TMP}a) that are not covered by the suffix list (${TMP}d).  Then we
X # merge these with the suffix list and sort it to produce the final output.
X #
X ispell $wchars -d /dev/null -p ${TMP}d -l < ${TMP}a | tr -d \\015 \
X   | sort -u -t/ +0 -1 +1 - ${TMP}d
X /bin/rm -f ${TMP}*
SHAR_EOF
if test 6218 -ne "`wc -c < 'munchlist.sh'`"
then
	echo shar: error transmitting "'munchlist.sh'" '(should have been 6218 characters)'
fi
chmod +x 'munchlist.sh'
fi # end of overwriting check
echo shar: extracting "'ispell.el'" '(6763 characters)'
if test -f 'ispell.el'
then
	echo shar: will not over-write existing file "'ispell.el'"
else
sed 's/^X //' << \SHAR_EOF > 'ispell.el'
X ;;; Spelling correction interface for GNU EMACS using "ispell"
X 
X ;;; Walt Buehring
X ;;; Texas Instruments - Computer Science Center
X ;;; ARPA:  Buehring%TI-CSL@CSNet-Relay
X ;;; UUCP:  {smu, texsun, im4u, rice} ! ti-csl ! buehring
X 
X ;;; Depends on the ispell program snarfed from MIT-PREP in early 
X ;;; 1986.  The only interactive command is "ispell-word" which should be
X ;;; bound to M-$.  If someone writes an "ispell-region" command, 
X ;;; I would appreciate a copy.
X 
X ;;; To fully install this, add this file to your GNU lisp directory and 
X ;;; compile it with M-X byte-compile-file.  Then add the following to the
X ;;; appropriate init file:
X 
X ;;;  (autoload 'ispell-word "ispell"
X ;;;    "Check the spelling of word in buffer." t)
X ;;;  (global-set-key "\e$" 'ispell-word)
X 
X ;;; If run on a heavily loaded system, the timeout value in ispell-check 
X ;;; and the initial sleep time in ispell-init-process may need to be increased.
X 
X ;;; No warranty expressed or implied.  All sales final.  Void where prohibited.
X ;;; If you don't like it, change it.
X 
X (defvar ispell-syntax-table nil)
X 
X (if (null ispell-syntax-table)
X     ;; The following assumes that the standard-syntax-table
X     ;; is static.  If you add words with funky characters
X     ;; to your dictionary, the following may have to change.
X     (progn
X       (setq ispell-syntax-table (make-syntax-table))
X       ;; Make certain characters word constituents
X       (modify-syntax-entry ?' "w   " ispell-syntax-table)
X       (modify-syntax-entry ?- "w   " ispell-syntax-table)
X       ;; Get rid on existing word syntax on certain characters 
X       (modify-syntax-entry ?$ ".   " ispell-syntax-table)
X       (modify-syntax-entry ?% ".   " ispell-syntax-table)))
X 
X 
X (defun ispell-word (&optional quietly)
X   "Check spelling of word at or before dot.
X If word not found in dictionary, display possible corrections in a window 
X and let user select."
X   (interactive)
X   (let* ((current-syntax (syntax-table))
X 	 start end word poss replace)
X     (unwind-protect
X 	(save-excursion
X 	  ;; Ensure syntax table is reasonable 
X 	  (set-syntax-table ispell-syntax-table)
X 	  ;; Move backward for word if not already on one.
X 	  (if (not (looking-at "\\w"))
X 	      (re-search-backward "\\w" (dot-min) 'stay))
X 	  ;; Move to start of word
X 	  (re-search-backward "\\W" (dot-min) 'stay)
X 	  ;; Find start and end of word
X 	  (or (re-search-forward "\\w+" nil t)
X 	      (error "No word to check."))
X 	  (setq start (match-beginning 0)
X 		end (match-end 0)
X 		word (buffer-substring start end)))
X       (set-syntax-table current-syntax))
X     (or quietly (message "Checking spelling of %s..." (upcase word)))
X     (setq poss (ispell-check word))
X     (cond ((eq poss t)
X 	   (or quietly (message "Found %s" (upcase word))))
X 	  ((stringp poss)
X 	   (or quietly (message "Found it because of %s" (upcase poss))))
X 	  ((null poss)
X 	   (or quietly (message "Could Not Find %s" (upcase word))))
X 	  (t (setq replace (ispell-choose poss))
X 	     (if replace
X 		 (progn
X 		   (goto-char end)
X 		   (delete-region start end)
X 		   (insert-string replace)))))
X     poss))
X 
X 
X (defun ispell-choose (choices)
X   "Display possible corrections from list CHOICES.  Return chosen word or nil 
X if none chosen."
X   (unwind-protect 
X       (save-window-excursion
X 	(let ((count 0)
X 	      (words choices)
X 	      (pick -1)
X 	      (window-min-height 2))
X 	  (overlay-window 3)
X 	  (switch-to-buffer "*Choices*") (erase-buffer)
X 	  (setq mode-line-format "--  %b  --")
X 	  (while words
X 	    (if (> (+ 7 (current-column) (length (car words))) (window-width))
X 		(insert "\n"))
X 	    (insert "(" (+ count ?a) ") " (car words) "  ")
X 	    (setq words (cdr words)
X 		  count (1+ count)))
X 	  (select-window (next-window))
X 	  (while (eq pick -1)
X 	    (message "Enter letter to replace word;  Space to flush")
X 	    (let* ((char (read-char))
X 		   (num (1+ (- (upcase char) ?A))))
X 	      (cond ((= char ? ) (setq pick 0))
X 		    ((or (<= num 0) (> num count)) (ding))
X 		    (t (setq pick num)))))
X 	  (and (> pick 0) (nth (1- pick) choices))))
X     ;; Protected forms...
X     (bury-buffer "*Choices*")))
X 
X 
X (defun overlay-window (height)
X   "Create a (usually small) window with HEIGHT lines and avoid
X recentering."
X   (save-excursion
X     (let ((oldot (save-excursion (beginning-of-line) (dot)))
X 	  (top (save-excursion (move-to-window-line height) (dot)))
X 	  newin)
X       (if (< oldot top) (setq top oldot))
X       (setq newin (split-window-vertically height))
X       (set-window-start newin top))))
X 
X 
X (defvar ispell-process nil
X   "Holds the process object for 'ispell'")
X 
X ;;; create signal used by ispell-filter and ispell-check
X (put 'ispell-output 'error-conditions '(ispell-output))
X 
X (defun ispell-check (word)
X "Check spelling of string WORD, return either t for an exact match, a string
X containing the root word for a match via suffix removal, a list of possible 
X correct spellings, or nil for a complete miss."
X   (ispell-init-process)
X   (send-string ispell-process (concat word "\n"))
X   (condition-case output
X       (progn
X 	(sleep-for 20)
X 	(error "Timeout waiting for ispell process output"))
X     (ispell-output (ispell-parse-output (car (cdr output))))))
X 
X (defun ispell-parse-output (output)
X "Parse the OUTPUT string of 'ispell' and return a value as specified by the 
X 'ispell-check' function."
X   (cond
X    ((string= output "*") t)
X    ((string= output "#") nil)
X    ((string= (substring output 0 1) "+")
X     (substring output 2))
X    (t
X     (let ((choice-list '()))
X       (while (not (string= output ""))
X 	(let* ((start (string-match "[A-z]" output))
X 	       (end (string-match " \\|$" output start)))
X 	  (if start
X 	      (setq choice-list (cons (substring output start end)
X 				      choice-list)))
X 	  (setq output (substring output (1+ end)))))
X       choice-list))))
X 
X 
X (defvar ispell-process-output ""
X   "Holds partial output from the 'ispell' process")
X 
X (defun ispell-filter (process output)
X   "The filter-function for 'ispell'.  Signals complete line using the 
X ispell-output signal"
X   (if (string= "\n" (substring output (1- (length output))))
X       (progn
X 	(setq output (concat ispell-process-output
X 			     (substring output 0 (1- (length output))))
X 	      ispell-process-output "")
X 	(signal 'ispell-output (list output)))
X       (setq ispell-process-output (concat ispell-process-output output))))
X 
X (defun ispell-init-process ()
X   "Check status of 'ispell' process and start if necessary; set up 
X filter function for output."
X   (if (or (not ispell-process)
X 	  (not (eq (process-status ispell-process) 'run)))
X       (progn
X 	(message "Starting new ispell process...")
X 	(and (get-buffer "*ispell*") (kill-buffer "*ispell*"))
X 	(setq ispell-process (start-process "ispell" "*ispell*"
X 					   "ispell" "-a"))
X 	(set-process-filter ispell-process 'ispell-filter)
X 	(process-kill-without-query ispell-process)
X 	(sit-for 3))))
X 
SHAR_EOF
if test 6763 -ne "`wc -c < 'ispell.el'`"
then
	echo shar: error transmitting "'ispell.el'" '(should have been 6763 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'buildhash.c'" '(6459 characters)'
if test -f 'buildhash.c'
then
	echo shar: will not over-write existing file "'buildhash.c'"
else
sed 's/^X //' << \SHAR_EOF > 'buildhash.c'
X /* -*- Mode: Text -*- */
X /*
X  * buildhash.c - make a hash table for ispell
X  *
X  * Pace Willisson, 1983
X  */
X 
X #include <stdio.h>
X #include <sys/types.h>
X #include <sys/stat.h>
X #include <sys/param.h>
X #include "ispell.h"
X #include "config.h"
X 
X #define NSTAT 100
X struct stat dstat, cstat;
X 
X int numwords, hashsize;
X 
X char *malloc();
X 
X struct dent *hashtbl;
X 
X char *Dfile;
X char *Hfile;
X 
X char Cfile[MAXPATHLEN];
X char Sfile[MAXPATHLEN];
X 
X main (argc,argv)
X int argc;
X char **argv;
X {
X 	FILE *countf;
X 	FILE *statf;
X 	int stats[NSTAT];
X 	int i;
X 
X 	if (argc > 1) {
X 		++argv;
X 		Dfile = *argv;
X 		if (argc > 2) {
X 			++argv;
X 			Hfile = *argv;
X 		}
X 		else
X 			Hfile = DEFHASH;
X 	}
X 	else {
X 		Dfile = DEFDICT;
X 		Hfile = DEFHASH;
X 	}
X 
X 	sprintf(Cfile,"%s.cnt",Dfile);
X 	sprintf(Sfile,"%s.stat",Dfile);
X 
X 	if (stat (Dfile, &dstat) < 0) {
X 		fprintf (stderr, "No dictionary (%s)\n", Dfile);
X 		exit (1);
X 	}
X 
X 	if (stat (Cfile, &cstat) < 0 || dstat.st_mtime > cstat.st_mtime)
X 		newcount ();
X 
X 	if ((countf = fopen (Cfile, "r")) == NULL) {
X 		fprintf (stderr, "No count file\n");
X 		exit (1);
X 	}
X 	numwords = 0;
X 	fscanf (countf, "%d", &numwords);
X 	fclose (countf);
X 	if (numwords == 0) {
X 		fprintf (stderr, "Bad count file\n");
X 		exit (1);
X 	}
X 	hashsize = numwords;
X 	readdict ();
X 
X 	if ((statf = fopen (Sfile, "w")) == NULL) {
X 		fprintf (stderr, "Can't create %s\n", Sfile);
X 		exit (1);
X 	}
X 
X 	for (i = 0; i < NSTAT; i++)
X 		stats[i] = 0;
X 	for (i = 0; i < hashsize; i++) {
X 		struct dent *dp;
X 		int j;
X 		if (hashtbl[i].used == 0) {
X 			stats[0]++;
X 		} else {
X 			for (j = 1, dp = &hashtbl[i]; dp->next != NULL; j++, dp = dp->next)
X 				;
X 			if (j >= NSTAT)
X 				j = NSTAT - 1;
X 			stats[j]++;
X 		}
X 	}
X 	for (i = 0; i < NSTAT; i++)
X 		fprintf (statf, "%d: %d\n", i, stats[i]);
X 	fclose (statf);
X 
X 	filltable ();
X 
X 	output ();
X 	exit(0);
X }
X 
X output ()
X {
X 	FILE *outfile;
X 	struct hashheader hashheader;
X 	int strptr, n, i;
X 
X 	if ((outfile = fopen (Hfile, "w")) == NULL) {
X 		fprintf (stderr, "can't create %s\n",Hfile);
X 		return;
X 	}
X 	hashheader.magic = MAGIC;
X 	hashheader.stringsize = 0;
X 	hashheader.tblsize = hashsize;
X 	fwrite (&hashheader, sizeof hashheader, 1, outfile);
X 	strptr = 0;
X 	for (i = 0; i < hashsize; i++) {
X 		n = strlen (hashtbl[i].word) + 1;
X 		fwrite (hashtbl[i].word, n, 1, outfile);
X 		hashtbl[i].word = (char *)strptr;
X 		strptr += n;
X 	}
X 	for (i = 0; i < hashsize; i++) {
X 		if (hashtbl[i].next != 0) {
X 			int x;
X 			x = hashtbl[i].next - hashtbl;
X 			hashtbl[i].next = (struct dent *)x;
X 		} else {
X 			hashtbl[i].next = (struct dent *)-1;
X 		}
X 	}
X 	fwrite (hashtbl, sizeof (struct dent), hashsize, outfile);
X 	hashheader.stringsize = strptr;
X 	rewind (outfile);
X 	fwrite (&hashheader, sizeof hashheader, 1, outfile);
X 	fclose (outfile);
X }
X 
X filltable ()
X {
X 	struct dent *freepointer, *nextword, *dp;
X 	int i;
X 
X 	for (freepointer = hashtbl; freepointer->used; freepointer++)
X 		;
X 	for (nextword = hashtbl, i = numwords; i != 0; nextword++, i--) {
X 		if (nextword->used == 0) {
X 			continue;
X 		}
X 		if (nextword->next == NULL) {
X 			continue;
X 		}
X 		if (nextword->next >= hashtbl && nextword->next < hashtbl + hashsize) {
X 			continue;
X 		}
X 		dp = nextword;
X 		while (dp->next) {
X 			if (freepointer > hashtbl + hashsize) {
X 				fprintf (stderr, "table overflow\n");
X 				getchar ();
X 				break;
X 			}
X 			*freepointer = *(dp->next);
X 			dp->next = freepointer;
X 			dp = freepointer;
X 
X 			while (freepointer->used)
X 				freepointer++;
X 		}
X 	}
X }
X 
X 
X readdict ()
X {
X 	struct dent d;
X 	char lbuf[100];
X 	FILE *dictf;
X 	int i;
X 	int h;
X 	char *p;
X 
X 	if ((dictf = fopen (Dfile, "r")) == NULL) {
X 		fprintf (stderr, "Can't open dictionary\n");
X 		exit (1);
X 	}
X 
X 	hashtbl = (struct dent *) calloc (numwords, sizeof (struct dent));
X 	if (hashtbl == NULL) {
X 		fprintf (stderr, "couldn't allocate hash table\n");
X 		exit (1);
X 	}
X 
X 	i = 0;
X 	while (fgets (lbuf, sizeof lbuf, dictf) != NULL) {
X 		if (i % 1000 == 0) {
X 			printf ("%d ", i);
X 			fflush (stdout);
X 		}
X 		i++;
X 
X 		p = &lbuf [ strlen (lbuf) - 1 ];
X 		if (*p == '\n')
X 			*p = 0;
X 
X 		if (makedent (lbuf, &d) < 0)
X 			continue;
X 
X 		d.word = malloc (strlen (lbuf) + 1);
X 		if (d.word == NULL) {
X 			fprintf (stderr, "couldn't allocate space for word %s\n", lbuf);
X 			exit (1);
X 		}
X 		strcpy (d.word, lbuf);
X 
X 		h = hash (lbuf, strlen (lbuf), hashsize);
X 
X 		if (hashtbl[h].used == 0) {
X 			hashtbl[h] = d;
X 
X 		} else {
X 			struct dent *dp;
X 
X 			dp = (struct dent *) malloc (sizeof (struct dent));
X 			if (dp == NULL) {
X 				fprintf (stderr, "couldn't allocate space for collision\n");
X 				exit (1);
X 			}
X 			*dp = d;
X 			dp->next = hashtbl[h].next;
X 			hashtbl[h].next = dp;
X 		}
X 	}
X 	printf ("\n");
X }
X 
X /*
X  * fill in the flags in d, and put a null after the word in s
X  */
X 
X makedent (lbuf, d)
X char *lbuf;
X struct dent *d;
X {
X 	char *p, *index();
X 
X 	d->next = NULL;
X 	d->used = 1;
X 	d->v_flag = 0;
X 	d->n_flag = 0;
X 	d->x_flag = 0;
X 	d->h_flag = 0;
X 	d->y_flag = 0;
X 	d->g_flag = 0;
X 	d->j_flag = 0;
X 	d->d_flag = 0;
X 	d->t_flag = 0;
X 	d->r_flag = 0;
X 	d->z_flag = 0;
X 	d->s_flag = 0;
X 	d->p_flag = 0;
X 	d->m_flag = 0;
X 
X 	p = index (lbuf, '/');
X 	if (p != NULL)
X 		*p = 0;
X 	if (strlen (lbuf) > WORDLEN - 1) {
X 		printf ("%s: word too big\n");
X 		return (-1);
X 	}
X 
X 	if (p == NULL)
X 		return (0);
X 
X 	p++;
X 	while (*p != NULL) {
X 		switch (*p) {
X 		case 'V': d->v_flag = 1; break;
X 		case 'N': d->n_flag = 1; break;
X 		case 'X': d->x_flag = 1; break;
X 		case 'H': d->h_flag = 1; break;
X 		case 'Y': d->y_flag = 1; break;
X 		case 'G': d->g_flag = 1; break;
X 		case 'J': d->j_flag = 1; break;
X 		case 'D': d->d_flag = 1; break;
X 		case 'T': d->t_flag = 1; break;
X 		case 'R': d->r_flag = 1; break;
X 		case 'Z': d->z_flag = 1; break;
X 		case 'S': d->s_flag = 1; break;
X 		case 'P': d->p_flag = 1; break;
X 		case 'M': d->m_flag = 1; break;
X 		case 0:
X  			fprintf (stderr, "no key word %s\n", lbuf);
X 			continue;
X 		default:
X 			fprintf (stderr, "unknown flag %c word %s\n", 
X 					*p, lbuf);
X 			break;
X 		}
X 		p++;
X 		if (*p != '/' && *p != NULL && *p != '\n') {
X 			fprintf (stderr, "bad format %s (%c 0%o)\n", 
X 					lbuf, *p, *p);
X 			break;
X 		}
X 		if (*p)
X 			p++;
X 	
X 	}
X 	return (0);
X }
X 
X newcount ()
X {
X 	char buf[200];
X 	FILE *d;
X 	int i;
X 
X 	fprintf (stderr, "Counting words in dictionary ...\n");
X 
X 	if ((d = fopen (Dfile, "r")) == NULL) {
X 		fprintf (stderr, "Can't open dictionary\n");
X 		exit (1);
X 	}
X 
X 	i = 0;
X 	while (fgets (buf, sizeof buf, d) != NULL) {
X 		i++;
X 		if (i % 1000 == 0) {
X 			printf ("%d ", i);
X 			fflush (stdout);
X 		}
X 	}
X 	fclose (d);
X 	printf ("\n%d words\n", i);
X 	if ((d = fopen (Cfile, "w")) == NULL) {
X 		fprintf (stderr, "can't create %s\n", Cfile);
X 		exit (1);
X 	}
X 	fprintf (d, "%d\n", i);
X 	fclose (d);
X }
SHAR_EOF
if test 6459 -ne "`wc -c < 'buildhash.c'`"
then
	echo shar: error transmitting "'buildhash.c'" '(should have been 6459 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
-- 

	Geoff Kuenning
	{hplabs,ihnp4}!trwrb!desint!geoff

geoff@desint.UUCP (03/14/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:
#	config.h
#	good.c
#	hash.c
#	ispell.c
#	ispell.h
#	lookup.c
#	term.c
#	tree.c
# This archive created: Sat Mar 14 00:59:10 1987
export PATH; PATH=/bin:$PATH
echo shar: extracting "'config.h'" '(2543 characters)'
if test -f 'config.h'
then
	echo shar: will not over-write existing file "'config.h'"
else
sed 's/^X //' << \SHAR_EOF > 'config.h'
X /*
X ** library directory for hash table(s) / default hash table name
X ** If you intend to use multiple dictionary files, I would suggest
X ** LIBDIR be a directory which will contain nothing else, so sensible
X ** names can be constructed for the -d option without conflict.
X */
X #define LIBDIR "/usr/local/lib"
X #define DEFHASH "ispell.hash"
X 
X #ifdef SYSV
X #define index strchr
X #endif
X 
X /* environment variable for user's word list */
X #define PDICTVAR "WORDLIST"
X 
X /* default word list */
X #define DEFPDICT "ispell.words"
X 
X /* mktemp template for temporary file - MUST contain 6 consecutive X's */
X #define TEMPNAME "/usr/tmp/spellXXXXXX"
X 
X /* default dictionary file */
X #define DEFDICT "dict.191"
X 
X /* define LOOK if look(1) command is available */
X #define LOOK
X 
X /* path to egrep (use speeded up version if available) */
X #define EGREPCMD "/usr/local/egrep -i"
X 
X /* path to wordlist for Lookup command (typically /usr/dict/{words|web2} */
X #define WORDS	"/usr/dict/web2"
X 
X /* buffer size to use for file names if not in sys/param.h */
X #ifndef MAXPATHLEN
X #define MAXPATHLEN 240
X #endif
X 
X /* word length allowed in dictionary by buildhash */
X #define WORDLEN 30
X 
X /* hash table magic number */
X #define MAGIC 1
X 
X /* suppress the 8-bit character feature */
X #define NO8BIT
X 
X /* Approximate number of words in the full dictionary, after munching.
X ** Err on the high side unless you are very short on memory, in which
X ** case you might want to change the tables in tree.c and also increase
X ** MAXPCT.
X **
X ** (Note:  dict.191 is a bit over 15000 words.  dict.191 munched with
X ** /usr/dict/words is a little over 28000).
X */
X #define BIG_DICT	29000
X 
X /*
X ** Maximum hash table fullness percentage.  Larger numbers trade space
X ** for time.
X **/
X #define MAXPCT	70		/* Expand table when 70% full */
X 
X /*
X ** the isXXXX macros normally only check ASCII range.  These are used
X ** instead for text characters, which we assume may be 8 bit.  The
X ** NO8BIT ifdef shuts off significance of 8 bit characters.  If you are
X ** using this, and your ctype.h already masks, you can simplify.
X */
X #ifdef NO8BIT
X #define myupper(X) isupper((X)&0x7f)
X #define mylower(X) islower((X)&0x7f)
X #define myspace(X) isspace((X)&0x7f)
X #define myalpha(X) isalpha((X)&0x7f)
X #else
X #define myupper(X) (!((X)&0x80) && isupper(X))
X #define mylower(X) (!((X)&0x80) && islower(X))
X #define myspace(X) (!((X)&0x80) && isspace(X))
X #define myalpha(X) (!((X)&0x80) && isalpha(X))
X #endif
X 
X /*
X ** the NOPARITY mask is applied to user input characters from the terminal
X ** in order to mask out the parity bit.
X */
X #define NOPARITY 0x7f
SHAR_EOF
if test 2543 -ne "`wc -c < 'config.h'`"
then
	echo shar: error transmitting "'config.h'" '(should have been 2543 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'good.c'" '(10274 characters)'
if test -f 'good.c'
then
	echo shar: will not over-write existing file "'good.c'"
else
sed 's/^X //' << \SHAR_EOF > 'good.c'
X /* -*- Mode:Text -*- */
X 
X /*
X  * good.c - see if a word or its root word
X  * is in the dictionary.
X  *
X  * Pace Willisson, 1983
X  */
X 
X #include <stdio.h>
X #include <ctype.h>
X #include "ispell.h"
X #include "config.h"
X 
X struct dent *lookup();
X 
X static int wordok;
X 
X extern int cflag;
X 
X good (w)
X register char *w;
X {
X 	char nword[100];
X 	register char *p, *q;
X 	register n;
X 
X 	for (p = w, q = nword; *p; p++, q++) {
X 		if (mylower (*p))
X 			*q = toupper (*p);
X 		else
X 			*q = *p;
X 	}
X 	*q = 0;
X 
X 	rootword[0] = 0;
X 
X 	if (cflag)
X 		printf ("%s\n", nword);
X 	else if (lookup (nword, q - nword, 1) != NULL) {
X 		return (1);
X 	}
X 
X 	/* try stripping off suffixes */
X 
X 	n = strlen (w);
X 	if (n == 1)
X 		return (1);
X 
X 	if (n < 4)
X 		return 0;
X 
X 	wordok = 0;
X 
X 	/* this part from 'check.mid' */
X 	switch (q[-1]) {
X 	case 'D': d_ending (nword); break;	/* FOR "CREATED", "IMPLIED", "CROSSED" */
X 	case 'T': t_ending (nword); break;	/* FOR "LATEST", "DIRTIEST", "BOLDEST" */
X 	case 'R': r_ending (nword); break;	/* FOR "LATER", "DIRTIER", "BOLDER" */
X 	case 'G': g_ending (nword); break;	/* FOR "CREATING", "FIXING" */
X 	case 'H': h_ending (nword); break;	/* FOR "HUNDREDTH", "TWENTIETH" */
X 	case 'S': s_ending (nword); break;	/* FOR ALL SORTS OF THINGS ENDING IN "S" */
X 	case 'N': n_ending (nword); break;	/* "TIGHTEN", "CREATION", "MULIPLICATION" */
X 	case 'E': e_ending (nword); break;	/* FOR "CREATIVE", "PREVENTIVE" */
X 	case 'Y': y_ending (nword); break;	/* FOR "QUICKLY" */
X 	default:
X 		break;
X 	}
X 	
X 	if (wordok) {
X 		strcpy (rootword, lastdent->word);
X 	}
X 	return (wordok);
X 
X }
X 
X 
X g_ending (w)
X char *w;
X {
X 	char *p;
X 	struct dent *dent;
X 
X 	p = w + strlen (w) - 3;	/* if the word ends in 'ing', then *p == 'i' */
X 	
X 	if (strcmp (p, "ING") != 0)
X 		return;
X 
X 	*p = 'E';	/* change I to E, like in CREATING */
X 	*(p+1) = 0;
X 
X 	if (strlen (w) < 2)
X 		return;
X 
X 	if (cflag)
X 		printf ("%s/G\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 	  &&  dent->g_flag) {
X 		wordok = 1;
X 		return;
X 	}
X 
X 
X 	*p = 0;
X 
X 	if (strlen (w) < 2)
X 		return;
X 
X 	if (p[-1] == 'E')
X 		return;	/* this stops CREATEING */
X 
X 	if (cflag)
X 		printf ("%s/G\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL) {
X 		if (dent->g_flag)
X 			wordok = 1;
X 		return;
X 	}
X 	return;
X }
X 
X d_ending (w)
X char *w;
X {
X 	char *p;
X 	struct dent *dent;
X 
X 	p = w + strlen (w) - 2;
X 
X 	if (strcmp (p, "ED") != 0)
X 		return;
X 
X 	p[1] = 0;	/* kill 'D' */
X 
X 	if (cflag)
X 		printf ("%s/D\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL) { /* eg CREATED */
X 		if (dent->d_flag)
X 			wordok = 1;
X 		return;
X 	}
X 
X 	if (strlen (w) < 3)
X 		return;
X 
X 	p[0] = 0;
X 	p--;
X 
X 	/* ED is now completely gone */
X 
X 	if (p[0] == 'I' && !vowel (p[-1])) {
X 		p[0] = 'Y';
X 		if (cflag)
X 			printf ("%s/D\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 		    &&  dent->d_flag) {
X 			wordok = 1;
X 			return;
X 		}
X 		p[0] = 'I';
X 	}
X 
X 	if ((p[0] != 'E' && p[0] != 'Y') ||
X 	    (p[0] == 'Y' && vowel (p[-1]))) {
X 		if (cflag)
X 			printf ("%s/D\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL) {
X 			if (dent->d_flag)
X 				wordok = 1;
X 			return;
X 		}
X 	}
X }
X 
X t_ending (w)
X char *w;
X {
X 
X 	char *p;
X 	struct dent *dent;
X 
X 	p = w + strlen (w) - 3;
X 
X 	if (strcmp (p, "EST") != 0)
X 		return;
X 
X 	p[1] = 0;	/* kill 'S' */
X 
X 	if (cflag)
X 		printf ("%s/T\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 	    &&  dent->t_flag) {
X 		wordok = 1;
X 		return;
X 	}
X 
X 	if (strlen (w) < 3)
X 		return;
X 
X 	p[0] = 0;
X 	p--;
X 
X 	/* EST is now completely gone */
X 
X 	if (p[0] == 'I' && !vowel (p[-1])) {
X 		p[0] = 'Y';
X 		if (cflag)
X 			printf ("%s/T\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 		    &&  dent->t_flag) {
X 			wordok = 1;
X 			return;
X 		}
X 		p[0] = 'I';
X 	}
X 
X 	if ((p[0] != 'E' && p[0] != 'Y') ||
X 	    (p[0] == 'Y' && vowel (p[-1]))) {
X 		if (cflag)
X 			printf ("%s/T\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL) {
X 			if (dent->t_flag)
X 				wordok = 1;
X 			return;
X 		}
X 	}
X 
X }
X 
X 
X r_ending (w)
X char *w;
X {
X 	char *p;
X 	struct dent *dent;
X 
X 	p = w + strlen (w) - 2;
X 
X 	if (strcmp (p, "ER") != 0)
X 		return;
X 
X 	p[1] = 0;	/* kill 'R' */
X 
X 	if (cflag)
X 		printf ("%s/R\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 	    &&  dent->r_flag) {
X 		wordok = 1;
X 		return;
X 	}
X 
X 	if (strlen (w) < 3)
X 		return;
X 
X 	p[0] = 0;
X 	p--;
X 
X 	/* ER is now completely gone */
X 
X 	if (p[0] == 'I' && !vowel (p[-1])) {
X 		p[0] = 'Y';
X 		if (cflag)
X 			printf ("%s/R\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 		    &&  dent->r_flag) {
X 			wordok = 1;
X 			return;
X 		}
X 		p[0] = 'I';
X 	}
X 
X 	if ((p[0] != 'E' && p[0] != 'Y') ||
X 	    (p[0] == 'Y' && vowel (p[-1]))) {
X 		if (cflag)
X 			printf ("%s/R\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL) {
X 			if (dent->r_flag)
X 				wordok = 1;
X 			return;
X 		}
X 	}
X 
X }
X 
X h_ending (w)
X char *w;
X {
X 	char *p;
X 	struct dent *dent;
X 
X 	p = w + strlen (w) - 2;
X 
X 	if (strcmp (p, "TH") != 0)
X 		return;
X 
X 	*p = 0;
X 
X 	p -= 2;
X 
X 	if (p[1] != 'Y') {
X 		if (cflag)
X 			printf ("%s/H\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 		    &&  dent->h_flag)
X 			wordok = 1;
X 	}
X 
X 	if (strcmp (p, "IE") != 0)
X 		return;
X 
X 	p[0] = 'Y';
X 	p[1] = 0;
X 
X 	if (cflag)
X 		printf ("%s/H\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL)
X 		if (dent->h_flag)
X 			wordok = 1;
X 
X }
X 
X /*
X  * check for flags: X, J, Z, S, P, M
X  *
X  * X	-ions or -ications or -ens
X  * J	-ings
X  * Z	-ers or -iers
X  * S	-ies or -es or -s
X  * P	-iness or -ness
X  * M	-'S
X  */
X 
X s_ending (w)
X char *w;
X {
X 	char *p;
X 	struct dent *dent;
X 
X 	p = w + strlen (w);
X 
X 	p[-1] = 0;
X 
X 	if (index ("SXZHY", p[-2]) == NULL || (p[-2] == 'Y' && vowel (p[-3]))) {
X 		if (cflag)
X 			printf ("%s/S\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 		    &&  dent->s_flag) {
X 			wordok = 1;
X 			return;
X 		}
X 	}
X 
X 
X 	switch (p[-2]) {	/* letter before S */
X 	case 'N':	/* X */
X 		if (strcmp (p-4, "ION") == 0) {
X 			p[-4] = 'E';
X 			p[-3] = 0;
X 			if (cflag)
X 				printf ("%s/X\n", w);
X 			else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 			  &&  dent->x_flag) {
X 				wordok = 1;
X 				return;
X 			}
X 		}
X 		if (strcmp (p-8, "ICATE") == 0) {
X 			p[-8] = 'Y';
X 			p[-7] = 0;
X 			if (cflag)
X 				printf ("%s/X\n", w);
X 			else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 			    && dent->x_flag)
X 				wordok = 1;
X 			return;
X 		}
X 		if (strcmp (p-3, "EN") == 0 && p[-4] != 'E' && p[-4] != 'Y') {
X 			p[-3] = 0;
X 			if (cflag)
X 				printf ("%s/X\n", w);
X 			else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 			    && dent->x_flag)
X 				wordok = 1;
X 			return;
X 		}
X 	case 'G':	/* J */
X 		if (strcmp (p-4, "ING") != 0)
X 			return;
X 		p[-4] = 'E';
X 		p[-3] = 0;
X 		if (cflag)
X 			printf ("%s/J\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 		    &&  dent->j_flag) {
X 			wordok = 1;
X 			return;
X 		}
X 		if (p[-5] == 'E')
X 			return;		/* This stops CREATEING */
X 		p[-4] = 0;
X 		if (cflag)
X 			printf ("%s/J\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 		    && dent->j_flag)
X 			wordok = 1;
X 		return;
X 	case 'R':	/* Z */
X 		if (strcmp (p-3, "ER") != 0)
X 			return;
X 
X 		p[-2] = 0;
X 		if (cflag)
X 			printf ("%s/Z\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 		    &&  dent->z_flag) {
X 			wordok = 1;
X 			return;
X 		}
X 		if (p[-4] == 'I'  &&  !vowel (p[-5])) {
X 			p[-4] = 'Y';
X 			p[-3] = 0;
X 			if (cflag)
X 				printf ("%s/Z\n", w);
X 			else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 			    && dent->z_flag) {
X 				wordok = 1;
X 				return;
X 			}
X 			p[-4] = 'I';
X 		}
X 		if ((p[-4] != 'E' && p[-4] != 'Y') ||
X 		    (p[-4] == 'Y' && vowel (p[-5]))) {
X 			p[-3] = 0;
X 			if (cflag)
X 				printf ("%s/Z\n", w);
X 			else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 			  && dent->z_flag)
X 				wordok = 1;
X 		}
X 		return;
X 	case 'E': /* S (except simple adding of an S) */
X 		p[-2] = 0;	/* drop the ES */
X 		if (index ("SXZH", p[-3]) != NULL) {
X 			if (cflag)
X 				printf ("%s/S\n", w);
X 			else if ((dent = lookup (w, strlen (w), 1)) != NULL) {
X 				if (dent->s_flag)
X 					wordok = 1;;
X 				return;
X 			}
X 		}
X 		if (p[-3] == 'I') {
X 			p[-3] = 'Y';
X 			if (cflag)
X 				printf ("%s/S\n", w);
X 			else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 			    && dent->s_flag)
X 				wordok = 1;
X 			return;
X 		}
X 		return;
X 
X 	case 'S':	/* P */
X 		if (strcmp (p-4, "NES") != 0)
X 			return;
X 
X 		p[-4] = 0;	/* kill 'N' */
X 		if (p[-5] != 'Y' || vowel (p[-6])) {
X 			if (cflag)
X 				printf ("%s/P\n", w);
X 			else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 			    &&  dent->p_flag) {
X 				wordok = 1;
X 				return;
X 			}
X 		}
X 		if (p[-5] == 'I') {
X 			p[-5] = 'Y';
X 			if (cflag)
X 				printf ("%s/P\n", w);
X 			else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 			    && dent->p_flag)
X 				wordok = 1;
X 		}
X 		return;
X 	case '\'':	/* M */
X 		p[-2] = '\0';
X 		if (cflag)
X 			printf ("%s/M\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 		    &&  dent->m_flag)
X 			wordok = 1;
X 		return;
X 	}
X }
X 
X /* only the N flag */
X n_ending (w)
X char *w;
X {
X 	char *p;
X 	struct dent *dent;
X 
X 	p = w + strlen (w);
X 
X 	if (p[-2] == 'E') {
X 		if (p[-3] == 'E' || p[-3] == 'Y')
X 			return;
X 		p[-2] = 0;
X 		if (cflag)
X 			printf ("%s/N\n", w);
X 		else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 		    && dent->n_flag)
X 			wordok = 1;
X 		return;
X 	}
X 
X 	if (strcmp (p-3, "ION") != 0)
X 		return;
X 
X 	p[-3] = 'E';
X 	p[-2] = 0;
X 
X 	if (cflag)
X 		printf ("%s/N\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL) {
X 		if (dent->n_flag)
X 			wordok = 1;
X 		return;
X 	}
X 
X 	if (strcmp (p-7, "ICATE") != 0)	/* check is really against "ICATION" */
X 		return;
X 
X 	p[-7] = 'Y';
X 	p[-6] = 0;
X 	
X 	if (cflag)
X 		printf ("%s/N\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL && dent->n_flag)
X 		wordok = 1;
X 	return;
X }
X 
X /* flags: v */
X e_ending (w)
X char *w;
X {
X 	char *p;
X 	struct dent *dent;
X 
X 	p = w + strlen (w);
X 
X 	if (strcmp (p-3, "IVE") != 0)
X 		return;
X 	p[-3] = 'E';
X 	p[-2] = 0;
X 
X 	if (cflag)
X 		printf ("%s/V\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL
X 	  &&  dent->v_flag) {
X 		wordok = 1;
X 		return;
X 	}
X 
X 	if (p[-4] == 'E')
X 		return;
X 
X 	p[-3] = 0;
X 
X 	if (cflag)
X 		printf ("%s/V\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL && dent->v_flag)
X 		wordok = 1;
X 	return;
X }
X 
X /* flags: y */
X y_ending (w)
X char *w;
X {
X 	char *p;
X 	struct dent *dent;
X 
X 	p = w + strlen (w);
X 
X 	if (strcmp (p-2, "LY") != 0)
X 		return;
X 
X 	p[-2] = 0;
X 
X 	if (cflag)
X 		printf ("%s/Y\n", w);
X 	else if ((dent = lookup (w, strlen (w), 1)) != NULL && dent->y_flag)
X 		wordok = 1;
X 	return;
X }
X 
X vowel (c)
X char c;
X {
X 	return (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U');
X }
SHAR_EOF
if test 10274 -ne "`wc -c < 'good.c'`"
then
	echo shar: error transmitting "'good.c'" '(should have been 10274 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'hash.c'" '(343 characters)'
if test -f 'hash.c'
then
	echo shar: will not over-write existing file "'hash.c'"
else
sed 's/^X //' << \SHAR_EOF > 'hash.c'
X /* -*- Mode:Text -*- */
X /*
X  * hash.c - a simple hash function for ispell
X  *
X  * Pace Willisson, 1983
X  */
X 
X hash (s, n, hashsize)
X register char *s;
X register n;
X register hashsize;
X {
X 	register short h = 0;
X 
X 	while (n--) {
X 		h ^= *s++;
X 		if (h < 0) {
X 			h <<= 1;
X 			h++;
X 		} else {
X 			h <<= 1;
X 		}
X 	}
X 
X 	h &= 077777;
X 	return (h %= hashsize);
X }
X 
X 
X 
X 		
SHAR_EOF
if test 343 -ne "`wc -c < 'hash.c'`"
then
	echo shar: error transmitting "'hash.c'" '(should have been 343 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ispell.c'" '(16239 characters)'
if test -f 'ispell.c'
then
	echo shar: will not over-write existing file "'ispell.c'"
else
sed 's/^X //' << \SHAR_EOF > 'ispell.c'
X /* -*- Mode:Text -*- */
X 
X /*
X  * ispell.c - An interactive spelling corrector.
X  *
X  * Copyright (c), 1983, by Pace Willisson
X  * Permission for non-profit use is hereby granted.
X  * All other rights reserved.
X  *
X  * 1987, Robert McQueer, added:
X  *	-w option & handling of extra legal word characters
X  *	-d option for alternate dictionary file
X  *	-p option & WORDLIST variable for alternate personal dictionary
X  *	-x option to suppress .bak files.
X  *	8 bit text & config.h parameters
X  * 1987, Geoff Kuenning, added:
X  *	-c option for creating suffix suggestions from raw words
X  *	suffixes in personal dictionary file
X  *	hashed personal dictionary file
X  */
X 
X #include <stdio.h>
X #include <ctype.h>
X #include <sys/param.h>
X #include "ispell.h"
X #include "config.h"
X 
X FILE *infile;
X FILE *outfile;
X 
X char hashname[MAXPATHLEN];
X 
X extern struct dent *treeinsert();
X 
X /*
X ** we use extended character set range specifically to allow intl.
X ** character set characters.  We are being REALLY paranoid about indexing
X ** this array - explicitly cast into unsigned INTEGER, then mask
X ** If NO8BIT is set, text will be masked to ascii range.
X */
X static int Trynum;
X #ifdef NO8BIT
X static char Try[128];
X static char Checkch[128];
X #define iswordch(X) (Checkch[((unsigned)(X))&0x7f])
X #else
X static char Try[256];
X static char Checkch[256];
X #define iswordch(X) (Checkch[((unsigned)(X))&0xff])
X #endif
X 
X givehelp ()
X {
X 	erase ();
X 	printf ("Whenever a word is found that is not in the dictionary,\r\n");
X 	printf ("it is printed on the first line of the screen.  If the dictionary\r\n");
X 	printf ("contains any similar words, they are listed with a single digit\r\n");
X 	printf ("next to each one.  You have the option of replacing the word\r\n");
X 	printf ("completely, or choosing one of the suggested words.\r\n");
X 	printf ("\r\n");
X 	printf ("Commands are:\r\n\r\n");
X 	printf ("R       Replace the misspelled word completely.\r\n");
X 	printf ("Space   Accept the word this time only\r\n");
X 	printf ("A       Accept the word for the rest of this file.\r\n");
X 	printf ("I       Accept the word, and put it in your private dictionary.\r\n");
X 	printf ("0-9     Replace with one of the suggested words.\r\n");
X 	printf ("L       Look up words in system dictionary.\r\n");
X 	printf ("Q       Write the rest of this file, ignoring misspellings, ");
X 	printf (         "and start next file.\r\n");
X 	printf ("X       Exit immediately.  Asks for confirmation.  ");
X 	printf (         "Leaves file unchanged.\r\n");
X 	printf ("!       Shell escape.\r\n");
X 	printf ("^L      Redraw screen.\r\n");
X 	printf ("\r\n\r\n");
X 	printf ("-- Type space to continue --");
X 	fflush (stdout);
X 	getchar ();
X }
X 
X 
X char *getline();
X 
X int cflag = 0;
X int lflag = 0;
X int aflag = 0;
X int fflag = 0;
X #ifndef USG
X int sflag = 0;
X #endif
X int xflag = 0;
X 
X char *askfilename;
X 
X static char *Cmd;
X 
X usage ()
X {
X 	fprintf (stderr, "Usage: %s [-dfile | -pfile | -wchars | -x] file .....\n",Cmd);
X 	fprintf (stderr, "       %s [-dfile | -pfile | -wchars] -l\n",Cmd);
X #ifdef USG
X 	fprintf (stderr, "       %s [-dfile | -pfile | -ffile | -s] -a\n",Cmd);
X #else
X 	fprintf (stderr, "       %s [-dfile | -pfile | -ffile] -a\n",Cmd);
X #endif
X 	fprintf (stderr, "       %s [-wchars] -c\n");
X 	exit (1);
X }
X 
X static initckch()
X {
X 	int c;
X 
X 	Trynum = 0;
X #ifdef NO8BIT
X 	for (c = 0; c < 128; ++c) {
X #else
X 	for (c = 0; c < 256; ++c) {
X #endif
X 		if (myalpha((char) c)) {
X 			Checkch[c] = (char) 1;
X 			if (myupper((char) c)) {
X 				Try[Trynum] = (char) c;
X 				++Trynum;
X 			}
X 		}
X 		else
X 			Checkch[c] = (char) 0;
X 	}
X }
X 
X main (argc, argv)
X char **argv;
X {
X 	char *p;
X 	char *cpd;
X 	char num[4];
X 	unsigned mask;
X 
X 	Cmd = *argv;
X 
X 	initckch();
X 	sprintf(hashname,"%s/%s",LIBDIR,DEFHASH);
X 
X 	cpd = NULL;
X 
X 	argv++;
X 	argc--;
X 	while (argc && **argv == '-') {
X 		switch ((*argv)[1]) {
X 		case 'a':
X 			aflag++;
X 			break;
X 		case 'c':
X 			cflag++;
X 			lflag++;
X 			break;
X 		case 'x':
X 			xflag++;
X 			break;
X 		case 'f':
X 			fflag++;
X 			p = (*argv)+2;
X 			if (*p == '\0') {
X 				argv++; argc--;
X 				if (argc == 0)
X 					usage ();
X 				p = *argv;
X 			}
X 			askfilename = p;
X 			break;
X 		case 'l':
X 			lflag++;
X 			break;
X #ifndef USG
X 		case 's':
X 			sflag++;
X 			break;
X #endif
X 		case 'p':
X 			cpd = (*argv)+2;
X 			if (*cpd == '\0') {
X 				argv++; argc--;
X 				if (argc == 0)
X 					usage ();
X 				cpd = *argv;
X 			}
X 			break;
X 		case 'd':
X 			p = (*argv)+2;
X 			if (*p == '\0') {
X 				argv++; argc--;
X 				if (argc == 0)
X 					usage ();
X 				p = *argv;
X 			}
X 			if (*p == '/')
X 				strcpy(hashname,p);
X 			else
X 				sprintf(hashname,"%s/%s",LIBDIR,p);
X 			break;
X 		case 'w':
X 			num[3] = '\0';
X #ifdef NO8BIT
X 			mask = 0x7f;
X #else
X 			mask = 0xff;
X #endif
X 			p = (*argv)+2;
X 			if (*p == '\0') {
X 				argv++; argc--;
X 				if (argc == 0)
X 					usage ();
X 				p = *argv;
X 			}
X 			while (Trynum <= mask && *p != '\0') {
X 				if (*p != 'n') {
X 					Checkch[((unsigned)(*p))&mask] = (char) 1;
X 					Try[Trynum] = *p & mask;
X 					++p;
X 				}
X 				else {
X 					++p;
X 					num[0] = *p; ++p;
X 					num[1] = *p; ++p;
X 					num[2] = *p; ++p;
X 					Try[Trynum] = atoi(num) & mask;
X 					Checkch[atoi(num)&mask] = (char) 1;
X 				}
X 				++Trynum;
X 			}
X 			break;
X 		default:
X 			usage();
X 		}
X 		argv++; argc--;
X 	}
X 
X 	if (!argc && !lflag && !aflag)
X 		usage ();
X 
X 	if (linit () < 0)
X 		exit (0);
X 
X 	treeinit (cpd);
X 
X 	if (aflag) {
X 		askmode ();
X 		exit (0);
X 	}
X 
X 	if (lflag) {
X 		infile = stdin;
X 		checkfile ();
X 		exit (0);
X 	}
X 
X 	terminit ();
X 
X 	while (argc--)
X 		dofile (*argv++);
X 
X 	done ();
X }
X 
X char firstbuf[BUFSIZ], secondbuf[BUFSIZ];
X char *currentchar;
X char token[BUFSIZ];
X 
X int quit;
X 
X char *currentfile = NULL;
X 
X dofile (filename)
X char *filename;
X {
X 	int c;
X 	char	bakfile[256];
X 
X 	currentfile = filename;
X 
X 	if ((infile = fopen (filename, "r")) == NULL) {
X 		fprintf (stderr, "Can't open %s\r\n", filename);
X 		sleep (2);
X 		return;
X 	}
X 
X 	if (access (filename, 2) < 0) {
X 		fprintf (stderr, "Can't write to %s\r\n", filename);
X 		sleep (2);
X 		return;
X 	}
X 
X 	strcpy(tempfile, TEMPNAME);
X 	mktemp (tempfile);
X 	if ((outfile = fopen (tempfile, "w")) == NULL) {
X 		fprintf (stderr, "Can't create %s\r\n", tempfile);
X 		sleep (2);
X 		return;
X 	}
X 
X 	quit = 0;
X 
X 	checkfile ();
X 
X 	fclose (infile);
X 	fclose (outfile);
X 
X 	if (!cflag)
X 		treeoutput ();
X 
X 	if ((infile = fopen (tempfile, "r")) == NULL) {
X 		fprintf (stderr, "tempoary file disappeared (%s)\r\n", tempfile);	
X 		sleep (2);
X 		return;
X 	}
X 
X 	sprintf(bakfile, "%s.bak", filename);
X 	if(link(filename, bakfile) == 0)
X 		unlink(filename);
X 
X 	/* if we can't write new, preserve .bak regardless of xflag */
X 	if ((outfile = fopen (filename, "w")) == NULL) {
X 		fprintf (stderr, "can't create %s\r\n", filename);
X 		sleep (2);
X 		return;
X 	}
X 
X 	while ((c = getc (infile)) != EOF)
X 		putc (c, outfile);
X 
X 	fclose (infile);
X 	fclose (outfile);
X 
X 	unlink (tempfile);
X 	if (xflag)
X 		unlink(bakfile);
X }
X 
X checkfile ()
X {
X 	int c;
X 	char *p;
X 	int len;
X 
X 	secondbuf[0] = 0;
X 	currentchar = secondbuf;
X 
X 	while (1) {
X 		strcpy (firstbuf, secondbuf);
X 		if (quit) {	/* quit can't be set in l mode */
X 			while (fgets (secondbuf, sizeof secondbuf, infile) != NULL)
X 				fputs (secondbuf, outfile);
X 			break;
X 		}
X 
X 		if (fgets (secondbuf, sizeof secondbuf, infile) == NULL)
X 			break;
X 		currentchar = secondbuf;
X 		
X 		len = strlen (secondbuf) - 1;
X 		if (secondbuf [ len ] == '\n')
X 			secondbuf [ len ] = 0;
X 
X 		/* if this is a formatter command, skip over it */
X 		if (*currentchar == '.') {
X 			while (*currentchar && !myspace (*currentchar)) {
X 				if (!lflag)
X 					putc (*currentchar, outfile);
X 				currentchar++;
X 			}
X 			if (*currentchar == 0) {
X 				if (!lflag)
X 					putc ('\n', outfile);
X 				continue;
X 			}
X 		}
X 
X 		while (1) {
X 			while (*currentchar && !iswordch(*currentchar)) {
X 				/* formatting escape sequences */
X 				if (*currentchar == '\\') {
X 				    if(currentchar[1] == 'f') {
X 					/* font change: \fX */
X 					copyout(&currentchar, 3);
X 					continue;
X 				    }
X 				    else if(currentchar[1] == 's') {
X 					/* size change */
X 					if(currentchar[2] < 6 &&
X 					   currentchar[2] != 0)
X 						/* two digit size */
X 						copyout(&currentchar, 4);
X 					else
X 						/* one digit size */
X 						copyout(&currentchar, 3);
X 					continue;
X 				    }
X 				    else if(currentchar[1] == '(') {
X 					/* extended char set escape: \(XX */
X 					copyout(&currentchar, 4);
X 					continue;
X 				    }
X 				}
X 
X 				if (!lflag)
X 					putc (*currentchar, outfile);
X 				currentchar++;
X 			}
X 
X 			if (*currentchar == 0)
X 				break;
X 
X 			p = token;
X 			while (iswordch(*currentchar) ||
X 			       (*currentchar == '\'' &&
X 				iswordch(*(currentchar + 1))))
X 			  *p++ = *currentchar++;
X 			*p = 0;
X 			if (lflag) {
X 				if (!good (token)  &&  !cflag)
X 					printf ("%s\r\n", token);
X 			} else {
X 				if (!quit)
X 				correct (token, &currentchar);
X 			}
X 			if (!lflag)
X 				fprintf (outfile, "%s", token);
X 		}
X 		if (!lflag)
X 			putc ('\n', outfile);
X 	}
X }
X 
X char possibilities[10][BUFSIZ];
X int pcount;
X 
X correct (token, currentchar)
X char *token;
X char **currentchar;
X {
X 	int c;
X 	int i;
X 	char *p;
X 	int len;
X 	char *begintoken;
X 
X 	len = strlen (token);
X 	begintoken = *currentchar - len;
X 
X checkagain:
X 	if (good (token))
X 		return;
X 
X 	erase ();
X 	printf ("    %s", token);
X 	if (currentfile)
X 		printf ("              File: %s", currentfile);
X 	printf ("\r\n\r\n");
X 
X 	makepossibilities (token);
X 
X 	for (i = 0; i < 10; i++) {
X 		if (possibilities[i][0] == 0)
X 			break;
X 		printf ("%d: %s\r\n", i, possibilities[i]);
X 	}
X 
X 	move (15, 0);
X 	printf ("%s\r\n", firstbuf);
X 
X 	for (p = secondbuf; p != begintoken; p++)
X 		putchar (*p);
X 	inverse ();
X 	for (i = strlen (token); i > 0; i--)
X 		putchar (*p++);
X 	normal ();
X 	while (*p)
X 		putchar (*p++);
X 	printf ("\r\n");
X 
X 	while (1) {
X 		switch (c = (getchar () & NOPARITY)) {
X #ifndef USG
X 		case 'Z' & 037:
X 			stop ();
X 			erase ();
X 			goto checkagain;
X #endif
X 		case ' ':
X 			erase ();
X 			return;
X 		case 'x': case 'X':
X 			printf ("Are you sure you want to throw away your changes? ");
X 			c = (getchar () & NOPARITY);
X 			if (c == 'y' || c == 'Y') {
X 				erase ();
X 				done ();
X 			}
X 			putchar (7);
X 			goto checkagain;
X 		case 'i': case 'I':
X 			treeinsert (token, 1);
X 			erase ();
X 			return;
X 		case 'a': case 'A':
X 			treeinsert (token, 0);
X 			erase ();
X 			return;
X 		case 'L' & 037:
X 			goto checkagain;
X 		case '?':
X 			givehelp ();
X 			goto checkagain;
X 		case '!':
X 			{
X 				char buf[200];
X 				move (18, 0);
X 				putchar ('!');
X 				if (getline (buf) == NULL) {
X 					putchar (7);
X 					erase ();
X 					goto checkagain;
X 				}
X 				printf ("\r\n");
X 				shellescape (buf);
X 				erase ();
X 				goto checkagain;
X 			}
X 		case 'r': case 'R':
X 			move (18, 0);
X 			printf ("Replace with: ");
X 			if (getline (token) == NULL) {
X 				putchar (7);
X 				erase ();
X 				goto checkagain;
X 			}
X 			inserttoken (secondbuf, begintoken, token, currentchar);
X 			erase ();
X 			goto checkagain;
X 		case '0': case '1': case '2': case '3': case '4':
X 		case '5': case '6': case '7': case '8': case '9':
X 			if (possibilities[c - '0'][0] != 0) {
X 				strcpy (token, possibilities[c - '0']);
X 				inserttoken (secondbuf, begintoken, token, currentchar);				erase ();
X 				return;
X 			}
X 			putchar (7);
X 			break;
X 		case 'l': case 'L':
X 			{
X 				char buf[100];
X 				move (18, 0);
X 				printf ("Lookup string ('*' is wildcard): ");
X 				if (getline (buf) == NULL) {
X 					putchar (7);
X 					erase ();
X 					goto checkagain;
X 				}
X 				printf ("\r\n\r\n");
X 				lookharder (buf);
X 				erase ();
X 				goto checkagain;
X 			}
X 		case 'q': case 'Q':
X 			quit = 1;
X 			erase ();
X 			return;
X 		default:
X 			putchar (7);
X 			break;
X 		}
X 	}
X }
X 
X inserttoken (buf, start, token, currentchar)
X char *buf, *start, *token;
X char **currentchar;
X {
X 	char copy[BUFSIZ];
X 	char *p, *q;
X 
X 	strcpy (copy, buf);
X 
X 	for (p = buf, q = copy; p != start; p++, q++)
X 		*p = *q;
X 	while (*token)
X 		*p++ = *token++;
X 	q += *currentchar - start;
X 	*currentchar = p;
X 	while (*p++ = *q++)
X 		;
X }
X 
X 
X makepossibilities (word)
X char word[];
X {
X 	int i;
X 
X 	for (i = 0; i < 10; i++)
X 		possibilities[i][0] = 0;
X 	pcount = 0;
X 
X 	if (pcount < 10) wrongletter (word);
X 	if (pcount < 10) extraletter (word);
X 	if (pcount < 10) missingletter (word);
X 	if (pcount < 10) transposedletter (word);
X 
X }
X 
X char *cap();
X 
X insert (word)
X char *word;
X {
X 	int i;
X 
X 	for (i = 0; i < pcount; i++)
X 		if (strcmp (possibilities[i], word) == 0)
X 			return (0);
X 
X 	strcpy (possibilities[pcount++], word);
X 	if (pcount >= 10)
X 		return (-1);
X 	else
X 		return (0);
X }
X 
X wrongletter (word)
X char word[];
X {
X 	int i, j, c, n;
X 	char newword[BUFSIZ];
X 
X 	n = strlen (word);
X 	strcpy (newword, word);
X 
X 	for (i = 0; i < n; i++) {
X 		for (j=0; j < Trynum; ++j) {
X 			newword[i] = Try[j];
X 			if (good (newword)) {
X 				if (insert (cap (newword, word)) < 0)
X 					return;
X 			}
X 		}
X 		newword[i] = word[i];
X 	}
X }
X 
X extraletter (word)
X char word[];
X {
X 	char newword[BUFSIZ], *p, *s, *t;
X 
X 	if (strlen (word) < 3)
X 		return;
X 
X 	for (p = word; *p; p++) {
X 		for (s = word, t = newword; *s; s++)
X 			if (s != p)
X 				*t++ = *s;
X 		*t = 0;
X 		if (good (newword)) {
X 			if (insert (cap (newword, word)) < 0)
X 				return;
X 		}
X 	}
X }
X 
X missingletter (word)
X char word[];
X {
X 	char newword[BUFSIZ], *p, *r, *s, *t;
X 	int i;
X 
X 	for (p = word; p == word || p[-1]; p++) {
X 		for (s = newword, t = word; t != p; s++, t++)
X 			*s = *t;
X 		r = s++;
X 		while (*t)
X 			*s++ = *t++;
X 		*s = 0;
X 		for (i=0; i < Trynum; ++i) {
X 			*r = Try[i];
X 			if (good (newword)) {
X 				if (insert (cap (newword, word)) < 0)
X 					return;
X 			}
X 		}
X 	}
X }
X 
X transposedletter (word)
X char word[];
X {
X 	char newword[BUFSIZ];
X 	int t;
X 	char *p;
X 
X 	strcpy (newword, word);
X 	for (p = newword; p[1]; p++) {
X 		t = p[0];
X 		p[0] = p[1];
X 		p[1] = t;
X 		if (good (newword)) {
X 			if (insert (cap (newword, word)) < 0)
X 				return;
X 		}
X 		t = p[0];
X 		p[0] = p[1];
X 		p[1] = t;
X 	}
X }
X 
X char *
X cap (word, pattern)
X char word[], pattern[];
X {
X 	static char newword[BUFSIZ];
X 	char *p, *q;
X 
X 	if (*word == 0)
X 		return;
X 
X 	if (myupper (pattern[0])) {
X 		if (myupper (pattern[1])) {
X 			for (p = word, q = newword; *p; p++, q++) {
X 				if (mylower (*p))
X 					*q = toupper (*p);
X 				else
X 					*q = *p;
X 			}
X 			*q = 0;
X 		} else {
X 			if (mylower (word [0]))
X 				newword[0] = toupper (word[0]);
X 			else
X 				newword[0] = word[0];
X 
X 			for (p = word + 1, q = newword + 1; *p; p++, q++)
X 				if (myupper (*p))
X 					*q = tolower (*p);
X 				else
X 					*q = *p;
X 
X 			*q = 0;
X 		}
X 	} else {
X 		for (p = word, q = newword; *p; p++, q++)
X 			if (myupper (*p))
X 				*q = tolower (*p);
X 			else
X 				*q = *p;
X 		*q = 0;
X 	}
X 	return (newword);
X }
X 
X char *
X getline (s)
X char *s;
X {
X 	char *p;
X 	int c;
X 
X 	p = s;
X 
X 	while (1) {
X 		c = (getchar () & NOPARITY);
X 		if (c == '\\') {
X 			putchar ('\\');
X 			c = (getchar () & NOPARITY);
X 			backup ();
X 			putchar (c);
X 			*p++ = c;
X 		} else if (c == ('G' & 037)) {
X 			return (NULL);
X 		} else if (c == '\n' || c == '\r') {
X 			*p = 0;
X 			return (s);
X 		} else if (c == erasechar) {
X 			if (p != s) {
X 				p--;
X 				backup ();
X 				putchar (' ');
X 				backup ();
X 			}
X 		} else if (c == killchar) {
X 			while (p != s) {
X 				p--;
X 				backup ();
X 				putchar (' ');
X 				backup ();
X 			}
X 		} else {
X 			*p++ = c;
X 			putchar (c);
X 		}
X 	}
X }
X 
X askmode ()
X {
X 	char buf[BUFSIZ];
X 	int i;
X 
X 	if (fflag) {
X 		if (freopen (askfilename, "w", stdout) == NULL) {
X 			fprintf (stderr, "Can't create %s\n", askfilename);
X 			exit (1);
X 		}
X 	}
X 
X 	setbuf (stdin, NULL);
X 	setbuf (stdout, NULL);
X 
X 	while (gets (buf) != NULL) {
X 		if (good (buf)) {
X 			if (rootword[0] == 0) {
X 				printf ("*\n");	/* perfect match */
X 			} else {
X 				printf ("+ %s\n", rootword);
X 			}
X 		} else {
X 			makepossibilities (buf);
X 			if (possibilities[0][0]) {
X 				printf ("& ");
X 				for (i = 0; i < 10; i++) {
X 					if (possibilities[i][0] == 0)
X 						break;
X 					printf ("%s ", possibilities[i]);
X 				}
X 				printf ("\n");
X 			} else {
X 				printf ("#\n");
X 			}
X 		}
X #ifndef USG
X 		if (sflag) {
X 			stop ();
X 			if (fflag) {
X 				rewind (stdout);
X 				creat (askfilename, 0666);
X 			}
X 		}
X #endif
X 	}
X }
X 
X 
X copyout(cc, cnt)
X char	**cc;
X {
X 	while (--cnt >= 0) {
X 		if (*(*cc) == 0)
X 			break;
X 		if (!lflag)
X 			putc (*(*cc), outfile);
X 		(*cc)++;
X 	}
X 
X }
X 
X lookharder(string)
X char *string;
X {
X 	char cmd[150];
X 	char *g, *s, grepstr[100];
X 	int wild = 0;
X 
X 	g = grepstr;
X 	for (s = string; *s != '\0'; s++)
X 		if (*s == '*') {
X 			wild++;
X 			*g++ = '.';
X 			*g++ = '*';
X 		} else
X 			*g++ = *s;
X 	*g = '\0';
X 	if (grepstr[0]) {
X #ifdef LOOK
X 		if (wild)
X 			/* string has wild card characters */
X 			sprintf (cmd, "%s '^%s$' %s", EGREPCMD, grepstr, WORDS);
X 		else
X 			/* no wild, use look(1) */
X 			sprintf (cmd, "/usr/bin/look -df %s %s", grepstr, WORDS);
X #else
X 		sprintf (cmd, "%s '^%s$' %s", EGREPCMD, grepstr, WORDS);
X #endif
X 		shellescape (cmd);
X 	}
X }
SHAR_EOF
if test 16239 -ne "`wc -c < 'ispell.c'`"
then
	echo shar: error transmitting "'ispell.c'" '(should have been 16239 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ispell.h'" '(4964 characters)'
if test -f 'ispell.h'
then
	echo shar: will not over-write existing file "'ispell.h'"
else
sed 's/^X //' << \SHAR_EOF > 'ispell.h'
X /* -*- Mode: Text -*- */
X 
X #define LIBDIR "/tmp2/lib"
X 
X struct dent {
X 	struct dent *next;
X 	char *word;
X 
X 	unsigned short used : 1;
X 
X /* bit fields for all of the flags */
X 	unsigned short v_flag : 1;
X 		/*
X 			"V" flag:
X 		        ...E --> ...IVE  as in CREATE --> CREATIVE
X 		        if # .ne. E, ...# --> ...#IVE  as in PREVENT --> PREVENTIVE
X 		*/
X 	unsigned short n_flag : 1;
X 		/*
X 			"N" flag:
X 			        ...E --> ...ION  as in CREATE --> CREATION
X 			        ...Y --> ...ICATION  as in MULTIPLY --> MULTIPLICATION
X 			        if # .ne. E or Y, ...# --> ...#EN  as in FALL --> FALLEN
X 		*/
X 	unsigned short x_flag : 1;
X 		/*
X 			"X" flag:
X 			        ...E --> ...IONS  as in CREATE --> CREATIONS
X 			        ...Y --> ...ICATIONS  as in MULTIPLY --> MULTIPLICATIONS
X 			        if # .ne. E or Y, ...# --> ...#ENS  as in WEAK --> WEAKENS
X 		*/
X 	unsigned short h_flag : 1;
X 		/*
X 			"H" flag:
X 			        ...Y --> ...IETH  as in TWENTY --> TWENTIETH
X 			        if # .ne. Y, ...# --> ...#TH  as in HUNDRED --> HUNDREDTH
X 		*/
X 	unsigned short y_flag : 1;
X 		/*
X 			"Y" FLAG:
X 			        ... --> ...LY  as in QUICK --> QUICKLY
X 		*/
X 	unsigned short g_flag : 1;
X 		/*
X 			"G" FLAG:
X 			        ...E --> ...ING  as in FILE --> FILING
X 			        if # .ne. E, ...# --> ...#ING  as in CROSS --> CROSSING
X 		*/
X 	unsigned short j_flag : 1;
X 		/*
X 			"J" FLAG"
X 			        ...E --> ...INGS  as in FILE --> FILINGS
X 			        if # .ne. E, ...# --> ...#INGS  as in CROSS --> CROSSINGS
X 		*/
X 	unsigned short d_flag : 1;
X 		/*
X 			"D" FLAG:
X 			        ...E --> ...ED  as in CREATE --> CREATED
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@IED  as in IMPLY --> IMPLIED
X 			        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X 			                ...@# --> ...@#ED  as in CROSS --> CROSSED
X 			                                or CONVEY --> CONVEYED
X 		*/
X 	unsigned short t_flag : 1;
X 		/*
X 			"T" FLAG:
X 			        ...E --> ...EST  as in LATE --> LATEST
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@IEST  as in DIRTY --> DIRTIEST
X 			        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X 			                ...@# --> ...@#EST  as in SMALL --> SMALLEST
X 			                                or GRAY --> GRAYEST
X 		*/
X 	unsigned short r_flag : 1;
X 		/*
X 			"R" FLAG:
X 			        ...E --> ...ER  as in SKATE --> SKATER
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@IER  as in MULTIPLY --> MULTIPLIER
X 			        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X 			                ...@# --> ...@#ER  as in BUILD --> BUILDER
X 			                                or CONVEY --> CONVEYER
X 		*/
X 	unsigned short z_flag : 1;
X 		/*
X 			"Z FLAG:
X 			        ...E --> ...ERS  as in SKATE --> SKATERS
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@IERS  as in MULTIPLY --> MULTIPLIERS
X 			        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X 			                ...@# --> ...@#ERS  as in BUILD --> BUILDERS
X 			                                or SLAY --> SLAYERS
X 		*/
X 	unsigned short s_flag : 1;
X 		/*
X 			"S" FLAG:
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@IES  as in IMPLY --> IMPLIES
X 			        if # .eq. S, X, Z, or H,
X 			                ...# --> ...#ES  as in FIX --> FIXES
X 			        if # .ne. S,X,Z,H, or Y, or (# = Y and @ = A, E, I, O, or U)
X 			                ...# --> ...#S  as in BAT --> BATS
X 			                                or CONVEY --> CONVEYS
X 		*/
X 	unsigned short p_flag : 1;
X 		/*
X 			"P" FLAG:
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@INESS  as in CLOUDY --> CLOUDINESS
X 			        if # .ne. Y, or @ = A, E, I, O, or U,
X 			                ...@# --> ...@#NESS  as in LATE --> LATENESS
X 			                                or GRAY --> GRAYNESS
X 		*/
X 	unsigned short m_flag : 1;
X 		/*
X 			"M" FLAG:
X 			        ... --> ...'S  as in DOG --> DOG'S
X 		*/
X 
X 	unsigned short keep : 1;
X 
X };
X 
X #define WORDLEN 30
X 
X struct hashheader {
X 	int magic;
X 	int stringsize;
X 	int tblsize;
X };
X 
X #define MAGIC 1
X 
X 	
X /*
X  * termcap variables
X  */
X char *tgetstr();
X char PC;	/* padding character */
X char *BC;	/* backspace if not ^H */
X char *UP;	/* Upline (cursor up) */
X char *cd;	/* clear to end of display */
X char *ce;	/* clear to end of line */
X char *cl;	/* clear display */
X char *cm;	/* cursor movement */
X char *dc;	/* delete character */
X char *dl;	/* delete line */
X char *dm;	/* delete mode */
X char *ed;	/* exit delete mode */
X char *ei;	/* exit insert mode */
X char *ho;	/* home */
X char *ic;	/* insert character */
X char *il;	/* insert line */
X char *im;	/* insert mode */
X char *ip;	/* insert padding */
X char *nd;	/* non-destructive space */
X char *vb;	/* visible bell */
X char *so;	/* standout */
X char *se;	/* standout end */
X int bs;
X int li, co;	/* lines, columns */
X 
X char termcap[1024];
X char termstr[1024];	/* for string values */
X char *termptr;
X 
X char rootword[BUFSIZ];
X struct dent *lastdent;
X 
X char *hashstrings;
X 
X 
X int aflag;
X int lflag;
X 
X int erasechar;
X int killchar;
X 
X char tempfile[200];
SHAR_EOF
if test 4964 -ne "`wc -c < 'ispell.h'`"
then
	echo shar: error transmitting "'ispell.h'" '(should have been 4964 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'lookup.c'" '(2762 characters)'
if test -f 'lookup.c'
then
	echo shar: will not over-write existing file "'lookup.c'"
else
sed 's/^X //' << \SHAR_EOF > 'lookup.c'
X /* -*- Mode:Text -*- */
X 
X /*
X  * lookup.c - see if a word appears in the dictionary
X  *
X  * Pace Willisson, 1983
X  */
X 
X #include <stdio.h>
X #include "ispell.h"
X #include "config.h"
X 
X 
X struct dent *hashtbl;
X int hashsize;
X 
X extern char hashname[];
X 
X static inited = 0;
X 
X linit ()
X {
X 	int hashfd;
X 	struct hashheader hashheader;
X 	register int i;
X 	register struct dent *dp;
X 
X 	if (inited)
X 		return;
X 
X 	if ((hashfd = open (hashname, 0)) < 0) {
X 		fprintf (stderr, "can't open %s\r\n", hashname);
X 		return (-1);
X 	}
X 
X 	hashsize = read (hashfd, &hashheader, sizeof hashheader);
X 	if (hashsize == 0) {
X 		/*
X 		 * Empty file - create an empty dummy table.  We
X 		 * actually have to have one entry since the hash
X 		 * algorithm involves a divide by the table size
X 		 * (actually modulo, but zero is still unacceptable).
X 		 * So we create an entry with a word of all lowercase,
X 		 * which can't match because the comparison string has
X 		 * been converted to uppercase by then.
X 		 */
X 		close (hashfd);
X 		hashsize = 1;		/* This prevents divides by zero */
X 		hashtbl = (struct dent *) calloc (1, sizeof (struct dent));
X 		if (hashtbl == NULL) {
X 			(void) fprintf (stderr,
X 			    "Couldn't allocate space for hash table\n");
X 			return (-1);
X 		}
X 		hashtbl[0].word = "xxxxxxxxxxx";
X 		hashtbl[0].next = NULL;
X 		hashtbl[0].keep = 0;
X 		hashtbl[0].used = 1;
X 		/* The flag bits don't matter, but calloc cleared them. */
X 		inited = 1;
X 		return 0;
X 	}
X 	else if (hashsize < 0  ||  hashheader.magic != MAGIC) {
X 		fprintf (stderr, "Illegal format hash table\r\n");
X 		return (-1);
X 	}
X 	hashstrings = (char *) malloc (hashheader.stringsize);
X 	hashtbl = (struct dent *) malloc (hashheader.tblsize * sizeof (struct dent));
X 	if (hashtbl == NULL  ||  hashstrings == NULL) {
X 		(void) fprintf (stderr,
X 		    "Couldn't allocate space for hash table\n");
X 		return (-1);
X 	}
X 	hashsize = hashheader.tblsize;
X 
X 	read (hashfd, hashstrings, hashheader.stringsize);
X 	read (hashfd, hashtbl, hashheader.tblsize * sizeof (struct dent));
X 	close (hashfd);
X 
X 	for (i = hashsize, dp = hashtbl;  --i >= 0;  dp++) {
X 		dp->word = &hashstrings [ (int)(dp->word) ];
X 		if (dp->next == (struct dent *) -1)
X 			dp->next = NULL;
X 		else
X 			dp->next = &hashtbl [ (int)(dp->next) ];
X 	}
X 
X 	inited = 1;
X 	return (0);
X }
X 
X /* n is length of s */
X struct dent *
X lookup (s, n, dotree)
X register char *s;
X {
X 	int i;
X 	register struct dent *dp;
X 	register char *s1, *s2;
X 
X 	dp = &hashtbl [ hash (s, n, hashsize) ];
X 	for (  ; dp != NULL; dp = dp->next) {
X 		/* quick strcmp, but only for equality */
X 		s1 = dp->word;
X 		s2 = s;
X 		while (*s1 == *s2++)
X 			if (*s1++=='\0') {
X 				lastdent = dp;
X 				return (lastdent);
X 			}
X 	}
X 	if (dotree) {
X 		i = s[n];
X 		s[n] = '\0';
X 		if ((dp = treelookup (s)) != NULL)
X 			lastdent = dp;
X 		s[n] = i;
X 		return dp;
X 	}
X 	else
X 		return NULL;
X }
X 
SHAR_EOF
if test 2762 -ne "`wc -c < 'lookup.c'`"
then
	echo shar: error transmitting "'lookup.c'" '(should have been 2762 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'term.c'" '(3781 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 "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 #endif
X static termchanged = 0;
X 
X 
X terminit ()
X {
X 	int done();
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 	signal (SIGINT, done);
X #else
X 	int tpgrp;
X 	int onstop();
X 
X retry:
X 	sigsetmask(1<<SIGTSTP | 1<<SIGTTIN | 1<<SIGTTOU);
X 	if (ioctl(0, TIOCGPGRP, &tpgrp) != 0) {
X 		fprintf (stderr, "Can't deal with non interactive use yet.\n");
X 		exit (1);
X 	}
X 	if (tpgrp != getpgrp(0)) { /* not in foreground */
X 		sigsetmask(1<<SIGTSTP | 1<<SIGTTIN);
X 		signal(SIGTTOU, SIG_DFL);
X 		kill(0, SIGTTOU);
X 		/* job stops here waiting for SIGCONT */
X 		goto retry;
X 	}
X 
X 	ioctl (0, TIOCGETP, &osbuf);
X 	termchanged = 1;
X 
X 	sbuf = osbuf;
X 	sbuf.sg_flags &= ~ECHO;
X 	sbuf.sg_flags |= RAW;
X 	ioctl (0, TIOCSETP, &sbuf);
X 
X 	erasechar = sbuf.sg_erase;
X 	killchar = sbuf.sg_kill;
X 
X 	signal (SIGINT, done);
X 
X 	sigsetmask(0);
X 	signal(SIGTTIN, onstop);
X 	signal(SIGTTOU, onstop);
X 	signal(SIGTSTP, onstop);
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 #endif
X 	exit (0);
X }
X 
X #ifndef USG
X onstop(signo)
X int signo;
X {
X 	ioctl (0, TIOCSETP, &osbuf);
X 	signal(signo, SIG_DFL);
X 	kill(0, signo);
X 	/* stop here until continued */
X 	signal(signo, onstop);
X 	ioctl (0, TIOCSETP, &sbuf);
X }
X 
X stop ()
X {
X 	onstop (SIGTSTP);
X }
X #endif
X 
X shellescape (buf)
X char *buf;
X {
X #ifdef USG
X 	ioctl (0, TCSETAW, &osbuf);
X 	signal (SIGINT, SIG_IGN);
X 	signal (SIGQUIT, SIG_IGN);
X #else
X 	ioctl (0, TIOCSETP, &osbuf);
X 	signal (SIGINT, 1);
X 	signal (SIGQUIT, 1);
X 	signal(SIGTTIN, SIG_DFL);
X 	signal(SIGTTOU, SIG_DFL);
X 	signal(SIGTSTP, SIG_DFL);
X #endif
X 
X 	system (buf);
X 
X #ifndef USG
X 	signal(SIGTTIN, onstop);
X 	signal(SIGTTOU, onstop);
X 	signal(SIGTSTP, onstop);
X #endif
X 	signal (SIGINT, done);
X 	signal (SIGQUIT, SIG_DFL);
X 
X #ifdef USG
X 	ioctl (0, TCSETAW, &sbuf);
X #else
X 	ioctl (0, TIOCSETP, &sbuf);
X #endif
X 	printf ("\n-- Type space to continue --");
X 	getchar ();
X }
SHAR_EOF
if test 3781 -ne "`wc -c < 'term.c'`"
then
	echo shar: error transmitting "'term.c'" '(should have been 3781 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'tree.c'" '(10534 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 "ispell.h"
X #include "config.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 
X static char personaldict[MAXPATHLEN];
X static FILE *dictf;
X static newwords = 0;
X 
X extern char *index ();
X extern struct dent *hashtbl;
X extern int hashsize;
X 
X treeinit (p)
X char *p;
X {
X 	char *h;
X 	char *orig;
X 	char buf[BUFSIZ];
X 	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 		while (h != NULL) {
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 			/* Exit loop if no more flags */
X 			if (*h++ != '/')
X 				break;
X 		}
X 	}
X 
X 	fclose (dictf);
X 
X 	newwords = 0;
X 
X 	if (!lflag && !aflag && access (personaldict, 2) < 0)
X 		printf ("Warning: Cannot update personal dictionary (%s)\r\n", personaldict);
X }
X 
X treeprint ()
X {
X 	register int i;
X 	register struct dent *dp;
X 	register struct dent *cp;
X 
X 	printf ("(");
X 	for (i = 0;  i < hsize;  i++) {
X 		dp = &htab[i];
X 		if (dp->used) {
X 			for (cp = dp;  cp != NULL;  cp = cp->next)
X 				printf ("%s ", cp->word);
X 		}
X 	}
X 	printf (")");
X }
X 
X struct dent *
X treeinsert (word, keep)
X char *word;
X {
X 	register int i;
X 	struct dent *dp;
X 	struct dent *olddp;
X 	struct dent *oldhtab;
X 	int oldhsize;
X 	char nword[BUFSIZ];
X 
X 	strcpy (nword, word);
X 	upcase (nword);
X 	if ((dp = lookup (nword, strlen (nword), 0)) != NULL) {
X 		if (keep)
X 			dp->keep = 1;
X 		return dp;
X 	}
X 	/*
X 	 * Expand hash table when it is MAXPCT % full.
X 	 */
X 	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 	}
X 	newwords = 1;
X 	return tinsert (nword, (struct dent *) NULL, keep);
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 	int hcode;
X 	register struct dent *hp; /* Next trial entry in hash table */
X 	struct dent *php;	/* Previous value of hp, for chaining */
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 		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 		strcpy (hp->word, word);
X 		hp->keep = keep;
X 		hcount++;
X 		return (hp);
X 	}
X }
X 
X struct dent *
X treelookup (word)
X char *word;
X {
X 	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 	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 	toutput1 ();
X 
X 	fclose (dictf);
X }
X 
X static
X toutput1 ()
X {
X 	register struct dent *cent;	/* Current entry */
X 	register struct dent *lent;	/* Linked entry */
X 
X 	for (cent = htab;  cent - htab < hsize;  cent++) {
X 		for (lent = cent;  lent != NULL;  lent = lent->next) {
X 			if (lent->used  &&  lent->keep)
X 				toutput2 (lent);
X 		}
X 	}
X 	for (cent = hashtbl, lent = hashtbl + hashsize;
X 	    cent < lent;
X 	    cent++) {
X 		if (cent->used  &&  cent->keep)
X 			toutput2 (cent);
X 	}
X }
X 
X static
X toutput2 (cent)
X register struct dent *cent;
X {
X 	fprintf (dictf, "%s", cent->word);
X 	if (cent->d_flag)
X 		fprintf (dictf, "/D");
X 	if (cent->g_flag)
X 		fprintf (dictf, "/G");
X 	if (cent->h_flag)
X 		fprintf (dictf, "/H");
X 	if (cent->j_flag)
X 		fprintf (dictf, "/J");
X 	if (cent->m_flag)
X 		fprintf (dictf, "/M");
X 	if (cent->n_flag)
X 		fprintf (dictf, "/N");
X 	if (cent->p_flag)
X 		fprintf (dictf, "/P");
X 	if (cent->r_flag)
X 		fprintf (dictf, "/R");
X 	if (cent->s_flag)
X 		fprintf (dictf, "/S");
X 	if (cent->t_flag)
X 		fprintf (dictf, "/T");
X 	if (cent->v_flag)
X 		fprintf (dictf, "/V");
X 	if (cent->x_flag)
X 		fprintf (dictf, "/X");
X 	if (cent->y_flag)
X 		fprintf (dictf, "/Y");
X 	if (cent->z_flag)
X 		fprintf (dictf, "/Z");
X 	fprintf (dictf, "\n");
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 }
SHAR_EOF
if test 10534 -ne "`wc -c < 'tree.c'`"
then
	echo shar: error transmitting "'tree.c'" '(should have been 10534 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
-- 

	Geoff Kuenning
	{hplabs,ihnp4}!trwrb!desint!geoff