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