home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume02 / ncode < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  25.9 KB

  1. From mipos3!intelca!oliveb!ames!necntc!ncoast!allbery Sat Jan 23 19:37:13 PST 1988
  2. Article 256 of comp.sources.misc:
  3. Path: td2cad!mipos3!intelca!oliveb!ames!necntc!ncoast!allbery
  4. From: good@pixar.UUCP (Craig)
  5. Newsgroups: comp.sources.misc
  6. Subject: v02i007: New, really improved "ncode" random text construction kit
  7. Message-ID: <7081@ncoast.UUCP>
  8. Date: 15 Jan 88 00:45:01 GMT
  9. Sender: root@ncoast.UUCP
  10. Organization: Pixar -- Marin County, California
  11. Lines: 1118
  12. Approved: allbery@ncoast.UUCP
  13. X-Archive: comp.sources.misc/8801/7
  14. Comp.Sources.Misc: Volume 2, Issue 7
  15. Submitted-By: Craig <good@pixar.UUCP>
  16. Archive-Name: ncode
  17.  
  18. Comp.Sources.Misc: Volume 2, Issue 7
  19. Submitted-By: Craig <good@pixar.UUCP>
  20. Archive-Name: ncode
  21.  
  22. Here it is: the new, improved ncode.c along with new, improved sample
  23. files which help you appreciate all the wonderful features of the program.
  24. Some highlights:
  25.  
  26.     * Arbitrary file sizes
  27.     * #include
  28.     * comments now allowed in files
  29.     * "variables": special groups which are expanded exactly once
  30.     * bigger .c file to impress your friends
  31.  
  32. To unwrap your kit, save it in a file called "ncode.shar".
  33.  
  34. To assemble your kit, delete everything in the file above (and including)
  35. this "cut here" line, and delete everything below (and including) the
  36. other "cut here" line near the bottom of the file.  Then give the command
  37.  
  38.     sh ncode.shar
  39.  
  40. and start by reading the README file.  Cheers.
  41. ----------------------------- cut here --------------------------------
  42. echo x - README
  43. sed 's/^X//' >README <<'*-*-END-of-README-*-*'
  44. XYou should now have README, ncode.c, ncode.1, poetry.n and foxes.n.
  45. X
  46. XThe program will handle arbitrarily large files (you can even #include
  47. X/usr/dict/words) if you have the memory for it.  New for this release are
  48. Xcomments and "variables".  Gory details in the man page, ncode.1
  49. X
  50. XThis source is known to compile and run on 4.3 BSD and on Sun 3.4.  I
  51. Xunderstand that it compiles fine on sysV if you replace the calls to random()
  52. Xand srandom() with calls to rand() and srand().  Non 4.3 users will probably
  53. Xalso have to replace the innards of a_random_number() with something that
  54. Xworks on your system.  You basically want some number to seed the random
  55. Xnumber generator.  A getpid() doesn't change very quickly but will work;
  56. Xcalls to the real-time clock work better.  This version of a_random_number()
  57. Xwas written by pixar!brighton who insists that all the baroque bit twiddling
  58. Xhelps.  I just know that it works.
  59. X
  60. XCompile it "cc ncode.c -O -o ncode" and then try
  61. X
  62. X    ncode ncode.sample.1
  63. X
  64. XFor more fun, try
  65. X
  66. X    ncode -n 5 ncode.sample.1
  67. X
  68. XAnd for a good education say
  69. X
  70. X    ncode -g "I had a date with FOX\" ncode.sample.1
  71. X
  72. XThen you might want to read the man page, ncode.1, to learn about how it
  73. Xworks.  You can make it pretty with "nroff -man ncode.1".  If all of this
  74. Xleaves you hopelessly confused, send me some mail and I'll send you more
  75. Xconfusing sample files.  Maybe.  If I feel like it.
  76. X
  77. X
  78. X        --Craig
  79. X        ...{ucbvax,pyramid,sun}!pixar!good
  80. X
  81. *-*-END-of-README-*-*
  82. echo x - ncode.c
  83. sed 's/^X//' >ncode.c <<'*-*-END-of-ncode.c-*-*'
  84. X/*
  85. X *    ncode.c --  a random text constructor
  86. X *    pixar!good
  87. X *    vaguely based on a program by pixar!mark
  88. X */
  89. X
  90. X#include <stdio.h>
  91. X#include <sys/file.h>
  92. X#include <sys/time.h>
  93. X#include <sys/types.h>
  94. X#include <sys/stat.h>
  95. X
  96. X#define DATALUMP    8192    /* increment size of data[] by this as needed */
  97. X#define BIGBUF        4096    /* nice, roomy buffer for group name checks */
  98. X/*
  99. X *    These are for the status element of gstruct.
  100. X */
  101. X#define OBUF        -1    /* the output buffer lives here */
  102. X#define NVAR        0    /* this is not a "variable" */
  103. X#define AVAR        1    /* this is a "variable" and needs to be "set" */
  104. X#define DVAR        2    /* this "variable" has been set */
  105. X
  106. Xchar **data;    /* array of pointers to elements in bucket */
  107. Xint dindex;    /* number of elements in data */
  108. Xint datasize;    /* how many elements would fit in data[] right now */
  109. X
  110. X/*
  111. X *    Size of our output buffer, and the initial size of "variable" buffers
  112. X */
  113. X#define MYBUFSIZ BUFSIZ
  114. X
  115. Xchar *malloc();
  116. Xchar *realloc();
  117. Xchar *rindex();
  118. Xlong random();
  119. X
  120. Xstruct gstruct {
  121. X    char *name;    /* points to name of a group in data[] */
  122. X    char *buf;    /* points to a buffer for set "variable" data */
  123. X    char *bptr;    /* points to current position in buf */
  124. X    char *lim;    /* points to last element of buf[] */
  125. X    int bufsiz;    /* current size of buf element */
  126. X    int count;    /* how many elements of data belong to this group */
  127. X    int index;    /* index of element of data where group starts */
  128. X    int status;    /* are we a "variable" and, if so, what's our status? */
  129. X};
  130. Xstruct gstruct *groups; /* where the group structs live, or is that obvious? */
  131. Xint ngroups;        /* number of elements in groups */
  132. Xstruct gstruct bbuf;    /* output buffer lives in here */
  133. X
  134. Xmain (ac,av)
  135. Xint ac;
  136. Xchar *av[];
  137. X{
  138. X    char *prog;        /* name of this program */
  139. X    char *fname = 0;
  140. X    int loopcnt = 1;    /* times through main loop */
  141. X     char *groupname = "CODE";
  142. X
  143. X    prog = rindex(*av,'/');
  144. X    prog = ( prog == NULL ) ? *av : ++prog ;
  145. X    ac--;av++;
  146. X    while(ac && **av == '-'){
  147. X        if (strcmp(*av,"-n") == 0){
  148. X            ac--;av++;
  149. X            loopcnt = atoi(*av);
  150. X            if (loopcnt <= 0){
  151. X                fprintf(stderr,
  152. X                    "%s: -n: need positive integer\n",prog);
  153. X                exit(1);
  154. X            }
  155. X            ac--;av++;
  156. X        } else if (strcmp(*av,"-g") == 0){
  157. X            ac--;av++;
  158. X            groupname = *av;    /* use instead of "CODE" */
  159. X            if (! groupname ){
  160. X                fprintf(stderr,
  161. X                    "%s: -g: need group name\n",prog);
  162. X                exit(1);
  163. X            }
  164. X            ac--;av++;
  165. X        } else {
  166. X            printf(
  167. X            "Usage %s [-n n ] [-g groupname] codefile\n",prog);
  168. X            exit(0);
  169. X        }
  170. X    }
  171. X    if (!ac){
  172. X        fprintf(stderr,
  173. X            "Usage %s [-n n ] [-g groupname] codefile\n",prog);
  174. X        exit(1);
  175. X    }
  176. X    fname = *av;
  177. X
  178. X    /*
  179. X     * Set up the special-case struct where the output buffer lives.
  180. X     */
  181. X    if ((bbuf.buf = (char *) malloc(MYBUFSIZ * sizeof(char))) == NULL ){
  182. X        perror("main: could not malloc for bbuf.buf");
  183. X        exit(1);
  184. X    }
  185. X    /*
  186. X     *    This stuff only has to happen once
  187. X     */
  188. X    bbuf.bufsiz = MYBUFSIZ;
  189. X    bbuf.lim = bbuf.buf+MYBUFSIZ-1;
  190. X    bbuf.status = OBUF;
  191. X    bbuf.name = NULL;
  192. X    bbuf.count = 0;    /* this shouldn't mean a thing */
  193. X    bbuf.index = 0;
  194. X
  195. X    /*
  196. X     *    Make some room to start, and increment by DATALUMP as needed
  197. X     */
  198. X    datasize = DATALUMP;
  199. X    if ((data = (char **) malloc(datasize * sizeof(char *))) == NULL ){
  200. X        perror("main: could not malloc for data[]");
  201. X        exit(1);
  202. X    }
  203. X    dindex = 0;
  204. X    if( init(fname) != 0 ){    
  205. X        fprintf(stderr,"%s: init error\n",prog);
  206. X        exit(1);
  207. X    }
  208. X    /*
  209. X     * This should be more than enough room for worst-case, since even
  210. X     * if the file were full of empty group declarations there would only
  211. X     * be dindex/2 possible groups.
  212. X     */
  213. X    groups = (struct gstruct *) malloc(dindex * sizeof(struct gstruct));
  214. X    if (groups == NULL){
  215. X        perror("main: could not malloc for groups[]");
  216. X        exit(1);
  217. X    }
  218. X    if ( scan() != 0 ){
  219. X        fprintf(stderr,"%s: scan error\n",prog);
  220. X        exit(1);
  221. X    }
  222. X    srandom(a_random_number());    /* seed the number generator */
  223. X    /*
  224. X     *    And away we go...
  225. X     */
  226. X    while ( loopcnt ){
  227. X        bbuf.bptr = bbuf.buf;
  228. X        expand(groupname,strlen(groupname),&bbuf);
  229. X        *bbuf.bptr = '\0';    /* terminate before flushing */
  230. X        flushbuf(bbuf.buf);
  231. X        loopcnt--;
  232. X    }
  233. X    exit(0);
  234. X}
  235. X
  236. Xinit(fname)
  237. Xchar *fname;
  238. X{
  239. X    char *bucket;    /* big array where data lives */
  240. X    char *bptr;    /* points into bucket */
  241. X    int fd;
  242. X    struct stat sbuf;
  243. X    char *s, *t;
  244. X
  245. X    fd = open(fname,O_RDONLY,0);
  246. X    if ( fd < 0 ) {
  247. X        perror(fname);
  248. X        return 1;
  249. X    }
  250. X    if ( fstat(fd,&sbuf) != 0 ){
  251. X        perror(fname);
  252. X        return 1;
  253. X    }
  254. X    if ((bucket = (char *) malloc( sbuf.st_size + 1)) == NULL ){
  255. X        perror("init(): malloc() trouble");
  256. X        return 1;
  257. X    }
  258. X    /*
  259. X     *    Read entire file into bucket[]
  260. X     */
  261. X    if ((read(fd,bucket,sbuf.st_size)) != sbuf.st_size){
  262. X        perror("init: read error");
  263. X        return 1;
  264. X    }
  265. X    close(fd);
  266. X    /*
  267. X     * Make first pass through memory, pointing data[] the right way
  268. X     * and recursing as needed on #include files.
  269. X     */
  270. X    bptr = bucket;
  271. X    while ( *bptr && (bptr <= bucket + sbuf.st_size) ){
  272. X        s = bptr; 
  273. X        while ( *s != '\0' ){
  274. X            if(*s == '\n' )
  275. X                *s = '\0';    /* nuke newline */
  276. X            else
  277. X                s++;
  278. X        }
  279. X        if( strncmp(bptr, "#include", 8) == 0 ){
  280. X            for(t = bptr + 8; *t!='\0' && (*t==' '||*t=='\t');t++)
  281. X                ;    /* skipping white space */
  282. X            if (init(t) != 0){    /* RECURSES HERE */
  283. X                return 1;
  284. X            }
  285. X            bptr = t + strlen(t) + 1; /* skip the #include line */
  286. X            continue;    /* back to the top of the while loop */
  287. X        } else if ( *bptr == '#' ) {    /* must be a comment */
  288. X            bptr += strlen(bptr) + 1; /* skip #comment line */
  289. X            continue;    
  290. X        }
  291. X        /*
  292. X         *    Make sure data[] is still big enough
  293. X         */
  294. X        if ( dindex >= datasize){
  295. X            datasize += DATALUMP;
  296. X            if((data=(char **) realloc(data,
  297. X                    datasize*sizeof(char *)))==NULL){
  298. X                perror("init: could not realloc for data[]");
  299. X                return(1);
  300. X            }
  301. X        }
  302. X        data[dindex] = bptr;    /* point it at the data */
  303. X        bptr = s + 1;    /* move bptr to the next location to fill */
  304. X        dindex++;
  305. X    }
  306. X    return 0;
  307. X}
  308. X
  309. X/*
  310. X *    Scan data[] marking and counting groups
  311. X */
  312. Xscan()
  313. X{
  314. X    register int i, gcnt, gindex;
  315. X    register char *vptr;
  316. X
  317. X    /*
  318. X     * special case: first line always a group name 
  319. X     */
  320. X    groups[0].name = data[0];
  321. X    groups[0].index = 0;
  322. X    ngroups = 1;
  323. X    i = 1;
  324. X    gindex = 0;
  325. X    gcnt = 0;
  326. X    while ( i < dindex ){
  327. X        if ( data[i][0] == '%' ){
  328. X            groups[gindex].count = gcnt;
  329. X            gcnt = 0;        /* close out prev group */
  330. X            ngroups++;
  331. X            i++;            /* start next group */
  332. X            /*
  333. X             *    If a #included file has any blank lines after
  334. X             *    the last '%' then the group name would wind
  335. X             *    up being '\0'.  So the first group name after
  336. X             *    the #include won't be marked as a group name
  337. X             *    and will thus never be expanded.  We could
  338. X             *    cluck our tongues at the user and say he has
  339. X             *    a bogus file and thus deserves what he gets.
  340. X             *    But hopefully this check will just make the
  341. X             *    program more robust.
  342. X             */
  343. X            while ((i < dindex) && (data[i][0] == '\0')) {
  344. X                    i++;
  345. X            }
  346. X            gindex++;
  347. X            groups[gindex].name = data[i];
  348. X            groups[gindex].index = i;
  349. X            groups[gindex].status = NVAR;
  350. X            vptr = groups[gindex].name;
  351. X            if (vptr) vptr += strlen(groups[gindex].name) -1;
  352. X            if ( vptr && *vptr == '*' ){
  353. X                *vptr = '\0';    /* terminate the name */
  354. X                groups[gindex].status = AVAR;
  355. X                if (
  356. X(groups[gindex].buf = (char *) malloc(MYBUFSIZ * sizeof(char))) == NULL ){
  357. X            perror("scan(): could not malloc for groups.buf");
  358. X                    exit(1);
  359. X                }
  360. X                groups[gindex].bptr = groups[gindex].buf;
  361. X                groups[gindex].lim=groups[gindex].buf+MYBUFSIZ-1;
  362. X                groups[gindex].bufsiz=MYBUFSIZ;
  363. X            }
  364. X        }else{
  365. X            gcnt++;
  366. X        }
  367. X        i++;
  368. X    }
  369. X    ngroups--;    /* The last % in the file doesn't start a new group */
  370. X    return 0;
  371. X}
  372. X
  373. X/*
  374. X *    This is where we finally do the deed.  If a string is a group name
  375. X *    then expand will randomly select a member of that group to
  376. X *    replace it.  Through the miracle of recursion, a whole sentence
  377. X *    may be passed to expand and each word (anything bounded by what
  378. X *    we call "white space" gets expanded.  Anything that cannot be
  379. X *    expanded gets printed out.
  380. X */
  381. Xexpand(s,lim,grp)
  382. Xchar s[];    /* from */
  383. Xint lim;
  384. Xstruct gstruct *grp;    /* to */
  385. X{
  386. X    register int i, j, k, done, n, r;
  387. X
  388. X    i = j = 0;
  389. X    while ( s[i] != 0 && i < lim ){
  390. X        done = 0;
  391. X        while ( ! done && j <= lim ){
  392. X            if ( isawhite(s[j]) ){
  393. X                /* chase down remaining white space */
  394. X                for (k=j; k<=lim && s[k] && isawhite(s[k]);k++){
  395. X                    ;
  396. X                }
  397. X                n = isagroup(&s[i], j-i);
  398. X                if ( n >= 0 ){
  399. X                    switch ( groups[n].status ){
  400. X                    case NVAR:    r = (groups[n].index + 1
  401. X                            + rnd(groups[n].count));
  402. X                    expand(data[r],strlen(data[r]),grp);
  403. X                        outstring(&s[j],k-j,grp);
  404. X                            break;
  405. X                    case AVAR:
  406. X                        /* only the first one counts */
  407. X                        r = groups[n].index + 1;
  408. X                expand(data[r],strlen(data[r]),&groups[n]);
  409. X                            groups[n].status=DVAR;
  410. X                            /* fall through */
  411. X                    case DVAR:
  412. X/*
  413. X * Call outstring for groups[n].buf, then for the white space between j and k 
  414. X */
  415. X                        outstring(groups[n].buf,
  416. X                        strlen(groups[n].buf),grp);
  417. X                        outstring(&s[j], k-j,grp);
  418. X                            break;
  419. X                    case OBUF:
  420. X                    printf("This shouldn't happen.\n");
  421. X                            break;
  422. X                    }
  423. X                } else {
  424. X                        outstring(&s[i], k-i, grp);
  425. X                }
  426. X                done++;
  427. X                i = j = k; /* should be on next word, if any */
  428. X            }
  429. X            j++;
  430. X        }
  431. X    }
  432. X}
  433. X
  434. X/*
  435. X *    Return index into groups[] array if a group name, -1 if just a word.
  436. X *    We have to use gbuf, a seperate place, so that we can null-terminate
  437. X *    the string where we want.  Otherwise it wouldn't know santa from
  438. X *    santana.
  439. X */
  440. Xisagroup(s,lim)
  441. Xchar s[];
  442. Xint lim;
  443. X{
  444. X    register int i;
  445. X    static char gbuf[BIGBUF];
  446. X
  447. X    strncpy(gbuf,s,lim);
  448. X    gbuf[lim] = '\0';    /* strncpy might not do this */
  449. X    for(i=0; i<ngroups; i++ ){
  450. X        if (groups[i].name && strcmp(gbuf,groups[i].name) == 0){
  451. X            return i;    /* hit */
  452. X        }
  453. X    }
  454. X    return -1;    /* fail */
  455. X}
  456. X
  457. X/*
  458. X *     Output string, handling splices
  459. X */
  460. Xoutstring(s,lim,grp)
  461. Xchar s[];    /* from */
  462. Xint lim;
  463. Xstruct gstruct *grp; /* to */
  464. X{
  465. X    register int i = 0;
  466. X    register char *p;
  467. X    int boff;
  468. X
  469. X    p = grp->bptr;
  470. X    while ( s[i] != '\0' && i < lim ){
  471. X        if ( p == grp->lim ){
  472. X            *p = '\0';    /* terminate with extreme prejudice */
  473. X            if (grp->status == OBUF){
  474. X                flushbuf(grp->buf);    /* time to flush! */
  475. X                p = grp->buf;        /* reset pointer */
  476. X            } else {
  477. X                /* make more room for variable */
  478. X                boff = p - grp->buf;
  479. X                grp->bufsiz += MYBUFSIZ;
  480. X                if((grp->buf=(char *) realloc(grp->buf,
  481. X                    sizeof(char) * grp->bufsiz))==NULL){
  482. X                    perror("outstring: could not realloc");
  483. X                    exit(1);
  484. X                }
  485. X                p = grp->buf + boff;    /* put this back */
  486. X            }
  487. X        }
  488. X        switch (s[i]){
  489. X        case '|':
  490. X                if ( s[i+1] == '\\' ){
  491. X                    *p = '\\';    /* special case:     */
  492. X                    i++;        /* |\ outputs a \    */
  493. X                    p++;
  494. X                    break;    
  495. X                }
  496. X                break;    /* splice: no output */
  497. X        case '\\':
  498. X                *p = '\n';
  499. X                p++;
  500. X                break;
  501. X        default:
  502. X                *p = s[i];
  503. X                p++;
  504. X                break;
  505. X        }
  506. X        i++;
  507. X    }
  508. X    grp->bptr = p;    /* catch up on the current state of things */
  509. X}
  510. X
  511. X/*
  512. X *     Return random number 0 to limit
  513. X */
  514. Xrnd(limit)
  515. Xint limit;
  516. X{
  517. X    if (limit > 0){
  518. X        return (random() % limit);
  519. X    }
  520. X    return 0;    /* better than a floating exception if lim == 0 */
  521. X}
  522. X
  523. Xa_random_number()
  524. X{
  525. X    struct timeval tp;
  526. X    struct timezone tzp;
  527. X
  528. X    gettimeofday (&tp, &tzp);
  529. X
  530. X    return((getpid() ^ tp.tv_usec) % 123456);
  531. X}
  532. X
  533. X/*
  534. X *    Return 1 if one of our "white" characters.  A white character is
  535. X *    any character which can bound a group name, so punctuation marks
  536. X *    are included.
  537. X */
  538. Xisawhite(c)
  539. Xchar c;
  540. X{
  541. X    if (    c == '\0' ||        /* traditional white space */
  542. X        c == ' '  ||
  543. X        c == '\t' ||
  544. X        c == '|'  ||        /* "splice" character */
  545. X        c == '\\' ||        /* becomes a newline */
  546. X        c == '.'  ||        /* common punctuation */
  547. X        c == '-'  ||
  548. X        c == ':'  ||
  549. X        c == ';'  ||
  550. X        c == ','  ||
  551. X        c == '!'  ||
  552. X        c == '?'  ||
  553. X        c == '['  ||
  554. X        c == ']'  ||
  555. X        c == '{'  ||
  556. X        c == '}'  ||
  557. X        c == '('  ||
  558. X        c == ')'  ||
  559. X        c == '\'' ||
  560. X        c == '\"' ||
  561. X        c == '`'
  562. X    )
  563. X        return 1;
  564. X    return 0;
  565. X}
  566. X/*
  567. X *    Flush everything in a buffer to stdout
  568. X *    (Really just puts() without the '\n' on the end)
  569. X */
  570. Xflushbuf(s)
  571. Xregister char *s;
  572. X{
  573. X    register int c;
  574. X
  575. X    while (c = *s++)
  576. X        putchar(c);
  577. X}
  578. *-*-END-of-ncode.c-*-*
  579. echo x - ncode.1
  580. sed 's/^X//' >ncode.1 <<'*-*-END-of-ncode.1-*-*'
  581. X.TH NCODE 1 "Pixar"    
  582. X.SH NAME
  583. Xncode  - stochastic text construction
  584. X.SH SYNOPSIS
  585. X.B ncode [-n number] [-g groupname] codefile
  586. X.SH DESCRIPTION
  587. X.I Ncode
  588. Xreads in a file of a certain format and randomly constructs text based on
  589. Xthe organization of the file.  Other files may be recursively included by
  590. Xputting
  591. X
  592. X.nf
  593. X    #include pathname
  594. X.fi
  595. X
  596. Xon any line of the file.  This is useful when
  597. Xyou want to use a file of basic definitions, or groups, in different
  598. Xconfigurations.
  599. X
  600. XComments are lines which begin with a "#" but which are not #include lines.
  601. X
  602. XThe -n flag is used to run the program through the main loop multiple times.
  603. X
  604. XThe -g flag allows you to start the expanding process on a group name other
  605. Xthan the default, which is "CODE".  The argument may be a group name, or an
  606. Xentire string including group names, just as if it were a line in the file.
  607. XIt is legal to start on any group in the file, and groups may be referenced
  608. Xbefore or after the place in the file where they are defined.  In the case of
  609. Xduplicate group definitions, the first one occurring is the only one used.
  610. X
  611. XA "group" name is defined as the word on the first line of the file and, more
  612. Xcommonly, the word on each line following a line starting with "%".  The members
  613. Xof a group are all lines between the group name and the next "%".  When a
  614. Xgroup name is encountered, surrounded by any of a set of characters called
  615. X"white space" in this context, it is randomly expanded into one of its members.
  616. XGroup names are not allowed to contain any white space, to prevent terminal
  617. Xconfusion on the part of the program.
  618. X
  619. X
  620. XFor example, here is a sample group definition:
  621. X
  622. X.nf
  623. X    NOUN
  624. X    lamp
  625. X    house
  626. X    car
  627. X    %
  628. X.fi
  629. X
  630. XThe line "See the NOUN." could be randomly expanded to say "See the lamp."
  631. X
  632. XSpecial "variable" groups are those with a "*" as the last character of the
  633. Xgroup name.  The first (which should be the only) member of the group will
  634. Xbe recursively expanded only once.  All subsequent references to that group
  635. Xwill produce the same string.  For example, a group may be defined as
  636. X
  637. X.nf
  638. X    NOUN1*
  639. X    NOUN
  640. X%
  641. X.fi
  642. X
  643. XThe line "She said that his NOUN1 was a very fine NOUN1 indeed." would be
  644. Xexpanded into something such as "She said that his car was a very fine
  645. Xcar indeed."
  646. X
  647. XThe characters considered "white" for the purpose of bounding a group name,
  648. Xbesides what is normally considered white space, are currently: 
  649. X
  650. X    | \\ .  - : ; , ! ? [ ] { } () ' " `
  651. X
  652. XTwo of those characters have special meanings to
  653. X.I ncode.
  654. XThe "|" symbol allows you to "splice" things to a group name.  When it is
  655. Xencountered, no character is printed on output.  The "\\" causes a newline
  656. Xto be printed on output.  If you want a "\\" to appear on output, use a
  657. Xsplice, as in "|\\".
  658. X
  659. XThe simplest application would be for a "fortune" program, but
  660. X.I ncode
  661. Xcould also be used for more complex things such as a rumor generating file.
  662. XThe group definitions will be left as an exercise for the reader, but the
  663. Xfollowing example should prove illuminating:
  664. X
  665. X.nf
  666. XCODE
  667. XIt was rumored today that COMPANY will be bought by COMPANY for PRICE\\.
  668. XPERSON, POSITION of COMPANY, said that PRODUCT will be announced DATE\\.
  669. X.fi
  670. X
  671. XNote that every string to be expanded must be on only one line of the file.
  672. XThe program now dynamically allocates memory in a very general (if not
  673. Xoptimum) way, so you are really limited only by how much memory you can get
  674. Xand how deep your stack can go.  The only hard limit is that
  675. Xa group name can't be over 4096 characters long.  If you can't come up
  676. Xwith a unique group name in fewer characters than that then you shouldn't
  677. Xbe allowed to play with computers.
  678. X
  679. X.SH BUGS
  680. XNo bugs.  Only features that you haven't figured out how to use yet.
  681. XA recent improvement makes it tolerant of blank lines following the last %
  682. Xin a #include file.
  683. X.SH DIAGNOSTICS
  684. XStandard perror() stuff.  Pretty self explanatory.  A bogus input file might
  685. Xbenignly yield cryptic results.  If you see just the string "CODE" as output
  686. Xyou probably don't have what you think you have in your input file.
  687. X.SH AUTHOR
  688. XCraig Good
  689. *-*-END-of-ncode.1-*-*
  690. echo x - poetry.n
  691. sed 's/^X//' >poetry.n <<'*-*-END-of-poetry.n-*-*'
  692. X# Here's an example of one of those "variable" groups.
  693. X# The * means that it will be expanded only once.  Note that this group
  694. X# has only one member.  Additional members would be ignored, so just leave
  695. X# them off.  You may have also noticed that ncode now supports comments.
  696. XNOUNE*
  697. XNOUN
  698. X%
  699. XNOUNW*
  700. XNOUN
  701. X%
  702. XNOUN
  703. XNorth
  704. XSouth
  705. XEast
  706. XWest
  707. XTruth
  708. Xgrass
  709. Xdesk
  710. Xwall
  711. Xwindow
  712. Xceiling
  713. Xfloor
  714. Xcar
  715. Xsign
  716. X%
  717. XNUMBER
  718. Xone
  719. Xtwo
  720. Xtwo
  721. X3.1415927
  722. Xthree
  723. Xeleven
  724. Xa googol
  725. X%
  726. XVERB
  727. Xmeet
  728. Xknock
  729. Xkiss
  730. Xhug
  731. Xtrot
  732. Xmiss
  733. Xnod
  734. Xwink
  735. Xhit
  736. Xwalk
  737. Xfly
  738. Xzip
  739. Xsmash
  740. Xsniff
  741. X%
  742. XFLOWERS
  743. XRoses
  744. XViolets
  745. XChrysanthemums
  746. XDaisies
  747. XGardenias
  748. XStinkweeds
  749. XPetunias
  750. X%
  751. XCOLOR
  752. Xpuce
  753. Xinvisible
  754. Xred
  755. Xtan
  756. Xwhite
  757. Xblue
  758. Xgreen
  759. Xmuave
  760. Xpurple
  761. Xchartreuse
  762. Xblack
  763. Xyellow
  764. X%
  765. XSOMETHING
  766. XI am
  767. XSugar is
  768. XRadiation is
  769. XComputing is
  770. XNitrous Oxide is
  771. XANIMALS are
  772. XAUTHOR_ANY is
  773. XYou are
  774. X%
  775. XPROPERTY
  776. Xfearful
  777. Xliberal
  778. Xconservative
  779. Xsexy
  780. Xschizophrenic
  781. Xsweet
  782. Xbitter
  783. Xstupid
  784. Xugly
  785. Xhilarious
  786. Xslow
  787. Xmiserable
  788. X%
  789. XISYOU
  790. Xare you.
  791. Xis this.
  792. Xam I.
  793. Xis Maple Surple.
  794. Xis it.
  795. Xit is.
  796. Xare they.
  797. X...who cares?
  798. X%
  799. XHAND
  800. Xmouth
  801. Xhand
  802. Xhand
  803. Xeye
  804. Xeye
  805. Xnose
  806. Xear
  807. Xtooth
  808. Xfoot
  809. X%
  810. XAUTHOR_A
  811. XDavid Johansen
  812. XCraig Good
  813. XMichael Jackson
  814. XWally
  815. XSpock
  816. XGidget
  817. XBambi
  818. XDracula
  819. XSuperman
  820. XKahn
  821. XBullwinkle
  822. XBo Derek
  823. XKoo Stark
  824. XLady Diana
  825. XRoy Rogers
  826. XBugs Bunny
  827. XJames Bond
  828. XGodzilla
  829. XKilroy
  830. XThe Emperor
  831. XSweeny Todd
  832. XKate Bush
  833. X%
  834. XAUTHOR_AN
  835. XAnonymous
  836. XAndre
  837. XAlvy Ray Smith
  838. XEd Catmull
  839. X%
  840. XAUTHOR_ANY
  841. XAUTHOR_AN
  842. XAUTHOR_A
  843. XAUTHOR_A
  844. XFOX
  845. XFOX
  846. XFOX
  847. X%
  848. XANIMAL_A
  849. XBird
  850. XSnail
  851. XPanda
  852. XFishy
  853. XDoggy
  854. XPuppy
  855. XTiger
  856. XKitty
  857. XWorm
  858. XKangaroo
  859. XWart Hog
  860. XPenguin
  861. XPolar Bear
  862. XParakeet
  863. XCat
  864. XMountain Goat
  865. XMoose
  866. XMouse
  867. X%
  868. XANIMAL_AN
  869. XEgret
  870. XAardvark
  871. XEmu
  872. XElephant
  873. X%
  874. XANIMAL_ANY
  875. XANIMAL_AN
  876. XANIMAL_A
  877. XANIMAL_A
  878. XANIMAL_A
  879. X%
  880. XANIMAL_TIG*
  881. XANIMAL_ANY
  882. X%
  883. XANIMALS
  884. XBirds
  885. XSnails
  886. XPandas
  887. XFish
  888. XDogs
  889. XPuppies
  890. XTigers
  891. XKittens
  892. XAardvarks
  893. XWorms
  894. XKangaroos
  895. XWart Hogs
  896. XPenguins
  897. XPolar Bears
  898. XParakeets
  899. XCats
  900. XMountain Goats
  901. XMooses
  902. XMice
  903. X%
  904. XROYALTY
  905. XPrince
  906. XKing
  907. XBoss
  908. XProgrammer
  909. XHacker
  910. XSalesman
  911. XHead Hunter
  912. X%
  913. XMITS
  914. Xknickers
  915. Xarm bands
  916. Xmittens
  917. Xsunglasses
  918. Xcowboy boots
  919. Xgaloshes
  920. X%
  921. XHURT
  922. Xhurt
  923. Xhurt
  924. Xkill
  925. Xslap
  926. Xdeoderize
  927. Xbreak
  928. Xzap
  929. Xvaporize
  930. Xirradiate
  931. Xbother
  932. X%
  933. XSTICKS
  934. XSticks
  935. XStones
  936. XBullets
  937. XBombs
  938. XCroissants
  939. XKeyboards
  940. X%
  941. XFOREST
  942. Xball park
  943. Xforest
  944. Xswamp land
  945. Xjungle
  946. Xghetto
  947. Xdrug store
  948. Xoffice
  949. X%
  950. XPLACE
  951. Xgarage
  952. Xoven
  953. Xbush
  954. Xbush
  955. XFOREST
  956. X%
  957. XTREE
  958. Xa tree
  959. XFOX's knee
  960. XFOX's knee
  961. XFOX's knee
  962. XFOX's knee
  963. X%
  964. XPROVERB
  965. XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the twain shall meet.\
  966. XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the twain shall VERB.\
  967. XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the twain shall VERB.\
  968. XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the ANIMAL_ANY shall VERB.\
  969. XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the ANIMAL_ANY shall VERB.\
  970. XNOUNE is NOUNE, and NOUNW is NOUNW,\and never the ANIMAL_ANY shall VERB.\
  971. XA ANIMAL_A is as good as a FOREST to AUTHOR_ANY.\
  972. XA ANIMAL_A is as good as a FOREST to AUTHOR_ANY.\
  973. XAn ANIMAL_AN is as good as a FOREST to AUTHOR_ANY.\
  974. XA HURT is as good as a VERB to a ANIMAL_A.\
  975. XA HURT is as good as a VERB to an ANIMAL_AN.\
  976. XA HURT is as good as a VERB to a ANIMAL_A.\
  977. XA HURT is as good as a VERB to an ANIMAL_AN.\
  978. XA VERB is as good as a HURT to AUTHOR_ANY.\
  979. XA VERB is as good as a HURT to AUTHOR_ANY.\
  980. XFLOWERS and MITS\May HURT my bones,\But AUTHOR_ANY will never VERB me.\
  981. XSTICKS and ANIMALS\May HURT my bones,\But FLOWERS will never HURT me.\
  982. XFLOWERS and STICKS\May HURT my bones,\But MITS will never HURT me.\
  983. XSTICKS and STICKS\May HURT my bones,\But ANIMALS will never VERB me.\
  984. XNever VERB today what you can HURT tomorrow.
  985. XNever VERB today what you can HURT tomorrow.
  986. XNever HURT today what you can VERB tomorrow.
  987. XA ANIMAL_A in the HAND is worth NUMBER in the PLACE.
  988. XAn ANIMAL_AN in the HAND is worth NUMBER in the PLACE.
  989. XA ANIMAL_A in the HAND is worth NUMBER in the PLACE.
  990. XAn ANIMAL_AN in the HAND is worth NUMBER in the PLACE.
  991. XA AUTHOR_A in the HAND is worth NUMBER in the PLACE.
  992. XAn AUTHOR_AN in the HAND is worth NUMBER in the PLACE.
  993. XNever look a gift ANIMAL_ANY in the mouth.
  994. XDead ANIMALS aren't much fun.
  995. X%
  996. XVERSE
  997. XANIMAL_TIG, ANIMAL_TIG, burning bright\In the FOREST of the night\What immortal HAND or HAND\Dare frame thy PROPERTY symmetry?\
  998. XFLOWERS are COLOR,\FLOWERS are COLOR,\SOMETHING PROPERTY,\And so ISYOU\
  999. XHark!  Hark!\The ANIMALS do bark!\The ROYALTY is fond of ANIMALS\He likes to take their insides out\And wear them as his MITS.\
  1000. XI think that I shall never see\A thing as lovely\As TREE.\
  1001. X%
  1002. XTITLE
  1003. X        "Why AUTHOR_ANY tried to HURT the ANIMAL_ANY"
  1004. X        "The day AUTHOR_ANY wanted to HURT the ANIMAL_ANY"
  1005. X            "ANIMALS"
  1006. X            "FLOWERS"
  1007. X        "The PROPERTY ANIMAL_ANY"
  1008. X        "The PROPERTY FLOWERS"
  1009. X        "Ode to AUTHOR_ANY"
  1010. X        "I'm so COLOR without my ANIMAL_ANY"
  1011. X        "Ode to the ANIMAL_ANY"
  1012. X        "I'm dreaming of a COLOR Christmas"
  1013. X        "I Love The FLOWERS"
  1014. X            "Dead ANIMALS"
  1015. X%
  1016. XCODE
  1017. X\PROVERB\\            --AUTHOR_ANY\
  1018. X\PROVERB\\            --AUTHOR_ANY\
  1019. X\VERSE\\            --AUTHOR_ANY\
  1020. X\VERSE\\            --AUTHOR_ANY\
  1021. X\TITLE\\VERSE\\            --AUTHOR_ANY\
  1022. X%
  1023. X#
  1024. X# These #include lines can happen anywhere in the file.  Note that you do
  1025. X# not use quotes around the pathname.
  1026. X#
  1027. X#include foxes.n
  1028. *-*-END-of-poetry.n-*-*
  1029. echo x - foxes.n
  1030. sed 's/^X//' >foxes.n <<'*-*-END-of-foxes.n-*-*'
  1031. X# Save this file as "foxes" to be #included in other files
  1032. XFOX
  1033. XAlexandra Paul
  1034. XAmanda Pays
  1035. XAmy Irving
  1036. XAppollonia
  1037. XApril Wayne
  1038. XBarbara Hershey
  1039. XBrooke Adams
  1040. XCat
  1041. XCathleen Collins
  1042. XCindy Crawford
  1043. XCarly Simon
  1044. XCarol Alt
  1045. XCassandra Peterson
  1046. XCatherine Mary Stewart
  1047. XCathy Tyson
  1048. XCheryl Tiegs
  1049. XChristie Brinkley
  1050. XCoco Mitchell
  1051. XCourteney Cox
  1052. XCynthia Rhodes
  1053. XCybill Shepherd
  1054. XDaphne Zuniga
  1055. XDarryl Hannah
  1056. XElizabeth McGovern
  1057. XElle Macpherson
  1058. XErin Grey
  1059. XFarrah Fawcett Majors
  1060. XFawn Hall
  1061. XFrederique
  1062. XHeather Locklear
  1063. XHeather Thomas
  1064. XIman
  1065. XJaclyn Smith
  1066. XJamie Lee Curtis
  1067. XJane Seymour
  1068. XJanet Jones
  1069. XJenna de Rosnay
  1070. XJennifer Beales
  1071. XJenny Seagrove
  1072. XJill Goodacre
  1073. XJody Watley
  1074. XJohann Carlo
  1075. XJulie Wolfe
  1076. XKaren Alexander
  1077. XKate Capshaw
  1078. XKate Jackson
  1079. XKathy Ireland
  1080. XKelly Emberg
  1081. XKelly LeBrock
  1082. XKim Alexis
  1083. XKim Basinger
  1084. XKoo Stark
  1085. XLaura Antonelli
  1086. XLauren Hutton
  1087. XLea Thompson
  1088. XLisa Bonet
  1089. XLisa Hartman
  1090. XMarkie Post
  1091. XMarlee Matlin
  1092. XMaryam d'Abo
  1093. XMeg Ryan
  1094. XMelanie Griffith
  1095. XMichelle Pfieffer
  1096. XMelissa Gilbert
  1097. XMonika Schnarre
  1098. XNastasia Kinski
  1099. XOla Ray
  1100. XOlivia Newton John
  1101. XPamela Sue Martin
  1102. XPatty Owen
  1103. XPaulina Porizkova
  1104. XPhoebe Cates
  1105. XRachel Ward
  1106. XRae Dawn Chong
  1107. XRenee Simonsen
  1108. XRosanna Arquette
  1109. XSade
  1110. XSela Ward
  1111. XSheila E
  1112. XShelly Hack
  1113. XSigney Coleman
  1114. XSuzee Pai
  1115. XStephanie Seymour
  1116. XStevie Nicks
  1117. XTahnee Welch
  1118. XTanya Roberts
  1119. XTheresa Russell
  1120. XTish Campbell
  1121. XTraci Wolfe
  1122. XVictoria Principal
  1123. XVivian Ruiz
  1124. XWhitney Houston
  1125. X%
  1126. *-*-END-of-foxes.n-*-*
  1127. exit
  1128. ----------------------------- cut here --------------------------------
  1129. (delete from here down)
  1130.  
  1131. Have fun!
  1132.  
  1133. -- 
  1134.         --Craig
  1135.         ...{ucbvax,pyramid,sun}!pixar!good
  1136.  
  1137.  
  1138.