#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.6.3).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh26390
# Made on 2011-05-29 13:17 PDT by <gtoal@raiders>.
# Source directory was `/home/gtoal/gtoal.com/wordgames/bigspell'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#   7597 -rw-r--r-- ReadMe
#  11200 -rw-r--r-- grope.h
#    573 -rw-r--r-- porting.h
#    402 -rw-r--r-- splib.h
#   2368 -rw-r--r-- dawg.h
#  18202 -rw-r--r-- token.c
#    467 -rw-r--r-- pdawg.c
#   1161 -rw-r--r-- sextest.c
#   8189 -rw-r--r-- wordcheck.c
#   4658 -rw-r--r-- dawg_words.c
#    774 -rw-r--r-- dawg_challenge.c
#   1756 -rw-r--r-- makefile
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
  echo 'Note: not verifying md5sums.  Consider installing GNU coreutils.'
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    case `$dir/gettext --version 2>&1 | sed 1q` in
      *GNU*) gettext_dir=$dir ;;
    esac
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
     then shar_n= shar_c='
'
     else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
   test ! -f ${st1} && test -f ${f}; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
   test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
   test ! -f ${st3} && test -f ${f}; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'

else
  shar_touch=:
  echo
  ${echo} 'WARNING: not restoring timestamps.  Consider getting and'
  ${echo} 'installing GNU `touch'\'', distributed in GNU coreutils...'
  echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir}
then : ; else ${echo} 'lock directory '${lock_dir}' exists'
  exit 1
fi
if mkdir ${lock_dir}
then ${echo} 'x - created lock directory `'${lock_dir}\''.'
else ${echo} 'x - failed to create lock directory `'${lock_dir}\''.'
  exit 1
fi
# ============= ReadMe ==============
if test -f 'ReadMe' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING ReadMe (file already exists)'
else
${echo} 'x - extracting ReadMe (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'ReadMe' &&
This letter was written to the BSD project when this code was handed
over with the intention of replacing the AT&T 'spell' program.  Some
of the stuff here is a bit dated, but I'll leave the file here anyway
in case the explanations help anyone.  As you probably know, BSD
adopted 'ispell' as the spelling checker of choice and no-one seemed
to miss the old style interface, so the code below was never put into
production.
X
Graham Toal <gtoaL@gtoal.com>
X
X
-----
Spell utilities release 0.1
X
X
Dear Keith,
X
X   here's a first iteration of my spell code; your chap will probably want
to make it more unix-like -- especially in the parameter handling.  You
could add getopt or parseargs handling if you want.
X
I've structured the source as a directory containing the program sources,
with a subdirectory SpellLib containing all the files which are built into
the library object, 'splib'.  I'll probably add a 'tests' directory later.
There's no unix makefile yet; I'll include the Risc Os one as a guide for
now.
X
The library modules all have a .h file of the same name which is generated
automatically by 'mkptypes'.  The library header file itself ("splib.h")
pulls these files in.  I hope include-file semantics on bsd are the same as
my system -- if you include file "/somewhere/include/fred.h", and fred.h
includes "jim.h", you'll pull in "/somewhere/include/jim.h". If not, we'll
have to rethink include files a little.
X
I'm also assuming your compilers support prototypes nowadays.  (See comments
later in this file if not)
X
I've changed the dawg file format only by 8 bytes -- I now store a magic
number at the top, and a 0L in the first word; previously I stored the
number of edges in the first word and overwrote it with a 0L once I read the
data in.  Doing it this way means the file can be connected in read-only
memory with mmap, and shared among multiple users.  (Oh - note that the
address of the dawg to be filled in by dawg_init is 8 bytes into the file,
because of the magic number and the edge count)
X
(before:   [edges, poked to 0] [data]
X           ^ dawg start
X now:      [magic] [edges] [0] [data])
X                           ^ dawg start
X
At the moment, I'm just loading the dawg in with fread; if you want to use
mmap, remember to check for byte sex first; if the data isn't already in the
appropriate sex, re-connect it in copy-on-write mode and flip the order in
situ.
X
I strongly recommend you allow the dawg files to be of either sex so that
they can be as efficient as possible for any arbitrary machine.  I've
included a simple sex-change program which I used while testing to make sure
my sex-change code worked.  You might want to expand that into a proper
utility.
X
I've made the hash-table dynamically sized, using a reasonable heuristic
*for simple dictionaries*.  If this code is ever applied to non-dictionaries
(eg as a database lookup method with entries of the form "keyword=data
value"), where there is less sharing of tails etc, you'll have to add an
extra run-time parameter to set the hash-table size explicitly.
X
At the moment, I've added a "-l" parameter which simply bumps up the
calculated size by a constant fudge-factor.  A "-h <N>" option as well might
be useful.
X
The program takes an infile and outfile parameter, which have  to include
the appropriate file extensions if those are being used. (I recommend .dwg
but you don't have to stick with that) I did this because I run on a
non-unix platform, and it was tidier than lots of ifdef's for different
systems' extensions. However, since your version of the code is for 4bsd
only, feel free to remove as much of the remaining portability code as you
feel like.  The only thing I'd like you to keep is the dawg file format, so
that programs on other systems can read them. (Even though I'd prefer people
to pass dictionaries around as text, I know it won't happen.)
X
I've decided against storing lots of info in the dawg file (like character
set used, name of dictionary supplier etc.) -- this can go either in the
text file or in an ancilliary file with a different extension. (.dtx ?)) If
you allow this extra info to go in the text dictionary file, you will of
course have to alter dawg.c so that it ignores it.
X
The default dictionary has to be set to something sensible; probably
"/usr/dict/words.dwg" or whatever you use nowadays. At the moment it is a
local "dict.dwg".
X
If you want to turn the code into a filter, you'll definitely have to add a
"-n <hash size>" parameter, since you won't know how big the file will be in
order to estimate it.
X
X
I've included a trivial checking program (texcheck); this is *only* there as
a confidence test for porting.  It was my first hack using flex.  DO NOT use
it in any other way. It's crap! :-)  [It checks tex source files, as you may
have guessed]
X
I've completely (I hope) removed all the Packed-trie versions.  The benefits
of the faster format were outweighed by the complexity of having two
sources for everything.
X
Feel free (== I insist!) to change the names of the library procedures. They
weren't chosen with any thought.  Note I've done away with the rather tacky
included C files; however the library structuring leaves a little to be
desired.  I'll work on it.  Or you can if you prefer. (For example: there's
a prime finder in the library; I think it should be in dawg.c)
X
I've formatted it with the default parameters of GNU Indent, and removed all
the ANSI prototypes/K&R headers from all procedures.  If you can't assume
ANSI prototypes, I'd prefer if you distributed the source in ANSI style with
an ansi->pcc converter, rather than reverse engineering it back to K&R.
However the choice is yours; I don't insist.
X
If you want to take over the code completely now, that's OK by me.  Or
equally I'll hack to order if you prefer.  If you do a lot of work on it,
please send me back copies so I can try to keep in synch.  I'm assuming it's
your project since you are closer to the system than I am, so as of this
release you have the master source file.  Please be explicit anytime you
hand over the lock to me. (as in 'we have not changed it since your release
1.2', or 'take these source files and add feature '...', then hand them back
to us as release 1.3')
X
My system of numbering is
X
First digit:   major release (eg new data structures, incompatible changes)
Second digit:  minor release (internal changes, small added features)
Third digit:   local edit number (you won't see those)
X
I use RCS here, but the version numbers I am talking about refer to whole
systems; the RCS numbers for individual files may be different.
X
This shar file is release 0.1 of spell.
X
X
What I *haven't* included are the many versions of checking procedures --
with/ without case sensitivity etc., fuzzy matching, correction et al.  I
know unix 'spell' doesn't use these.  Let me know what the replacement needs
and I'll incorporate them properly.
X
A sensible extension to spell would be to allow checking in multiple dicts,
and suppression of certain words from dicts.  This can be done with the
parts you have.  However, for an interactive checker, you want to remember
new words as they are found.  I haven't included that code (for dynamic
additions to dawgs) yet as it is far from efficient at the moment.  Again,
if you're not doing such a checker, let me know & I won't spend as much time
on improving that code as I would have.
X
I have a pretty good idea of what is needed as I've already hacked a copy of
ispell to use my stuff.
X
I believe the code is fairly solid.  I've made minimal changes for this
release.
X
best regards
X   graham
X
SHAR_EOF
  (set 20 08 10 12 12 06 08 'ReadMe'; eval "$shar_touch") &&
  chmod 0644 'ReadMe'
if test $? -ne 0
then ${echo} 'restore of ReadMe failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'ReadMe: MD5 check failed'
       ) << SHAR_EOF
