[alt.sources] Random text generation

wiml@milton.u.washington.edu (William Lewis) (08/09/90)

   In the spirit of the recent spate of random-text-generation programs
to alt.sources, I have converted two of those programs (sifi and
madrock) to SPEW rulefile format, and am reposting them here. Since
I had to modify SPEW slightly to port sifi, I'm also posting it, 
and the original spewfile (headline). I also added word-wrap to spew's
output.

   Note to people who plan to do dome more modification to spew: The 
current implementation of \PRUNE is pretty kludgy. It should really 
be done by return values instead of setjmp/longjmp, but I'm too 
lazy right now. Also, the indication of prunsetops could 
be a bit "nicer". I haven't done this yet, but if 
seeing this post makes you improve spew some more, get in touch with me 
so we don't duplicate changes or create incompatible versions =8)

----------------------cut here---------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	readme
#	headline
#	sifi.sp
#	madrock.sp
#	manual
#	spew.c
# This archive created: Wed Aug  8 23:33:28 1990
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'readme'" '(4509 characters)'
if test -f 'readme'
then
	echo shar: "will not over-write existing file 'readme'"
else
sed 's/^X//' << \SHAR_EOF > 'readme'
XA while back, mark@pixar posted a program to generate random 'National
XEnquirer' headlines.  This program worked from a 'rules file' which was a text
Xfile describing how the headlines would be constructed.
X
XMark's program was, unfortunately, highly non-portable, and rather than
Xtry to salvage it I wrote a new interpreter for the same text file.
XSince then I have added several features, and thus greatly changed the
Xformat of the rules file. Credits go to mark for the original concept
Xand much of the text in the supplied rulesfile ( which I have cleaned up
Xand added to ).
X
XThis shar includes the National Enquirer rules-file 'headline', the 
XMAD rock concert rulesfile 'madrock.sp', the Sci-Fi plot rulesfile 
X'sifi.sp', the source to the 'spew' interpreter, a 'manual' for the 
Xformat of the control file, and this READ_ME file. I believe this 
Xprogram might actually be useful, for such tasks as generating huge 
Xquantities of input text for testing programs.  ( I may have a 
Xfile which generates random syntactically-correct C code, but I
Xwon't admit to it!! :-). The format of the file allows a wide variety of text
Xformats to be generated - it almost works like Yacc in reverse.
XAnyway, things like 'festoon' could certainly be coded as 'spew' rulesfiles,
Xand could thus be sent to the net as a 'spew' source.
XSorry I haven't written a proper manual page, but...
X
XUSAGE:
X	spew [n]        generate one [or n] random thing(s) from default
X			rulesfile. If the environment variable RULESFILE
X			is set, the file-name is taken from there; other-
X			wise a compiled-in name is used ( see Installation
X			instructions ).
X
X	spew [n] file   Same, but use the given file as input.
X
X	spew -c
Xor	spew -c file    'Compress' the default or given file to the
X			standard output (the compressed format is unreadable
X			and must be redirected). 'Compress' is a misnomer
X			because the file gets about 20% larger. The
X			'compressed' format is more efficient for spew to
X			operate from, though. Spew automatically knows
X			whether it is reading a compressed or human-readable
X			rulesfile.  Examples:
X		spew headline			<< make a headline
X		spew -c headline >headline.comp	<< make compressed file
X		spew headline.comp		<< make another headline
X
X	spew -d
X	spew -d file    Read the default or given file, and dump the
X			resulting internal structure to the std output.
X			The format is pretty easy to figure out. It is
X			somewhat different when the input file is in
X			'compressed' format. DUMP must be #define'd
X			to enable this feeping creature.
X
X
XINSTALLATION INSTRUCTIONS:
XThe file spew.c contains some clearly labeled #defines which you may
Xwant to play with. It should be possible to port to non-Un*x systems
Xjust by changing these. The most important ones to start with are:
X
XDEFFILE which is the default rules file to use. Set this to the path
X	of your 'headline' file and then you can just put 'spew' in your
X	.login.
XENVIRON which is set to "RULESFILE" in the release package. If this
X	environment variable is set, it is assumed to be a default file-name
X	over-riding the DEFFILE. You may want to change this.
X	Remove the #define if you don't have getenv().
XSETRAND	
XROLL(n)	define the former to a STATEMENT (not an expression) which
X	initializes your random number generator. Define the latter as
X	an expression which gives a random integer in the range 0<=i<n.
X	'n' will be an integer from 1 to several hundred.
X	The supplied definitions may or may not work well, depending
X	on your machine (here we have a VAX 11/780 4.2BSD, works ok
X	on a Sun too ).
X
X-------------------------------------------------------------------------
XNotes of modification:
X
XI have modified the source to make it compilable under DOS on an IBM-PC
Xwith Borland Turbo C.  It is still compilable under UNIX,  just make sure
Xthe #define DOS is commented out.  It should compile just fine with
XMicrosoft C v4.0/v5.x, but I have not tried it.
X	-- Ti Kan --
X-------------------------------------------------------------------------
XI modified Ti Kan's version to include the \PRUNE pseudoclass (described
Xabove) and to break output lines on word boundaries (which could 
Xconcievably hurt some uses, but I've never seen a spewfile for
Xanything but humor text). It should still compile everywhere it used
Xto ( :-) ); if setjmp/longjmp is not available then #define PRUNE can
Xbe commented out.
X        William Lewis (phelliax)
X        wiml@milton.u.washington.edu
X-------------------------------------------------------------------------
echo shar: "a missing newline was added to 'readme'"
SHAR_EOF
if test 4509 -ne "`wc -c < 'readme'`"
then
	echo shar: "error transmitting 'readme'" '(should have been 4509 characters)'
fi
fi
echo shar: "extracting 'headline'" '(8211 characters)'
if test -f 'headline'
then
	echo shar: "will not over-write existing file 'headline'"
