home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume2 / ncode < prev    next >
Internet Message Format  |  1991-08-07  |  26KB

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