202a302f4556334e5860606ea98175ab  ReadMe
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'ReadMe'` -ne 7597 && \
  ${echo} 'restoration warning:  size of ReadMe is not 7597'
  fi
fi
# ============= grope.h ==============
if test -f 'grope.h' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING grope.h (file already exists)'
else
${echo} 'x - extracting grope.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'grope.h' &&
#ifndef grope_h
#define grope_h 1
X
#ifdef TESTING_DEFS
/*###################################################################*/
/*
X * This is an exercise to assist in writing portable programs.
X *
X * To use as a header file, eg "grope.h", just leave this file
X * as it is.  To use it to define new entries, rename it as
X * "grope.c" and compile it as "cc -DTESTING_DEFS grope".
X *
X * To customise this test program for your system, I have set it up
X * so that all features are enabled.  If you find that one feature
X * causes a compile-time error, test a suitable set of '#ifdef's for
X * your machine and #undef the values below which are not appropriate.
X *
X * Please do your best to see that your tests are unique, and that
X * you do not undo any tests already implemented.
X *
X * One last request; PLEASE PLEASE PLEASE send me any updates you
X * may make. If you cannot get through to me on email, send me a
X * paper copy (or even better, a floppy copy :-)) to Grahan Toal,
X * c/o 6 Pypers wynd, Prestonpans, East Lothian, Scotland EH32 9AH.
X *
X *   Graham Toal <gtoal@uk.ac.ed>
X * [PS: I can read DOS and RISC OS floppies only]
X */
#define STDLIBS 1
#define PROTOTYPES 1
#define KNOWS_VOID 1
#define KNOWS_LINE 1
#define KNOWS_REGISTER 1
#endif /* TESTING_DEFS */
/*###################################################################*/
#define SYS_ANY 1
#define COMPILER_ANY 1
X  /* Don't yet know what machine it is.  Add a test once identified. */
/*--------------------------*/
#ifdef MSDOS
#define SYS_MSDOS 1
#endif
/*--------------------------*/
#ifdef __STDC__
#define STDLIBS 1
#define PROTOTYPES 1
#define KNOWS_VOID 1
X  /* If the compiler defines STDC it should have these. We can undef
X     them later if the compiler was telling lies! */
#endif
/*--------------------------*/
#ifdef MPU8086
#define SYS_MSDOS 1
X  /* Aztec does not #define MSDOS.
X     We assume it is Aztec on MSDOS from the MPU8086.
X   */
#ifdef __STDC__
#define COMPILER_AZTEC 1
X  /* Aztec is known to also define __STDC__ (illegally).  Therefore if
X     __STDC__ is not defined, it is probably not Aztec */
#endif
#endif
X
#ifdef SYS_MSDOS
/*--------------------------*/
#ifdef __STDC__
/*----------------------*/
#define COMPILER_MICROSOFT 1
X  /* I assume that the combination of #define MSDOS and #define __STDC__
X     without any other collaboration means MICROSOFT.  (Who, incidentally,
X     are being naughty by declaring __STDC__) */
#define KNOWS_LINE 1
#else
/*----------------------*/
#ifdef __ZTC__
/*------------------*/
#define COMPILER_ZORTECH 1
#undef STDLIBS
X  /* Another system without locale.h */
#define PROTOTYPES 1
#else
/*------------------*/
/* A non-std msdos compiler */
#undef STDLIBS
#undef PROTOTYPES
/*------------------*/
#endif
/*----------------------*/
#endif
/*--------------------------*/
#endif
#ifdef TURBOC
X  /* Although Turbo C correctly does not define __STDC__, it has SOME
X     standard libraries (but not all - locale.h?) and accepts prototypes. */
#undef STDLIBS
#define PROTOTYPES 1
#define SYS_MSDOS 1
#define COMPILER_TURBOC 1
X  /* TURBOC is defined, but has no value.  This allows it to be tested
X     with #if as well as #ifdef. */
#endif
/*--------------------------*/
#ifdef COMPILER_MICROSOFT
#undef STDLIBS
X  /* Again, like Turbo C, does not know locale.h */
#define PROTOTYPES 1
#endif
/*--------------------------*/
#ifdef SYS_MSDOS
#define MEMMODELS 1
X  /* We assume ALL MSDOS machines use memory models */
#endif
/*--------------------------*/
#ifdef UX63
#undef STDLIBS
#undef PROTOTYPES
#define SYS_UX63 1
#define COMPILER_PCC 1
/*#define LIB_STRINGS 1 - apparently not... */
#endif
/*--------------------------*/
#ifdef sun
#undef STDLIBS
#undef PROTOTYPES
#define SYS_SUN 1
#define COMPILER_PCC 1
#endif
/*--------------------------*/
#ifdef THINK_C
#define SYS_MAC 1
#define COMPILER_THINKC 1
#define KNOWS_VOID 1
#endif
/*--------------------------*/
#ifdef sparc
#undef STDLIBS
#undef PROTOTYPES
#define SYS_SPARC 1
#define COMPILER_PCC 1
#endif
/*--------------------------*/
#ifdef ARM
#define SYS_RISCOS 1
X  /* I fear Acorn may define 'ARM' on both unix and risc os versions.
X     Should find out whether they define others as well, to differentiate. */
#endif
#ifdef __ARM__
#define SYS_RISCOS 1
X  /* I fear Acorn may define 'ARM' on both unix and risc os versions.
X     Should find out whether they define others as well, to differentiate. */
#endif
#ifdef __arm
#define SYS_RISCOS 1
X  /* I fear Acorn may define 'ARM' on both unix and risc os versions.
X     Should find out whether they define others as well, to differentiate. */
#endif
/*--------------------------*/
#ifdef SYS_RISCOS
#define COMPILER_NORCROFT 1
#define KNOWS_REGISTER 1
#define KNOWS_LINE 1
#endif
/*--------------------------*/
#ifdef vms
#define SYS_VMS 1
#endif
/*--------------------------*/
X
/*--------------------------*/
#ifdef SYS_UX63
#undef SYS_ANY
#endif
#ifdef SYS_MSDOS
#undef SYS_ANY
#endif
#ifdef SYS_SUN
#undef SYS_ANY
#endif
#ifdef SYS_SPARC
#undef SYS_ANY
#endif
#ifdef SYS_RISCOS
#undef SYS_ANY
#endif
#ifdef SYS_MAC
#undef SYS_ANY
#endif
#ifdef SYS_VMS
#undef SYS_ANY
#endif
/*--------------------------*/
#ifdef COMPILER_PCC
#undef COMPILER_ANY
#endif
#ifdef COMPILER_MICROSOFT
#undef COMPILER_ANY
#endif
#ifdef COMPILER_TURBOC
#undef COMPILER_ANY
#endif
#ifdef COMPILER_ZORTECH
#undef COMPILER_ANY
#endif
#ifdef COMPILER_AZTEC
#undef COMPILER_ANY
#endif
#ifdef COMPILER_NORCROFT
#undef COMPILER_ANY
#endif
#ifdef COMPILER_THINKC
#undef COMPILER_ANY
#endif
/*--------------------------*/
/* ##################################################################### */
#ifdef TESTING_DEFS
#include <stdio.h>
/* ======================================================================= */
#ifdef STDLIBS
X              /* If any of these fail, make sure STDLIBS is not
X                 defined for your machine. */
#include <stdlib.h>      /* STDLIBS should not be defined. */
#include <time.h>        /* STDLIBS should not be defined. */
#include <locale.h>      /* STDLIBS should not be defined. */
#endif
/* ======================================================================= */
#ifdef KNOWS_VOID
void test() {            /* KNOWS_VOID should not be defined */
X  /* Make sure your ifdef's don't #define KNOWS_VOID if this fails */
}
#endif
/* ======================================================================= */
#ifdef KNOWS_REGISTER
int regtest() {
register int i = 0;          /* KNOWS_REGISTER should not be defined */
X  /* Make sure your ifdef's don't #define KNOWS_REGISTER if this fails */
X  return(i);
}
#endif
/* ======================================================================= */
#ifdef PROTOTYPES
int main(int argc, char **argv)   /* PROTOTYPES should not be defined */
/* If this fails, make sure PROTOTYPES is not defined for your machine. */
#else
int main(argc,argv)
int argc;
char **argv;
#endif
{
/*-------------------------------------------------------------------------*/
X  printf("We should know just what the machine is, or 'SYS_ANY':\n");
#ifdef SYS_UX63
X  printf("#define SYS_UX63 %d\n", SYS_UX63);
#endif
#ifdef SYS_MSDOS
X  printf("#define SYS_MSDOS %d\n", SYS_MSDOS);
#endif
#ifdef SYS_SUN
X  printf("#define SYS_SUN %d\n", SYS_SUN);
#endif
#ifdef SYS_SPARC
X  printf("#define SYS_SPARC %d\n", SYS_SPARC);
#endif
#ifdef SYS_RISCOS
X  printf("#define SYS_RISCOS %d\n", SYS_RISCOS);
#endif
#ifdef SYS_MAC
X  printf("#define SYS_MAC %d\n", SYS_MAC);
#endif
#ifdef SYS_VMS
X  printf("#define SYS_VMS %d\n", SYS_VMS);
#endif
#ifdef SYS_ANY
X  printf("#define SYS_ANY %d\n", SYS_ANY);
#endif
/*-------------------------------------------------------------------------*/
X  printf("Either the machine has different memory models or not:\n");
#ifdef MEMMODELS
X  printf("#define MEMMODELS %d\n", MEMMODELS);
#else
X  printf("#undef MEMMODELS\n");
#endif
/*-------------------------------------------------------------------------*/
X  printf("One compiler name should be given, or 'COMPILER_ANY':\n");
#ifdef COMPILER_PCC
X  printf("#define COMPILER_PCC %d\n", COMPILER_PCC);
#endif
#ifdef COMPILER_MICROSOFT
X  printf("#define COMPILER_MICROSOFT %d\n", COMPILER_MICROSOFT);
#endif
#ifdef COMPILER_TURBOC
X  printf("#define COMPILER_TURBOC %d\n", COMPILER_TURBOC);
#endif
#ifdef COMPILER_ZORTECH
X  printf("#define COMPILER_ZORTECH %d\n", COMPILER_ZORTECH);
#endif
#ifdef COMPILER_AZTEC
X  printf("#define COMPILER_AZTEC %d\n", COMPILER_AZTEC);
X  /* Can exist on other machines as well as MSDOS */
#endif
#ifdef COMPILER_LATTICE
X  /* Currently coming through as 'COMPILER_ANY' - haven't found one to test */
X  /* Can exist on other machines as well as MSDOS. Meanwhile pass it in     */
X  /* on the command_line?                                                   */
X  printf("#define COMPILER_LATTICE %d\n", COMPILER_LATTICE);
#endif
#ifdef COMPILER_GCC
X  /* Ditto. Test in appropriate places for each machine. */
X  printf("#define COMPILER_GCC %d\n", COMPILER_GCC);
#endif
#ifdef COMPILER_NORCROFT
X  printf("#define COMPILER_NORCROFT %d\n", COMPILER_NORCROFT);
#endif
#ifdef COMPILER_THINKC
X  printf("#define COMPILER_THINKC %d\n", COMPILER_THINKC);
#endif
#ifdef COMPILER_ANY
X  printf("#define COMPILER_ANY %d\n", COMPILER_ANY);
#endif
/*-------------------------------------------------------------------------*/
X  printf("Either the compiler accepts ANSI-like libraries or not:\n");
#ifdef STDLIBS
X  printf("#define STDLIBS %d\n",STDLIBS);
#else
X  printf("#undef STDLIBS\n");
#endif
/*-------------------------------------------------------------------------*/
X  printf("Either the machine accepts ANSI prototypes or not:\n");
#ifdef PROTOTYPES
X  printf("#define PROTOTYPES %d\n", PROTOTYPES);
#else
X  printf("#undef PROTOTYPES\n");
#endif
/*-------------------------------------------------------------------------*/
X  printf("Either the machine needs nonstandard #include <strings.h> or not:\n");
#ifdef LIB_STRINGS
X  printf("#define LIB_STRINGS %d\n", LIB_STRINGS);
#else
X  printf("#undef LIB_STRINGS\n");
#endif
/*-------------------------------------------------------------------------*/
X  printf("Either the machine accepts the 'void' keyword or not:\n");
#ifdef KNOWS_VOID
X  printf("#define KNOWS_VOID %d\n", KNOWS_VOID);
#else
X  printf("#undef KNOWS_VOID\n");
#endif
/*-------------------------------------------------------------------------*/
X  printf("Either the compiler accepts the '__LINE__' directive or not:\n");
#ifdef KNOWS_LINE
X  printf("#define KNOWS_LINE %d\n", KNOWS_LINE);
#else
X  printf("#undef KNOWS_LINE\n");
#endif
/*-------------------------------------------------------------------------*/
X  printf("Either the machine accepts the 'register' keyword or not:\n");
#ifdef KNOWS_REGISTER
X  printf("#define KNOWS_REGISTER %d\n", KNOWS_REGISTER);
#else
X  printf("#undef KNOWS_REGISTER\n");
#endif
X  /* Note - this is intended to be used only if your compiler accepts
X     'register' *AND* compiles code with it correctly!  Some compilers
X     show up bugs when register optimisations are attempted! */
/*-------------------------------------------------------------------------*/
X  if (argv[argc] != 0) printf("Warning! argv[argc] != NULL !!! (Non ansii)\n");
}
#endif /* TESTING_DEFS */
#endif /* Already seen? */
X
SHAR_EOF
  (set 20 11 05 29 12 58 06 'grope.h'; eval "$shar_touch") &&
  chmod 0644 'grope.h'
if test $? -ne 0
then ${echo} 'restore of grope.h failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'grope.h: MD5 check failed'
       ) << SHAR_EOF
827fd3035e61c2cfacf3c20a5540b203  grope.h
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'grope.h'` -ne 11200 && \
  ${echo} 'restoration warning:  size of grope.h is not 11200'
  fi
