Initial commit
[keepassx] / src / apg / pronpass.c
1 /*
2 ** This module uses code from the NIST implementation of  FIPS-181,
3 ** but the algorythm is CHANGED and I think that I CAN
4 ** copyright it. See copiright notes below.
5 */
6
7 /*
8 ** Copyright (c) 1999, 2000, 2001, 2002, 2003
9 ** Adel I. Mirzazhanov. All rights reserved
10 **
11 ** Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions
13 ** are met:
14 ** 
15 **     1.Redistributions of source code must retain the above copyright notice,
16 **       this list of conditions and the following disclaimer. 
17 **     2.Redistributions in binary form must reproduce the above copyright
18 **       notice, this list of conditions and the following disclaimer in the
19 **       documentation and/or other materials provided with the distribution. 
20 **     3.The name of the author may not be used to endorse or promote products
21 **       derived from this software without specific prior written permission. 
22 **                
23 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR  ``AS IS'' AND ANY EXPRESS
24 ** OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED
25 ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ** ARE DISCLAIMED.  IN  NO  EVENT  SHALL THE AUTHOR BE LIABLE FOR ANY
27 ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE
29 ** GOODS OR SERVICES;  LOSS OF USE,  DATA,  OR  PROFITS;  OR BUSINESS
30 ** INTERRUPTION)  HOWEVER  CAUSED  AND  ON  ANY  THEORY OF LIABILITY,
31 ** WHETHER  IN  CONTRACT,   STRICT   LIABILITY,  OR  TORT  (INCLUDING
32 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 #include <sys/types.h>
42
43 #include "random.h"
44
45 #include "pronpass.h"
46 #include "randpass.h"
47 #include "convert.h"
48
49 struct unit
50 {
51     char    unit_code[5];
52     USHORT  flags;
53 };
54
55 static struct unit  rules[] =
56 {   {"a", VOWEL},
57     {"b", NO_SPECIAL_RULE},
58     {"c", NO_SPECIAL_RULE},
59     {"d", NO_SPECIAL_RULE},
60     {"e", NO_FINAL_SPLIT | VOWEL},
61     {"f", NO_SPECIAL_RULE},
62     {"g", NO_SPECIAL_RULE},
63     {"h", NO_SPECIAL_RULE},
64     {"i", VOWEL},
65     {"j", NO_SPECIAL_RULE},
66     {"k", NO_SPECIAL_RULE},
67     {"l", NO_SPECIAL_RULE},
68     {"m", NO_SPECIAL_RULE},
69     {"n", NO_SPECIAL_RULE},
70     {"o", VOWEL},
71     {"p", NO_SPECIAL_RULE},
72     {"r", NO_SPECIAL_RULE},
73     {"s", NO_SPECIAL_RULE},
74     {"t", NO_SPECIAL_RULE},
75     {"u", VOWEL},
76     {"v", NO_SPECIAL_RULE},
77     {"w", NO_SPECIAL_RULE},
78     {"x", NOT_BEGIN_SYLLABLE},
79     {"y", ALTERNATE_VOWEL | VOWEL},
80     {"z", NO_SPECIAL_RULE},
81     {"ch", NO_SPECIAL_RULE},
82     {"gh", NO_SPECIAL_RULE},
83     {"ph", NO_SPECIAL_RULE},
84     {"rh", NO_SPECIAL_RULE},
85     {"sh", NO_SPECIAL_RULE},
86     {"th", NO_SPECIAL_RULE},
87     {"wh", NO_SPECIAL_RULE},
88     {"qu", NO_SPECIAL_RULE},
89     {"ck", NOT_BEGIN_SYLLABLE}
90 };
91
92 static int  digram[][RULE_SIZE] =
93 {
94     {/* aa */ ILLEGAL_PAIR,
95      /* ab */ ANY_COMBINATION,
96      /* ac */ ANY_COMBINATION,
97      /* ad */ ANY_COMBINATION,
98      /* ae */ ILLEGAL_PAIR,
99      /* af */ ANY_COMBINATION,
100      /* ag */ ANY_COMBINATION,
101      /* ah */ NOT_BEGIN | BREAK | NOT_END,
102      /* ai */ ANY_COMBINATION,
103      /* aj */ ANY_COMBINATION,
104      /* ak */ ANY_COMBINATION,
105      /* al */ ANY_COMBINATION,
106      /* am */ ANY_COMBINATION,
107      /* an */ ANY_COMBINATION,
108      /* ao */ ILLEGAL_PAIR,
109      /* ap */ ANY_COMBINATION,
110      /* ar */ ANY_COMBINATION,
111      /* as */ ANY_COMBINATION,
112      /* at */ ANY_COMBINATION,
113      /* au */ ANY_COMBINATION,
114      /* av */ ANY_COMBINATION,
115      /* aw */ ANY_COMBINATION,
116      /* ax */ ANY_COMBINATION,
117      /* ay */ ANY_COMBINATION,
118      /* az */ ANY_COMBINATION,
119      /* ach */ ANY_COMBINATION,
120      /* agh */ ILLEGAL_PAIR,
121      /* aph */ ANY_COMBINATION,
122      /* arh */ ILLEGAL_PAIR,
123      /* ash */ ANY_COMBINATION,
124      /* ath */ ANY_COMBINATION,
125      /* awh */ ILLEGAL_PAIR,
126      /* aqu */ BREAK | NOT_END,
127      /* ack */ ANY_COMBINATION},
128     {/* ba */ ANY_COMBINATION,
129      /* bb */ NOT_BEGIN | BREAK | NOT_END,
130      /* bc */ NOT_BEGIN | BREAK | NOT_END,
131      /* bd */ NOT_BEGIN | BREAK | NOT_END,
132      /* be */ ANY_COMBINATION,
133      /* bf */ NOT_BEGIN | BREAK | NOT_END,
134      /* bg */ NOT_BEGIN | BREAK | NOT_END,
135      /* bh */ NOT_BEGIN | BREAK | NOT_END,
136      /* bi */ ANY_COMBINATION,
137      /* bj */ NOT_BEGIN | BREAK | NOT_END,
138      /* bk */ NOT_BEGIN | BREAK | NOT_END,
139      /* bl */ BEGIN | SUFFIX | NOT_END,
140      /* bm */ NOT_BEGIN | BREAK | NOT_END,
141      /* bn */ NOT_BEGIN | BREAK | NOT_END,
142      /* bo */ ANY_COMBINATION,
143      /* bp */ NOT_BEGIN | BREAK | NOT_END,
144      /* br */ BEGIN | END,
145      /* bs */ NOT_BEGIN,
146      /* bt */ NOT_BEGIN | BREAK | NOT_END,
147      /* bu */ ANY_COMBINATION,
148      /* bv */ NOT_BEGIN | BREAK | NOT_END,
149      /* bw */ NOT_BEGIN | BREAK | NOT_END,
150      /* bx */ ILLEGAL_PAIR,
151      /* by */ ANY_COMBINATION,
152      /* bz */ NOT_BEGIN | BREAK | NOT_END,
153      /* bch */ NOT_BEGIN | BREAK | NOT_END,
154      /* bgh */ ILLEGAL_PAIR,
155      /* bph */ NOT_BEGIN | BREAK | NOT_END,
156      /* brh */ ILLEGAL_PAIR,
157      /* bsh */ NOT_BEGIN | BREAK | NOT_END,
158      /* bth */ NOT_BEGIN | BREAK | NOT_END,
159      /* bwh */ ILLEGAL_PAIR,
160      /* bqu */ NOT_BEGIN | BREAK | NOT_END,
161      /* bck */ ILLEGAL_PAIR },
162     {/* ca */ ANY_COMBINATION,
163      /* cb */ NOT_BEGIN | BREAK | NOT_END,
164      /* cc */ NOT_BEGIN | BREAK | NOT_END,
165      /* cd */ NOT_BEGIN | BREAK | NOT_END,
166      /* ce */ ANY_COMBINATION,
167      /* cf */ NOT_BEGIN | BREAK | NOT_END,
168      /* cg */ NOT_BEGIN | BREAK | NOT_END,
169      /* ch */ NOT_BEGIN | BREAK | NOT_END,
170      /* ci */ ANY_COMBINATION,
171      /* cj */ NOT_BEGIN | BREAK | NOT_END,
172      /* ck */ NOT_BEGIN | BREAK | NOT_END,
173      /* cl */ SUFFIX | NOT_END,
174      /* cm */ NOT_BEGIN | BREAK | NOT_END,
175      /* cn */ NOT_BEGIN | BREAK | NOT_END,
176      /* co */ ANY_COMBINATION,
177      /* cp */ NOT_BEGIN | BREAK | NOT_END,
178      /* cr */ NOT_END,
179      /* cs */ NOT_BEGIN | END,
180      /* ct */ NOT_BEGIN | PREFIX,
181      /* cu */ ANY_COMBINATION,
182      /* cv */ NOT_BEGIN | BREAK | NOT_END,
183      /* cw */ NOT_BEGIN | BREAK | NOT_END,
184      /* cx */ ILLEGAL_PAIR,
185      /* cy */ ANY_COMBINATION,
186      /* cz */ NOT_BEGIN | BREAK | NOT_END,
187      /* cch */ ILLEGAL_PAIR,
188      /* cgh */ ILLEGAL_PAIR,
189      /* cph */ NOT_BEGIN | BREAK | NOT_END,
190      /* crh */ ILLEGAL_PAIR,
191      /* csh */ NOT_BEGIN | BREAK | NOT_END,
192      /* cth */ NOT_BEGIN | BREAK | NOT_END,
193      /* cwh */ ILLEGAL_PAIR,
194      /* cqu */ NOT_BEGIN | SUFFIX | NOT_END,
195      /* cck */ ILLEGAL_PAIR},
196     {/* da */ ANY_COMBINATION,
197      /* db */ NOT_BEGIN | BREAK | NOT_END,
198      /* dc */ NOT_BEGIN | BREAK | NOT_END,
199      /* dd */ NOT_BEGIN,
200      /* de */ ANY_COMBINATION,
201      /* df */ NOT_BEGIN | BREAK | NOT_END,
202      /* dg */ NOT_BEGIN | BREAK | NOT_END,
203      /* dh */ NOT_BEGIN | BREAK | NOT_END,
204      /* di */ ANY_COMBINATION,
205      /* dj */ NOT_BEGIN | BREAK | NOT_END,
206      /* dk */ NOT_BEGIN | BREAK | NOT_END,
207      /* dl */ NOT_BEGIN | BREAK | NOT_END,
208      /* dm */ NOT_BEGIN | BREAK | NOT_END,
209      /* dn */ NOT_BEGIN | BREAK | NOT_END,
210      /* do */ ANY_COMBINATION,
211      /* dp */ NOT_BEGIN | BREAK | NOT_END,
212      /* dr */ BEGIN | NOT_END,
213      /* ds */ NOT_BEGIN | END,
214      /* dt */ NOT_BEGIN | BREAK | NOT_END,
215      /* du */ ANY_COMBINATION,
216      /* dv */ NOT_BEGIN | BREAK | NOT_END,
217      /* dw */ NOT_BEGIN | BREAK | NOT_END,
218      /* dx */ ILLEGAL_PAIR,
219      /* dy */ ANY_COMBINATION,
220      /* dz */ NOT_BEGIN | BREAK | NOT_END,
221      /* dch */ NOT_BEGIN | BREAK | NOT_END,
222      /* dgh */ NOT_BEGIN | BREAK | NOT_END,
223      /* dph */ NOT_BEGIN | BREAK | NOT_END,
224      /* drh */ ILLEGAL_PAIR,
225      /* dsh */ NOT_BEGIN | NOT_END,
226      /* dth */ NOT_BEGIN | PREFIX,
227      /* dwh */ ILLEGAL_PAIR,
228      /* dqu */ NOT_BEGIN | BREAK | NOT_END,
229      /* dck */ ILLEGAL_PAIR },
230     {/* ea */ ANY_COMBINATION,
231      /* eb */ ANY_COMBINATION,
232      /* ec */ ANY_COMBINATION,
233      /* ed */ ANY_COMBINATION,
234      /* ee */ ANY_COMBINATION,
235      /* ef */ ANY_COMBINATION,
236      /* eg */ ANY_COMBINATION,
237      /* eh */ NOT_BEGIN | BREAK | NOT_END,
238      /* ei */ NOT_END,
239      /* ej */ ANY_COMBINATION,
240      /* ek */ ANY_COMBINATION,
241      /* el */ ANY_COMBINATION,
242      /* em */ ANY_COMBINATION,
243      /* en */ ANY_COMBINATION,
244      /* eo */ BREAK,
245      /* ep */ ANY_COMBINATION,
246      /* er */ ANY_COMBINATION,
247      /* es */ ANY_COMBINATION,
248      /* et */ ANY_COMBINATION,
249      /* eu */ ANY_COMBINATION,
250      /* ev */ ANY_COMBINATION,
251      /* ew */ ANY_COMBINATION,
252      /* ex */ ANY_COMBINATION,
253      /* ey */ ANY_COMBINATION,
254      /* ez */ ANY_COMBINATION,
255      /* ech */ ANY_COMBINATION,
256      /* egh */ NOT_BEGIN | BREAK | NOT_END,
257      /* eph */ ANY_COMBINATION,
258      /* erh */ ILLEGAL_PAIR,
259      /* esh */ ANY_COMBINATION,
260      /* eth */ ANY_COMBINATION,
261      /* ewh */ ILLEGAL_PAIR,
262      /* equ */ BREAK | NOT_END,
263      /* eck */ ANY_COMBINATION },
264     {/* fa */ ANY_COMBINATION,
265      /* fb */ NOT_BEGIN | BREAK | NOT_END,
266      /* fc */ NOT_BEGIN | BREAK | NOT_END,
267      /* fd */ NOT_BEGIN | BREAK | NOT_END,
268      /* fe */ ANY_COMBINATION,
269      /* ff */ NOT_BEGIN,
270      /* fg */ NOT_BEGIN | BREAK | NOT_END,
271      /* fh */ NOT_BEGIN | BREAK | NOT_END,
272      /* fi */ ANY_COMBINATION,
273      /* fj */ NOT_BEGIN | BREAK | NOT_END,
274      /* fk */ NOT_BEGIN | BREAK | NOT_END,
275      /* fl */ BEGIN | SUFFIX | NOT_END,
276      /* fm */ NOT_BEGIN | BREAK | NOT_END,
277      /* fn */ NOT_BEGIN | BREAK | NOT_END,
278      /* fo */ ANY_COMBINATION,
279      /* fp */ NOT_BEGIN | BREAK | NOT_END,
280      /* fr */ BEGIN | NOT_END,
281      /* fs */ NOT_BEGIN,
282      /* ft */ NOT_BEGIN,
283      /* fu */ ANY_COMBINATION,
284      /* fv */ NOT_BEGIN | BREAK | NOT_END,
285      /* fw */ NOT_BEGIN | BREAK | NOT_END,
286      /* fx */ ILLEGAL_PAIR,
287      /* fy */ NOT_BEGIN,
288      /* fz */ NOT_BEGIN | BREAK | NOT_END,
289      /* fch */ NOT_BEGIN | BREAK | NOT_END,
290      /* fgh */ NOT_BEGIN | BREAK | NOT_END,
291      /* fph */ NOT_BEGIN | BREAK | NOT_END,
292      /* frh */ ILLEGAL_PAIR,
293      /* fsh */ NOT_BEGIN | BREAK | NOT_END,
294      /* fth */ NOT_BEGIN | BREAK | NOT_END,
295      /* fwh */ ILLEGAL_PAIR,
296      /* fqu */ NOT_BEGIN | BREAK | NOT_END,
297      /* fck */ ILLEGAL_PAIR },
298     {/* ga */ ANY_COMBINATION,
299      /* gb */ NOT_BEGIN | BREAK | NOT_END,
300      /* gc */ NOT_BEGIN | BREAK | NOT_END,
301      /* gd */ NOT_BEGIN | BREAK | NOT_END,
302      /* ge */ ANY_COMBINATION,
303      /* gf */ NOT_BEGIN | BREAK | NOT_END,
304      /* gg */ NOT_BEGIN,
305      /* gh */ NOT_BEGIN | BREAK | NOT_END,
306      /* gi */ ANY_COMBINATION,
307      /* gj */ NOT_BEGIN | BREAK | NOT_END,
308      /* gk */ ILLEGAL_PAIR,
309      /* gl */ BEGIN | SUFFIX | NOT_END,
310      /* gm */ NOT_BEGIN | BREAK | NOT_END,
311      /* gn */ NOT_BEGIN | BREAK | NOT_END,
312      /* go */ ANY_COMBINATION,
313      /* gp */ NOT_BEGIN | BREAK | NOT_END,
314      /* gr */ BEGIN | NOT_END,
315      /* gs */ NOT_BEGIN | END,
316      /* gt */ NOT_BEGIN | BREAK | NOT_END,
317      /* gu */ ANY_COMBINATION,
318      /* gv */ NOT_BEGIN | BREAK | NOT_END,
319      /* gw */ NOT_BEGIN | BREAK | NOT_END,
320      /* gx */ ILLEGAL_PAIR,
321      /* gy */ NOT_BEGIN,
322      /* gz */ NOT_BEGIN | BREAK | NOT_END,
323      /* gch */ NOT_BEGIN | BREAK | NOT_END,
324      /* ggh */ ILLEGAL_PAIR,
325      /* gph */ NOT_BEGIN | BREAK | NOT_END,
326      /* grh */ ILLEGAL_PAIR,
327      /* gsh */ NOT_BEGIN,
328      /* gth */ NOT_BEGIN,
329      /* gwh */ ILLEGAL_PAIR,
330      /* gqu */ NOT_BEGIN | BREAK | NOT_END,
331      /* gck */ ILLEGAL_PAIR },
332     {/* ha */ ANY_COMBINATION,
333      /* hb */ NOT_BEGIN | BREAK | NOT_END,
334      /* hc */ NOT_BEGIN | BREAK | NOT_END,
335      /* hd */ NOT_BEGIN | BREAK | NOT_END,
336      /* he */ ANY_COMBINATION,
337      /* hf */ NOT_BEGIN | BREAK | NOT_END,
338      /* hg */ NOT_BEGIN | BREAK | NOT_END,
339      /* hh */ ILLEGAL_PAIR,
340      /* hi */ ANY_COMBINATION,
341      /* hj */ NOT_BEGIN | BREAK | NOT_END,
342      /* hk */ NOT_BEGIN | BREAK | NOT_END,
343      /* hl */ NOT_BEGIN | BREAK | NOT_END,
344      /* hm */ NOT_BEGIN | BREAK | NOT_END,
345      /* hn */ NOT_BEGIN | BREAK | NOT_END,
346      /* ho */ ANY_COMBINATION,
347      /* hp */ NOT_BEGIN | BREAK | NOT_END,
348      /* hr */ NOT_BEGIN | BREAK | NOT_END,
349      /* hs */ NOT_BEGIN | BREAK | NOT_END,
350      /* ht */ NOT_BEGIN | BREAK | NOT_END,
351      /* hu */ ANY_COMBINATION,
352      /* hv */ NOT_BEGIN | BREAK | NOT_END,
353      /* hw */ NOT_BEGIN | BREAK | NOT_END,
354      /* hx */ ILLEGAL_PAIR,
355      /* hy */ ANY_COMBINATION,
356      /* hz */ NOT_BEGIN | BREAK | NOT_END,
357      /* hch */ NOT_BEGIN | BREAK | NOT_END,
358      /* hgh */ NOT_BEGIN | BREAK | NOT_END,
359      /* hph */ NOT_BEGIN | BREAK | NOT_END,
360      /* hrh */ ILLEGAL_PAIR,
361      /* hsh */ NOT_BEGIN | BREAK | NOT_END,
362      /* hth */ NOT_BEGIN | BREAK | NOT_END,
363      /* hwh */ ILLEGAL_PAIR,
364      /* hqu */ NOT_BEGIN | BREAK | NOT_END,
365      /* hck */ ILLEGAL_PAIR },
366     {/* ia */ ANY_COMBINATION,
367      /* ib */ ANY_COMBINATION,
368      /* ic */ ANY_COMBINATION,
369      /* id */ ANY_COMBINATION,
370      /* ie */ NOT_BEGIN,
371      /* if */ ANY_COMBINATION,
372      /* ig */ ANY_COMBINATION,
373      /* ih */ NOT_BEGIN | BREAK | NOT_END,
374      /* ii */ ILLEGAL_PAIR,
375      /* ij */ ANY_COMBINATION,
376      /* ik */ ANY_COMBINATION,
377      /* il */ ANY_COMBINATION,
378      /* im */ ANY_COMBINATION,
379      /* in */ ANY_COMBINATION,
380      /* io */ BREAK,
381      /* ip */ ANY_COMBINATION,
382      /* ir */ ANY_COMBINATION,
383      /* is */ ANY_COMBINATION,
384      /* it */ ANY_COMBINATION,
385      /* iu */ NOT_BEGIN | BREAK | NOT_END,
386      /* iv */ ANY_COMBINATION,
387      /* iw */ NOT_BEGIN | BREAK | NOT_END,
388      /* ix */ ANY_COMBINATION,
389      /* iy */ NOT_BEGIN | BREAK | NOT_END,
390      /* iz */ ANY_COMBINATION,
391      /* ich */ ANY_COMBINATION,
392      /* igh */ NOT_BEGIN,
393      /* iph */ ANY_COMBINATION,
394      /* irh */ ILLEGAL_PAIR,
395      /* ish */ ANY_COMBINATION,
396      /* ith */ ANY_COMBINATION,
397      /* iwh */ ILLEGAL_PAIR,
398      /* iqu */ BREAK | NOT_END,
399      /* ick */ ANY_COMBINATION },
400     {/* ja */ ANY_COMBINATION,
401      /* jb */ NOT_BEGIN | BREAK | NOT_END,
402      /* jc */ NOT_BEGIN | BREAK | NOT_END,
403      /* jd */ NOT_BEGIN | BREAK | NOT_END,
404      /* je */ ANY_COMBINATION,
405      /* jf */ NOT_BEGIN | BREAK | NOT_END,
406      /* jg */ ILLEGAL_PAIR,
407      /* jh */ NOT_BEGIN | BREAK | NOT_END,
408      /* ji */ ANY_COMBINATION,
409      /* jj */ ILLEGAL_PAIR,
410      /* jk */ NOT_BEGIN | BREAK | NOT_END,
411      /* jl */ NOT_BEGIN | BREAK | NOT_END,
412      /* jm */ NOT_BEGIN | BREAK | NOT_END,
413      /* jn */ NOT_BEGIN | BREAK | NOT_END,
414      /* jo */ ANY_COMBINATION,
415      /* jp */ NOT_BEGIN | BREAK | NOT_END,
416      /* jr */ NOT_BEGIN | BREAK | NOT_END,
417      /* js */ NOT_BEGIN | BREAK | NOT_END,
418      /* jt */ NOT_BEGIN | BREAK | NOT_END,
419      /* ju */ ANY_COMBINATION,
420      /* jv */ NOT_BEGIN | BREAK | NOT_END,
421      /* jw */ NOT_BEGIN | BREAK | NOT_END,
422      /* jx */ ILLEGAL_PAIR,
423      /* jy */ NOT_BEGIN,
424      /* jz */ NOT_BEGIN | BREAK | NOT_END,
425      /* jch */ NOT_BEGIN | BREAK | NOT_END,
426      /* jgh */ NOT_BEGIN | BREAK | NOT_END,
427      /* jph */ NOT_BEGIN | BREAK | NOT_END,
428      /* jrh */ ILLEGAL_PAIR,
429      /* jsh */ NOT_BEGIN | BREAK | NOT_END,
430      /* jth */ NOT_BEGIN | BREAK | NOT_END,
431      /* jwh */ ILLEGAL_PAIR,
432      /* jqu */ NOT_BEGIN | BREAK | NOT_END,
433      /* jck */ ILLEGAL_PAIR },
434     {/* ka */ ANY_COMBINATION,
435      /* kb */ NOT_BEGIN | BREAK | NOT_END,
436      /* kc */ NOT_BEGIN | BREAK | NOT_END,
437      /* kd */ NOT_BEGIN | BREAK | NOT_END,
438      /* ke */ ANY_COMBINATION,
439      /* kf */ NOT_BEGIN | BREAK | NOT_END,
440      /* kg */ NOT_BEGIN | BREAK | NOT_END,
441      /* kh */ NOT_BEGIN | BREAK | NOT_END,
442      /* ki */ ANY_COMBINATION,
443      /* kj */ NOT_BEGIN | BREAK | NOT_END,
444      /* kk */ NOT_BEGIN | BREAK | NOT_END,
445      /* kl */ SUFFIX | NOT_END,
446      /* km */ NOT_BEGIN | BREAK | NOT_END,
447      /* kn */ BEGIN | SUFFIX | NOT_END,
448      /* ko */ ANY_COMBINATION,
449      /* kp */ NOT_BEGIN | BREAK | NOT_END,
450      /* kr */ SUFFIX | NOT_END,
451      /* ks */ NOT_BEGIN | END,
452      /* kt */ NOT_BEGIN | BREAK | NOT_END,
453      /* ku */ ANY_COMBINATION,
454      /* kv */ NOT_BEGIN | BREAK | NOT_END,
455      /* kw */ NOT_BEGIN | BREAK | NOT_END,
456      /* kx */ ILLEGAL_PAIR,
457      /* ky */ NOT_BEGIN,
458      /* kz */ NOT_BEGIN | BREAK | NOT_END,
459      /* kch */ NOT_BEGIN | BREAK | NOT_END,
460      /* kgh */ NOT_BEGIN | BREAK | NOT_END,
461      /* kph */ NOT_BEGIN | PREFIX,
462      /* krh */ ILLEGAL_PAIR,
463      /* ksh */ NOT_BEGIN,
464      /* kth */ NOT_BEGIN | BREAK | NOT_END,
465      /* kwh */ ILLEGAL_PAIR,
466      /* kqu */ NOT_BEGIN | BREAK | NOT_END,
467      /* kck */ ILLEGAL_PAIR },
468     {/* la */ ANY_COMBINATION,
469      /* lb */ NOT_BEGIN | PREFIX,
470      /* lc */ NOT_BEGIN | BREAK | NOT_END,
471      /* ld */ NOT_BEGIN | PREFIX,
472      /* le */ ANY_COMBINATION,
473      /* lf */ NOT_BEGIN | PREFIX,
474      /* lg */ NOT_BEGIN | PREFIX,
475      /* lh */ NOT_BEGIN | BREAK | NOT_END,
476      /* li */ ANY_COMBINATION,
477      /* lj */ NOT_BEGIN | PREFIX,
478      /* lk */ NOT_BEGIN | PREFIX,
479      /* ll */ NOT_BEGIN | PREFIX,
480      /* lm */ NOT_BEGIN | PREFIX,
481      /* ln */ NOT_BEGIN | BREAK | NOT_END,
482      /* lo */ ANY_COMBINATION,
483      /* lp */ NOT_BEGIN | PREFIX,
484      /* lr */ NOT_BEGIN | BREAK | NOT_END,
485      /* ls */ NOT_BEGIN,
486      /* lt */ NOT_BEGIN | PREFIX,
487      /* lu */ ANY_COMBINATION,
488      /* lv */ NOT_BEGIN | PREFIX,
489      /* lw */ NOT_BEGIN | BREAK | NOT_END,
490      /* lx */ ILLEGAL_PAIR,
491      /* ly */ ANY_COMBINATION,
492      /* lz */ NOT_BEGIN | BREAK | NOT_END,
493      /* lch */ NOT_BEGIN | PREFIX,
494      /* lgh */ NOT_BEGIN | BREAK | NOT_END,
495      /* lph */ NOT_BEGIN | PREFIX,
496      /* lrh */ ILLEGAL_PAIR,
497      /* lsh */ NOT_BEGIN | PREFIX,
498      /* lth */ NOT_BEGIN | PREFIX,
499      /* lwh */ ILLEGAL_PAIR,
500      /* lqu */ NOT_BEGIN | BREAK | NOT_END,
501      /* lck */ ILLEGAL_PAIR },
502     {/* ma */ ANY_COMBINATION,
503      /* mb */ NOT_BEGIN | BREAK | NOT_END,
504      /* mc */ NOT_BEGIN | BREAK | NOT_END,
505      /* md */ NOT_BEGIN | BREAK | NOT_END,
506      /* me */ ANY_COMBINATION,
507      /* mf */ NOT_BEGIN | BREAK | NOT_END,
508      /* mg */ NOT_BEGIN | BREAK | NOT_END,
509      /* mh */ NOT_BEGIN | BREAK | NOT_END,
510      /* mi */ ANY_COMBINATION,
511      /* mj */ NOT_BEGIN | BREAK | NOT_END,
512      /* mk */ NOT_BEGIN | BREAK | NOT_END,
513      /* ml */ NOT_BEGIN | BREAK | NOT_END,
514      /* mm */ NOT_BEGIN,
515      /* mn */ NOT_BEGIN | BREAK | NOT_END,
516      /* mo */ ANY_COMBINATION,
517      /* mp */ NOT_BEGIN,
518      /* mr */ NOT_BEGIN | BREAK | NOT_END,
519      /* ms */ NOT_BEGIN,
520      /* mt */ NOT_BEGIN,
521      /* mu */ ANY_COMBINATION,
522      /* mv */ NOT_BEGIN | BREAK | NOT_END,
523      /* mw */ NOT_BEGIN | BREAK | NOT_END,
524      /* mx */ ILLEGAL_PAIR,
525      /* my */ ANY_COMBINATION,
526      /* mz */ NOT_BEGIN | BREAK | NOT_END,
527      /* mch */ NOT_BEGIN | PREFIX,
528      /* mgh */ NOT_BEGIN | BREAK | NOT_END,
529      /* mph */ NOT_BEGIN,
530      /* mrh */ ILLEGAL_PAIR,
531      /* msh */ NOT_BEGIN,
532      /* mth */ NOT_BEGIN,
533      /* mwh */ ILLEGAL_PAIR,
534      /* mqu */ NOT_BEGIN | BREAK | NOT_END,
535      /* mck */ ILLEGAL_PAIR },
536     {/* na */ ANY_COMBINATION,
537      /* nb */ NOT_BEGIN | BREAK | NOT_END,
538      /* nc */ NOT_BEGIN | BREAK | NOT_END,
539      /* nd */ NOT_BEGIN,
540      /* ne */ ANY_COMBINATION,
541      /* nf */ NOT_BEGIN | BREAK | NOT_END,
542      /* ng */ NOT_BEGIN | PREFIX,
543      /* nh */ NOT_BEGIN | BREAK | NOT_END,
544      /* ni */ ANY_COMBINATION,
545      /* nj */ NOT_BEGIN | BREAK | NOT_END,
546      /* nk */ NOT_BEGIN | PREFIX,
547      /* nl */ NOT_BEGIN | BREAK | NOT_END,
548      /* nm */ NOT_BEGIN | BREAK | NOT_END,
549      /* nn */ NOT_BEGIN,
550      /* no */ ANY_COMBINATION,
551      /* np */ NOT_BEGIN | BREAK | NOT_END,
552      /* nr */ NOT_BEGIN | BREAK | NOT_END,
553      /* ns */ NOT_BEGIN,
554      /* nt */ NOT_BEGIN,
555      /* nu */ ANY_COMBINATION,
556      /* nv */ NOT_BEGIN | BREAK | NOT_END,
557      /* nw */ NOT_BEGIN | BREAK | NOT_END,
558      /* nx */ ILLEGAL_PAIR,
559      /* ny */ NOT_BEGIN,
560      /* nz */ NOT_BEGIN | BREAK | NOT_END,
561      /* nch */ NOT_BEGIN | PREFIX,
562      /* ngh */ NOT_BEGIN | BREAK | NOT_END,
563      /* nph */ NOT_BEGIN | PREFIX,
564      /* nrh */ ILLEGAL_PAIR,
565      /* nsh */ NOT_BEGIN,
566      /* nth */ NOT_BEGIN,
567      /* nwh */ ILLEGAL_PAIR,
568      /* nqu */ NOT_BEGIN | BREAK | NOT_END,
569      /* nck */ NOT_BEGIN | PREFIX },
570     {/* oa */ ANY_COMBINATION,
571      /* ob */ ANY_COMBINATION,
572      /* oc */ ANY_COMBINATION,
573      /* od */ ANY_COMBINATION,
574      /* oe */ ILLEGAL_PAIR,
575      /* of */ ANY_COMBINATION,
576      /* og */ ANY_COMBINATION,
577      /* oh */ NOT_BEGIN | BREAK | NOT_END,
578      /* oi */ ANY_COMBINATION,
579      /* oj */ ANY_COMBINATION,
580      /* ok */ ANY_COMBINATION,
581      /* ol */ ANY_COMBINATION,
582      /* om */ ANY_COMBINATION,
583      /* on */ ANY_COMBINATION,
584      /* oo */ ANY_COMBINATION,
585      /* op */ ANY_COMBINATION,
586      /* or */ ANY_COMBINATION,
587      /* os */ ANY_COMBINATION,
588      /* ot */ ANY_COMBINATION,
589      /* ou */ ANY_COMBINATION,
590      /* ov */ ANY_COMBINATION,
591      /* ow */ ANY_COMBINATION,
592      /* ox */ ANY_COMBINATION,
593      /* oy */ ANY_COMBINATION,
594      /* oz */ ANY_COMBINATION,
595      /* och */ ANY_COMBINATION,
596      /* ogh */ NOT_BEGIN,
597      /* oph */ ANY_COMBINATION,
598      /* orh */ ILLEGAL_PAIR,
599      /* osh */ ANY_COMBINATION,
600      /* oth */ ANY_COMBINATION,
601      /* owh */ ILLEGAL_PAIR,
602      /* oqu */ BREAK | NOT_END,
603      /* ock */ ANY_COMBINATION },
604     {/* pa */ ANY_COMBINATION,
605      /* pb */ NOT_BEGIN | BREAK | NOT_END,
606      /* pc */ NOT_BEGIN | BREAK | NOT_END,
607      /* pd */ NOT_BEGIN | BREAK | NOT_END,
608      /* pe */ ANY_COMBINATION,
609      /* pf */ NOT_BEGIN | BREAK | NOT_END,
610      /* pg */ NOT_BEGIN | BREAK | NOT_END,
611      /* ph */ NOT_BEGIN | BREAK | NOT_END,
612      /* pi */ ANY_COMBINATION,
613      /* pj */ NOT_BEGIN | BREAK | NOT_END,
614      /* pk */ NOT_BEGIN | BREAK | NOT_END,
615      /* pl */ SUFFIX | NOT_END,
616      /* pm */ NOT_BEGIN | BREAK | NOT_END,
617      /* pn */ NOT_BEGIN | BREAK | NOT_END,
618      /* po */ ANY_COMBINATION,
619      /* pp */ NOT_BEGIN | PREFIX,
620      /* pr */ NOT_END,
621      /* ps */ NOT_BEGIN | END,
622      /* pt */ NOT_BEGIN | END,
623      /* pu */ NOT_BEGIN | END,
624      /* pv */ NOT_BEGIN | BREAK | NOT_END,
625      /* pw */ NOT_BEGIN | BREAK | NOT_END,
626      /* px */ ILLEGAL_PAIR,
627      /* py */ ANY_COMBINATION,
628      /* pz */ NOT_BEGIN | BREAK | NOT_END,
629      /* pch */ NOT_BEGIN | BREAK | NOT_END,
630      /* pgh */ NOT_BEGIN | BREAK | NOT_END,
631      /* pph */ NOT_BEGIN | BREAK | NOT_END,
632      /* prh */ ILLEGAL_PAIR,
633      /* psh */ NOT_BEGIN | BREAK | NOT_END,
634      /* pth */ NOT_BEGIN | BREAK | NOT_END,
635      /* pwh */ ILLEGAL_PAIR,
636      /* pqu */ NOT_BEGIN | BREAK | NOT_END,
637      /* pck */ ILLEGAL_PAIR },
638     {/* ra */ ANY_COMBINATION,
639      /* rb */ NOT_BEGIN | PREFIX,
640      /* rc */ NOT_BEGIN | PREFIX,
641      /* rd */ NOT_BEGIN | PREFIX,
642      /* re */ ANY_COMBINATION,
643      /* rf */ NOT_BEGIN | PREFIX,
644      /* rg */ NOT_BEGIN | PREFIX,
645      /* rh */ NOT_BEGIN | BREAK | NOT_END,
646      /* ri */ ANY_COMBINATION,
647      /* rj */ NOT_BEGIN | PREFIX,
648      /* rk */ NOT_BEGIN | PREFIX,
649      /* rl */ NOT_BEGIN | PREFIX,
650      /* rm */ NOT_BEGIN | PREFIX,
651      /* rn */ NOT_BEGIN | PREFIX,
652      /* ro */ ANY_COMBINATION,
653      /* rp */ NOT_BEGIN | PREFIX,
654      /* rr */ NOT_BEGIN | PREFIX,
655      /* rs */ NOT_BEGIN | PREFIX,
656      /* rt */ NOT_BEGIN | PREFIX,
657      /* ru */ ANY_COMBINATION,
658      /* rv */ NOT_BEGIN | PREFIX,
659      /* rw */ NOT_BEGIN | BREAK | NOT_END,
660      /* rx */ ILLEGAL_PAIR,
661      /* ry */ ANY_COMBINATION,
662      /* rz */ NOT_BEGIN | PREFIX,
663      /* rch */ NOT_BEGIN | PREFIX,
664      /* rgh */ NOT_BEGIN | BREAK | NOT_END,
665      /* rph */ NOT_BEGIN | PREFIX,
666      /* rrh */ ILLEGAL_PAIR,
667      /* rsh */ NOT_BEGIN | PREFIX,
668      /* rth */ NOT_BEGIN | PREFIX,
669      /* rwh */ ILLEGAL_PAIR,
670      /* rqu */ NOT_BEGIN | PREFIX | NOT_END,
671      /* rck */ NOT_BEGIN | PREFIX },
672     {/* sa */ ANY_COMBINATION,
673      /* sb */ NOT_BEGIN | BREAK | NOT_END,
674      /* sc */ NOT_END,
675      /* sd */ NOT_BEGIN | BREAK | NOT_END,
676      /* se */ ANY_COMBINATION,
677      /* sf */ NOT_BEGIN | BREAK | NOT_END,
678      /* sg */ NOT_BEGIN | BREAK | NOT_END,
679      /* sh */ NOT_BEGIN | BREAK | NOT_END,
680      /* si */ ANY_COMBINATION,
681      /* sj */ NOT_BEGIN | BREAK | NOT_END,
682      /* sk */ ANY_COMBINATION,
683      /* sl */ BEGIN | SUFFIX | NOT_END,
684      /* sm */ SUFFIX | NOT_END,
685      /* sn */ PREFIX | SUFFIX | NOT_END,
686      /* so */ ANY_COMBINATION,
687      /* sp */ ANY_COMBINATION,
688      /* sr */ NOT_BEGIN | NOT_END,
689      /* ss */ NOT_BEGIN | PREFIX,
690      /* st */ ANY_COMBINATION,
691      /* su */ ANY_COMBINATION,
692      /* sv */ NOT_BEGIN | BREAK | NOT_END,
693      /* sw */ BEGIN | SUFFIX | NOT_END,
694      /* sx */ ILLEGAL_PAIR,
695      /* sy */ ANY_COMBINATION,
696      /* sz */ NOT_BEGIN | BREAK | NOT_END,
697      /* sch */ BEGIN | SUFFIX | NOT_END,
698      /* sgh */ NOT_BEGIN | BREAK | NOT_END,
699      /* sph */ NOT_BEGIN | BREAK | NOT_END,
700      /* srh */ ILLEGAL_PAIR,
701      /* ssh */ NOT_BEGIN | BREAK | NOT_END,
702      /* sth */ NOT_BEGIN | BREAK | NOT_END,
703      /* swh */ ILLEGAL_PAIR,
704      /* squ */ SUFFIX | NOT_END,
705      /* sck */ NOT_BEGIN },
706     {/* ta */ ANY_COMBINATION,
707      /* tb */ NOT_BEGIN | BREAK | NOT_END,
708      /* tc */ NOT_BEGIN | BREAK | NOT_END,
709      /* td */ NOT_BEGIN | BREAK | NOT_END,
710      /* te */ ANY_COMBINATION,
711      /* tf */ NOT_BEGIN | BREAK | NOT_END,
712      /* tg */ NOT_BEGIN | BREAK | NOT_END,
713      /* th */ NOT_BEGIN | BREAK | NOT_END,
714      /* ti */ ANY_COMBINATION,
715      /* tj */ NOT_BEGIN | BREAK | NOT_END,
716      /* tk */ NOT_BEGIN | BREAK | NOT_END,
717      /* tl */ NOT_BEGIN | BREAK | NOT_END,
718      /* tm */ NOT_BEGIN | BREAK | NOT_END,
719      /* tn */ NOT_BEGIN | BREAK | NOT_END,
720      /* to */ ANY_COMBINATION,
721      /* tp */ NOT_BEGIN | BREAK | NOT_END,
722      /* tr */ NOT_END,
723      /* ts */ NOT_BEGIN | END,
724      /* tt */ NOT_BEGIN | PREFIX,
725      /* tu */ ANY_COMBINATION,
726      /* tv */ NOT_BEGIN | BREAK | NOT_END,
727      /* tw */ BEGIN | SUFFIX | NOT_END,
728      /* tx */ ILLEGAL_PAIR,
729      /* ty */ ANY_COMBINATION,
730      /* tz */ NOT_BEGIN | BREAK | NOT_END,
731      /* tch */ NOT_BEGIN,
732      /* tgh */ NOT_BEGIN | BREAK | NOT_END,
733      /* tph */ NOT_BEGIN | END,
734      /* trh */ ILLEGAL_PAIR,
735      /* tsh */ NOT_BEGIN | END,
736      /* tth */ NOT_BEGIN | BREAK | NOT_END,
737      /* twh */ ILLEGAL_PAIR,
738      /* tqu */ NOT_BEGIN | BREAK | NOT_END,
739      /* tck */ ILLEGAL_PAIR },
740     {/* ua */ NOT_BEGIN | BREAK | NOT_END,
741      /* ub */ ANY_COMBINATION,
742      /* uc */ ANY_COMBINATION,
743      /* ud */ ANY_COMBINATION,
744      /* ue */ NOT_BEGIN,
745      /* uf */ ANY_COMBINATION,
746      /* ug */ ANY_COMBINATION,
747      /* uh */ NOT_BEGIN | BREAK | NOT_END,
748      /* ui */ NOT_BEGIN | BREAK | NOT_END,
749      /* uj */ ANY_COMBINATION,
750      /* uk */ ANY_COMBINATION,
751      /* ul */ ANY_COMBINATION,
752      /* um */ ANY_COMBINATION,
753      /* un */ ANY_COMBINATION,
754      /* uo */ NOT_BEGIN | BREAK,
755      /* up */ ANY_COMBINATION,
756      /* ur */ ANY_COMBINATION,
757      /* us */ ANY_COMBINATION,
758      /* ut */ ANY_COMBINATION,
759      /* uu */ ILLEGAL_PAIR,
760      /* uv */ ANY_COMBINATION,
761      /* uw */ NOT_BEGIN | BREAK | NOT_END,
762      /* ux */ ANY_COMBINATION,
763      /* uy */ NOT_BEGIN | BREAK | NOT_END,
764      /* uz */ ANY_COMBINATION,
765      /* uch */ ANY_COMBINATION,
766      /* ugh */ NOT_BEGIN | PREFIX,
767      /* uph */ ANY_COMBINATION,
768      /* urh */ ILLEGAL_PAIR,
769      /* ush */ ANY_COMBINATION,
770      /* uth */ ANY_COMBINATION,
771      /* uwh */ ILLEGAL_PAIR,
772      /* uqu */ BREAK | NOT_END,
773      /* uck */ ANY_COMBINATION },
774     {/* va */ ANY_COMBINATION,
775      /* vb */ NOT_BEGIN | BREAK | NOT_END,
776      /* vc */ NOT_BEGIN | BREAK | NOT_END,
777      /* vd */ NOT_BEGIN | BREAK | NOT_END,
778      /* ve */ ANY_COMBINATION,
779      /* vf */ NOT_BEGIN | BREAK | NOT_END,
780      /* vg */ NOT_BEGIN | BREAK | NOT_END,
781      /* vh */ NOT_BEGIN | BREAK | NOT_END,
782      /* vi */ ANY_COMBINATION,
783      /* vj */ NOT_BEGIN | BREAK | NOT_END,
784      /* vk */ NOT_BEGIN | BREAK | NOT_END,
785      /* vl */ NOT_BEGIN | BREAK | NOT_END,
786      /* vm */ NOT_BEGIN | BREAK | NOT_END,
787      /* vn */ NOT_BEGIN | BREAK | NOT_END,
788      /* vo */ ANY_COMBINATION,
789      /* vp */ NOT_BEGIN | BREAK | NOT_END,
790      /* vr */ NOT_BEGIN | BREAK | NOT_END,
791      /* vs */ NOT_BEGIN | BREAK | NOT_END,
792      /* vt */ NOT_BEGIN | BREAK | NOT_END,
793      /* vu */ ANY_COMBINATION,
794      /* vv */ NOT_BEGIN | BREAK | NOT_END,
795      /* vw */ NOT_BEGIN | BREAK | NOT_END,
796      /* vx */ ILLEGAL_PAIR,
797      /* vy */ NOT_BEGIN,
798      /* vz */ NOT_BEGIN | BREAK | NOT_END,
799      /* vch */ NOT_BEGIN | BREAK | NOT_END,
800      /* vgh */ NOT_BEGIN | BREAK | NOT_END,
801      /* vph */ NOT_BEGIN | BREAK | NOT_END,
802      /* vrh */ ILLEGAL_PAIR,
803      /* vsh */ NOT_BEGIN | BREAK | NOT_END,
804      /* vth */ NOT_BEGIN | BREAK | NOT_END,
805      /* vwh */ ILLEGAL_PAIR,
806      /* vqu */ NOT_BEGIN | BREAK | NOT_END,
807      /* vck */ ILLEGAL_PAIR },
808     {/* wa */ ANY_COMBINATION,
809      /* wb */ NOT_BEGIN | PREFIX,
810      /* wc */ NOT_BEGIN | BREAK | NOT_END,
811      /* wd */ NOT_BEGIN | PREFIX | END,
812      /* we */ ANY_COMBINATION,
813      /* wf */ NOT_BEGIN | PREFIX,
814      /* wg */ NOT_BEGIN | PREFIX | END,
815      /* wh */ NOT_BEGIN | BREAK | NOT_END,
816      /* wi */ ANY_COMBINATION,
817      /* wj */ NOT_BEGIN | BREAK | NOT_END,
818      /* wk */ NOT_BEGIN | PREFIX,
819      /* wl */ NOT_BEGIN | PREFIX | SUFFIX,
820      /* wm */ NOT_BEGIN | PREFIX,
821      /* wn */ NOT_BEGIN | PREFIX,
822      /* wo */ ANY_COMBINATION,
823      /* wp */ NOT_BEGIN | PREFIX,
824      /* wr */ BEGIN | SUFFIX | NOT_END,
825      /* ws */ NOT_BEGIN | PREFIX,
826      /* wt */ NOT_BEGIN | PREFIX,
827      /* wu */ ANY_COMBINATION,
828      /* wv */ NOT_BEGIN | PREFIX,
829      /* ww */ NOT_BEGIN | BREAK | NOT_END,
830      /* wx */ NOT_BEGIN | PREFIX,
831      /* wy */ ANY_COMBINATION,
832      /* wz */ NOT_BEGIN | PREFIX,
833      /* wch */ NOT_BEGIN,
834      /* wgh */ NOT_BEGIN | BREAK | NOT_END,
835      /* wph */ NOT_BEGIN,
836      /* wrh */ ILLEGAL_PAIR,
837      /* wsh */ NOT_BEGIN,
838      /* wth */ NOT_BEGIN,
839      /* wwh */ ILLEGAL_PAIR,
840      /* wqu */ NOT_BEGIN | BREAK | NOT_END,
841      /* wck */ NOT_BEGIN },
842     {/* xa */ NOT_BEGIN,
843      /* xb */ NOT_BEGIN | BREAK | NOT_END,
844      /* xc */ NOT_BEGIN | BREAK | NOT_END,
845      /* xd */ NOT_BEGIN | BREAK | NOT_END,
846      /* xe */ NOT_BEGIN,
847      /* xf */ NOT_BEGIN | BREAK | NOT_END,
848      /* xg */ NOT_BEGIN | BREAK | NOT_END,
849      /* xh */ NOT_BEGIN | BREAK | NOT_END,
850      /* xi */ NOT_BEGIN,
851      /* xj */ NOT_BEGIN | BREAK | NOT_END,
852      /* xk */ NOT_BEGIN | BREAK | NOT_END,
853      /* xl */ NOT_BEGIN | BREAK | NOT_END,
854      /* xm */ NOT_BEGIN | BREAK | NOT_END,
855      /* xn */ NOT_BEGIN | BREAK | NOT_END,
856      /* xo */ NOT_BEGIN,
857      /* xp */ NOT_BEGIN | BREAK | NOT_END,
858      /* xr */ NOT_BEGIN | BREAK | NOT_END,
859      /* xs */ NOT_BEGIN | BREAK | NOT_END,
860      /* xt */ NOT_BEGIN | BREAK | NOT_END,
861      /* xu */ NOT_BEGIN,
862      /* xv */ NOT_BEGIN | BREAK | NOT_END,
863      /* xw */ NOT_BEGIN | BREAK | NOT_END,
864      /* xx */ ILLEGAL_PAIR,
865      /* xy */ NOT_BEGIN,
866      /* xz */ NOT_BEGIN | BREAK | NOT_END,
867      /* xch */ NOT_BEGIN | BREAK | NOT_END,
868      /* xgh */ NOT_BEGIN | BREAK | NOT_END,
869      /* xph */ NOT_BEGIN | BREAK | NOT_END,
870      /* xrh */ ILLEGAL_PAIR,
871      /* xsh */ NOT_BEGIN | BREAK | NOT_END,
872      /* xth */ NOT_BEGIN | BREAK | NOT_END,
873      /* xwh */ ILLEGAL_PAIR,
874      /* xqu */ NOT_BEGIN | BREAK | NOT_END,
875      /* xck */ ILLEGAL_PAIR },
876     {/* ya */ ANY_COMBINATION,
877      /* yb */ NOT_BEGIN,
878      /* yc */ NOT_BEGIN | NOT_END,
879      /* yd */ NOT_BEGIN,
880      /* ye */ ANY_COMBINATION,
881      /* yf */ NOT_BEGIN | NOT_END,
882      /* yg */ NOT_BEGIN,
883      /* yh */ NOT_BEGIN | BREAK | NOT_END,
884      /* yi */ BEGIN | NOT_END,
885      /* yj */ NOT_BEGIN | NOT_END,
886      /* yk */ NOT_BEGIN,
887      /* yl */ NOT_BEGIN | NOT_END,
888      /* ym */ NOT_BEGIN,
889      /* yn */ NOT_BEGIN,
890      /* yo */ ANY_COMBINATION,
891      /* yp */ NOT_BEGIN,
892      /* yr */ NOT_BEGIN | BREAK | NOT_END,
893      /* ys */ NOT_BEGIN,
894      /* yt */ NOT_BEGIN,
895      /* yu */ ANY_COMBINATION,
896      /* yv */ NOT_BEGIN | NOT_END,
897      /* yw */ NOT_BEGIN | BREAK | NOT_END,
898      /* yx */ NOT_BEGIN,
899      /* yy */ ILLEGAL_PAIR,
900      /* yz */ NOT_BEGIN,
901      /* ych */ NOT_BEGIN | BREAK | NOT_END,
902      /* ygh */ NOT_BEGIN | BREAK | NOT_END,
903      /* yph */ NOT_BEGIN | BREAK | NOT_END,
904      /* yrh */ ILLEGAL_PAIR,
905      /* ysh */ NOT_BEGIN | BREAK | NOT_END,
906      /* yth */ NOT_BEGIN | BREAK | NOT_END,
907      /* ywh */ ILLEGAL_PAIR,
908      /* yqu */ NOT_BEGIN | BREAK | NOT_END,
909      /* yck */ ILLEGAL_PAIR },
910     {/* za */ ANY_COMBINATION,
911      /* zb */ NOT_BEGIN | BREAK | NOT_END,
912      /* zc */ NOT_BEGIN | BREAK | NOT_END,
913      /* zd */ NOT_BEGIN | BREAK | NOT_END,
914      /* ze */ ANY_COMBINATION,
915      /* zf */ NOT_BEGIN | BREAK | NOT_END,
916      /* zg */ NOT_BEGIN | BREAK | NOT_END,
917      /* zh */ NOT_BEGIN | BREAK | NOT_END,
918      /* zi */ ANY_COMBINATION,
919      /* zj */ NOT_BEGIN | BREAK | NOT_END,
920      /* zk */ NOT_BEGIN | BREAK | NOT_END,
921      /* zl */ NOT_BEGIN | BREAK | NOT_END,
922      /* zm */ NOT_BEGIN | BREAK | NOT_END,
923      /* zn */ NOT_BEGIN | BREAK | NOT_END,
924      /* zo */ ANY_COMBINATION,
925      /* zp */ NOT_BEGIN | BREAK | NOT_END,
926      /* zr */ NOT_BEGIN | NOT_END,
927      /* zs */ NOT_BEGIN | BREAK | NOT_END,
928      /* zt */ NOT_BEGIN,
929      /* zu */ ANY_COMBINATION,
930      /* zv */ NOT_BEGIN | BREAK | NOT_END,
931      /* zw */ SUFFIX | NOT_END,
932      /* zx */ ILLEGAL_PAIR,
933      /* zy */ ANY_COMBINATION,
934      /* zz */ NOT_BEGIN,
935      /* zch */ NOT_BEGIN | BREAK | NOT_END,
936      /* zgh */ NOT_BEGIN | BREAK | NOT_END,
937      /* zph */ NOT_BEGIN | BREAK | NOT_END,
938      /* zrh */ ILLEGAL_PAIR,
939      /* zsh */ NOT_BEGIN | BREAK | NOT_END,
940      /* zth */ NOT_BEGIN | BREAK | NOT_END,
941      /* zwh */ ILLEGAL_PAIR,
942      /* zqu */ NOT_BEGIN | BREAK | NOT_END,
943      /* zck */ ILLEGAL_PAIR },
944     {/* cha */ ANY_COMBINATION,
945      /* chb */ NOT_BEGIN | BREAK | NOT_END,
946      /* chc */ NOT_BEGIN | BREAK | NOT_END,
947      /* chd */ NOT_BEGIN | BREAK | NOT_END,
948      /* che */ ANY_COMBINATION,
949      /* chf */ NOT_BEGIN | BREAK | NOT_END,
950      /* chg */ NOT_BEGIN | BREAK | NOT_END,
951      /* chh */ NOT_BEGIN | BREAK | NOT_END,
952      /* chi */ ANY_COMBINATION,
953      /* chj */ NOT_BEGIN | BREAK | NOT_END,
954      /* chk */ NOT_BEGIN | BREAK | NOT_END,
955      /* chl */ NOT_BEGIN | BREAK | NOT_END,
956      /* chm */ NOT_BEGIN | BREAK | NOT_END,
957      /* chn */ NOT_BEGIN | BREAK | NOT_END,
958      /* cho */ ANY_COMBINATION,
959      /* chp */ NOT_BEGIN | BREAK | NOT_END,
960      /* chr */ NOT_END,
961      /* chs */ NOT_BEGIN | BREAK | NOT_END,
962      /* cht */ NOT_BEGIN | BREAK | NOT_END,
963      /* chu */ ANY_COMBINATION,
964      /* chv */ NOT_BEGIN | BREAK | NOT_END,
965      /* chw */ NOT_BEGIN | NOT_END,
966      /* chx */ ILLEGAL_PAIR,
967      /* chy */ ANY_COMBINATION,
968      /* chz */ NOT_BEGIN | BREAK | NOT_END,
969      /* chch */ ILLEGAL_PAIR,
970      /* chgh */ NOT_BEGIN | BREAK | NOT_END,
971      /* chph */ NOT_BEGIN | BREAK | NOT_END,
972      /* chrh */ ILLEGAL_PAIR,
973      /* chsh */ NOT_BEGIN | BREAK | NOT_END,
974      /* chth */ NOT_BEGIN | BREAK | NOT_END,
975      /* chwh */ ILLEGAL_PAIR,
976      /* chqu */ NOT_BEGIN | BREAK | NOT_END,
977      /* chck */ ILLEGAL_PAIR },
978     {/* gha */ ANY_COMBINATION,
979      /* ghb */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
980      /* ghc */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
981      /* ghd */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
982      /* ghe */ ANY_COMBINATION,
983      /* ghf */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
984      /* ghg */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
985      /* ghh */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
986      /* ghi */ BEGIN | NOT_END,
987      /* ghj */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
988      /* ghk */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
989      /* ghl */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
990      /* ghm */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
991      /* ghn */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
992      /* gho */ BEGIN | NOT_END,
993      /* ghp */ NOT_BEGIN | BREAK | NOT_END,
994      /* ghr */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
995      /* ghs */ NOT_BEGIN | PREFIX,
996      /* ght */ NOT_BEGIN | PREFIX,
997      /* ghu */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
998      /* ghv */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
999      /* ghw */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
1000      /* ghx */ ILLEGAL_PAIR,
1001      /* ghy */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
1002      /* ghz */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
1003      /* ghch */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
1004      /* ghgh */ ILLEGAL_PAIR,
1005      /* ghph */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
1006      /* ghrh */ ILLEGAL_PAIR,
1007      /* ghsh */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
1008      /* ghth */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
1009      /* ghwh */ ILLEGAL_PAIR,
1010      /* ghqu */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
1011      /* ghck */ ILLEGAL_PAIR },
1012     {/* pha */ ANY_COMBINATION,
1013      /* phb */ NOT_BEGIN | BREAK | NOT_END,
1014      /* phc */ NOT_BEGIN | BREAK | NOT_END,
1015      /* phd */ NOT_BEGIN | BREAK | NOT_END,
1016      /* phe */ ANY_COMBINATION,
1017      /* phf */ NOT_BEGIN | BREAK | NOT_END,
1018      /* phg */ NOT_BEGIN | BREAK | NOT_END,
1019      /* phh */ NOT_BEGIN | BREAK | NOT_END,
1020      /* phi */ ANY_COMBINATION,
1021      /* phj */ NOT_BEGIN | BREAK | NOT_END,
1022      /* phk */ NOT_BEGIN | BREAK | NOT_END,
1023      /* phl */ BEGIN | SUFFIX | NOT_END,
1024      /* phm */ NOT_BEGIN | BREAK | NOT_END,
1025      /* phn */ NOT_BEGIN | BREAK | NOT_END,
1026      /* pho */ ANY_COMBINATION,
1027      /* php */ NOT_BEGIN | BREAK | NOT_END,
1028      /* phr */ NOT_END,
1029      /* phs */ NOT_BEGIN,
1030      /* pht */ NOT_BEGIN,
1031      /* phu */ ANY_COMBINATION,
1032      /* phv */ NOT_BEGIN | NOT_END,
1033      /* phw */ NOT_BEGIN | NOT_END,
1034      /* phx */ ILLEGAL_PAIR,
1035      /* phy */ NOT_BEGIN,
1036      /* phz */ NOT_BEGIN | BREAK | NOT_END,
1037      /* phch */ NOT_BEGIN | BREAK | NOT_END,
1038      /* phgh */ NOT_BEGIN | BREAK | NOT_END,
1039      /* phph */ ILLEGAL_PAIR,
1040      /* phrh */ ILLEGAL_PAIR,
1041      /* phsh */ NOT_BEGIN | BREAK | NOT_END,
1042      /* phth */ NOT_BEGIN | BREAK | NOT_END,
1043      /* phwh */ ILLEGAL_PAIR,
1044      /* phqu */ NOT_BEGIN | BREAK | NOT_END,
1045      /* phck */ ILLEGAL_PAIR },
1046     {/* rha */ BEGIN | NOT_END,
1047      /* rhb */ ILLEGAL_PAIR,
1048      /* rhc */ ILLEGAL_PAIR,
1049      /* rhd */ ILLEGAL_PAIR,
1050      /* rhe */ BEGIN | NOT_END,
1051      /* rhf */ ILLEGAL_PAIR,
1052      /* rhg */ ILLEGAL_PAIR,
1053      /* rhh */ ILLEGAL_PAIR,
1054      /* rhi */ BEGIN | NOT_END,
1055      /* rhj */ ILLEGAL_PAIR,
1056      /* rhk */ ILLEGAL_PAIR,
1057      /* rhl */ ILLEGAL_PAIR,
1058      /* rhm */ ILLEGAL_PAIR,
1059      /* rhn */ ILLEGAL_PAIR,
1060      /* rho */ BEGIN | NOT_END,
1061      /* rhp */ ILLEGAL_PAIR,
1062      /* rhr */ ILLEGAL_PAIR,
1063      /* rhs */ ILLEGAL_PAIR,
1064      /* rht */ ILLEGAL_PAIR,
1065      /* rhu */ BEGIN | NOT_END,
1066      /* rhv */ ILLEGAL_PAIR,
1067      /* rhw */ ILLEGAL_PAIR,
1068      /* rhx */ ILLEGAL_PAIR,
1069      /* rhy */ BEGIN | NOT_END,
1070      /* rhz */ ILLEGAL_PAIR,
1071      /* rhch */ ILLEGAL_PAIR,
1072      /* rhgh */ ILLEGAL_PAIR,
1073      /* rhph */ ILLEGAL_PAIR,
1074      /* rhrh */ ILLEGAL_PAIR,
1075      /* rhsh */ ILLEGAL_PAIR,
1076      /* rhth */ ILLEGAL_PAIR,
1077      /* rhwh */ ILLEGAL_PAIR,
1078      /* rhqu */ ILLEGAL_PAIR,
1079      /* rhck */ ILLEGAL_PAIR },
1080     {/* sha */ ANY_COMBINATION,
1081      /* shb */ NOT_BEGIN | BREAK | NOT_END,
1082      /* shc */ NOT_BEGIN | BREAK | NOT_END,
1083      /* shd */ NOT_BEGIN | BREAK | NOT_END,
1084      /* she */ ANY_COMBINATION,
1085      /* shf */ NOT_BEGIN | BREAK | NOT_END,
1086      /* shg */ NOT_BEGIN | BREAK | NOT_END,
1087      /* shh */ ILLEGAL_PAIR,
1088      /* shi */ ANY_COMBINATION,
1089      /* shj */ NOT_BEGIN | BREAK | NOT_END,
1090      /* shk */ NOT_BEGIN,
1091      /* shl */ BEGIN | SUFFIX | NOT_END,
1092      /* shm */ BEGIN | SUFFIX | NOT_END,
1093      /* shn */ BEGIN | SUFFIX | NOT_END,
1094      /* sho */ ANY_COMBINATION,
1095      /* shp */ NOT_BEGIN,
1096      /* shr */ BEGIN | SUFFIX | NOT_END,
1097      /* shs */ NOT_BEGIN | BREAK | NOT_END,
1098      /* sht */ SUFFIX,
1099      /* shu */ ANY_COMBINATION,
1100      /* shv */ NOT_BEGIN | BREAK | NOT_END,
1101      /* shw */ SUFFIX | NOT_END,
1102      /* shx */ ILLEGAL_PAIR,
1103      /* shy */ ANY_COMBINATION,
1104      /* shz */ NOT_BEGIN | BREAK | NOT_END,
1105      /* shch */ NOT_BEGIN | BREAK | NOT_END,
1106      /* shgh */ NOT_BEGIN | BREAK | NOT_END,
1107      /* shph */ NOT_BEGIN | BREAK | NOT_END,
1108      /* shrh */ ILLEGAL_PAIR,
1109      /* shsh */ ILLEGAL_PAIR,
1110      /* shth */ NOT_BEGIN | BREAK | NOT_END,
1111      /* shwh */ ILLEGAL_PAIR,
1112      /* shqu */ NOT_BEGIN | BREAK | NOT_END,
1113      /* shck */ ILLEGAL_PAIR },
1114     {/* tha */ ANY_COMBINATION,
1115      /* thb */ NOT_BEGIN | BREAK | NOT_END,
1116      /* thc */ NOT_BEGIN | BREAK | NOT_END,
1117      /* thd */ NOT_BEGIN | BREAK | NOT_END,
1118      /* the */ ANY_COMBINATION,
1119      /* thf */ NOT_BEGIN | BREAK | NOT_END,
1120      /* thg */ NOT_BEGIN | BREAK | NOT_END,
1121      /* thh */ NOT_BEGIN | BREAK | NOT_END,
1122      /* thi */ ANY_COMBINATION,
1123      /* thj */ NOT_BEGIN | BREAK | NOT_END,
1124      /* thk */ NOT_BEGIN | BREAK | NOT_END,
1125      /* thl */ NOT_BEGIN | BREAK | NOT_END,
1126      /* thm */ NOT_BEGIN | BREAK | NOT_END,
1127      /* thn */ NOT_BEGIN | BREAK | NOT_END,
1128      /* tho */ ANY_COMBINATION,
1129      /* thp */ NOT_BEGIN | BREAK | NOT_END,
1130      /* thr */ NOT_END,
1131      /* ths */ NOT_BEGIN | END,
1132      /* tht */ NOT_BEGIN | BREAK | NOT_END,
1133      /* thu */ ANY_COMBINATION,
1134      /* thv */ NOT_BEGIN | BREAK | NOT_END,
1135      /* thw */ SUFFIX | NOT_END,
1136      /* thx */ ILLEGAL_PAIR,
1137      /* thy */ ANY_COMBINATION,
1138      /* thz */ NOT_BEGIN | BREAK | NOT_END,
1139      /* thch */ NOT_BEGIN | BREAK | NOT_END,
1140      /* thgh */ NOT_BEGIN | BREAK | NOT_END,
1141      /* thph */ NOT_BEGIN | BREAK | NOT_END,
1142      /* thrh */ ILLEGAL_PAIR,
1143      /* thsh */ NOT_BEGIN | BREAK | NOT_END,
1144      /* thth */ ILLEGAL_PAIR,
1145      /* thwh */ ILLEGAL_PAIR,
1146      /* thqu */ NOT_BEGIN | BREAK | NOT_END,
1147      /* thck */ ILLEGAL_PAIR },
1148     {/* wha */ BEGIN | NOT_END,
1149      /* whb */ ILLEGAL_PAIR,
1150      /* whc */ ILLEGAL_PAIR,
1151      /* whd */ ILLEGAL_PAIR,
1152      /* whe */ BEGIN | NOT_END,
1153      /* whf */ ILLEGAL_PAIR,
1154      /* whg */ ILLEGAL_PAIR,
1155      /* whh */ ILLEGAL_PAIR,
1156      /* whi */ BEGIN | NOT_END,
1157      /* whj */ ILLEGAL_PAIR,
1158      /* whk */ ILLEGAL_PAIR,
1159      /* whl */ ILLEGAL_PAIR,
1160      /* whm */ ILLEGAL_PAIR,
1161      /* whn */ ILLEGAL_PAIR,
1162      /* who */ BEGIN | NOT_END,
1163      /* whp */ ILLEGAL_PAIR,
1164      /* whr */ ILLEGAL_PAIR,
1165      /* whs */ ILLEGAL_PAIR,
1166      /* wht */ ILLEGAL_PAIR,
1167      /* whu */ ILLEGAL_PAIR,
1168      /* whv */ ILLEGAL_PAIR,
1169      /* whw */ ILLEGAL_PAIR,
1170      /* whx */ ILLEGAL_PAIR,
1171      /* why */ BEGIN | NOT_END,
1172      /* whz */ ILLEGAL_PAIR,
1173      /* whch */ ILLEGAL_PAIR,
1174      /* whgh */ ILLEGAL_PAIR,
1175      /* whph */ ILLEGAL_PAIR,
1176      /* whrh */ ILLEGAL_PAIR,
1177      /* whsh */ ILLEGAL_PAIR,
1178      /* whth */ ILLEGAL_PAIR,
1179      /* whwh */ ILLEGAL_PAIR,
1180      /* whqu */ ILLEGAL_PAIR,
1181      /* whck */ ILLEGAL_PAIR },
1182     {/* qua */ ANY_COMBINATION,
1183      /* qub */ ILLEGAL_PAIR,
1184      /* quc */ ILLEGAL_PAIR,
1185      /* qud */ ILLEGAL_PAIR,
1186      /* que */ ANY_COMBINATION,
1187      /* quf */ ILLEGAL_PAIR,
1188      /* qug */ ILLEGAL_PAIR,
1189      /* quh */ ILLEGAL_PAIR,
1190      /* qui */ ANY_COMBINATION,
1191      /* quj */ ILLEGAL_PAIR,
1192      /* quk */ ILLEGAL_PAIR,
1193      /* qul */ ILLEGAL_PAIR,
1194      /* qum */ ILLEGAL_PAIR,
1195      /* qun */ ILLEGAL_PAIR,
1196      /* quo */ ANY_COMBINATION,
1197      /* qup */ ILLEGAL_PAIR,
1198      /* qur */ ILLEGAL_PAIR,
1199      /* qus */ ILLEGAL_PAIR,
1200      /* qut */ ILLEGAL_PAIR,
1201      /* quu */ ILLEGAL_PAIR,
1202      /* quv */ ILLEGAL_PAIR,
1203      /* quw */ ILLEGAL_PAIR,
1204      /* qux */ ILLEGAL_PAIR,
1205      /* quy */ ILLEGAL_PAIR,
1206      /* quz */ ILLEGAL_PAIR,
1207      /* quch */ ILLEGAL_PAIR,
1208      /* qugh */ ILLEGAL_PAIR,
1209      /* quph */ ILLEGAL_PAIR,
1210      /* qurh */ ILLEGAL_PAIR,
1211      /* qush */ ILLEGAL_PAIR,
1212      /* quth */ ILLEGAL_PAIR,
1213      /* quwh */ ILLEGAL_PAIR,
1214      /* ququ */ ILLEGAL_PAIR,
1215      /* quck */ ILLEGAL_PAIR },
1216     {/* cka */ NOT_BEGIN | BREAK | NOT_END,
1217      /* ckb */ NOT_BEGIN | BREAK | NOT_END,
1218      /* ckc */ NOT_BEGIN | BREAK | NOT_END,
1219      /* ckd */ NOT_BEGIN | BREAK | NOT_END,
1220      /* cke */ NOT_BEGIN | BREAK | NOT_END,
1221      /* ckf */ NOT_BEGIN | BREAK | NOT_END,
1222      /* ckg */ NOT_BEGIN | BREAK | NOT_END,
1223      /* ckh */ NOT_BEGIN | BREAK | NOT_END,
1224      /* cki */ NOT_BEGIN | BREAK | NOT_END,
1225      /* ckj */ NOT_BEGIN | BREAK | NOT_END,
1226      /* ckk */ NOT_BEGIN | BREAK | NOT_END,
1227      /* ckl */ NOT_BEGIN | BREAK | NOT_END,
1228      /* ckm */ NOT_BEGIN | BREAK | NOT_END,
1229      /* ckn */ NOT_BEGIN | BREAK | NOT_END,
1230      /* cko */ NOT_BEGIN | BREAK | NOT_END,
1231      /* ckp */ NOT_BEGIN | BREAK | NOT_END,
1232      /* ckr */ NOT_BEGIN | BREAK | NOT_END,
1233      /* cks */ NOT_BEGIN,
1234      /* ckt */ NOT_BEGIN | BREAK | NOT_END,
1235      /* cku */ NOT_BEGIN | BREAK | NOT_END,
1236      /* ckv */ NOT_BEGIN | BREAK | NOT_END,
1237      /* ckw */ NOT_BEGIN | BREAK | NOT_END,
1238      /* ckx */ ILLEGAL_PAIR,
1239      /* cky */ NOT_BEGIN,
1240      /* ckz */ NOT_BEGIN | BREAK | NOT_END,
1241      /* ckch */ NOT_BEGIN | BREAK | NOT_END,
1242      /* ckgh */ NOT_BEGIN | BREAK | NOT_END,
1243      /* ckph */ NOT_BEGIN | BREAK | NOT_END,
1244      /* ckrh */ ILLEGAL_PAIR,
1245      /* cksh */ NOT_BEGIN | BREAK | NOT_END,
1246      /* ckth */ NOT_BEGIN | BREAK | NOT_END,
1247      /* ckwh */ ILLEGAL_PAIR,
1248      /* ckqu */ NOT_BEGIN | BREAK | NOT_END,
1249      /* ckck */ ILLEGAL_PAIR}
1250 };
1251
1252 /*
1253 ** gen_pron_pass will generate a Random word and place it in the
1254 ** buffer word.  Also, the hyphenated word will be placed into
1255 ** the buffer hyphenated_word.  Both word and hyphenated_word must
1256 ** be pre-allocated.  The words generated will have sizes between
1257 ** minlen and maxlen.  If restrict is TRUE, words will not be generated that
1258 ** appear as login names or as entries in the on-line dictionary.
1259 ** This algorithm was initially worded out by Morrie Gasser in 1975.
1260 ** Any changes here are minimal so that as many word combinations
1261 ** can be produced as possible (and thus keep the words Random).
1262 ** The seed is used on first use of the routine.
1263 ** The length of the unhyphenated word is returned, or -1 if there
1264 ** were an error (length settings are wrong or dictionary checking
1265 ** could not be done.
1266 */
1267 int
1268 gen_pron_pass (char *word, char *hyphenated_word, USHORT minlen,
1269                USHORT maxlen, unsigned int pass_mode)
1270 {
1271
1272     int     pwlen;
1273
1274  /* 
1275   * Check for minlen>maxlen.  This is an error.
1276   * and a length of 0.
1277   */
1278     if (minlen > maxlen || minlen > APG_MAX_PASSWORD_LENGTH ||
1279         maxlen > APG_MAX_PASSWORD_LENGTH)
1280       return (-1);
1281  /* 
1282   * Check for zero length words.  This is technically not an error,
1283   * so we take the short cut and return a null word and a length of 0.
1284   */
1285     if (maxlen == 0)
1286     {
1287      word[0] = '\0';
1288      hyphenated_word[0] = '\0';
1289      return (0);
1290     }
1291
1292  /* 
1293   * Find password.
1294   */
1295     pwlen = gen_word (word, hyphenated_word, get_random (minlen, maxlen), pass_mode);
1296     return (pwlen);
1297 }
1298
1299
1300 /*
1301  * This is the routine that returns a Random word -- as
1302  * yet unchecked against the passwd file or the dictionary.
1303  * It collects Random syllables until a predetermined
1304  * word length is found.  If a retry threshold is reached,
1305  * another word is tried.  Given that the Random number
1306  * generator is uniformly distributed, eventually a word
1307  * will be found if the retry limit is adequately large enough.
1308  */
1309 int
1310 gen_word (char *word, char *hyphenated_word, USHORT pwlen, unsigned int pass_mode)
1311 {
1312     USHORT word_length;
1313     USHORT syllable_length;
1314     char   *new_syllable;
1315     char   *syllable_for_hyph;
1316     USHORT *syllable_units;
1317     USHORT word_size;
1318     USHORT word_place;
1319     USHORT *word_units;
1320     USHORT syllable_size;
1321     UINT   tries;
1322     int ch_flag = FALSE;
1323     int dsd = 0;
1324
1325     /*
1326      * Keep count of retries.
1327      */
1328     tries = 0;
1329
1330     /*
1331      * The length of the word in characters.
1332      */
1333     word_length = 0;
1334
1335     /*
1336      * The length of the word in character units (each of which is one or
1337      * two characters long.
1338      */
1339     word_size = 0;
1340
1341     /*
1342      * Initialize the array storing the word units.  Since we know the
1343      * length of the word, we only need one of that length.  This method is
1344      * preferable to a static array, since it allows us flexibility in
1345      * choosing arbitrarily long word lengths.  Since a word can contain one
1346      * syllable, we should make syllable_units, the array holding the
1347      * analogous units for an individual syllable, the same length. No
1348      * explicit rule limits the length of syllables, but digram rules and
1349      * heuristics do so indirectly.
1350      */
1351     if ( (word_units     = (USHORT *) calloc (sizeof (USHORT), pwlen+1))==NULL ||
1352          (syllable_units = (USHORT *) calloc (sizeof (USHORT), pwlen+1))==NULL ||
1353          (new_syllable   = (char *) calloc (sizeof (USHORT), pwlen+1))  ==NULL ||
1354          (syllable_for_hyph = (char *) calloc (sizeof(char), 20))==NULL)
1355            return(-1);
1356
1357     /*
1358      * Find syllables until the entire word is constructed.
1359      */
1360     while (word_length < pwlen)
1361     {
1362      /*
1363       * Get the syllable and find its length.
1364       */
1365      (void) gen_syllable (new_syllable, pwlen - word_length, syllable_units, &syllable_size);
1366      syllable_length = strlen (new_syllable);
1367      
1368      /*
1369       * Append the syllable units to the word units.
1370       */
1371      for (word_place = 0; word_place <= syllable_size; word_place++)
1372          word_units[word_size + word_place] = syllable_units[word_place];
1373      word_size += syllable_size + 1;
1374
1375      /* 
1376       * If the word has been improperly formed, throw out
1377       * the syllable.  The checks performed here are those
1378       * that must be formed on a word basis.  The other
1379       * tests are performed entirely within the syllable.
1380       * Otherwise, append the syllable to the word and
1381       * append the syllable to the hyphenated version of
1382       * the word.
1383       */
1384      if (improper_word (word_units, word_size) ||
1385         ((word_length == 0) && have_initial_y (syllable_units, syllable_size)) ||
1386         ((word_length + syllable_length == pwlen) && have_final_split (syllable_units, syllable_size)))
1387            word_size -= syllable_size + 1;
1388      else
1389      {
1390          if (word_length == 0)
1391          {
1392           /*
1393           ** Modify syllable for numeric or capital symbols required
1394           ** Should be done after word quality check. 
1395           */
1396           dsd = randint(2);
1397           if ( ((pass_mode & S_NB) > 0) && (syllable_length == 1) && dsd == 0)
1398             {
1399              numerize(new_syllable);
1400              ch_flag = TRUE;
1401             }
1402           if ( ((pass_mode & S_SS) > 0) && (syllable_length == 1) && (dsd == 1))
1403             {
1404               specialize(new_syllable);
1405               ch_flag = TRUE;
1406             }
1407           if ( ( (pass_mode & S_CL) > 0) && (ch_flag != TRUE))
1408              capitalize(new_syllable);
1409           ch_flag = FALSE;
1410           /**/
1411           (void) strcpy (word, new_syllable);
1412           if (syllable_length == 1)
1413              {
1414               symb2name(new_syllable, syllable_for_hyph);
1415               (void) strcpy (hyphenated_word, syllable_for_hyph);
1416              }
1417           else
1418              {
1419               (void) strcpy (hyphenated_word, new_syllable);
1420              }
1421           (void)memset ( (void *)new_syllable, 0, (size_t)(pwlen * sizeof(USHORT)+1));
1422           (void)memset ( (void *)syllable_for_hyph, 0, 20);
1423          }
1424          else
1425          {
1426           /*
1427           ** Modify syllable for numeric or capital symbols required
1428           ** Should be done after word quality check.
1429           */
1430           dsd = randint(2);
1431           if ( ((pass_mode & S_NB) > 0) && (syllable_length == 1) && (dsd == 0))
1432             {
1433              numerize(new_syllable);
1434              ch_flag = TRUE;
1435             }
1436           if ( ( (pass_mode & S_SS) > 0) && (syllable_length == 1) && (dsd == 1))
1437             {
1438              specialize(new_syllable);
1439              ch_flag = TRUE;
1440             }
1441           if ( ( (pass_mode & S_CL) > 0) && (ch_flag != TRUE))
1442              capitalize(new_syllable);
1443           ch_flag = FALSE;
1444           /**/
1445           (void) strcat (word, new_syllable);
1446           (void) strcat (hyphenated_word, "-");
1447           if (syllable_length == 1)
1448              {
1449               symb2name(new_syllable, syllable_for_hyph);
1450               (void) strcat (hyphenated_word, syllable_for_hyph);
1451              }
1452           else
1453              {
1454               (void) strcat (hyphenated_word, new_syllable);
1455              }
1456           (void)memset ( (void *)new_syllable, 0, (size_t)(pwlen * sizeof(USHORT)+1));
1457           (void)memset ( (void *)syllable_for_hyph, 0, 20);
1458          }
1459          word_length += syllable_length;
1460      }
1461
1462        /* 
1463         * Keep track of the times we have tried to get
1464         * syllables.  If we have exceeded the threshold,
1465         * reinitialize the pwlen and word_size variables, clear
1466         * out the word arrays, and start from scratch.
1467         */
1468      tries++;
1469      if (tries > MAX_RETRIES)
1470      {
1471          word_length = 0;
1472          word_size = 0;
1473          tries = 0;
1474          (void) strcpy (word, "");
1475          (void) strcpy (hyphenated_word, "");
1476      }
1477     }
1478
1479     /* 
1480      * The units arrays and syllable storage are internal to this
1481      * routine.  Since the caller has no need for them, we
1482      * release the space.
1483      */
1484     free ((char *) new_syllable);
1485     free ((char *) syllable_units);
1486     free ((char *) word_units);
1487     free ((char *) syllable_for_hyph);
1488
1489     return ((int) word_length);
1490 }
1491
1492
1493
1494 /*
1495  * Check that the word does not contain illegal combinations
1496  * that may span syllables.  Specifically, these are:
1497  *   1. An illegal pair of units between syllables.
1498  *   2. Three consecutive vowel units.
1499  *   3. Three consecutive consonant units.
1500  * The checks are made against units (1 or 2 letters), not against
1501  * the individual letters, so three consecutive units can have
1502  * the length of 6 at most.
1503  */
1504 boolean
1505 improper_word (USHORT *units, USHORT word_size)
1506 {
1507     USHORT unit_count;
1508     boolean failure;
1509
1510     failure = FALSE;
1511
1512     for (unit_count = 0; !failure && (unit_count < word_size);
1513          unit_count++)
1514     {
1515      /* 
1516       * Check for ILLEGAL_PAIR.  This should have been caught
1517       * for units within a syllable, but in some cases it
1518       * would have gone unnoticed for units between syllables
1519       * (e.g., when saved_unit's in gen_syllable() were not
1520       * used).
1521       */
1522      if ((unit_count != 0) &&
1523           (digram[units[unit_count - 1]][units[unit_count]] &
1524               ILLEGAL_PAIR))
1525          failure = TRUE;
1526
1527      /* 
1528       * Check for consecutive vowels or consonants.  Because
1529       * the initial y of a syllable is treated as a consonant
1530       * rather than as a vowel, we exclude y from the first
1531       * vowel in the vowel test.  The only problem comes when
1532       * y ends a syllable and two other vowels start the next,
1533       * like fly-oint.  Since such words are still
1534       * pronounceable, we accept this.
1535       */
1536      if (!failure && (unit_count >= 2))
1537      {
1538          /*
1539           * Vowel check.
1540           */
1541          if ((((rules[units[unit_count - 2]].flags & VOWEL) &&
1542                    !(rules[units[unit_count - 2]].flags &
1543                     ALTERNATE_VOWEL)) &&
1544                (rules[units[unit_count - 1]].flags & VOWEL) &&
1545                (rules[units[unit_count]].flags & VOWEL)) ||
1546          /*
1547           * Consonant check.
1548           */
1549               (!(rules[units[unit_count - 2]].flags & VOWEL) &&
1550                !(rules[units[unit_count - 1]].flags & VOWEL) &&
1551                !(rules[units[unit_count]].flags & VOWEL)))
1552           failure = TRUE;
1553      }
1554     }
1555
1556     return (failure);
1557 }
1558
1559
1560 /*
1561  * Treating y as a vowel is sometimes a problem.  Some words
1562  * get formed that look irregular.  One special group is when
1563  * y starts a word and is the only vowel in the first syllable.
1564  * The word ycl is one example.  We discard words like these.
1565  */
1566 boolean
1567 have_initial_y (USHORT *units, USHORT unit_size)
1568 {
1569     USHORT unit_count;
1570     USHORT vowel_count;
1571     USHORT normal_vowel_count;
1572
1573     vowel_count = 0;
1574     normal_vowel_count = 0;
1575
1576     for (unit_count = 0; unit_count <= unit_size; unit_count++)
1577      /*
1578       * Count vowels.
1579       */
1580      if (rules[units[unit_count]].flags & VOWEL)
1581      {
1582          vowel_count++;
1583
1584          /*
1585           * Count the vowels that are not: 1. y, 2. at the start of
1586           * the word.
1587           */
1588          if (!(rules[units[unit_count]].flags & ALTERNATE_VOWEL) ||
1589               (unit_count != 0))
1590           normal_vowel_count++;
1591      }
1592
1593     return ((vowel_count <= 1) && (normal_vowel_count == 0));
1594 }
1595
1596
1597 /*
1598  * Besides the problem with the letter y, there is one with
1599  * a silent e at the end of words, like face or nice.  We
1600  * allow this silent e, but we do not allow it as the only
1601  * vowel at the end of the word or syllables like ble will
1602  * be generated.
1603  */
1604 boolean
1605 have_final_split (USHORT *units, USHORT unit_size)
1606 {
1607     USHORT unit_count;
1608     USHORT vowel_count;
1609
1610     vowel_count = 0;
1611
1612     /*
1613      *    Count all the vowels in the word.
1614      */
1615     for (unit_count = 0; unit_count <= unit_size; unit_count++)
1616      if (rules[units[unit_count]].flags & VOWEL)
1617          vowel_count++;
1618
1619     /*
1620      * Return TRUE iff the only vowel was e, found at the end if the
1621      * word.
1622      */
1623     return ((vowel_count == 1) &&
1624          (rules[units[unit_size]].flags & NO_FINAL_SPLIT));
1625 }
1626
1627
1628 /*
1629  * Generate next unit to password, making sure that it follows
1630  * these rules:
1631  *   1. Each syllable must contain exactly 1 or 2 consecutive
1632  *      vowels, where y is considered a vowel.
1633  *   2. Syllable end is determined as follows:
1634  *        a. Vowel is generated and previous unit is a
1635  *           consonant and syllable already has a vowel.  In
1636  *           this case, new syllable is started and already
1637  *           contains a vowel.
1638  *        b. A pair determined to be a "break" pair is encountered.
1639  *           In this case new syllable is started with second unit
1640  *           of this pair.
1641  *        c. End of password is encountered.
1642  *        d. "begin" pair is encountered legally.  New syllable is
1643  *           started with this pair.
1644  *        e. "end" pair is legally encountered.  New syllable has
1645  *           nothing yet.
1646  *   3. Try generating another unit if:
1647  *        a. third consecutive vowel and not y.
1648  *        b. "break" pair generated but no vowel yet in current
1649  *           or previous 2 units are "not_end".
1650  *        c. "begin" pair generated but no vowel in syllable
1651  *           preceding begin pair, or both previous 2 pairs are
1652  *          designated "not_end".
1653  *        d. "end" pair generated but no vowel in current syllable
1654  *           or in "end" pair.
1655  *        e. "not_begin" pair generated but new syllable must
1656  *           begin (because previous syllable ended as defined in
1657  *           2 above).
1658  *        f. vowel is generated and 2a is satisfied, but no syllable
1659  *           break is possible in previous 3 pairs.
1660  *        g. Second and third units of syllable must begin, and
1661  *           first unit is "alternate_vowel".
1662  */
1663 char *
1664 gen_syllable (char *syllable, USHORT pwlen, USHORT *units_in_syllable,
1665               USHORT *syllable_length)
1666 {
1667     USHORT  unit = 0;
1668     SHORT   current_unit = 0;
1669     USHORT  vowel_count = 0;
1670     boolean rule_broken;
1671     boolean want_vowel;
1672     boolean want_another_unit;
1673     UINT    tries = 0;
1674     USHORT  last_unit = 0;
1675     SHORT   length_left = 0;
1676     USHORT  hold_saved_unit = 0;
1677     static  USHORT saved_unit;
1678     static  USHORT saved_pair[2];
1679
1680     /*
1681      * This is needed if the saved_unit is tries and the syllable then
1682      * discarded because of the retry limit. Since the saved_unit is OK and
1683      * fits in nicely with the preceding syllable, we will always use it.
1684      */
1685     hold_saved_unit = saved_unit;
1686
1687     /*
1688      * Loop until valid syllable is found.
1689      */
1690     do
1691     {
1692      /* 
1693       * Try for a new syllable.  Initialize all pertinent
1694       * syllable variables.
1695       */
1696      tries = 0;
1697      saved_unit = hold_saved_unit;
1698      (void) strcpy (syllable, "");
1699      vowel_count = 0;
1700      current_unit = 0;
1701      length_left = (short int) pwlen;
1702      want_another_unit = TRUE;
1703
1704      /*
1705       * This loop finds all the units for the syllable.
1706       */
1707      do
1708      {
1709          want_vowel = FALSE;
1710
1711          /*
1712           * This loop continues until a valid unit is found for the
1713           * current position within the syllable.
1714           */
1715          do
1716          {
1717           /* 
1718            * If there are saved_unit's from the previous
1719            * syllable, use them up first.
1720            */
1721           if (saved_unit != 0)
1722           {
1723               /* 
1724                * If there were two saved units, the first is
1725                * guaranteed (by checks performed in the previous
1726                * syllable) to be valid.  We ignore the checks
1727                * and place it in this syllable manually.
1728                */
1729               if (saved_unit == 2)
1730               {
1731                units_in_syllable[0] = saved_pair[1];
1732                if (rules[saved_pair[1]].flags & VOWEL)
1733                    vowel_count++;
1734                current_unit++;
1735                (void) strcpy (syllable, rules[saved_pair[1]].unit_code);
1736                length_left -= strlen (syllable);
1737               }
1738
1739               /* 
1740                * The unit becomes the last unit checked in the
1741                * previous syllable.
1742                */
1743               unit = saved_pair[0];
1744
1745               /*
1746                * The saved units have been used.  Do not try to
1747                * reuse them in this syllable (unless this particular
1748                * syllable is rejected at which point we start to rebuild
1749                * it with these same saved units.
1750                */
1751               saved_unit = 0;
1752           }
1753           else
1754               /* 
1755                * If we don't have to scoff the saved units,
1756                * we generate a Random one.  If we know it has
1757                * to be a vowel, we get one rather than looping
1758                * through until one shows up.
1759                */
1760               if (want_vowel)
1761                unit = random_unit (VOWEL);
1762               else
1763                unit = random_unit (NO_SPECIAL_RULE);
1764           length_left -= (short int) strlen (rules[unit].unit_code);
1765
1766           /*
1767            * Prevent having a word longer than expected.
1768            */
1769           if (length_left < 0)
1770               rule_broken = TRUE;
1771           else
1772               rule_broken = FALSE;
1773
1774           /*
1775            * First unit of syllable.  This is special because the
1776            * digram tests require 2 units and we don't have that yet.
1777            * Nevertheless, we can perform some checks.
1778            */
1779           if (current_unit == 0)
1780           {
1781               /* 
1782                * If the shouldn't begin a syllable, don't
1783                * use it.
1784                */
1785               if (rules[unit].flags & NOT_BEGIN_SYLLABLE)
1786                rule_broken = TRUE;
1787               else
1788                /* 
1789                 * If this is the last unit of a word,
1790                 * we have a one unit syllable.  Since each
1791                 * syllable must have a vowel, we make sure
1792                 * the unit is a vowel.  Otherwise, we
1793                 * discard it.
1794                 */
1795                if (length_left == 0)
1796                   {
1797                    if (rules[unit].flags & VOWEL)
1798                     want_another_unit = FALSE;
1799                    else
1800                     rule_broken = TRUE;
1801                   }
1802           }
1803           else
1804           {
1805               /* 
1806                * There are some digram tests that are
1807                * universally true.  We test them out.
1808                */
1809
1810               /*
1811                * Reject ILLEGAL_PAIRS of units.
1812                */
1813               if ((ALLOWED (ILLEGAL_PAIR)) ||
1814
1815               /*
1816                * Reject units that will be split between syllables
1817                * when the syllable has no vowels in it.
1818                */
1819                    (ALLOWED (BREAK) && (vowel_count == 0)) ||
1820
1821               /*
1822                * Reject a unit that will end a syllable when no
1823                * previous unit was a vowel and neither is this one.
1824                */
1825                    (ALLOWED (END) && (vowel_count == 0) &&
1826                     !(rules[unit].flags & VOWEL)))
1827                rule_broken = TRUE;
1828
1829               if (current_unit == 1)
1830               {
1831                /*
1832                 * Reject the unit if we are at te starting digram of
1833                 * a syllable and it does not fit.
1834                 */
1835                if (ALLOWED (NOT_BEGIN))
1836                    rule_broken = TRUE;
1837               }
1838               else
1839               {
1840                /* 
1841                 * We are not at the start of a syllable.
1842                 * Save the previous unit for later tests.
1843                 */
1844                last_unit = units_in_syllable[current_unit - 1];
1845
1846                /*
1847                 * Do not allow syllables where the first letter is y
1848                 * and the next pair can begin a syllable.  This may
1849                 * lead to splits where y is left alone in a syllable.
1850                 * Also, the combination does not sound to good even
1851                 * if not split.
1852                 */
1853                if (((current_unit == 2) &&
1854                         (ALLOWED (BEGIN)) &&
1855                         (rules[units_in_syllable[0]].flags &
1856                          ALTERNATE_VOWEL)) ||
1857
1858                     /*
1859                      * If this is the last unit of a word, we should
1860                      * reject any digram that cannot end a syllable.
1861                      */
1862                     (ALLOWED (NOT_END) &&
1863                         (length_left == 0)) ||
1864
1865                     /*
1866                      * Reject the unit if the digram it forms wants
1867                      * to break the syllable, but the resulting
1868                      * digram that would end the syllable is not
1869                      * allowed to end a syllable.
1870                      */
1871                     (ALLOWED (BREAK) &&
1872                         (digram[units_in_syllable
1873                              [current_unit - 2]]
1874                          [last_unit] &
1875                          NOT_END)) ||
1876
1877                     /*
1878                      * Reject the unit if the digram it forms
1879                      * expects a vowel preceding it and there is
1880                      * none.
1881                      */
1882                     (ALLOWED (PREFIX) &&
1883                         !(rules[units_in_syllable
1884                              [current_unit - 2]].flags &
1885                          VOWEL)))
1886                    rule_broken = TRUE;
1887
1888                /*
1889                 * The following checks occur when the current unit
1890                 * is a vowel and we are not looking at a word ending
1891                 * with an e.
1892                 */
1893                if (!rule_broken &&
1894                     (rules[unit].flags & VOWEL) &&
1895                     ((length_left > 0) ||
1896                         !(rules[last_unit].flags &
1897                          NO_FINAL_SPLIT)))
1898                   {
1899                    /*
1900                     * Don't allow 3 consecutive vowels in a
1901                     * syllable.  Although some words formed like this
1902                     * are OK, like beau, most are not.
1903                     */
1904                    if ((vowel_count > 1) &&
1905                         (rules[last_unit].flags & VOWEL))
1906                     rule_broken = TRUE;
1907                    else
1908                     /*
1909                      * Check for the case of
1910                      * vowels-consonants-vowel, which is only
1911                      * legal if the last vowel is an e and we are
1912                      * the end of the word (wich is not
1913                      * happening here due to a previous check.
1914                      */
1915                     if ((vowel_count != 0) &&
1916                          !(rules[last_unit].flags & VOWEL))
1917                     {
1918                         /*
1919                          * Try to save the vowel for the next
1920                          * syllable, but if the syllable left here
1921                          * is not proper (i.e., the resulting last
1922                          * digram cannot legally end it), just
1923                          * discard it and try for another.   
1924                          */
1925                         if (digram[units_in_syllable
1926                               [current_unit - 2]]
1927                              [last_unit] &
1928                              NOT_END)
1929                          rule_broken = TRUE;
1930                         else
1931                         {
1932                          saved_unit = 1;
1933                          saved_pair[0] = unit;
1934                          want_another_unit = FALSE;
1935                         }
1936                     }
1937                   }
1938               }
1939
1940               /*
1941                * The unit picked and the digram formed are legal.
1942                * We now determine if we can end the syllable.  It may,
1943                * in some cases, mean the last unit(s) may be deferred to
1944                * the next syllable.  We also check here to see if the
1945                * digram formed expects a vowel to follow.
1946                */
1947               if (!rule_broken && want_another_unit)
1948               {
1949                /*
1950                 * This word ends in a silent e.
1951                 */
1952 /******/        if (((vowel_count != 0) &&
1953                      (rules[unit].flags & NO_FINAL_SPLIT) &&
1954                      (length_left == 0) &&
1955                     !(rules[last_unit].flags & VOWEL)) ||
1956
1957                     /*
1958                      * This syllable ends either because the digram
1959                      * is an END pair or we would otherwise exceed
1960                      * the length of the word.
1961                      */
1962                     (ALLOWED (END) || (length_left == 0)))
1963                    {
1964                    want_another_unit = FALSE;
1965                    }
1966                else
1967                    /*
1968                     * Since we have a vowel in the syllable
1969                     * already, if the digram calls for the end of the
1970                     * syllable, we can legally split it off. We also
1971                     * make sure that we are not at the end of the
1972                     * dangerous because that syllable may not have
1973                     * vowels, or it may not be a legal syllable end,
1974                     * and the retrying mechanism will loop infinitely
1975                     * with the same digram.
1976                     */
1977                    if ((vowel_count != 0) && (length_left > 0))
1978                    {
1979                     /*
1980                      * If we must begin a syllable, we do so if
1981                      * the only vowel in THIS syllable is not part
1982                      * of the digram we are pushing to the next
1983                      * syllable.
1984                      */
1985                     if (ALLOWED (BEGIN) &&
1986                          (current_unit > 1) &&
1987                          !((vowel_count == 1) &&
1988                          (rules[last_unit].flags & VOWEL)))
1989                     {
1990                         saved_unit = 2;
1991                         saved_pair[0] = unit;
1992                         saved_pair[1] = last_unit;
1993                         want_another_unit = FALSE;
1994                     }
1995                     else
1996                         if (ALLOWED (BREAK))
1997                         {
1998                          saved_unit = 1;
1999                          saved_pair[0] = unit;
2000                          want_another_unit = FALSE;
2001                         }
2002                    }
2003                    else
2004                     if (ALLOWED (SUFFIX))
2005                      {
2006                         want_vowel = TRUE;
2007                      }
2008               }
2009           }
2010 /********/
2011           tries++;
2012
2013           /*
2014            * If this unit was illegal, redetermine the amount of
2015            * letters left to go in the word.
2016            */
2017           if (rule_broken)
2018               length_left += (short int) strlen (rules[unit].unit_code);
2019          }
2020          while (rule_broken && (tries <= MAX_RETRIES));
2021
2022          /*
2023           * The unit fit OK.
2024           */
2025          if (tries <= MAX_RETRIES)
2026          {
2027           /* 
2028            * If the unit were a vowel, count it in.
2029            * However, if the unit were a y and appear
2030            * at the start of the syllable, treat it
2031            * like a constant (so that words like year can
2032            * appear and not conflict with the 3 consecutive
2033            * vowel rule.
2034            */
2035           if ((rules[unit].flags & VOWEL) &&
2036                ((current_unit > 0) ||
2037                    !(rules[unit].flags & ALTERNATE_VOWEL)))
2038               vowel_count++;
2039
2040           /* 
2041            * If a unit or units were to be saved, we must
2042            * adjust the syllable formed.  Otherwise, we
2043            * append the current unit to the syllable.
2044            */
2045           switch (saved_unit)
2046           {
2047               case 0: 
2048                units_in_syllable[current_unit] = unit;
2049                (void) strcat (syllable, rules[unit].unit_code);
2050                break;
2051               case 1: 
2052                current_unit--;
2053                break;
2054               case 2: 
2055                (void) strcpy (&syllable[strlen (syllable) -
2056                         strlen (rules[last_unit].unit_code)],"");
2057                length_left += (short int) strlen (rules[last_unit].unit_code);
2058                current_unit -= 2;
2059                break;
2060           }
2061          }
2062          else
2063          /*
2064           * Whoops!  Too many tries.  We set rule_broken so we can
2065           * loop in the outer loop and try another syllable.
2066           */
2067           rule_broken = TRUE;
2068
2069          /*
2070           * ...and the syllable length grows.
2071           */
2072          *syllable_length = current_unit;
2073
2074          current_unit++;
2075      }
2076      while ((tries <= MAX_RETRIES) && want_another_unit);
2077     }
2078     while (rule_broken ||
2079            illegal_placement (units_in_syllable, *syllable_length));
2080
2081     return (syllable);
2082 }
2083
2084
2085 /*
2086  * This routine goes through an individual syllable and checks
2087  * for illegal combinations of letters that go beyond looking
2088  * at digrams.  We look at things like 3 consecutive vowels or
2089  * consonants, or syllables with consonants between vowels (unless
2090  * one of them is the final silent e).
2091  */
2092 boolean
2093 illegal_placement (USHORT *units, USHORT pwlen)
2094 {
2095     USHORT vowel_count;
2096     USHORT unit_count;
2097     boolean failure;
2098
2099     vowel_count = 0;
2100     failure = FALSE;
2101
2102     for (unit_count = 0; !failure && (unit_count <= pwlen);
2103          unit_count++)
2104     {
2105      if (unit_count >= 1)
2106      {
2107          /* 
2108           * Don't allow vowels to be split with consonants in
2109           * a single syllable.  If we find such a combination
2110           * (except for the silent e) we have to discard the
2111           * syllable).
2112           */
2113          if ((!(rules[units[unit_count - 1]].flags & VOWEL) &&
2114                (rules[units[unit_count]].flags & VOWEL) &&
2115                !((rules[units[unit_count]].flags & NO_FINAL_SPLIT) &&
2116                    (unit_count == pwlen)) && (vowel_count != 0)) ||
2117          /*
2118           * Perform these checks when we have at least 3 units.
2119           */
2120               ((unit_count >= 2) &&
2121
2122                   /*
2123                    * Disallow 3 consecutive consonants.
2124                    */
2125                ((!(rules[units[unit_count - 2]].flags & VOWEL) &&
2126                     !(rules[units[unit_count - 1]].flags &
2127                         VOWEL) &&
2128                     !(rules[units[unit_count]].flags &
2129                         VOWEL)) ||
2130
2131                    /*
2132                     * Disallow 3 consecutive vowels, where the first is
2133                     * not a y.
2134                     */
2135                    (((rules[units[unit_count - 2]].flags &
2136                          VOWEL) &&
2137                         !((rules[units[0]].flags &
2138                              ALTERNATE_VOWEL) &&
2139                          (unit_count == 2))) &&
2140                     (rules[units[unit_count - 1]].flags &
2141                         VOWEL) &&
2142                     (rules[units[unit_count]].flags &
2143                         VOWEL)))))
2144           failure = TRUE;
2145      }
2146
2147      /* 
2148       * Count the vowels in the syllable.  As mentioned somewhere
2149       * above, exclude the initial y of a syllable.  Instead,
2150       * treat it as a consonant.
2151       */
2152      if ((rules[units[unit_count]].flags & VOWEL) &&
2153           !((rules[units[0]].flags & ALTERNATE_VOWEL) &&
2154               (unit_count == 0) && (pwlen != 0)))
2155          vowel_count++;
2156     }
2157
2158     return (failure);
2159 }
2160
2161
2162
2163 /*
2164  * This is the standard Random unit generating routine for
2165  * gen_syllable().  It does not reference the digrams, but
2166  * assumes that it contains 34 units in a particular order.
2167  * This routine attempts to return unit indexes with a distribution
2168  * approaching that of the distribution of the 34 units in
2169  * English.  In order to do this, a Random number (supposedly
2170  * uniformly distributed) is used to do a table lookup into an
2171  * array containing unit indices.  There are 211 entries in
2172  * the array for the random_unit entry point.  The probability
2173  * of a particular unit being generated is equal to the
2174  * fraction of those 211 entries that contain that unit index.
2175  * For example, the letter `a' is unit number 1.  Since unit
2176  * index 1 appears 10 times in the array, the probability of
2177  * selecting an `a' is 10/211.
2178  *
2179  * Changes may be made to the digram table without affect to this
2180  * procedure providing the letter-to-number correspondence of
2181  * the units does not change.  Likewise, the distribution of the
2182  * 34 units may be altered (and the array size may be changed)
2183  * in this procedure without affecting the digram table or any other
2184  * programs using the Random_word subroutine.
2185  */
2186 static USHORT numbers[] =
2187 {
2188     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2189     1, 1, 1, 1, 1, 1, 1, 1,
2190     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2191     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2192     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
2193     5, 5, 5, 5, 5, 5, 5, 5,
2194     6, 6, 6, 6, 6, 6, 6, 6,
2195     7, 7, 7, 7, 7, 7,
2196     8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
2197     9, 9, 9, 9, 9, 9, 9, 9,
2198     10, 10, 10, 10, 10, 10, 10, 10,
2199     11, 11, 11, 11, 11, 11,
2200     12, 12, 12, 12, 12, 12,
2201     13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2202     14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
2203     15, 15, 15, 15, 15, 15,
2204     16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2205     17, 17, 17, 17, 17, 17, 17, 17,
2206     18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
2207     19, 19, 19, 19, 19, 19,
2208     20, 20, 20, 20, 20, 20, 20, 20,
2209     21, 21, 21, 21, 21, 21, 21, 21,
2210     22,
2211     23, 23, 23, 23, 23, 23, 23, 23,
2212     24,
2213     25,
2214     26,
2215     27,
2216     28,
2217     29, 29,
2218     30,
2219     31,
2220     32,
2221     33
2222 };
2223
2224
2225 /*
2226  * This structure has a typical English frequency of vowels.
2227  * The value of an entry is the vowel position (a=0, e=4, i=8,
2228  * o=14, u=19, y=23) in the rules array.  The number of times
2229  * the value appears is the frequency.  Thus, the letter "a"
2230  * is assumed to appear 2/12 = 1/6 of the time.  This array
2231  * may be altered if better data is obtained.  The routines that
2232  * use vowel_numbers will adjust to the size difference
2233 automatically.
2234  */
2235 static USHORT vowel_numbers[] =
2236 {
2237     0, 0, 4, 4, 4, 8, 8, 14, 14, 19, 19, 23
2238 };
2239
2240
2241 /*
2242  * Select a unit (a letter or a consonant group).  If a vowel is
2243  * expected, use the vowel_numbers array rather than looping through
2244  * the numbers array until a vowel is found.
2245  */
2246 USHORT
2247 random_unit (USHORT type)
2248 {
2249      USHORT number;
2250
2251     /* 
2252      * Sometimes, we are asked to explicitly get a vowel (i.e., if
2253      * a digram pair expects one following it).  This is a shortcut
2254      * to do that and avoid looping with rejected consonants.
2255      */
2256     if (type & VOWEL)
2257      number = vowel_numbers[get_random (0, (sizeof (vowel_numbers) / sizeof (USHORT))-1)];
2258     else
2259      /* 
2260       * Get any letter according to the English distribution.
2261       */
2262      number = numbers[get_random (0, (sizeof (numbers) / sizeof (USHORT))-1)];
2263     return (number);
2264 }
2265
2266
2267 /*
2268 ** get_random() -
2269 ** This routine should return a uniformly distributed Random number between
2270 ** minlen and maxlen inclusive.  The Electronic Code Book form of CAST is
2271 ** used to produce the Random number.  The inputs to CAST are the old pass-
2272 ** word and a pseudoRandom key generated according to the procedure out-
2273 ** lined in Appendix C of ANSI X9.17.
2274 ** INPUT:
2275 **   USHORT - minimum
2276 **   USHORT - maximum
2277 ** OUTPUT:
2278 **   USHORT - random number
2279 ** NOTES:
2280 **   none.
2281 */
2282
2283 USHORT
2284 get_random (USHORT minlen, USHORT maxlen)
2285 {
2286  USHORT ret = 0;
2287  ret = minlen + (USHORT) randint ((int) (maxlen - minlen + 1));
2288  return (ret);
2289 }