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