fi
# ============= porting.h ==============
if test -f 'porting.h' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING porting.h (file already exists)'
else
${echo} 'x - extracting porting.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'porting.h' &&
/*
X
X    File:    utils.c
X    Author:  Graham Toal
X    Purpose: Portability library
X
Description:
X
X    This is a cut-down version of my portability header-file.
X    We cater here only for Unix and Risc OS (the latter being
X    my development environment).
X
*/
X
/* Temporary while developing at vangogh.berkeley.edu: */
#define DEFAULT_DAWG "web2"
#define EXT_CHAR '.'
X
#define READ_TEXT "r"
#define WRITE_TEXT "w"
#define WRITE_BIN "wb"
#define READ_BIN "rb"
X
X
/* system configuration */
X
#include <stdlib.h>  /* for malloc, free & exit */
#define RANGECHECK(idx,max) (idx)
SHAR_EOF
  (set 20 11 05 29 12 58 07 'porting.h'; eval "$shar_touch") &&
  chmod 0644 'porting.h'
if test $? -ne 0
then ${echo} 'restore of porting.h failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'porting.h: MD5 check failed'
       ) << SHAR_EOF
ba8d31e4f7d4c18d731ab1938590a129  porting.h
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'porting.h'` -ne 573 && \
  ${echo} 'restoration warning:  size of porting.h is not 573'
  fi
fi
# ============= splib.h ==============
if test -f 'splib.h' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING splib.h (file already exists)'
else
${echo} 'x - extracting splib.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'splib.h' &&
#include "grope.h"
#include <stdio.h>
X
#ifndef FALSE
#define TRUE (0==0)
#define FALSE (0!=0)
#endif
X
extern int spell_verbose;
X
#include "dawg.h"
#include "porting.h"
X
/* The individual procedures are kept up to date by mkptypes */
#include "SpellLib/print.h"
#include "SpellLib/init.h"
#include "SpellLib/prime.h"
#include "SpellLib/check.h"
#include "SpellLib/pathopen.h"
#include "SpellLib/typo.h"
SHAR_EOF
  (set 20 11 05 29 12 58 08 'splib.h'; eval "$shar_touch") &&
  chmod 0644 'splib.h'
if test $? -ne 0
then ${echo} 'restore of splib.h failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'splib.h: MD5 check failed'
       ) << SHAR_EOF
fb1e211312202f8f24e7af768137105a  splib.h
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'splib.h'` -ne 402 && \
  ${echo} 'restoration warning:  size of splib.h is not 402'
  fi
fi
# ============= dawg.h ==============
if test -f 'dawg.h' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING dawg.h (file already exists)'
else
${echo} 'x - extracting dawg.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'dawg.h' &&
/**
*
*       DAWG.H
*
*       Header file for Directed Acyclic Word Graph access
*
*       The format of a DAWG node (8-bit arbitrary data) is:
*
*        33  32  31                24 23                                             0
*       +---+---+--------------------+------------------------------------------------+
*       | W | N |      Letter        |                       Node pointer             |
*       +---+---+--------------------+------------------------------------------------+
*
*      where N flags the last edge in a node and W flags an edge as the
*      end of a word. 21 bits are used to store the node pointer, so the
*      dawg can contain up to 2^24-1 edges.
*
*      The root node of the dawg is at address 1 (because node 0 is reserved
*      for the node with no edges).
*
*      Files containing a DAWG have a magic-number immediately before the 0-th
*      element.
*
**/
X
#ifndef TRUE
#define TRUE (0==0)
#endif
#ifndef FALSE
#define FALSE (0!=0)
#endif
X
#define DAWG_MAGIC 0x71C64144F7LL           /* Arbitrary value */
#define REVERSE_DAWG_MAGIC 0xF74441C671000000LL   /* reverse byte-sex */
X
#define TERMINAL_NODE 0     /* First word always contains 0L */
#define ROOT_NODE 1         /* Root of dag                   */
X
#define V_END_OF_WORD   33                      /* Bit number of W */
#define M_END_OF_WORD   (1LL << V_END_OF_WORD)
#define V_END_OF_NODE   32                      /* Bit number of N */
#define M_END_OF_NODE   (1LL << V_END_OF_NODE)
X
#define V_LETTER        24
#define M_LETTER        0xFF
X
#define M_NODE_POINTER  0xFFFFFFLL     /* Bit mask for node pointer */
X
/* max_chars and base_chars are a hangover from the days when this
X   was trying to save space, and dawgs were only able to contain
X   characters in the range 'a'..'z' 'A'..'Z' (squeezed into 6 bits).
X   Now that we're '8-bit clean' we no longer need these.  Later code
X   in fact doesn't support the old style; but some procedures still
X   subtract 'BASE_CHAR' from the character to normalize it.  Since it
X   is now 0 it is a no-op... 
X
X   Just in case this code ever migrates to a 16-bit environment (Japanese?),
X   I'll leave these in.
X
X */
#define MAX_CHARS       256
#define BASE_CHAR       0
X
/* Enough? (This is fairly arbitrary) */
#define MAX_WORD_LEN    256
X
#define MAX_LINE        256
X
typedef long long NODE;
typedef long INDEX;
X
SHAR_EOF
  (set 20 11 05 29 12 58 05 'dawg.h'; eval "$shar_touch") &&
  chmod 0644 'dawg.h'
if test $? -ne 0
then ${echo} 'restore of dawg.h failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'dawg.h: MD5 check failed'
       ) << SHAR_EOF
