home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / names2 / part01 next >
Text File  |  1990-02-26  |  32KB  |  1,157 lines

  1. Newsgroups: comp.sources.misc
  2. organization: University of East Anglia, Norwich
  3. subject: v10i086: Names2, a random names generator (part 1 of 2)
  4. From: jrk@sys.uea.ac.uk (Richard Kennaway)
  5. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  6.  
  7. Posting-number: Volume 10, Issue 86
  8. Submitted-by: jrk@sys.uea.ac.uk (Richard Kennaway)
  9. Archive-name: names2/part01
  10.  
  11. This is names2.c, a program which generates random names for FRP
  12. characters or placenames.  It is a development of names.c, which I posted
  13. to comp.sources.misc in July 1989.
  14.  
  15. The posting is in two parts.  This is part 1, containing the program;
  16. part 2 contains the data files.
  17.  
  18. For those who saw the earlier version, this is what's new:
  19.  
  20. -  some data files are included to get you started (Sindarin, German,
  21. Chinese, and Chaucerian English).
  22.  
  23. -  you can specify which characters in the input should be considered
  24. "letters"; for example, you can have it recognise punctuation marks and
  25. accents, or apply it to Greek or Cyrillic text (provided each character
  26. is represented by a single byte).
  27.  
  28. -  the internal data structures are much smaller, at the cost of taking
  29. longer to analyse the input and begin generating names.
  30.  
  31. For those who didnt see the earlier version, unlike all similar programs
  32. I've seen, names2 will generate output to match any language you like.
  33. Feed it with text in that language, and it will generate words
  34. statistically similar to the input text.
  35.  
  36. It runs on a Macintosh (if you have MPW C) and Unix.
  37.  
  38. For further information and examples, see the manual entry (near the
  39. begining of the shar archive).
  40.  
  41. The program is public domain.  Share and enjoy.
  42.  
  43. --
  44. Richard Kennaway          SYS, University of East Anglia, Norwich, U.K.
  45. Internet:  jrk@uk.ac.uea.sys                uucp:  ...mcvax!ukc!uea-sys!jrk
  46.  
  47. #!/bin/sh
  48. echo x - MANIFEST1
  49. sed 's/^X//' >MANIFEST1 <<'*-*-END-of-MANIFEST1-*-*'
  50. XMANIFEST1        This file.
  51. Xnames2.1        The manual entry.
  52. Xnames2.c        The source.
  53. XNames2.make        The Macintosh makefile.  (See comment at the
  54. X            beginning before using it.)
  55. XMakefile.unix        The UNIX makefile.
  56. *-*-END-of-MANIFEST1-*-*
  57. echo x - names2.1
  58. sed 's/^X//' >names2.1 <<'*-*-END-of-names2.1-*-*'
  59. X.TH NAMES2 1 "January 1990"
  60. X.UC
  61. X.SH NAME
  62. Xnames2 \- generate random names \- version 2
  63. X.SH SYNOPSIS
  64. X.B names2
  65. X[
  66. X.B \-3
  67. X] [
  68. X.BR \-w\ |\ \-s
  69. X] [
  70. X.B -l
  71. X.I nnn
  72. X] [
  73. X.I files
  74. X]
  75. X.SH DESCRIPTION
  76. X.I Names2
  77. Xis a random name generator. It will read text from standard input or from
  78. Xfiles given on the command line, and generate a random stream of words
  79. Xwhose statistical characteristics are similar to those of the input. Thus
  80. Xif you give it a database of Elvish names, it will generate Elvish-like
  81. Xnames; if a database of Orcish names, it generates Orc-like names, etc.
  82. X.PP
  83. XIt does this by counting the frequency of all 1-, 2-, 3-, and 4-character
  84. Xsequences of letters or spaces in the input. Case is ignored by default,
  85. Xand all runs of non-letters are seen as single spaces. The first character
  86. Xto be output, say "r", is generated according to the relative frequencies
  87. Xwith which each character was found to follow a space in the input. The
  88. Xsecond, say "o", is generated according to the relative frequencies with
  89. Xwhich each character can appear following the digraph " r". The third, say
  90. X"l" is generated according to the relative frequencies with which each
  91. Xcharacter follows the trigraph " ro", and thereafter each character is
  92. Xgenerated according to the frequencies with which the different possible
  93. Xcharacters follow the preceding three.
  94. X.PP
  95. XBy default, the letters are the characters a-z and A-Z, with case
  96. Xdifferences ignored. There are options letting you specify that case is
  97. Xsignificant, or to add or remove characters from the set of "letters".
  98. XThus you can use it to generate names in Greek, Cyrillic, Japanese
  99. Xkana, etc. provided the input text is encoded in some way with one byte
  100. Xper character.
  101. X.PP
  102. XThe larger the input, the better. You need at least a few thousand bytes
  103. Xof input for good results. If the input is not large enough, you will
  104. Xtend to get words from the input appearing verbatim in the output, as much
  105. Xof the time three consecutive characters will uniquely determine the next
  106. Xcharacter. (To see an extreme form of this, try running it on the text
  107. X"the cat sat on the mat".) If more input of the desired form is not
  108. Xavailable, the program can be made to use a third-order approximation
  109. Xinstead, each character of the output depending only on the two preceding
  110. Xcharacters.
  111. X.PP
  112. XThe output is wrapped to 76 chars maximum, hyphenating any word that has
  113. Xto be broken over a line-end.
  114. X.PP
  115. X.I Names2
  116. Xwill run on Unix, and on a Macintosh as an MPW shell tool with MPW C
  117. Xversion 3.
  118. X.SH EXAMPLES
  119. XFor your inspiration, here are some examples demonstrating its
  120. Xversatility.  To generate Elvish names, feed it with the Sindarin words
  121. Xfrom a Sindarin-English dictionary.  You get something like this:
  122. X.PP
  123. X.na
  124. X.in +3
  125. X.ll -3
  126. X.I
  127. Xthaiglin thoromirin mallorien orth girithrass bregalad imloth
  128. X.I
  129. Xmenel berhael cirion saur celebdil aradrif oroth ered eryd mindon
  130. X.I
  131. Xmirandros aer balrond adui narfingor emyn gaurnen sernui silien
  132. X.I
  133. Xglorn fuin celegost bladhren gil breth argonuiliath hinguruthon...
  134. X.PP
  135. X.ad
  136. XAs you can see, not all the output is directly usable, but by exercising
  137. Xsome selection you can obtain results like:
  138. X.PP
  139. X.na
  140. X.in +3
  141. X.ll -3
  142. X.I
  143. XTolfalad, Lothlain, Ossarnen, Malbarahir, Minarwen, Eredil,
  144. X.I
  145. XSuldor Belebrethand, Berielegor, Gaurgor, Mithron, Galadhril,
  146. X.I
  147. XSammathremmir, Erufinrod, Fangband, Turingamar, Ninuviel, Elwinion...
  148. X.PP
  149. X.ad
  150. XPretty convincing, eh?  Yet none of these words actually occurred in the
  151. Xinput file.  Using the output as inspiration, you can even construct
  152. XElvish text.  Here is an extract from the tale of Suldor Belebrethand's
  153. Xjourney through the orclands of Gaurgor to the foothills of Tolfalad, in
  154. Xan ancient and little-known Sindarin dialect (thus forestalling any
  155. Xcriticisms from smart-alecs who actually speak Elvish :-)):
  156. X.PP
  157. X.na
  158. X.in +3
  159. X.ll -3
  160. X.I
  161. X...Argirien emyn druadar lhun arach sarinan-duhirion Erufinrod.
  162. X.I
  163. XSuldor bas caracharon arad mor gwanui alfiriel, i los hin arant
  164. X.I
  165. Xdruadan-calad.  Til edras, "Barachaer bas gaurondon", orguldur...
  166. X.PP
  167. X.ad
  168. XIn contrast, here's some output from the names in the index of a book on
  169. Xearly mediaeval Germany.  I told names2 to consider '"' a letter, and
  170. Xused it to represent a dieresis on the following vowel.  On a Macintosh
  171. Xyou could use the accented characters themselves.
  172. X.PP
  173. X.na
  174. X.in +3
  175. X.ll -3
  176. X.I
  177. Xpassen chutizi albrem m"olden nordgard kunich sched salzburg
  178. X.I
  179. Xbaldwig capendhausengar dal vith assau gisela hildestins pr"ubeck
  180. X.I
  181. Xsclavaringau edgau rick hed albert alcuin ruodlingen hodo boleslas
  182. X.I
  183. Xmisti bert hrothard bold ekkarl wettinau tegenburg zevenstedt...
  184. X.I
  185. X.PP
  186. X.ad
  187. XJust the thing for Warhammer.  I can see it now: chaos tribes have crossed
  188. Xthe Chutizi river and threaten the territory of Count Hrothard of the
  189. XRuodling family, ruler of the town of Zevenstedt and province of
  190. XNordgard, who sends his faithful servant Hodo to ask for help from King
  191. XBaldwig in Wettinau; the party encounter the dying Hodo, waylaid by
  192. Xruffians in the pay of evil Baron Ekkarl; also in the plot are Abbess
  193. XHildestin of Pr"ubeck, Bishop Albrem of M"olden, the village of
  194. XCapendhausen, and the city state of Tegenburg-Assau ... the scenario
  195. Xwrites itself once you get the names right.
  196. X.PP
  197. XHere is some output from a list of names of characters in "The Story of
  198. Xthe Stone", a Chinese novel of the 18th century, in Pinyin romanization:
  199. X.PP
  200. X.na
  201. X.in +3
  202. X.ll -3
  203. X.I
  204. Xxian weng rong shixilua yu lian lin liao wen shiyin hun qian
  205. X.I
  206. Xyun xue chuan bing xiaoqing lian yin xian wan jing wen wan tian
  207. X.I
  208. Xsiji song xue shen xiang deng langzhe ruhai xin xifei lan hun
  209. X.I
  210. Xyouang xi baojinxiao ziten xifei xue erji huan zhe xingyun jie...
  211. X.PP
  212. X.ad
  213. XLastly, this is generated from English text, with all punctuation marks
  214. Xrecognised as "letters" and upper and lower case distinguished:
  215. X.PP
  216. X.in +3
  217. X.ll -3
  218. X.I
  219. Xof a Ch'huen as just is are your prime, stupidition. -- Alfred
  220. X.I
  221. Xin a mismal comple it in that fortune und fall Lighs take you
  222. X.I
  223. Xdoubtful fleeps. I that just Dented, somed formen. Sit chese
  224. X.I
  225. X.PP
  226. XWith names2, who needs James Joyce?
  227. X.SH OPTIONS
  228. XWhen an option takes an argument, there must be no space between the
  229. Xoption and the argument.  Options must be written separately, e.g. -3 -c,
  230. Xnot -3c.
  231. X.TP
  232. X.B \-3
  233. XUse trigraph frequencies instead of tetragraph frequencies.  Gives better
  234. Xresults when input data is limited.  It is interesting to experiment with
  235. Xthis option even if you have enough data to use tetragraphs.
  236. X.TP
  237. X.B \-axxxx
  238. XAdd the characters in the string xxxx to the set of "letters".
  239. X.TP
  240. X.B \-c
  241. XTreat letters in different cases as different.  By default they are not
  242. Xdistinguished.  When this option is given, output is in lower-case.
  243. X.TP
  244. X.B \-dxxxx
  245. XRemove the characters in the string xxxx from the set of "letters".
  246. X\-a and \-d options are processed sequentially, and the \-c option, if
  247. Xpresent, is applied last.
  248. X.TP
  249. X.B \-lnnn
  250. XGenerate nnn lines of output.  Default is 20.  No space between the \-l
  251. Xand the nnn.  If \-l is given with no argument, the output will go on
  252. X(nearly) forever.
  253. X.TP
  254. X.B \-rnnn
  255. XUse nnn as the seed for the random number generator.  As the value of the
  256. Xseed is printed on stderr, this enables you to reproduce the output.  By
  257. Xdefault, the value of the seconds clock is used.
  258. X.TP
  259. X.B \-s
  260. XNegation of
  261. X.B \-w
  262. Xoption.
  263. XThe first character of each word will depend on the last three characters
  264. Xgenerated (i.e. the last two characters of the preceding word, and the
  265. Xinter-word space).
  266. X.TP
  267. X.B \-w
  268. XNegation of
  269. X.B \-s
  270. Xoption.
  271. XGenerate successive words independently, i.e. each word begins as if it
  272. Xwas the beginning of the whole output, ignoring how the preceding word
  273. Xended.  (Default.)
  274. X.SH DIAGNOSTICS
  275. X.I Names2
  276. Xgives a usage message if the arguments are bad.  Exits with status 0 if all
  277. Xwent well.  Exits with status 1 if there were bad arguments (other than
  278. Xnon-existent files), or insufficient memory.  No names are generated.
  279. XOtherwise, exits with status 2 if any files were not found (however, it
  280. Xwill read all the files it could find and generate names).
  281. X.PP
  282. XWrites to stderr a count of the number of different "letter" characters, a
  283. Xcount of the characters read (i.e. letters and runs of non-letters), and
  284. Xthe seed for the random number generator.
  285. X.PP
  286. XIf compiled with SHOWTABLE defined, it dumps the tables to standard output
  287. Xbefore the random names.
  288. X.SH CHANGES SINCE PREVIOUS VERSION
  289. XAdded -a, -c, -d, -r options.  Vastly improved memory allocation.  Ported
  290. Xto MPW version 3.
  291. X.SH BUGS
  292. XThe ignoring of case only applies to the characters a-z and A-Z, not to
  293. Xthe accented letters and ligatures in the Macintosh character set. If you
  294. Xwant to accept all the extra characters and ignore case differences, you
  295. Xcan will need to preprocess your input to map, say, A-dieresis into
  296. Xa-dieresis, OE to oe, etc.
  297. X.SH FURTHER IDEAS
  298. XThere is still some room for improvement in the efficiency of
  299. Xrepresentation of the tables. The space required is approximately four
  300. Xtimes the size of the input, plus eight times the square of the size of
  301. Xthe alphabet. With the -3 option, it would be possible to compress the
  302. Xtables by half, but this is not done - the presence of the -3 option makes
  303. Xno difference to the amount of memory used.
  304. X.PP
  305. XArrange to write the tables to a file and read them in again, to avoid
  306. Xhaving to reconstruct them every time you run the program on the same
  307. Xinput.
  308. X.PP
  309. XThe enthusiastic may want to convert the program to run as a stand-alone
  310. Xapplication on the Macintosh.
  311. X.SH ACKNOWLEDGEMENTS
  312. XThe distribution includes several word-lists from various sources: the
  313. XSindarin dictionary contained in "An Introduction to Elvish", edited by
  314. XJim Allan, published by Bran's Head Books Ltd, 91 Wimborne Avenue, Hayes,
  315. XMiddlesex, U.K., 1978 (but I hear they've gone bust, so that address may
  316. Xnot be any use); the personal and place names from the index of "Rule and
  317. XConflict in an early Medieval Society", by Karl Leyser (Basil Blackwell,
  318. XOxford, U.K., 1989); the names from the index of characters of "The Story
  319. Xof the Stone", by Cao Xueqin (trans. David Hawkes, 3 volumes, Penguin
  320. X1973); and some text from Chaucer.
  321. X.PP
  322. XThe Chinese file is rather short; the example above was produced with
  323. Xthe -3 option.
  324. X.SH AUTHOR
  325. XRichard Kennaway.
  326. X.TP
  327. Xjrk@sys.uea.ac.uk (INTERNET), ...mcvax!uea-sys!jrk (UUCP).
  328. X.TP
  329. XThis program is public domain.
  330. *-*-END-of-names2.1-*-*
  331. echo x - names2.c
  332. sed 's/^X//' >names2.c <<'*-*-END-of-names2.c-*-*'
  333. X/* names2.c */
  334. X/* Random name generator */
  335. X
  336. X/* Richard Kennaway */
  337. X/* INTERNET:    jrk@uk.ac.uea.sys */
  338. X/* UUCP:    ...mcvax!uea-sys!jrk */
  339. X
  340. X/* Public domain! */
  341. X/* August 1989:   First version. */
  342. X/* January 1990:  Ported to MPW3.
  343. X          Removed some untidiness (lint warnings).
  344. X          Print randseed to stderr and take randseed as option
  345. X          to allow reproducibility.
  346. X          Better representation of tetragraph table.
  347. X          Ability to specify character set.  */
  348. X
  349. X
  350. X#define FALSE  0
  351. X#define TRUE   1
  352. X
  353. X/* Choose one... */
  354. X#define UNIX   TRUE   /* Version for Unix */
  355. X#define MPW    FALSE    /* Version for Apple Macintosh (MPW C) */
  356. X
  357. X/* If MPW is TRUE, define one of MPW2 or MPW3 as TRUE, the other as FALSE. */
  358. X#define MPW2   FALSE   /* MPW version 2 */
  359. X#define MPW3   FALSE    /* MPW version 3 */
  360. X
  361. X
  362. X/* System declarations */
  363. X
  364. X#include <stdio.h>
  365. X#if MPW
  366. X#include <Memory.h>    /* For BlockMove(). */
  367. X#include <QuickDraw.h>    /* For random numbers. */
  368. X#include <OSUtils.h>    /* For GetDateTime(). */
  369. X#endif
  370. X
  371. X#define EOFCHAR     (-1)
  372. X
  373. Xextern char *malloc();
  374. X
  375. X
  376. X/* Compatibility */
  377. X
  378. Xtypedef char int8;
  379. Xtypedef unsigned char uint8;
  380. Xtypedef short int16;
  381. Xtypedef unsigned short uint16;
  382. Xtypedef unsigned long uint32;
  383. Xtypedef long int32;
  384. X
  385. X#define MAXUINT8        ((uint8) ((int8) (-1)))
  386. X#define MAXUINT16        ((uint16) ((int16) (-1)))
  387. X#define MAXUINT32        ((int32) ((int32) (-1)))
  388. X#define NUMCHARS    256
  389. X#define chartoint(c)    ((int16)(uint8)(c))
  390. X#define A_CHAR        chartoint('A')
  391. X#define Z_CHAR        chartoint('Z')
  392. X#define a_CHAR        chartoint('a')
  393. X#define z_CHAR        chartoint('z')
  394. X#define SPACE_CHAR    chartoint(' ')
  395. X#define A_TO_a        (a_CHAR-A_CHAR)
  396. X
  397. X#if MPW2
  398. X#define NEWLINECHAR     chartoint('\r')
  399. X#endif
  400. X#if UNIX || MPW3
  401. X#define NEWLINECHAR     chartoint('\n')
  402. X/* Note: the actual value of '\n' is different in UNIX and MPW3,
  403. X and '\n' in MPW3 is the same as '\r' in MPW2. */
  404. X#endif
  405. X
  406. X
  407. X/* Where is the random number generator? */
  408. X
  409. X#if UNIX
  410. Xtypedef char *Ptr;
  411. X#define Boolean        int
  412. X#define BlockMove    bcopy
  413. Xint32 random();
  414. X#define Random()    ((int16) (random()))
  415. X#endif
  416. Xuint32 RandSeed;
  417. X
  418. X
  419. X/* Globals. */
  420. X
  421. Xint Argc;
  422. Xunsigned char **Argv;
  423. Xint ExitStatus = 0;
  424. XBoolean FileArgs = FALSE, Big = TRUE, SeparateWords = TRUE;
  425. XBoolean CaseSignificant = FALSE, Letters[NUMCHARS];
  426. Xint16 CurFile;
  427. X
  428. X
  429. X/* Layout. */
  430. X
  431. X#define BREAK1        60
  432. X#define BREAK2        75
  433. Xint16 Column = 0;
  434. Xint32 Lines = 0;
  435. X#define DEFAULTMAXLINES        20
  436. Xint32 MaxLines = DEFAULTMAXLINES;
  437. X
  438. X
  439. X/* Tables */
  440. X
  441. Xint16 NumChars = 0;
  442. X#define SPACEINDEX      0
  443. Xint32 t2size, t3size, t4size;
  444. X
  445. X#define NOTCHOICE        MAXUINT16
  446. X
  447. Xint16 CharToIndex[NUMCHARS], IndexToChar[NUMCHARS];
  448. X
  449. Xint32    table0 = 0,
  450. X    *table1 = NULL,
  451. X    *table2 = NULL;
  452. X
  453. X#define BLOCKSIZE(n)        (sizeof(int32) + sizeof(int32) + (n)*sizeof(uint16))
  454. X#define INITSIZE        10
  455. X#define GROWNUM            5
  456. X#define GROWDEN            4
  457. X
  458. Xtypedef struct DigraphBlock {
  459. X    int32 size, maxsize;
  460. X    uint16 data[1];
  461. X} DigraphBlockRec, *DigraphBlockPtr;
  462. X
  463. XDigraphBlockPtr *quadtable = NULL;
  464. X
  465. X
  466. X/* Sorting */
  467. X
  468. Xstatic void SortArray();
  469. X
  470. Xtypedef Boolean (*ComparisonProc)();
  471. X
  472. X
  473. X/* Memory allocation */
  474. X
  475. Xchar *trymemory( bytesNeeded, mustGet )
  476. Xint32 bytesNeeded;
  477. XBoolean mustGet;
  478. X{
  479. Xchar *result;
  480. X
  481. X    result = (char *) malloc( bytesNeeded );
  482. X    if ((result==NULL) && (mustGet)) {
  483. X    fprintf( stderr, "Could not get %lu bytes - terminating.%c",
  484. X         bytesNeeded, NEWLINECHAR );
  485. X    ExitStatus = 1;
  486. X    exit( ExitStatus );
  487. X    }
  488. X    return( result );
  489. X}  /* char *trymemory( bytesNeeded, mustGet ) */
  490. X
  491. Xvoid zero( start, numBytes )
  492. Xchar *start;
  493. Xint32 numBytes;
  494. X{
  495. X/* Your system may well have a faster way of zeroing memory. */
  496. X/* In fact, the static arrays to which this procedure is applied */
  497. X/* may be automatically initialised to zero already. */
  498. X/* But portability would be impaired by asssuming that. */
  499. X
  500. Xint32 remainder, i, num32bits;
  501. X
  502. X    remainder = numBytes % ((int32) 4);
  503. X    for (i=1; i <= remainder; i++) start[numBytes-i] = 0;
  504. X    num32bits = numBytes / ((int32) 4);
  505. X    for (i=0; i<num32bits; i++) ((int32 *) start)[i] = 0;
  506. X}  /* void zero( start, numBytes ) */
  507. X
  508. Xvoid getmemory()
  509. X{
  510. Xint32 i;
  511. X
  512. X    table1 = (int32 *) trymemory( NumChars * sizeof(int32), TRUE );
  513. X    table2 = (int32 *) trymemory( t2size * sizeof(int32), TRUE );
  514. X    quadtable = (DigraphBlockPtr *) trymemory( t2size * sizeof(DigraphBlockPtr), TRUE );
  515. X
  516. X    zero( (char *) table1, NumChars * sizeof(int32) );
  517. X    zero( (char *) table2, t2size * sizeof(int32) );
  518. X    for (i=0; i<t2size; i++) quadtable[i] = NULL;
  519. X}  /* void getmemory() */
  520. X
  521. Xvoid freememory()
  522. X{
  523. X    if (table1 != NULL) free( (char *) table1 );
  524. X    if (table2 != NULL) free( (char *) table2 );
  525. X}  /* void freememory() */
  526. X
  527. X
  528. X/* Preliminary setup */
  529. X
  530. Xvoid setchar( c, accept )
  531. Xuint8 c;
  532. XBoolean accept;
  533. X{
  534. X    Letters[c] = accept;
  535. X    if (! CaseSignificant) {
  536. X    if ((A_CHAR <= c) && (c <= Z_CHAR)) Letters[c + A_TO_a] = accept;
  537. X    if ((a_CHAR <= c) && (c <= z_CHAR)) Letters[c - A_TO_a] = accept;
  538. X    }
  539. X}  /* void setchar( c, accept ) */
  540. X
  541. Xvoid setchars( s, accept )
  542. Xuint8 *s;
  543. XBoolean accept;
  544. X{
  545. Xint16 i;
  546. Xuint8 c;
  547. X
  548. X    if (s==NULL) return;
  549. X    i = 0;
  550. X    while ((c = s[i++]) != 0) setchar( c, accept );
  551. X}  /* void setchars( s, accept ) */
  552. X
  553. Xvoid maketranstable()
  554. X{
  555. Xint16 c;
  556. X
  557. X    for (c=0; c < NUMCHARS; c++) {
  558. X    CharToIndex[(uint8)c] = SPACEINDEX;
  559. X    IndexToChar[(uint8)c] = SPACE_CHAR;
  560. X    }
  561. X    NumChars = 1;
  562. X    if (!CaseSignificant) {
  563. X    for (c=a_CHAR; c<= z_CHAR; c++) {
  564. X        if (Letters[(uint8)(c - A_TO_a)] != Letters[(uint8)c]) {
  565. X            Letters[(uint8)c] = TRUE;
  566. X            Letters[(uint8)(c - A_TO_a)] = TRUE;
  567. X        }
  568. X    }
  569. X    }
  570. X    for (c=0; c < NUMCHARS; c++) {
  571. X    if (Letters[(uint8)c] && (CaseSignificant || (c < A_CHAR) || (Z_CHAR < c))) {
  572. X        CharToIndex[(uint8)c] = NumChars;
  573. X        IndexToChar[(uint8)NumChars] = c;
  574. X        NumChars++;
  575. X    }
  576. X    }
  577. X    if (!CaseSignificant) {
  578. X    for (c=a_CHAR; c<= z_CHAR; c++) {
  579. X        CharToIndex[(uint8)(c - A_TO_a)] = CharToIndex[(uint8)c];
  580. X    }
  581. X    }
  582. X    IndexToChar[(uint8)SPACEINDEX] = SPACE_CHAR;
  583. X
  584. X    t2size = NumChars*NumChars;
  585. X    t3size = t2size*NumChars;
  586. X    t4size = t2size*t2size;
  587. X}  /* void maketranstable() */
  588. X
  589. X
  590. X/* Input */
  591. X
  592. XBoolean openfile()
  593. X{
  594. XFILE *temp;
  595. X
  596. X    temp = freopen( Argv[CurFile], "r", stdin );
  597. X    if (temp == NULL) {
  598. X    fprintf( stderr, "%s: could not open file \"%s\"%c",
  599. X        Argv[0], Argv[CurFile], NEWLINECHAR );
  600. X    ExitStatus = 2;
  601. X    }
  602. X    return( temp != NULL );
  603. X}  /* Boolean openfile() */
  604. X
  605. XBoolean getnextfile()
  606. X{
  607. X    while (((++CurFile) < Argc) && (! openfile())) { /* nothing */ }
  608. X    return( CurFile < Argc );
  609. X}  /* Boolean getnextfile() */
  610. X
  611. Xint16 getrawchar()
  612. X{
  613. Xint16 c;
  614. X    c = getchar();
  615. X    while ((c==EOFCHAR) && getnextfile()) {
  616. X    c = getchar();
  617. X    }
  618. X    return(c);
  619. X}  /* int16 getrawchar() */
  620. X
  621. X#define WASSPACE    0
  622. X#define WASNONSPACE 1
  623. X#define END         2
  624. Xint16 Where = WASSPACE;
  625. X
  626. Xint16 nextchar()
  627. X{
  628. Xint16 c;
  629. X
  630. X    switch (Where) {
  631. X    case WASSPACE:
  632. X        while (((c = getrawchar()) != EOFCHAR) &&
  633. X           (!Letters[(uint8)c])) {
  634. X        /* nothing */
  635. X        }
  636. X        if (c==EOFCHAR) {
  637. X        Where = END;
  638. X        return(-1);
  639. X        } else {
  640. X        Where = WASNONSPACE;
  641. X        return(CharToIndex[(uint8)c]);
  642. X        }
  643. X    case WASNONSPACE:
  644. X        c = getrawchar();
  645. X        if (c==EOFCHAR) {
  646. X        Where = END;
  647. X        return(SPACEINDEX);
  648. X        } else if (Letters[(uint8)c]) {
  649. X        return(CharToIndex[(uint8)c]);
  650. X        } else {
  651. X        Where = WASSPACE;
  652. X        return(SPACEINDEX);
  653. X        }
  654. X    case END:
  655. X        return(-1);
  656. X    }
  657. X    return(-1);    /* Never happens. */
  658. X}  /* int16 nextchar() */
  659. X
  660. XDigraphBlockPtr NewBlock( size )
  661. Xint32 size;
  662. X{
  663. XDigraphBlockPtr temp;
  664. X    temp = (DigraphBlockPtr) malloc( BLOCKSIZE(size) );
  665. X    return( temp );
  666. X}  /* DigraphBlockPtr NewBlock( size ) */
  667. X
  668. XBoolean insertdigraph( t, cd )
  669. XDigraphBlockPtr *t;
  670. Xuint16 cd;
  671. X{
  672. XDigraphBlockPtr temp;
  673. Xint32 newSize;
  674. X
  675. X    if (t==NULL) return( FALSE );
  676. X    if (((*t)==NULL) || ((*t)->size >= (*t)->maxsize)) {
  677. X    newSize = (*t)==NULL ? INITSIZE : ((*t)->size * GROWNUM)/GROWDEN;
  678. X    temp = NewBlock( newSize );
  679. X    if (temp==NULL) return( FALSE );
  680. X    if ((*t)==NULL) {
  681. X        temp->size = 1;
  682. X    } else {
  683. X        BlockMove( (Ptr) (*t), (Ptr) temp, BLOCKSIZE((*t)->size) );
  684. X        temp->size = (*t)->size + 1;
  685. X        free( (char *) (*t) );
  686. X    }
  687. X    temp->maxsize = newSize;
  688. X    *t = temp;
  689. X    (*t)->data[(*t)->size-1] = cd;
  690. X    } else {
  691. X        (*t)->data[(*t)->size++] = cd;
  692. X    }
  693. X    return( TRUE );
  694. X}  /* Boolean insertdigraph( t, cd ) */
  695. X
  696. Xint16 AA = 0, BB = 0, CC = 0;
  697. X
  698. Xvoid entergroup( d )
  699. Xint16 d;
  700. X{
  701. Xint32 ab, cd;
  702. X
  703. X    ab = AA*NumChars + BB;
  704. X    cd = CC*NUMCHARS + d;
  705. X    if (table2[ab] < MAXUINT16) {
  706. X    if (insertdigraph( &(quadtable[ab]), (uint16) cd )) {
  707. X        table0++;
  708. X        table1[d]++;
  709. X        table2[ab]++;
  710. X    }
  711. X    }
  712. X    AA = BB;  BB = CC;  CC = d;
  713. X}  /* void entergroup( d ) */
  714. X
  715. Xvoid buildtable()
  716. X{
  717. Xint16 a0, b0, c0, d;
  718. X
  719. X    a0 = nextchar();
  720. X    if (a0==SPACEINDEX) a0 = nextchar();
  721. X    b0 = nextchar();
  722. X    c0 = nextchar();
  723. X    if (c0 == -1) return;
  724. X    AA = a0;  BB = b0;  CC = c0;
  725. X    while ((d = nextchar()) != (-1)) {
  726. X    entergroup( d );
  727. X    }
  728. X    if (CC==SPACEINDEX) {
  729. X    entergroup( a0 );
  730. X    entergroup( b0 );
  731. X    entergroup( c0 );
  732. X    } else {
  733. X    entergroup( SPACEINDEX );
  734. X    entergroup( a0 );
  735. X    entergroup( b0 );
  736. X    entergroup( c0 );
  737. X    }
  738. X}  /* void buildtable() */
  739. X
  740. X
  741. X#ifdef SHOWTABLE
  742. X
  743. X/* Dump the tables. */
  744. X/* Only called if SHOWTABLE is defined at compile time. */
  745. X
  746. Xvoid showtable()
  747. X{
  748. Xuint8 i, j, k;
  749. Xint32 *t2;
  750. Xuint8 *t4;
  751. X
  752. X    for (i=0; i<NumChars; i++) if (table1[i] != 0) {
  753. X    printf( "%c\t%lu%c", IndexToChar[i], table1[i], NEWLINECHAR );
  754. X    t2 = table2 + i*NumChars;
  755. X    for (j=0; j<NumChars; j++) if (t2[j] != 0) {
  756. X        printf( "%c%c\t%u", IndexToChar[i], IndexToChar[j], t2[j] );
  757. X        t4 = (uint8 *) (quadtable[i*NumChars + j]->data);
  758. X        for (k=0; k<t2[j]; k++) {
  759. X        if ((k%20==0) && (k>0)) { putchar( NEWLINECHAR );  putchar( '\t' ); }
  760. X        putchar( ' ' );
  761. X        putchar( IndexToChar[ (uint8)(t4[k+k]) ] );
  762. X        putchar( IndexToChar[ (uint8)(t4[k+k+1]) ] );
  763. X        }
  764. X        putchar( NEWLINECHAR );
  765. X    }
  766. X    putchar( NEWLINECHAR );
  767. X    }
  768. X    fflush( stdout );
  769. X}  /* void showtable() */
  770. X
  771. X#endif
  772. X
  773. X
  774. X/* Generation of output */
  775. X
  776. Xuint16 Rand16()
  777. X{
  778. X    return( (uint16) Random() );
  779. X}  /* uint16 Rand16() */
  780. X
  781. Xint32 randint( max )
  782. Xint32 max;
  783. X{
  784. X    if (max==0) return( 0 );
  785. X    if (max <= MAXUINT16) return( ((int32) Rand16())%max );
  786. X    return( ((((int32) Random()) << 16) + ((int32) Random())) % max );
  787. X}  /* int32 randint( max ) */
  788. X
  789. Xuint16 randchoice32( tot, dist )
  790. Xint32 tot;
  791. Xint32 *dist;
  792. X{
  793. Xint32 i;
  794. Xuint8 j;
  795. X
  796. X    if (tot==0) return(NOTCHOICE);
  797. X    i = randint( tot );
  798. X    for (j=0; j<NumChars; j++) {
  799. X        if (i < dist[j]) return(j);
  800. X    i -= dist[j];
  801. X    }
  802. X    return( NOTCHOICE );    /* Should never happen. */
  803. X}  /* uint16 randchoice32( tot, dist ) */
  804. X
  805. Xcleanupquads()
  806. X{
  807. Xint32 i;
  808. X
  809. X    for (i=0; i<t2size; i++) if (table2[i] > 0) {
  810. X    SortArray( quadtable[i]->data, quadtable[i]->size );
  811. X    }
  812. X}  /* cleanupquads() */
  813. X
  814. Xuint16 randtrip( a, b )
  815. Xuint8 a, b;
  816. X{
  817. Xuint16 aNb;
  818. Xint32 t2;
  819. Xuint8 *t4;
  820. Xint32 r;
  821. X
  822. X    aNb = a*NumChars+b;
  823. X    t2 = table2[ aNb ];
  824. X    t4 = (uint8 *) (quadtable[ aNb ]->data);
  825. X    r = randint( t2 );
  826. X    return( (uint16) (t4[r+r]) );
  827. X}  /* uint16 randtrip( a, b ) */
  828. X
  829. Xuint16 randquad( a, b, c )
  830. Xuint8 a, b, c;
  831. X{
  832. Xuint16 aNb;
  833. Xint32 t2;
  834. Xuint8 *t4;
  835. Xint32 lo, hi, i, r;
  836. X
  837. X    aNb = a*NumChars+b;
  838. X    t2 = table2[ aNb ];
  839. X    t4 = (uint8 *) (quadtable[ aNb ]->data);
  840. X    lo = 0;
  841. X    hi = 0;
  842. X    for (i=0; i<t2; i++) {
  843. X        if (t4[i+i] <= c){
  844. X        hi++;
  845. X            if (t4[i+i] < c) lo++;
  846. X    } else break;
  847. X    }
  848. X    if (lo >= hi) {
  849. X        /* This should never happen. */
  850. X        return( NOTCHOICE );
  851. X    }
  852. X    r = lo + randint( hi-lo );
  853. X    return( (uint16) (t4[r+r+1]) );
  854. X}  /* uint16 randquad( a, b, c ) */
  855. X
  856. Xvoid outchar( c )
  857. Xint16 c;
  858. X{
  859. X    if (Column < BREAK1) {
  860. X    putchar(c);  Column++;
  861. X    } else if (c==chartoint(' ')) {
  862. X    putchar( NEWLINECHAR );
  863. X    Column = 0;  Lines++;
  864. X    } else if (Column >= BREAK2) {
  865. X    putchar('-');  putchar( NEWLINECHAR );
  866. X    Column = 0;  Lines++;
  867. X    if (Lines < MaxLines) {
  868. X        putchar(c);  Column++;
  869. X    }
  870. X    } else {
  871. X    putchar(c);  Column++;
  872. X    }
  873. X}  /* void outchar( c ) */
  874. X
  875. Xvoid generateword()
  876. X{
  877. Xuint16 a, b, c, d;
  878. X
  879. X    a = (uint16)SPACEINDEX;
  880. X    b = randchoice32( (int32) (table1[a]), table2 + a*NumChars );
  881. X    if (b==NOTCHOICE) return;
  882. X    outchar( IndexToChar[(uint8)b] );
  883. X    if (SeparateWords && (b==SPACEINDEX)) return;
  884. X
  885. X    c = randtrip( (uint16)SPACEINDEX, (uint8)b );
  886. X    outchar( IndexToChar[(uint8)c] );
  887. X    if (SeparateWords && (c==(uint16)SPACEINDEX)) return;
  888. X
  889. X    while (Lines < MaxLines) {
  890. X        d = Big ? randquad( (uint8)a, (uint8)b, (uint8)c )
  891. X        : randtrip( (uint8)b, (uint8)c );
  892. X    if (d==NOTCHOICE) {
  893. X        outchar( '.' );
  894. X        return;
  895. X    }
  896. X    outchar( IndexToChar[(uint8)d] );
  897. X    if (SeparateWords && (d==(uint16)SPACEINDEX)) return;
  898. X    a = b;  b = c;  c = d;
  899. X    }
  900. X}  /* void generateword() */
  901. X
  902. Xvoid generate()
  903. X{
  904. X    if (table0 > 0) while (Lines < MaxLines) generateword();
  905. X}  /* void generate() */
  906. X
  907. X
  908. X/* Argument parsing */
  909. X
  910. Xvoid usageerror()
  911. X{
  912. X    fprintf( stderr, "Usage: %s [-3] [-s|-w] [-c] [-axxxx] [-dxxxx] [-lnnn] [-rnnn] [file]%c",
  913. X    Argv[0], NEWLINECHAR );
  914. X    fprintf( stderr, "\t-3: 3rd-order statistics.%c",
  915. X    NEWLINECHAR );
  916. X    fprintf( stderr, "\t-w: Successive words are independent (default).%c",
  917. X    NEWLINECHAR );
  918. X    fprintf( stderr, "\t-s: (Sentences) Successive words are dependent.%c",
  919. X    NEWLINECHAR );
  920. X    fprintf( stderr, "\t-c: Treat case differences as significant.%c",
  921. X    NEWLINECHAR );
  922. X    fprintf( stderr, "\t-axxxx: Accept characters in string \"xxxx\" as 'letters'.%c",
  923. X    NEWLINECHAR );
  924. X    fprintf( stderr, "\t-dxxxx: Treat characters in string \"xxxx\" as spaces.%c",
  925. X    NEWLINECHAR );
  926. X    fprintf( stderr, "\tSuccessive -a/-d options are processed sequentially.%c",
  927. X    NEWLINECHAR );
  928. X    fprintf( stderr, "\t-lnnn: Generate nnn lines of output (default %d).%c",
  929. X    DEFAULTMAXLINES, NEWLINECHAR );
  930. X    fprintf( stderr, "\t-rnnn: Specify random generator seed.%c",
  931. X    DEFAULTMAXLINES, NEWLINECHAR );
  932. X    ExitStatus = 1;
  933. X    exit( ExitStatus );
  934. X}  /* void usageerror() */
  935. X
  936. Xvoid processoptions()
  937. X{
  938. Xint16 i;
  939. X
  940. X/* getopt()?  What's that? :-) */
  941. X
  942. X    CaseSignificant = FALSE;
  943. X    for (i=0; i<NUMCHARS; i++) Letters[(uint8)i] = FALSE;
  944. X    setchars( (uint8 *) "abcdefghijklmnopqrstuvwxyz", TRUE );
  945. X
  946. X    CurFile = Argc;
  947. X    for (i=1; i<Argc; i++) {
  948. X    if (Argv[i][0] == '-') {
  949. X        switch (Argv[i][1]) {
  950. X        case 's':
  951. X            SeparateWords = FALSE;
  952. X            break;
  953. X        case 'w':
  954. X            SeparateWords = TRUE;
  955. X            break;
  956. X        case 'a':
  957. X            setchars( &(Argv[i][1]), TRUE );
  958. X            break;
  959. X        case 'd':
  960. X            setchars( &(Argv[i][1]), TRUE );
  961. X            break;
  962. X        case 'c':
  963. X            CaseSignificant = TRUE;
  964. X            break;
  965. X        case '3':
  966. X            Big = FALSE;
  967. X            break;
  968. X        case 'l':
  969. X            if (Argv[i][2]==0) {
  970. X            MaxLines = MAXUINT32;
  971. X            } else if ((sscanf( &(Argv[i][2]), "%lu", &MaxLines ) != 1) ||
  972. X            (MaxLines < 0)) {
  973. X            usageerror();  /* exits */
  974. X            }
  975. X            break;
  976. X        case 'r':
  977. X            if ((Argv[i][2] != 0) &&
  978. X            (sscanf( &(Argv[i][2]), "%lu", &RandSeed ) != 1)) {
  979. X            usageerror();  /* exits */
  980. X            }
  981. X            break;
  982. X        default:
  983. X            usageerror();  /* exits */
  984. X        }
  985. X    } else if (Argv[i][0] == 0) {
  986. X        FileArgs = FALSE;
  987. X    } else {
  988. X        FileArgs = TRUE;
  989. X        CurFile = i-1;
  990. X        (void) getnextfile();
  991. X        return;
  992. X    }
  993. X    }
  994. X}  /* void processoptions() */
  995. X
  996. X
  997. X/* Control */
  998. X
  999. X#if UNIX
  1000. Xcleanup( status, ignore )
  1001. Xint status;
  1002. Xchar *ignore;
  1003. X#endif
  1004. X#if MPW
  1005. Xvoid cleanup( status )
  1006. Xint status;
  1007. X#endif
  1008. X{
  1009. X    freememory();
  1010. X}  /* cleanup( status, ignore ) */
  1011. X
  1012. Xvoid SeedRand()
  1013. X{
  1014. X#if MPW
  1015. X    qd.randSeed = (int32) RandSeed;
  1016. X#endif
  1017. X#if UNIX
  1018. X    srandom( RandSeed );
  1019. X#endif
  1020. X}  /* void SeedRand() */
  1021. X
  1022. Xmain( argc, argv )
  1023. Xint argc;
  1024. Xuint8 **argv;
  1025. X{
  1026. X    Argc = argc;  Argv = argv;
  1027. X
  1028. X#if MPW
  1029. X    InitGraf( &(qd.thePort) );  /* for random numbers */
  1030. X    GetDateTime( &RandSeed );
  1031. X#endif
  1032. X#if UNIX
  1033. X    RandSeed = time(0);
  1034. X    on_exit( cleanup, NULL );        /* Probably not necessary. */
  1035. X#endif
  1036. X#if MPW2
  1037. X    onexit( cleanup );            /* Maybe necessary? */
  1038. X#endif
  1039. X
  1040. X    processoptions();
  1041. X
  1042. X    SeedRand();
  1043. X    maketranstable();
  1044. X    getmemory();
  1045. X    fprintf( stderr, "Reading input...%c", NEWLINECHAR );
  1046. X    buildtable();
  1047. X    fprintf( stderr, "%d different letters, %u characters input.  Randseed = %lu%c",
  1048. X    NumChars-1, table0, RandSeed, NEWLINECHAR );
  1049. X    if (table0 > 0) {
  1050. X#ifdef SHOWTABLE
  1051. X    showtable();
  1052. X#endif
  1053. X    if (Big) cleanupquads();
  1054. X#ifdef SHOWTABLE
  1055. X    showtable();
  1056. X#endif
  1057. X    generate();
  1058. X    fflush( stdout );
  1059. X    }
  1060. X    exit( ExitStatus );
  1061. X}  /* main() */
  1062. X
  1063. X
  1064. X/* Heapsort. */
  1065. X
  1066. Xstatic uint16 *TheArray;
  1067. X
  1068. Xuint16 Temp;
  1069. X
  1070. X#define SWAPITEM( i, j )    \
  1071. X    Temp = TheArray[(i)];    \
  1072. X    TheArray[(i)] = TheArray[(j)];    \
  1073. X    TheArray[(j)] = Temp    \
  1074. X
  1075. Xstatic void MakeHeap( theElement, numElements )
  1076. Xint32 theElement, numElements;
  1077. X{
  1078. Xint32 left, right;
  1079. X
  1080. X    while ((left = theElement+theElement+1L) < numElements) {  
  1081. X    right = left+1L;
  1082. X    if (TheArray[theElement] < TheArray[left]) {
  1083. X        if ((right < numElements) &&
  1084. X        (TheArray[left] < TheArray[right])) {
  1085. X        /* M<L<R */
  1086. X        SWAPITEM( theElement, right );
  1087. X        theElement = right;
  1088. X        } else {  /* M<L, M<R<L, R<M<L */
  1089. X        SWAPITEM( theElement, left );
  1090. X        theElement = left;
  1091. X        }
  1092. X    } else if ((right < numElements) &&
  1093. X           (TheArray[theElement] < TheArray[right])) {
  1094. X        /* L<M<R */
  1095. X        SWAPITEM( theElement, right );
  1096. X        theElement = right;
  1097. X    } else {
  1098. X        /* L<M, L<R<M, R<L<M */
  1099. X        break;
  1100. X    }
  1101. X    }
  1102. X}  /* static void MakeHeap( theElement, numElements ) */
  1103. X
  1104. Xstatic void SortArray( theArray, length )
  1105. Xuint16 *theArray;
  1106. Xint32 length;
  1107. X{
  1108. Xint32 i;
  1109. X
  1110. X    TheArray = theArray;
  1111. X    
  1112. X    for (i = (length / 2L) - 1L; i >= 0L; i--) {
  1113. X    MakeHeap( i, length );
  1114. X    }
  1115. X    for (i = length-1L; i >= 1L; i--) {
  1116. X    SWAPITEM( 0L, i );
  1117. X    MakeHeap( 0L, i );
  1118. X    }
  1119. X}  /* static void SortArray( theArray, length ) */
  1120. *-*-END-of-names2.c-*-*
  1121. echo x - Names2.make
  1122. sed 's/^X//' >Names2.make <<'*-*-END-of-Names2.make-*-*'
  1123. X#    Replace each backslash by option-d, and each colon by option-f.
  1124. X#    Then use the Build command on the Build menu to build Names2.
  1125. X
  1126. X#   File:       Names2.make
  1127. X#   Target:     Names2
  1128. X#   Sources:    names2.c
  1129. X#   Created:    Thursday, February 15, 1990 20:42:06 with MPW C version 3
  1130. X
  1131. Xnames2.c.o : Names2.make names2.c
  1132. X     C  names2.c
  1133. X
  1134. XSOURCES = names2.c
  1135. XOBJECTS = names2.c.o
  1136. X
  1137. XNames2 :: Names2.make {OBJECTS}
  1138. X    Link -w -c 'MPS ' -t MPST \
  1139. X        {OBJECTS} \
  1140. X        "{Libraries}"stubs.o \
  1141. X        "{CLibraries}"CRuntime.o \
  1142. X        "{Libraries}"Interface.o \
  1143. X        "{CLibraries}"StdCLib.o \
  1144. X        "{CLibraries}"CSANELib.o \
  1145. X        "{CLibraries}"Math.o \
  1146. X        "{CLibraries}"CInterface.o \
  1147. X        "{Libraries}"ToolLibs.o \
  1148. X        -o Names2
  1149. *-*-END-of-Names2.make-*-*
  1150. echo x - Makefile.unix
  1151. sed 's/^X//' >Makefile.unix <<'*-*-END-of-Makefile.unix-*-*'
  1152. Xnames2 : names2.c
  1153. X    cc names2.c -o names2
  1154. *-*-END-of-Makefile.unix-*-*
  1155. exit
  1156.  
  1157.