good@pixar.UUCP (Craig) (01/15/88)
Comp.Sources.Misc: Volume 2, Issue 7 Submitted-By: Craig <good@pixar.UUCP> Archive-Name: ncode Comp.Sources.Misc: Volume 2, Issue 7 Submitted-By: Craig <good@pixar.UUCP> Archive-Name: ncode Here it is: the new, improved ncode.c along with new, improved sample files which help you appreciate all the wonderful features of the program. Some highlights: * Arbitrary file sizes * #include * comments now allowed in files * "variables": special groups which are expanded exactly once * bigger .c file to impress your friends To unwrap your kit, save it in a file called "ncode.shar". To assemble your kit, delete everything in the file above (and including) this "cut here" line, and delete everything below (and including) the other "cut here" line near the bottom of the file. Then give the command sh ncode.shar and start by reading the README file. Cheers. ----------------------------- cut here -------------------------------- echo x - README sed 's/^X//' >README <<'*-*-END-of-README-*-*' XYou should now have README, ncode.c, ncode.1, poetry.n and foxes.n. X XThe program will handle arbitrarily large files (you can even #include X/usr/dict/words) if you have the memory for it. New for this release are Xcomments and "variables". Gory details in the man page, ncode.1 X XThis source is known to compile and run on 4.3 BSD and on Sun 3.4. I Xunderstand that it compiles fine on sysV if you replace the calls to random() Xand srandom() with calls to rand() and srand(). Non 4.3 users will probably Xalso have to replace the innards of a_random_number() with something that Xworks on your system. You basically want some number to seed the random Xnumber generator. A getpid() doesn't change very quickly but will work; Xcalls to the real-time clock work better. This version of a_random_number() Xwas written by pixar!brighton who insists that all the baroque bit twiddling Xhelps. I just know that it works. X XCompile it "cc ncode.c -O -o ncode" and then try X X ncode ncode.sample.1 X XFor more fun, try X X ncode -n 5 ncode.sample.1 X XAnd for a good education say X X ncode -g "I had a date with FOX\" ncode.sample.1 X XThen you might want to read the man page, ncode.1, to learn about how it Xworks. You can make it pretty with "nroff -man ncode.1". If all of this Xleaves you hopelessly confused, send me some mail and I'll send you more Xconfusing sample files. Maybe. If I feel like it. X X X --Craig X ...{ucbvax,pyramid,sun}!pixar!good X *-*-END-of-README-*-* echo x - ncode.c sed 's/^X//' >ncode.c <<'*-*-END-of-ncode.c-*-*' X/* X * ncode.c -- a random text constructor X * pixar!good X * vaguely based on a program by pixar!mark X */ X X#include <stdio.h> X#include <sys/file.h> X#include <sys/time.h> X#include <sys/types.h> X#include <sys/stat.h> X X#define DATALUMP 8192 /* increment size of data[] by this as needed */ X#define BIGBUF 4096 /* nice, roomy buffer for group name checks */ X/* X * These are for the status element of gstruct. X */ X#define OBUF -1 /* the output buffer lives here */ X#define NVAR 0 /* this is not a "variable" */ X#define AVAR 1 /* this is a "variable" and needs to be "set" */ X#define DVAR 2 /* this "variable" has been set */ X Xchar **data; /* array of pointers to elements in bucket */ Xint dindex; /* number of elements in data */ Xint datasize; /* how many elements would fit in data[] right now */ X X/* X * Size of our output buffer, and the initial size of "variable" buffers X */ X#define MYBUFSIZ BUFSIZ X Xchar *malloc(); Xchar *realloc(); Xchar *rindex(); Xlong random(); X Xstruct gstruct { X char *name; /* points to name of a group in data[] */ X char *buf; /* points to a buffer for set "variable" data */ X char *bptr; /* points to current position in buf */ X char *lim; /* points to last element of buf[] */ X int bufsiz; /* current size of buf element */ X int count; /* how many elements of data belong to this group */ X int index; /* index of element of data where group starts */ X int status; /* are we a "variable" and, if so, what's our status? */ X}; Xstruct gstruct *groups; /* where the group structs live, or is that obvious? */ Xint ngroups; /* number of elements in groups */ Xstruct gstruct bbuf; /* output buffer lives in here */ X Xmain (ac,av) Xint ac; Xchar *av[]; X{ X char *prog; /* name of this program */ X char *fname = 0; X int loopcnt = 1; /* times through main loop */ X char *groupname = "CODE"; X X prog = rindex(*av,'/'); X prog = ( prog == NULL ) ? *av : ++prog ; X ac--;av++; X while(ac && **av == '-'){ X if (strcmp(*av,"-n") == 0){ X ac--;av++; X loopcnt = atoi(*av); X if (loopcnt <= 0){ X fprintf(stderr, X "%s: -n: need positive integer\n",prog); X exit(1); X } X ac--;av++; X } else if (strcmp(*av,"-g") == 0){ X ac--;av++; X groupname = *av; /* use instead of "CODE" */ X if (! groupname ){ X fprintf(stderr, X "%s: -g: need group name\n",prog); X exit(1); X } X ac--;av++; X } else { X printf( X "Usage %s [-n n ] [-g groupname] codefile\n",prog); X exit(0); X } X } X if (!ac){ X fprintf(stderr, X "Usage %s [-n n ] [-g groupname] codefile\n",prog); X exit(1); X } X fname = *av; X X /* X * Set up the special-case struct where the output buffer lives. X */ X if ((bbuf.buf = (char *) malloc(MYBUFSIZ * sizeof(char))) == NULL ){ X perror("main: could not malloc for bbuf.buf"); X exit(1); X } X /* X * This stuff only has to happen once X */ X bbuf.bufsiz = MYBUFSIZ; X bbuf.lim = bbuf.buf+MYBUFSIZ-1; X bbuf.status = OBUF; X bbuf.name = NULL; X bbuf.count = 0; /* this shouldn't mean a thing */ X bbuf.index = 0; X X /* X * Make some room to start, and increment by DATALUMP as needed X */ X datasize = DATALUMP; X if ((data = (char **) malloc(datasize * sizeof(char *))) == NULL ){ X perror("main: could not malloc for data[]"); X exit(1); X } X dindex = 0; X if( init(fname) != 0 ){ X fprintf(stderr,"%s: init error\n",prog); X exit(1); X } X /* X * This should be more than enough room for worst-case, since even X * if the file were full of empty group declarations there would only X * be dindex/2 possible groups. X */ X groups = (struct gstruct *) malloc(dindex * sizeof(struct gstruct)); X if (groups == NULL){ X perror("main: could not malloc for groups[]"); X exit(1); X } X if ( scan() != 0 ){ X fprintf(stderr,"%s: scan error\n",prog); X exit(1); X } X srandom(a_random_number()); /* seed the number generator */ X /* X * And away we go... X */ X while ( loopcnt ){ X bbuf.bptr = bbuf.buf; X expand(groupname,strlen(groupname),&bbuf); X *bbuf.bptr = '\0'; /* terminate before flushing */ X flushbuf(bbuf.buf); X loopcnt--; X } X exit(0); X} X Xinit(fname) Xchar *fname; X{ X char *bucket; /* big array where data lives */ X char *bptr; /* points into bucket */ X int fd; X struct stat sbuf; X char *s, *t; X X fd = open(fname,O_RDONLY,0); X if ( fd < 0 ) { X perror(fname); X return 1; X } X if ( fstat(fd,&sbuf) != 0 ){ X perror(fname); X return 1; X } X if ((bucket = (char *) malloc( sbuf.st_size + 1)) == NULL ){ X perror("init(): malloc() trouble"); X return 1; X } X /* X * Read entire file into bucket[] X */ X if ((read(fd,bucket,sbuf.st_size)) != sbuf.st_size){ X perror("init: read error"); X return 1; X } X close(fd); X /* X * Make first pass through memory, pointing data[] the right way X * and recursing as needed on #include files. X */ X bptr = bucket; X while ( *bptr && (bptr <= bucket + sbuf.st_size) ){ X s = bptr; X while ( *s != '\0' ){ X if(*s == '\n' ) X *s = '\0'; /* nuke newline */ X else X s++; X } X if( strncmp(bptr, "#include", 8) == 0 ){ X for(t = bptr + 8; *t!='\0' && (*t==' '||*t=='\t');t++) X ; /* skipping white space */ X if (init(t) != 0){ /* RECURSES HERE */ X return 1; X } X bptr = t + strlen(t) + 1; /* skip the #include line */ X continue; /* back to the top of the while loop */ X } else if ( *bptr == '#' ) { /* must be a comment */ X bptr += strlen(bptr) + 1; /* skip #comment line */ X continue; X } X /* X * Make sure data[] is still big enough X */ X if ( dindex >= datasize){ X datasize += DATALUMP; X if((data=(char **) realloc(data, X datasize*sizeof(char *)))==NULL){ X perror("init: could not realloc for data[]"); X return(1); X } X } X data[dindex] = bptr; /* point it at the data */ X bptr = s + 1; /* move bptr to the next location to fill */ X dindex++; X } X return 0; X} X X/* X * Scan data[] marking and counting groups X */ Xscan() X{ X register int i, gcnt, gindex; X register char *vptr; X X /* X * special case: first line always a group name X */ X groups[0].name = data[0]; X groups[0].index = 0; X ngroups = 1; X i = 1; X gindex = 0; X gcnt = 0; X while ( i < dindex ){ X if ( data[i][0] == '%' ){ X groups[gindex].count = gcnt; X gcnt = 0; /* close out prev group */ X ngroups++; X i++; /* start next group */ X /* X * If a #included file has any blank lines after X * the last '%' then the group name would wind X * up being '\0'. So the first group name after X * the #include won't be marked as a group name X * and will thus never be expanded. We could X * cluck our tongues at the user and say he has X * a bogus file and thus deserves what he gets. X * But hopefully this check will just make the X * program more robust. X */ X while ((i < dindex) && (data[i][0] == '\0')) { X i++; X } X gindex++; X groups[gindex].name = data[i]; X groups[gindex].index = i; X groups[gindex].status = NVAR; X vptr = groups[gindex].name; X if (vptr) vptr += strlen(groups[gindex].name) -1; X if ( vptr && *vptr == '*' ){ X *vptr = '\0'; /* terminate the name */ X groups[gindex].status = AVAR; X if ( X(groups[gindex].buf = (char *) malloc(MYBUFSIZ * sizeof(char))) == NULL ){ X perror("scan(): could not malloc for groups.buf"); X exit(1); X } X groups[gindex].bptr = groups[gindex].buf; X groups[gindex].lim=groups[gindex].buf+MYBUFSIZ-1; X groups[gindex].bufsiz=MYBUFSIZ; X } X }else{ X gcnt++; X } X i++; X } X ngroups--; /* The last % in the file doesn't start a new group */ X return 0; X} X X/* X * This is where we finally do the deed. If a string is a group name X * then expand will randomly select a member of that group to X * replace it. Through the miracle of recursion, a whole sentence X * may be passed to expand and each word (anything bounded by what X * we call "white space" gets expanded. Anything that cannot be X * expanded gets printed out. X */ Xexpand(s,lim,grp) Xchar s[]; /* from */ Xint lim; Xstruct gstruct *grp; /* to */ X{ X register int i, j, k, done, n, r; X X i = j = 0; X while ( s[i] != 0 && i < lim ){ X done = 0; X while ( ! done && j <= lim ){ X if ( isawhite(s[j]) ){ X /* chase down remaining white space */ X for (k=j; k<=lim && s[k] && isawhite(s[k]);k++){ X ; X } X n = isagroup(&s[i], j-i); X if ( n >= 0 ){ X switch ( groups[n].status ){ X case NVAR: r = (groups[n].index + 1 X + rnd(groups[n].count)); X expand(data[r],strlen(data[r]),grp); X outstring(&s[j],k-j,grp); X break; X case AVAR: X /* only the first one counts */ X r = groups[n].index + 1; X expand(data[r],strlen(data[r]),&groups[n]); X groups[n].status=DVAR; X /* fall through */ X case DVAR: X/* X * Call outstring for groups[n].buf, then for the white space between j and k X */ X outstring(groups[n].buf, X strlen(groups[n].buf),grp); X outstring(&s[j], k-j,grp); X break; X case OBUF: X printf("This shouldn't happen.\n"); X break; X } X } else { X outstring(&s[i], k-i, grp); X } X done++; X i = j = k; /* should be on next word, if any */ X } X j++; X } X } X} X X/* X * Return index into groups[] array if a group name, -1 if just a word. X * We have to use gbuf, a seperate place, so that we can null-terminate X * the string where we want. Otherwise it wouldn't know santa from X * santana. X */ Xisagroup(s,lim) Xchar s[]; Xint lim; X{ X register int i; X static char gbuf[BIGBUF]; X X strncpy(gbuf,s,lim); X gbuf[lim] = '\0'; /* strncpy might not do this */ X for(i=0; i<ngroups; i++ ){ X if (groups[i].name && strcmp(gbuf,groups[i].name) == 0){ X return i; /* hit */ X } X } X return -1; /* fail */ X} X X/* X * Output string, handling splices X */ Xoutstring(s,lim,grp) Xchar s[]; /* from */ Xint lim; Xstruct gstruct *grp; /* to */ X{ X register int i = 0; X register char *p; X int boff; X X p = grp->bptr; X while ( s[i] != '\0' && i < lim ){ X if ( p == grp->lim ){ X *p = '\0'; /* terminate with extreme prejudice */ X if (grp->status == OBUF){ X flushbuf(grp->buf); /* time to flush! */ X p = grp->buf; /* reset pointer */ X } else { X /* make more room for variable */ X boff = p - grp->buf; X grp->bufsiz += MYBUFSIZ; X if((grp->buf=(char *) realloc(grp->buf, X sizeof(char) * grp->bufsiz))==NULL){ X perror("outstring: could not realloc"); X exit(1); X } X p = grp->buf + boff; /* put this back */ X } X } X switch (s[i]){ X case '|': X if ( s[i+1] == '\\' ){ X *p = '\\'; /* special case: */ X i++; /* |\ outputs a \ */ X p++; X break; X } X break; /* splice: no output */ X case '\\': X *p = '\n'; X p++; X break; X default: X *p = s[i]; X p++; X break; X } X i++; X } X grp->bptr = p; /* catch up on the current state of things */ X} X X/* X * Return random number 0 to limit X */ Xrnd(limit) Xint limit; X{ X if (limit > 0){ X return (random() % limit); X } X return 0; /* better than a floating exception if lim == 0 */ X} X Xa_random_number() X{ X struct timeval tp; X struct timezone tzp; X X gettimeofday (&tp, &tzp); X X return((getpid() ^ tp.tv_usec) % 123456); X} X X/* X * Return 1 if one of our "white" characters. A white character is X * any character which can bound a group name, so punctuation marks X * are included. X */ Xisawhite(c) Xchar c; X{ X if ( c == '\0' || /* traditional white space */ X c == ' ' || X c == '\t' || X c == '|' || /* "splice" character */ X c == '\\' || /* becomes a newline */ X c == '.' || /* common punctuation */ X c == '-' || X c == ':' || X c == ';' || X c == ',' || X c == '!' || X c == '?' || X c == '[' || X c == ']' || X c == '{' || X c == '}' || X c == '(' || X c == ')' || X c == '\'' || X c == '\"' || X c == '`' X ) X return 1; X return 0; X} X/* X * Flush everything in a buffer to stdout X * (Really just puts() without the '\n' on the end) X */ Xflushbuf(s) Xregister char *s; X{ X register int c; X X while (c = *s++) X putchar(c); X} *-*-END-of-ncode.c-*-* echo x - ncode.1 sed 's/^X//' >ncode.1 <<'*-*-END-of-ncode.1-*-*' X.TH NCODE 1 "Pixar" X.SH NAME Xncode - stochastic text construction X.SH SYNOPSIS X.B ncode [-n number] [-g groupname] codefile X.SH DESCRIPTION X.I Ncode Xreads in a file of a certain format and randomly constructs text based on Xthe organization of the file. Other files may be recursively included by Xputting X X.nf X #include pathname X.fi X Xon any line of the file. This is useful when Xyou want to use a file of basic definitions, or groups, in different Xconfigurations. X XComments are lines which begin with a "#" but which are not #include lines. X XThe -n flag is used to run the program through the main loop multiple times. X XThe -g flag allows you to start the expanding process on a group name other Xthan the default, which is "CODE". The argument may be a group name, or an Xentire string including group names, just as if it were a line in the file. XIt is legal to start on any group in the file, and groups may be referenced Xbefore or after the place in the file where they are defined. In the case of Xduplicate group definitions, the first one occurring is the only one used. X XA "group" name is defined as the word on the first line of the file and, more Xcommonly, the word on each line following a line starting with "%". The members Xof a group are all lines between the group name and the next "%". When a Xgroup name is encountered, surrounded by any of a set of characters called X"white space" in this context, it is randomly expanded into one of its members. XGroup names are not allowed to contain any white space, to prevent terminal Xconfusion on the part of the program. X X XFor example, here is a sample group definition: X X.nf X NOUN X lamp X house X car X % X.fi X XThe line "See the NOUN." could be randomly expanded to say "See the lamp." X XSpecial "variable" groups are those with a "*" as the last character of the Xgroup name. The first (which should be the only) member of the group will Xbe recursively expanded only once. All subsequent references to that group Xwill produce the same string. For example, a group may be defined as X X.nf X NOUN1* X NOUN X% X.fi X XThe line "She said that his NOUN1 was a very fine NOUN1 indeed." would be Xexpanded into something such as "She said that his car was a very fine Xcar indeed." X XThe characters considered "white" for the purpose of bounding a group name, Xbesides what is normally considered white space, are currently: X X | \\ . - : ; , ! ? [ ] { } () ' " ` X XTwo of those characters have special meanings to X.I ncode. XThe "|" symbol allows you to "splice" things to a group name. When it is Xencountered, no character is printed on output. The "\\" causes a newline Xto be printed on output. If you want a "\\" to appear on output, use a Xsplice, as in "|\\". X XThe simplest application would be for a "fortune" program, but X.I ncode Xcould also be used for more complex things such as a rumor generating file. XThe group definitions will be left as an exercise for the reader, but the Xfollowing example should prove illuminating: X X.nf XCODE XIt was rumored today that COMPANY will be bought by COMPANY for PRICE\\. XPERSON, POSITION of COMPANY, said that PRODUCT will be announced DATE\\. X.fi X XNote that every string to be expanded must be on only one line of the file. XThe program now dynamically allocates memory in a very general (if not Xoptimum) way, so you are really limited only by how much memory you can get Xand how deep your stack can go. The only hard limit is that Xa group name can't be over 4096 characters long. If you can't come up Xwith a unique group name in fewer characters than that then you shouldn't Xbe allowed to play with computers. X X.SH BUGS XNo bugs. Only features that you haven't figured out how to use yet. XA recent improvement makes it tolerant of blank lines following the last % Xin a #include file. X.SH DIAGNOSTICS XStandard perror() stuff. Pretty self explanatory. A bogus input file might Xbenignly yield cryptic results. If you see just the string "CODE" as output Xyou probably don't have what you think you have in your input file. X.SH AUTHOR XCraig Good *-*-END-of-ncode.1-*-* echo x - poetry.n sed 's/^X//' >poetry.n <<'*-*-END-of-poetry.n-*-*' X# Here's an example of one of those "variable" groups. X# The * means that it will be expanded only once. Note that this group X# has only one member. Additional members would be ignored, so just leave X# them off. You may have also noticed that ncode now supports comments. XNOUNE* XNOUN X% XNOUNW* XNOUN X% XNOUN XNorth XSouth XEast XWest XTruth Xgrass Xdesk Xwall Xwindow Xceiling Xfloor Xcar Xsign X% XNUMBER Xone Xtwo Xtwo X3.1415927 Xthree Xeleven Xa googol X% XVERB Xmeet Xknock Xkiss Xhug Xtrot Xmiss Xnod Xwink Xhit Xwalk Xfly Xzip Xsmash Xsniff X% XFLOWERS XRoses XViolets XChrysanthemums XDaisies XGardenias XStinkweeds XPetunias X% XCOLOR Xpuce Xinvisible Xred Xtan Xwhite Xblue Xgreen Xmuave Xpurple Xchartreuse Xblack Xyellow X% XSOMETHING XI am XSugar is XRadiation is XComputing is XNitrous Oxide is XANIMALS are XAUTHOR_ANY is XYou are X% XPROPERTY Xfearful Xliberal Xconservative Xsexy Xschizophrenic Xsweet Xbitter Xstupid Xugly Xhilarious Xslow Xmiserable X% XISYOU Xare you. Xis this. Xam I. Xis Maple Surple. Xis it. Xit is. Xare they. X...who cares? X% XHAND Xmouth Xhand Xhand Xeye Xeye Xnose Xear Xtooth Xfoot X% XAUTHOR_A XDavid Johansen XCraig Good XMichael Jackson XWally XSpock XGidget XBambi XDracula XSuperman XKahn XBullwinkle XBo Derek XKoo Stark XLady Diana XRoy Rogers XBugs Bunny XJames Bond XGodzilla XKilroy XThe Emperor XSweeny Todd XKate Bush X% XAUTHOR_AN XAnonymous XAndre XAlvy Ray Smith XEd Catmull X% XAUTHOR_ANY XAUTHOR_AN XAUTHOR_A XAUTHOR_A XFOX XFOX XFOX X% XANIMAL_A XBird XSnail XPanda XFishy XDoggy XPuppy XTiger XKitty XWorm XKangaroo XWart Hog XPenguin XPolar Bear XParakeet XCat XMountain Goat XMoose XMouse X% XANIMAL_AN XEgret XAardvark XEmu XElephant X% XANIMAL_ANY XANIMAL_AN XANIMAL_A XANIMAL_A XANIMAL_A X% XANIMAL_TIG* XANIMAL_ANY X% XANIMALS XBirds XSnails XPandas XFish XDogs XPuppies XTigers XKittens XAardvarks XWorms XKangaroos XWart Hogs XPenguins XPolar Bears XParakeets XCats XMountain Goats XMooses XMice X% XROYALTY XPrince XKing XBoss XProgrammer XHacker XSalesman XHead Hunter X% XMITS Xknickers Xarm bands Xmittens Xsunglasses Xcowboy boots Xgaloshes X% XHURT Xhurt Xhurt Xkill Xslap Xdeoderize Xbreak Xzap Xvaporize Xirradiate Xbother X% XSTICKS XSticks XStones XBullets XBombs XCroissants XKeyboards X% XFOREST Xball park Xforest Xswamp land Xjungle Xghetto Xdrug store Xoffice X% XPLACE Xgarage Xoven Xbush Xbush XFOREST X% XTREE Xa tree XFOX's knee XFOX's knee XFOX's knee XFOX's knee X% XPROVERB XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the twain shall meet.\ XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the twain shall VERB.\ XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the twain shall VERB.\ XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the ANIMAL_ANY shall VERB.\ XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the ANIMAL_ANY shall VERB.\ XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the ANIMAL_ANY shall VERB.\ XA ANIMAL_A is as good as a FOREST to AUTHOR_ANY.\ XA ANIMAL_A is as good as a FOREST to AUTHOR_ANY.\ XAn ANIMAL_AN is as good as a FOREST to AUTHOR_ANY.\ XA HURT is as good as a VERB to a ANIMAL_A.\ XA HURT is as good as a VERB to an ANIMAL_AN.\ XA HURT is as good as a VERB to a ANIMAL_A.\ XA HURT is as good as a VERB to an ANIMAL_AN.\ XA VERB is as good as a HURT to AUTHOR_ANY.\ XA VERB is as good as a HURT to AUTHOR_ANY.\ XFLOWERS and MITS\May HURT my bones,\But AUTHOR_ANY will never VERB me.\ XSTICKS and ANIMALS\May HURT my bones,\But FLOWERS will never HURT me.\ XFLOWERS and STICKS\May HURT my bones,\But MITS will never HURT me.\ XSTICKS and STICKS\May HURT my bones,\But ANIMALS will never VERB me.\ XNever VERB today what you can HURT tomorrow. XNever VERB today what you can HURT tomorrow. XNever HURT today what you can VERB tomorrow. XA ANIMAL_A in the HAND is worth NUMBER in the PLACE. XAn ANIMAL_AN in the HAND is worth NUMBER in the PLACE. XA ANIMAL_A in the HAND is worth NUMBER in the PLACE. XAn ANIMAL_AN in the HAND is worth NUMBER in the PLACE. XA AUTHOR_A in the HAND is worth NUMBER in the PLACE. XAn AUTHOR_AN in the HAND is worth NUMBER in the PLACE. XNever look a gift ANIMAL_ANY in the mouth. XDead ANIMALS aren't much fun. X% XVERSE XANIMAL_TIG, ANIMAL_TIG, burning bright\In the FOREST of the night\What immortal HAND or HAND\Dare frame thy PROPERTY symmetry?\ XFLOWERS are COLOR,\FLOWERS are COLOR,\SOMETHING PROPERTY,\And so ISYOU\ XHark! Hark!\The ANIMALS do bark!\The ROYALTY is fond of ANIMALS\He likes to take their insides out\And wear them as his MITS.\ XI think that I shall never see\A thing as lovely\As TREE.\ X% XTITLE X "Why AUTHOR_ANY tried to HURT the ANIMAL_ANY" X "The day AUTHOR_ANY wanted to HURT the ANIMAL_ANY" X "ANIMALS" X "FLOWERS" X "The PROPERTY ANIMAL_ANY" X "The PROPERTY FLOWERS" X "Ode to AUTHOR_ANY" X "I'm so COLOR without my ANIMAL_ANY" X "Ode to the ANIMAL_ANY" X "I'm dreaming of a COLOR Christmas" X "I Love The FLOWERS" X "Dead ANIMALS" X% XCODE X\PROVERB\\ --AUTHOR_ANY\ X\PROVERB\\ --AUTHOR_ANY\ X\VERSE\\ --AUTHOR_ANY\ X\VERSE\\ --AUTHOR_ANY\ X\TITLE\\VERSE\\ --AUTHOR_ANY\ X% X# X# These #include lines can happen anywhere in the file. Note that you do X# not use quotes around the pathname. X# X#include foxes.n *-*-END-of-poetry.n-*-* echo x - foxes.n sed 's/^X//' >foxes.n <<'*-*-END-of-foxes.n-*-*' X# Save this file as "foxes" to be #included in other files XFOX XAlexandra Paul XAmanda Pays XAmy Irving XAppollonia XApril Wayne XBarbara Hershey XBrooke Adams XCat XCathleen Collins XCindy Crawford XCarly Simon XCarol Alt XCassandra Peterson XCatherine Mary Stewart XCathy Tyson XCheryl Tiegs XChristie Brinkley XCoco Mitchell XCourteney Cox XCynthia Rhodes XCybill Shepherd XDaphne Zuniga XDarryl Hannah XElizabeth McGovern XElle Macpherson XErin Grey XFarrah Fawcett Majors XFawn Hall XFrederique XHeather Locklear XHeather Thomas XIman XJaclyn Smith XJamie Lee Curtis XJane Seymour XJanet Jones XJenna de Rosnay XJennifer Beales XJenny Seagrove XJill Goodacre XJody Watley XJohann Carlo XJulie Wolfe XKaren Alexander XKate Capshaw XKate Jackson XKathy Ireland XKelly Emberg XKelly LeBrock XKim Alexis XKim Basinger XKoo Stark XLaura Antonelli XLauren Hutton XLea Thompson XLisa Bonet XLisa Hartman XMarkie Post XMarlee Matlin XMaryam d'Abo XMeg Ryan XMelanie Griffith XMichelle Pfieffer XMelissa Gilbert XMonika Schnarre XNastasia Kinski XOla Ray XOlivia Newton John XPamela Sue Martin XPatty Owen XPaulina Porizkova XPhoebe Cates XRachel Ward XRae Dawn Chong XRenee Simonsen XRosanna Arquette XSade XSela Ward XSheila E XShelly Hack XSigney Coleman XSuzee Pai XStephanie Seymour XStevie Nicks XTahnee Welch XTanya Roberts XTheresa Russell XTish Campbell XTraci Wolfe XVictoria Principal XVivian Ruiz XWhitney Houston X% *-*-END-of-foxes.n-*-* exit ----------------------------- cut here -------------------------------- (delete from here down) Have fun! -- --Craig ...{ucbvax,pyramid,sun}!pixar!good