ec963f02df8030c534d7ff221eb7c0da  dawg.h
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'dawg.h'` -ne 2368 && \
  ${echo} 'restoration warning:  size of dawg.h is not 2368'
  fi
fi
# ============= token.c ==============
if test -f 'token.c' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING token.c (file already exists)'
else
${echo} 'x - extracting token.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'token.c' &&
/*
X * Title:   token.c
X *
X * Authors: Richard Hooker & Graham Toal
X *
X * Purpose: Convert a sorted dictionary into a word-dag
X *
X * $Log:        c.token
X *
X * $ Revision 1.5  11/05/28  15:18:23  gtoal Fixed a 32/64 bit compatibility problem
X *
X * Revision 1.4  91/07/15  18:47:31  gtoal Changed name to token.
X *
X * Revision 1.2  91/03/23  17:56:35  gtoal About to be released
X *
X * Revision 1.1  91/03/23  16:15:35  gtoal Initial revision
X *
X */
X
char   *RCS_ID = "$Header: rcs.c.token 1.4 91/07/15 18:47:31 gtoal Exp Locker: gtoal $";
X
X
#include "copyr.h"
#include "splib.h"
X
int spell_verbose = FALSE;
X
#include <string.h>
#include <ctype.h>
#include <unistd.h>
X
/* Use system getopt.  Is there a header file for this? */
/**/
/*extern int getopt(int argc, char **argv, char *opstring);*/
extern char *optarg;
extern int optind, opterr;
/**/
#ifdef MEMDEBUG
#include "../mnemosyne/mnemosyn.h"
#endif
X
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define ABS(x) ((x) < 0 ? -(x) : (x))
X
/* pick one about 20% larger than needed */
long    hash_table_size = 0;
#define HASH_TABLE_SIZE hash_table_size
#define MIN_HASH_SIZE 60013L
#define MAX_EDGES (HASH_TABLE_SIZE-1)
#define MAX_FUDGE 4L		/* Factor by which our estimate might be out
X				 * for atypical files */
X
char   *infile = NULL, *outfile = NULL;
static FILE *fpin, *fpout;	/* Input/output files */
static unsigned char current_word[(MAX_LINE + 1)];	/* The last word read from
X	            					 * fpin */
X
static int first_diff;
/* The position of the first letter at which */
/* current_word differs from the previous    */
/* word read                                 */
X
static NODE *hash_table;
static int first_time = TRUE;
static int this_char = '?', lastch;
static NODE *dawg;
X
static int FILE_ENDED = FALSE;	/* I'm having real problems getting merged
X				 * dawgs to work on the PC; this is yet
X				 * another filthy hack. Sorry. */
X
static char *array_name = "_token";
static char *progname = "token", *realprogname = NULL;
static int token_verbose = FALSE;
static int cfile = FALSE;	/* Write output as a C file instead */
static int short_circuit = FALSE;	/* Skip dawg building - use
X					 * precomputed one */
static INDEX nwords, nnodes, total_edges;
X
/*
X * Macros for array accesses with checking.  If RCHECK isn't defined, these
X * don't contribute any overhead. I suggest leaving RCHECK on except for
X * production code.
X */
X
#define EDGE_LIST(idx) \
X  edge_list[RANGECHECK(idx, MAX_CHARS)]
#define CURRENT_WORD(idx) \
X  current_word[RANGECHECK(idx, MAX_LINE+1)]
#define DAWG(idx) \
X  dawg[RANGECHECK(idx, MAX_EDGES)]
#define HASH_TABLE(idx) \
X  hash_table[RANGECHECK(idx, HASH_TABLE_SIZE)]
X
/*
X * Forward references
X */
X
static INDEX build_node(int depth);
static INDEX add_node(NODE * edge_list, INDEX nedges);
static void read_next_word(void);
static INDEX compute_hashcode(NODE * edge_list, INDEX nedges);
static void report_size(void);
X
void
usage(void)
{
X	fprintf(stderr,
X	    "usage: %s [-c] [-l | -H hashsize] [-d tokenfile | -f wordlist] [-o outfile]\n",
X	    progname);
X	fprintf(stderr,
X	    "       %s -H 100000 -f /usr/share/dict/web2 -o web2.dwg\n", progname);
X	fprintf(stderr,
X	    "       %s -l -f anagdict.txt -o anags.dwg\n", progname);
X	fprintf(stderr,
X	    "       %s -c -f connectives.txt -o connectives.h\n", progname);
X	fprintf(stderr,
X	    "       %s -c -d anags.dwg -o anags.h\n", progname);
}
X
X
static char *
hex(long long l)
{
X	static char tmp[14];
X	char    hexdig[17] = "0123456789abcdef";
X	int     p;
X	strcpy(tmp, "           LL");
X	p = 10;
X	for (;;) {
X		tmp[p] = hexdig[l & 15];
X		l = (l >> 4LL) & 0xffffffffLL;
X		if (l == 0) {
X			p -= 1;
X			tmp[p] = 'x';
X			p -= 1;
X			tmp[p] = '0';
X			return (tmp);
X		}
X		p -= 1;
X	}
}
X
static void
dump_c_array(FILE * f, NODE * data, INDEX length)
{
X	INDEX   i, j;
X	for (i = 0; i < length; i += 6) {
X		for (j = i; j < i + 6 && j < length; j++) {
X			fprintf(f, "%s", hex(data[j]));
X			if (j + 1 != length)
X				fprintf(f, ", ");
X		}
X		fprintf(f, "\n");
X	}
}
X
X
/*
X * Take a list of alpha sorted and uniq words and convert into token file
X */
X
int
main(int argc, char **argv)
{
X	INDEX   i;
X	long    insize = 0L;
X	long    fudge_factor = 1L;
X	int     c;
X
X	realprogname = progname = argv[0];
X	short_circuit = FALSE;
X	token_verbose = FALSE;
X	while ((c = getopt(argc, argv, "cd:f:H:lo:vh?")) != -1) {
X		switch (c) {
X		case 'c':
X			/* Generate given C output file rather than .dwg file */
X			cfile = TRUE;
X			if (token_verbose)
X				fprintf(stderr, "%s: output file will be C source\n", progname);
X			break;
X		case 'd':
X			/* This option lets you give a precomputed token file
X			 * as input, to be converted to C. */
X			if (infile != NULL) {
X				fprintf(stderr, "%s: cannot have both -f and -d\n", progname);
X				exit(EXIT_FAILURE);
X			}
X			infile = optarg;
X			if (token_verbose)
X				fprintf(stderr, "%s: reading directly from token file %s\n",
X				    progname, optarg);
X			short_circuit = TRUE;
X			break;
X		case 'f':
X			if (infile != NULL) {
X				fprintf(stderr, "%s: cannot have both -d and -f\n", progname);
X				exit(EXIT_FAILURE);
X			}
X			infile = optarg;
X			if (token_verbose)
X				fprintf(stderr, "%s: reading from word list %s\n", progname, infile);
X			break;
X		case 'H':
X			if (!isdigit(*optarg)) {
X				fprintf(stderr, "%s: argument to -h must be an integer\n", progname);
X				usage();
X			}
X			hash_table_size = atol(optarg);
X			if (token_verbose)
X				fprintf(stderr, "%s: setting hash_table_size to %ld\n",
X				    progname, hash_table_size);
X			break;
X		case 'l':
X			fudge_factor = MAX_FUDGE;
X			if (token_verbose)
X				fprintf(stderr, "%s: making some elbow-room!\n", progname);
X			break;
X		case 'n':
X			array_name = optarg;
X			break;
X		case 'o':
X			if (outfile != NULL) {
X				fprintf(stderr, "%s: cannot have both more than one -o\n", progname);
X				exit(EXIT_FAILURE);
X			}
X			outfile = optarg;
X			if (token_verbose)
X				fprintf(stderr, "%s: creating token file %s\n", progname, outfile);
X			break;
X		case 'v':
X		        token_verbose = TRUE; spell_verbose = TRUE;
X			break;
X		case 'h':
X		case '?':
X			usage();
X			exit(EXIT_SUCCESS);
X		default:
X			usage();
X			exit(EXIT_FAILURE);
X		}
X	}
X
X	/* Spelling from stdin? */
X	if (optind != argc) {
X		fprintf(stderr, "%s: spurious extra parameter %s\n", progname, argv[optind]);
X		exit(EXIT_FAILURE);
X	}
X	/* Find out how large the input file is; guess how many nodes will be
X	 * needed. */
X
X	/* This code should be reworked so that if infile is not given, you
X	 * read from stdin instead.  Currently it does not do so, but that was
X	 * only because of the difficulty of estimating hash table sizes.  If
X	 * you allow the hash table size to be a parameter, it would make
X	 * sense to accept input from a pipe instead. */
X	if ((infile == NULL) && (outfile == NULL)) {
X		usage();
X		exit(EXIT_FAILURE);
X	}
X	if (infile == NULL) {
X		fprintf(stderr, "%s: requires a -f infile parameter\n", progname);
X		exit(EXIT_FAILURE);
X	}
X	if (outfile == NULL) {
X		fprintf(stderr, "%s: requires a -o outfile parameter\n", progname);
X		exit(EXIT_FAILURE);
X	}
X	if (short_circuit && !cfile) {
X		/* short-circuit implies cfile */
X		/* do this check before anything gets overwritten! */
X		fprintf(stderr, "%s: giving \"-d %s\" usually implies -c too;\n", progname, infile);
X		fprintf(stderr, "%s: didn\'t you really intend to generate a C file perhaps?\n", progname);
X		exit(EXIT_FAILURE);
X	}
X	fpout = fopen(outfile, WRITE_BIN);
X	if (fpout == NULL) {
X		fprintf(stderr, "%s: can\'t open output file \"%s\"\n", progname, outfile);
X		exit(EXIT_FAILURE);
X	}
X	if (short_circuit) {
X		/* Load dawg directly */
X		if (!dawg_init(infile, &dawg, &total_edges)) {
X			fprintf(stderr, "%s: cannot load pre-computed dictionary file %s\n",
X			    progname, infile);
X			exit(EXIT_FAILURE);
X		} else {
X			if (token_verbose)
X				fprintf(stderr, "%s: Loaded dict %s of %ld edges\n",
X				    progname, infile, total_edges);
X		}
X	} else {
X		if (hash_table_size <= 0) {	/* I.e. not given explicitly */
X			fpin = fopen(infile, READ_BIN);	/* Has to be binary for
X							 * ftell to work */
X			if (fpin == NULL) {
X				fprintf(stderr, "%s: can\'t open text file \"%s\"\n", progname, infile);
X				/* Could print out error string but it's not
X				 * portable... */
X				exit(EXIT_FAILURE);
X			}
X			fseek(fpin, 0L, SEEK_END);
X			insize = ftell(fpin);
X			fclose(fpin);
X
X			hash_table_size = insize / 11L;	/* Pretty close estimate
X							 * of nodes */
X			hash_table_size = hash_table_size * 133L;
X			hash_table_size = hash_table_size / 100L;	/* Plus 33% */
X			hash_table_size = hash_table_size * fudge_factor;
X
X		}
X		hash_table_size = prime(hash_table_size);	/* Up to next prime
X								 * number */
X		hash_table_size = MAX(hash_table_size, MIN_HASH_SIZE);
X
X		if (token_verbose)
X			fprintf(stderr, "%s: using a hash table of %ld %d-byte edges\n",
X				progname, hash_table_size, sizeof(long long /* NODE * */));
X
X		fpin = fopen(infile, READ_TEXT);	/* Had better work! */
X		/**
X	        *  Allocate the memory for the dawg
X	        **/
X
X		if ((dawg = malloc((size_t) MAX_EDGES * sizeof(long long/*NODE * */))) == NULL) {
X			fprintf(stderr, "%s: can\'t allocate dictionary memory\n", progname);
X			exit(EXIT_FAILURE);
X		}
X		for (i = 0; i < (INDEX) MAX_EDGES; i++)
X			dawg[i] = 0L;
X		/**
X	        *  Allocate the hash table.
X	        *  Fill it with zeroes later just before use.  Don't trust calloc etc.
X	        *  - not portable enough.  Anyway, in the multi-pass version we don't
X	        *  want to continually free/claim...
X	        **/
X
X		if ((hash_table =
X			malloc((size_t) (HASH_TABLE_SIZE + 1L) * sizeof(NODE))) == NULL) {
X			fprintf(stderr, "%s: can\'t allocate memory for hash table\n", progname);
X			exit(EXIT_FAILURE);
X		}
X		/**
X	        *  Read the first word from the dictionary
X	        **/
X
X		first_time = TRUE;
X		nwords = 0;
X		current_word[0] = 0;
X		read_next_word();
X		lastch = *current_word;
X		/**
X	        *  Initialise the counters, taking account of the root node (which is
X	        *  a special case)
X	        **/
X
X		nnodes = 1;
X		total_edges = MAX_CHARS;
X
X		/**
X	        *  Build the dawg and report the outcome
X	        **/
X
X		/* Explicitly initialise hash table to all zeros */
X		{
X			INDEX   a;
X			for (a = 0; a <= HASH_TABLE_SIZE; a++)
X				hash_table[a] = 0;
X		}
X
X		(void) build_node(0);
X		fclose(fpin);
X	}
X
X	/**
X        *  Save the dawg to file
X        **/
X
X	if (cfile) {
X		/* Generate C output instead */
X		fprintf(fpout, "long long %s[%ld] = {\n", array_name, total_edges + 1);
X		/* name of 'long _token[]' to be a parameter */
X		dump_c_array(fpout, dawg, total_edges + 1);	/* Loses DAWG_MAGIC and
X								 * length.  Retains
X								 * initial 0L. */
X		fprintf(fpout, "};\n");
X	} else {
X		/* Prepend a magic-number, then write raw data to token file.  */
X		{
X			NODE    dawg_magic = DAWG_MAGIC;
X			fwrite(&dawg_magic, 1, sizeof(dawg_magic), fpout);
X		}
X		{
X			NODE    nedges = total_edges + 1;
X			fwrite(&nedges, 1, sizeof(nedges), fpout);
X		}
X		*dawg = 0L;
X		total_edges = sizeof(NODE) * (total_edges + 1);	/* Convert to byte count */
X
X		{
X			long    cnt;
X			if ((cnt = fwrite((char *) dawg, 1, (size_t) total_edges, fpout)) != total_edges) {
X				fprintf(stderr, "%s: %ld bytes written instead of %ld\n.",
X				    progname, cnt, total_edges);
X				exit(EXIT_FAILURE);
X			}
X		}
X	}
X	fflush(fpout);
X	fclose(fpout);
X
X	if (token_verbose)
X		fprintf(stderr, "%s: %sfile %s generated\n", progname, (cfile ? "C " : ""), outfile);
X	exit(EXIT_SUCCESS);
}
/**
*       BUILD_NODE
*
*       Recursively build the next node and all its sub-nodes
**/
X
static  INDEX
build_node(int depth)
{
X	INDEX   nedges = 0;
X	INDEX   i;
X	NODE   *edge_list;
X
X	edge_list = NULL;
X	if (CURRENT_WORD(depth) == 0) {
X		/**
X	        *  End of word reached. If the next word isn't a continuation of the
X	        *  current one, then we've reached the bottom of the recursion tree.
X	        **/
X
X		read_next_word();
X		if (first_diff < depth)
X			return (0);
X	}
X	/* This malloc below costs like hell!  May someday rewrite the store
X	 * management for this bit... */
X	edge_list = (NODE *) malloc(MAX_CHARS * sizeof(NODE));
X	if (edge_list == NULL) {
X		fprintf(stderr, "%s: stack full (depth %d)\n", progname, depth);
X		exit(EXIT_FAILURE);
X	}
X	for (i = 0; i < MAX_CHARS; i++)
X		EDGE_LIST(i) = 0LL;
X
X	/**
X        *  Loop through all the sub-nodes until a word is read which can't
X        *  be reached via this node
X        **/
X
X	do {
X		/* Construct the edge. Letter.... */
X		EDGE_LIST(nedges) = (NODE) (((NODE) CURRENT_WORD(depth)))
X		    << (NODE) V_LETTER;
X		/* ....end-of-word flag.... */
X		if (CURRENT_WORD(depth + 1L) == 0)
X			EDGE_LIST(nedges) |= M_END_OF_WORD;
X		/* ....and node pointer. */
X		EDGE_LIST(nedges) |= build_node(depth + 1);
X		nedges++;
X		/* (don't ++ in a macro) */
X	} while (first_diff == depth);
X
X	if (first_diff > depth) {
X		fprintf(stderr, "%s: internal error -- first_diff = %d, depth = %d\n",
X		    progname, first_diff, depth);
X		exit(EXIT_FAILURE);
X	}
X	EDGE_LIST(nedges - 1) |= M_END_OF_NODE;
X	/* Flag the last edge in the node */
X
X	/**
X        *  Add the node to the dawg
X        **/
X
X	if (depth) {
X		NODE    result = add_node(edge_list, nedges);
X		free(edge_list);
X		return (result);
X	}
X	/**
X        *  depth is zero, so the root node (as a special case) goes at the start
X        **/
X
X	edge_list[MAX_CHARS - 1] |= M_END_OF_NODE;	/* For backward searches */
X	for (i = 0; i < MAX_CHARS; i++) {
X		dawg[i + 1] = edge_list[i];
X	}
X	free(edge_list);
X	return (0);
}
/**
*       ADD_NODE
*
*       Add a node to the dawg if it isn't already there. A hash table is
*       used to speed up the search for an identical node.
**/
X
static  INDEX
add_node(NODE * edge_list, INDEX nedges)
{
X	NODE    hash_entry;
X	INDEX   inc;
X	INDEX   a, first_a;
X	INDEX   i;
X
X	/**
X        *  Look for an identical node. A quadratic probing algorithm is used
X        *  to traverse the hash table.
X        **/
X
X	first_a = compute_hashcode(edge_list, nedges);
X	first_a = ABS(first_a) % HASH_TABLE_SIZE;
X	a = first_a;
X	inc = 9;
X
X	for (;;) {
X		hash_entry = HASH_TABLE(a) & M_NODE_POINTER;
X
X		if (hash_entry == 0)
X			break;	/* Node not found, so add it to the dawg */
X
X		for (i = 0; i < nedges; i++)
X			if (DAWG((hash_entry + i) % HASH_TABLE_SIZE) != EDGE_LIST(i))
X				break;
X
X		/* On the 1.6M dictionary, this gave a rangecheck with < 0.
X		 * Now fixed I think - it was a problem with MOD giving
X		 * unexpected results. */
X
X		if (i == nedges) {
X			return (hash_entry);	/* Node found */
X		}
X		/**
X	        *  Node not found here. Look in the next spot
X	        **/
X
X		a += inc;
X		inc += 8;
X		if (a >= HASH_TABLE_SIZE)
X			a -= HASH_TABLE_SIZE;
X		if (inc >= HASH_TABLE_SIZE)
X			inc -= HASH_TABLE_SIZE;
X		if (a == first_a) {
X			fprintf(stderr, "%s: hash table full\n", progname);
X			exit(EXIT_FAILURE);
X		}
X	}
X
X	/**
X        *  Add the node to the dawg
X        **/
X
X	if (total_edges + nedges >= MAX_EDGES) {
X		fprintf(stderr,
X		    "%s: error -- dictionary full - total edges = %ld\n",
X		    progname, total_edges);
X		fprintf(stderr,
X		    "%s: try running again with \"token -l infile outfile\"\n", progname);
X		exit(EXIT_FAILURE);
X	}
X	HASH_TABLE(a) |= total_edges + 1;
X	nnodes++;
X	for (i = 0; i < nedges; i++) {
X		DAWG((total_edges + 1 + i) % HASH_TABLE_SIZE) = EDGE_LIST(i);
X	}
X	total_edges += nedges;
X	return (total_edges - nedges + 1);
}
/**
*       READ_NEXT_WORD
*
*       Read the next word from the input file, setting first_diff accordingly
**/
X
static void
read_next_word(void)
{
X	/* This stuff imposes the limitation of not allowing '\0' in a word;
X	 * not yet a problem but the dawg structure itself could probably cope
X	 * if the feature were wanted. (Maybe with a little teweaking) */
X	unsigned char	linebuff[(MAX_LINE + 1)];
X	int     length;
X	for (;;) {
X		int     next = 0, c;
X		for (;;) {
X			c = fgetc(fpin);
X			if (FILE_ENDED || (c == EOF) || ferror(fpin) || feof(fpin)) {
X				/* for some reason, we always get a blank line
X				 * at the end of files */
X				current_word[0] = 0;
X				first_diff = -1;
X				linebuff[next] = '\0';
X				FILE_ENDED = TRUE;
X				return;
X			}
X			c &= 255;
X			if (next == 0 && c == '\n')
X				continue;	/* skip blank lines... */
X			linebuff[next++] = c;
X			if (c == '\n')
X				break;
X		}
X		linebuff[next] = '\0';
X
X		length = strlen(linebuff);
X
X		if (linebuff[length - 1] == '\n')
X			linebuff[length - 1] = '\0';
X		if (linebuff[length] == '\n')
X			linebuff[length] = '\0';
X
X		if ((length < 2) || (length > MAX_LINE - 1)) {
X			fprintf(stderr, "\n%s: %s - invalid length\n", progname, linebuff);
X			continue;	/* Previously exit()ed, but now ignore
X					 * so that test sites without my
X					 * pddict can use /usr/dict/words */
X		}
X		break;
X	}
X	for (length = 0; current_word[length] == linebuff[length]; length++) {
X		/* Get common part of string to check order */
X	}
X	if ((((unsigned int)current_word[length])&255) > (((unsigned int)linebuff[length])&255)) {
X		fprintf(stderr,
X		    "%s: word out of sequence (%s > %s) -- \"sort -u\" the dictionary please.\n(Be wary of 8-bit charsets and unix sort)\n",
X		    progname, linebuff, current_word);
X		exit(EXIT_FAILURE);
X	}
X	first_diff = length;
X
X	nwords++;
X	strcpy(current_word, linebuff);
X
X	if ((nwords > 1) && (!(nwords & 0x3FF)))
X		report_size();
X	this_char = current_word[0];	/* for diagnostics... */
}
/**
*       COMPUTE_HASHCODE
*
*       Compute the hash code for a node
**/
X
static  INDEX
compute_hashcode(NODE * edge_list, INDEX nedges)
{
X	INDEX   i;
X	INDEX   res = 0L;
X
X	for (i = 0; i < nedges; i++)
X		res = ((res << 1) | (res >> 31)) ^ EDGE_LIST(i);
X	return (res);
}
/**
*       REPORT_SIZE
*
*       Report the current size etc
**/
X
static void
report_size(void)
{
X
X	if (first_time) {
X		if (token_verbose)
X			fprintf(stderr, "      Words    Nodes    Edges    Bytes    BitsPW\n");
X		if (token_verbose)
X			fprintf(stderr, "      -----    -----    -----    -----    ------\n");
X		first_time = FALSE;
X	}
X	if (*current_word) {
X		if (token_verbose)
X			fprintf(stderr, "%c:", *current_word);
X	} else {
X		if (token_verbose)
X			fprintf(stderr, "Total:");
X	}
X
X	if (token_verbose)
X		fprintf(stderr, "  %7ld  %7ld  %7ld  %7ld  %8d\n",
X		    nwords, nnodes, total_edges,
X			(long) sizeof(long long /* NODE * */) * (total_edges + 1),
X			(int) ((sizeof(long long /* NODE * */) * (total_edges + 1) * 8) / nwords)
X		    );
}
SHAR_EOF
  (set 20 11 05 29 12 57 57 'token.c'; eval "$shar_touch") &&
  chmod 0644 'token.c'
if test $? -ne 0
then ${echo} 'restore of token.c failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'token.c: MD5 check failed'
       ) << SHAR_EOF
342ca6de231ef2e3fe1914f8339f52d7  token.c
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'token.c'` -ne 18202 && \
  ${echo} 'restoration warning:  size of token.c is not 18202'
  fi
