[comp.sources.games] v01i026: fortune - quote for the day, Part02/16

games-request@tekred.UUCP (05/27/87)

Submitted by: arnold@apollo.UUCP
Comp.sources.games: Volume 1, Issue 26
Archive-name: fortune/Part02



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 16)."
# Contents:  rnd.c strfile.c unstr.c :trfix Troff.sed
# Wrapped by billr@tekred on Thu May 21 16:54:43 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f rnd.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"rnd.c\"
else
echo shar: Extracting \"rnd.c\" \(12105 characters\)
sed "s/^X//" >rnd.c <<'END_OF_rnd.c'
X/*
X * code for when the good (berkeley) random number generator is around
X */
X
Xrnd(num)
X{
X	extern long	random();
X
X	return (random() % num);
X}
X
Xsrnd(num)
X{
X	srandom(num);
X}
X
X#ifdef	NO_RANDOM
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)random.c	4.2	(Berkeley)	83/01/02";
X#endif
X
X#include	<stdio.h>
X
X/*
X * random.c:
X * An improved random number generation package.  In addition to the standard
X * rand()/srand() like interface, this package also has a special state info
X * interface.  The initstate() routine is called with a seed, an array of
X * bytes, and a count of how many bytes are being passed in; this array is then
X * initialized to contain information for random number generation with that
X * much state information.  Good sizes for the amount of state information are
X * 32, 64, 128, and 256 bytes.  The state can be switched by calling the
X * setstate() routine with the same array as was initiallized with initstate().
X * By default, the package runs with 128 bytes of state information and
X * generates far better random numbers than a linear congruential generator.
X * If the amount of state information is less than 32 bytes, a simple linear
X * congruential R.N.G. is used.
X * Internally, the state information is treated as an array of longs; the
X * zeroeth element of the array is the type of R.N.G. being used (small
X * integer); the remainder of the array is the state information for the
X * R.N.G.  Thus, 32 bytes of state information will give 7 longs worth of
X * state information, which will allow a degree seven polynomial.  (Note: the 
X * zeroeth word of state information also has some other information stored
X * in it -- see setstate() for details).
X * The random number generation technique is a linear feedback shift register
X * approach, employing trinomials (since there are fewer terms to sum up that
X * way).  In this approach, the least significant bit of all the numbers in
X * the state table will act as a linear feedback shift register, and will have
X * period 2^deg - 1 (where deg is the degree of the polynomial being used,
X * assuming that the polynomial is irreducible and primitive).  The higher
X * order bits will have longer periods, since their values are also influenced
X * by pseudo-random carries out of the lower bits.  The total period of the
X * generator is approximately deg*(2**deg - 1); thus doubling the amount of
X * state information has a vast influence on the period of the generator.
X * Note: the deg*(2**deg - 1) is an approximation only good for large deg,
X * when the period of the shift register is the dominant factor.  With deg
X * equal to seven, the period is actually much longer than the 7*(2**7 - 1)
X * predicted by this formula.
X */
X
X
X
X/*
X * For each of the currently supported random number generators, we have a
X * break value on the amount of state information (you need at least this
X * many bytes of state info to support this random number generator), a degree
X * for the polynomial (actually a trinomial) that the R.N.G. is based on, and
X * the separation between the two lower order coefficients of the trinomial.
X */
X
X#define		TYPE_0		0		/* linear congruential */
X#define		BREAK_0		8
X#define		DEG_0		0
X#define		SEP_0		0
X
X#define		TYPE_1		1		/* x**7 + x**3 + 1 */
X#define		BREAK_1		32
X#define		DEG_1		7
X#define		SEP_1		3
X
X#define		TYPE_2		2		/* x**15 + x + 1 */
X#define		BREAK_2		64
X#define		DEG_2		15
X#define		SEP_2		1
X
X#define		TYPE_3		3		/* x**31 + x**3 + 1 */
X#define		BREAK_3		128
X#define		DEG_3		31
X#define		SEP_3		3
X
X#define		TYPE_4		4		/* x**63 + x + 1 */
X#define		BREAK_4		256
X#define		DEG_4		63
X#define		SEP_4		1
X
X
X/*
X * Array versions of the above information to make code run faster -- relies
X * on fact that TYPE_i == i.
X */
X
X#define		MAX_TYPES	5		/* max number of types above */
X
Xstatic  int		degrees[ MAX_TYPES ]	= { DEG_0, DEG_1, DEG_2,
X								DEG_3, DEG_4 };
X
Xstatic  int		seps[ MAX_TYPES ]	= { SEP_0, SEP_1, SEP_2,
X								SEP_3, SEP_4 };
X
X
X
X/*
X * Initially, everything is set up as if from :
X *		initstate( 1, &randtbl, 128 );
X * Note that this initialization takes advantage of the fact that srandom()
X * advances the front and rear pointers 10*rand_deg times, and hence the
X * rear pointer which starts at 0 will also end up at zero; thus the zeroeth
X * element of the state information, which contains info about the current
X * position of the rear pointer is just
X *	MAX_TYPES*(rptr - state) + TYPE_3 == TYPE_3.
X */
X
Xstatic  long		randtbl[ DEG_3 + 1 ]	= { TYPE_3,
X			    0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 
X			    0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 
X			    0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, 
X			    0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 
X			    0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, 
X			    0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, 
X			    0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 
X					0xf5ad9d0e, 0x8999220b, 0x27fb47b9 };
X
X/*
X * fptr and rptr are two pointers into the state info, a front and a rear
X * pointer.  These two pointers are always rand_sep places aparts, as they cycle
X * cyclically through the state information.  (Yes, this does mean we could get
X * away with just one pointer, but the code for random() is more efficient this
X * way).  The pointers are left positioned as they would be from the call
X *			initstate( 1, randtbl, 128 )
X * (The position of the rear pointer, rptr, is really 0 (as explained above
X * in the initialization of randtbl) because the state table pointer is set
X * to point to randtbl[1] (as explained below).
X */
X
Xstatic  long		*fptr			= &randtbl[ SEP_3 + 1 ];
Xstatic  long		*rptr			= &randtbl[ 1 ];
X
X
X
X/*
X * The following things are the pointer to the state information table,
X * the type of the current generator, the degree of the current polynomial
X * being used, and the separation between the two pointers.
X * Note that for efficiency of random(), we remember the first location of
X * the state information, not the zeroeth.  Hence it is valid to access
X * state[-1], which is used to store the type of the R.N.G.
X * Also, we remember the last location, since this is more efficient than
X * indexing every time to find the address of the last element to see if
X * the front and rear pointers have wrapped.
X */
X
Xstatic  long		*state			= &randtbl[ 1 ];
X
Xstatic  int		rand_type		= TYPE_3;
Xstatic  int		rand_deg		= DEG_3;
Xstatic  int		rand_sep		= SEP_3;
X
Xstatic  long		*end_ptr		= &randtbl[ DEG_3 + 1 ];
X
X
X
X/*
X * srandom:
X * Initialize the random number generator based on the given seed.  If the
X * type is the trivial no-state-information type, just remember the seed.
X * Otherwise, initializes state[] based on the given "seed" via a linear
X * congruential generator.  Then, the pointers are set to known locations
X * that are exactly rand_sep places apart.  Lastly, it cycles the state
X * information a given number of times to get rid of any initial dependencies
X * introduced by the L.C.R.N.G.
X * Note that the initialization of randtbl[] for default usage relies on
X * values produced by this routine.
X */
X
Xsrandom( x )
X
X    unsigned		x;
X{
X    	register  int		i, j;
X
X	if(  rand_type  ==  TYPE_0  )  {
X	    state[ 0 ] = x;
X	}
X	else  {
X	    j = 1;
X	    state[ 0 ] = x;
X	    for( i = 1; i < rand_deg; i++ )  {
X		state[i] = 1103515245*state[i - 1] + 12345;
X	    }
X	    fptr = &state[ rand_sep ];
X	    rptr = &state[ 0 ];
X	    for( i = 0; i < 10*rand_deg; i++ )  random();
X	}
X}
X
X
X
X/*
X * initstate:
X * Initialize the state information in the given array of n bytes for
X * future random number generation.  Based on the number of bytes we
X * are given, and the break values for the different R.N.G.'s, we choose
X * the best (largest) one we can and set things up for it.  srandom() is
X * then called to initialize the state information.
X * Note that on return from srandom(), we set state[-1] to be the type
X * multiplexed with the current value of the rear pointer; this is so
X * successive calls to initstate() won't lose this information and will
X * be able to restart with setstate().
X * Note: the first thing we do is save the current state, if any, just like
X * setstate() so that it doesn't matter when initstate is called.
X * Returns a pointer to the old state.
X */
X
Xchar  *
Xinitstate( seed, arg_state, n )
X
X    unsigned		seed;			/* seed for R. N. G. */
X    char		*arg_state;		/* pointer to state array */
X    int			n;			/* # bytes of state info */
X{
X	register  char		*ostate		= (char *)( &state[ -1 ] );
X
X	if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
X	else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
X	if(  n  <  BREAK_1  )  {
X	    if(  n  <  BREAK_0  )  {
X		fprintf( stderr, "initstate: not enough state (%d bytes) with which to do jack; ignored.\n" );
X		return;
X	    }
X	    rand_type = TYPE_0;
X	    rand_deg = DEG_0;
X	    rand_sep = SEP_0;
X	}
X	else  {
X	    if(  n  <  BREAK_2  )  {
X		rand_type = TYPE_1;
X		rand_deg = DEG_1;
X		rand_sep = SEP_1;
X	    }
X	    else  {
X		if(  n  <  BREAK_3  )  {
X		    rand_type = TYPE_2;
X		    rand_deg = DEG_2;
X		    rand_sep = SEP_2;
X		}
X		else  {
X		    if(  n  <  BREAK_4  )  {
X			rand_type = TYPE_3;
X			rand_deg = DEG_3;
X			rand_sep = SEP_3;
X		    }
X		    else  {
X			rand_type = TYPE_4;
X			rand_deg = DEG_4;
X			rand_sep = SEP_4;
X		    }
X		}
X	    }
X	}
X	state = &(  ( (long *)arg_state )[1]  );	/* first location */
X	end_ptr = &state[ rand_deg ];	/* must set end_ptr before srandom */
X	srandom( seed );
X	if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
X	else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
X	return( ostate );
X}
X
X
X
X/*
X * setstate:
X * Restore the state from the given state array.
X * Note: it is important that we also remember the locations of the pointers
X * in the current state information, and restore the locations of the pointers
X * from the old state information.  This is done by multiplexing the pointer
X * location into the zeroeth word of the state information.
X * Note that due to the order in which things are done, it is OK to call
X * setstate() with the same state as the current state.
X * Returns a pointer to the old state information.
X */
X
Xchar  *
Xsetstate( arg_state )
X
X    char		*arg_state;
X{
X	register  long		*new_state	= (long *)arg_state;
X	register  int		type		= new_state[0]%MAX_TYPES;
X	register  int		rear		= new_state[0]/MAX_TYPES;
X	char			*ostate		= (char *)( &state[ -1 ] );
X
X	if(  rand_type  ==  TYPE_0  )  state[ -1 ] = rand_type;
X	else  state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type;
X	switch(  type  )  {
X	    case  TYPE_0:
X	    case  TYPE_1:
X	    case  TYPE_2:
X	    case  TYPE_3:
X	    case  TYPE_4:
X		rand_type = type;
X		rand_deg = degrees[ type ];
X		rand_sep = seps[ type ];
X		break;
X
X	    default:
X		fprintf( stderr, "setstate: state info has been munged; not changed.\n" );
X	}
X	state = &new_state[ 1 ];
X	if(  rand_type  !=  TYPE_0  )  {
X	    rptr = &state[ rear ];
X	    fptr = &state[ (rear + rand_sep)%rand_deg ];
X	}
X	end_ptr = &state[ rand_deg ];		/* set end_ptr too */
X	return( ostate );
X}
X
X
X
X/*
X * random:
X * If we are using the trivial TYPE_0 R.N.G., just do the old linear
X * congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the
X * same in all ther other cases due to all the global variables that have been
X * set up.  The basic operation is to add the number at the rear pointer into
X * the one at the front pointer.  Then both pointers are advanced to the next
X * location cyclically in the table.  The value returned is the sum generated,
X * reduced to 31 bits by throwing away the "least random" low bit.
X * Note: the code takes advantage of the fact that both the front and
X * rear pointers can't wrap on the same call by not testing the rear
X * pointer if the front one has wrapped.
X * Returns a 31-bit random number.
X */
X
Xlong
Xrandom()
X{
X	long		i;
X	
X	if(  rand_type  ==  TYPE_0  )  {
X	    i = state[0] = ( state[0]*1103515245 + 12345 )&0x7fffffff;
X	}
X	else  {
X	    *fptr += *rptr;
X	    i = (*fptr >> 1)&0x7fffffff;	/* chucking least random bit */
X	    if(  ++fptr  >=  end_ptr  )  {
X		fptr = state;
X		++rptr;
X	    }
X	    else  {
X		if(  ++rptr  >=  end_ptr  )  rptr = state;
X	    }
X	}
X	return( i );
X}
X
X#endif	NO_RANDOM
END_OF_rnd.c
if test 12105 -ne `wc -c <rnd.c`; then
    echo shar: \"rnd.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f strfile.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"strfile.c\"
