7 NPREF
= 2, /* number of prefix words */
8 NHASH
= 4093, /* size of state hash table array */
9 MAXGEN
= 10000 /* maximum words generated */
12 typedef struct State State
;
13 typedef struct Suffix Suffix
;
15 struct State
{ /* prefix + suffix list */
16 char *pref
[NPREF
]; /* prefix words */
17 Suffix
*suf
; /* list of suffixes */
18 State
*next
; /* next in hash table */
21 struct Suffix
{ /* list of suffixes */
22 char *word
; /* suffix */
23 Suffix
*next
; /* next in list of suffixes */
27 char NONWORD
[] = "\n";
29 State
*statetab
[NHASH
]; /* hash table of states */
31 /* xmalloc: dies if malloc() fails */
32 void *xmalloc(size_t size
)
44 /* xstrdup: dies if strdup() fails */
45 char *xstrdup(const char *s
)
57 /* hash: compute hash value for array of NPREF strings */
58 unsigned int hash(char *s
[NPREF
])
65 for (i
= 0; i
< NPREF
; i
++)
66 for (p
= (unsigned char *) s
[i
]; *p
!= '\0'; p
++)
67 h
= MULTIPLIER
* h
+ *p
;
71 /* lookup: search for prefix; create if requested. */
72 /* returns pointer if present or created; NULL if not. */
73 /* creation doesn't strdup so strings mustn't change later */
74 State
*lookup(char *prefix
[NPREF
], int create
)
80 for (sp
= statetab
[h
]; sp
!= NULL
; sp
= sp
->next
) {
81 for (i
= 0; i
< NPREF
; i
++)
82 if (strcmp(prefix
[i
], sp
->pref
[i
]) != 0)
84 if (i
== NPREF
) /* found it */
89 sp
= (State
*) xmalloc(sizeof(State
));
90 for (i
= 0; i
< NPREF
; i
++)
91 sp
->pref
[i
] = prefix
[i
];
93 sp
->next
= statetab
[h
];
100 /* addsuffix: add to state. suffix must not change later */
101 void addsuffix(State
*sp
, char *suffix
)
105 suf
= (Suffix
*) xmalloc(sizeof(Suffix
));
111 /* add: add word to suffix list, update prefix */
112 void add(char *prefix
[NPREF
], char *suffix
)
116 sp
= lookup(prefix
, 1); /* create if not found */
117 addsuffix(sp
, suffix
);
118 /* move the words down the prefix */
119 memmove(prefix
, prefix
+ 1, (NPREF
- 1) * sizeof(prefix
[0]));
120 prefix
[NPREF
-1] = suffix
;
123 /* build: read input, build prefix table */
124 void build(char *prefix
[NPREF
], FILE *f
)
126 char buf
[100], fmt
[10];
128 /* create a format string; %s could overflow buf */
129 sprintf(fmt
, "%%%ds", sizeof(buf
)-1);
130 while (fscanf(f
, fmt
, buf
) != EOF
)
131 add(prefix
, xstrdup(buf
));
134 /* generate: produce output, one word per line */
135 void generate(int nwords
)
139 char *prefix
[NPREF
], *w
;
142 for (i
= 0; i
< NPREF
; i
++) /* reset initial prefix */
145 for (i
= 0; i
< nwords
; i
++) {
146 sp
= lookup(prefix
, 0);
148 for (suf
= sp
->suf
; suf
!= NULL
; suf
= suf
->next
)
149 if (rand() % ++nmatch
== 0) /* prob = 1/nmatch */
151 if (strcmp(w
, NONWORD
) == 0)
154 memmove(prefix
, prefix
+ 1, (NPREF
-1) * sizeof(prefix
[0]));
162 char *prefix
[NPREF
]; /* current input prefix */
166 for (i
= 0; i
< NPREF
; i
++) /* set up initial prefix */
169 build(prefix
, stdin
);
170 add(prefix
, NONWORD
);