fi
# ============= pdawg.c ==============
if test -f 'pdawg.c' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING pdawg.c (file already exists)'
else
${echo} 'x - extracting pdawg.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'pdawg.c' &&
#include "splib.h"
X
int spell_verbose = FALSE;
X
int
main(int argc, char **argv)
{
X    NODE           *dawg;
X    INDEX           nedges;
X
X    if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) {
X      argc -= 1; argv += 1; spell_verbose = TRUE;
X    }
X
X    if (!dawg_init((argc == 1 ? "" : argv[1]), &dawg, &nedges)) exit(EXIT_FAILURE);
X    dawg_print(dawg, (INDEX) ROOT_NODE);
X    if (spell_verbose) fprintf(stderr, "Finished printing dawg\n");
X    exit(EXIT_SUCCESS);
}
SHAR_EOF
  (set 20 11 05 29 12 57 53 'pdawg.c'; eval "$shar_touch") &&
  chmod 0644 'pdawg.c'
if test $? -ne 0
then ${echo} 'restore of pdawg.c failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'pdawg.c: MD5 check failed'
       ) << SHAR_EOF
3e6f0fe97d91acb0e4da9cb20fe38425  pdawg.c
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'pdawg.c'` -ne 467 && \
  ${echo} 'restoration warning:  size of pdawg.c is not 467'
  fi
fi
# ============= sextest.c ==============
if test -f 'sextest.c' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING sextest.c (file already exists)'
else
${echo} 'x - extracting sextest.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'sextest.c' &&
#include "splib.h"
X
X
static long
sex_change(long number)
{                /* Most inefficient and cumbersome (but safe) version) */
X  long b0, b1, b2, b3;
X  b0 = number&255L;   number >>= 8L;
X  b1 = number&255L;   number >>= 8L;
X  b2 = number&255L;   number >>= 8L;
X  b3 = number&255L;
X  number = b0;        number <<= 8L;
X  number = number|b1; number <<= 8L;
X  number = number|b2; number <<= 8L;
X  number = number|b3;
X  return(number);
}
X
int
main(int argc, char **argv)
{
X  FILE *in;
X  FILE *out;
X  NODE node;
X  long i;
X  if (argc != 3) {
X    fprintf(stderr, "usage: sextest infile outfile\n");
X    exit(EXIT_FAILURE);
X  }
X  in = fopen(argv[1], READ_BIN);
X  if (in == NULL) {
X    fprintf(stderr, "sextest: cannot read from %s\n", argv[1]);
X    exit(EXIT_FAILURE);
X  }
X  out = fopen(argv[2], WRITE_BIN);
X  if (out == NULL) {
X    fprintf(stderr, "sextest: cannot write to %s\n", argv[2]);
X    exit(EXIT_FAILURE);
X  }
X  for (;;) {
X    long l;
X    if ((i = fread((char *)&node, 1, sizeof(NODE), in)) != sizeof(NODE)) break;
X    l = sex_change(node);
X    fwrite((char *)&l, 1, sizeof(l), out);
X  }
X  fclose(in);
X  fprintf(stderr, "i = %ld\n", i);
X  fclose(out);
}
SHAR_EOF
  (set 20 11 05 29 12 57 54 'sextest.c'; eval "$shar_touch") &&
  chmod 0644 'sextest.c'
if test $? -ne 0
then ${echo} 'restore of sextest.c failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'sextest.c: MD5 check failed'
       ) << SHAR_EOF
c478bdc08d2308733560fe55c0d15047  sextest.c
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'sextest.c'` -ne 1161 && \
  ${echo} 'restoration warning:  size of sextest.c is not 1161'
  fi