else
echo shar: Extracting \"strfile.c\" \(8802 characters\)
sed "s/^X//" >strfile.c <<'END_OF_strfile.c'
X# include	<stdio.h>
X# include	<ctype.h>
X# include	<sys/types.h>
X# include	"strfile.h"
X
X/*
X *	This program takes a file composed of strings seperated by
X * lines starting with two consecutive delimiting character (default
X * character is '%') and creates another file which consists of a table
X * describing the file (structure from "strfile.h"), a table of seek
X * pointers to the start of the strings, and the strings, each terinated
X * by a null byte.  Usage:
X *
X *	% strfile [ - ] [ -cC ] [ -sv ] [ -oir ] sourcefile [ datafile ]
X *
X *	- - Give a usage summary useful for jogging the memory
X *	c - Change delimiting character from '%' to 'C'
X *	s - Silent.  Give no summary of data processed at the end of
X *	    the run.
X *	v - Verbose.  Give summary of data processed.  (Default)
X *	o - order the strings in alphabetic order
X *	i - if ordering, ignore case 
X *	r - randomize the order of the strings
X *
X *		Ken Arnold	Sept. 7, 1978 --
X *
X *	Added method to indicate dividers.  A "%-" will cause the address
X * to be added to the structure in one of the pointer elements.
X *
X *		Ken Arnold	Nov., 1984 --
X *
X *	Added ordering options.
X */
X
X# define	TRUE	1
X# define	FALSE	0
X
X# define	DELIM_CH	'-'
X
Xtypedef struct {
X	char	first;
X	off_t	pos;
X} STR;
X
Xchar	*Infile		= NULL,		/* input file name */
X	Outfile[100]	= "",		/* output file name */
X	Delimch		= '%',		/* delimiting character */
X	*Usage[]	= {		/* usage summary */
X       "usage:	strfile [ - ] [ -cC ] [ -sv ] [ -oir ] inputfile [ datafile ]",
X       "	- - Give this usage summary",
X       "	c - Replace delimiting character with 'C'",
X       "	s - Silent.  Give no summary",
X       "	v - Verbose.  Give summary.  (default)",
X       "	o - order strings alphabetically",
X       "	i - ignore case in ordering",
X       "	r - randomize the order of the strings",
X       "	Default \"datafile\" is inputfile.dat",
X	NULL
X	};
X
Xint	Sflag		= FALSE;	/* silent run flag */
Xint	Oflag		= FALSE;	/* ordering flag */
Xint	Iflag		= FALSE;	/* ignore case flag */
Xint	Rflag		= FALSE;	/* randomize order flag */
Xint	Delim		= 0;		/* current delimiter number */
X
Xoff_t	*Seekpts;
X
XFILE	*Sort_1, *Sort_2;		/* pointers for sorting */
X
XSTRFILE	Tbl;				/* statistics table */
X
XSTR	*Firstch;			/* first chars of each string */
X
Xchar	*fgets(), *malloc(), *strcpy(), *strcat();
X
Xmain(ac, av)
Xint	ac;
Xchar	**av;
X{
X	register char		*sp, dc;
X	register off_t		*lp;
X	register unsigned int	curseek;	/* number of strings */
X	register off_t		*seekpts, li;	/* table of seek pointers */
X	register FILE		*inf, *outf;
X	register int		first;
X	register char		*nsp;
X	register STR		*fp;
X	static char		string[257];
X
X	getargs(ac, av);		/* evalute arguments */
X
X	/*
X	 * initial counting of input file
X	 */
X
X	dc = Delimch;
X	if ((inf = fopen(Infile, "r")) == NULL) {
X		perror(Infile);
X		exit(-1);
X	}
X	for (curseek = 0; (sp = fgets(string, 256, inf)) != NULL; )
X		if (*sp++ == dc && (*sp == dc || *sp == DELIM_CH))
X			curseek++;
X	curseek++;
X
X	/*
X	 * save space at begginning of file for tables
X	 */
X
X	if ((outf = fopen(Outfile, "w")) == NULL) {
X		perror(Outfile);
X		exit(-1);
X	}
X
X	/*
X	 * Allocate space for the pointers, adding one to the end so the
X	 * length of the final string can be calculated.
X	 */
X	++curseek;
X	seekpts = (off_t *) malloc(sizeof *seekpts * curseek);	/* NOSTRICT */
X	if (seekpts == NULL) {
X		perror("calloc");
X		exit(-1);
X	}
X	if (Oflag) {
X		Firstch = (STR *) malloc(sizeof *Firstch * curseek);
X		if (Firstch == NULL) {
X			perror("calloc");
X			exit(-1);
X		}
X	}
X
X	(void) fseek(outf, (off_t) (sizeof Tbl + sizeof *seekpts * curseek), 0);
X	(void) fseek(inf, (off_t) 0, 0);	/* goto start of input */
X
X	/*
X	 * write the strings onto the file
X	 */
X
X	Tbl.str_longlen = 0;
X	Tbl.str_shortlen = (unsigned int) 0xffffffff;
X	lp = seekpts;
X	first = Oflag;
X	*seekpts = ftell(outf);
X	fp = Firstch;
X	do {
X		sp = fgets(string, 256, inf);
X		if (sp == NULL ||
X		    (*sp == dc && (sp[1] == dc || sp[1] == DELIM_CH))) {
X			putc('\0', outf);
X			*++lp = ftell(outf);
X			li = ftell(outf) - lp[-1] - 1;
X			if (Tbl.str_longlen < li)
X				Tbl.str_longlen = li;
X			if (Tbl.str_shortlen > li)
X				Tbl.str_shortlen = li;
X			if (sp && sp[1] == DELIM_CH && Delim < MAXDELIMS) {
X				Tbl.str_dpos[Delim] = *lp;
X				Tbl.str_delims[Delim++] = lp - seekpts;
X			}
X			first = Oflag;
X		}
X		else {
X			if (first) {
X				for (nsp = sp; !isalnum(*nsp); nsp++)
X					continue;
X				if (Iflag && isupper(*nsp))
X					fp->first = tolower(*nsp);
X				else
X					fp->first = *nsp;
X				fp->pos = *lp;
X				fp++;
X				first = FALSE;
X			}
X			fputs(sp, outf);
X		}
X	} while (sp != NULL);
X
X	/*
X	 * write the tables in
X	 */
X
X	(void) fclose(inf);
X	Tbl.str_numstr = curseek - 1;
X
X	if (Oflag)
X		do_order(seekpts, outf);
X	else if (Rflag)
X		randomize(seekpts);
X
X	(void) fseek(outf, (off_t) 0, 0);
X	(void) fwrite((char *) &Tbl, sizeof Tbl, 1, outf);
X	(void) fwrite((char *) seekpts, sizeof *seekpts, (int) curseek, outf);
X	(void) fclose(outf);
X
X	if (!Sflag) {
X		printf("\"%s\" converted to \"%s\"\n", Infile, Outfile);
X		if (curseek == 0)
X			puts("There was 1 string");
X		else
X			printf("There were %u strings\n", curseek - 1);
X		printf("Longest string: %u byte%s\n", Tbl.str_longlen,
X		       Tbl.str_longlen == 1 ? "" : "s");
X		printf("Shortest string: %u byte%s\n", Tbl.str_shortlen,
X		       Tbl.str_shortlen == 1 ? "" : "s");
X	}
X	exit(0);
X}
X
X/*
X *	This routine evaluates arguments from the command line
X */
Xgetargs(ac, av)
Xregister int	ac;
Xregister char	**av;
X{
X	register char	*sp;
X	register int	i;
X	register int	bad, j;
X
X	bad = 0;
X	for (i = 1; i < ac; i++)
X		if (*av[i] == '-' && av[i][1]) {
X			for (sp = &av[i][1]; *sp; sp++)
X				switch (*sp) {
X				  case 'c': /* new delimiting char */
X					if ((Delimch = *++sp) == '\0') {
X						--sp;
X						Delimch = *av[++i];
X					}
X					if (Delimch <= 0 || Delimch > '~' ||
X					    Delimch == DELIM_CH) {
X						printf("bad delimiting character: '\\%o\n'",
X						       Delimch);
X						bad++;
X					}
X					break;
X				  case 's':	/* silent */
X					Sflag++;
X					break;
X				  case 'v':	/* verbose */
X					Sflag = 0;
X					break;
X				  case 'o':	/* order strings */
X					Oflag++;
X					break;
X				  case 'i':	/* ignore case in ordering */
X					Iflag++;
X					break;
X				  case 'r':	/* ignore case in ordering */
X					Rflag++;
X					break;
X				  default:	/* unknown flag */
X					bad++;
X					printf("bad flag: '%c'\n", *sp);
X					break;
X				}
X		}
X		else if (*av[i] == '-') {
X			for (j = 0; Usage[j]; j++)
X				puts(Usage[j]);
X			exit(0);
X		}
X		else if (Infile)
X			(void) strcpy(Outfile, av[i]);
X		else
X			Infile = av[i];
X	if (!Infile) {
X		bad++;
X		puts("No input file name");
X	}
X	if (*Outfile == '\0' && !bad) {
X		(void) strcpy(Outfile, Infile);
X		(void) strcat(Outfile, ".dat");
X	}
X	if (bad) {
X		puts("use \"strfile -\" to get usage");
X		exit(-1);
X	}
X}
X
X/*
X * do_order:
X *	Order the strings alphabetically (possibly ignoring case).
X */
Xdo_order(seekpts, outf)
Xoff_t	*seekpts;
XFILE	*outf;
X{
X	register int	i;
X	register off_t	*lp;
X	register STR	*fp;
X	extern int	cmp_str();
X
X	(void) fflush(outf);
X	Sort_1 = fopen(Outfile, "r");
X	Sort_2 = fopen(Outfile, "r");
X	Seekpts = seekpts;
X	qsort((char *) Firstch, (int) Tbl.str_numstr, sizeof *Firstch, cmp_str);
X	i = Tbl.str_numstr;
X	lp = seekpts;
X	fp = Firstch;
X	while (i--)
X		*lp++ = fp++->pos;
X	(void) fclose(Sort_1);
X	(void) fclose(Sort_2);
X	Tbl.str_flags |= STR_ORDERED;
X}
X
X/*
X * cmp_str:
X *	Compare two strings in the file
X */
Xcmp_str(p1, p2)
XSTR	*p1, *p2;
X{
X	register int	c1, c2;
X
X	c1 = p1->first;
X	c2 = p2->first;
X	if (c1 != c2)
X		return c1 - c2;
X
X	(void) fseek(Sort_1, p1->pos, 0);
X	(void) fseek(Sort_2, p2->pos, 0);
X
X	while (!isalnum(c1 = getc(Sort_1)) && c1 != '\0')
X		continue;
X	while (!isalnum(c2 = getc(Sort_2)) && c2 != '\0')
X		continue;
X
X	while (c1 != '\0' && c2 != '\0') {
X		if (Iflag) {
X			if (isupper(c1))
X				c1 = tolower(c1);
X			if (isupper(c2))
X				c2 = tolower(c2);
X		}
X		if (c1 != c2)
X			return c1 - c2;
X		c1 = getc(Sort_1);
X		c2 = getc(Sort_2);
X	}
X	return c1 - c2;
X}
X
X/*
X * randomize:
X *	Randomize the order of the string table.  We must be careful
X *	not to randomize across delimiter boundaries.  All
X *	randomization is done within each block.
X */
Xrandomize(seekpts)
Xregister off_t	*seekpts;
X{
X	register int	cnt, i, j, start;
X	register off_t	tmp;
X	register off_t	*origsp;
X
X	Tbl.str_flags |= STR_RANDOM;
X	srnd(time((time_t *) NULL) + getpid());
X	origsp = seekpts;
X	for (j = 0; j <= Delim; j++) {
X
X		/*
X		 * get the starting place for the block
X		 */
X
X		if (j == 0)
X			start = 0;
X		else
X			start = Tbl.str_delims[j - 1];
X
X		/*
X		 * get the ending point
X		 */
X
X		if (j == Delim)
X			cnt = Tbl.str_numstr;
X		else
X			cnt = Tbl.str_delims[j];
X
X		/*
X		 * move things around randomly
X		 */
X
X		for (seekpts = &origsp[start]; cnt > start; cnt--, seekpts++) {
X			i = rnd(cnt - start);
X			tmp = seekpts[0];
X			seekpts[0] = seekpts[i];
X			seekpts[i] = tmp;
X		}
X	}
X}
END_OF_strfile.c
if test 8802 -ne `wc -c <strfile.c`; then
    echo shar: \"strfile.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f unstr.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"unstr.c\"
