home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume7 / names_jrk < prev    next >
Text File  |  1989-08-07  |  20KB  |  749 lines

  1. Newsgroups: comp.sources.misc
  2. organization: University of East Anglia, Norwich
  3. subject: v07i124: random names generator
  4. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5. Reply-To: jrk@sys.uea.ac.uk (Richard Kennaway)
  6.  
  7. Posting-number: Volume 7, Issue 124
  8. Submitted-by: jrk@sys.uea.ac.uk (Richard Kennaway)
  9. Archive-name: names_jrk
  10.  
  11. This is names.c, a program for generating random names for FRP characters.
  12. Unlike many other such programs, this one will generate names to match
  13. any language you like.  Feed it with text in that language, and it will
  14. generate words statistically similar to the input text.  For example,
  15. here is some of the output it gives when fed with the Sindarin words
  16. from a Sindarin-English dictionary:
  17.  
  18.     annun ossen bered lamedo tolbrandirithron meregil arad doriel
  19.     lothrond nim min rohir carch menel caradan uil las tolbrant arahad
  20.     dol egalen rhiw iath remmen celeth arveduin elwing benn min forlan
  21.     uil angborn morgai arad torn dain char thond toreth anfaladel
  22.  
  23. As you can see, not all the output is directly usable, but by
  24. exercising some selection you can obtain results like:
  25.  
  26.     Ossiriel, Eredhel, Belain, Minarwen, Gwathlain, Gundaer,
  27.     Suldor Belebrethand, Berielegor, Gwairithir, Gaurgor, Nardol,
  28.     Sammathremmir,...
  29.  
  30. For comparison, here's some output from the food-and-drink section of a
  31. German phrasebook :-):
  32.  
  33.     kursch rhampelebans prottelm tradivier en bohl sauber arnen men
  34.     rautt kabbeer banineln stetschahn blummeloneulen sarneclacher
  35.     men chwarschen aal raustdorelone en garscht karadie blat raube
  36.     sch kirschte protten flen mohl arderben audelspinguse trauchel
  37.  
  38. Runs on Macintosh (if you have MPW) and Unix.
  39. Public domain.  Share and enjoy.
  40.  
  41. --
  42. Richard Kennaway          SYS, University of East Anglia, Norwich, U.K.
  43. uucp:  ...mcvax!ukc!uea-sys!jrk        Janet:  kennaway@uk.ac.uea.sys
  44.  
  45. -----cut-----cut-----cut-----cut-----cut-----cut-----cut-----cut-----cut-----
  46. #! /bin/sh
  47. # This is a shar archive.  "sh" it to unpack.
  48. # Contents: names.1 Makefile names.c
  49. echo x - names.1
  50. sed 's/^X//' >names.1 <<'*-*-END-of-names.1-*-*'
  51. X.TH NAMES 1 "August 1989"
  52. X.UC
  53. X.SH NAME
  54. Xnames \- generate random names
  55. X.SH SYNOPSIS
  56. X.B names
  57. X[
  58. X.B \-3
  59. X] [
  60. X.BR \-w\ |\ \-s
  61. X] [
  62. X.B -l
  63. X.I nnn
  64. X] [
  65. X.I files
  66. X]
  67. X.SH DESCRIPTION
  68. X.I Names
  69. Xis a random name generator.
  70. XIt will read text from standard input or from files given on the
  71. Xcommand line, and generate a random stream of words whose statistical
  72. Xcharacteristics are similar to those of the input.
  73. XThus if you give it a database of Elvish names, it will generate Elvish-like
  74. Xnames; if a database of Orcish names, it generates Orc-like names, etc.
  75. X.PP
  76. XIt does this by counting the frequency of all 1-, 2-, 3-, and 4-character
  77. Xsequences of letters or spaces in the input.
  78. XCase is ignored, and all runs of non-letters are seen as single spaces.
  79. XThe first character to be output, say "a",
  80. Xis generated according to the relative frequencies
  81. Xwith which each character was found to follow a space in the input.
  82. XThe second, say "b", is generated according to the relative frequencies with
  83. Xwhich each character can appear following the digraph " a".
  84. XThe third is generated according to the relative frequencies with which
  85. Xeach character follows the trigraph " ab".
  86. XAnd so on ad infinitum, each new character depending on the previous three.
  87. X.PP
  88. XThe larger the input, the better.
  89. XIt needs at least a few thousand bytes of input for useful results.
  90. XIf the input is not large enough,
  91. Xyou will tend to get words from the input appearing verbatim in the
  92. Xoutput, as much of the time three consecutive characters will uniquely
  93. Xdetermine the next character.
  94. XIf more input of the desired form is not available, the program can be
  95. Xmade to use a third-order approximation instead, each character of the
  96. Xoutput depending only on the two preceding characters.  This is also
  97. Xuseful if there is not enough memory to construct the tetragraph
  98. Xtable, which occupies just over half a megabyte.
  99. X.PP
  100. XThe output is wrapped to 76 chars maximum, hyphenating any word
  101. Xthat has to be broken over a line-end.
  102. X.PP
  103. X.I Names
  104. Xwill run on Unix, and on a Macintosh as an MPW shell tool.
  105. X.SH OPTIONS
  106. X.TP
  107. X.B \-w
  108. XGenerate successive words independently,
  109. Xi.e. each word begins as if it was the beginning of the whole output,
  110. Xignoring how the preceding word ended.  (Default.)
  111. X.TP
  112. X.B \-s
  113. XNegation of
  114. X.B \-w
  115. Xoption.
  116. XThe first character of each word will depend on the last three characters
  117. Xgenerated (i.e. the last two characters of the preceding word,
  118. Xand the inter-word space).
  119. X.TP
  120. X.B \-l nnn
  121. XGenerate nnn lines of output.  Default is 20.
  122. XNo space between the \-l and the nnn.
  123. XIf \-l is given with no argument, the output will go on (nearly) forever.
  124. X.TP
  125. X.B \-3
  126. XUse trigraph frequencies instead of tetragraph frequencies.
  127. XGives better results when input data is limited.
  128. XThis option will automatically be used if there is insufficient memory
  129. Xto build the tetragraph table (a warning will be given).
  130. X.SH DIAGNOSTICS
  131. X.I Names
  132. Xgives a usage message if the arguments are bad.
  133. XExits with status 0 if all went well.
  134. XExits with status 1 if there were bad arguments (other than non-existent
  135. Xfiles), or insufficient memory for even trigraph tables.
  136. XNo names are generated.
  137. XOtherwise, exits with status 2 if any files were not found
  138. X(however, it will read all the files it could find and generate names).
  139. X.PP
  140. XWrites to stderr a count of the characters read
  141. X(i.e. letters and runs of non-letters).
  142. X.PP
  143. XIf compiled with SHOWTABLE defined,
  144. Xdumps the 0th to 3rd order tables to standard output
  145. Xbefore the random names.
  146. X.SH LIMITATIONS
  147. XThe tetragraph counts are limited to 255 maximum,
  148. Xthe trigraph and digraph counts to 65535,
  149. Xand the total number of characters read to 4294967295.
  150. X(The counts stick at their maximum values if they are reached,
  151. Xthey do not overflow.)
  152. X.SH FURTHER IDEAS
  153. XA more compact form of the tetragraph tables could be used.
  154. XThis would allow the use of a larger character set (e.g. accented letters,
  155. Xwhich play a large part in the Elvish languages).
  156. X.PP
  157. XArrange to write the tetragraph tables to a file
  158. Xand read them in again, to avoid having to reconstruct them
  159. Xevery time.  Use some sort of compression to keep the file size down.
  160. X(Run-length encoding might do - most of the entries will be zero.)
  161. X.PP
  162. XWhen insufficient input is available for good fourth-order generation,
  163. Xinstead of using trigraph statistics a better way of improving the output
  164. Xmight be to fudge the tetragraph frequencies a little.  Wherever a trigraph is
  165. Xfound with only one possible successor, choose some other letter
  166. Xand make its frequency nonzero.  Make the choice based on some
  167. Xnotion of similarity among letters.  Such a notion should not
  168. Xbe defined a priori, but based on the statistics of the input.
  169. X.SH AUTHOR
  170. XRichard Kennaway.
  171. X.PP
  172. Xjrk@uk.ac.uea.sys (JANET), ...mcvax!uea-sys!jrk (UUCP).
  173. X.PP
  174. XThis program is public domain.
  175. XDon't bother telling me the code could be improved, I know.
  176. XBy all means tell me of any improvements you make.
  177. *-*-END-of-names.1-*-*
  178. echo x - Makefile
  179. sed 's/^X//' >Makefile <<'*-*-END-of-Makefile-*-*'
  180. Xnames : names.c
  181. X    cc names.c -o names
  182. *-*-END-of-Makefile-*-*
  183. echo x - names.c
  184. sed 's/^X//' >names.c <<'*-*-END-of-names.c-*-*'
  185. X/* names.c */
  186. X/* Random name generator */
  187. X
  188. X/* Richard Kennaway */
  189. X/* JANET:  jrk@uk.ac.uea.sys */
  190. X/* UUCP:   ...mcvax!uea-sys!jrk */
  191. X
  192. X/* August 1989 */
  193. X/* Public domain! */
  194. X
  195. X
  196. X#define FALSE  0
  197. X#define TRUE   1
  198. X
  199. X/* Choose one... */
  200. X#define UNIX   TRUE    /* Version for Unix */
  201. X#define MPW    FALSE   /* Version for Apple MacIntosh (MPW C) */
  202. X
  203. X
  204. X/* System stuff */
  205. X
  206. X#include <stdio.h>
  207. X
  208. Xtypedef char int8;
  209. Xtypedef unsigned char uint8;
  210. Xtypedef short int16;
  211. Xtypedef unsigned short uint16;
  212. Xtypedef long int32;
  213. Xtypedef unsigned long uint32;
  214. X
  215. X#define MAXUINT8        ((uint8) ((int8) (-1)))
  216. X#define MAXUINT16        ((uint16) ((int16) (-1)))
  217. X#define MAXUINT32        ((uint32) ((int32) (-1)))
  218. X
  219. X#if MPW
  220. X#include <QuickDraw.h>    /* need this for random numbers */
  221. X#endif
  222. X#if UNIX
  223. X#define Boolean        int
  224. Xint32 random();
  225. X#define Random()    ((int16) (random()))
  226. X#endif
  227. X
  228. X#if MPW
  229. X#define NEWLINECHAR     '\r'
  230. X#endif
  231. X#if UNIX
  232. X#define NEWLINECHAR     '\n'
  233. X#endif
  234. X
  235. X#define EOFCHAR     (-1)
  236. X
  237. Xchar *malloc();
  238. X
  239. X
  240. X/* Parameters stuff */
  241. X
  242. Xint Argc;
  243. Xchar **Argv;
  244. Xint ExitStatus = 0;
  245. X
  246. Xint16 CurFile;
  247. XBoolean FileArgs = FALSE;
  248. X
  249. XBoolean Big = TRUE, SeparateWords = TRUE;
  250. X
  251. X#define BREAK1        60
  252. X#define BREAK2        75
  253. X
  254. Xint16 Column = 0;
  255. Xuint32 Lines = 0;
  256. X#define DEFAULTMAXLINES        20
  257. Xuint32 MaxLines = DEFAULTMAXLINES;
  258. X
  259. X
  260. X/* Tables */
  261. X
  262. X#define MAXINDEX        27
  263. X#define SPACEINDEX      26
  264. X#define T4SIZE        (MAXINDEX*MAXINDEX*MAXINDEX*MAXINDEX)
  265. X
  266. Xuint16 chartable[256];
  267. X#define indextable(c)   ((c)==(-1) ? NEWLINECHAR : \
  268. X                         (c)==SPACEINDEX ? ' ' : \
  269. X                         ((c)+'a') \
  270. X                        )
  271. X
  272. Xuint32 table0 = 0, *table1 = NULL;
  273. Xuint16 **table2 = NULL, ***table3 = NULL;
  274. Xuint8 *table4 = NULL;
  275. X
  276. X
  277. X/* Memory allocation */
  278. X
  279. Xnomemory()
  280. X{
  281. X    fprintf( stderr, "Cannot get memory!%c", NEWLINECHAR );
  282. X    ExitStatus = 1;
  283. X    exit( ExitStatus );
  284. X}  /* nomemory() */
  285. X
  286. Xgetmemory()
  287. X{
  288. Xuint32 i, j, k;
  289. Xuint16 *t2, **t3, *tt3;
  290. X
  291. X    table1 = (uint32 *) malloc( MAXINDEX * sizeof(uint32) );
  292. X    if (table1==NULL) nomemory();
  293. X    table2 = (uint16 **) malloc( MAXINDEX * sizeof(uint16 *) );
  294. X    if (table2==NULL) nomemory();
  295. X    for (i=0; i<MAXINDEX; i++) {
  296. X        table2[i] = NULL;
  297. X    }
  298. X    table3 = (uint16 ***) malloc( MAXINDEX * sizeof(uint16 **) );
  299. X    if (table3==NULL) nomemory();
  300. X    for (i=0; i<MAXINDEX; i++) {
  301. X        table3[i] = NULL;
  302. X    }
  303. X
  304. X    if (Big) {
  305. X    table4 = (uint8 *) malloc( T4SIZE * sizeof(uint8) );
  306. X    if (table4==NULL) {
  307. X        Big = FALSE;
  308. X        fprintf( stderr, "Cannot get space for 4th-order generation - using 3rd-order instead.%c",
  309. X        NEWLINECHAR );
  310. X    }
  311. X    if (Big) for (i=0; i<T4SIZE; i++) table4[i] = 0;
  312. X    }
  313. X
  314. X    for (i=0; i<MAXINDEX; i++) {
  315. X        table1[i] = 0;
  316. X
  317. X        t2 = (uint16 *) malloc( MAXINDEX * sizeof(uint16) );
  318. X        if (t2==NULL) nomemory();
  319. X        table2[i] = t2;
  320. X
  321. X        t3 = (uint16 **) malloc( MAXINDEX * sizeof(uint16 *) );
  322. X        if (t3==NULL) nomemory();
  323. X        table3[i] = t3;
  324. X        for (j=0; j<MAXINDEX; j++) {
  325. X            t3[j] = NULL;
  326. X        }
  327. X        for (j=0; j<MAXINDEX; j++) {
  328. X            t2[j] = 0;
  329. X            tt3 = (uint16 *) malloc( MAXINDEX * sizeof(uint16) );
  330. X            if (tt3==NULL) nomemory();
  331. X            t3[j] = tt3;
  332. X            for (k=0; k<MAXINDEX; k++) {
  333. X                tt3[k] = 0;
  334. X        }
  335. X        }
  336. X    }
  337. X}  /* getmemory() */
  338. X
  339. Xfreememory()
  340. X{
  341. Xuint16 i, j, k;
  342. Xuint16 *t2, **t3, *tt3;
  343. X
  344. X    if (table1 != NULL) free( table1 );
  345. X    if (table2 != NULL) {
  346. X        for (i=0; i<MAXINDEX; i++) {
  347. X            if (table2[i] != NULL) free( table2[i] );
  348. X        }
  349. X        free( table2 );
  350. X    }
  351. X    if (table3 != NULL) {
  352. X        for (i=0; i<MAXINDEX; i++) {
  353. X            t3 = table3[i];
  354. X            if (t3 != NULL) {
  355. X                for (j=0; j<MAXINDEX; j++) {
  356. X                    if (t3[j] != NULL) free( t3[j] );
  357. X                }
  358. X                free( t3 );
  359. X            }
  360. X        }
  361. X        free( table3 );
  362. X    }
  363. X    if (table4 != NULL) free( table4 );
  364. X    table1 = NULL;
  365. X    table2 = NULL;
  366. X    table3 = NULL;
  367. X    table4 = NULL;
  368. X}  /* freememory() */
  369. X
  370. X
  371. X/* Preliminary setup */
  372. X
  373. Xmaketranstable()
  374. X{
  375. Xuint16 c;
  376. X
  377. X    for (c=0; c<256; c++) chartable[c] = SPACEINDEX;
  378. X    for (c='A'; c<='Z'; c++) chartable[c] = c-'A';
  379. X    for (c='a'; c<='z'; c++) chartable[c] = c-'a';
  380. X}  /* maketranstable() */
  381. X
  382. X
  383. X/* Input */
  384. X
  385. XBoolean openfile()
  386. X{
  387. XFILE *temp;
  388. X
  389. X    temp = freopen( Argv[CurFile], "r", stdin );
  390. X    if (temp == NULL) {
  391. X        fprintf( stderr, "%s: could not open file \"%s\"%c",
  392. X        Argv[0], Argv[CurFile], NEWLINECHAR );
  393. X    ExitStatus = 2;
  394. X    }
  395. X    return( temp != NULL );
  396. X}  /* Boolean openfile() */
  397. X
  398. XBoolean getnextfile()
  399. X{
  400. XFILE *temp;
  401. X
  402. X    while (((++CurFile) < Argc) && (! openfile())) { /* nothing */ }
  403. X    return( CurFile < Argc );
  404. X}  /* Boolean getnextfile() */
  405. X
  406. Xint16 getrawchar()
  407. X{
  408. Xint16 c;
  409. X    c = getchar();
  410. X    while ((c==EOFCHAR) && getnextfile()) {
  411. X        c = getchar();
  412. X    }
  413. X    return(c);
  414. X}  /* int16 getrawchar() */
  415. X
  416. X#define WASSPACE    0
  417. X#define WASNONSPACE 1
  418. X#define END         2
  419. Xint16 Where = WASSPACE;
  420. X
  421. Xint16 nextchar()
  422. X{
  423. Xint16 c, result;
  424. X
  425. X    switch (Where) {
  426. X        case WASSPACE:
  427. X            while (((c = getrawchar()) != EOFCHAR) &&
  428. X                   (chartable[c]==SPACEINDEX)) {
  429. X                /* nothing */
  430. X            }
  431. X            if (c==EOFCHAR) {
  432. X                Where = END;
  433. X                return(-1);
  434. X            } else {
  435. X                Where = WASNONSPACE;
  436. X                return(chartable[c]);
  437. X            }
  438. X        case WASNONSPACE:
  439. X            c = getrawchar();
  440. X            if (c==EOFCHAR) {
  441. X                Where = END;
  442. X                return(SPACEINDEX);
  443. X            } else {
  444. X                result = chartable[c];
  445. X                if (result==SPACEINDEX) Where = WASSPACE;
  446. X                return(result);
  447. X            }
  448. X        case END:
  449. X            return(-1);
  450. X    }
  451. X    return(-1);    /* Never happens. */
  452. X}  /* int16 nextchar() */
  453. X
  454. Xentergroup( a, b, c, d )
  455. Xint16 a, b, c, d;
  456. X{
  457. Xuint32 ind;
  458. XBoolean do_it;
  459. X
  460. X    if (table0 >= MAXUINT32) return;
  461. X    do_it = table1[a] < MAXUINT16;
  462. X    if (Big && do_it) {
  463. X    ind = (((((a*MAXINDEX) + b)*MAXINDEX) + c)*MAXINDEX) + d;
  464. X    do_it = table4[ind] < MAXUINT8;
  465. X    if (do_it) table4[ind]++;
  466. X    }
  467. X    if (do_it) {
  468. X    table0++;
  469. X    table1[a]++;
  470. X    table2[a][b]++;
  471. X    table3[a][b][c]++;
  472. X    }
  473. X}  /* entergroup( a, b, c, d ) */
  474. X
  475. Xbuildtable()
  476. X{
  477. Xint16 a0, b0, c0, a, b, c, d;
  478. X
  479. X    a0 = nextchar();
  480. X    b0 = nextchar();
  481. X    c0 = nextchar();
  482. X    if (c0 == -1) return;
  483. X    a = a0;  b = b0;  c = c0;
  484. X    while ((d = nextchar()) != (-1)) {
  485. X        entergroup( a, b, c, d );
  486. X    a = b;  b = c;  c = d;
  487. X    }
  488. X    if (c==SPACEINDEX) {
  489. X    entergroup( a, b, c, a0 );
  490. X    entergroup( b, c, a0, b0 );
  491. X    entergroup( c, a0, b0, c0 );
  492. X    } else {
  493. X    entergroup( a, b, c, SPACEINDEX );
  494. X    entergroup( b, c, SPACEINDEX, a0 );
  495. X    entergroup( c, SPACEINDEX, a0, b0 );
  496. X    entergroup( SPACEINDEX, a0, b0, c0 );
  497. X    }
  498. X}  /* buildtable() */
  499. X
  500. X
  501. X/* Dump the 0th to 3rd order tables.  Not the 4th-order! */
  502. X/* Only called if SHOWTABLE is defined at compile time. */
  503. X
  504. Xshowtable()
  505. X{
  506. Xuint16 i, j, k;
  507. Xuint16 *t2, **t3, *tt3;
  508. X
  509. X    for (i=0; i<MAXINDEX; i++) if (table1[i] != 0) {
  510. X        printf( "%c\t%lu%c\t\ttot", i+'a', table1[i], NEWLINECHAR );
  511. X        for (k=0; k<MAXINDEX; k++) {
  512. X            printf( "\t%c", k+'a' );
  513. X        }
  514. X        putchar( NEWLINECHAR );
  515. X        t2 = table2[i];
  516. X        t3 = table3[i];
  517. X        for (j=0; j<MAXINDEX; j++) if (t2[j] != 0) {
  518. X            printf( "\t%c\t%u", j+'a', t2[j] );
  519. X            tt3 = t3[j];
  520. X            for (k=0; k<MAXINDEX; k++) {
  521. X                putchar( '\t' );
  522. X                if (tt3[k]==0) putchar( '-' );
  523. X                else printf( "%u", tt3[k] );
  524. X            }
  525. X            putchar( NEWLINECHAR );
  526. X        }
  527. X        putchar( NEWLINECHAR );
  528. X    }
  529. X}  /* showtable() */
  530. X
  531. X
  532. X/* Generation of output */
  533. X
  534. Xint16 randint( max )
  535. Xuint16 max;
  536. X{
  537. X    return( max==0 ? 0 : (int16) (((uint16) Random())%max) );
  538. X}  /* int16 randint( max ) */
  539. X
  540. Xint16 randchoice8( tot, dist )
  541. Xuint32 tot;
  542. Xuint8 *dist;
  543. X{
  544. Xint16 i, j;
  545. X
  546. X    if (tot==0) return(-1);
  547. X    i = randint( tot );
  548. X    for (j=0; j<MAXINDEX; j++) {
  549. X        i -= dist[j];
  550. X        if (i < 0) {
  551. X            return(j);
  552. X    }
  553. X    }
  554. X    return( -1 );    /* Should never happen. */
  555. X}  /* int16 randchoice8( tot, dist ) */
  556. X
  557. Xint16 randchoice16( tot, dist )
  558. Xuint32 tot;
  559. Xuint16 *dist;
  560. X{
  561. Xint16 i, j;
  562. X
  563. X    if (tot==0) return(-1);
  564. X    i = randint( tot );
  565. X    for (j=0; j<MAXINDEX; j++) {
  566. X        i -= dist[j];
  567. X        if (i < 0) {
  568. X            return(j);
  569. X    }
  570. X    }
  571. X    return( -1 );    /* Should never happen. */
  572. X}  /* int16 randchoice16( tot, dist ) */
  573. X
  574. Xint16 randchoice32( tot, dist )
  575. Xuint32 tot;
  576. Xuint32 *dist;
  577. X{
  578. Xint16 i, j;
  579. X
  580. X    if (tot==0) return(-1);
  581. X    i = randint( tot );
  582. X    for (j=0; j<MAXINDEX; j++) {
  583. X        i -= dist[j];
  584. X        if (i<0) return(j);
  585. X    }
  586. X    return( -1 );    /* Should never happen. */
  587. X}  /* int16 randchoice32( tot, dist ) */
  588. X
  589. Xoutchar( c )
  590. Xchar c;
  591. X{
  592. X    if ((c=='.') || (c==' ')) {
  593. X    if (Column > BREAK1) {
  594. X        if (c=='.') putchar('.');
  595. X        putchar( NEWLINECHAR );
  596. X        Column = 0;  Lines++;
  597. X    } else {
  598. X        if (c=='.') { putchar('.');  putchar(' ');  Column += 2; }
  599. X        putchar(' ');  Column++;
  600. X    }
  601. X    } else {
  602. X    if (Column > BREAK2) {
  603. X        putchar('-');  putchar( NEWLINECHAR );  Column = 0;  Lines++;
  604. X    }
  605. X    putchar(c);  Column++;
  606. X    }
  607. X}  /* outchar( c ) */
  608. X
  609. Xgenerateword()
  610. X{
  611. Xint16 a, b, c, d;
  612. X
  613. X    a = SPACEINDEX;
  614. X    b = randchoice16( table1[a], table2[a] );
  615. X    if (b==(-1)) return;
  616. X    outchar( indextable(b) );
  617. X    c = randchoice16( table2[a][b], table3[a][b] );
  618. X    if (c==(-1)) return;
  619. X    outchar( indextable(c) );
  620. X    while (Lines < MaxLines) {
  621. X    if (Big) {
  622. X        d = randchoice8( table3[a][b][c], &(table4[ ((((a*MAXINDEX)+b)*MAXINDEX)+c)*MAXINDEX ]) );
  623. X    } else {
  624. X        d = randchoice16( table2[b][c], table3[b][c] );
  625. X    }
  626. X    if (d==(-1)) {
  627. X        outchar( '.' );
  628. X        d = SPACEINDEX;
  629. X    } else {
  630. X        outchar( indextable(d) );
  631. X    }
  632. X    if (SeparateWords && (d==SPACEINDEX)) return;
  633. X        a = b;  b = c;  c = d;
  634. X    }
  635. X}  /* generateword() */
  636. X
  637. Xgenerate()
  638. X{
  639. X    if (table0 > 0) while (Lines < MaxLines) generateword();
  640. X}  /* generate() */
  641. X
  642. X
  643. X/* Argument parsing */
  644. X
  645. Xusageerror()
  646. X{
  647. X    fprintf( stderr, "Usage: %s [-3] [-s|-w] [-lnnn] [file]%c",
  648. X        Argv[0], NEWLINECHAR );
  649. X    fprintf( stderr, "\t-3: 3rd-order statistics (default is 4th-order)%c",
  650. X        NEWLINECHAR );
  651. X    fprintf( stderr, "\t-w: successive words are independent (default)%c",
  652. X        NEWLINECHAR );
  653. X    fprintf( stderr, "\t-s: (sentences) successive words are dependent%c",
  654. X        NEWLINECHAR );
  655. X    fprintf( stderr, "\t-lnnn: Generate nnn lines of output (default %d).%c",
  656. X        DEFAULTMAXLINES, NEWLINECHAR );
  657. X    ExitStatus = 1;
  658. X    exit( ExitStatus );
  659. X}  /* usageerror() */
  660. X
  661. Xprocessoptions()
  662. X{
  663. Xint i;
  664. X
  665. X    CurFile = Argc;
  666. X    for (i=1; i<Argc; i++) {
  667. X        if (Argv[i][0] == '-') {
  668. X        switch (Argv[i][1]) {
  669. X            case 's':
  670. X            SeparateWords = FALSE;
  671. X            break;
  672. X            case 'w':
  673. X            SeparateWords = TRUE;
  674. X            break;
  675. X        case '3':
  676. X            Big = FALSE;
  677. X            break;
  678. X        case 'l':
  679. X            if (Argv[i][2]==0) {
  680. X            MaxLines = MAXUINT32;
  681. X            } else if ((sscanf( &(Argv[i][2]), "%lu", &MaxLines ) != 1) ||
  682. X            (MaxLines < 0)) {
  683. X                usageerror();  /* exits */
  684. X            }
  685. X            break;
  686. X        default:
  687. X            usageerror();  /* exits */
  688. X        }
  689. X    } else if (Argv[i][0] == 0) {
  690. X        FileArgs = FALSE;
  691. X    } else {
  692. X        FileArgs = TRUE;
  693. X        CurFile = i-1;
  694. X        getnextfile();
  695. X        return;
  696. X    }
  697. X    }
  698. X}  /* processoptions() */
  699. X
  700. X
  701. X/* Control */
  702. X
  703. X#if UNIX
  704. Xcleanup( status, ignore )
  705. Xint status;
  706. Xchar *ignore;
  707. X#endif
  708. X#if MPW
  709. Xvoid cleanup( status )
  710. Xint status;
  711. X#endif
  712. X{
  713. X    freememory();
  714. X}  /* cleanup( status, ignore ) */
  715. X
  716. Xmain( argc, argv )
  717. Xint argc;
  718. Xchar **argv;
  719. X{
  720. X#if MPW
  721. X    InitGraf( &(qd.thePort) );  /* for random numbers */
  722. X    GetDateTime( &(qd.randSeed) );
  723. X#endif
  724. X#if UNIX
  725. X    srandom( time(0) );
  726. X#endif
  727. X
  728. X    Argc = argc;  Argv = argv;
  729. X#if UNIX
  730. X    on_exit( cleanup, NULL );    /* probably not necessary */
  731. X#endif
  732. X#if MPW
  733. X    onexit( cleanup );        /* maybe necessary */
  734. X#endif
  735. X    processoptions();
  736. X    maketranstable();
  737. X    getmemory();
  738. X    buildtable();
  739. X    fprintf( stderr, "%u characters%c", table0, NEWLINECHAR );
  740. X#ifdef SHOWTABLE
  741. X    showtable();
  742. X#endif
  743. X    generate();
  744. X    exit( ExitStatus );
  745. X}  /* main() */
  746. *-*-END-of-names.c-*-*
  747. exit
  748.  
  749.