fi
# ============= wordcheck.c ==============
if test -f 'wordcheck.c' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING wordcheck.c (file already exists)'
else
${echo} 'x - extracting wordcheck.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'wordcheck.c' &&
#include "splib.h"
#include <string.h>
X
int spell_verbose = FALSE;
X
/* Use system getopt.  Is there a header file for this? */
extern int      getopt(int argc, char **argv, char *opstring);
extern char    *optarg;
extern int      optind, opterr;
X
/* All our consts, types, and globals are in this header file */
#include "wordcheck.h"
X
/*
X * -d dict and -s stoplist params come through here.  The dictionaries are
X * loaded and noted in an array, which is used in 'check_file'
X */
void
add_dict(int enabling, char *dictname, int (*check) (NODE * dawg, char *word),
X         NODE * dawg, INDEX edges) {
X    dict[max_dict].dict = dawg;
X    dict[max_dict].edges = edges;
X    dict[max_dict].dict_name = dictname;
X    dict[max_dict].full_name = dictname;        /* For now - should expand
X                                                 * dawg_init args */
X    dict[max_dict].check = check;
X    if (enabling) {
X        dict[max_dict].enabling = TRUE;
X        if (wordcheck_verbose)
X            fprintf(stderr,
X                    "%s: accepting words from dict %s\n",
X                    progname, dictname);
X    } else {
X        dict[max_dict].enabling = FALSE;
X        if (wordcheck_verbose)
X            fprintf(stderr,
X                    "%s: suppressing words from dict %s\n",
X                    progname, dictname);
X    }
X    max_dict += 1;
X    if (max_dict == MAX_USER_DICTS) {
X        fprintf(stderr,
X                "%s: can\'t cope with more than %d user dictionaries\n",
X                progname, MAX_USER_DICTS);
X        exit(EXIT_FAILURE);
X    }
}
X
/*
X * Main body of spelling checker.  Takes a list of words, one per line, and
X * checks in dict.  This approach allows other (user-supplied) utilities to
X * define what exactly constitutes a word.  Outputs any rejected words to
X * stdout on a line on their own.
X */
void
check_file(FILE * f)
{
X    char            line[MAX_LINE_LEN];
X    int             ok;
X    int             i;
X
X    if (max_dict == 0) {
X        fprintf(stderr, "%s: no dictionaries given!\n", progname);
X        exit(EXIT_FAILURE);
X    }
X    for (;;) {
X        if (fgets(line, MAX_LINE_LEN, stdin) == NULL)
X            break;
X        if (ferror(stdin))
X            break;
X        if ((i = strlen(line)) <= 1)
X            continue;           /* Allow blank lines */
X        line[i - 1] = '\0';     /* remove '\n' */
X        ok = FALSE;
X        for (i = 0; i < max_dict; i++) {
X            /*
X             * rather neat code for minimum checking against multiple dicts
X             * and stop lists
X             */
X            if (!ok && dict[i].enabling) {
X                if (dict[i].check(dict[i].dict, line)) {
X                    ok = TRUE;
X                }
X            } else if (ok && !dict[i].enabling) {
X                if (dict[i].check(dict[i].dict, line)) {
X                    ok = FALSE;
X                }
X            }                   /* Otherwise skip to the next dict that
X                                 * matters */
X        }
X        if (!ok)
X            puts(line);
X    }
X    /* dawg_terminate(dawg); */
X    fflush(stdout);
}
X
void
usage(void)
{
X    /*
X     * If a usage error is given, we want the user to know which program
X     * really gave the error -- ie 'wordcheck' rather than spell.  This is
X     * because it is almost certainly a mistake on the part of the shell
X     * script writer, not the user.
X     */
X    fprintf(stderr,
X            "usage: %s -w progname -v -x -d dict -D transdict -s stoplist -S transstop\n",
X            trueprogname);
}
X
/*
X * wordcheck: takes a file of lines.  Each line is assumed to be a single
X * word, which is checked against the dictionaries.  Words which fail the
X * check are printed to stdout.  This supports multiple dictionaries and stop
X * lists.
X */
int
main(int argc, char **argv)
{
X    NODE           *dawg;
X    INDEX           edges;
X    int             c;
X
X    trueprogname = progname = argv[0];
X    exact_case = FALSE;
X
X    while ((c = getopt(argc, argv, "D:d:S:s:vw:xyh?")) != -1) {
X        switch (c) {
X        case 'D':
X            if (!dawg_init(optarg, &dawg, &edges)) {
X                fprintf(stderr,
X                        "%s: cannot load translation list \"%s\"\n",
X                        progname, optarg);
X                exit(EXIT_FAILURE);
X            }
X            /*
X             * The "left=right" style of dictionary requires a slightly
X             * different checking procedure.
X             */
X            add_dict(ENABLING, optarg, dawg_checkeq, dawg, edges);
X            if (!exact_case)
X                add_dict(ENABLING, optarg, dawg_casecheckeq, dawg, edges);
X            break;
X        case 'd':
X            if (!dawg_init(optarg, &dawg, &edges)) {
X                fprintf(stderr,
X                        "%s: cannot load dictionary \"%s\"\n",
X                        progname, optarg);
X                exit(EXIT_FAILURE);
X            }
X            add_dict(ENABLING, optarg, dawg_check, dawg, edges);
X            /*
X             * If we're not worried about exact case matching, we can add
X             * another procedure to check the word less strictly.  Note that
X             * the second procedure will only be called if the first returns
X             * false.
X             */
X            if (!exact_case)
X                add_dict(ENABLING, optarg, dawg_casecheck, dawg, edges);
X            break;
X        case 'S':
X            if (!dawg_init(optarg, &dawg, &edges)) {
X                fprintf(stderr,
X                        "%s: cannot load translation stop list \"%s\"\n",
X                        progname, optarg);
X                exit(EXIT_FAILURE);
X            }
X            /*
X             * The "left=right" style of dictionary requires a slightly
X             * different checking procedure.
X             */
X            add_dict(DISABLING, optarg, dawg_checkeq, dawg, edges);
X            if (!exact_case)
X                add_dict(DISABLING, optarg, dawg_casecheckeq, dawg, edges);
X            break;
X        case 's':
X            if (!dawg_init(optarg, &dawg, &edges)) {
X                fprintf(stderr,
X                        "%s: cannot load stop list \"%s\"\n",
X                        progname, optarg);
X                exit(EXIT_FAILURE);
X            }
X            add_dict(DISABLING, optarg, dawg_check, dawg, edges);
X            if (!exact_case)
X                add_dict(DISABLING, optarg, dawg_casecheck, dawg, edges);
X            break;
X        case 'v':
X            /* LOUD, AREN'T YOU? */
X	    wordcheck_verbose = TRUE; spell_verbose = TRUE;
X            break;
X        case 'w':
X            /* Inherit our callers program name, for better diagnostics */
X            progname = optarg;
X            break;
X        case 'x':
X            /* Words must match those in dicts following this flag exactly. */
X            exact_case = TRUE;
X            break;
X        case 'y':
X            /*
X             * Normal service has been resumed.  This is only likely to be
X             * needed if you've built a dawg from AN ALL UPPERCASE WORD LIST
X             * :-(
X             */
X            exact_case = TRUE;
X            break;
X        case 'h':
X        case '?':
X            usage();
X            exit(EXIT_SUCCESS);
X            break;
X        default:
X            fprintf(stderr,
X                    "syntax: %s -w progname -v -x -d dict -s stoplist -t translate\n", argv[0]);
X            exit(EXIT_FAILURE);
X        }
X    }
X
X    /* Spelling from stdin? */
X    if (optind == argc) {
X        if (wordcheck_verbose)
X            fprintf(stderr, "%s: checking stdin\n", progname);
X        check_file(stdin);
X        exit(EXIT_SUCCESS);
X    }
X    /* Lots of files -- do them all. */
X    /* Perhaps should check each file before doing any, but why bother? */
X    for (; optind < argc; optind++) {
X        if (wordcheck_verbose)
X            fprintf(stderr,
X                    "%s: checking text file %s\n", progname, argv[optind]);
X        if (freopen(argv[optind], "r", stdin) == NULL) {
X            fprintf(stderr,
X                 "%s: cannot open input file %s\n", progname, argv[optind]);
X            exit(EXIT_FAILURE);
X        }
X        check_file(stdin);
X    }
X
X    exit(EXIT_SUCCESS);
X    /* NAUGHT RETCHED */
X    return (0);
}
SHAR_EOF
  (set 20 11 05 29 12 57 57 'wordcheck.c'; eval "$shar_touch") &&
  chmod 0644 'wordcheck.c'