else
sed 's/^X//' << \SHAR_EOF > 'headline'
X\* National Enquirer Headlines.
X\*
X%SPIRITUAL
XSpiritual
XClairvoyant
XTelepathic
XTelekinetic
X%RELATIVE
XFather
XUncle
XGrandfather
XGrandmother
XSon
XDaughter
XMother
XAunt
XPostman
XAccountant
XDog Catcher
XIRS Man
XHairdresser
XAvon Lady
X%WEAPON{a}
X{|a }Meat Cleaver
X{|a }Hatchet
X{|a }Machete
X{|a }Phased Plasma Rifle
X{|a }Chain Saw
X{|a }Samurai Sword
X{|an }Axe
X{|a }Machine Gun
X{|an }Anti-tank weapon
X\*{\FRUIT|\FRUIT/a}
X\FRUIT/&
X%GHOST
XGhost
XEvil Spirt
XPoltergist
XDemon
XPhantom
XBogie Man
X%RELIGION
XBuddist
XMethodist
XBaptist
XIslamic
XMoslem
XRoman Catholic
XAtheist
X%UFFO
XUFO
XFlying Saucer
XSpace Ship
XMother Ship
XSpace cruiser
XUSS Enterprise
XGalactic Space Cruiser
X%PLANET
XPluto
XMars
XVenus
XMercury
XNeptune
XSaturn
XJupiter
XThe Moon
X%ET{s}
XExtra-Terrestrial{|s}
XE.T.{|'s}
XSpace Alien{|s}
XBeing{|s}
XSpace Being{|s}
XCyborg{|s}
XHumanoid{|s}
XAlien{|s}
X%DRUG
XHeroin
XLSD
XAngel Dust
XCoke
XCocaine
XCrack
XQuaaludes
XAmphetamines
XSpam
X%FRUIT{as}
X{|a |}Mango{||es}
X{|a |}Tomato{||es}
X{|a |}Banana{||s}
X{|a |}Cherr{y|y|ies}
X{|an |}Apple{||s}
X{|a |}Plum{||s}
X{|a |}Pear{||s}
X{|an |}Orange{||s}
X{|a |}Tangerine{||s}
X{|a |}Lemon{||s}
X{|a |}Lime{||s}
X{|a |}Block{||s} of Spam
X%MADNESS
XCrazed
XDrug-Crazed
XInsane
XManic Depressive
XNeurotic
XPsychotic
XPsychopathic
XDevoted
XReligious
XFanatical
XPathological
X%KILLER{s}
X(2)\KILLERX/&
X\MADNESS \KILLERX/&
X%KILLERX{s}
X\FRUIT/&
XGreat White Shark{|s}
XTerminator{|s}
XEwok{|s}
XWombat{|s}
XBee{|s}
XWasp{|s}
XWhale{|s}
XShark{|s}
XLion{|s}
XDolphin{|s}
XElephant{|s}
XWorm{|s}
XClam{|s}
XKitten{|s}
XLobster{|s}
XTiger{|s}
XLeopard{|s}
XPanda{|s}
XCrocodile{|s}
X%MCELEB
XRonald Reagan
XDan Quayle
XFrank Sinatra
XMichael Jackson
XPrince
XMick Jagger
XDonny Osmond
XLou Albano
XSylvester Stallone
XSean Penn
XBob Dylan
XDavid Letterman
XJohnny Carson
XMuammar Quadaffi
XMoammar Khadafy
XKenny Rogers
XBurt Reynolds
XJohn Davidson
XRichard Nixon
XPrince Charles
XGeorge Lucas
X%FCELEB
XPrincess Diana
XQueen Elizabeth
XNancy Reagan
XLinda Ronstadt
XMaggie Trudeau
XLiz Taylor
XTina Turner
XDolly Parton
XCher
XJane Fonda
XEva Gabor
XJoan Rivers
XMadonna
XCindi Lauper
X%BABY{s}
XBab{y|ies}
XChild{|ren}
XSon{|s}
XDaughter{|s}
X%FDEAD\* female persons long dead
XCleopatra
XJoan of Arc
XLady Godiva
XQueen Victoria
XThe Queen of Sheba
X%DFCELEB\* dead female 'celebrities'
XMarilyn Monroe
XJanis Joplin
X(4)\FDEAD
X%MDEAD\* male persons long dead
XAtilla the Hun
XKing Henry VIII
XAbraham Lincoln
XGeorge Washington
XMoses
X%DMCELEB\* dead male celebs
X(3)Elvis
XJimi Hendrix
XJim Morrison
XJohn F. Kennedy
XBing Crosby
XJohn Lennon
XJFK
XGroucho Marx
XHarry Chapin
X\MDEAD
X%DCELEB
X\DMCELEB
X\DFCELEB
X%DEAD
X\FDEAD
X\MDEAD
X%EAT{sd}
X{eat|eats|ate}
Xkidnap{|s|ped}
X{take|takes|took}
Xkill{|s|ed}
Xdevour{|s|ed}
Xmaim{|s|ed}
Xinjure{|s|d}
Xrape{|s|d}
X%SAY{s}
XSay{|s}
XReveal{|s}
X\*Admit{|s}
XClaim{|s}
XInsist{|s}
X\*Warn{|s}
X%DOCTOR{s}
XDoctor{|s}
XPsychologist{|s}
XPsychiatrist{|s}
XPhysician{|s}
XNeurologist{|s}
XDentist{|s}
XPediatrician{|s}
XVetrinarian{|s}
XOptician{|s}
X%SCIENTIST{s}
XScientist{|s}
X\DOCTOR/&
XChemist{|s}
XPhysicist{|s}
XMeta-physicist{|s}
XEngineer{|s}
XComputer Scientist{|s}
XProfessor{|s}
XTechnician{|s}
XWhiz Kid{|s}
XBrain Boff{|s}
XAI Expert{|s}
XPattern Recognition Researcher{|s}
X%NATIONALITY
XRussian
XSoviet
XBritish
XPolish
XFrench
XBelgian
XSwiss
XGerman
XSpanish
XMexican
XUkranian
XAmerican
XCanadian
XAlbanian
XAustralian
XChinese
XJapanese
X%DISEASE
XHerpes
XAIDS
XFlu
XLeprosy
XVD
Xa Backache
XChicken Pox
XMalaria
XLaryngitis
Xa Nosebleed
XTuberculosis
XCancer
X%FICTCHAR
XSanta Claus
XBigfoot
XSnow White
XGod
XBhudda
XMary Poppins
XThe Loch Ness Monster
XYogi Bear
XJames Bond
XThe Wicked Witch of the West
XThe Wizard of Oz
XCaptain Kirk
XThe Tooth Fairy
XKermit the frog
XBatman
XSuperman
XSpiderman
X%KILL{sd}
XKill{|s|ed}
XMurder{|s|ed}
XMaim{|s|ed}
XSlaughter{|s|ed}
XMutilate{|s|d}
XSho{ot|ots|t}
XMug{|s|ged}
X%NUMBER
X\NUMBER1
X(2)\NUMBER2
XTwenty-\NUMBER1
XThirty-\NUMBER1
XForty-\NUMBER1
XFifty-\NUMBER1
XSixty-\NUMBER1
XSeventy-\NUMBER1
XEighty-\NUMBER1
XNinety-\NUMBER1
X%NUMBER1
XTwo
XThree
XFour
XFive
XSix
XSeven
XEight
XNine
X%NUMBER2
XTen
XEleven
XTwelve
XThirteen
XFourteen
XFifteen
XSixteen
XSeventeen
XEighteen
XNineteen
X%FOOD{a}
X{|a }Taco
X(5)\FRUIT/&
X{|an }Enchilada
X{|a }Burrito
X{|a }Watermelon
X{|a }Triple Ice Cream Cone
X{|a }Tostada
X%PERSON{s}
X\KILLER/&
XFootball player{|s}
X{Man|Men}
XWom{an|en}
XTV Personalit{y|ies}
XGame Show Host{|s}
XPolitician{|s}
X\SCIENTIST/&
X\DOCTOR/&
X\NATIONALITY \SCIENTIST/&
X\NATIONALITY \DOCTOR/&
XUnemployed \SCIENTIST/&
XStudent{|s}
XAir Traffic Controller{|s}
X\NATIONALITY Student{|s}
X\ET/&
X%AIRCRAFT
XAirplane
XHelicopter
XAirship
XHot Air Balloon
XHang Glider
XHelium Balloon
XUFO
XJet Fighter
X747
XDC-10
X%CELEB
X\MCELEB
X\FCELEB
X%PLACE
XRedwood City
XAustralia
XNevada
XAustin, Texas
XMagrathea
XOuter Space
XMemphis
XEngland
XSan Francisco
XCastro Street
XSan Jose
XL.A.
XNew York
XOrlando, Florida
XMissouri
XMiddle Earth
XThe Shire
XBarsoom
XPlanet Vulcan
XFremont Airport
XTokyo
XTransylvania
XTimes Square
XWall Street
XSan Rafael
XIsrael
XBeirut
XMordor
XBBC television center
XDr. Who's Tardis
XStalingrad
XMoscow
XAmsterdam
XManchester
XEdinburgh
XRed Square
XKremlin
XMimico
XHollywood
XDaytona Beach
XSalt Lake City
XMississauga
XMajorca
XBangkok
XMonte Carlo
XLisbon
XBarrie
XNirvana
X%MAIN
X\CONST.\!\!
X%INVOLVED
X.\! -- \CELEB Reveals All
X.\! -- \CELEB May Be Involved
X%PROOF
X\PHOTO
X\PHOTO
X.\! -- \NATIONALITY \SCIENTIST/s Offer Undeniable Proof
X%PHOTO
X.\! -- Exclusive Pictures Inside
X.\! -- Photographic Evidence Offers Proof
X.\! -- National Enquirer Photo Exclusive
X%CONST
X"Killer \KILLER/s From \PLANET \EAT/d My \BABY" \SAY/s \CELEB\PHOTO
X"\CELEB Is Really \ET From \PLANET" \SAY/s \CELEB
X"\CELEB Is Really \ET From \PLANET" \SAY \NATIONALITY \SCIENTIST/s
X\MCELEB and \FCELEB Secretly Wed in \PLACE, It's Official\PHOTO
XEating \FRUIT/s Can Give You \DISEASE, \SAY \NATIONALITY \DOCTOR/s
X"\ET/s From \PLANET Gave Me \DISEASE" \SAY/s \CELEB
X"\FICTCHAR is for real".\! -- \NATIONALITY \SCIENTIST/s come up with undeniable proof
X"\MCELEB is really my father", \SAY/s \CELEB
X"\FCELEB is really my mother", \SAY/s \CELEB
X\NATIONALITY \SCIENTIST/s discover lost city of \PLACE
X\CELEB \KILL/s \NUMBER \PERSON/s in drunken rampage
X\PERSON, stoned on \DRUG, \KILL/s \NUMBER \PERSON/s
X\CELEB Falls \NUMBER thousand feet out of \AIRCRAFT ... and survives
X"\ET/s From \PLANET Landed In My Garden And \EAT/d \NUMBER \FRUIT/s" \SAY/s \CELEB
X\FCELEB Gives birth to \NUMBER \BABY/s\INVOLVED
X\RELIGION Monks report \UFFO Sighting in \PLACE\! "They Came From \PLANET!"\PROOF
XReal Life Ghost Busters Exorcise \GHOST from \CELEB/ 's home in \PLACE
X\BABY \KILL/d by Pet \KILLER\PHOTO
XAmazing \MADNESS \KILLERX from \PLACE
X"I Chopped My \RELATIVE To Death With \WEAPON/a" -- \PERSON
X\PERSON Goes Berserk And \KILL/s \NUMBER \PERSON/s With \WEAPON
X\FCELEB Tells Of Night Of Terror With \MCELEB. "He Threatened Me With \WEAPON/a"
X\MCELEB Tells Of Night Of Terror With \FCELEB. "She Threatened Me With \WEAPON/a"
X\FRUIT/s Have \SPIRITUAL Powers, \SAY \NATIONALITY \SCIENTIST/s\PROOF
X\PERSON Sees Face Of \FICTCHAR In \FOOD/a
X"Elvis Died From Eating \FRUIT/s", \SAY/s \CELEB\PROOF
X\NATIONALITY \SCIENTIST/s Produce \SPIRITUAL \KILLER Girl
X\PERSON \KILL/s \NUMBER \PERSON/s With \WEAPON,\!Then Is Acquitted By Jury
X\NUMBER Years For \MADNESS \WEAPON Murderer. "I Would Do It Again" Says \CELEB
X\PERSON Struck By Lightning -- \NUMBER Times
XJury Acquit Notorious \WEAPON Murderer From \PLACE
X\MCELEB and \FCELEB Seen Together in \PLACE. "Is It Love?"
X\PERSON/ 's Bizarre Claim: "\NATIONALITY \SCIENTIST/s Planted Mind Control Device In My Head"
X"Does \FICTCHAR Exist?" \NATIONALITY \SCIENTIST/s Offer New Evidence
XTravelling To \PLACE In A Stolen \AIRCRAFT -- \CELEB Tells All\PHOTO
X"\FICTCHAR \EAT/d My \BABY", \SAY/s \PERSON
X"\MCELEB is the Father Of My \BABY", \SAY/s \MADNESS \PERSON
X"\FCELEB is the Mother Of My \BABY", \SAY/s \MCELEB\INVOLVED
X\FCELEB Files Paternity Suit Against \FCELEB -- Claiming Sex Change
X"I Am The Reincarnation of \FDEAD", \SAY/s \FCELEB
X"I Am The Reincarnation of \MDEAD", \SAY/s \MCELEB
X\SCIENTIST/s Discover \FCELEB Was Married to \MDEAD in Previous Life
X"I spoke to \DCELEB through \FRUIT/a" \SAY/s \PERSON
X"I Saw \DCELEB Alive and Well in \PLACE" \SAY/s \PERSON
X\NATIONALITY \SCIENTIST/s resurrect \DCELEB\PROOF
XIn \MADNESS Rage, \PERSON \KILL/s \NUMBER, Self
X"\CELEB Is Addicted to \DRUG"\PROOF
X"\FCELEB is the \RELATIVE of my \RELATIVE" says \MCELEB \PROOF
X%%
SHAR_EOF
if test 8211 -ne "`wc -c < 'headline'`"
then
	echo shar: "error transmitting 'headline'" '(should have been 8211 characters)'
fi
fi
echo shar: "extracting 'sifi.sp'" '(2958 characters)'
if test -f 'sifi.sp'
then
	echo shar: "will not over-write existing file 'sifi.sp'"
else
sed 's/^X//' << \SHAR_EOF > 'sifi.sp'
X\* SIFI: Sci-Fi Plot Generator
X\* Last Modified: 8 July 1990 by wiml@milton.u.washington.edu
X\*
X\* Originally coded by Kevin D. Quitt (demott!kdq, kdq@demott.com)
X\* who commented, in the C version,
X\* "This program was converted on [24-July-1990] from a spaghetti-
X\* coded BASIC program (that almost worked). I am the original
X\* author of both works, though G*d only knows why someone would
X\* claim otherwise. .... Note that the original flowchart for this
X\* program is *not* my [kdq's] creation - I believe Gahan Wilson did it
X\* originally, I think about '81, published in OMNI magazine."
X\* Minor modifications to the C code by chad@anasaz.UUCP on 31 July 1990.
X\* Converted to spewfile format 7 August 1990 by wiml@milton.u.washington.edu,
X\* also a few more phrases added and probabilities tweaked.
X\* The \PRUNE pseudo-class is unique to the version of SPEW modified
X\* for this rulesfile.
X%SIZE
Xtiny
Xgiant
Xmicroscopic
Xplanet-sized
Xhumongous
Xitty-bitty
X%BEING
Xbugs, which
Xreptiles, which
Xmechanical devices, which
Xsuper persons, who
Xicky things, which
Xbeings composed completely of energy, which
X%BEINGTYPE
Xextra-galactic
XMartian
XMoon
XBetelgeusian
X%COMETRESULTS
Xdestroyed.
Xsaved by Jesus and the J.D.L.
Xnot destroyed, but everybody dies.
Xsaved by a a reclusive hermit and his cute alien pet.
X%KILLEDBY
Xthe Atomic Bomb
Xa crowd of peasnts with torches
Xthe Army, Navy, Air Force, Marine Corps and/or Coast Guard
Xorbiting laser satellites
Xguerilla foces
X%BUT
Xthey fall in love with a beautiful girl
Xa cute little kid convinces them that people are OK
Xa priest talks to them of God
XCaptain Kirk uses logic on them
X%TERM1
Xand they die. \PRUNE
Xand they leave. \PRUNE
Xand they turn into disgusting lumps. \PRUNE
X%TERM2
Xbut they die from catching chicken pox. \PRUNE
Xso they kill us. \PRUNE
Xso they put us under a benign dictatorship. \PRUNE
Xso they eat us. \PRUNE
X%WEAPONRESULTS
Xwhich fails
Xwhich kills them. \PRUNE
Xwhich turns them into disgusting lumps. \PRUNE
X%DESCRIBEBEING
X\SIZE \BEINGTYPE \BEING \DESCRIBEBEINGTAIL
X%DESCRIBEBEINGTAIL
Xwant our women,
Xwant our women, take a few and leave. \PRUNE
Xare friendly. \PRUNE
Xare friendly, but misunderstood,
Xmisunderstand us
Xunderstand us too well
Xare emissaries from God
Xlook upon us only as a source of nourishment
Xlook upon us only as a source of nourishment, and eat us. \PRUNE
X%DOBUT
X, but \BUT \TERM1
X%SIFI!
X(2)Earth is struck by a giant comet and \COMETRESULTS
X(5)Scientists discover or invent \DESCRIBEBEINGCURIE
X(5)Earth is attacked by \DESCRIBEBEINGCURIE
XEarth burns up or freezes or falls into the sun and everybody dies.
XEarth burns up or freezes or falls into the sun and almost everybody dies.
X%MAYBE
X(1)
X(1) not
X%DESCRIBEBEINGCURIE
X\DESCRIBEBEING and are\MAYBE radioactive, and can\MAYBE be killed by \KILLEDBY/ \WHATTODO
X%WHATTODO   \* WHATTODO is a recursive version of the iterative original
X\DOBUT \TERM2
X\DOBUT so scientists invent a weapon \WEAPONRESULTS \WHATTODO
X%MAIN
X\SIFI!/ \!\!
X%%
SHAR_EOF
if test 2958 -ne "`wc -c < 'sifi.sp'`"
then
	echo shar: "error transmitting 'sifi.sp'" '(should have been 2958 characters)'
fi
fi
echo shar: "extracting 'madrock.sp'" '(3470 characters)'
if test -f 'madrock.sp'
then
	echo shar: "will not over-write existing file 'madrock.sp'"
else
sed 's/^X//' << \SHAR_EOF > 'madrock.sp'
X\* SPEW implementation of MAD rock concert article generator
X\* Based on: "C Implementation of MAD magazine's
X\*    ALL-INCLUSIVE DO-IT-YOURSELF ROCK CONCERT Newspaper Story
X\*    by satyr@ucscb.ucsc.edu 1987
X\* SPEW implementation by wiml@u.washington.edu 1990
X%HOWMANY
XThousands of
XMillions of
XHundreds of
XSeveral
XUncounted millions of
XFourteen
XA huge number of
XBillions of
XSeven and a half
XMany
XQuite a few
XMore than one
X%WHATSTATE
Xscreaming
Xripped-off
Xborn-again
XBloom County
Xsuicidal
Xtoxic
Xwhacked-out
Xslightly used
Xpregnant
Xmolting
Xfrigid
Xcalcium deficient
X%WHO
Xrock fans
Xteenagers
Xmarmot-breeders
XSandanistas
XBob Uecker look-alikes
Xboat people
Xamnesiacs
XTrivial Pursuit players
Xowl worshippers
Xbed-wetters
XDeLorean dealers
Xsoothsayers
X%WHERE
Xthe City Auditorium
Xthe Kingdome
XBernie's Car Wash
XSt. Patrick's Cathedral
Xthe Oval Office
XBuddy Hackett's hot tub
Xthe Australian outback
Xa new Honda Civic
XTed and Rita's family room
Xthe K-Mart linens section
XLake Huron
Xthe Exit 17 offramp
X%WHOTOSEE
Xthe Jacksons
XVan Halen
XBoy George
Xthe Little Rascals
XKate and Allie
XBotswana wife-swappers
Xthe Dallas Mavericks
XMr. T's caterer
Xthe Miss Bulgaria finalists
Xthe last Civil War veteran
XCasper Weinberger
Xa KGB double agent
X%DIDSOMETHING
Xstood in line
Xcounted their toes
Xshouted pygmy oaths
Xchanted "DEE-fense!"
Xaged prematurely
Xlicked Snickers wrappers
Xdonned wet suits
Xpolished their nose-rings
Xwept openly
Xbroke wind
Xswapped zip-codes
Xfondled their ear-lobes
X%DOSOMETHING
Xpay $30
Xsell their sisters
Xgrovel shamelessly
Xlose their virginity
Xrenounce Satan
Xgive up breathing
Xsacrifice a beagle
Xbetray their scoutmaster
Xsell their vital organs
Xgive up their citizenship
Xpawn their phony Omegas
Xchange their sex
X%SOME
Xa few outbreaks of
Xthe usual
Xsome harmless
Xpost-Olympic
Xsloppy attempts at
Xauthentic Haitian
Xprecision drill
Xthe romantic lure of
Xthe Bush Cabinet's
Xsome very creative
Xthe lethal effects of
Xthe distinctive odor of
X%DISTRACTION
Xrioting
Xterrorism
Xdrunkenness
Xcar-stripping
Xpillaging
Xnude break-dancing
Xpossum worship
XKarl Malden impersonations
Xsilicone rejection
Xout-of-body retching
Xestate planning
Xparakeet training
X%ANNOYANCE
Xarrest
Xflogging
Xhearing loss
Xdeath screams
Xmelt-down
Xspraying
Xflossing
Xglassy-eyed stares
Xpre-soaking
Xpoor penalty-killing
Xfactory recall
Xpainless removal
X%ANNOYADJ
Xunruly
Xoff-duty
Xstoned
Xpre-Columbian
Xsingles-bar
Xfur-bearing
XLucasfilm
XLibyan-backed
Xreincarnated
Xset-user-id
Xmoss-covered
Xcutesy-pie
Xsplattered
X%ANNOYOBJ
Xpunks
Xdrug dealers
XSagittarians
Xnerds
Xwelfare cheats
XUnitarians
Xsurfers
Xmercenaries
XCornhuskers
Xskycaps
XMunchkins
Xcenterfolds
X%FUN
Xan unqualified success
Xa victory for good taste
Xmore fun than Pearl Harbor
Xa vindication of greed
Xproof of God's love
Xan incredible waste of time
Xas significant as Flag Day
Xa triumph of Jerry Falwell
Xa glorification of self-abuse
Xas memorable as 'Lottery'
Xa festival for degenerates
Xan answer for Communism
X%MAIN
X\* We have to break this line up or SPEW will chop it
X\HEADER\! \PART1 \PART2 \PART3 \!\!
X%HEADER
X                                MAD MAGAZINE\!                                \
X------------\!                           ROCK CONCERT LAST NIGHT\!
X%PART1
X  \HOWMANY \WHATSTATE \WHO packed \WHERE last night to see \WHOTOSEE in concert.
X%PART2
X Many fans \DIDSOMETHING for more than ten hours while waiting to \DOSOMETHING for a ticket.
X%PART3
X Despite \SOME \DISTRACTION and the occasional \ANNOYANCE of \ANNOYADJ \ANNOYOBJ, the promoters of the event called it \FUN.
X%%
SHAR_EOF
if test 3470 -ne "`wc -c < 'madrock.sp'`"
then
	echo shar: "error transmitting 'madrock.sp'" '(should have been 3470 characters)'
fi
fi
echo shar: "extracting 'manual'" '(5498 characters)'
if test -f 'manual'
then
	echo shar: "will not over-write existing file 'manual'"
else
sed 's/^X//' << \SHAR_EOF > 'manual'
XINPUT FILE FORMAT:
X
XThe file is a series of class definitions followed by an end
Xmarker. The end marker is a line containing only "%%".
X
XA class definition begins with a line containing '%' followed by a class
Xname. Class names can be any length and can consist of any combination
Xof upper and lower case letters, and numbers.
X
XThe lines following are instances of the class, one per line. When a
Xclass is invoked, one of these is picked at random. Most characters in
Xthe line are just copied to the output. The newline at the end is not
Xcopied. An instance may be continued onto the next line by ending the
Xline with '\'. There is a limit of 1000 bytes on the total size of an
Xinstance.  An instance may begin with '%' if it is escaped: '\%'. A
Xnewline may be written as '\!'. A backslash may be written as '\\'.
X
XThe following is a simple rules-file that prints out either 'foo'
Xor bar, followed by a carriage-return:
X
X%MAIN
Xfoo\!
Xbar\!
X%%
X
XThe program generates a random instance of the class 'MAIN', which in
Xthis case selects 'foo' or 'bar', with a 50-50 chance. A newline is
Xappended.
X
X	WEIGHTS
X
XTo give 'foo' a 90% chance of happening, you can assign weights:
X
X%MAIN
X(9)foo\!
Xbar\!
X%%
X
XThe weight of 'bar' is 1 by default. If an instance is to begin with '('
Xit must be escaped, or given an explicit weight:
X
X\(animal)
X(1)(vegetable)
X
X	INVOCATION
X
XClasses are normally invoked by writing their name immediately after a
Xbackslash. Below is a rules-file which is equivalent to the foo-bar
Xexample:
X
X%MAIN
X\word\!
X%word
X(9)foo
Xbar
X%%
X
XIn this case, the class 'word' outputs either 'foo' or 'bar', and
Xthe newline is appended after the invocation in 'MAIN'.
X
XIf you wish to immediately follow a class invokation by a letter or a number,
Xyou must write it followed by a slash and a space:
X
X%MAIN
X\word/ bar\!
X%word
Xfoo
Xbar
X%%
X
XThe above outputs either 'foobar' or 'barbar'. This method must also
Xbe used if the invokation is to be immediately followed by a slash.
X
X	VARIANTS
X
XA class may be defined with variants, and may then be invoked with
Xvariants. The 's' variant defined for the 'fruit' class below
Xallows correct plurals to be generated:
X
X%fruit{s}
Xapple{|s}
Xcherr{y|ies}
Xpear{|s}
Xmango{|es}
X%MAIN
XOne \fruit and two \fruit/s.\!
X%%
X
XThe variant tag is a single letter or number. In an invocation, the
Xclass name is followed by a slash which is followed by the tag. Every
Xclass has a 'null' variant (tagged by a space) by default (thus the "/ "
Xnotation).
X
XIn the class definition line, the class name is followed by a list
Xof variant tags in curly brackets. The order of the tags is
Xsignificant.
X
XIn an instance definition, variants may be created with the following
Xnotation:
X	{ <null-variant-text> | <1st-variant-text> | <2nd-variant-text }
X
XWhen a class is invoked with a null tag, or with a blank tag, the
Xtext before the first '|' is used. If the first tag is used in the
Xinvocation (i.e. the first tag listed in {}'s in the class definition),
Xthe text between the first and second |'s is used, and so forth.  All
Xtext not in {}'s is copied regardless of the tag used.
X
XThere are normally as many |'s in these as there are tags defined.
XIf there are too many tags, the excess ones select null strings, and
Xif there are too many |'s, the excess strings are redundant.
X
XThe '{' character, if required literally,  must always be escaped
Xoutside the selector construction: '\{', even when no variants are
Xdefined in a class. The '|' and '}' characters must likewise be
Xescaped inside a constructor.
X
XInvocations may appear in a selector, but cannot span a selector.
XI.e. you cannot select between invoking 'catwalk' and 'catfish' by
X
X	\cat{walk|fish}
X
XYou must use {\catwalk|\catfish}.
X
XFinally, there is the & tag which may be used in an invocation and
Xselects the same tag letter (or number) which the invoking
Xclass was invoked with:
X
X%food{s}
X\fruit/&			<--- this is the same as
X{\fruit|\fruit/s}		<--- this.
X
XMAIN is initially invoked with the null tag (although it can be invoked
Xrecursively with other tags).
X
XHere is a class with multiple tags that generates irregular verbs:
X
X%verb{sd}
X{eat|eats|ate}
X{be|is|was}
X{see|sees|saw}
Xlook{|s|ed}
Xf{ind|inds|ound}
X%%
X
XThus \verb/d generates a past-tense verb.
X
X     PRUNING
X
XThere is one "special" pseudo-class, PRUNE. When PRUNE is invoked, no
Xmore output is generated on that line, and control immediately reverts
Xto the *end* of the last class invoked whose name ended with an '!'.
XThis is useful when a certain series of choices can suddenly end
Xthe phrase or whatever (such as an abrupt, "startler" terminator to a
Xjoke). Currently prunestops (those classes ending with an '!' which
Xstop the backtracking after a \PRUNE) can not be nested; a \PRUNE after
Xan inner prunestop has been exited will cause an error message. This
Xshould probably be fixed sometime, as well as making the prunestop
Xspecification more elegant. Example:
X
X%MAIN
XJoe got sick, \THENWHAT!/ .
X%THENWHAT!
X\MIDDLE \CONVALESCE
X%MIDDLE
Xwas sick for a while,
Xate some magic herbs,
Xand died\PRUNE
X%CONVALESCE
Xthen got better.
Xand recovered.
X%%
X 
X  In this case, if "and died" is chosen, text generation will resume
Ximmediately after \THENWHAT!/ , producing "Joe got sick, and died.".
X
X	COMMENTS:
X
XAt any point, '\*' may appear on a line and the rest of the line
Xis ignored. Blank lines are ignored completely ( as are lines
Xbeginning in \* ).
XEmpty instances must therefore be given an explicit weight of one:
X
X%AllOrNothing\*	50% chance, 'All', or nothing.
XAll
X(1)
X
SHAR_EOF
if test 5498 -ne "`wc -c < 'manual'`"
then
	echo shar: "error transmitting 'manual'" '(should have been 5498 characters)'
fi
fi
echo shar: "extracting 'spew.c'" '(22540 characters)'
if test -f 'spew.c'
then
	echo shar: "will not over-write existing file 'spew.c'"
else
sed 's/^X//' << \SHAR_EOF > 'spew.c'
X/*
X * SPEW.C
X */
X
X/* #define DOS      Undef this if compiling under BSD UNIX */
X#define PRUNE	/* Undef this if /PRUNE pseudoclass not used or
X		   setjmp/longjmp not available (WML) */
X
X
X#ifndef lint
Xstatic char *cpr[]={
X   "  Copyright 1987 Greg Smith",
X   "  Permission is granted to freely use and distribute this software",
X   "provided this notice is left attached and no monetary gain is made."
X};
X
Xstatic char *mod_notice[] =  {
X   "  Modified for compilation under DOS with Borland Turbo C.",
X   "by Ti Kan 5-31-1988.",
X   "  Other modifications, additions, and improvements",
X   "by Wim Lewis (WML) August 1990."
X};
X#endif
X
X#include <stdio.h>
X#include <ctype.h>
X
X#ifdef PRUNE
X#include <setjmp.h>
X#endif
X
X#ifdef DOS
X
X#include <stdlib.h>
X#include <string.h>
X#include <alloc.h>
X#include <bios.h>
X#define index(s,c)      strchr(s,c)
X#define rindex(s,c)     strrchr(s,c)
X
X#else
X
X#include <strings.h>
Xextern char *malloc();
Xextern int atoi();
X
X#endif
X
Xchar *my_alloc();
Xchar *save();
X#define TRUE (1)
X#define FALSE (0)
X#define MAGIC 4         /* distinguish compressed file from normal */
X
Xvoid print(), printc();
X
X/*--------------- system configuration ------------------*/
X
X/* define some parameters */
X
X#define MAXCLASS 300            /* max # of classes */
X#define MAXLINE 256             /* max size of input line */
X#define MAXDEF 1000             /* max # bytes in a definition */
X
X/* Define the default rulesfile */
X
X#ifndef DEFFILE
X#define DEFFILE "/b1/wiml/pub/headline"
X#endif
X
X/* Define the environment variable which is to be interrogated for
X   name of rules file before DEFFILE is used. Delete this to
X   remove the code that calls getenv() */
X
X#define ENVIRON "RULESFILE"
X
X/* Define the output line width. Lines are word-broken to this width. */
X
X#define LINE_WIDTH (75)
X
X/* Define the random number generator */
X
X#ifndef DOS
Xextern long getpid();
Xextern int rand(), srand();
X#endif
X
X
X        /* SETRAND must be a complete statement: note semicolon */
X#ifdef DOS
X#define SETRAND (void) srand((unsigned) biostime(0, 0L));
X#else
X#define SETRAND (void)srand((int) getpid());
X#endif
X
X        /* ROLL(n) returns integer 0..n-1 */
X#define ROLL(n) ((((long)rand()&0x7ffffff)>>5)%(n))
X
X/* Enable '-d' dump debug option by defining DUMP */
X#define DUMP
X
X/*---------------------------------------------------*/
X
XFILE *InFile;
X
Xtypedef struct def_struct{
X        int cumul;                      /* cumulative weights */
X        char *string;                   /* string which defines it */
X        struct def_struct *next;        /* link to next */
X} defn;
Xdefn *process();
X/*
X * within a definition, names of subdefinitions are bracketed in BSLASH
X * and SLASH chars. The whole definition ends with a '\0'.
X * The SLASH character is always follwed by a variant tag - default is ' '.
X */
X#define BSLASH '\\'
X#define SLASH  '/'
X#define VBAR     '|'
X
Xtypedef struct{
X        int weight;     /* total weight of definitions in class */
X        defn *list;     /* list of them */
X        char *name;     /* name of this class */
X        char *tags;     /* pointer to list of tags */
X} class;
X
Xclass * Class;  /* pointer to array of class records */
Xchar *NullTags = " ";   /* default tags ( shared ) */
Xint Classes;    /* number of them */
Xint HowMany = 1;
Xint CompIn = FALSE;     /* is input file in compressed format? */
Xint CompMain;           /* class # of MAIN class when compressed */
X#ifdef PRUNE
Xjmp_buf prunebuf;	/* where to longjmp when PRUNE encountered */
Xint prune_ok;		/* Whether prunebuf is still valid */
X#endif
X
Xchar InLine[MAXLINE];
X
Xmain(argc, argv )
Xint argc;
Xchar **argv;
X{
X        char *fname;
X        char main_class[20];
X        int i, c_flag = FALSE;
X#ifdef DUMP
X        int d_flag = FALSE;
X#endif DUMP
X#ifdef ENVIRON
X        extern char *getenv();
X        fname = getenv( ENVIRON );
X#else
X        fname = NULL;
X#endif ENVIRON
X
X        while( argc > 1 ){
X                if( isdigit(*argv[1]) ){
X                        HowMany = atoi(*++argv);
X                        --argc;
X                }else if( strcmp( argv[1], "-c") == 0 ){
X                        c_flag = TRUE;  /* 'compress' option */
X                        --argc;
X                        ++argv;
X#ifdef DUMP
X                }else if( strcmp( argv[1], "-d" )== 0 ){
X                        d_flag = TRUE;  /* 'dump' option */
X                        --argc;
X                        ++argv;
X#endif DUMP
X                }else break;
X        }
X        if( argc > 1 ) fname = argv[1];
X        if (fname == NULL ) fname = DEFFILE;
X        InFile = fopen( fname, "r" );
X        if( InFile == NULL ){
X                fprintf( stderr, "Can\'t open: %s\n", fname );
X                exit(1);
X        }
X        init();
X#ifdef DUMP
X        if( d_flag ){
X                dump();
X                exit(0);
X        }
X#endif DUMP
X        if( c_flag ){
X                compress();
X        }else{
X                if( CompIn ) sprintf( main_class, "%d/ ", CompMain);
X                else         strcpy( main_class, "MAIN/ ");
X                for(i=0; i<HowMany; ++ i) 
X		  {
X#ifdef PRUNE
X		    if(setjmp(prunebuf) == 0)
X		    {
X		      prune_ok = 1;
X#endif
X		      display(main_class,' ');
X#ifdef PRUNE
X		    }
X#endif
X		  }
X        }
X        exit(0);
X}
X
Xinit(){
X        int c;
X
X        SETRAND         /* spin random number gen */
X        c = getc( InFile );     /* is compressed? */
X        CompIn = ( c== MAGIC ); /* set flag */
X        if( CompIn ){
X                readcomp();     /* read compressed version */
X        }else{
X                ungetc(c, InFile );
X                readtext();
X        }
X}
Xreadtext(){
X        register class *cp;
X        register defn *dp;
X        defn **update;
X        int clcomp();
X
X        Class = (class *)my_alloc( (unsigned)(MAXCLASS * sizeof(class)) );
X        Classes = 0;
X
X        cp = Class;
X        readline();
X        if( InLine[0]!='%'){
X                fprintf( stderr,"Class definition expected at: %s\n", InLine);
X                exit(1);
X        }
X        while( InLine[1] != '%' ){
X                if( Classes == MAXCLASS ){
X                        fprintf(stderr,"Too many classes -- max = %d\n", MAXCLASS);
X                        exit(1);
X                }
X                setup( cp );            /* set up the class struct */
X                readline();
X                if( InLine[0] == '%' ){
X                        fprintf( stderr, "Expected class instance at: %s\n", InLine);
X                        exit(1);
X                }
X                update = &(cp->list);   /* update pointer */
X                do{
X                        dp = process();
X                        *update = dp;
X                        cp->weight += dp->cumul;        /* add new stuff */
X                        dp->cumul = cp->weight;         /* set breakpoint */
X                        update = &(dp->next);
X                }while( readline(), InLine[0]!= '%' );
X                ++Classes;              /* count them */
X                ++cp;
X                *update = NULL;
X        }
X        qsort( (char*)Class, Classes, sizeof( class ), clcomp);
X}
X/*
X * display is given a class name ( delimited by SLASH, not '\0' ),
X * and will (1) find its class descriptor, by calling lookup
X * (2) pick a definition  (3) output that definition, and
X * recursively display any definitions in it, and convert any escapes.
X * The variant tag after the SLASH is used to pick out the appropriate
X * variants. If that variant tag is '&', the tag 'deftag' is used, which
X * is the active variant of the containing activation.
X */
Xdisplay(s,deftag)
Xchar *s;
Xint deftag;
X{
X        register class *cp;
X        register defn *dp;
X        register char *p;
X        class *lookup();
X        int i,variant,incurly;
X        register int c,writing;
X	int weprune=0;  /* if we set the prune stop here */
X
X        if( CompIn ){           /* input is compressed */
X                cp = &Class[ atoi(s) ];         /* explicit class # */
X        }else{
X#ifdef PRUNE
X		if(!strncmp(s, "PRUNE/", 6))
X		{
X			if(!prune_ok)
X			{
X				print("\n -- Prune too late, aborting.\n");
X				exit(2);
X			}
X			else longjmp(prunebuf, 1);
X		}
X		if(index(s, '!') == (index(s, '/')-1))
X		{
X			if(setjmp(prunebuf))
X			{
X				prune_ok = 0;
X				return;
X			}
X			weprune=1;
X		}
X#endif
X                cp = lookup(s);
X                if( cp == NULL ) {              /* none found */
X                        print("???");
X                        while( *s != SLASH ) printc( *s++ );
X                        print("???");
X#ifdef PRUNE
X			if(weprune) prune_ok = 0;
X#endif
X                        return;
X                }
X
X        }
X        c = index(s,SLASH)[1];          /* get variant tag */
X        if( c != '&' ) deftag=c;        /* use given tag */
X        p = index(cp->tags, deftag);            /* look it up */
X        if(p == NULL ){
X                variant = 0;
X                print("??");
X                printc(deftag);
X                print("??");
X                deftag = ' ';           /* for passing as deftag */
X        }else variant = p - cp->tags;
X
X        i = ROLL( cp->weight );
X        dp = cp->list;
X        while(dp->cumul <= i){  /* pick one based on cumul. weights */
X                dp = dp->next;
X        }
X
X        incurly = 0;            /* not in curlies */
X        writing = 1;            /* writing */
X        p = dp->string;         /* this is the string */
X        for(;;)switch(c = *p++){
X                case '\0': 
X#ifdef PRUNE
X			   if(weprune) prune_ok = 0; 
X#endif
X		  					return;
X                case BSLASH:
X                        if(( c = *p++) == '\0' ) 
X			{
X#ifdef PRUNE
X			   if(weprune) prune_ok = 0;
X#endif
X			   return; /* ?? */
X			}
X                        else if( c == '!' ){
X                                 if(writing)printc('\n'); /* \! = newline */
X                        }else if( isalnum(c) ){ /* reference */
X                                if(writing)display(p-1,deftag);  /* recurse */
X                                while( *p!=SLASH )++p;
X                                p += 2;         /* skip variant tag */
X                        }else{
X                                if(writing) printc(c);
X                        }
X                        break;
X                case '{':
X                        if( !incurly ){
X                                incurly = 1;
X                                writing = (variant == 0 );
X                        }else{
X                                if( writing )printc('{');
X                        }
X                        break;
X                case VBAR:
X                        if( incurly ){
X                                writing = ( variant == incurly++ );
X                        }else{
X                                printc(VBAR);
X                        }
X                        break;
X                case '}':
X                        if( incurly ){
X                                writing = 1;
X                                incurly = 0;
X                        }else printc('}');
X                        break;
X                default:
X                        if( writing) printc(c);
X        }
X   /*NOTREACHED*/
X}
Xclass *
Xlookup( str )           /* delimited by SLASH, not '\0' */
Xchar *str;
X{
X        int first, last, try, comp;
X        int namecomp();
X
X        first = 0;
X        last = Classes-1;
X        while( first <= last ){
X                try = (first+last)>>1;
X                comp = namecomp( str, Class[try].name );
X                if( comp == 0 ) return &Class[try];
X                if( comp > 0 ) first = try+1;
X                else last = try-1;
X        }
X        return NULL;
X}
Xint namecomp(a,b)       /* 'a' is delim. by SLASH, 'b' by NULL */
Xregister char *a,*b;
X{
X        register int ac;
X        for(;;){
X                ac = *a++;
X                if(ac == SLASH ) ac = '\0';
X                if( ac < *b ) return -1;
X                if( ac > *b++ ) return 1;
X                if( ac == '\0' ) return 0;
X        }
X}
Xreadline(){
X        register char *p;
X        do{
X                if( fgets( InLine, MAXLINE, InFile ) == NULL ){
X                        InLine[0] = InLine[1] = '%';
X                        InLine[2] = '\0';       /* create EOF */
X                }else if( (p=rindex( InLine, '\n'))!= NULL ) *p = '\0';
X                p = InLine;
X                while( (p = index( p, BSLASH )) != NULL ){
X                        if(p[1] == '*' ){
X                                *p = 0; /* kill comment */
X                                break;
X                        }else ++p;
X                }
X        }while( InLine[0] == '\0' );
X}
X
Xint clcomp(a,b)                 
Xregister class *a,*b;
X{
X        if( a==b) return 0;
X        return strcmp( a->name, b->name );
X}
Xchar *save(str)
Xchar *str;
X{
X        register char *p;
X        p = my_alloc( (unsigned)((strlen(str)+1)*sizeof(char)));
X        return strcpy(p,str);
X}
X/*
X * setup a class record. The 'class' line is in InLine.
X */
Xsetup(cp)
Xregister class *cp;
X{
X        char temp[100];
X        register char *p,*p2;
X
X        p = &InLine[1];         /* point after the % */
X        while( *p == ' ' )++p;
X        if( !isalnum(*p) ) goto baddec;
X        p2 = temp;
X        do *p2++ = *p++; while( isalnum(*p) || (*p == '!'));
X        *p2 = '\0';
X        cp->weight = 0;         /* save the name of it */
X        cp->name = save( temp );
X        cp->list = NULL;
X        cp->tags = NullTags;    /* by default */
X        for(;;)switch(*p++){
X        case '\0':
X                return; /* all done; */
X        case ' ':
X                break;          /* allowed those */
X        case '{':               /* tags list */
X                if( cp->tags  != NullTags ) goto baddec; /* already */
X                p2 = temp;
X                *p2++ = ' ';    /* provide null tag */
X                while(*p!='}'){
X                        if( !isalnum(*p)) goto baddec;
X                        *p2++ = *p++;
X                }
X                ++p;    /* junk rh brace */
X                *p2 = 0;
X                cp->tags = save(temp);
X                break;
X        default: goto baddec;
X        }
X  baddec:
X        fprintf(stderr,"Bad class header: %s\n", InLine );
X        exit(1);
X}
X/*
X * create a 'processed' version of the InLine, and return a pointer to
X * the definition. The 'cumul' field is temporarily used to hold the
X * assigned weight of the line.
X */
Xdefn *process(){
X        static char stuff[ MAXDEF ];
X        register char *p,*pout;
X        register defn *dp;
X        register int c;
X
X        dp = (defn *) my_alloc( (unsigned) sizeof( defn ));
X
X        p = InLine;
X        pout = stuff;
X        if( *p == '(' ){                /* get a weight */
X                while(*++p ==' ');      /* scan */
X                if(!isdigit(*p)) goto badweight;
X                c = *p - '0';
X                while(isdigit(*++p)) c = c*10 + (*p - '0' );
X                while( *p == ' ')++p;
X                if( *p != ')') goto badweight;
X                ++p;
X                dp->cumul = c;
X        }else{
X                dp->cumul = 1;  /* default weight */
X        }
X        while((c = *p++)!='\0')switch(c){
X        case BSLASH:
X                *pout++ = BSLASH;
X                if( isalnum(*p)){       /* is a ref */
X                        do{ *pout++ = *p++;
X                        }while( isalnum(*p) || (*p == '!'));
X                        *pout++ = SLASH;                /* delimit */
X                        if( *p == SLASH ){      /* get variant char */
X                                ++p;
X                                if( !isalnum(*p)&& *p!= ' ' && *p!= '&' ){
X                                        *pout++ = ' ';
X                                }else *pout++ = *p++;
X                        }else *pout++ = ' ';
X                }else{
X                        *pout++ = *p;
X                        if( *p!= '\0'){
X                                 ++p;
X                        }else{
X                                --pout; /* delete spurious '\' */
X                                readline();     /* get new line */
X                                p = InLine;     /* point to it */
X                        }
X                }
X                break;
X        default:
X                *pout++ = c;
X        }
X        *pout = '\0';
X        dp->string = save( stuff );
X        return dp;
X
X  badweight:
X        fprintf(stderr, "Bad line weight: %s\n", InLine );
X        exit(1);
X        /*NOTREACHED*/
X}
X#ifdef DUMP
Xdump(){
X        register class *cp;
X        register defn *dp;
X        register int i;
X        for( i=0, cp=Class; i<Classes; ++cp,++i ){
X                if( CompIn)
X                        printf("%d, {%s} %d:\n",i ,cp->tags, cp->weight );
X                else
X                        printf("%s, {%s} %d:\n", cp->name,cp->tags, cp->weight );
X                for( dp = cp->list; dp!=NULL; dp=dp->next ){
X                        printf("(%d)%s\n",dp->cumul, dp->string );
X                }
X        }
X}
X#endif DUMP
X
Xchar *my_alloc(n)
Xunsigned n;
X{
X        register char *p;
X        p = malloc( n );
X        if( p==NULL ){
X                fprintf(stderr, "Out Of Memory\n");
X                exit(1);
X        }
X        return p;
X}
X
X/*
X * write the file to the standard output in compressed form, prepending
X * the MAGIC byte for identification.
X */
Xcompress(){
X        register class *cp;
X        register int i;
X
X        putchar( MAGIC );
X        putw( Classes, stdout );        /* write the number of classes */
X        putw( -Classes, stdout );       /* write this to make sure */
X
X        if( !CompIn ){
X                cp = lookup("MAIN/ ");          /* get main */
X                if( cp == NULL ){
X                        fprintf(stderr, "MAIN undefined\n");
X                        exit(1);
X                }
X                CompMain = cp - Class;
X        }
X        putw( CompMain, stdout );
X        cp = Class;
X        i  = Classes;
X        while(i--) comp1(cp++);
X}
X/*
X * write a 'class' record in compressed format
X */
Xcomp1(cp)
Xregister class *cp;
X{
X        register char *p;
X        register defn *dp;
X        register int n;
X
X        putw( cp->weight, stdout );     /* write total weight */
X        p = cp->tags;
X        if( strcmp(p,NullTags) != 0 )   /* special case " " -> "" */
X                fputs( p, stdout );             /* write tags */
X        putchar(0);                     /* delimiter */
X        n = 0;
X        dp = cp->list;
X        while( dp!= NULL ){
X                ++n;            /* count the defs */
X                dp = dp->next;
X        }
X        putw( n, stdout );      /* write the count of them */
X        dp = cp->list;
X        while( dp != NULL ){
X                compdef(dp);
X                dp = dp->next;  /* compress them */
X        }
X}
Xcompdef(dp)
Xregister defn *dp;
X{
X        register char *p;
X        register int c;
X        putw( dp-> cumul , stdout );    /* write its cumul weight */
X        p = dp->string;
X        while( (c = *p++) != '\0' ){
X                if( c==BSLASH){
X                        if(!CompIn && isalnum(*p) ){    /* a ref */
X                                class *cp;
X                                cp = lookup(p);         /* find it */
X                                if( cp == NULL ){
X                                        fprintf( stderr, "Undefined class: ");
X                                        while( *p != SLASH ) fputc( *p++, stderr);
X                                        fputc('\n', stderr );
X                                        exit(1);
X                                }else{
X                                        printf("%c%d", BSLASH, cp-Class );
X                                        while( *p != SLASH ) ++p;
X                                }
X                        }else{          /* is escape seq */
X                                putchar( BSLASH );
X                                putchar( *p++ );
X                        }
X                }else{
X                        putchar(c);
X                }
X        }
X        putchar(0);
X}
X
X/*
X * readcomp reads the compressed format of the file into core.
X * the MAGIC char has been read already.
X */
Xreadcomp(){
X        register class *cp;
X        register int i;
X        Classes = getw( InFile );
X        if( Classes <= 0 || getw( InFile ) + Classes != 0 )
X                badfile();      /* format check */
X        CompMain = getw( InFile );              /* read that next */
X        Class = (class*) my_alloc( (unsigned)(Classes*sizeof(class)) );
X        for( i= Classes, cp = Class; i--; ++cp)readcclass(cp);
X}
X
Xreadcclass(cp)
Xregister class *cp;
X{
X        register int n;
X        register defn *dp;
X        defn **dput;
X
X        char store[MAXDEF];     /* for tags */
X        cp->weight = getw( InFile );
X        instring(store,MAXDEF);
X        cp->tags = ( store[0] == '\0' )? NullTags: save( store );
X        n = getw( InFile );
X        if( n<=0 ) badfile();
X        dput = &(cp->list);     /* link on here */
X        while(n--){
X                dp = (defn *)my_alloc( (unsigned) sizeof( defn));
X                *dput = dp;
X                dp->cumul = getw( InFile );
X                instring(store, MAXDEF );
X                dp->string = save( store );
X                dput = &(dp->next);
X        }
X        *dput = NULL;           /* last one */
X}
X
X
X
Xvoid print(line) char *line;  /* output text, breaking on word bounds */
X{
X for( ; *line ; line++)
X   printc(*line);
X}
X
Xstatic char linebuf [LINE_WIDTH+1];  /* text awaiting output */
Xstatic int col = 0;   /* column position */
Xvoid printc(ch) char ch;  
X{
X  if(isspace(ch)) /* think about flushing */
X  {
X    if((ch == '\n') || (ch == '\r'))
X    {
X     puts(linebuf);
X     linebuf[0] = 0;
X     col = 0;
X     return;
X    }
X    if((col + strlen(linebuf) > LINE_WIDTH) && col)
X    {
X     putchar('\n');
X     fputs(linebuf, stdout);
X     putchar(ch);
X     col = strlen(linebuf) + 1;
X     linebuf[0] = 0;     
X     return;
X    }
X    if(col + strlen(linebuf) > LINE_WIDTH)
X    {
X     puts(linebuf);
X     linebuf[0] = 0;
X     return;
X    }
X    fputs(linebuf, stdout);
X    col += strlen(linebuf);
X    *linebuf = 0;
X    if(col < LINE_WIDTH)
X    {
X     col++;
X     putchar(' ');
X    }
X  }
X  else
X  {
X   char *cp;
X   cp = linebuf + strlen(linebuf);
X   *cp++ = ch;
X   *cp = (char)0;
X  }
X return;
X}
X
Xinstring( where, how_many )
Xregister char *where;
Xregister int how_many;
X{
X        register int c;
X        do{
X                c = getc( InFile );
X                if( c == EOF ) badfile();
X                *where++ = c;
X                if( c== '\0' ) return;
X        }while(--how_many);
X        badfile();
X}
Xbadfile(){
X        fprintf(stderr,"Bad file format\n");
X        exit(1);
X}
SHAR_EOF
if test 22540 -ne "`wc -c < 'spew.c'`"
then
	echo shar: "error transmitting 'spew.c'" '(should have been 22540 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
wiml@blake.acs.washington.edu       Seattle, Washington  | No sig under
(William Lewis)  |  47 41' 15" N   122 42' 58" W  |||||||| construction