"Fossies" - the Fresh Open Source Software Archive

Member "apg-2.2.3/pronpass.c" (7 Aug 2003, 79621 Bytes) of package /linux/privat/old/apg-2.2.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    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 "pronpass.h"
   46 #include "randpass.h"
   47 #include "convert.h"
   48 #include "errs.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, get_random (minlen, maxlen), pass_mode);
 1297     return (pwlen);
 1298 }
 1299 
 1300 
 1301 /*
 1302  * This is the routine that returns a Random word -- as
 1303  * yet unchecked against the passwd file or the dictionary.
 1304  * It collects Random syllables until a predetermined
 1305  * word length is found.  If a retry threshold is reached,
 1306  * another word is tried.  Given that the Random number
 1307  * generator is uniformly distributed, eventually a word
 1308  * will be found if the retry limit is adequately large enough.
 1309  */
 1310 int
 1311 gen_word (char *word, char *hyphenated_word, USHORT pwlen, unsigned int pass_mode)
 1312 {
 1313     USHORT word_length;
 1314     USHORT syllable_length;
 1315     char   *new_syllable;
 1316     char   *syllable_for_hyph;
 1317     USHORT *syllable_units;
 1318     USHORT word_size;
 1319     USHORT word_place;
 1320     USHORT *word_units;
 1321     USHORT syllable_size;
 1322     UINT   tries;
 1323     int ch_flag = FALSE;
 1324     int dsd = 0;
 1325 
 1326     /*
 1327      * Keep count of retries.
 1328      */
 1329     tries = 0;
 1330 
 1331     /*
 1332      * The length of the word in characters.
 1333      */
 1334     word_length = 0;
 1335 
 1336     /*
 1337      * The length of the word in character units (each of which is one or
 1338      * two characters long.
 1339      */
 1340     word_size = 0;
 1341 
 1342     /*
 1343      * Initialize the array storing the word units.  Since we know the
 1344      * length of the word, we only need one of that length.  This method is
 1345      * preferable to a static array, since it allows us flexibility in
 1346      * choosing arbitrarily long word lengths.  Since a word can contain one
 1347      * syllable, we should make syllable_units, the array holding the
 1348      * analogous units for an individual syllable, the same length. No
 1349      * explicit rule limits the length of syllables, but digram rules and
 1350      * heuristics do so indirectly.
 1351      */
 1352     if ( (word_units     = (USHORT *) calloc (sizeof (USHORT), pwlen+1))==NULL ||
 1353          (syllable_units = (USHORT *) calloc (sizeof (USHORT), pwlen+1))==NULL ||
 1354          (new_syllable   = (char *) calloc (sizeof (USHORT), pwlen+1))  ==NULL ||
 1355      (syllable_for_hyph = (char *) calloc (sizeof(char), 20))==NULL)
 1356        return(-1);
 1357 
 1358     /*
 1359      * Find syllables until the entire word is constructed.
 1360      */
 1361     while (word_length < pwlen)
 1362     {
 1363      /*
 1364       * Get the syllable and find its length.
 1365       */
 1366      (void) gen_syllable (new_syllable, pwlen - word_length, syllable_units, &syllable_size);
 1367      syllable_length = strlen (new_syllable);
 1368      
 1369      /*
 1370       * Append the syllable units to the word units.
 1371       */
 1372      for (word_place = 0; word_place <= syllable_size; word_place++)
 1373          word_units[word_size + word_place] = syllable_units[word_place];
 1374      word_size += syllable_size + 1;
 1375 
 1376      /* 
 1377       * If the word has been improperly formed, throw out
 1378       * the syllable.  The checks performed here are those
 1379       * that must be formed on a word basis.  The other
 1380       * tests are performed entirely within the syllable.
 1381       * Otherwise, append the syllable to the word and
 1382       * append the syllable to the hyphenated version of
 1383       * the word.
 1384       */
 1385      if (improper_word (word_units, word_size) ||
 1386         ((word_length == 0) && have_initial_y (syllable_units, syllable_size)) ||
 1387         ((word_length + syllable_length == pwlen) && have_final_split (syllable_units, syllable_size)))
 1388            word_size -= syllable_size + 1;
 1389      else
 1390      {
 1391          if (word_length == 0)
 1392          {
 1393           /*
 1394           ** Modify syllable for numeric or capital symbols required
 1395           ** Should be done after word quality check. 
 1396           */
 1397       dsd = randint(2);
 1398           if ( ((pass_mode & S_NB) > 0) && (syllable_length == 1) && dsd == 0)
 1399             {
 1400              numerize(new_syllable);
 1401          ch_flag = TRUE;
 1402             }
 1403           if ( ((pass_mode & S_SS) > 0) && (syllable_length == 1) && (dsd == 1))
 1404             {
 1405           specialize(new_syllable);
 1406           ch_flag = TRUE;
 1407         }
 1408           if ( ( (pass_mode & S_CL) > 0) && (ch_flag != TRUE))
 1409              capitalize(new_syllable);
 1410           ch_flag = FALSE;
 1411           /**/
 1412           (void) strcpy (word, new_syllable);
 1413       if (syllable_length == 1)
 1414          {
 1415           symb2name(new_syllable, syllable_for_hyph);
 1416               (void) strcpy (hyphenated_word, syllable_for_hyph);
 1417          }
 1418       else
 1419          {
 1420               (void) strcpy (hyphenated_word, new_syllable);
 1421          }
 1422       (void)memset ( (void *)new_syllable, 0, (size_t)(pwlen * sizeof(USHORT)+1));
 1423       (void)memset ( (void *)syllable_for_hyph, 0, 20);
 1424          }
 1425          else
 1426          {
 1427           /*
 1428           ** Modify syllable for numeric or capital symbols required
 1429           ** Should be done after word quality check.
 1430           */
 1431       dsd = randint(2);
 1432           if ( ((pass_mode & S_NB) > 0) && (syllable_length == 1) && (dsd == 0))
 1433             {
 1434              numerize(new_syllable);
 1435          ch_flag = TRUE;
 1436             }
 1437           if ( ( (pass_mode & S_SS) > 0) && (syllable_length == 1) && (dsd == 1))
 1438             {
 1439          specialize(new_syllable);
 1440          ch_flag = TRUE;
 1441         }
 1442           if ( ( (pass_mode & S_CL) > 0) && (ch_flag != TRUE))
 1443              capitalize(new_syllable);
 1444           ch_flag = FALSE;
 1445           /**/
 1446           (void) strcat (word, new_syllable);
 1447           (void) strcat (hyphenated_word, "-");
 1448       if (syllable_length == 1)
 1449          {
 1450           symb2name(new_syllable, syllable_for_hyph);
 1451               (void) strcat (hyphenated_word, syllable_for_hyph);
 1452          }
 1453       else
 1454          {
 1455               (void) strcat (hyphenated_word, new_syllable);
 1456          }
 1457       (void)memset ( (void *)new_syllable, 0, (size_t)(pwlen * sizeof(USHORT)+1));
 1458       (void)memset ( (void *)syllable_for_hyph, 0, 20);
 1459          }
 1460          word_length += syllable_length;
 1461      }
 1462 
 1463        /* 
 1464         * Keep track of the times we have tried to get
 1465         * syllables.  If we have exceeded the threshold,
 1466         * reinitialize the pwlen and word_size variables, clear
 1467         * out the word arrays, and start from scratch.
 1468         */
 1469      tries++;
 1470      if (tries > MAX_RETRIES)
 1471      {
 1472          word_length = 0;
 1473          word_size = 0;
 1474          tries = 0;
 1475          (void) strcpy (word, "");
 1476          (void) strcpy (hyphenated_word, "");
 1477      }
 1478     }
 1479 
 1480     /* 
 1481      * The units arrays and syllable storage are internal to this
 1482      * routine.  Since the caller has no need for them, we
 1483      * release the space.
 1484      */
 1485     free ((char *) new_syllable);
 1486     free ((char *) syllable_units);
 1487     free ((char *) word_units);
 1488     free ((char *) syllable_for_hyph);
 1489 
 1490     return ((int) word_length);
 1491 }
 1492 
 1493 
 1494 
 1495 /*
 1496  * Check that the word does not contain illegal combinations
 1497  * that may span syllables.  Specifically, these are:
 1498  *   1. An illegal pair of units between syllables.
 1499  *   2. Three consecutive vowel units.
 1500  *   3. Three consecutive consonant units.
 1501  * The checks are made against units (1 or 2 letters), not against
 1502  * the individual letters, so three consecutive units can have
 1503  * the length of 6 at most.
 1504  */
 1505 boolean
 1506 improper_word (USHORT *units, USHORT word_size)
 1507 {
 1508     USHORT unit_count;
 1509     boolean failure;
 1510 
 1511     failure = FALSE;
 1512 
 1513     for (unit_count = 0; !failure && (unit_count < word_size);
 1514          unit_count++)
 1515     {
 1516      /* 
 1517       * Check for ILLEGAL_PAIR.  This should have been caught
 1518       * for units within a syllable, but in some cases it
 1519       * would have gone unnoticed for units between syllables
 1520       * (e.g., when saved_unit's in gen_syllable() were not
 1521       * used).
 1522       */
 1523      if ((unit_count != 0) &&
 1524           (digram[units[unit_count - 1]][units[unit_count]] &
 1525               ILLEGAL_PAIR))
 1526          failure = TRUE;
 1527 
 1528      /* 
 1529       * Check for consecutive vowels or consonants.  Because
 1530       * the initial y of a syllable is treated as a consonant
 1531       * rather than as a vowel, we exclude y from the first
 1532       * vowel in the vowel test.  The only problem comes when
 1533       * y ends a syllable and two other vowels start the next,
 1534       * like fly-oint.  Since such words are still
 1535       * pronounceable, we accept this.
 1536       */
 1537      if (!failure && (unit_count >= 2))
 1538      {
 1539          /*
 1540           * Vowel check.
 1541           */
 1542          if ((((rules[units[unit_count - 2]].flags & VOWEL) &&
 1543                    !(rules[units[unit_count - 2]].flags &
 1544                     ALTERNATE_VOWEL)) &&
 1545                (rules[units[unit_count - 1]].flags & VOWEL) &&
 1546                (rules[units[unit_count]].flags & VOWEL)) ||
 1547          /*
 1548           * Consonant check.
 1549           */
 1550               (!(rules[units[unit_count - 2]].flags & VOWEL) &&
 1551                !(rules[units[unit_count - 1]].flags & VOWEL) &&
 1552                !(rules[units[unit_count]].flags & VOWEL)))
 1553           failure = TRUE;
 1554      }
 1555     }
 1556 
 1557     return (failure);
 1558 }
 1559 
 1560 
 1561 /*
 1562  * Treating y as a vowel is sometimes a problem.  Some words
 1563  * get formed that look irregular.  One special group is when
 1564  * y starts a word and is the only vowel in the first syllable.
 1565  * The word ycl is one example.  We discard words like these.
 1566  */
 1567 boolean
 1568 have_initial_y (USHORT *units, USHORT unit_size)
 1569 {
 1570     USHORT unit_count;
 1571     USHORT vowel_count;
 1572     USHORT normal_vowel_count;
 1573 
 1574     vowel_count = 0;
 1575     normal_vowel_count = 0;
 1576 
 1577     for (unit_count = 0; unit_count <= unit_size; unit_count++)
 1578      /*
 1579       * Count vowels.
 1580       */
 1581      if (rules[units[unit_count]].flags & VOWEL)
 1582      {
 1583          vowel_count++;
 1584 
 1585          /*
 1586           * Count the vowels that are not: 1. y, 2. at the start of
 1587           * the word.
 1588           */
 1589          if (!(rules[units[unit_count]].flags & ALTERNATE_VOWEL) ||
 1590               (unit_count != 0))
 1591           normal_vowel_count++;
 1592      }
 1593 
 1594     return ((vowel_count <= 1) && (normal_vowel_count == 0));
 1595 }
 1596 
 1597 
 1598 /*
 1599  * Besides the problem with the letter y, there is one with
 1600  * a silent e at the end of words, like face or nice.  We
 1601  * allow this silent e, but we do not allow it as the only
 1602  * vowel at the end of the word or syllables like ble will
 1603  * be generated.
 1604  */
 1605 boolean
 1606 have_final_split (USHORT *units, USHORT unit_size)
 1607 {
 1608     USHORT unit_count;
 1609     USHORT vowel_count;
 1610 
 1611     vowel_count = 0;
 1612 
 1613     /*
 1614      *    Count all the vowels in the word.
 1615      */
 1616     for (unit_count = 0; unit_count <= unit_size; unit_count++)
 1617      if (rules[units[unit_count]].flags & VOWEL)
 1618          vowel_count++;
 1619 
 1620     /*
 1621      * Return TRUE iff the only vowel was e, found at the end if the
 1622      * word.
 1623      */
 1624     return ((vowel_count == 1) &&
 1625          (rules[units[unit_size]].flags & NO_FINAL_SPLIT));
 1626 }
 1627 
 1628 
 1629 /*
 1630  * Generate next unit to password, making sure that it follows
 1631  * these rules:
 1632  *   1. Each syllable must contain exactly 1 or 2 consecutive
 1633  *      vowels, where y is considered a vowel.
 1634  *   2. Syllable end is determined as follows:
 1635  *        a. Vowel is generated and previous unit is a
 1636  *           consonant and syllable already has a vowel.  In
 1637  *           this case, new syllable is started and already
 1638  *           contains a vowel.
 1639  *        b. A pair determined to be a "break" pair is encountered.
 1640  *           In this case new syllable is started with second unit
 1641  *           of this pair.
 1642  *        c. End of password is encountered.
 1643  *        d. "begin" pair is encountered legally.  New syllable is
 1644  *           started with this pair.
 1645  *        e. "end" pair is legally encountered.  New syllable has
 1646  *           nothing yet.
 1647  *   3. Try generating another unit if:
 1648  *        a. third consecutive vowel and not y.
 1649  *        b. "break" pair generated but no vowel yet in current
 1650  *           or previous 2 units are "not_end".
 1651  *        c. "begin" pair generated but no vowel in syllable
 1652  *           preceding begin pair, or both previous 2 pairs are
 1653  *          designated "not_end".
 1654  *        d. "end" pair generated but no vowel in current syllable
 1655  *           or in "end" pair.
 1656  *        e. "not_begin" pair generated but new syllable must
 1657  *           begin (because previous syllable ended as defined in
 1658  *           2 above).
 1659  *        f. vowel is generated and 2a is satisfied, but no syllable
 1660  *           break is possible in previous 3 pairs.
 1661  *        g. Second and third units of syllable must begin, and
 1662  *           first unit is "alternate_vowel".
 1663  */
 1664 char *
 1665 gen_syllable (char *syllable, USHORT pwlen, USHORT *units_in_syllable,
 1666               USHORT *syllable_length)
 1667 {
 1668     USHORT  unit = 0;
 1669     SHORT   current_unit = 0;
 1670     USHORT  vowel_count = 0;
 1671     boolean rule_broken;
 1672     boolean want_vowel;
 1673     boolean want_another_unit;
 1674     UINT    tries = 0;
 1675     USHORT  last_unit = 0;
 1676     SHORT   length_left = 0;
 1677     USHORT  hold_saved_unit = 0;
 1678     static  USHORT saved_unit;
 1679     static  USHORT saved_pair[2];
 1680 
 1681     /*
 1682      * This is needed if the saved_unit is tries and the syllable then
 1683      * discarded because of the retry limit. Since the saved_unit is OK and
 1684      * fits in nicely with the preceding syllable, we will always use it.
 1685      */
 1686     hold_saved_unit = saved_unit;
 1687 
 1688     /*
 1689      * Loop until valid syllable is found.
 1690      */
 1691     do
 1692     {
 1693      /* 
 1694       * Try for a new syllable.  Initialize all pertinent
 1695       * syllable variables.
 1696       */
 1697      tries = 0;
 1698      saved_unit = hold_saved_unit;
 1699      (void) strcpy (syllable, "");
 1700      vowel_count = 0;
 1701      current_unit = 0;
 1702      length_left = (short int) pwlen;
 1703      want_another_unit = TRUE;
 1704 
 1705      /*
 1706       * This loop finds all the units for the syllable.
 1707       */
 1708      do
 1709      {
 1710          want_vowel = FALSE;
 1711 
 1712          /*
 1713           * This loop continues until a valid unit is found for the
 1714           * current position within the syllable.
 1715           */
 1716          do
 1717          {
 1718           /* 
 1719            * If there are saved_unit's from the previous
 1720            * syllable, use them up first.
 1721            */
 1722           if (saved_unit != 0)
 1723           {
 1724               /* 
 1725                * If there were two saved units, the first is
 1726                * guaranteed (by checks performed in the previous
 1727                * syllable) to be valid.  We ignore the checks
 1728                * and place it in this syllable manually.
 1729                */
 1730               if (saved_unit == 2)
 1731               {
 1732                units_in_syllable[0] = saved_pair[1];
 1733                if (rules[saved_pair[1]].flags & VOWEL)
 1734                    vowel_count++;
 1735                current_unit++;
 1736                (void) strcpy (syllable, rules[saved_pair[1]].unit_code);
 1737                length_left -= strlen (syllable);
 1738               }
 1739 
 1740               /* 
 1741                * The unit becomes the last unit checked in the
 1742                * previous syllable.
 1743                */
 1744               unit = saved_pair[0];
 1745 
 1746               /*
 1747                * The saved units have been used.  Do not try to
 1748                * reuse them in this syllable (unless this particular
 1749                * syllable is rejected at which point we start to rebuild
 1750                * it with these same saved units.
 1751                */
 1752               saved_unit = 0;
 1753           }
 1754           else
 1755               /* 
 1756                * If we don't have to scoff the saved units,
 1757                * we generate a Random one.  If we know it has
 1758                * to be a vowel, we get one rather than looping
 1759                * through until one shows up.
 1760                */
 1761               if (want_vowel)
 1762                unit = random_unit (VOWEL);
 1763               else
 1764                unit = random_unit (NO_SPECIAL_RULE);
 1765           length_left -= (short int) strlen (rules[unit].unit_code);
 1766 
 1767           /*
 1768            * Prevent having a word longer than expected.
 1769            */
 1770           if (length_left < 0)
 1771               rule_broken = TRUE;
 1772           else
 1773               rule_broken = FALSE;
 1774 
 1775           /*
 1776            * First unit of syllable.  This is special because the
 1777            * digram tests require 2 units and we don't have that yet.
 1778            * Nevertheless, we can perform some checks.
 1779            */
 1780           if (current_unit == 0)
 1781           {
 1782               /* 
 1783                * If the shouldn't begin a syllable, don't
 1784                * use it.
 1785                */
 1786               if (rules[unit].flags & NOT_BEGIN_SYLLABLE)
 1787                rule_broken = TRUE;
 1788               else
 1789                /* 
 1790                 * If this is the last unit of a word,
 1791                 * we have a one unit syllable.  Since each
 1792                 * syllable must have a vowel, we make sure
 1793                 * the unit is a vowel.  Otherwise, we
 1794                 * discard it.
 1795                 */
 1796                if (length_left == 0)
 1797               {
 1798                    if (rules[unit].flags & VOWEL)
 1799                     want_another_unit = FALSE;
 1800                    else
 1801                     rule_broken = TRUE;
 1802           }
 1803           }
 1804           else
 1805           {
 1806               /* 
 1807                * There are some digram tests that are
 1808                * universally true.  We test them out.
 1809                */
 1810 
 1811               /*
 1812                * Reject ILLEGAL_PAIRS of units.
 1813                */
 1814               if ((ALLOWED (ILLEGAL_PAIR)) ||
 1815 
 1816               /*
 1817                * Reject units that will be split between syllables
 1818                * when the syllable has no vowels in it.
 1819                */
 1820                    (ALLOWED (BREAK) && (vowel_count == 0)) ||
 1821 
 1822               /*
 1823                * Reject a unit that will end a syllable when no
 1824                * previous unit was a vowel and neither is this one.
 1825                */
 1826                    (ALLOWED (END) && (vowel_count == 0) &&
 1827                     !(rules[unit].flags & VOWEL)))
 1828                rule_broken = TRUE;
 1829 
 1830               if (current_unit == 1)
 1831               {
 1832                /*
 1833                 * Reject the unit if we are at te starting digram of
 1834                 * a syllable and it does not fit.
 1835                 */
 1836                if (ALLOWED (NOT_BEGIN))
 1837                    rule_broken = TRUE;
 1838               }
 1839               else
 1840               {
 1841                /* 
 1842                 * We are not at the start of a syllable.
 1843                 * Save the previous unit for later tests.
 1844                 */
 1845                last_unit = units_in_syllable[current_unit - 1];
 1846 
 1847                /*
 1848                 * Do not allow syllables where the first letter is y
 1849                 * and the next pair can begin a syllable.  This may
 1850                 * lead to splits where y is left alone in a syllable.
 1851                 * Also, the combination does not sound to good even
 1852                 * if not split.
 1853                 */
 1854                if (((current_unit == 2) &&
 1855                         (ALLOWED (BEGIN)) &&
 1856                         (rules[units_in_syllable[0]].flags &
 1857                          ALTERNATE_VOWEL)) ||
 1858 
 1859                     /*
 1860                      * If this is the last unit of a word, we should
 1861                      * reject any digram that cannot end a syllable.
 1862                      */
 1863                     (ALLOWED (NOT_END) &&
 1864                         (length_left == 0)) ||
 1865 
 1866                     /*
 1867                      * Reject the unit if the digram it forms wants
 1868                      * to break the syllable, but the resulting
 1869                      * digram that would end the syllable is not
 1870                      * allowed to end a syllable.
 1871                      */
 1872                     (ALLOWED (BREAK) &&
 1873                         (digram[units_in_syllable
 1874                              [current_unit - 2]]
 1875                          [last_unit] &
 1876                          NOT_END)) ||
 1877 
 1878                     /*
 1879                      * Reject the unit if the digram it forms
 1880                      * expects a vowel preceding it and there is
 1881                      * none.
 1882                      */
 1883                     (ALLOWED (PREFIX) &&
 1884                         !(rules[units_in_syllable
 1885                              [current_unit - 2]].flags &
 1886                          VOWEL)))
 1887                    rule_broken = TRUE;
 1888 
 1889                /*
 1890                 * The following checks occur when the current unit
 1891                 * is a vowel and we are not looking at a word ending
 1892                 * with an e.
 1893                 */
 1894                if (!rule_broken &&
 1895                     (rules[unit].flags & VOWEL) &&
 1896                     ((length_left > 0) ||
 1897                         !(rules[last_unit].flags &
 1898                          NO_FINAL_SPLIT)))
 1899                   {
 1900                    /*
 1901                     * Don't allow 3 consecutive vowels in a
 1902                     * syllable.  Although some words formed like this
 1903                     * are OK, like beau, most are not.
 1904                     */
 1905                    if ((vowel_count > 1) &&
 1906                         (rules[last_unit].flags & VOWEL))
 1907                     rule_broken = TRUE;
 1908                    else
 1909                     /*
 1910                      * Check for the case of
 1911                      * vowels-consonants-vowel, which is only
 1912                      * legal if the last vowel is an e and we are
 1913                      * the end of the word (wich is not
 1914                      * happening here due to a previous check.
 1915                      */
 1916                     if ((vowel_count != 0) &&
 1917                          !(rules[last_unit].flags & VOWEL))
 1918                     {
 1919                         /*
 1920                          * Try to save the vowel for the next
 1921                          * syllable, but if the syllable left here
 1922                          * is not proper (i.e., the resulting last
 1923                          * digram cannot legally end it), just
 1924                          * discard it and try for another.   
 1925                          */
 1926                         if (digram[units_in_syllable
 1927                               [current_unit - 2]]
 1928                              [last_unit] &
 1929                              NOT_END)
 1930                          rule_broken = TRUE;
 1931                         else
 1932                         {
 1933                          saved_unit = 1;
 1934                          saved_pair[0] = unit;
 1935                          want_another_unit = FALSE;
 1936                         }
 1937                     }
 1938           }
 1939               }
 1940 
 1941               /*
 1942                * The unit picked and the digram formed are legal.
 1943                * We now determine if we can end the syllable.  It may,
 1944                * in some cases, mean the last unit(s) may be deferred to
 1945                * the next syllable.  We also check here to see if the
 1946                * digram formed expects a vowel to follow.
 1947                */
 1948               if (!rule_broken && want_another_unit)
 1949               {
 1950                /*
 1951                 * This word ends in a silent e.
 1952                 */
 1953 /******/        if (((vowel_count != 0) &&
 1954                      (rules[unit].flags & NO_FINAL_SPLIT) &&
 1955                      (length_left == 0) &&
 1956                     !(rules[last_unit].flags & VOWEL)) ||
 1957 
 1958                     /*
 1959                      * This syllable ends either because the digram
 1960                      * is an END pair or we would otherwise exceed
 1961                      * the length of the word.
 1962                      */
 1963                     (ALLOWED (END) || (length_left == 0)))
 1964            {
 1965                    want_another_unit = FALSE;
 1966            }
 1967            else
 1968                    /*
 1969                     * Since we have a vowel in the syllable
 1970                     * already, if the digram calls for the end of the
 1971                     * syllable, we can legally split it off. We also
 1972                     * make sure that we are not at the end of the
 1973                     * dangerous because that syllable may not have
 1974                     * vowels, or it may not be a legal syllable end,
 1975                     * and the retrying mechanism will loop infinitely
 1976                     * with the same digram.
 1977                     */
 1978                    if ((vowel_count != 0) && (length_left > 0))
 1979                    {
 1980                     /*
 1981                      * If we must begin a syllable, we do so if
 1982                      * the only vowel in THIS syllable is not part
 1983                      * of the digram we are pushing to the next
 1984                      * syllable.
 1985                      */
 1986                     if (ALLOWED (BEGIN) &&
 1987                          (current_unit > 1) &&
 1988                          !((vowel_count == 1) &&
 1989                          (rules[last_unit].flags & VOWEL)))
 1990                     {
 1991                         saved_unit = 2;
 1992                         saved_pair[0] = unit;
 1993                         saved_pair[1] = last_unit;
 1994                         want_another_unit = FALSE;
 1995                     }
 1996                     else
 1997                         if (ALLOWED (BREAK))
 1998                         {
 1999                          saved_unit = 1;
 2000                          saved_pair[0] = unit;
 2001                          want_another_unit = FALSE;
 2002                         }
 2003                    }
 2004                    else
 2005                     if (ALLOWED (SUFFIX))
 2006              {
 2007                         want_vowel = TRUE;
 2008              }
 2009               }
 2010           }
 2011 /********/
 2012           tries++;
 2013 
 2014           /*
 2015            * If this unit was illegal, redetermine the amount of
 2016            * letters left to go in the word.
 2017            */
 2018           if (rule_broken)
 2019               length_left += (short int) strlen (rules[unit].unit_code);
 2020          }
 2021          while (rule_broken && (tries <= MAX_RETRIES));
 2022 
 2023          /*
 2024           * The unit fit OK.
 2025           */
 2026          if (tries <= MAX_RETRIES)
 2027          {
 2028           /* 
 2029            * If the unit were a vowel, count it in.
 2030            * However, if the unit were a y and appear
 2031            * at the start of the syllable, treat it
 2032            * like a constant (so that words like year can
 2033            * appear and not conflict with the 3 consecutive
 2034            * vowel rule.
 2035            */
 2036           if ((rules[unit].flags & VOWEL) &&
 2037                ((current_unit > 0) ||
 2038                    !(rules[unit].flags & ALTERNATE_VOWEL)))
 2039               vowel_count++;
 2040 
 2041           /* 
 2042            * If a unit or units were to be saved, we must
 2043            * adjust the syllable formed.  Otherwise, we
 2044            * append the current unit to the syllable.
 2045            */
 2046           switch (saved_unit)
 2047           {
 2048               case 0: 
 2049                units_in_syllable[current_unit] = unit;
 2050                (void) strcat (syllable, rules[unit].unit_code);
 2051                break;
 2052               case 1: 
 2053                current_unit--;
 2054                break;
 2055               case 2: 
 2056                (void) strcpy (&syllable[strlen (syllable) -
 2057                         strlen (rules[last_unit].unit_code)],"");
 2058                length_left += (short int) strlen (rules[last_unit].unit_code);
 2059                current_unit -= 2;
 2060                break;
 2061           }
 2062          }
 2063          else
 2064          /*
 2065           * Whoops!  Too many tries.  We set rule_broken so we can
 2066           * loop in the outer loop and try another syllable.
 2067           */
 2068           rule_broken = TRUE;
 2069 
 2070          /*
 2071           * ...and the syllable length grows.
 2072           */
 2073          *syllable_length = current_unit;
 2074 
 2075          current_unit++;
 2076      }
 2077      while ((tries <= MAX_RETRIES) && want_another_unit);
 2078     }
 2079     while (rule_broken ||
 2080            illegal_placement (units_in_syllable, *syllable_length));
 2081 
 2082     return (syllable);
 2083 }
 2084 
 2085 
 2086 /*
 2087  * This routine goes through an individual syllable and checks
 2088  * for illegal combinations of letters that go beyond looking
 2089  * at digrams.  We look at things like 3 consecutive vowels or
 2090  * consonants, or syllables with consonants between vowels (unless
 2091  * one of them is the final silent e).
 2092  */
 2093 boolean
 2094 illegal_placement (USHORT *units, USHORT pwlen)
 2095 {
 2096     USHORT vowel_count;
 2097     USHORT unit_count;
 2098     boolean failure;
 2099 
 2100     vowel_count = 0;
 2101     failure = FALSE;
 2102 
 2103     for (unit_count = 0; !failure && (unit_count <= pwlen);
 2104          unit_count++)
 2105     {
 2106      if (unit_count >= 1)
 2107      {
 2108          /* 
 2109           * Don't allow vowels to be split with consonants in
 2110           * a single syllable.  If we find such a combination
 2111           * (except for the silent e) we have to discard the
 2112           * syllable).
 2113           */
 2114          if ((!(rules[units[unit_count - 1]].flags & VOWEL) &&
 2115                (rules[units[unit_count]].flags & VOWEL) &&
 2116                !((rules[units[unit_count]].flags & NO_FINAL_SPLIT) &&
 2117                    (unit_count == pwlen)) && (vowel_count != 0)) ||
 2118          /*
 2119           * Perform these checks when we have at least 3 units.
 2120           */
 2121               ((unit_count >= 2) &&
 2122 
 2123                   /*
 2124                    * Disallow 3 consecutive consonants.
 2125                    */
 2126                ((!(rules[units[unit_count - 2]].flags & VOWEL) &&
 2127                     !(rules[units[unit_count - 1]].flags &
 2128                         VOWEL) &&
 2129                     !(rules[units[unit_count]].flags &
 2130                         VOWEL)) ||
 2131 
 2132                    /*
 2133                     * Disallow 3 consecutive vowels, where the first is
 2134                     * not a y.
 2135                     */
 2136                    (((rules[units[unit_count - 2]].flags &
 2137                          VOWEL) &&
 2138                         !((rules[units[0]].flags &
 2139                              ALTERNATE_VOWEL) &&
 2140                          (unit_count == 2))) &&
 2141                     (rules[units[unit_count - 1]].flags &
 2142                         VOWEL) &&
 2143                     (rules[units[unit_count]].flags &
 2144                         VOWEL)))))
 2145           failure = TRUE;
 2146      }
 2147 
 2148      /* 
 2149       * Count the vowels in the syllable.  As mentioned somewhere
 2150       * above, exclude the initial y of a syllable.  Instead,
 2151       * treat it as a consonant.
 2152       */
 2153      if ((rules[units[unit_count]].flags & VOWEL) &&
 2154           !((rules[units[0]].flags & ALTERNATE_VOWEL) &&
 2155               (unit_count == 0) && (pwlen != 0)))
 2156          vowel_count++;
 2157     }
 2158 
 2159     return (failure);
 2160 }
 2161 
 2162 
 2163 
 2164 /*
 2165  * This is the standard Random unit generating routine for
 2166  * gen_syllable().  It does not reference the digrams, but
 2167  * assumes that it contains 34 units in a particular order.
 2168  * This routine attempts to return unit indexes with a distribution
 2169  * approaching that of the distribution of the 34 units in
 2170  * English.  In order to do this, a Random number (supposedly
 2171  * uniformly distributed) is used to do a table lookup into an
 2172  * array containing unit indices.  There are 211 entries in
 2173  * the array for the random_unit entry point.  The probability
 2174  * of a particular unit being generated is equal to the
 2175  * fraction of those 211 entries that contain that unit index.
 2176  * For example, the letter `a' is unit number 1.  Since unit
 2177  * index 1 appears 10 times in the array, the probability of
 2178  * selecting an `a' is 10/211.
 2179  *
 2180  * Changes may be made to the digram table without affect to this
 2181  * procedure providing the letter-to-number correspondence of
 2182  * the units does not change.  Likewise, the distribution of the
 2183  * 34 units may be altered (and the array size may be changed)
 2184  * in this procedure without affecting the digram table or any other
 2185  * programs using the Random_word subroutine.
 2186  */
 2187 static USHORT numbers[] =
 2188 {
 2189     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 2190     1, 1, 1, 1, 1, 1, 1, 1,
 2191     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
 2192     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 2193     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
 2194     5, 5, 5, 5, 5, 5, 5, 5,
 2195     6, 6, 6, 6, 6, 6, 6, 6,
 2196     7, 7, 7, 7, 7, 7,
 2197     8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
 2198     9, 9, 9, 9, 9, 9, 9, 9,
 2199     10, 10, 10, 10, 10, 10, 10, 10,
 2200     11, 11, 11, 11, 11, 11,
 2201     12, 12, 12, 12, 12, 12,
 2202     13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
 2203     14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
 2204     15, 15, 15, 15, 15, 15,
 2205     16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
 2206     17, 17, 17, 17, 17, 17, 17, 17,
 2207     18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
 2208     19, 19, 19, 19, 19, 19,
 2209     20, 20, 20, 20, 20, 20, 20, 20,
 2210     21, 21, 21, 21, 21, 21, 21, 21,
 2211     22,
 2212     23, 23, 23, 23, 23, 23, 23, 23,
 2213     24,
 2214     25,
 2215     26,
 2216     27,
 2217     28,
 2218     29, 29,
 2219     30,
 2220     31,
 2221     32,
 2222     33
 2223 };
 2224 
 2225 
 2226 /*
 2227  * This structure has a typical English frequency of vowels.
 2228  * The value of an entry is the vowel position (a=0, e=4, i=8,
 2229  * o=14, u=19, y=23) in the rules array.  The number of times
 2230  * the value appears is the frequency.  Thus, the letter "a"
 2231  * is assumed to appear 2/12 = 1/6 of the time.  This array
 2232  * may be altered if better data is obtained.  The routines that
 2233  * use vowel_numbers will adjust to the size difference
 2234 automatically.
 2235  */
 2236 static USHORT vowel_numbers[] =
 2237 {
 2238     0, 0, 4, 4, 4, 8, 8, 14, 14, 19, 19, 23
 2239 };
 2240 
 2241 
 2242 /*
 2243  * Select a unit (a letter or a consonant group).  If a vowel is
 2244  * expected, use the vowel_numbers array rather than looping through
 2245  * the numbers array until a vowel is found.
 2246  */
 2247 USHORT
 2248 random_unit (USHORT type)
 2249 {
 2250      USHORT number;
 2251 
 2252     /* 
 2253      * Sometimes, we are asked to explicitly get a vowel (i.e., if
 2254      * a digram pair expects one following it).  This is a shortcut
 2255      * to do that and avoid looping with rejected consonants.
 2256      */
 2257     if (type & VOWEL)
 2258      number = vowel_numbers[get_random (0, (sizeof (vowel_numbers) / sizeof (USHORT))-1)];
 2259     else
 2260      /* 
 2261       * Get any letter according to the English distribution.
 2262       */
 2263      number = numbers[get_random (0, (sizeof (numbers) / sizeof (USHORT))-1)];
 2264     return (number);
 2265 }
 2266 
 2267 
 2268 /*
 2269 ** get_random() -
 2270 ** This routine should return a uniformly distributed Random number between
 2271 ** minlen and maxlen inclusive.  The Electronic Code Book form of CAST is
 2272 ** used to produce the Random number.  The inputs to CAST are the old pass-
 2273 ** word and a pseudoRandom key generated according to the procedure out-
 2274 ** lined in Appendix C of ANSI X9.17.
 2275 ** INPUT:
 2276 **   USHORT - minimum
 2277 **   USHORT - maximum
 2278 ** OUTPUT:
 2279 **   USHORT - random number
 2280 ** NOTES:
 2281 **   none.
 2282 */
 2283 
 2284 USHORT
 2285 get_random (USHORT minlen, USHORT maxlen)
 2286 {
 2287  USHORT ret = 0;
 2288  ret = minlen + (USHORT) randint ((int) (maxlen - minlen + 1));
 2289  return (ret);
 2290 }