if test $? -ne 0
then ${echo} 'restore of wordcheck.c failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wordcheck.c: MD5 check failed'
       ) << SHAR_EOF
5e89dea53240958a38d9f35e0e4d8d55  wordcheck.c
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'wordcheck.c'` -ne 8189 && \
  ${echo} 'restoration warning:  size of wordcheck.c is not 8189'
  fi
fi
# ============= dawg_words.c ==============
if test -f 'dawg_words.c' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING dawg_words.c (file already exists)'
else
${echo} 'x - extracting dawg_words.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'dawg_words.c' &&
/* dawg_words.c - find words in a dawg using letters on your rack */
X
/* Copyright (C) 1994 by John J. Chew, III <jjchew@math.utoronto.ca>
* All rights reserved.
* 
* Usage: dawg_words.c -d dict.dawg -r rack
*
* Lists words to stdout.
*/
X
/* based on Graham Toal's DAWG package, as posted to alt.sources */
/* See Also... SpellLib/wild.c */
X
#undef DEBUG
#define MAXWORD 256
X
#include <stdio.h>
#include <unistd.h>
X
#include "splib.h"
X
int spell_verbose = FALSE;
X
#ifdef DEBUG
#define PR_DUMP(Tag, I, Old, New) \
X      printf("%s: i=%d old=%08x[%c]%c%c new=%08x[%c]%c%c ", (Tag), (I), \
X	(Old)-dawg, ((*(Old))>>V_LETTER) & M_LETTER, \
X	(*(Old)&M_END_OF_NODE)?'N':' ', \
X	(*(Old)&M_END_OF_WORD)?'W':' ', \
X	(New)-dawg, (*(New))>>V_LETTER & M_LETTER, \
X	(*(New)&M_END_OF_NODE)?'N':' ', \
X	(*(New)&M_END_OF_WORD)?'W':' ' \
X	); \
X	putRack(nChars); putchar(' '); \
X        putWord(word, blanks, i); 
X
#endif
X
void putRack(unsigned int *count) {
X  register int i, j; 
X  for (i=0; i<256; i++) for (j=0; j<count[i]; j++) putchar(i);
X  }
X   
void putWord(char *chars, int *blanks, int length) {
X  register char ch;
X  while (length--) {
X    ch = *chars++;
#ifdef OLD_BUG
X    *blanks++ ? putchar(ch ^ ('a'-'A')) : putchar(ch); /* ASCIIism */
#else
X    /* code was not i18n.  We also want html ... */ 
X    *blanks++ ? printf("<strong>%c</strong>", ch): putchar(ch);
#endif
X    }
X  putchar('\n');
X  return;
X  }
X
void processRack(NODE *dawg, register char *rack, int bingosOnly) {
X  unsigned int       bingoLength = 0;
X  int                blanks[MAXWORD];
X  NODE              *edge;
X  register int       i;
X  register unsigned  u;
X  unsigned int       nBlanks = 0;
X  unsigned int       nChars[256];
X  NODE              *stemEdges[MAXWORD];
X  char               word[MAXWORD];
X  
X  (void) memset(&nChars[0], 0, sizeof nChars);
X  while (u = *rack++) { bingoLength++; u == '?' ? nBlanks++ : nChars[u]++; }
X
X  edge = dawg + ROOT_NODE;
X  i = 0;
#ifdef DEBUG
X  PR_DUMP("st", i, edge, edge)
#endif
X
X  while (1) {
X    u = (*edge >> V_LETTER) & M_LETTER;     /* u = char at this node       */
X    if (nChars[u]) {                        /* if still a u on rack        */
X      nChars[u]--;                            /* take it off the rack      */
X      blanks[i] = 0;                          /* not a blank               */
X      goto added_letter;
X      }
X    else if (nBlanks) {
X      nBlanks--;
X      blanks[i] = 1;
added_letter:
X      word[i] = u;
X      if (*edge & M_END_OF_WORD) {              /* if we have a word       */
X	if (bingoLength == i+1) {                   /* if it's long enough   */
X	  putWord(word, blanks, i+1);
X	  goto unadd;
X	  }
X	if (!bingosOnly)                         /* if we don't care       */
X	  putWord(word, blanks, i+1);
X	}
X      if (*edge & M_NODE_POINTER) {             /* can we go deeper?       */
#ifdef DEBUG
X        PR_DUMP("dn", i, edge, dawg+(*edge&M_NODE_POINTER))
#endif
X        stemEdges[i++] = edge;                    /* save this stem        */
X        edge = dawg + (*edge & M_NODE_POINTER);   /* walk down graph       */
X	continue;                                 /* try again             */
X        }
unadd:
X      blanks[i] ? nBlanks++ : nChars[u]++;
X      }
up:
X    while (*edge & M_END_OF_NODE) {
X      if (i-- == 0) return;
#ifdef DEBUG
X      PR_DUMP("up", i, edge, stemEdges[i])
#endif
X      blanks[i] ? nBlanks++ : nChars[word[i]]++;
X      edge = stemEdges[i];
X      }
#ifdef DEBUG
X    PR_DUMP("nx", i, edge, edge+1)
#endif
X    edge++;                                   /* try next edge       */
X    }
X  return;
X  }
X
int main(unsigned argc, char **argv) {
X  int           bingosOnly = 1;
X  NODE         *dawg;
X  char         *dictFileName = 0;
X  register int  i;
X  INDEX         nedges;
X  unsigned int  nErrors = 0;
X  extern int    optind;
X  extern char  *optarg;
X  char         *rackString = 0;
X
X  while (EOF != (i = getopt(argc, argv, "abd:r:"))) switch(i) {
X    case 'a': bingosOnly = 0; break;
X    case 'b': bingosOnly = 1; break;
X    case 'd': dictFileName = optarg; break;
X    case 'r': rackString = optarg; break;
X    case '?': nErrors = 1; break;
X    }
X
X  if (nErrors || !dictFileName || !rackString || optind != argc) {
X    fprintf(stderr, "Usage: %s [-a|-b] -d dict -r rack\n", argv[0]); 
X    fputs("  -a       list all words, not just bingos\n", stderr);
X    fputs("  -b       list bingos only (default)\n", stderr);
X    fputs("  -d dict  DAWG dictionary in which to find words\n", stderr);
X    fputs("  -r rack  letters with which to make word (?=blank)\n", stderr);
X    exit(2);
X    }
X
X  if (!dawg_init(dictFileName, &dawg, &nedges)) exit(2);
X
X  processRack(dawg, rackString, bingosOnly);
X
X  exit(0);
X  }
X
SHAR_EOF
  (set 20 11 05 29 13 16 13 'dawg_words.c'; eval "$shar_touch") &&
  chmod 0644 'dawg_words.c'
if test $? -ne 0
then ${echo} 'restore of dawg_words.c failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'dawg_words.c: MD5 check failed'
       ) << SHAR_EOF
e364fecd5f681347a0674127b0211575  dawg_words.c
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'dawg_words.c'` -ne 4658 && \
  ${echo} 'restoration warning:  size of dawg_words.c is not 4658'
  fi
