Home | History | Annotate | Download | only in fips181
      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
   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
   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
   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
   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
   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 *
   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
   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
   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