else
echo shar: Extracting \"unstr.c\" \(3701 characters\)
sed "s/^X//" >unstr.c <<'END_OF_unstr.c'
X# include	<stdio.h>
X# include	<ctype.h>
X# include	"strfile.h"
X
X# define	TRUE	1
X# define	FALSE	0
X
X/*
X *	This program un-does what "strfile" makes, thereby obtaining the
X * original file again.  This can be invoked with the name of the output
X * file, the input file, or both. If invoked with only a single argument
X * ending in ".dat", it is pressumed to be the input file and the output
X * file will be the same stripped of the ".dat".  If the single argument
X * doesn't end in ".dat", then it is presumed to be the output file, and
X * the input file is that name prepended by a ".dat".  If both are given
X * they are treated literally as the input and output files.
X *
X *	Ken Arnold		Aug 13, 1978
X */
X
X# define	DELIM_CH	'-'
X
Xchar	Infile[100],			/* name of input file */
X	Outfile[100],			/* name of output file */
X	Delimch = '%';			/* delimiter character */
X
Xshort	Oflag = FALSE;			/* use order of initial table */
X
XFILE	*Inf, *Outf;
X
Xchar	*rindex(), *malloc(), *strcat(), *strcpy();
X
Xmain(ac, av)
Xint	ac;
Xchar	**av;
X{
X	register int	c;
X	register int	nstr, delim;
X	static STRFILE	tbl;		/* description table */
X
X	getargs(ac, av);
X	if ((Inf = fopen(Infile, "r")) == NULL) {
X		perror(Infile);
X		exit(-1);
X		/* NOTREACHED */
X	}
X	if ((Outf = fopen(Outfile, "w")) == NULL) {
X		perror(Outfile);
X		exit(-1);
X		/* NOTREACHED */
X	}
X	(void) fread((char *) &tbl, sizeof tbl, 1, Inf);
X	if (Oflag) {
X		order_unstr(&tbl);
X		exit(0);
X		/* NOTREACHED */
X	}
X	nstr = tbl.str_numstr;
X	(void) fseek(Inf, (off_t) (sizeof (off_t) * (nstr + 1)), 1);
X	delim = 0;
X	nstr = 0;
X	while ((c = getc(Inf)) != EOF)
X		if (c != '\0')
X			putc(c, Outf);
X		else if (nstr != tbl.str_numstr - 1)
X			if (++nstr == tbl.str_delims[delim]) {
X				fprintf(Outf, "%c-\n", Delimch);
X				delim++;
X			}
X			else
X				fprintf(Outf, "%c%c\n", Delimch, Delimch);
X	exit(0);
X	/* NOTREACHED */
X}
X
Xgetargs(ac, av)
Xregister int	ac;
Xregister char	*av[];
X{
X	register int	i;
X	register char	*sp;
X	register int	j;
X	register short	bad;
X
X	bad = 0;
X	for (i = 1; i < ac; i++)  {
X		if (av[i][0] != '-') {
X			(void) strcpy(Infile, av[i]);
X			if (i + 1 >= ac) {
X				(void) strcpy(Outfile, Infile);
X				if ((sp = rindex(av[i], '.')) &&
X				    strcmp(sp, ".dat") == 0)
X					Outfile[strlen(Outfile) - 4] = '\0';
X				else
X					(void) strcat(Infile, ".dat");
X			}
X			else
X				(void) strcpy(Outfile, av[i + 1]);
X			break;
X		}
X		else if (av[i][1] == '\0') {
X			printf("usage: unstr [-o] [-cC] datafile[.dat] [outfile]\n");
X			exit(0);
X			/* NOTREACHED */
X		}
X		else
X			for (sp = &av[i][1]; *sp != '\0'; sp++)
X				switch (*sp) {
X				  case 'o':	/* print out in seekpt