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