home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume21
/
thought
/
part01
next >
Wrap
Text File
|
1991-07-21
|
45KB
|
1,467 lines
Newsgroups: comp.sources.misc
From: David F. Skoll <dfs@doe.carleton.ca>
Subject: v21i023: thought - A replacement for 'fortune', Part01/02
Message-ID: <csm-v21i023=thought.175143@sparky.imd.sterling.com>
X-Md4-Signature: 00abd78133b2081edf9e6a75437f45f6
Date: Sun, 21 Jul 1991 22:52:49 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: David F. Skoll <dfs@doe.carleton.ca>
Posting-number: Volume 21, Issue 23
Archive-name: thought/part01
Environment: UNIX
Thought is a program which randomly generates sayings. These sayings
can at times be trite, are often funny, and occasionally seem profound.
Thought is configurable and can produce a wide variety of sayings, with a
little work.
I have supplied two grammar files - 'thought.rc' gives generally demented
sayings, and 'st.rc' gives demented sayings that sound like something from
Star Trek.
Many of the words in thought.rc were obtained from John Lamping's 'shop'
program, posted on alt.sources. Thanks go out to John Lamping,
lamping@parc.xerox.com.
David F. Skoll (dfs@doe.carleton.ca)
------------- Cut Here ---------- Cut Here ---------- Cut Here -------------
#!/bin/sh
# This is Thought 1.0, a shell archive (shar 3.32)
# made 07/17/1991 19:39 UTC by dfs@kmpec
# Source directory /enterprise/transporter/dfs/work/.thought/v1.0
#
# existing files will NOT be overwritten
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 2128 -rw------- Makefile
# 814 -rw------- README
# 745 -rw------- examples
# 2645 -rw------- protos.h
# 3634 -rw------- st.rc
# 26519 -rw------- thought.c
# 1895 -rw------- thought.man
# 22131 -rw------- thought.rc
# 7061 -rw------- thoughtfile.man
# 1036 -rw------- version.h
#
if touch 2>&1 | fgrep 'amc' > /dev/null
then TOUCH=touch
else TOUCH=true
fi
# ============= Makefile ==============
if test X"$1" != X"-c" -a -f 'Makefile'; then
echo "File already exists: skipping 'Makefile'"
else
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X###############################################################
X# #
X# Makefile for THOUGHT #
X# #
X# This file is part of THOUGHT by David F. Skoll. #
X# #
X# You can use THOUGHT in any way you see fit, but you must #
X# fully document any changes you make to the software, and #
X# must not remove this header from any of the files. #
X# #
X# THOUGHT is free and comes with no warranty. #
X# #
X# THOUGHT is copyright (C) 1991 by David F. Skoll #
X# #
X###############################################################
X
X#--------------- BEGINNING OF THINGS YOU CAN CHANGE --------------
X
X#If you have a SYSV system, uncomment next line:
X#CFLAGS= -DSYSV
X
X#If you want to use gcc:
X#CC= gcc
X
X#Where do you want it installed?
XBINDIR= /usr/local/bin
X
X#Where must the default grammar file go?
XLIBDIR= /usr/share/lib
X
X#What should the default grammar file be called?
XGRAMFILE= thought.rc
X
X# What program does the installation? If you don't have 'install', use
X# 'cp' instead.
XINSTALL= install
X#INSTALL= cp
X
X# Top level mandir
XMANDIR= /usr/man
X
X# What man section for the "thought" man page? (User commands)
XTMANSECT= 1
X
X# Whan man section for the "thoughtfile" man page? (File formats)
XTFMANSECT= 5
X
X#--------------- SHOULDN'T CHANGE STUFF BELOW HERE ---------------
X
Xall: thought.c protos.h version.h
X $(CC) -DLIBPATH=\"$(LIBDIR)\" -DFILE_DEFAULT=\"$(GRAMFILE)\" -o thought thought.c
X
Xinstall:
X $(INSTALL) thought $(BINDIR)
X $(INSTALL) thought $(LIBDIR)/$(GRAMFILE)
X
Xinstall.man:
X $(INSTALL) thought.man $(MANDIR)/man$(TMANSECT)/thought.$(TMANSECT)
X $(INSTALL) thoughtfile.man $(MANDIR)/man$(TFMANSECT)/thoughtfile.$(TFMANSECT)
X
Xclean:
X rm -f *.o core *~
X
Xclobber:
X rm -f *.o core *~ thought
SHAR_EOF
$TOUCH -am 0704145491 Makefile &&
chmod 0600 Makefile ||
echo "restore of Makefile failed"
set `wc -c Makefile`;Wc_c=$1
if test "$Wc_c" != "2128"; then
echo original size 2128, current size $Wc_c
fi
fi
# ============= README ==============
if test X"$1" != X"-c" -a -f 'README'; then
echo "File already exists: skipping 'README'"
else
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
XTHOUGHT - A replacement for fortune.
X
XThought is a program which randomly generates sayings. These sayings
Xcan at times be trite, are often funny, and occasionally seem profound.
XThought is configurable and can produce a wide variety of sayings, with a
Xlittle work.
X
XINSTALLING THOUGHT
X
X1 - Edit "Makefile" to your liking. This involves picking installation
X directories and so on. The grammar file "thought.rc" goes into the
X LIBDIR.
X
X2 - Type "make"
X
X3 - Type "make install"
X
X4 - Type "make install.man"
X
XAnd you're on your way! To create your own grammar files, read the
Xman page for "thoughtfile".
X
XI have supplied two grammar files - 'thought.rc' gives generally demented
Xsayings, and 'st.rc' gives demented sayings that sound like something from
XStar Trek.
X
X--
XDavid F. Skoll (dfs@doe.carleton.ca)
SHAR_EOF
$TOUCH -am 0717153691 README &&
chmod 0600 README ||
echo "restore of README failed"
set `wc -c README`;Wc_c=$1
if test "$Wc_c" != "814"; then
echo original size 814, current size $Wc_c
fi
fi
# ============= examples ==============
if test X"$1" != X"-c" -a -f 'examples'; then
echo "File already exists: skipping 'examples'"
else
echo "x - extracting examples (Text)"
sed 's/^X//' << 'SHAR_EOF' > examples &&
XI'm not interested in his sickening door. Give me a disgusting yam that
Xshivers angrily any day.
X
XBertrand! I told you not to anger Betty's gas tank! Now you must berate her
Xto make up for your cool behaviour.
X
XMy favorite eggplants are Arthur the Dismembered and Brenda the Weird.
X
XBats, unicorns, vampires, lend me your workstations. I come to stab Trevor,
Xnot to maim him.
X
XKelly is as disgusting as an icon.
X
XTo shiver is disgusting; to exhale, stinking.
X
XI'm not interested in your cool snout. Give me a reliable dervish that kisses
Xvoraciously any day.
X
XArnold! I told you not to split Sylvie's window manager! Now you must hug
Xher to make up for your stinking behaviour.
X
XThose dismembered, leprous, weird strawberries of summer!
X
SHAR_EOF
$TOUCH -am 0704150991 examples &&
chmod 0600 examples ||
echo "restore of examples failed"
set `wc -c examples`;Wc_c=$1
if test "$Wc_c" != "745"; then
echo original size 745, current size $Wc_c
fi
fi
# ============= protos.h ==============
if test X"$1" != X"-c" -a -f 'protos.h'; then
echo "File already exists: skipping 'protos.h'"
else
echo "x - extracting protos.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > protos.h &&
X/***************************************************************/
X/* */
X/* PROTOS.H */
X/* */
X/* Function prototypes and certain default definitions. */
X/* */
X/* This file is part of THOUGHT by David F. Skoll. */
X/* */
X/* You can use THOUGHT in any way you see fit, but you must */
X/* fully document any changes you make to the software, and */
X/* must not remove this header from any of the files. */
X/* */
X/* THOUGHT is free and comes with no warranty. */
X/* */
X/* THOUGHT is copyright (C) 1991 by David F. Skoll */
X/* */
X/***************************************************************/
X
X/* Define the structure of a word */
Xtypedef struct word
X{
X struct word *next;
X char *def;
X} Word;
X
X/* Define the structure of a tag */
Xtypedef struct tag
X{
X struct tag *next;
X char *def;
X Word *wordlist;
X int numwords; /* Number of words with this tag definition */
X} Tag;
X
X/* Define the structure of a sentence */
X
Xtypedef struct sentence
X{
X struct sentence *next;
X char *def;
X} Sentence;
X
X/* ARGH! Our stupid header files don't give prototype for getenv! */
X#ifdef __STDC__
Xchar * getenv(char *);
X#else
Xchar * getenv();
X#endif
X
X#ifdef __STDC__
XTag * FindTag(char *tagname);
Xchar * FindModifier(char *mod, char *srch);
Xchar * NextWord(char **s);
Xchar * ReadToken(const char *sep, FILE *fp, char **istream);
Xchar * ResolveFilename(char *f);
Xint DefSent(FILE *fp);
Xint DefTag(FILE *fp);
Xint DefWord(Tag *tag, FILE *fp);
Xint ReadChar(FILE *fp, char **s);
Xint UnReadChar(FILE *fp, char **s, char ch);
Xint main(int argc, char **argv);
Xvoid Usage(void);
Xvoid Banner(void);
Xvoid Format(char *s, int width);
Xvoid GenerateThought(Sentence *sen);
Xvoid ReadFile (char *fname);
Xvoid WriteWord(Tag *tag, Word *w, char *mod, char **out, char upper);
X#else
XTag * FindTag();
Xchar * FindModifier();
Xchar * NextWord();
Xchar * ReadToken();
Xchar * ResolveFilename();
Xint DefSent();
Xint DefTag();
Xint DefWord();
Xint ReadChar();
Xint UnReadChar();
Xint main();
Xvoid Usage();
Xvoid Banner();
Xvoid Format();
Xvoid GenerateThought();
Xvoid ReadFile ();
Xvoid WriteWord();
X#endif
SHAR_EOF
$TOUCH -am 0704111591 protos.h &&
chmod 0600 protos.h ||
echo "restore of protos.h failed"
set `wc -c protos.h`;Wc_c=$1
if test "$Wc_c" != "2645"; then
echo original size 2645, current size $Wc_c
fi
fi
# ============= st.rc ==============
if test X"$1" != X"-c" -a -f 'st.rc'; then
echo "File already exists: skipping 'st.rc'"
else
echo "x - extracting st.rc (Text)"
sed 's/^X//' << 'SHAR_EOF' > st.rc &&
X# A star-trek like grammar file
X
X#--------------------------------------------------------------------------#
X
X# First, let's declare the parts of speech we want to use.
X
X{deftag art} # Articles - "the", "a", and so on
X{deftag adj} # Adjectives
X{deftag adv} # Adverbs
X{deftag vi;3s=!s} # Intransitive verbs with mod for 3rd person singular
X{deftag vt;3s=!s} # Transitive verbs with mod for 3rd person singular
X{deftag n;p=!s} # Nouns with mod for plural
X{deftag mname} # Male's name
X{deftag fname} # Female's name
X{deftag name} # Name (either gender)
X{deftag abn} # "Abstract" nouns.
X
X
X#--------------------------------------------------------------------------#
X
X# Now let's define a bunch of sentences
X
X{defsent These are the {n;p} of the {n} "Enterprise." Her 5-year mission --
Xto {adv} go where no {n} has gone before.}
X
X{defsent
X{Abn}, sir, should be {adj} to all.
X}
X
X{defsent
XNo {n} is {adj}.
X}
X
X{defsent
XSuperior {abn} breeds superior {abn}.
X}
X
X{defsent
XIt's hard to believe that something which is neither {adj} nor {adj}
Xcan be so {adj}. And that's what kept the {n;p} in the {n;p} all
Xthese centuries.
X}
X
X{defsent Red alert, Mr. {mname}. And {vt} the {n;p}.}
X
X{defsent Without {n;p}, {abn} cannot {vi}.}
X
X{defsent {N;p} don't talk {abn} unless they are ready to back it up with
X{abn}.}
X
X{defsent {Abn} tends to {vi}.}
X
X{defsent Even {n;p} fail to learn from {abn}; they repeat the same {n;p}.}
X
X{defsent {Abn} is {adj}, like a {n} with {n;p}, {n;p} and {abn}.}
X
X{defsent {Abn} is the essential process of all {abn}.}
X
X{defsent {Abn} is {adj}, {adj}!}
X
X{defsent {Abn} has no purpose. Or {abn}. But it may have a {n}.}
X
X{defsent {Abn} becomes {adj} after a point. {N;p} become {adj}.}
X
X{defsent {Adj}. It's not {abn} as we know it, Jim.}
X
X{defsent Set your {n;p} on stun! I don't want any {abn}.}
X
X{defsent We come on a mission of {abn}.}
X
X{defsent I believe that is not {fname}. She swapped {n;p}
Xwith {mname} when we went through the {n}.}
X
X{defsent There are {n;p} on the {adj} {n}!}
X
X{defsent {Adv}! There's no {abn} to {vt}!}
X
X#--------------------------------------------------------------------------#
X
X# Now supply some words!
X
X{n
X mind, life form, star, galaxy;p=galaxies, man;p=men, race, crisis;p=crises,
X cage, child;p=!ren, computer, crewman;p=crewmen, follower, river, current,
X myth, saint, savage, woman;p=women, computer, scientist, Vulcan, Klingon,
X Romulan, shield, sensor, photon torpedo;p=!es, phaser, shuttle,
X Tribble, channel, screen, bridge, cabin, brig, force field, tractor beam,
X trilithium crystal, warp drive, impulse engine
X}
X
X{abn
X simplicity, complexity, ability, ambition, power, danger, peace, freedom,
X prejudice, creativity, suffering, purpose, reason, emotion, violence,
X evil, time, killing, sentience, slavery, imprisonment, despair,
X exaltation, impatience, anger, hatred, love, bravado, machismo,
X disgust
X}
X
X{adj
X insoluble, superior, ultimate, hard, independent, free, self-made, stupid,
X useless, wrong, ineffective, insensitive, fluid, disloyal, alien, interesting,
X fascinating, logical, illogical, unacceptable, sentient
X}
X
X{vi
X spread, destroy, live, happen, kill, lead, exaggerate, worship, repeat,
X exaggerate, fail, learn, repeat, know, eliminate, generate, communicate
X}
X
X{vt
X worship, kill, stun, disregard, control, arm, fire, lock, secure,
X seal, beam down;s=beams down, waste, fill, destroy, stun, attack
X}
X
X{mname
X Kirk, Spock, McCoy, Worf, Picard, LaForge, Data, Scotty, Chekov
X}
X
X{fname
X Uhura, Troi, Yar, Crusher
X}
X
X{adv
X merely, forcibly, suddenly, logically, simply, philosophically,
X easily, mysteriously, boldly, carefully, directly, eagerly
X}
SHAR_EOF
$TOUCH -am 0717153491 st.rc &&
chmod 0600 st.rc ||
echo "restore of st.rc failed"
set `wc -c st.rc`;Wc_c=$1
if test "$Wc_c" != "3634"; then
echo original size 3634, current size $Wc_c
fi
fi
# ============= thought.c ==============
if test X"$1" != X"-c" -a -f 'thought.c'; then
echo "File already exists: skipping 'thought.c'"
else
echo "x - extracting thought.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > thought.c &&
X/***************************************************************/
X/* */
X/* THOUGHT.C */
X/* */
X/* This file is part of THOUGHT by David F. Skoll. */
X/* */
X/* You can use THOUGHT in any way you see fit, but you must */
X/* fully document any changes you make to the software, and */
X/* must not remove this header from any of the files. */
X/* */
X/* THOUGHT is free and comes with no warranty. */
X/* */
X/* THOUGHT is copyright (C) 1991 by David F. Skoll */
X/* */
X/***************************************************************/
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X#include <string.h>
X
X#ifdef MSDOS
X#include <stdlib.h>
X#include <dos.h>
X#include <io.h>
X#include <malloc.h>
X#else
X#include <sys/file.h>
X#include <sys/types.h>
X#ifdef SYSV
X#include <time.h>
X#else
X#include <sys/time.h>
X#endif
X#endif
X
X#include "protos.h"
X#include "version.h"
X
X/* The next two defines are to stop my editor's bracket-matching algorithm
X from complaining later on in the program. */
X
X#define CLEFT '{'
X#define CRIGHT '}'
X
X#define UPPER(c) ( ((c) >= 'a' && (c) <= 'z') ? (c) - ('a' - 'A') : (c) )
X
Xchar *SEP1="{}=;,";
Xchar *SEP2="{}=;, \n\t";
X
X/* The global data structures - a singly-linked list of tags
X and a singly-linked list of sentence definitions. */
X
XTag *TagList = NULL;
Xint NumTags = 0;
X
XSentence *SentenceList = NULL;
Xint NumSentences = 0;
X
Xchar Buffer[1024]; /* Temp buffer - big for sentence definitions */
Xchar Mod[32]; /* Temp buffer to hold current modifier */
Xchar Token[200]; /* Another temp. buffer for various stuff */
Xchar FileName[256]; /* Resolved filename */
X/***************************************************************/
X/* */
X/* ReadChar */
X/* */
X/* Read a character from a file if fp is not null; otherwise, */
X/* read from a string. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xint ReadChar(FILE *fp, char **s)
X#else
Xint ReadChar(fp, s)
XFILE *fp;
Xchar **s;
X#endif
X{
X if (fp) return getc(fp);
X if (!(**s)) return EOF;
X else return * (*s)++;
X}
X
X/***************************************************************/
X/* */
X/* UnReadChar */
X/* */
X/* Put a character back. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xint UnReadChar(FILE *fp, char **s, char ch)
X#else
Xint UnReadChar(fp, s, ch)
XFILE *fp;
Xchar **s;
Xchar ch;
X#endif
X{
X if (fp) return ungetc(ch, fp);
X if (!**s) return EOF;
X else *(--(*s)) = ch;
X return ch;
X}
X
X/***************************************************************/
X/* */
X/* ReadToken */
X/* */
X/* Read a token from the specified input stream, with leading */
X/* and trailing whitespace stripped. Tokens are separated by */
X/* any of the characters in 'sep'. Tokens are stored in a */
X/* static area and are overwritten with each call to */
X/* ReadToken. Returns the Null string (NOT NULL) if EOF */
X/* */
X/* If fp is not NULL, reads from file. Otherwise, reads from */
X/* a string, adjusting the string pointer. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xchar *ReadToken(const char *sep, FILE *fp, char **istream)
X#else
Xchar *ReadToken(sep, fp, istream)
Xchar *sep;
XFILE *fp;
Xchar **istream;
X#endif
X{
X int ch;
X char read = 0;
X char *s;
X while(1) { /* Skip comments and leading space */
X do {
X ch = ReadChar(fp, istream);
X } while (isspace (ch));
X
X if (ch == '#') {
X do {ch = ReadChar(fp, istream);} while (ch != '\n' && ch != EOF);
X } else break;
X }
X
X s = Token;
X
X while (1) {
X if (ch == EOF) {
X if (read) break;
X else {
X *Token = 0;
X return Token;
X }
X }
X if (ch == '#') {
X UnReadChar(fp, istream, ch);
X break;
X }
X if (strchr(sep, ch)) {
X if (read) {
X UnReadChar(fp, istream, ch);
X break;
X } else {
X *Token = ch;
X *(Token + 1) = 0;
X return Token;
X }
X }
X if (ch == '\n') ch = ' ';
X *s++ = ch;
X *s = 0;
X ch = ReadChar(fp, istream);
X read = 1;
X }
X
X/* Strip trailing whitespace */
X s = Token + strlen(Token) - 1;
X while (s >= Token && isspace(*s)) *s-- = 0;
X
X return Token;
X}
X
X/***************************************************************/
X/* */
X/* DefTag */
X/* */
X/* Add a tag definition */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xint DefTag(FILE *fp)
X#else
Xint DefTag(fp)
XFILE *fp;
X#endif
X{
X Tag *new;
X char *s;
X
X/* Read the tag's name */
X s = ReadToken(SEP1, fp, NULL);
X strcpy(Buffer, s);
X if (strchr (SEP1, *s)) {
X fprintf(stderr, "Illegal tag definition: %s\n", Buffer);
X exit(1);
X }
X
X/* Copy the tag name to temp. buffer */
X strcpy(Buffer, s);
X/* Parse for definitions */
X while (1) {
X s = ReadToken(SEP1, fp, NULL);
X if (*s != ';' && *s != CRIGHT) {
X fprintf(stderr, "Unknown token %s in tag definition %s.\n", s, Buffer);
X exit (1);
X }
X if (*s == CRIGHT) {
X if (FindTag(Buffer)) {
X fprintf(stderr, "Ignoring duplicate definition of tag %s\n", Buffer);
X return 1;
X }
X
X /* add it onto the list */
X new = (Tag *) malloc(sizeof(Tag));
X if (!new) {
X fprintf(stderr, "Memory allocation problem for tag %s.\n", s);
X exit(1);
X }
X new->next = TagList;
X new->wordlist = (Word *) NULL;
X new->numwords = 0;
X TagList = new;
X NumTags++;
X new->def = strdup(Buffer);
X if (! new->def) {
X fprintf(stderr, "Memory allocation problem for tag %s.\n", Buffer);
X exit(1);
X }
X return 0;
X }
X
X
X/* Must be ';' */
X strcat(Buffer, s);
X
X/* Get the modifier */
X s = ReadToken(SEP1, fp, NULL);
X strcat(Buffer, s);
X if (strchr (SEP1, *s)) {
X fprintf(stderr, "Illegal tag definition: %s\n", Buffer);
X exit(1);
X }
X
X/* Get the equals sign */
X s = ReadToken(SEP1, fp, NULL);
X strcat(Buffer, s);
X if (*s != '=') {
X fprintf(stderr, "Illegal tag definition: %s\n", Buffer);
X exit(1);
X }
X
X/* Get the definition */
X s = ReadToken(SEP1, fp, NULL);
X strcat(Buffer, s);
X if (strchr (SEP1, *s)) {
X fprintf(stderr, "Illegal tag definition: %s\n", Buffer);
X exit(1);
X }
X }
X}
X
X/***************************************************************/
X/* */
X/* FindTag - given a tag, find its definition. */
X/* Return NULL if not found, else pointer to definition. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
XTag *FindTag(char *tagname)
X#else
XTag *FindTag(tagname)
Xchar *tagname;
X#endif
X{
X char *s, *t;
X Tag *found = TagList;
X
X while (found) {
X s = tagname;
X t = found->def;
X while (*s && *t && *s != ';' && *t != ';' && UPPER(*s) == UPPER(*t)) {
X s++;
X t++;
X }
X if ((!*s && !*t) || (!*s && *t == ';')
X || (*s == ';' && !*t) || (*s == ';' && *t == ';'))
X return found;
X found = found->next;
X }
X return found;
X}
X
X/***************************************************************/
X/* */
X/* DefWord */
X/* */
X/* Define a list of words. We enter with the tag found, and */
X/* keep adding words to the tag's word list until we hit a */
X/* closing brace. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xint DefWord(Tag *tag, FILE *fp)
X#else
Xint DefWord(tag, fp)
XTag *tag;
XFILE *fp;
X#endif
X{
X char *s;
X Word *new;
X
X s = ReadToken(SEP1, fp, NULL);
X
X while(1) {
X if (strchr(SEP1, *s)) {
X fprintf(stderr, "Illegal word definition: %s\n", s);
X exit(1);
X }
X strcpy(Buffer, s);
X s = ReadToken(SEP1, fp, NULL);
X while (*s == ';') { /* Collect modifiers */
X strcat(Buffer, s);
X s = ReadToken(SEP1, fp, NULL); /* Modifier name */
X strcat(Buffer, s);
X if (strchr(SEP1, *s)) {
X fprintf(stderr, "Illegal word definition: %s\n", s);
X exit(1);
X }
X s = ReadToken(SEP1, fp, NULL); /* equals sign */
X strcat(Buffer, s);
X if (*s != '=') {
X fprintf(stderr, "Illegal word definition: %s\n", s);
X exit(1);
X }
X s = ReadToken(SEP1, fp, NULL); /* Definition */
X strcat(Buffer, s);
X if (strchr(SEP1, *s)) {
X fprintf(stderr, "Illegal word definition: %s\n", s);
X exit(1);
X }
X s = ReadToken(SEP1, fp, NULL);
X }
X if (*s != ',' && *s != CRIGHT) {
X fprintf(stderr, "Illegal word definition: %s%s\n", Buffer, s);
X exit(1);
X }
X new = (Word *) malloc (sizeof(Word));
X if (!new) {
X fprintf(stderr, "Memory allocation error for word: %s\n", Buffer);
X exit(1);
X }
X new->def = strdup(Buffer);
X if (!new->def) {
X fprintf(stderr, "Memory allocation error for word: %s\n", Buffer);
X exit(1);
X }
X new->next = tag->wordlist;
X tag->wordlist = new;
X tag->numwords++;
X if (*s == CRIGHT) return 0;
X s = ReadToken(SEP1, fp, NULL);
X }
X}
X
X/***************************************************************/
X/* */
X/* DefSent */
X/* */
X/* Add a sentence definition to the list. We just slurp all */
X/* the characters until a closing brace. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xint DefSent(FILE *fp)
X#else
Xint DefSent(fp)
XFILE *fp;
X#endif
X{
X Sentence *new;
X char ch;
X char *s;
X int nleft;
X
X s = Buffer;
X *s = 0;
X nleft = 0;
X
X do {
X ch = ReadChar(fp, NULL);
X } while (isspace(ch));
X
X while (1) {
X if (ch == EOF) {
X fprintf(stderr, "Unexpected end of file!\n");
X exit(1);
X }
X if (ch == CRIGHT && !nleft) {
X s = Buffer + strlen(Buffer)-1;
X while (s >= Buffer && isspace(*s)) *s-- = 0;
X new = (Sentence *) malloc (sizeof (Sentence));
X if (!new) {
X fprintf(stderr, "Memory allocation failure during defsent!\n");
X exit(1);
X }
X new->def = strdup(Buffer);
X if (!new->def) {
X fprintf(stderr, "Memory allocation failure during defsent!\n");
X exit(1);
X }
X NumSentences++;
X new->next = SentenceList;
X SentenceList = new;
X return 0;
X }
X if (ch == '\n') ch = ' ';
X *s++ = ch;
X *s = 0;
X if (ch == CLEFT) nleft++;
X else if (ch == CRIGHT) nleft--;
X ch = ReadChar(fp, NULL);
X }
X}
X
X/***************************************************************/
X/* */
X/* ReadFile */
X/* */
X/* Read and process the grammar file, setting up all internal */
X/* data structures. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xvoid ReadFile (char *fname)
X#else
Xvoid ReadFile (fname)
Xchar *fname;
X#endif
X{
X FILE *fp;
X char *s;
X Tag *t;
X
X fp = fopen(fname, "r");
X if (fp == NULL) {
X perror(fname);
X exit(1);
X }
X
X while(1) {
X s = ReadToken(SEP2, fp, NULL);
X if (!*s) {
X fclose(fp);
X return;
X }
X if (*s != CLEFT) {
X fprintf(stderr, "Expecting %c, found %s\n", CLEFT, s);
X fclose(fp);
X exit(1);
X }
X s = ReadToken(SEP2, fp, NULL);
X if (! stricmp(s, "deftag")) DefTag(fp);
X else if (! stricmp(s, "defsent")) DefSent(fp);
X else {
X t = FindTag(s);
X if (!t) {
X fprintf(stderr, "Unknown tag: %s\n", s);
X fclose(fp);
X exit(1);
X }
X DefWord(t, fp);
X }
X }
X}
X
X/***************************************************************/
X/* */
X/* GenerateThought */
X/* */
X/* This is where it all happens! Generate a thought for the */
X/* day and leave it in 'Buffer' */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xvoid GenerateThought(Sentence *sen)
X#else
Xvoid GenerateThought(sen)
XSentence *sen;
X#endif
X{
X char *sd = sen->def;
X char *out, *tok;
X char *mod;
X char ch;
X Tag *tag;
X Word *w;
X int i;
X char upper;
X
X out = Buffer;
X *out = 0;
X
X while(*sd) {
X ch = *sd++;
X if (ch != CLEFT) {
X *out++ = ch;
X *out = 0;
X continue;
X }
X tok = ReadToken(SEP1, NULL, &sd);
X if (*tok >= 'A' && *tok <='Z') upper = 1; else upper = 0;
X tag = FindTag(tok);
X if (!tag) {
X fprintf(stderr, "Unknown tag %s in sentence definition\n%s\n", tok, sen->def);
X exit(1);
X }
X tok = ReadToken(SEP1, NULL, &sd);
X if (*tok != ';' && *tok != CRIGHT) {
X fprintf(stderr, "Illegal tag definition in %s\n", sen->def);
X exit(1);
X }
X if (*tok == ';') {
X tok = ReadToken(SEP1, NULL, &sd);
X strcpy(Mod, tok);
X mod = Mod;
X tok = ReadToken(SEP1, NULL, &sd);
X if (*tok != CRIGHT) {
X fprintf(stderr, "Illegal tag definition in %s\n", sen->def);
X exit(1);
X }
X } else mod = (char *) NULL;
X
X/* We've got the tag and the modifier - now pick a random word */
X if (!tag->numwords) {
X fprintf(stderr, "Tag %s has no words defined.\n", tag->def);
X exit(1);
X }
X i = rand() % tag->numwords;
X
X/* Find the actual word - this is HIGHLY INEFFICIENT!! */
X w = tag->wordlist;
X while (i && w) {
X w = w->next;
X i--;
X }
X
X if (!w) {
X fprintf(stderr, "Internal error! numwords for tag %s is too high!!!\n", tag->def);
X exit(1);
X }
X
X/* We've got a word - emit it */
X WriteWord(tag, w, mod, &out, upper);
X }
X}
X/***************************************************************/
X/* */
X/* WriteWord - Write a word, applying any modifiers. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xvoid WriteWord(Tag *tag, Word *w, char *mod, char **out, char upper)
X#else
Xvoid WriteWord(tag, w, mod, out, upper)
XTag *tag;
XWord *w;
Xchar *mod;
Xchar **out;
Xchar upper;
X#endif
X{
X char *s;
X char *OrigOut = *out;
X char *ModDef;
X
X if (!mod) { /* easy case first - no modifiers */
X s = w->def;
X while (*s && *s != ';') {
X *(*out)++ = *s++;
X }
X **out = 0;
X if (upper) *OrigOut = UPPER(*OrigOut);
X return;
X }
X
X/* Grrr - Search for a modifier. Search word description first; then search
X tag description. */
X ModDef = FindModifier(mod, w->def);
X if (!ModDef) ModDef = FindModifier(mod, tag->def);
X if (!ModDef) {
X fprintf(stderr, "Could not find modifier %s for word %s\n", mod, w->def);
X exit(1);
X }
X
X/* Write out the modified word */
X while (*ModDef && *ModDef != ';') {
X if (*ModDef != '!') {
X *(*out)++ = *ModDef++;
X **out = 0;
X } else {
X ModDef++;
X s = w->def;
X while (*s && *s != ';') *(*out)++ = *s++;
X **out = 0;
X }
X }
X if (upper) *OrigOut = UPPER(*OrigOut);
X}
X
X/***************************************************************/
X/* */
X/* FindModifier - find a modifier definition. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xchar *FindModifier(char *mod, char *srch)
X#else
Xchar *FindModifier(mod, srch)
Xchar *mod, *srch;
X#endif
X{
X /* Assumes the syntax is CORRECT and CHECKED already! */
X char *m;
X
X /* Skip to the modifier section - go past the first semicolon. */
X while (*srch && *srch != ';') srch++;
X while (*srch) {
X srch++; /* We're on the preceding semicolon */
X m = mod;
X while (*m && *srch && UPPER(*m) == UPPER(*srch)) {m++; srch++;}
X if (!*m && *srch == '=') return srch+1;
X
X /* Failed. Skip to semicolon */
X while (*srch && *srch != ';') srch++;
X }
X return NULL;
X}
X
X/***************************************************************/
X/* */
X/* Format - output a string formatted for the terminal. */
X/* */
X/* You can specify the terminal width (min. 10). */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xvoid Format(char *s, int width)
X#else
Xvoid Format(s, width)
Xchar *s;
Xint width;
X#endif
X{
X int pos;
X int len;
X char *wd;
X
X pos = 0;
X while (*s) {
X wd = NextWord(&s); /* With leading spaces, not with trailing spaces */
X len = strlen(wd);
X if (pos + len > width-2) {
X putchar('\n');
X while (isspace(*wd)) wd++;
X pos = strlen(wd);
X printf("%s", wd);
X } else {
X pos += len;
X printf("%s", wd);
X }
X }
X putchar('\n');
X}
X
X/***************************************************************/
X/* */
X/* NextWord - return the next word in the buffer. Also */
X/* handle conversions between "a" and "an" */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xchar *NextWord(char **s)
X#else
Xchar *NextWord(s)
Xchar **s;
X#endif
X{
X char *dest=Token; /* Output goes here. */
X char *realword;
X char *t;
X while (isspace(**s)) *dest++ = *(*s)++; /* Copy leading spaces */
X
X realword = dest; /* Start of the real word */
X if (**s == '-' || **s == '+') (*s)++; /* Skip any "a/an" thing */
X while (**s && !isspace(**s)) *dest++ = *(*s)++; /* Copy word */
X *dest = 0;
X
X if (stricmp(realword, "a")) return Token; /* Exit if not "a" */
X
X /* Look for start of next word */
X t = *s;
X while (isspace(*t)) t++;
X if (strchr("aeiouAEIOU+", *t)) {
X *dest++ = 'n';
X *dest = 0;
X }
X return Token;
X}
X
X/***************************************************************/
X/* */
X/* ResolveFilename - search for the file */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xchar *ResolveFilename(char *f)
X#else
Xchar *ResolveFilename(f)
Xchar *f;
X#endif
X{
X char *home;
X
X /* If an absolute path is given, do nothing. */
X if (*f == '/') return f;
X
X /* If it's in the current dir, do nothing. */
X if (!access(f, R_OK)) return f;
X
X /* Check if it's in the home directory */
X home = getenv("HOME");
X if (home) {
X strcpy(FileName, home);
X strcat(FileName, "/");
X strcat(FileName, f);
X if (!access(FileName, R_OK)) return FileName;
X }
X
X /* Check in the library directory */
X strcpy(FileName, LIBPATH);
X strcat(FileName, "/");
X strcat(FileName, f);
X if (!access(FileName, R_OK)) return FileName;
X
X /* Couldn't resolve it - die. */
X return f;
X}
X
X/***************************************************************/
X/* */
X/* Banner - print the program banner. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xvoid Banner(void)
X#else
Xvoid Banner()
X#endif
X{
X fprintf(stderr, "\nThought version %s (PL %s)\nby David F. Skoll\n\n",
X VERSION, PATCHLEVEL);
X}
X
X/***************************************************************/
X/* */
X/* Usage - display program usage. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xvoid Usage(void)
X#else
Xvoid Usage()
X#endif
X{
X Banner();
X fprintf(stderr, "Usage: thought [-dvi] [-w#] [filename]\n\n");
X fprintf(stderr, "Options: -d = Debug sentence definitions.\n");
X fprintf(stderr, " -v = Verbose mode.\n");
X fprintf(stderr, " -i = Interactive mode.\n");
X fprintf(stderr, " -w# = set formatted output width to # columns.\n\n");
X fprintf(stderr, "filename is optional grammar file. Default file is\n");
X fprintf(stderr, "'%s'.\n\n", FILE_DEFAULT);
X fprintf(stderr, "In interactive mode, enter 'q' to quit.\n\n");
X}
X
X/***************************************************************/
X/* */
X/* SystemTime */
X/* */
X/* Returns current system time in seconds past midnight. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xlong SystemTime(void)
X#else
Xlong SystemTime()
X#endif
X{
X#ifndef MSDOS
X time_t tloc;
X struct tm *t;
X
X (void) time(&tloc);
X t = localtime(&tloc);
X return (long) t->tm_hour * 3600L + (long) t->tm_min * 60L + (long) t->tm_sec;
X
X#else
X struct dostime_t tloc;
X _dos_gettime(&tloc);
X return (long) tloc.hour * 3600L + (long) tloc.minute * 60L + (long) tloc.second;
X#endif
X}
X
X/***************************************************************/
X/* */
X/* MAIN - Main program. */
X/* */
X/***************************************************************/
X#ifdef __STDC__
Xint main (int argc, char **argv)
X#else
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X#endif
X{
X char *filename=FILE_DEFAULT;
X char *curarg;
X char Verbose = 0;
X char Debug = 0;
X char Interactive = 0;
X int Width = 80;
X Sentence *sent;
X struct timeval tv;
X int i;
X
X while (--argc) {
X argv++;
X curarg = *argv;
X if (*curarg == '-') {
X while (*++curarg) {
X switch(*curarg) {
X case 'v': Verbose = 1; break;
X case 'd': Debug = 1; break;
X case 'i': Interactive = 1; break;
X case 'w': Width = atoi(curarg+1);
X while (*(curarg+1)) curarg++;
X break;
X default: Usage(); exit(1);
X }
X }
X } else filename = curarg;
X }
X if (Verbose) Banner();
X if (Width < 10) {
X fprintf(stderr, "Minimum terminal width is 10.\n");
X exit(1);
X }
X filename = ResolveFilename(filename);
X if (access(filename, R_OK)) {
X perror(filename);
X exit(1);
X }
X if (Verbose) fprintf(stderr, "[Using '%s' as grammar file.]\n\n", filename);
X ReadFile(filename);
X if (!NumSentences) {
X fprintf(stderr, "No sentence definitions found!\n");
X exit(1);
X }
X/* initialize the random seed */
X srand( (int) SystemTime());
X for (i=0; i<5; i++) (void) rand();
X
X/* If it's DEBUG, loop through all sentence definitions */
X if (Debug) {
X if (Verbose) fprintf(stderr, "Checking sentence definitions...\n");
X sent = SentenceList;
X while(sent) {
X GenerateThought(sent);
X Format(Buffer, Width);
X putchar('\n');
X sent = sent->next;
X }
X fprintf(stderr, "All sentence definitions appear to be OK.\n");
X exit(0);
X }
X
X/* Check that stdin, stdout is a tty if interactive mode is set */
X if (Interactive) {
X if (!isatty(0) || !isatty(1)) {
X fprintf(stderr, "For interactive mode, stdin and stdout must be a tty.\n");
X exit(1);
X }
X }
X
X while(1) {
X i = rand() % NumSentences;
X sent = SentenceList;
X
X while (i && sent) {
X sent = sent->next;
X i--;
X }
X
X if (!sent) {
X fprintf(stderr, "Internal error! NumSentences is too high!\n");
X exit(1);
X }
X GenerateThought(sent);
X Format(Buffer, Width);
X if (!Interactive) exit(0);
X gets(Buffer);
X if (*Buffer == 'q' || *Buffer == 'Q') exit(0);
X }
X
X}
SHAR_EOF
$TOUCH -am 0717120791 thought.c &&
chmod 0600 thought.c ||
echo "restore of thought.c failed"
set `wc -c thought.c`;Wc_c=$1
if test "$Wc_c" != "26519"; then
echo original size 26519, current size $Wc_c
fi
fi
# ============= thought.man ==============
if test X"$1" != X"-c" -a -f 'thought.man'; then
echo "File already exists: skipping 'thought.man'"
else
echo "x - extracting thought.man (Text)"
sed 's/^X//' << 'SHAR_EOF' > thought.man &&
X.TH THOUGHT 1 "4 July 1991"
X.UC 4
X.SH NAME
Xthought \- a program to generate random (and demented) thoughts-for-today
X.SH SYNOPSIS
X.B thought
X[\fB\-dvi\fP] [\fB\-w\fP\fIn\fP] [\fIfilename\fP]
X.SH DESCRIPTION
X.B Thought
Xreads the specified \fIfilename\fP, which must contain a grammar specification,
Xand generates random thoughts. The \fIfilename\fP defaults to \fBthought.rc\fP
Xif one is not supplied. See the man page for \fBthoughtfile\fP(5) for
Xinformation on the format of grammar files.
X.PP
X\fBThought\fP will look for the grammar file first in the current directory;
Xnext in your home directory, and finally in a central location determined
Xby the person who built \fBthought\fP.
X.SH OPTIONS
X.TP
X.B \-d
XThe \fB\-d\fP flag causes \fBthought\fP to scan through all sentence
Xdefinitions in the grammar file to check that they are specified correctly.
XA thought-of-the-day for each type of sentence is displayed. For this
Xreason, if you only want to check for errors, you may wish to pipe
Xstandard output to /dev/null.
XThis flag should only be of interest if you are creating grammar files.
X.TP
X.B \-i
XThe \fB\-i\fP flag causes \fBthought\fP to go into an interactive mode.
XAfter each thought has been displayed, it waits for you to press return.
XIt will keep displaying thoughts until you hit 'q' or 'Q' and press return.
X.TP
X.B \-v
XThe \fB\-v\fP causes \fBthought\fP to be slightly more verbose.
X.TP
X.B \-w
XThe \fB\-w\fP\fIn\fP option causes the output to be formatted for a terminal
Xwith \fIn\fP columns.
X.SH AUTHOR
XDavid F. Skoll (dfs@doe.carleton.ca)
X.SH BUGS
X\fBThought\fP reads the entire grammar file into memory. This consumes lots
Xof space, and is wasteful if you only want to issue one thought for the day.
X.PP
X\fBThought\fR is quite inefficient as far as speed goes.
X.PP
XLots of silly restrictions about lengths of words, sentences, and so on.
X.SH SEE ALSO
X\fBthoughtfile\fP(5)
SHAR_EOF
$TOUCH -am 0704142291 thought.man &&
chmod 0600 thought.man ||
echo "restore of thought.man failed"
set `wc -c thought.man`;Wc_c=$1
if test "$Wc_c" != "1895"; then
echo original size 1895, current size $Wc_c
fi
fi
echo "End of part 1, continue with part 2"
exit 0
exit 0 # Just in case...