fi
# ============= dawg_challenge.c ==============
if test -f 'dawg_challenge.c' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING dawg_challenge.c (file already exists)'
else
${echo} 'x - extracting dawg_challenge.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'dawg_challenge.c' &&
/* dawg_challenge.c - use a dawg file to resolve a word game challenge */
X
/* Copyright (C) 1994 by John J. Chew, III <jjchew@math.utoronto.ca>
X * All rights reserved.
X * 
X * Usage: dawg_challenge dict.dawg word1 word2 ...
X *
X * Exits with status 0 if all words are acceptable, status 1 if at least
X * one is not, status 2 if an error occurs.
X */
X
/* based on Graham Toal's DAWG package, as posted to alt.sources */
X
/* Manadatory header files */
#include <stdio.h>
#include "splib.h"
X
int spell_verbose = FALSE;
X
int main(argc, argv)
X  unsigned argc;
X  char *argv[];
X  {
X  NODE *dawg;
X  INDEX nedges;
X  int i;
X
X  if (argc < 3) exit(2);
X  if (!dawg_init(argv[1], &dawg, &nedges)) exit(2);
X  for (i=2; i<argc; i++)
X    if (!dawg_check(dawg, argv[i])) exit(1);
X  exit(0);
X  }
SHAR_EOF
  (set 20 11 05 29 13 17 20 'dawg_challenge.c'; eval "$shar_touch") &&
  chmod 0644 'dawg_challenge.c'
if test $? -ne 0
then ${echo} 'restore of dawg_challenge.c failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'dawg_challenge.c: MD5 check failed'
       ) << SHAR_EOF
631eb10cd2df08eb0d836e409e781173  dawg_challenge.c
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'dawg_challenge.c'` -ne 774 && \
  ${echo} 'restoration warning:  size of dawg_challenge.c is not 774'
  fi
fi
# ============= makefile ==============
if test -f 'makefile' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING makefile (file already exists)'
else
${echo} 'x - extracting makefile (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'makefile' &&
# CC = gcc -DMEMDEBUG -Wall -Wshadow -Wid-clash-8 -Wpointer-arith -Wcast-qual -Wwrite-strings
CC = gcc -g -ansi -D_ANSI_SOURCE
#LEX = lex
LEX = flex
#LEXLIB = -ll
LEXLIB = -lfl
MEMDEBUG = 
X
all:	token pdawg wordtell wordcheck sextest wordroff wordtex spell.shar screensp.o dawg_words dawg_challenge # boggle
X	echo All programs up to date.
X
# boggle has been moved to ../gtboggle.  See also ../gboggle
X
dawg_challenge: dawg_challenge.c
X	cc -o dawg_challenge dawg_challenge.c -L. -lspell
X
dawg_words: dawg_words.c
X	cc -o dawg_words dawg_words.c -L. -lspell
X
boggle: boggle.c
X	cc -o boggle boggle.c -L. -lspell
X
wordroff:	wordroff.l
X	$(LEX) wordroff.l
X	$(CC) -o wordroff lex.yy.c $(LEXLIB)
X
libspell.a:	makefile
X	echo NEED TO MAKE LIBSPELL.A
X
wordtex:	wordtex.l
X	$(LEX) wordtex.l
X	$(CC) -o wordtex lex.yy.c $(LEXLIB)
X
sharfile:	spell.shar
X	@echo Sharfile created
X
spell.shar:	ReadMe grope.h porting.h splib.h dawg.h token.c pdawg.c sextest.c wordtell.c wordcheck.c dawg_words.c dawg_challenge.c makefile
X	shar ReadMe grope.h porting.h splib.h dawg.h token.c pdawg.c sextest.c wordcheck.c dawg_words.c dawg_challenge.c makefile > spell.shar
X
token:	token.c dawg.h splib.h libspell.a
X	$(CC) -o token token.c $(MEMDEBUG) -L. -lspell 
X
pdawg:	pdawg.c splib.h libspell.a
X	$(CC) -o pdawg pdawg.c $(MEMDEBUG) -L. -lspell 
X
wordcheck:	wordcheck.c splib.h libspell.a
X	$(CC) -o wordcheck wordcheck.c $(MEMDEBUG) -L. -lspell 
X
screensp.o:	wordcheck.c splib.h
X	$(CC) -c screensp.c $(MEMDEBUG)
X
wordtell:	wordtell.c splib.h libspell.a
X	$(CC) -o wordtell wordtell.c $(MEMDEBUG) -L. -lspell
X
sextest:	sextest.c
X	$(CC) -o sextest sextest.c
X
clean:	pdawg token wordcheck sextest wordroff wordtex
X	rm pdawg
X	rm token
X	rm wordcheck
X	rm sextest
X	rm dawg_words
X	rm dawg_challenge
SHAR_EOF
  (set 20 11 05 29 12 58 14 'makefile'; eval "$shar_touch") &&
  chmod 0644 'makefile'
if test $? -ne 0
then ${echo} 'restore of makefile failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'makefile: MD5 check failed'
       ) << SHAR_EOF
dacc18ac9477e06a2d0d1bdfa44aa587  makefile
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'makefile'` -ne 1756 && \
  ${echo} 'restoration warning:  size of makefile is not 1756'
  fi
fi
if rm -fr ${lock_dir}
then ${echo} 'x - removed lock directory `'${lock_dir}\''.'
else ${echo} 'x - failed to remove lock directory `'${lock_dir}\''.'
  exit 1
fi
exit 0
