home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume6 / sonnet / part01 next >
Internet Message Format  |  1989-02-13  |  37KB

  1. Path: uunet!tektronix!tekgen!tekred!games
  2. From: games@tekred.CNA.TEK.COM
  3. Newsgroups: comp.sources.games
  4. Subject: v06i004:  sonnet - a program to compose poetry, Part01/02
  5. Message-ID: <3608@tekred.CNA.TEK.COM>
  6. Date: 13 Feb 89 20:25:41 GMT
  7. Sender: billr@tekred.CNA.TEK.COM
  8. Lines: 1385
  9. Approved: billr@saab.CNA.TEK.COM
  10.  
  11. Submitted by: Rich Salz <rsalz@pineapple.bbn.com>
  12. Comp.sources.games: Volume 6, Issue 4
  13. Archive-name: sonnet/Part01
  14.  
  15. [From the author...  -br]
  16. [[Chris Wilbur wrote this a few years ago.  I recently resurrected the code
  17. and completely overhauled it with Chris's input.  If you understand the
  18. algorithm, you can change it to write your favorite form of poetry with a
  19. bit of work.  I generalized much of the code, but anything other than
  20. iambic pentameter sonnets will still take a bit of doing.
  21.  
  22. By default, the Makefile is set up to compile on a fairly modern Unix
  23. system.  It uses getopt and strchr/strrchr.  If you need getopt, or use
  24. index/rindex, you'll have to edit the Makefile.  It also uses curses,
  25. which is found in the "terminfo" library on some systems.  The program
  26. doesn't use any fancy curses functions, so at most you should just need
  27. to edit the Makefile.
  28.  
  29. If you find any bugs, send them to us.  If you add more than, say, 50
  30. words to the database, send them to us, too.
  31.     No funk effete plebian France of stun
  32.     Obscure avoirdupois no Job petite
  33.     Hysterical success impromptu sun
  34.     Recessive friends the stun environ heat
  35.  
  36.     Pronto the pile without beplastered food
  37.     Mouthpiece ambitious midrange kernel sponge
  38.     Computer jaundiced brushoff fire collude
  39.     Machismo epitaph excessive plunge
  40.  
  41.     Romance robotic twilight zone and chirp
  42.     Appeal with huge reversion memo fruit
  43.     Abhorred cantata foreign frowzy twerp
  44.     Intrinsic brilliance jimson footwork cute
  45.  
  46.     Incestuous exemplify of dull
  47.     Immense ambitious products hideous null
  48.  
  49.     /rich $alz                Chris Wilbur
  50.     <rsalz@bbn.com>                <chw@mirror.tmc.com>
  51.     <rsalz@uunet.uu.net>
  52. ]]
  53.  
  54. #! /bin/sh
  55. # This is a shell archive.  Remove anything before this line, then unpack
  56. # it by saving it into a file and typing "sh file".  To overwrite existing
  57. # files, type "sh file -c".  You can also feed this as standard input via
  58. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  59. # will see the following message at the end:
  60. #        "End of archive 1 (of 2)."
  61. # Contents:  MANIFEST Makefile README compose.c getopt.c makelex.c
  62. #   patchlog.h sonnet.6 sonnet.c sonnet.h
  63. # Wrapped by rsalz@fig.bbn.com on Wed Feb  8 16:34:52 1989
  64. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  65. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  66.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  67. else
  68. echo shar: Extracting \"'MANIFEST'\" \(695 characters\)
  69. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  70. X   File Name        Archive #    Description
  71. X-----------------------------------------------------------
  72. X MANIFEST                   1    This shipping list
  73. X Makefile                   1    Compilation instructions for make(1)
  74. X README                     1    Introduction
  75. X compose.c                  1    The main poetry-writing routines
  76. X getopt.c                   1    Getopt routine, if you need it
  77. X lex.data                   2    Dictionary
  78. X makelex.c                  1    Convert the dictionary to C code
  79. X patchlog.h                 1    Mistake recorder
  80. X sonnet.6                   1    Manual page
  81. X sonnet.c                   1    Curses-based driver for compose
  82. X sonnet.h                   1    Constants used by this package
  83. END_OF_FILE
  84. if test 695 -ne `wc -c <'MANIFEST'`; then
  85.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  86. fi
  87. # end of 'MANIFEST'
  88. fi
  89. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  90.   echo shar: Will not clobber existing file \"'Makefile'\"
  91. else
  92. echo shar: Extracting \"'Makefile'\" \(1456 characters\)
  93. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  94. X##
  95. X##  Makefile for sonnet.
  96. X##  $Header: Makefile,v 2.0 89/02/08 16:29:38 rsalz Release1 $
  97. X##
  98. X
  99. X##  Some systems have strchr/strrchr, some have index/rindex.
  100. X##  If you're the latter, then uncomment the next line.
  101. X#DEFS    = -DUSE_INDEX
  102. X
  103. X##  If getopt isn't in your C library, and you can't add it, uncomment
  104. X##  these two lines.
  105. X#GET_c    = getopt.c
  106. X#GET_o    = getopt.o
  107. X
  108. X##  On some systems, curses is just part of terminfo or termlib.
  109. X#LIBS    = -lterminfo
  110. XLIBS    = -lcurses -ltermcap
  111. X
  112. X##  If you don't want to check the code against the library use for lint,
  113. X##  edit this line
  114. XLLIBS    = $(LIBS)
  115. X
  116. X##  If you add to the database, put the words here.
  117. X#LEXERS    = lex.data lex.bbn
  118. XLEXERS    = lex.data
  119. X
  120. X##
  121. X##  END OF CONFIG SECTION
  122. X##
  123. X
  124. XCFLAGS    = -g $(DEFS)
  125. X
  126. XSOURCES    = sonnet.c compose.c $(GET_c)
  127. XOBJECTS    = sonnet.o compose.o $(GET_o)
  128. X
  129. Xall:        sonnet sonnet.6
  130. X
  131. Xinstall:    all
  132. X    @echo Install according to local convention
  133. X
  134. Xclean:
  135. X    rm -f foo core tags a.out lint lints lintm
  136. X    rm -f sonnet lex.c makelex $(OBJECTS)
  137. X
  138. Xshar:
  139. X    makekit -m -nSHAR
  140. X    @rm -f MANIFEST.BAK
  141. X##
  142. Xlint:        lints lintm
  143. Xlints:        sonnet
  144. X    lint -a -b -h $(DEFS) $(SOURCES) $(LLIBS) >lints
  145. Xlintm:        makelex
  146. X    lint -a -b -h $(DEFS) makelex.c >lintm
  147. X
  148. X##
  149. Xsonnet:        $(OBJECTS)
  150. X    @rm -f sonnet
  151. X    $(CC) $(CFLAGS) -o sonnet $(OBJECTS) $(LIBS)
  152. X
  153. Xmakelex:    makelex.c sonnet.h
  154. X    @rm -f makelex
  155. X    $(CC) $(CFLAGS) -o makelex makelex.c
  156. X
  157. X##
  158. X$(OBJECTS):        sonnet.h
  159. Xcompose.o:        lex.c
  160. Xlex.c:            lex.data makelex 
  161. X    @rm -f lex.c
  162. X    ./makelex $(LEXERS) >lex.c
  163. END_OF_FILE
  164. if test 1456 -ne `wc -c <'Makefile'`; then
  165.     echo shar: \"'Makefile'\" unpacked with wrong size!
  166. fi
  167. # end of 'Makefile'
  168. fi
  169. if test -f 'README' -a "${1}" != "-c" ; then 
  170.   echo shar: Will not clobber existing file \"'README'\"
  171. else
  172. echo shar: Extracting \"'README'\" \(2770 characters\)
  173. sed "s/^X//" >'README' <<'END_OF_FILE'
  174. X
  175. XSONNET INTRODUCTION
  176. X-------------------
  177. X
  178. XChris Wilbur wrote this a few years ago.  I recently resurrected the code
  179. Xand completely overhauled it with Chris's input.  If you understand the
  180. Xalgorithm, you can change it to write your favorite form of poetry with a
  181. Xbit of work.  I generalized much of the code, but anything other than
  182. Xiambic pentameter sonnets will still take a bit of doing.
  183. X
  184. XBy default, the Makefile is set up to compile on a fairly modern Unix
  185. Xsystem.  It uses getopt and strchr/strrchr.  If you need getopt, or use
  186. Xindex/rindex, you'll have to edit the Makefile.  It also uses curses,
  187. Xwhich is found in the "terminfo" library on some systems.  The program
  188. Xdoesn't use any fancy curses functions, so at most you should just need
  189. Xto edit the Makefile.
  190. X
  191. XThe database used by the program is in the lex.data file, which is then
  192. Xconverted into a C array by the utility program makelex.  "It's easy and
  193. Xfun to add new words to the vocabulary."  (Those are Chris's words; I
  194. Xdon't think it's very easy, and it's certainly not fun.)
  195. X
  196. XThe lex.data file consist of four colon-separated fields:
  197. X    word  :  foot_type  :  vowel_sound  :  consonant_type
  198. X
  199. XThe word is (obviously) the word itself.
  200. X
  201. XThe foot_type is the metrical pattern of the word; it represents the
  202. Xword's rhythm.  The legal values are the #define's in "sonnet.h" that
  203. Xstart with FT_.  You learn the meanings of the values quickly as you add
  204. Xwords; until you do, it's easiest to find a word with the same rhythm as
  205. Xthe one you're adding.  For example, if you add "inflammatory" you would
  206. Xscan the list and see that "administration" has the pattern, so you'd use
  207. XIIFF.  If you use the wrong pattern you'll end up with lines that don't
  208. Xscan, so be careful.
  209. X
  210. XThe vowel_sound and the consonant_type fields determine the actual
  211. Xrhymes.  The vowel sound is always a constant and are the #define's that
  212. Xbegin with VS_.  For example VS_LI is a long "i" as in "mice" while VS_SI
  213. Xis a short "i" as in "fish."  For more information, see the header file.
  214. X
  215. XThe consonant_type field is either a single lower-case letter ("t" for
  216. Xwords like "cat" "bat" and "rat") or a #define'd constant for a compound
  217. Xconsonant (ST for words like "best" "pest" and "undressed").  You can add
  218. Xyour own values to the consonant_type field, but make sure you don't use
  219. Xany of the lower-case letters or you'll get bogus rhymes.
  220. X
  221. XWhen adding a word, check to make sure that there a couple of words with
  222. Xsimilar rhymes, and and other entries if there don't seem to be many.
  223. X
  224. XIf you find any bugs, send them to us.  If you add more than, say, 50
  225. Xwords to the database, send them to us, too.
  226. X    /rich $alz                Chris Wilbur
  227. X    <rsalz@bbn.com>                <chw@mirror.tmc.com>
  228. X    <rsalz@uunet.uu.net>
  229. X
  230. X$Header: README,v 2.0 89/02/08 16:29:45 rsalz Release1 $
  231. END_OF_FILE
  232. if test 2770 -ne `wc -c <'README'`; then
  233.     echo shar: \"'README'\" unpacked with wrong size!
  234. fi
  235. # end of 'README'
  236. fi
  237. if test -f 'compose.c' -a "${1}" != "-c" ; then 
  238.   echo shar: Will not clobber existing file \"'compose.c'\"
  239. else
  240. echo shar: Extracting \"'compose.c'\" \(8502 characters\)
  241. sed "s/^X//" >'compose.c' <<'END_OF_FILE'
  242. X/*
  243. X**  COMPOSE
  244. X**  A routine to write some poetry.
  245. X*/
  246. X#include "sonnet.h"
  247. X#include <sys/types.h>
  248. X#ifndef    lint
  249. Xstatic char RCS[] =
  250. X    "$Header: compose.c,v 2.0 89/02/08 16:29:51 rsalz Release1 $";
  251. X#endif    /* lint */
  252. X
  253. X/*
  254. X**  Load the database.  The list has a dummy entry at the end, hence
  255. X**  the non-standard "-1" in NWORDS.
  256. X*/
  257. X#include "lex.c"
  258. X#define NWORDS        (sizeof Words / sizeof Words[0] - 1)
  259. X
  260. X
  261. X/*
  262. X**  A couple of magic percentages.  Feel free to tweak them.
  263. X*/
  264. X#define PAD_FACTOR    32        /* For adding a pad word    */
  265. X#define REV_FACTOR    3        /* For reversing first foot    */
  266. X
  267. X
  268. X/*
  269. X**  Generate a random number between 0 and n-1.  This is stolen from
  270. X**  hack, markov3, etc., etc., and should be portable.  If you change it,
  271. X**  make sure to read your manual pages carefully, and note that the bottom
  272. X**  bits are usually not very random.
  273. X*/
  274. X#define ROLL(n)        ((rand() >> 3) % (n))
  275. X
  276. X
  277. X/*
  278. X**  Externally-available variables.
  279. X*/
  280. XLINETYPE    *Lines;            /* The poem            */
  281. Xint         Lcount;        /* Number of lines/poem        */
  282. Xint         NumBeats;        /* Number of beats/line        */
  283. X
  284. X
  285. X/*
  286. X**  Magic data structures.
  287. X*/
  288. Xstatic char     hendec[] = "01010101010";
  289. Xstatic char     revdec[] = "10010101010";
  290. X
  291. Xstatic char    *OddRhythm[] = {
  292. X    "0",    "1",    "01",    "10",    "11",    "10",    "01",
  293. X    "010",    "0101",    "1010",    "01010","1010",    "101",    "10101"
  294. X};
  295. X
  296. Xstatic char    *EvenRhythm[] = {
  297. X    "0",    "01",    "01",    "10",    "11",    "10",    "01",
  298. X    "010",    "0101",    "1010",    "01010","1010",    "101",    "10101"
  299. X};
  300. X
  301. X
  302. X
  303. X/*
  304. X**  Return TRUE if the letter is a vowel.
  305. X*/
  306. Xstatic int
  307. XIsVowel(c)
  308. X    char     c;
  309. X{
  310. X    switch (c) {
  311. X    case 'a': case 'e': case 'i': case 'o': case 'u':
  312. X    case 'A': case 'E': case 'I': case 'O': case 'U':
  313. X    return TRUE;
  314. X    }
  315. X    return FALSE;
  316. X}
  317. X
  318. X
  319. X/*
  320. X**  Return a small "pad" word.
  321. X*/
  322. Xstatic char *
  323. XGetPad(word)
  324. X    char        *word;
  325. X{
  326. X    register int     f;
  327. X    
  328. X    f = ROLL(100);
  329. X
  330. X    if (f > 94)
  331. X    return "of";
  332. X    if (f > 83)
  333. X    return "and";
  334. X    if (f > 75)
  335. X    return IsVowel(*word) ? "an" : "a";
  336. X    if (f > 54)
  337. X    return "no";
  338. X    if (f > 53)
  339. X    return "to";
  340. X    if (f > 50)
  341. X    return "with";
  342. X    if (f > 45)
  343. X    return IsVowel(*word) ? "in an" : "in a";
  344. X    if (f > 44)
  345. X    return IsVowel(*word) ? "for an" : "for a";
  346. X    if (f > 43)
  347. X    return IsVowel(*word) ? "by an" : "by a";
  348. X    if (f > 42)
  349. X    return IsVowel(*word) ? "to an" : "to a";
  350. X    if (f > 41)
  351. X    return IsVowel(*word) ? "with an" : "with a";
  352. X    if (f > 40)
  353. X    return "they";
  354. X    if (f > 38)
  355. X    return "for";
  356. X    if (f > 37)
  357. X    return "we";
  358. X    if (f > 36)
  359. X    return "O";
  360. X    if (f > 35)
  361. X    return "but";
  362. X    if (f > 34)
  363. X    return "thou";
  364. X    return "the";
  365. X}
  366. X
  367. X
  368. X/*
  369. X**  Return TRUE if string s ends with substring t.  Not robuts, but
  370. X**  that's okay.
  371. X*/
  372. Xstatic int
  373. XEndsWith(s, t)
  374. X    char    *s;
  375. X    char    *t;
  376. X{
  377. X    return EQ(&s[strlen(s)] - strlen(t), t);
  378. X}
  379. X
  380. X
  381. X/*
  382. X**  Returns TRUE if ending with word would produce a perfect rhyme.
  383. X*/
  384. Xstatic int
  385. XIsPerfectRhyme(L, word)
  386. X    LINETYPE    *L;
  387. X    char    *word;
  388. X{
  389. X    return L->Line != L->Rhyme && EndsWith(Lines[L->Rhyme].Text, word);
  390. X}
  391. X
  392. X
  393. X/*
  394. X**  Apend a word to the end of a line.
  395. X*/
  396. Xstatic void
  397. XAppend(L, word)
  398. X    LINETYPE    *L;
  399. X    char    *word;
  400. X{
  401. X    if (L->Text[0])
  402. X    (void)strcat(L->Text, " ");
  403. X    (void)strcat(L->Text, word);
  404. X}
  405. X
  406. X
  407. X/*
  408. X**  Get a word that meets our criteria.
  409. X*/
  410. Xstatic WORDTYPE *
  411. XGetWord(L, i, RevOK, exact, syllables, pad)
  412. X    register LINETYPE    *L;
  413. X    register int     i;
  414. X    int             RevOK;
  415. X    int             exact;
  416. X    int            *syllables;
  417. X    int            *pad;
  418. X{
  419. X    register WORDTYPE    *W;
  420. X    register int     timeleft;
  421. X    register int     n;
  422. X    char        **RTable;
  423. X    char        *Template;
  424. X    char        *Rhythm;
  425. X    int             len;
  426. X    int             PadOK;
  427. X
  428. X    /* Clear the used bit, do some other setup. */
  429. X    for (W = Words; W < &Words[NWORDS]; W++)
  430. X    W->Used = FALSE;
  431. X    PadOK = ROLL(100) < PAD_FACTOR;
  432. X    RTable = i & 1 ? OddRhythm : EvenRhythm;
  433. X
  434. X    /* Search through all the words if we need to. */
  435. X    for (timeleft = NWORDS; --timeleft >= 0; ) {
  436. X    /* Find a word we haven't used. */
  437. X    while (Words[n = ROLL(NWORDS)].Used)
  438. X        ;
  439. X    W = &Words[n];
  440. X    W->Used = TRUE;
  441. X
  442. X    /* Allow reversed foot if it is not a dactyl. */
  443. X    Template = RevOK && W->Foot != FT_DF ? revdec : hendec;
  444. X    len = strlen(RTable[W->Foot]);
  445. X
  446. X    if (EQn(&Template[i], RTable[W->Foot], len)) {
  447. X        *pad = RTable == EvenRhythm && W->Foot == FT_HF;
  448. X        *syllables = len;
  449. X        if (*pad == FALSE || PadOK) {
  450. X        if (i + len < NumBeats)
  451. X            /* This isn't the last word, so don't check the rhyme. */
  452. X            return W;
  453. X
  454. X        /* Filter out feminine rhymes if at end of stanza. */
  455. X        Rhythm = RTable[W->Foot];
  456. X        if (((L->Active % 2) == 0 || L->Active == 13)
  457. X         && Rhythm[strlen(Rhythm) - 1] == '0')
  458. X            continue;
  459. X
  460. X        if (L->vowel == '\0' || L->cons == '\0') {
  461. X            L->vowel = W->vowel;
  462. X            L->cons = W->cons;
  463. X        }
  464. X        if (L->vowel == W->vowel
  465. X         && (!exact || L->cons == W->cons)
  466. X         && !IsPerfectRhyme(L, W->Text))
  467. X            return W;
  468. X        }
  469. X    }
  470. X    }
  471. X    return NULL;
  472. X}
  473. X
  474. X
  475. X
  476. X/*
  477. X**  Compose a line of poetry.
  478. X*/
  479. XComposeLine(L)
  480. X    register LINETYPE    *L;
  481. X{
  482. X    register WORDTYPE    *W;
  483. X    register LINETYPE    *Rhymer;
  484. X    int             RevOK;
  485. X    int             exact;
  486. X    int             i;
  487. X    int             pad;
  488. X    int             syllables;
  489. X
  490. X    if (L->Marked)
  491. X    /* User doesn't want this line touched. */
  492. X    return;
  493. X    if (L->Rhyme < 0) {
  494. X    /* A blank filler line. */
  495. X    L->Text[0] = '\0';
  496. X    return;
  497. X    }
  498. X
  499. X    /* Zap the text. */
  500. X    L->Text[0] = '\0';
  501. X
  502. X    /* Coordinate rhymes. */
  503. X    if (L->Rhyme == L->Line) {
  504. X    /* If the second line with this rhyme has been saved, make the first
  505. X     * one agree with it. */
  506. X    for (Rhymer = L + 1; Rhymer < &Lines[Lcount]; Rhymer++)
  507. X        if (Rhymer->Rhyme == L->Rhyme)
  508. X        break;
  509. X    if (Rhymer < &Lines[Lcount] && Rhymer->Marked) {
  510. X        L->vowel = Rhymer->vowel;
  511. X        L->cons = Rhymer->cons;
  512. X    }
  513. X    else {
  514. X        L->vowel = 0;
  515. X        L->cons = 0;
  516. X    }
  517. X    }
  518. X    else {
  519. X    L->vowel = Lines[L->Rhyme].vowel;
  520. X    L->cons = Lines[L->Rhyme].cons;
  521. X    }
  522. X
  523. X    /* Get enough syllables, try for exact match for time through. */
  524. X    for (exact = TRUE, i = 0; i < NumBeats; ) {
  525. X    pad = 0;
  526. X    RevOK = i == 0
  527. X        && ROLL(100) < REV_FACTOR * ((L->Active - 1) % 4 == 0 ? 3 : 1);
  528. X    if (W = GetWord(L, i, RevOK, exact, &syllables, &pad)) {
  529. X        if (pad)
  530. X        Append(L, GetPad(W->Text));
  531. X        Append(L, W->Text);
  532. X        i += syllables;
  533. X    }
  534. X    else {
  535. X        /* Couldn't find anything, try again. */
  536. X        i = 0;
  537. X        exact = FALSE;
  538. X        L->Text[0] = '\0';
  539. X    }
  540. X    }
  541. X
  542. X    /* Make line start with a capital letter. */
  543. X    if (islower(L->Text[0]))
  544. X    L->Text[0] = toupper(L->Text[0]);
  545. X}
  546. X
  547. X
  548. X/*
  549. X**  Set the desired rhyme scheme of a line.  These is the only time we
  550. X**  loop through the whole word list, and this routine is only called at
  551. X**  start-up, so it just doesn't seem worth keeping the list sorted and
  552. X**  using a binary search.
  553. X*/
  554. XSetRhyme(L)
  555. X    register LINETYPE    *L;
  556. X{
  557. X    register WORDTYPE    *W;
  558. X    register char    *p;
  559. X    register char    *q;
  560. X    register int     i;
  561. X
  562. X    if (L->Text[0] == '\0')
  563. X    return;
  564. X
  565. X    /* Find last word, see if it's in our list. */
  566. X    p = RDX(L->Text, ' ') + 1;
  567. X    for (W = Words, i = NWORDS; --i >= 0; W++)
  568. X    if (EQ(W->Text, p)) {
  569. X        L->vowel = W->vowel;
  570. X        L->cons = W->cons;
  571. X        return;
  572. X    }
  573. X
  574. X    /* Could be a two-word word, add in second-to-last word and search. */
  575. X    q = --p;
  576. X    *p = '\0';
  577. X    p = RDX(L->Text, ' ') + 1;
  578. X    *q = ' ';
  579. X    for (W = Words, i = NWORDS; --i >= 0; W++)
  580. X    if (EQ(W->Text, p)) {
  581. X        L->vowel = W->vowel;
  582. X        L->cons = W->cons;
  583. X        return;
  584. X    }
  585. X
  586. X    /* Can't happen, unless fed a poem that we didn't write. */
  587. X    Printf("WORD %s NOT FOUND", p);
  588. X    abort();
  589. X}
  590. X
  591. X
  592. X/*
  593. X**  Set up the rhyme pattern, seed the generator, etc.
  594. X*/
  595. XComposeInit(pattern, beats)
  596. X    register char    *pattern;
  597. X    int             beats;
  598. X{
  599. X    register LINETYPE    *L;
  600. X    register int     i;
  601. X    register int     j;
  602. X    register int     Active;
  603. X
  604. X    /* NOSTRICT "warning: long assignment may lose accuracy" */
  605. X    (void)srand((int)time((time_t *)NULL));
  606. X    if (pattern == NULL)
  607. X    pattern = "ABAB CDCD EFEF GG";
  608. X    NumBeats = beats ? beats : 10;
  609. X
  610. X    Lcount = strlen(pattern);
  611. X    /* NOSTRICT "warning: possible pointer alignment problem" */
  612. X    Lines = (LINETYPE *)malloc((unsigned int)Lcount * sizeof Lines[0]);
  613. X
  614. X    for (Active = 0, L = Lines, i = 0; i < Lcount; i++, L++) {
  615. X    L->Text[0] = '\0';
  616. X    L->Line = i;
  617. X    if (pattern[i] == ' ')
  618. X        L->Rhyme = -1;
  619. X    else
  620. X        for (L->Active = ++Active, j = 0; j < Lcount; j++)
  621. X        if (pattern[i] == pattern[j]) {
  622. X            L->Rhyme = j;
  623. X            break;
  624. X        }
  625. X    }
  626. X}
  627. X
  628. X
  629. X#ifdef    STANDALONE
  630. Xmain()
  631. X{
  632. X    register LINETYPE    *L;
  633. X    register int     i;
  634. X
  635. X    ComposeInit((char *)NULL, 0);
  636. X
  637. X    for (L = Lines, i = Lcount; --i >= 0; L++) {
  638. X    ComposeLine(L);
  639. X    Printf("%s\n", L->Text);
  640. X    }
  641. X
  642. X    exit(0);
  643. X}
  644. X#endif    /* STANDALONE */
  645. END_OF_FILE
  646. if test 8502 -ne `wc -c <'compose.c'`; then
  647.     echo shar: \"'compose.c'\" unpacked with wrong size!
  648. fi
  649. # end of 'compose.c'
  650. fi
  651. if test -f 'getopt.c' -a "${1}" != "-c" ; then 
  652.   echo shar: Will not clobber existing file \"'getopt.c'\"
  653. else
  654. echo shar: Extracting \"'getopt.c'\" \(1521 characters\)
  655. sed "s/^X//" >'getopt.c' <<'END_OF_FILE'
  656. X/*
  657. X**  Return options and their values from the command line.
  658. X**  This comes from the AT&T public-domain getopt published in mod.sources.
  659. X*/
  660. X#include <stdio.h>
  661. X
  662. X/* Pick one */
  663. X#define IDX    index        /* .. */
  664. X/*#define IDX    strchr        /* .. */
  665. X
  666. X#define TYPE    int
  667. X
  668. X#define ERR(s, c)                    \
  669. X    if (opterr) {                    \
  670. X    char buff[2];                    \
  671. X    buff[0] = c; buff[1] = '\n';            \
  672. X    (void)write(2, av[0], (TYPE)strlen(av[0]));    \
  673. X    (void)write(2, s, (TYPE)strlen(s));        \
  674. X    (void)write(2, buff, 2);            \
  675. X    }
  676. X
  677. Xint     opterr = 1;
  678. Xint     optind = 1;
  679. Xint     optopt;
  680. Xchar    *optarg;
  681. X
  682. Xint
  683. Xgetopt(ac, av, opts)
  684. X    int             ac;
  685. X    char        *av[];
  686. X    char        *opts;
  687. X{
  688. X    static int         i = 1;
  689. X    register char    *p;
  690. X
  691. X    /* Move to next value from argv? */
  692. X    if (i == 1) {
  693. X    if (optind >= ac || av[optind][0] != '-' || av[optind][1] == '\0')
  694. X        return EOF;
  695. X    if (strcmp(av[optind], "--") == 0) {
  696. X        optind++;
  697. X        return EOF;
  698. X    }
  699. X    }
  700. X
  701. X    /* Get next option character. */
  702. X    if ((optopt = av[optind][i]) == ':' || (p = IDX(opts,  optopt)) == NULL) {
  703. X    ERR(": illegal option -- ", optopt);
  704. X    if (av[optind][++i] == '\0') {
  705. X        optind++;
  706. X        i = 1;
  707. X    }
  708. X    return '?';
  709. X    }
  710. X
  711. X    /* Snarf argument? */
  712. X    if (*++p == ':') {
  713. X    if (av[optind][i + 1] != '\0')
  714. X        optarg = &av[optind++][i + 1];
  715. X    else {
  716. X        if (++optind >= ac) {
  717. X        ERR(": option requires an argument -- ", optopt);
  718. X        i = 1;
  719. X        return '?';
  720. X        }
  721. X        optarg = av[optind++];
  722. X    }
  723. X    i = 1;
  724. X    }
  725. X    else {
  726. X    if (av[optind][++i] == '\0') {
  727. X        i = 1;
  728. X        optind++;
  729. X    }
  730. X    optarg = NULL;
  731. X    }
  732. X
  733. X    return optopt;
  734. X}
  735. END_OF_FILE
  736. if test 1521 -ne `wc -c <'getopt.c'`; then
  737.     echo shar: \"'getopt.c'\" unpacked with wrong size!
  738. fi
  739. # end of 'getopt.c'
  740. fi
  741. if test -f 'makelex.c' -a "${1}" != "-c" ; then 
  742.   echo shar: Will not clobber existing file \"'makelex.c'\"
  743. else
  744. echo shar: Extracting \"'makelex.c'\" \(2315 characters\)
  745. sed "s/^X//" >'makelex.c' <<'END_OF_FILE'
  746. X/*
  747. X**  MAKELEX
  748. X**  Build lexical dictionary from the input file.
  749. X*/
  750. X#include "sonnet.h"
  751. X#ifndef    lint
  752. Xstatic char RCS[] =
  753. X    "$Header: makelex.c,v 2.0 89/02/08 16:30:16 rsalz Release1 $";
  754. X#endif    /* lint */
  755. X
  756. X
  757. X/*
  758. X**  Process one file.
  759. X*/
  760. Xstatic void
  761. XProcess(name, F)
  762. X    char        *name;
  763. X    register FILE    *F;
  764. X{
  765. X    register char    *p;
  766. X    register int     i;
  767. X    char         buff[128];
  768. X
  769. X    Printf("\t/* Input: %s */\n", name);
  770. X
  771. X    while (fgets(buff, sizeof buff, F)) {
  772. X    /* Blank lines and line beginning with a pound sign are comments. */
  773. X    if (buff[0] == '\n' || buff[0] == '#')
  774. X        continue;
  775. X
  776. X    /* Make isn't truncated. */
  777. X    if ((p = IDX(buff, '\n')) == NULL) {
  778. X        Fprintf(stderr, "Line too long, skipped:\n\t%s\n", buff);
  779. X        continue;
  780. X    }
  781. X    *p = '\0';
  782. X
  783. X    /* Make sure it's well-formed. */
  784. X    for (i = 0, p = buff; *p; p++)
  785. X        if (*p == ':')
  786. X        i++;
  787. X    if (i != 3) {
  788. X        Fprintf(stderr, "Badly-formed line, skipped:\n\t%s\n", buff);
  789. X        continue;
  790. X    }
  791. X
  792. X    /* First field is the actual word. */
  793. X    Printf("    {\t\"");
  794. X    for (i = 3, p = buff; *p != ':'; p++, i++)
  795. X        (void)putchar(*p);
  796. X
  797. X    /* Second field is the foot type. */
  798. X    Printf("\",\t%s 0, FT_", i < 8 ? "\t" : "");
  799. X    while (*++p != ':')
  800. X        (void)putchar(*p);
  801. X
  802. X    /* Third word is the vowel sound. */
  803. X    Printf(",  VS_");
  804. X    while (*++p != ':')
  805. X        (void)putchar(*p);
  806. X
  807. X    /* Fourth field is the consonant sound. */
  808. X    Printf(",  ");
  809. X    if (*++p == '\0')
  810. X        (void)putchar('0');
  811. X    else if (isdigit(*p))
  812. X        (void)putchar(*p);
  813. X    else if (islower(*p))
  814. X        Printf("'%c'", *p);
  815. X    else
  816. X        Printf("CS_%s", p);
  817. X    Printf("\t},\n");
  818. X    }
  819. X}
  820. X
  821. Xmain(ac, av)
  822. X    int             ac;
  823. X    char        *av[];
  824. X{
  825. X    register FILE    *F;
  826. X
  827. X    /* Print prolog. */
  828. X    Printf("/*\n");
  829. X    Printf("**  DICTIONARY -- DO NOT EDIT THIS FILE!\n");
  830. X    Printf("**  This file is generated by a program.  To edit the word\n");
  831. X    Printf("**  list, edit the data files then run make.\n");
  832. X    Printf("*/\n");
  833. X    Printf("\n");
  834. X    Printf("WORDTYPE Words[] = {\n");
  835. X
  836. X    /* Munch munch. */
  837. X    if (ac == 1)
  838. X    Process("standard input", stdin);
  839. X    else
  840. X    while (*++av)
  841. X        if ((F = fopen(*av, "r")) == NULL)
  842. X        Fprintf(stderr, "Can't open \"%s\" for input.\n", *av);
  843. X        else{ 
  844. X        Process(*av, F);
  845. X        (void)fclose(F);
  846. X        }
  847. X
  848. X
  849. X    /* Epilog. */
  850. X    Printf("    { NULL }\n");
  851. X    Printf("};\n");
  852. X
  853. X    /* That's all she wrote. */
  854. X    exit(0);
  855. X}
  856. END_OF_FILE
  857. if test 2315 -ne `wc -c <'makelex.c'`; then
  858.     echo shar: \"'makelex.c'\" unpacked with wrong size!
  859. fi
  860. # end of 'makelex.c'
  861. fi
  862. if test -f 'patchlog.h' -a "${1}" != "-c" ; then 
  863.   echo shar: Will not clobber existing file \"'patchlog.h'\"
  864. else
  865. echo shar: Extracting \"'patchlog.h'\" \(253 characters\)
  866. sed "s/^X//" >'patchlog.h' <<'END_OF_FILE'
  867. X/*
  868. X**  This file records official patches.
  869. X**
  870. X**  $Header: patchlog.h,v 2.0 89/02/08 16:30:24 rsalz Release1 $
  871. X**
  872. X**  $Log:    patchlog.h,v $
  873. X**  Revision 2.0  89/02/08  16:30:24  rsalz
  874. X**  First net release.
  875. X**  
  876. X*/
  877. X#define VERSION 2
  878. X#define PATCHLEVEL 0
  879. END_OF_FILE
  880. if test 253 -ne `wc -c <'patchlog.h'`; then
  881.     echo shar: \"'patchlog.h'\" unpacked with wrong size!
  882. fi
  883. # end of 'patchlog.h'
  884. fi
  885. if test -f 'sonnet.6' -a "${1}" != "-c" ; then 
  886.   echo shar: Will not clobber existing file \"'sonnet.6'\"
  887. else
  888. echo shar: Extracting \"'sonnet.6'\" \(1963 characters\)
  889. sed "s/^X//" >'sonnet.6' <<'END_OF_FILE'
  890. X.\" $Header: sonnet.6,v 2.0 89/02/08 16:30:30 rsalz Release1 $"
  891. X.TH SONNET 6
  892. X.SH NAME
  893. Xsonnet \- write (bad) poetry
  894. X.SH SYNOPSIS
  895. X.B sonnet
  896. X[
  897. X.BI \-l file
  898. X] [
  899. X.BI \-f file
  900. X] [
  901. X.B \-s
  902. X] [
  903. X.B \-v
  904. X]
  905. X.SH DESCRIPTION
  906. X.I Sonnet
  907. Xis a screen-oriented program that writes sonnets.
  908. XIt as an interactive
  909. X.IR curses (3)-based
  910. Xprogram.
  911. X.PP
  912. XThe ``\-v'' flag, if specified, prints the current version and patchlevel
  913. Xand exits.
  914. X.PP
  915. XTo start working on a pre-existing sonnet, use the ``\-l'' flag to
  916. Xload a sonnet, otherwise the program will write one from scratch.
  917. XIf you load in a file that has a poem not composed by this program
  918. Xit will abort.
  919. XOnce the sonnet has been composed, the program will display it
  920. Xand enter the main command loop.
  921. XIn this main loop, you can mark lines that you like, and try to
  922. Xwrite the rest of the poem around those lines.
  923. X.PP
  924. XCommands while in the main loop (either case, but end with a return):
  925. X.TP 10
  926. X.B "?, H"
  927. XDisplay help.
  928. X.TP 10
  929. X.B R
  930. XRecompose.
  931. XAll un-marked lines are recomposed.
  932. X.TP 10
  933. X.B [RETURN]
  934. XRecompose or Refresh.
  935. XNormally, the [RETURN] key will also compose a new sonnet.
  936. XIf the ``\-s'' flag is used, however, the program acts more ``safely''
  937. Xand [RETURN] will just redraw the screen.
  938. X.TP 10
  939. X.BI M #
  940. XMark a line.
  941. XThe line with the indicated number is marked so that it will not
  942. Xbe replaced with new text after the next restart.
  943. X.TP 10
  944. X.BI U #
  945. XUn-mark.
  946. XThe line is no longer protected.
  947. X.TP 10
  948. X.BI W [file]
  949. XWrite.
  950. XThe current poem is written to the named file.
  951. XIf no filename is given, the name specified with the ``\-f'' flag is used.
  952. XIf the file exists, the poem is appended to the existing contents.
  953. X.TP 10
  954. X.B Q
  955. XQuit.
  956. XThe program exits.
  957. XNote that the poem is not saved.
  958. X.PP
  959. XAny other key redraws the screen.
  960. X.SH BUGS
  961. XThe database is compiled into the program and must be generated using the
  962. Xundocumented
  963. X.IR makelex (8L)
  964. Xprogram distributed with the source.
  965. X.SH AUTHORS
  966. XChris Wilbur <chw@mirror.tmc.com>
  967. X.br
  968. XRich $alz <rsalz@bbn.com>
  969. END_OF_FILE
  970. if test 1963 -ne `wc -c <'sonnet.6'`; then
  971.     echo shar: \"'sonnet.6'\" unpacked with wrong size!
  972. fi
  973. # end of 'sonnet.6'
  974. fi
  975. if test -f 'sonnet.c' -a "${1}" != "-c" ; then 
  976.   echo shar: Will not clobber existing file \"'sonnet.c'\"
  977. else
  978. echo shar: Extracting \"'sonnet.c'\" \(5065 characters\)
  979. sed "s/^X//" >'sonnet.c' <<'END_OF_FILE'
  980. X/*
  981. X**  SONNET
  982. X**  Curses-based driver for the poetry composer.
  983. X*/
  984. X#include <curses.h>
  985. X#include "sonnet.h"
  986. Xstatic char RCS[] =
  987. X    "$Header: sonnet.c,v 2.0 89/02/08 16:30:38 rsalz Release1 $";
  988. X
  989. Xstatic int     safe = FALSE;
  990. X
  991. Xextern LINETYPE    *Lines;
  992. Xextern int     Lcount;
  993. X
  994. X
  995. X/*
  996. X**  Display the current sonnet
  997. X*/
  998. Xstatic void
  999. XShowIt()
  1000. X{
  1001. X    register LINETYPE    *L;
  1002. X    register int     i;
  1003. X
  1004. X    for (L = Lines, i = Lcount; --i >= 0; L++) {
  1005. X    (void)move(L->Line + 2, 0);
  1006. X    (void)clrtoeol();
  1007. X    if (L->Active)
  1008. X        Printw("%2d%c\t%s", L->Active, L->Marked ? '*' : ' ', L->Text);
  1009. X    }
  1010. X    Printw("\n");
  1011. X    (void)refresh();
  1012. X}
  1013. X
  1014. X
  1015. X/*
  1016. X**  Mark or un-mark a line.
  1017. X*/
  1018. Xstatic void
  1019. XMarkLine(p, on)
  1020. X    register char    *p;
  1021. X    register int     on;
  1022. X{
  1023. X    register LINETYPE    *L;
  1024. X    register int     i;
  1025. X    register int     offset;
  1026. X
  1027. X    while (*p && isspace(*p))
  1028. X    p++;
  1029. X    if (*p)
  1030. X    for (offset = atoi(p), L = Lines, i = Lcount; --i >= 0; L++)
  1031. X        if (L->Active == offset) {
  1032. X        L->Marked = on;
  1033. X        break;
  1034. X        }
  1035. X}
  1036. X
  1037. X
  1038. X/*
  1039. X**  Help the user out by listing the legal commands.
  1040. X*/
  1041. Xstatic void
  1042. XDoHelp()
  1043. X{
  1044. X    (void)move(0, 0);
  1045. X    (void)clrtobot();
  1046. X    Printw("\nSonnet commands:\n");
  1047. X    Printw("\tM #\t\tMark the indicated line\n");
  1048. X    Printw("\tU #\t\tUnmark the indicated line\n");
  1049. X    Printw("\tR\t\tRecompose all unmarked lines\n");
  1050. X    if (!safe)
  1051. X    Printw("\t[RETURN]\talso means recompose\n");
  1052. X    Printw("\tQ\t\tQuit\n");
  1053. X    Printw("\tW name\t\tAppend poem to indicated file\n");
  1054. X    Printw("\t?\t\tShow this help text\n");
  1055. X    Printw("\tH\t\tShow this help text\n");
  1056. X    Printw("\n");
  1057. X    Printw("  Any other key redraws the screen\n");
  1058. X    Printw(
  1059. X   "  Commands may be given in either case and must be ended with a RETURN.\n"
  1060. X        );
  1061. X    Printw("\n\n[Press return to continue]");
  1062. X    (void)refresh();
  1063. X    while ((getchar()) != '\n')
  1064. X    ;
  1065. X    (void)move(0, 0);
  1066. X    (void)clrtobot();
  1067. X    (void)refresh();
  1068. X}
  1069. X
  1070. X
  1071. X
  1072. X/*
  1073. X**  Main program.
  1074. X*/
  1075. Xmain(ac, av)
  1076. X    int             ac;
  1077. X    char        *av[];
  1078. X{
  1079. X    register FILE    *F;
  1080. X    register LINETYPE    *L;
  1081. X    register char    *p;
  1082. X    register int     i;
  1083. X    char        *outfile;
  1084. X    char        *infile;
  1085. X    char         buff[MAXLEN];
  1086. X
  1087. X    outfile = DEFAULT_OUT_FILE;
  1088. X    infile = NULL;
  1089. X    while ((i = getopt(ac, av, "f:l:sv")) != EOF)
  1090. X    switch (i) {
  1091. X    default:
  1092. X        Fprintf(stderr, "Usage:  %s [-l input] [-f outfilename]\n", av[0]);
  1093. X        exit(1);
  1094. X        /* NOTREACHED */
  1095. X    case 'f':
  1096. X        outfile = optarg;
  1097. X        break;
  1098. X    case 'l':
  1099. X        infile = optarg;
  1100. X        break;
  1101. X    case 's':
  1102. X        safe = TRUE;
  1103. X        break;
  1104. X    case 'v':
  1105. X        printf("Sonnet program Version %d, Patchlevel %d:\n\t%s\n",
  1106. X            VERSION, PATCHLEVEL, RCS);
  1107. X        exit(0);
  1108. X        /* NOTREACHED */
  1109. X    }
  1110. X
  1111. X    /* Set up curses. */
  1112. X    (void)initscr();
  1113. X    (void)move(0, 0);
  1114. X    (void)clrtobot();
  1115. X    (void)refresh();
  1116. X
  1117. X    /* Wake up, Mr. Shakespeare! */
  1118. X    ComposeInit((char *)NULL, 0);
  1119. X
  1120. X    /* Start with nothing, or from an existing poem. */
  1121. X    if (infile == NULL)
  1122. X    for (L = Lines, i = Lcount; --i >= 0; L++)
  1123. X        ComposeLine(L);
  1124. X    else {
  1125. X    if ((F = fopen(optarg, "r")) == NULL) {
  1126. X        Fprintf(stderr, "Can't open %s for input.\n", optarg);
  1127. X        exit(1);
  1128. X        /* NOTREACHED */
  1129. X    }
  1130. X    for (L = Lines, i = Lcount; --i >= 0; L++) {
  1131. X        /* Get a good line or give up. */
  1132. X        if (fgets(L->Text, sizeof L->Text, F) == NULL) {
  1133. X        Fprintf(stderr, "Too little data in file.\n");
  1134. X        (void)fclose(F);
  1135. X        exit(1);
  1136. X        /* NOTREACHED */
  1137. X        }
  1138. X        if ((p = IDX(L->Text, '\n')) == NULL) {
  1139. X        Fprintf(stderr, "Bad data in file.\n");
  1140. X        (void)fclose(F);
  1141. X        exit(1);
  1142. X        /* NOTREACHED */
  1143. X        }
  1144. X        *p = '\0';
  1145. X
  1146. X        L->Marked = TRUE;
  1147. X        SetRhyme(L);
  1148. X    }
  1149. X    (void)fclose(F);
  1150. X    }
  1151. X
  1152. X    /* Show what we're starting off with. */
  1153. X    ShowIt();
  1154. X
  1155. X    /* Main processing loop. */
  1156. X    for ( ; ; ) {
  1157. X    /* Show old poem and prompt.  Cautious curses calls. */
  1158. X    ShowIt();
  1159. X    (void)move(20, 0);
  1160. X    (void)clrtobot();
  1161. X    (void)move(20, 0);
  1162. X    Printw("[m# u# r w[file] q; ? for help]:  ");
  1163. X    (void)clrtoeol();
  1164. X    (void)refresh();
  1165. X
  1166. X    /* Get input. */
  1167. X    if (fgets(buff, sizeof buff, stdin) == NULL)
  1168. X        buff[0] = 'q';
  1169. X    else if (p = IDX(buff, '\n'))
  1170. X        *p = '\0';
  1171. X
  1172. X    /* Blank line in unsafe mode means rewrite. */
  1173. X    if (buff[0] == '\0' && !safe)
  1174. X        buff[0] = 'r';
  1175. X
  1176. X    /* Dispatch. */
  1177. X    switch (buff[0]) {
  1178. X    default:
  1179. X        clearok(curscr, TRUE);
  1180. X        touchwin(curscr);
  1181. X        (void)refresh();
  1182. X        break;
  1183. X    case '?':
  1184. X    case 'H': case 'h':
  1185. X        DoHelp();
  1186. X        break;
  1187. X    case 'M': case 'm':
  1188. X        MarkLine(&buff[1], TRUE);
  1189. X        break;
  1190. X    case 'Q': case 'q':
  1191. X        (void)move(LINES - 1, 0);
  1192. X        (void)refresh();
  1193. X        Printf("\n\n");
  1194. X        (void)endwin();
  1195. X        exit(0);
  1196. X        /* NOTREACHED */
  1197. X    case 'R': case 'r':
  1198. X        for (L = Lines, i = Lcount; --i >= 0; L++)
  1199. X        ComposeLine(L);
  1200. X        break;
  1201. X    case 'W': case 'w':
  1202. X        if (buff[1])
  1203. X        for (p = &buff[1]; *p && isspace(*p); p++)
  1204. X            ;
  1205. X        else
  1206. X        p = outfile;
  1207. X        if ((F = fopen(p, "a")) == NULL) {
  1208. X        Printf("Cannot open %s for output.\n", p);
  1209. X        exit(1);
  1210. X        /* NOTREACHED */
  1211. X        }
  1212. X        for (L = Lines, i = Lcount; --i >= 0; L++)
  1213. X        Fprintf(F, "%s\n", L->Text);
  1214. X        (void)fclose(F);
  1215. X        break;
  1216. X    case 'U': case 'u':
  1217. X        MarkLine(&buff[1], FALSE);
  1218. X        break;
  1219. X    }
  1220. X    }
  1221. X
  1222. X    /* NOTREACHED */
  1223. X}
  1224. END_OF_FILE
  1225. if test 5065 -ne `wc -c <'sonnet.c'`; then
  1226.     echo shar: \"'sonnet.c'\" unpacked with wrong size!
  1227. fi
  1228. # end of 'sonnet.c'
  1229. fi
  1230. if test -f 'sonnet.h' -a "${1}" != "-c" ; then 
  1231.   echo shar: Will not clobber existing file \"'sonnet.h'\"
  1232. else
  1233. echo shar: Extracting \"'sonnet.h'\" \(4349 characters\)
  1234. sed "s/^X//" >'sonnet.h' <<'END_OF_FILE'
  1235. X/*
  1236. X**
  1237. X**  $Header: sonnet.h,v 2.0 89/02/08 16:30:49 rsalz Release1 $
  1238. X*/
  1239. X#include <stdio.h>
  1240. X#include <ctype.h>
  1241. X#include "patchlog.h"
  1242. X
  1243. X/* Manifest constants, syntactic sugar. */
  1244. X#define NLINES            17
  1245. X#define MAXLEN            80
  1246. X#define EQ(a, b)        (strcmp((a), (b)) == 0)
  1247. X#define EQn(a, b, n)        (strncmp((a), (b), (n)) == 0)
  1248. X#define DEFAULT_OUT_FILE    "sonnet.out"
  1249. X
  1250. X/* Some fundamental constants of the universe. */
  1251. X#ifndef    TRUE
  1252. X#define TRUE            1
  1253. X#endif    /* TRUE */
  1254. X#ifndef    FALSE
  1255. X#define FALSE            0
  1256. X#endif    /* FALSE */
  1257. X
  1258. X/* Dialectical differences. */
  1259. X#ifdef    USE_INDEX
  1260. X#define IDX        strchr
  1261. X#define RDX        strrchr
  1262. X#else
  1263. X#define IDX        index
  1264. X#define RDX        rindex
  1265. X#endif    /* USE_INDEX */
  1266. X
  1267. X
  1268. X/* FOOT TYPES -- index into the Rhythm tables */
  1269. X#define FT__fill1     0        /* Not used            */
  1270. X#define FT_HF         1        /* ace (Single syllable)    */
  1271. X#define FT_IF         2        /* hurrah (Iambic)        */
  1272. X#define FT_TF         3        /* hollow (Trochaic)        */
  1273. X#define FT__fill2     4        /* Not used            */
  1274. X#define FT_DF         5        /* happily (Dactylic)        */
  1275. X#define FT_AF         6        /* ala mode (Anapestic)        */
  1276. X#define FT_IFF         7        /* resemble            */
  1277. X#define FT_IIF         8        /* establishing            */
  1278. X#define FT_TTF         9        /* education            */
  1279. X#define FT_IIFF        10        /* administration        */
  1280. X#define FT_TDF        11        /* BMW                */
  1281. X#define FT_HIF        12        /* document            */
  1282. X#define FT_TDIF        13        /* opportunity            */
  1283. X
  1284. X/* VOWEL SOUNDS */
  1285. X#define VS_LA        'A'        /* Cambridge (long A)        */
  1286. X#define VS_SA        'a'        /* mad (short A)        */
  1287. X#define VS_LE        'E'        /* MIT (long E)            */
  1288. X#define VS_SE        'e'        /* deaf (short E)        */
  1289. X#define VS_LI        'I'        /* bicep (long I)        */
  1290. X#define VS_SI        'i'        /* big (short I)        */
  1291. X#define VS_LO        'O'        /* bold (long O)        */
  1292. X#define VS_SO        'o'        /* bomb (short O)        */
  1293. X#define VS_LU        'U'        /* zoo (long U)            */
  1294. X#define VS_SU        'u'        /* lunch (short U)        */
  1295. X#define VS_OI        'y'        /* oil                */
  1296. X#define VS_OU        'w'        /* ouch                */
  1297. X#define VS_ER        'r'        /* purgative            */
  1298. X    /* You can add your own sounds if you need to. */
  1299. X
  1300. X/* CONSONANT SOUNDS */
  1301. X#define CS_SH        'A'        /* awash, dish, flesh        */
  1302. X#define CS_ST        'B'        /* feast, burst, juiced        */
  1303. X#define CS_CH        'C'        /* ouch, slouch, grouch        */
  1304. X#define CS_LD        'D'        /* soiled, boiled behold    */
  1305. X#define CS_RD        'E'        /* chord, hoard, buzzword    */
  1306. X#define CS_NK        'F'        /* junk, pink, crank        */
  1307. X#define CS_NT        'G'        /* grunt, insolent, paramount    */
  1308. X#define CS_ND        'H'        /* refined, stained, sustained    */
  1309. X#define CS_NG        'I'        /* wrong, long, song        */
  1310. X#define CS_NS        'J'        /* dense, tense, bounce        */
  1311. X#define CS_MP        'K'        /* champ, clamp, clomp        */
  1312. X#define CS_TH        'L'        /* south, mouth, rebirth    */
  1313. X#define CS_TS        'M'        /* guts, nuts, reports        */
  1314. X#define CS_RT        'N'        /* snort, sport, apart        */
  1315. X#define CS_RK        'O'        /* work, beserk, arc        */
  1316. X#define CS_CT        'P'        /* defunct, cataract, deject    */
  1317. X#define CS_RM        'Q'        /* harm, alarm, chloroform    */
  1318. X#define CS_PS        'R'        /* corpse, warps, elapse    */
  1319. X#define CS_PT        'S'        /* flipped, equipped, flapped    */
  1320. X#define CS_LT        'T'        /* insult, occult, salt        */
  1321. X#define CS_SP        'U'        /* grasp, rasp, lisp        */
  1322. X#define CS_NZ        'V'        /* wrench, stench, brunch    */
  1323. X#define CS_SK        'W'        /* risk, tasks, brusque        */
  1324. X#define CS_RS        'X'        /* worse, hearse, coarse    */
  1325. X#define CS_NJ        'Y'        /* hinge, cringe, munge        */
  1326. X#define CS_FT        'Z'        /* cleft, left, thrift        */
  1327. X#define CS_RN        '$'        /* born, worn, porn        */
  1328. X    /* If you add your own consonant sounds, make sure not to use
  1329. X     * the lowercase letters! */
  1330. X
  1331. X
  1332. Xtypedef struct _WORDTYPE {
  1333. X    char    *Text;        /* Text of the word            */
  1334. X    short     Used;        /* Used this word in the search?    */
  1335. X    short     Foot;        /* Foot type (for scanning)        */
  1336. X    short     vowel;        /* Vowel sound (for rhyming)        */
  1337. X    short     cons;        /* Consonant sound (for rhyming)    */
  1338. X} WORDTYPE;
  1339. X
  1340. X
  1341. Xtypedef struct _LINETYPE {
  1342. X    short     Line;        /* Absolute line number            */
  1343. X    short     Active;    /* Text line number            */
  1344. X    short     Rhyme;        /* Rhyme pattern location        */
  1345. X    short     Marked;    /* Save current contents?        */
  1346. X    short     vowel;        /* Vowel rhyme                */
  1347. X    short     cons;        /* Consonant rhyme            */
  1348. X    char     Text[MAXLEN + 1];    /* Output text            */
  1349. X} LINETYPE;
  1350. X
  1351. X
  1352. X/* Lint placation */
  1353. X#define Printf        (void)printf
  1354. X#define Printw        (void)printw
  1355. X#define Fprintf        (void)fprintf
  1356. X#define Sprintf        (void)sprintf
  1357. X#ifdef    lint
  1358. X#undef    putchar
  1359. X#endif    /* lint */
  1360. X
  1361. X
  1362. X/* Linked in later */
  1363. Xextern int     optind;
  1364. Xextern char    *optarg;
  1365. X
  1366. Xextern char    *malloc();
  1367. Xextern char    *sprintf();
  1368. Xextern char    *strcat();
  1369. Xextern char    *IDX();
  1370. Xextern char    *RDX();
  1371. Xextern int     rand();
  1372. Xextern long     time();
  1373. END_OF_FILE
  1374. if test 4349 -ne `wc -c <'sonnet.h'`; then
  1375.     echo shar: \"'sonnet.h'\" unpacked with wrong size!
  1376. fi
  1377. # end of 'sonnet.h'
  1378. fi
  1379. echo shar: End of archive 1 \(of 2\).
  1380. cp /dev/null ark1isdone
  1381. MISSING=""
  1382. for I in 1 2 ; do
  1383.     if test ! -f ark${I}isdone ; then
  1384.     MISSING="${MISSING} ${I}"
  1385.     fi
  1386. done
  1387. if test "${MISSING}" = "" ; then
  1388.     echo You have unpacked both archives.
  1389.     rm -f ark[1-9]isdone
  1390. else
  1391.     echo You still need to unpack the following archives:
  1392.     echo "        " ${MISSING}
  1393. fi
  1394. ##  End of shell archive.
  1395. exit 0
  1396.