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