/* @(#)97	 1.1  src/examples/pwdstren/gen.c, examples.src, os2dce21.dss, 960602a.1  1/31/96	16:09:47					     */
/*
 *   COMPONENT_NAME: security.src
 *
 *   FUNCTIONS: ALLOWED
 *		answer
 *		generate_pwd
 *		get_random
 *		get_syllable
 *		get_word
 *		have_final_split
 *		have_initial_y
 *		illegal_placement
 *		improper_word
 *		randint
 *		random_unit
 *		randomchars
 *		randomletters
 *		randomword
 *		set_seed
 *
 *   ORIGINS: 72
 *
 *   OBJECT CODE ONLY SOURCE MATERIALS
 */
/*
 * @OSF_COPYRIGHT@
 * COPYRIGHT NOTICE
 * Copyright (c) 1990, 1991, 1992, 1993, 1994 Open Software Foundation, Inc.
 * ALL RIGHTS RESERVED (DCE).  See the file named COPYRIGHT.DCE for
 * the full copyright text.
 */
/*
 * HISTORY
 * $Log: gen.c,v $
 * Revision 1.1.2.2  1994/08/10  19:22:01  annie
 *	expand copyright with OSF copyright text
 *	[1994/08/10  17:16:18  annie]
 *
 * Revision 1.1.2.1  1994/07/15  15:00:49  mdf
 *	Hewlett Packard Security Code Drop
 *	[1994/07/14  17:18:25  mdf]
 *
 *	/main/ODESSA_2/1  1994/06/15  17:48 UTC  mullan_s
 *	Merge -from mullan_el_bl19 -to ODESSA_2
 *
 *	/main/mullan_el_bl19/5	1994/06/10  17:54 UTC  mullan_s
 *	Use sec_key_mgmt_gen_rand_key for generating random keys.
 *
 *	/main/mullan_el_bl19/4	1994/05/31  16:59 UTC  mullan_s
 *	Add registry password policy checking.
 *
 *	/main/mullan_el_bl19/3	1994/05/19  17:02 UTC  mullan_s
 *	Clean up, remove command line args.
 *
 *	/main/mullan_el_bl19/2	1994/05/13  20:40 UTC  mullan_s
 *	Cleanup and convert to library calls.
 *
 *	/main/mullan_el_bl19/1	1994/05/13  18:27 UTC  mullan_s
 *	Password generation routines. This is (almost) the original NIST version.
 *	DES was replaced by rand() routines.
 *
 * $EndLog$
 */
/*
 * Copyright (c) Hewlett-Packard Company 1994
 * Unpublished work. All Rights Reserved.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#ifdef IBMOS2  /* CMVC 10856 */
#ifdef OS2_EXAMPLE
#include <dce/utc.h>
#else
#include <sys/time.h>
#endif
#endif /* IBMOS2 */

#include <dce/keymgmt.h>
#include <dce/rgynbase.h>
#include <dce/rpc.h>

#include <gen.h>

#define RAN_DEBUG
#define B1

#define TRUE		      1
#define FALSE		      0

#define RULE_SIZE	      (sizeof(rules)/sizeof(struct unit))
#define ALLOWED(flag)  (digram[units_in_syllable[current_unit - 1]][unit] & (flag))

#define MAX_UNACCEPTABLE      20
#define MAX_RETRIES	      (4 * (int) pwlen + RULE_SIZE)

#define NOT_BEGIN_SYLLABLE    010
#define NO_FINAL_SPLIT	      04
#define VOWEL		      02
#define ALTERNATE_VOWEL       01
#define NO_SPECIAL_RULE       0

#define BEGIN		      0200
#define NOT_BEGIN	      0100
#define BREAK		      040
#define PREFIX		      020
#define ILLEGAL_PAIR	      010
#define SUFFIX		      04
#define END		      02
#define NOT_END 	      01
#define ANY_COMBINATION       0

typedef int   boolean;

/* initial seed for random number generator */
long	seed = 0L;

static int get_word(char *, char *, unsigned int);
static boolean have_initial_y(register unsigned int *,
    register unsigned int);
static boolean illegal_placement(register unsigned int *,
    register unsigned int);
static boolean improper_word(register unsigned int *,
    register unsigned int);
static boolean have_final_split(register unsigned int *,
    register unsigned int);
static char   *get_syllable(char *, register unsigned int,
    register unsigned int *, register unsigned int *);
static unsigned int random_unit(register unsigned int);
static unsigned int randint(int);
static unsigned int get_random(register unsigned int,
    register unsigned int);
static void set_seed(long);
static int randomchars(register char *, register unsigned int,
    register unsigned int, register boolean, long);
static int randomletters(register char	*, register unsigned int,
    register unsigned int, register boolean, long);
static int randomword(register char *, register char  *,
    register unsigned int, register unsigned int,
    register boolean, long);
static int answer(unsigned char *, int);

struct unit
{
    char    unit_code[5];
    unsigned int  flags;
};

static struct unit  rules[] =
{
    {"a", VOWEL},
    {"b", NO_SPECIAL_RULE},
    {"c", NO_SPECIAL_RULE},
    {"d", NO_SPECIAL_RULE},
    {"e", NO_FINAL_SPLIT | VOWEL},
    {"f", NO_SPECIAL_RULE},
    {"g", NO_SPECIAL_RULE},
    {"h", NO_SPECIAL_RULE},
    {"i", VOWEL},
    {"j", NO_SPECIAL_RULE},
    {"k", NO_SPECIAL_RULE},
    {"l", NO_SPECIAL_RULE},
    {"m", NO_SPECIAL_RULE},
    {"n", NO_SPECIAL_RULE},
    {"o", VOWEL},
    {"p", NO_SPECIAL_RULE},
    {"r", NO_SPECIAL_RULE},
    {"s", NO_SPECIAL_RULE},
    {"t", NO_SPECIAL_RULE},
    {"u", VOWEL},
    {"v", NO_SPECIAL_RULE},
    {"w", NO_SPECIAL_RULE},
    {"x", NOT_BEGIN_SYLLABLE},
    {"y", ALTERNATE_VOWEL | VOWEL},
    {"z", NO_SPECIAL_RULE},
    {"ch", NO_SPECIAL_RULE},
    {"gh", NO_SPECIAL_RULE},
    {"ph", NO_SPECIAL_RULE},
    {"rh", NO_SPECIAL_RULE},
    {"sh", NO_SPECIAL_RULE},
    {"th", NO_SPECIAL_RULE},
    {"wh", NO_SPECIAL_RULE},
    {"qu", NO_SPECIAL_RULE},
    {"ck", NOT_BEGIN_SYLLABLE}
};

static int  digram[][RULE_SIZE] =
{
     /* aa */ {ILLEGAL_PAIR,
     /* ab */ ANY_COMBINATION,
     /* ac */ ANY_COMBINATION,
     /* ad */ ANY_COMBINATION,
     /* ae */ ILLEGAL_PAIR,
     /* af */ ANY_COMBINATION,
     /* ag */ ANY_COMBINATION,
     /* ah */ NOT_BEGIN | BREAK | NOT_END,
     /* ai */ ANY_COMBINATION,
     /* aj */ ANY_COMBINATION,
     /* ak */ ANY_COMBINATION,
     /* al */ ANY_COMBINATION,
     /* am */ ANY_COMBINATION,
     /* an */ ANY_COMBINATION,
     /* ao */ ILLEGAL_PAIR,
     /* ap */ ANY_COMBINATION,
     /* ar */ ANY_COMBINATION,
     /* as */ ANY_COMBINATION,
     /* at */ ANY_COMBINATION,
     /* au */ ANY_COMBINATION,
     /* av */ ANY_COMBINATION,
     /* aw */ ANY_COMBINATION,
     /* ax */ ANY_COMBINATION,
     /* ay */ ANY_COMBINATION,
     /* az */ ANY_COMBINATION,
     /* ach */ ANY_COMBINATION,
     /* agh */ ILLEGAL_PAIR,
     /* aph */ ANY_COMBINATION,
     /* arh */ ILLEGAL_PAIR,
     /* ash */ ANY_COMBINATION,
     /* ath */ ANY_COMBINATION,
     /* awh */ ILLEGAL_PAIR,
     /* aqu */ BREAK | NOT_END,
     /* ack */ ANY_COMBINATION},
     /* ba */ {ANY_COMBINATION,
     /* bb */ NOT_BEGIN | BREAK | NOT_END,
     /* bc */ NOT_BEGIN | BREAK | NOT_END,
     /* bd */ NOT_BEGIN | BREAK | NOT_END,
     /* be */ ANY_COMBINATION,
     /* bf */ NOT_BEGIN | BREAK | NOT_END,
     /* bg */ NOT_BEGIN | BREAK | NOT_END,
     /* bh */ NOT_BEGIN | BREAK | NOT_END,
     /* bi */ ANY_COMBINATION,
     /* bj */ NOT_BEGIN | BREAK | NOT_END,
     /* bk */ NOT_BEGIN | BREAK | NOT_END,
     /* bl */ BEGIN | SUFFIX | NOT_END,
     /* bm */ NOT_BEGIN | BREAK | NOT_END,
     /* bn */ NOT_BEGIN | BREAK | NOT_END,
     /* bo */ ANY_COMBINATION,
     /* bp */ NOT_BEGIN | BREAK | NOT_END,
     /* br */ BEGIN | END,
     /* bs */ NOT_BEGIN,
     /* bt */ NOT_BEGIN | BREAK | NOT_END,
     /* bu */ ANY_COMBINATION,
     /* bv */ NOT_BEGIN | BREAK | NOT_END,
     /* bw */ NOT_BEGIN | BREAK | NOT_END,
     /* bx */ ILLEGAL_PAIR,
     /* by */ ANY_COMBINATION,
     /* bz */ NOT_BEGIN | BREAK | NOT_END,
     /* bch */ NOT_BEGIN | BREAK | NOT_END,
     /* bgh */ ILLEGAL_PAIR,
     /* bph */ NOT_BEGIN | BREAK | NOT_END,
     /* brh */ ILLEGAL_PAIR,
     /* bsh */ NOT_BEGIN | BREAK | NOT_END,
     /* bth */ NOT_BEGIN | BREAK | NOT_END,
     /* bwh */ ILLEGAL_PAIR,
     /* bqu */ NOT_BEGIN | BREAK | NOT_END,
     /* bck */ ILLEGAL_PAIR},
     /* ca */ {ANY_COMBINATION,
     /* cb */ NOT_BEGIN | BREAK | NOT_END,
     /* cc */ NOT_BEGIN | BREAK | NOT_END,
     /* cd */ NOT_BEGIN | BREAK | NOT_END,
     /* ce */ ANY_COMBINATION,
     /* cf */ NOT_BEGIN | BREAK | NOT_END,
     /* cg */ NOT_BEGIN | BREAK | NOT_END,
     /* ch */ NOT_BEGIN | BREAK | NOT_END,
     /* ci */ ANY_COMBINATION,
     /* cj */ NOT_BEGIN | BREAK | NOT_END,
     /* ck */ NOT_BEGIN | BREAK | NOT_END,
     /* cl */ SUFFIX | NOT_END,
     /* cm */ NOT_BEGIN | BREAK | NOT_END,
     /* cn */ NOT_BEGIN | BREAK | NOT_END,
     /* co */ ANY_COMBINATION,
     /* cp */ NOT_BEGIN | BREAK | NOT_END,
     /* cr */ NOT_END,
     /* cs */ NOT_BEGIN | END,
     /* ct */ NOT_BEGIN | PREFIX,
     /* cu */ ANY_COMBINATION,
     /* cv */ NOT_BEGIN | BREAK | NOT_END,
     /* cw */ NOT_BEGIN | BREAK | NOT_END,
     /* cx */ ILLEGAL_PAIR,
     /* cy */ ANY_COMBINATION,
     /* cz */ NOT_BEGIN | BREAK | NOT_END,
     /* cch */ ILLEGAL_PAIR,
     /* cgh */ ILLEGAL_PAIR,
     /* cph */ NOT_BEGIN | BREAK | NOT_END,
     /* crh */ ILLEGAL_PAIR,
     /* csh */ NOT_BEGIN | BREAK | NOT_END,
     /* cth */ NOT_BEGIN | BREAK | NOT_END,
     /* cwh */ ILLEGAL_PAIR,
     /* cqu */ NOT_BEGIN | SUFFIX | NOT_END,
     /* cck */ ILLEGAL_PAIR},
     /* da */ {ANY_COMBINATION,
     /* db */ NOT_BEGIN | BREAK | NOT_END,
     /* dc */ NOT_BEGIN | BREAK | NOT_END,
     /* dd */ NOT_BEGIN,
     /* de */ ANY_COMBINATION,
     /* df */ NOT_BEGIN | BREAK | NOT_END,
     /* dg */ NOT_BEGIN | BREAK | NOT_END,
     /* dh */ NOT_BEGIN | BREAK | NOT_END,
     /* di */ ANY_COMBINATION,
     /* dj */ NOT_BEGIN | BREAK | NOT_END,
     /* dk */ NOT_BEGIN | BREAK | NOT_END,
     /* dl */ NOT_BEGIN | BREAK | NOT_END,
     /* dm */ NOT_BEGIN | BREAK | NOT_END,
     /* dn */ NOT_BEGIN | BREAK | NOT_END,
     /* do */ ANY_COMBINATION,
     /* dp */ NOT_BEGIN | BREAK | NOT_END,
     /* dr */ BEGIN | NOT_END,
     /* ds */ NOT_BEGIN | END,
     /* dt */ NOT_BEGIN | BREAK | NOT_END,
     /* du */ ANY_COMBINATION,
     /* dv */ NOT_BEGIN | BREAK | NOT_END,
     /* dw */ NOT_BEGIN | BREAK | NOT_END,
     /* dx */ ILLEGAL_PAIR,
     /* dy */ ANY_COMBINATION,
     /* dz */ NOT_BEGIN | BREAK | NOT_END,
     /* dch */ NOT_BEGIN | BREAK | NOT_END,
     /* dgh */ NOT_BEGIN | BREAK | NOT_END,
     /* dph */ NOT_BEGIN | BREAK | NOT_END,
     /* drh */ ILLEGAL_PAIR,
     /* dsh */ NOT_BEGIN | NOT_END,
     /* dth */ NOT_BEGIN | PREFIX,
     /* dwh */ ILLEGAL_PAIR,
     /* dqu */ NOT_BEGIN | BREAK | NOT_END,
     /* dck */ ILLEGAL_PAIR},
     /* ea */ {ANY_COMBINATION,
     /* eb */ ANY_COMBINATION,
     /* ec */ ANY_COMBINATION,
     /* ed */ ANY_COMBINATION,
     /* ee */ ANY_COMBINATION,
     /* ef */ ANY_COMBINATION,
     /* eg */ ANY_COMBINATION,
     /* eh */ NOT_BEGIN | BREAK | NOT_END,
     /* ei */ NOT_END,
     /* ej */ ANY_COMBINATION,
     /* ek */ ANY_COMBINATION,
     /* el */ ANY_COMBINATION,
     /* em */ ANY_COMBINATION,
     /* en */ ANY_COMBINATION,
     /* eo */ BREAK,
     /* ep */ ANY_COMBINATION,
     /* er */ ANY_COMBINATION,
     /* es */ ANY_COMBINATION,
     /* et */ ANY_COMBINATION,
     /* eu */ ANY_COMBINATION,
     /* ev */ ANY_COMBINATION,
     /* ew */ ANY_COMBINATION,
     /* ex */ ANY_COMBINATION,
     /* ey */ ANY_COMBINATION,
     /* ez */ ANY_COMBINATION,
     /* ech */ ANY_COMBINATION,
     /* egh */ NOT_BEGIN | BREAK | NOT_END,
     /* eph */ ANY_COMBINATION,
     /* erh */ ILLEGAL_PAIR,
     /* esh */ ANY_COMBINATION,
     /* eth */ ANY_COMBINATION,
     /* ewh */ ILLEGAL_PAIR,
     /* equ */ BREAK | NOT_END,
     /* eck */ ANY_COMBINATION},
     /* fa */ {ANY_COMBINATION,
     /* fb */ NOT_BEGIN | BREAK | NOT_END,
     /* fc */ NOT_BEGIN | BREAK | NOT_END,
     /* fd */ NOT_BEGIN | BREAK | NOT_END,
     /* fe */ ANY_COMBINATION,
     /* ff */ NOT_BEGIN,
     /* fg */ NOT_BEGIN | BREAK | NOT_END,
     /* fh */ NOT_BEGIN | BREAK | NOT_END,
     /* fi */ ANY_COMBINATION,
     /* fj */ NOT_BEGIN | BREAK | NOT_END,
     /* fk */ NOT_BEGIN | BREAK | NOT_END,
     /* fl */ BEGIN | SUFFIX | NOT_END,
     /* fm */ NOT_BEGIN | BREAK | NOT_END,
     /* fn */ NOT_BEGIN | BREAK | NOT_END,
     /* fo */ ANY_COMBINATION,
     /* fp */ NOT_BEGIN | BREAK | NOT_END,
     /* fr */ BEGIN | NOT_END,
     /* fs */ NOT_BEGIN,
     /* ft */ NOT_BEGIN,
     /* fu */ ANY_COMBINATION,
     /* fv */ NOT_BEGIN | BREAK | NOT_END,
     /* fw */ NOT_BEGIN | BREAK | NOT_END,
     /* fx */ ILLEGAL_PAIR,
     /* fy */ NOT_BEGIN,
     /* fz */ NOT_BEGIN | BREAK | NOT_END,
     /* fch */ NOT_BEGIN | BREAK | NOT_END,
     /* fgh */ NOT_BEGIN | BREAK | NOT_END,
     /* fph */ NOT_BEGIN | BREAK | NOT_END,
     /* frh */ ILLEGAL_PAIR,
     /* fsh */ NOT_BEGIN | BREAK | NOT_END,
     /* fth */ NOT_BEGIN | BREAK | NOT_END,
     /* fwh */ ILLEGAL_PAIR,
     /* fqu */ NOT_BEGIN | BREAK | NOT_END,
     /* fck */ ILLEGAL_PAIR},
     /* ga */ {ANY_COMBINATION,
     /* gb */ NOT_BEGIN | BREAK | NOT_END,
     /* gc */ NOT_BEGIN | BREAK | NOT_END,
     /* gd */ NOT_BEGIN | BREAK | NOT_END,
     /* ge */ ANY_COMBINATION,
     /* gf */ NOT_BEGIN | BREAK | NOT_END,
     /* gg */ NOT_BEGIN,
     /* gh */ NOT_BEGIN | BREAK | NOT_END,
     /* gi */ ANY_COMBINATION,
     /* gj */ NOT_BEGIN | BREAK | NOT_END,
     /* gk */ ILLEGAL_PAIR,
     /* gl */ BEGIN | SUFFIX | NOT_END,
     /* gm */ NOT_BEGIN | BREAK | NOT_END,
     /* gn */ NOT_BEGIN | BREAK | NOT_END,
     /* go */ ANY_COMBINATION,
     /* gp */ NOT_BEGIN | BREAK | NOT_END,
     /* gr */ BEGIN | NOT_END,
     /* gs */ NOT_BEGIN | END,
     /* gt */ NOT_BEGIN | BREAK | NOT_END,
     /* gu */ ANY_COMBINATION,
     /* gv */ NOT_BEGIN | BREAK | NOT_END,
     /* gw */ NOT_BEGIN | BREAK | NOT_END,
     /* gx */ ILLEGAL_PAIR,
     /* gy */ NOT_BEGIN,
     /* gz */ NOT_BEGIN | BREAK | NOT_END,
     /* gch */ NOT_BEGIN | BREAK | NOT_END,
     /* ggh */ ILLEGAL_PAIR,
     /* gph */ NOT_BEGIN | BREAK | NOT_END,
     /* grh */ ILLEGAL_PAIR,
     /* gsh */ NOT_BEGIN,
     /* gth */ NOT_BEGIN,
     /* gwh */ ILLEGAL_PAIR,
     /* gqu */ NOT_BEGIN | BREAK | NOT_END,
     /* gck */ ILLEGAL_PAIR},
     /* ha */ {ANY_COMBINATION,
     /* hb */ NOT_BEGIN | BREAK | NOT_END,
     /* hc */ NOT_BEGIN | BREAK | NOT_END,
     /* hd */ NOT_BEGIN | BREAK | NOT_END,
     /* he */ ANY_COMBINATION,
     /* hf */ NOT_BEGIN | BREAK | NOT_END,
     /* hg */ NOT_BEGIN | BREAK | NOT_END,
     /* hh */ ILLEGAL_PAIR,
     /* hi */ ANY_COMBINATION,
     /* hj */ NOT_BEGIN | BREAK | NOT_END,
     /* hk */ NOT_BEGIN | BREAK | NOT_END,
     /* hl */ NOT_BEGIN | BREAK | NOT_END,
     /* hm */ NOT_BEGIN | BREAK | NOT_END,
     /* hn */ NOT_BEGIN | BREAK | NOT_END,
     /* ho */ ANY_COMBINATION,
     /* hp */ NOT_BEGIN | BREAK | NOT_END,
     /* hr */ NOT_BEGIN | BREAK | NOT_END,
     /* hs */ NOT_BEGIN | BREAK | NOT_END,
     /* ht */ NOT_BEGIN | BREAK | NOT_END,
     /* hu */ ANY_COMBINATION,
     /* hv */ NOT_BEGIN | BREAK | NOT_END,
     /* hw */ NOT_BEGIN | BREAK | NOT_END,
     /* hx */ ILLEGAL_PAIR,
     /* hy */ ANY_COMBINATION,
     /* hz */ NOT_BEGIN | BREAK | NOT_END,
     /* hch */ NOT_BEGIN | BREAK | NOT_END,
     /* hgh */ NOT_BEGIN | BREAK | NOT_END,
     /* hph */ NOT_BEGIN | BREAK | NOT_END,
     /* hrh */ ILLEGAL_PAIR,
     /* hsh */ NOT_BEGIN | BREAK | NOT_END,
     /* hth */ NOT_BEGIN | BREAK | NOT_END,
     /* hwh */ ILLEGAL_PAIR,
     /* hqu */ NOT_BEGIN | BREAK | NOT_END,
     /* hck */ ILLEGAL_PAIR},
     /* ia */ {ANY_COMBINATION,
     /* ib */ ANY_COMBINATION,
     /* ic */ ANY_COMBINATION,
     /* id */ ANY_COMBINATION,
     /* ie */ NOT_BEGIN,
     /* if */ ANY_COMBINATION,
     /* ig */ ANY_COMBINATION,
     /* ih */ NOT_BEGIN | BREAK | NOT_END,
     /* ii */ ILLEGAL_PAIR,
     /* ij */ ANY_COMBINATION,
     /* ik */ ANY_COMBINATION,
     /* il */ ANY_COMBINATION,
     /* im */ ANY_COMBINATION,
     /* in */ ANY_COMBINATION,
     /* io */ BREAK,
     /* ip */ ANY_COMBINATION,
     /* ir */ ANY_COMBINATION,
     /* is */ ANY_COMBINATION,
     /* it */ ANY_COMBINATION,
     /* iu */ NOT_BEGIN | BREAK | NOT_END,
     /* iv */ ANY_COMBINATION,
     /* iw */ NOT_BEGIN | BREAK | NOT_END,
     /* ix */ ANY_COMBINATION,
     /* iy */ NOT_BEGIN | BREAK | NOT_END,
     /* iz */ ANY_COMBINATION,
     /* ich */ ANY_COMBINATION,
     /* igh */ NOT_BEGIN,
     /* iph */ ANY_COMBINATION,
     /* irh */ ILLEGAL_PAIR,
     /* ish */ ANY_COMBINATION,
     /* ith */ ANY_COMBINATION,
     /* iwh */ ILLEGAL_PAIR,
     /* iqu */ BREAK | NOT_END,
     /* ick */ ANY_COMBINATION},
     /* ja */ {ANY_COMBINATION,
     /* jb */ NOT_BEGIN | BREAK | NOT_END,
     /* jc */ NOT_BEGIN | BREAK | NOT_END,
     /* jd */ NOT_BEGIN | BREAK | NOT_END,
     /* je */ ANY_COMBINATION,
     /* jf */ NOT_BEGIN | BREAK | NOT_END,
     /* jg */ ILLEGAL_PAIR,
     /* jh */ NOT_BEGIN | BREAK | NOT_END,
     /* ji */ ANY_COMBINATION,
     /* jj */ ILLEGAL_PAIR,
     /* jk */ NOT_BEGIN | BREAK | NOT_END,
     /* jl */ NOT_BEGIN | BREAK | NOT_END,
     /* jm */ NOT_BEGIN | BREAK | NOT_END,
     /* jn */ NOT_BEGIN | BREAK | NOT_END,
     /* jo */ ANY_COMBINATION,
     /* jp */ NOT_BEGIN | BREAK | NOT_END,
     /* jr */ NOT_BEGIN | BREAK | NOT_END,
     /* js */ NOT_BEGIN | BREAK | NOT_END,
     /* jt */ NOT_BEGIN | BREAK | NOT_END,
     /* ju */ ANY_COMBINATION,
     /* jv */ NOT_BEGIN | BREAK | NOT_END,
     /* jw */ NOT_BEGIN | BREAK | NOT_END,
     /* jx */ ILLEGAL_PAIR,
     /* jy */ NOT_BEGIN,
     /* jz */ NOT_BEGIN | BREAK | NOT_END,
     /* jch */ NOT_BEGIN | BREAK | NOT_END,
     /* jgh */ NOT_BEGIN | BREAK | NOT_END,
     /* jph */ NOT_BEGIN | BREAK | NOT_END,
     /* jrh */ ILLEGAL_PAIR,
     /* jsh */ NOT_BEGIN | BREAK | NOT_END,
     /* jth */ NOT_BEGIN | BREAK | NOT_END,
     /* jwh */ ILLEGAL_PAIR,
     /* jqu */ NOT_BEGIN | BREAK | NOT_END,
     /* jck */ ILLEGAL_PAIR},
     /* ka */ {ANY_COMBINATION,
     /* kb */ NOT_BEGIN | BREAK | NOT_END,
     /* kc */ NOT_BEGIN | BREAK | NOT_END,
     /* kd */ NOT_BEGIN | BREAK | NOT_END,
     /* ke */ ANY_COMBINATION,
     /* kf */ NOT_BEGIN | BREAK | NOT_END,
     /* kg */ NOT_BEGIN | BREAK | NOT_END,
     /* kh */ NOT_BEGIN | BREAK | NOT_END,
     /* ki */ ANY_COMBINATION,
     /* kj */ NOT_BEGIN | BREAK | NOT_END,
     /* kk */ NOT_BEGIN | BREAK | NOT_END,
     /* kl */ SUFFIX | NOT_END,
     /* km */ NOT_BEGIN | BREAK | NOT_END,
     /* kn */ BEGIN | SUFFIX | NOT_END,
     /* ko */ ANY_COMBINATION,
     /* kp */ NOT_BEGIN | BREAK | NOT_END,
     /* kr */ SUFFIX | NOT_END,
     /* ks */ NOT_BEGIN | END,
     /* kt */ NOT_BEGIN | BREAK | NOT_END,
     /* ku */ ANY_COMBINATION,
     /* kv */ NOT_BEGIN | BREAK | NOT_END,
     /* kw */ NOT_BEGIN | BREAK | NOT_END,
     /* kx */ ILLEGAL_PAIR,
     /* ky */ NOT_BEGIN,
     /* kz */ NOT_BEGIN | BREAK | NOT_END,
     /* kch */ NOT_BEGIN | BREAK | NOT_END,
     /* kgh */ NOT_BEGIN | BREAK | NOT_END,
     /* kph */ NOT_BEGIN | PREFIX,
     /* krh */ ILLEGAL_PAIR,
     /* ksh */ NOT_BEGIN,
     /* kth */ NOT_BEGIN | BREAK | NOT_END,
     /* kwh */ ILLEGAL_PAIR,
     /* kqu */ NOT_BEGIN | BREAK | NOT_END,
     /* kck */ ILLEGAL_PAIR},
     /* la */ {ANY_COMBINATION,
     /* lb */ NOT_BEGIN | PREFIX,
     /* lc */ NOT_BEGIN | BREAK | NOT_END,
     /* ld */ NOT_BEGIN | PREFIX,
     /* le */ ANY_COMBINATION,
     /* lf */ NOT_BEGIN | PREFIX,
     /* lg */ NOT_BEGIN | PREFIX,
     /* lh */ NOT_BEGIN | BREAK | NOT_END,
     /* li */ ANY_COMBINATION,
     /* lj */ NOT_BEGIN | PREFIX,
     /* lk */ NOT_BEGIN | PREFIX,
     /* ll */ NOT_BEGIN | PREFIX,
     /* lm */ NOT_BEGIN | PREFIX,
     /* ln */ NOT_BEGIN | BREAK | NOT_END,
     /* lo */ ANY_COMBINATION,
     /* lp */ NOT_BEGIN | PREFIX,
     /* lr */ NOT_BEGIN | BREAK | NOT_END,
     /* ls */ NOT_BEGIN,
     /* lt */ NOT_BEGIN | PREFIX,
     /* lu */ ANY_COMBINATION,
     /* lv */ NOT_BEGIN | PREFIX,
     /* lw */ NOT_BEGIN | BREAK | NOT_END,
     /* lx */ ILLEGAL_PAIR,
     /* ly */ ANY_COMBINATION,
     /* lz */ NOT_BEGIN | BREAK | NOT_END,
     /* lch */ NOT_BEGIN | PREFIX,
     /* lgh */ NOT_BEGIN | BREAK | NOT_END,
     /* lph */ NOT_BEGIN | PREFIX,
     /* lrh */ ILLEGAL_PAIR,
     /* lsh */ NOT_BEGIN | PREFIX,
     /* lth */ NOT_BEGIN | PREFIX,
     /* lwh */ ILLEGAL_PAIR,
     /* lqu */ NOT_BEGIN | BREAK | NOT_END,
     /* lck */ ILLEGAL_PAIR},
     /* ma */ {ANY_COMBINATION,
     /* mb */ NOT_BEGIN | BREAK | NOT_END,
     /* mc */ NOT_BEGIN | BREAK | NOT_END,
     /* md */ NOT_BEGIN | BREAK | NOT_END,
     /* me */ ANY_COMBINATION,
     /* mf */ NOT_BEGIN | BREAK | NOT_END,
     /* mg */ NOT_BEGIN | BREAK | NOT_END,
     /* mh */ NOT_BEGIN | BREAK | NOT_END,
     /* mi */ ANY_COMBINATION,
     /* mj */ NOT_BEGIN | BREAK | NOT_END,
     /* mk */ NOT_BEGIN | BREAK | NOT_END,
     /* ml */ NOT_BEGIN | BREAK | NOT_END,
     /* mm */ NOT_BEGIN,
     /* mn */ NOT_BEGIN | BREAK | NOT_END,
     /* mo */ ANY_COMBINATION,
     /* mp */ NOT_BEGIN,
     /* mr */ NOT_BEGIN | BREAK | NOT_END,
     /* ms */ NOT_BEGIN,
     /* mt */ NOT_BEGIN,
     /* mu */ ANY_COMBINATION,
     /* mv */ NOT_BEGIN | BREAK | NOT_END,
     /* mw */ NOT_BEGIN | BREAK | NOT_END,
     /* mx */ ILLEGAL_PAIR,
     /* my */ ANY_COMBINATION,
     /* mz */ NOT_BEGIN | BREAK | NOT_END,
     /* mch */ NOT_BEGIN | PREFIX,
     /* mgh */ NOT_BEGIN | BREAK | NOT_END,
     /* mph */ NOT_BEGIN,
     /* mrh */ ILLEGAL_PAIR,
     /* msh */ NOT_BEGIN,
     /* mth */ NOT_BEGIN,
     /* mwh */ ILLEGAL_PAIR,
     /* mqu */ NOT_BEGIN | BREAK | NOT_END,
     /* mck */ ILLEGAL_PAIR},
     /* na */ {ANY_COMBINATION,
     /* nb */ NOT_BEGIN | BREAK | NOT_END,
     /* nc */ NOT_BEGIN | BREAK | NOT_END,
     /* nd */ NOT_BEGIN,
     /* ne */ ANY_COMBINATION,
     /* nf */ NOT_BEGIN | BREAK | NOT_END,
     /* ng */ NOT_BEGIN | PREFIX,
     /* nh */ NOT_BEGIN | BREAK | NOT_END,
     /* ni */ ANY_COMBINATION,
     /* nj */ NOT_BEGIN | BREAK | NOT_END,
     /* nk */ NOT_BEGIN | PREFIX,
     /* nl */ NOT_BEGIN | BREAK | NOT_END,
     /* nm */ NOT_BEGIN | BREAK | NOT_END,
     /* nn */ NOT_BEGIN,
     /* no */ ANY_COMBINATION,
     /* np */ NOT_BEGIN | BREAK | NOT_END,
     /* nr */ NOT_BEGIN | BREAK | NOT_END,
     /* ns */ NOT_BEGIN,
     /* nt */ NOT_BEGIN,
     /* nu */ ANY_COMBINATION,
     /* nv */ NOT_BEGIN | BREAK | NOT_END,
     /* nw */ NOT_BEGIN | BREAK | NOT_END,
     /* nx */ ILLEGAL_PAIR,
     /* ny */ NOT_BEGIN,
     /* nz */ NOT_BEGIN | BREAK | NOT_END,
     /* nch */ NOT_BEGIN | PREFIX,
     /* ngh */ NOT_BEGIN | BREAK | NOT_END,
     /* nph */ NOT_BEGIN | PREFIX,
     /* nrh */ ILLEGAL_PAIR,
     /* nsh */ NOT_BEGIN,
     /* nth */ NOT_BEGIN,
     /* nwh */ ILLEGAL_PAIR,
     /* nqu */ NOT_BEGIN | BREAK | NOT_END,
     /* nck */ NOT_BEGIN | PREFIX},
     /* oa */ {ANY_COMBINATION,
     /* ob */ ANY_COMBINATION,
     /* oc */ ANY_COMBINATION,
     /* od */ ANY_COMBINATION,
     /* oe */ ILLEGAL_PAIR,
     /* of */ ANY_COMBINATION,
     /* og */ ANY_COMBINATION,
     /* oh */ NOT_BEGIN | BREAK | NOT_END,
     /* oi */ ANY_COMBINATION,
     /* oj */ ANY_COMBINATION,
     /* ok */ ANY_COMBINATION,
     /* ol */ ANY_COMBINATION,
     /* om */ ANY_COMBINATION,
     /* on */ ANY_COMBINATION,
     /* oo */ ANY_COMBINATION,
     /* op */ ANY_COMBINATION,
     /* or */ ANY_COMBINATION,
     /* os */ ANY_COMBINATION,
     /* ot */ ANY_COMBINATION,
     /* ou */ ANY_COMBINATION,
     /* ov */ ANY_COMBINATION,
     /* ow */ ANY_COMBINATION,
     /* ox */ ANY_COMBINATION,
     /* oy */ ANY_COMBINATION,
     /* oz */ ANY_COMBINATION,
     /* och */ ANY_COMBINATION,
     /* ogh */ NOT_BEGIN,
     /* oph */ ANY_COMBINATION,
     /* orh */ ILLEGAL_PAIR,
     /* osh */ ANY_COMBINATION,
     /* oth */ ANY_COMBINATION,
     /* owh */ ILLEGAL_PAIR,
     /* oqu */ BREAK | NOT_END,
     /* ock */ ANY_COMBINATION},
     /* pa */ {ANY_COMBINATION,
     /* pb */ NOT_BEGIN | BREAK | NOT_END,
     /* pc */ NOT_BEGIN | BREAK | NOT_END,
     /* pd */ NOT_BEGIN | BREAK | NOT_END,
     /* pe */ ANY_COMBINATION,
     /* pf */ NOT_BEGIN | BREAK | NOT_END,
     /* pg */ NOT_BEGIN | BREAK | NOT_END,
     /* ph */ NOT_BEGIN | BREAK | NOT_END,
     /* pi */ ANY_COMBINATION,
     /* pj */ NOT_BEGIN | BREAK | NOT_END,
     /* pk */ NOT_BEGIN | BREAK | NOT_END,
     /* pl */ SUFFIX | NOT_END,
     /* pm */ NOT_BEGIN | BREAK | NOT_END,
     /* pn */ NOT_BEGIN | BREAK | NOT_END,
     /* po */ ANY_COMBINATION,
     /* pp */ NOT_BEGIN | PREFIX,
     /* pr */ NOT_END,
     /* ps */ NOT_BEGIN | END,
     /* pt */ NOT_BEGIN | END,
     /* pu */ NOT_BEGIN | END,
     /* pv */ NOT_BEGIN | BREAK | NOT_END,
     /* pw */ NOT_BEGIN | BREAK | NOT_END,
     /* px */ ILLEGAL_PAIR,
     /* py */ ANY_COMBINATION,
     /* pz */ NOT_BEGIN | BREAK | NOT_END,
     /* pch */ NOT_BEGIN | BREAK | NOT_END,
     /* pgh */ NOT_BEGIN | BREAK | NOT_END,
     /* pph */ NOT_BEGIN | BREAK | NOT_END,
     /* prh */ ILLEGAL_PAIR,
     /* psh */ NOT_BEGIN | BREAK | NOT_END,
     /* pth */ NOT_BEGIN | BREAK | NOT_END,
     /* pwh */ ILLEGAL_PAIR,
     /* pqu */ NOT_BEGIN | BREAK | NOT_END,
     /* pck */ ILLEGAL_PAIR},
     /* ra */ {ANY_COMBINATION,
     /* rb */ NOT_BEGIN | PREFIX,
     /* rc */ NOT_BEGIN | PREFIX,
     /* rd */ NOT_BEGIN | PREFIX,
     /* re */ ANY_COMBINATION,
     /* rf */ NOT_BEGIN | PREFIX,
     /* rg */ NOT_BEGIN | PREFIX,
     /* rh */ NOT_BEGIN | BREAK | NOT_END,
     /* ri */ ANY_COMBINATION,
     /* rj */ NOT_BEGIN | PREFIX,
     /* rk */ NOT_BEGIN | PREFIX,
     /* rl */ NOT_BEGIN | PREFIX,
     /* rm */ NOT_BEGIN | PREFIX,
     /* rn */ NOT_BEGIN | PREFIX,
     /* ro */ ANY_COMBINATION,
     /* rp */ NOT_BEGIN | PREFIX,
     /* rr */ NOT_BEGIN | PREFIX,
     /* rs */ NOT_BEGIN | PREFIX,
     /* rt */ NOT_BEGIN | PREFIX,
     /* ru */ ANY_COMBINATION,
     /* rv */ NOT_BEGIN | PREFIX,
     /* rw */ NOT_BEGIN | BREAK | NOT_END,
     /* rx */ ILLEGAL_PAIR,
     /* ry */ ANY_COMBINATION,
     /* rz */ NOT_BEGIN | PREFIX,
     /* rch */ NOT_BEGIN | PREFIX,
     /* rgh */ NOT_BEGIN | BREAK | NOT_END,
     /* rph */ NOT_BEGIN | PREFIX,
     /* rrh */ ILLEGAL_PAIR,
     /* rsh */ NOT_BEGIN | PREFIX,
     /* rth */ NOT_BEGIN | PREFIX,
     /* rwh */ ILLEGAL_PAIR,
     /* rqu */ NOT_BEGIN | PREFIX | NOT_END,
     /* rck */ NOT_BEGIN | PREFIX},
     /* sa */ {ANY_COMBINATION,
     /* sb */ NOT_BEGIN | BREAK | NOT_END,
     /* sc */ NOT_END,
     /* sd */ NOT_BEGIN | BREAK | NOT_END,
     /* se */ ANY_COMBINATION,
     /* sf */ NOT_BEGIN | BREAK | NOT_END,
     /* sg */ NOT_BEGIN | BREAK | NOT_END,
     /* sh */ NOT_BEGIN | BREAK | NOT_END,
     /* si */ ANY_COMBINATION,
     /* sj */ NOT_BEGIN | BREAK | NOT_END,
     /* sk */ ANY_COMBINATION,
     /* sl */ BEGIN | SUFFIX | NOT_END,
     /* sm */ SUFFIX | NOT_END,
     /* sn */ PREFIX | SUFFIX | NOT_END,
     /* so */ ANY_COMBINATION,
     /* sp */ ANY_COMBINATION,
     /* sr */ NOT_BEGIN | NOT_END,
     /* ss */ NOT_BEGIN | PREFIX,
     /* st */ ANY_COMBINATION,
     /* su */ ANY_COMBINATION,
     /* sv */ NOT_BEGIN | BREAK | NOT_END,
     /* sw */ BEGIN | SUFFIX | NOT_END,
     /* sx */ ILLEGAL_PAIR,
     /* sy */ ANY_COMBINATION,
     /* sz */ NOT_BEGIN | BREAK | NOT_END,
     /* sch */ BEGIN | SUFFIX | NOT_END,
     /* sgh */ NOT_BEGIN | BREAK | NOT_END,
     /* sph */ NOT_BEGIN | BREAK | NOT_END,
     /* srh */ ILLEGAL_PAIR,
     /* ssh */ NOT_BEGIN | BREAK | NOT_END,
     /* sth */ NOT_BEGIN | BREAK | NOT_END,
     /* swh */ ILLEGAL_PAIR,
     /* squ */ SUFFIX | NOT_END,
     /* sck */ NOT_BEGIN},
     /* ta */ {ANY_COMBINATION,
     /* tb */ NOT_BEGIN | BREAK | NOT_END,
     /* tc */ NOT_BEGIN | BREAK | NOT_END,
     /* td */ NOT_BEGIN | BREAK | NOT_END,
     /* te */ ANY_COMBINATION,
     /* tf */ NOT_BEGIN | BREAK | NOT_END,
     /* tg */ NOT_BEGIN | BREAK | NOT_END,
     /* th */ NOT_BEGIN | BREAK | NOT_END,
     /* ti */ ANY_COMBINATION,
     /* tj */ NOT_BEGIN | BREAK | NOT_END,
     /* tk */ NOT_BEGIN | BREAK | NOT_END,
     /* tl */ NOT_BEGIN | BREAK | NOT_END,
     /* tm */ NOT_BEGIN | BREAK | NOT_END,
     /* tn */ NOT_BEGIN | BREAK | NOT_END,
     /* to */ ANY_COMBINATION,
     /* tp */ NOT_BEGIN | BREAK | NOT_END,
     /* tr */ NOT_END,
     /* ts */ NOT_BEGIN | END,
     /* tt */ NOT_BEGIN | PREFIX,
     /* tu */ ANY_COMBINATION,
     /* tv */ NOT_BEGIN | BREAK | NOT_END,
     /* tw */ BEGIN | SUFFIX | NOT_END,
     /* tx */ ILLEGAL_PAIR,
     /* ty */ ANY_COMBINATION,
     /* tz */ NOT_BEGIN | BREAK | NOT_END,
     /* tch */ NOT_BEGIN,
     /* tgh */ NOT_BEGIN | BREAK | NOT_END,
     /* tph */ NOT_BEGIN | END,
     /* trh */ ILLEGAL_PAIR,
     /* tsh */ NOT_BEGIN | END,
     /* tth */ NOT_BEGIN | BREAK | NOT_END,
     /* twh */ ILLEGAL_PAIR,
     /* tqu */ NOT_BEGIN | BREAK | NOT_END,
     /* tck */ ILLEGAL_PAIR},
     /* ua */ {NOT_BEGIN | BREAK | NOT_END,
     /* ub */ ANY_COMBINATION,
     /* uc */ ANY_COMBINATION,
     /* ud */ ANY_COMBINATION,
     /* ue */ NOT_BEGIN,
     /* uf */ ANY_COMBINATION,
     /* ug */ ANY_COMBINATION,
     /* uh */ NOT_BEGIN | BREAK | NOT_END,
     /* ui */ NOT_BEGIN | BREAK | NOT_END,
     /* uj */ ANY_COMBINATION,
     /* uk */ ANY_COMBINATION,
     /* ul */ ANY_COMBINATION,
     /* um */ ANY_COMBINATION,
     /* un */ ANY_COMBINATION,
     /* uo */ NOT_BEGIN | BREAK,
     /* up */ ANY_COMBINATION,
     /* ur */ ANY_COMBINATION,
     /* us */ ANY_COMBINATION,
     /* ut */ ANY_COMBINATION,
     /* uu */ ILLEGAL_PAIR,
     /* uv */ ANY_COMBINATION,
     /* uw */ NOT_BEGIN | BREAK | NOT_END,
     /* ux */ ANY_COMBINATION,
     /* uy */ NOT_BEGIN | BREAK | NOT_END,
     /* uz */ ANY_COMBINATION,
     /* uch */ ANY_COMBINATION,
     /* ugh */ NOT_BEGIN | PREFIX,
     /* uph */ ANY_COMBINATION,
     /* urh */ ILLEGAL_PAIR,
     /* ush */ ANY_COMBINATION,
     /* uth */ ANY_COMBINATION,
     /* uwh */ ILLEGAL_PAIR,
     /* uqu */ BREAK | NOT_END,
     /* uck */ ANY_COMBINATION},
     /* va */ {ANY_COMBINATION,
     /* vb */ NOT_BEGIN | BREAK | NOT_END,
     /* vc */ NOT_BEGIN | BREAK | NOT_END,
     /* vd */ NOT_BEGIN | BREAK | NOT_END,
     /* ve */ ANY_COMBINATION,
     /* vf */ NOT_BEGIN | BREAK | NOT_END,
     /* vg */ NOT_BEGIN | BREAK | NOT_END,
     /* vh */ NOT_BEGIN | BREAK | NOT_END,
     /* vi */ ANY_COMBINATION,
     /* vj */ NOT_BEGIN | BREAK | NOT_END,
     /* vk */ NOT_BEGIN | BREAK | NOT_END,
     /* vl */ NOT_BEGIN | BREAK | NOT_END,
     /* vm */ NOT_BEGIN | BREAK | NOT_END,
     /* vn */ NOT_BEGIN | BREAK | NOT_END,
     /* vo */ ANY_COMBINATION,
     /* vp */ NOT_BEGIN | BREAK | NOT_END,
     /* vr */ NOT_BEGIN | BREAK | NOT_END,
     /* vs */ NOT_BEGIN | BREAK | NOT_END,
     /* vt */ NOT_BEGIN | BREAK | NOT_END,
     /* vu */ ANY_COMBINATION,
     /* vv */ NOT_BEGIN | BREAK | NOT_END,
     /* vw */ NOT_BEGIN | BREAK | NOT_END,
     /* vx */ ILLEGAL_PAIR,
     /* vy */ NOT_BEGIN,
     /* vz */ NOT_BEGIN | BREAK | NOT_END,
     /* vch */ NOT_BEGIN | BREAK | NOT_END,
     /* vgh */ NOT_BEGIN | BREAK | NOT_END,
     /* vph */ NOT_BEGIN | BREAK | NOT_END,
     /* vrh */ ILLEGAL_PAIR,
     /* vsh */ NOT_BEGIN | BREAK | NOT_END,
     /* vth */ NOT_BEGIN | BREAK | NOT_END,
     /* vwh */ ILLEGAL_PAIR,
     /* vqu */ NOT_BEGIN | BREAK | NOT_END,
     /* vck */ ILLEGAL_PAIR},
     /* wa */ {ANY_COMBINATION,
     /* wb */ NOT_BEGIN | PREFIX,
     /* wc */ NOT_BEGIN | BREAK | NOT_END,
     /* wd */ NOT_BEGIN | PREFIX | END,
     /* we */ ANY_COMBINATION,
     /* wf */ NOT_BEGIN | PREFIX,
     /* wg */ NOT_BEGIN | PREFIX | END,
     /* wh */ NOT_BEGIN | BREAK | NOT_END,
     /* wi */ ANY_COMBINATION,
     /* wj */ NOT_BEGIN | BREAK | NOT_END,
     /* wk */ NOT_BEGIN | PREFIX,
     /* wl */ NOT_BEGIN | PREFIX | SUFFIX,
     /* wm */ NOT_BEGIN | PREFIX,
     /* wn */ NOT_BEGIN | PREFIX,
     /* wo */ ANY_COMBINATION,
     /* wp */ NOT_BEGIN | PREFIX,
     /* wr */ BEGIN | SUFFIX | NOT_END,
     /* ws */ NOT_BEGIN | PREFIX,
     /* wt */ NOT_BEGIN | PREFIX,
     /* wu */ ANY_COMBINATION,
     /* wv */ NOT_BEGIN | PREFIX,
     /* ww */ NOT_BEGIN | BREAK | NOT_END,
     /* wx */ NOT_BEGIN | PREFIX,
     /* wy */ ANY_COMBINATION,
     /* wz */ NOT_BEGIN | PREFIX,
     /* wch */ NOT_BEGIN,
     /* wgh */ NOT_BEGIN | BREAK | NOT_END,
     /* wph */ NOT_BEGIN,
     /* wrh */ ILLEGAL_PAIR,
     /* wsh */ NOT_BEGIN,
     /* wth */ NOT_BEGIN,
     /* wwh */ ILLEGAL_PAIR,
     /* wqu */ NOT_BEGIN | BREAK | NOT_END,
     /* wck */ NOT_BEGIN},
     /* xa */ {NOT_BEGIN,
     /* xb */ NOT_BEGIN | BREAK | NOT_END,
     /* xc */ NOT_BEGIN | BREAK | NOT_END,
     /* xd */ NOT_BEGIN | BREAK | NOT_END,
     /* xe */ NOT_BEGIN,
     /* xf */ NOT_BEGIN | BREAK | NOT_END,
     /* xg */ NOT_BEGIN | BREAK | NOT_END,
     /* xh */ NOT_BEGIN | BREAK | NOT_END,
     /* xi */ NOT_BEGIN,
     /* xj */ NOT_BEGIN | BREAK | NOT_END,
     /* xk */ NOT_BEGIN | BREAK | NOT_END,
     /* xl */ NOT_BEGIN | BREAK | NOT_END,
     /* xm */ NOT_BEGIN | BREAK | NOT_END,
     /* xn */ NOT_BEGIN | BREAK | NOT_END,
     /* xo */ NOT_BEGIN,
     /* xp */ NOT_BEGIN | BREAK | NOT_END,
     /* xr */ NOT_BEGIN | BREAK | NOT_END,
     /* xs */ NOT_BEGIN | BREAK | NOT_END,
     /* xt */ NOT_BEGIN | BREAK | NOT_END,
     /* xu */ NOT_BEGIN,
     /* xv */ NOT_BEGIN | BREAK | NOT_END,
     /* xw */ NOT_BEGIN | BREAK | NOT_END,
     /* xx */ ILLEGAL_PAIR,
     /* xy */ NOT_BEGIN,
     /* xz */ NOT_BEGIN | BREAK | NOT_END,
     /* xch */ NOT_BEGIN | BREAK | NOT_END,
     /* xgh */ NOT_BEGIN | BREAK | NOT_END,
     /* xph */ NOT_BEGIN | BREAK | NOT_END,
     /* xrh */ ILLEGAL_PAIR,
     /* xsh */ NOT_BEGIN | BREAK | NOT_END,
     /* xth */ NOT_BEGIN | BREAK | NOT_END,
     /* xwh */ ILLEGAL_PAIR,
     /* xqu */ NOT_BEGIN | BREAK | NOT_END,
     /* xck */ ILLEGAL_PAIR},
     /* ya */ {ANY_COMBINATION,
     /* yb */ NOT_BEGIN,
     /* yc */ NOT_BEGIN | NOT_END,
     /* yd */ NOT_BEGIN,
     /* ye */ ANY_COMBINATION,
     /* yf */ NOT_BEGIN | NOT_END,
     /* yg */ NOT_BEGIN,
     /* yh */ NOT_BEGIN | BREAK | NOT_END,
     /* yi */ BEGIN | NOT_END,
     /* yj */ NOT_BEGIN | NOT_END,
     /* yk */ NOT_BEGIN,
     /* yl */ NOT_BEGIN | NOT_END,
     /* ym */ NOT_BEGIN,
     /* yn */ NOT_BEGIN,
     /* yo */ ANY_COMBINATION,
     /* yp */ NOT_BEGIN,
     /* yr */ NOT_BEGIN | BREAK | NOT_END,
     /* ys */ NOT_BEGIN,
     /* yt */ NOT_BEGIN,
     /* yu */ ANY_COMBINATION,
     /* yv */ NOT_BEGIN | NOT_END,
     /* yw */ NOT_BEGIN | BREAK | NOT_END,
     /* yx */ NOT_BEGIN,
     /* yy */ ILLEGAL_PAIR,
     /* yz */ NOT_BEGIN,
     /* ych */ NOT_BEGIN | BREAK | NOT_END,
     /* ygh */ NOT_BEGIN | BREAK | NOT_END,
     /* yph */ NOT_BEGIN | BREAK | NOT_END,
     /* yrh */ ILLEGAL_PAIR,
     /* ysh */ NOT_BEGIN | BREAK | NOT_END,
     /* yth */ NOT_BEGIN | BREAK | NOT_END,
     /* ywh */ ILLEGAL_PAIR,
     /* yqu */ NOT_BEGIN | BREAK | NOT_END,
     /* yck */ ILLEGAL_PAIR},
     /* za */ {ANY_COMBINATION,
     /* zb */ NOT_BEGIN | BREAK | NOT_END,
     /* zc */ NOT_BEGIN | BREAK | NOT_END,
     /* zd */ NOT_BEGIN | BREAK | NOT_END,
     /* ze */ ANY_COMBINATION,
     /* zf */ NOT_BEGIN | BREAK | NOT_END,
     /* zg */ NOT_BEGIN | BREAK | NOT_END,
     /* zh */ NOT_BEGIN | BREAK | NOT_END,
     /* zi */ ANY_COMBINATION,
     /* zj */ NOT_BEGIN | BREAK | NOT_END,
     /* zk */ NOT_BEGIN | BREAK | NOT_END,
     /* zl */ NOT_BEGIN | BREAK | NOT_END,
     /* zm */ NOT_BEGIN | BREAK | NOT_END,
     /* zn */ NOT_BEGIN | BREAK | NOT_END,
     /* zo */ ANY_COMBINATION,
     /* zp */ NOT_BEGIN | BREAK | NOT_END,
     /* zr */ NOT_BEGIN | NOT_END,
     /* zs */ NOT_BEGIN | BREAK | NOT_END,
     /* zt */ NOT_BEGIN,
     /* zu */ ANY_COMBINATION,
     /* zv */ NOT_BEGIN | BREAK | NOT_END,
     /* zw */ SUFFIX | NOT_END,
     /* zx */ ILLEGAL_PAIR,
     /* zy */ ANY_COMBINATION,
     /* zz */ NOT_BEGIN,
     /* zch */ NOT_BEGIN | BREAK | NOT_END,
     /* zgh */ NOT_BEGIN | BREAK | NOT_END,
     /* zph */ NOT_BEGIN | BREAK | NOT_END,
     /* zrh */ ILLEGAL_PAIR,
     /* zsh */ NOT_BEGIN | BREAK | NOT_END,
     /* zth */ NOT_BEGIN | BREAK | NOT_END,
     /* zwh */ ILLEGAL_PAIR,
     /* zqu */ NOT_BEGIN | BREAK | NOT_END,
     /* zck */ ILLEGAL_PAIR},
     /* cha */ {ANY_COMBINATION,
     /* chb */ NOT_BEGIN | BREAK | NOT_END,
     /* chc */ NOT_BEGIN | BREAK | NOT_END,
     /* chd */ NOT_BEGIN | BREAK | NOT_END,
     /* che */ ANY_COMBINATION,
     /* chf */ NOT_BEGIN | BREAK | NOT_END,
     /* chg */ NOT_BEGIN | BREAK | NOT_END,
     /* chh */ NOT_BEGIN | BREAK | NOT_END,
     /* chi */ ANY_COMBINATION,
     /* chj */ NOT_BEGIN | BREAK | NOT_END,
     /* chk */ NOT_BEGIN | BREAK | NOT_END,
     /* chl */ NOT_BEGIN | BREAK | NOT_END,
     /* chm */ NOT_BEGIN | BREAK | NOT_END,
     /* chn */ NOT_BEGIN | BREAK | NOT_END,
     /* cho */ ANY_COMBINATION,
     /* chp */ NOT_BEGIN | BREAK | NOT_END,
     /* chr */ NOT_END,
     /* chs */ NOT_BEGIN | BREAK | NOT_END,
     /* cht */ NOT_BEGIN | BREAK | NOT_END,
     /* chu */ ANY_COMBINATION,
     /* chv */ NOT_BEGIN | BREAK | NOT_END,
     /* chw */ NOT_BEGIN | NOT_END,
     /* chx */ ILLEGAL_PAIR,
     /* chy */ ANY_COMBINATION,
     /* chz */ NOT_BEGIN | BREAK | NOT_END,
     /* chch */ ILLEGAL_PAIR,
     /* chgh */ NOT_BEGIN | BREAK | NOT_END,
     /* chph */ NOT_BEGIN | BREAK | NOT_END,
     /* chrh */ ILLEGAL_PAIR,
     /* chsh */ NOT_BEGIN | BREAK | NOT_END,
     /* chth */ NOT_BEGIN | BREAK | NOT_END,
     /* chwh */ ILLEGAL_PAIR,
     /* chqu */ NOT_BEGIN | BREAK | NOT_END,
     /* chck */ ILLEGAL_PAIR},
     /* gha */ {ANY_COMBINATION,
     /* ghb */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghc */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghd */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghe */ ANY_COMBINATION,
     /* ghf */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghg */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghh */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghi */ BEGIN | NOT_END,
     /* ghj */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghk */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghl */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghm */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghn */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* gho */ BEGIN | NOT_END,
     /* ghp */ NOT_BEGIN | BREAK | NOT_END,
     /* ghr */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghs */ NOT_BEGIN | PREFIX,
     /* ght */ NOT_BEGIN | PREFIX,
     /* ghu */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghv */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghw */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghx */ ILLEGAL_PAIR,
     /* ghy */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghz */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghch */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghgh */ ILLEGAL_PAIR,
     /* ghph */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghrh */ ILLEGAL_PAIR,
     /* ghsh */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghth */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghwh */ ILLEGAL_PAIR,
     /* ghqu */ NOT_BEGIN | BREAK | PREFIX | NOT_END,
     /* ghck */ ILLEGAL_PAIR},
     /* pha */ {ANY_COMBINATION,
     /* phb */ NOT_BEGIN | BREAK | NOT_END,
     /* phc */ NOT_BEGIN | BREAK | NOT_END,
     /* phd */ NOT_BEGIN | BREAK | NOT_END,
     /* phe */ ANY_COMBINATION,
     /* phf */ NOT_BEGIN | BREAK | NOT_END,
     /* phg */ NOT_BEGIN | BREAK | NOT_END,
     /* phh */ NOT_BEGIN | BREAK | NOT_END,
     /* phi */ ANY_COMBINATION,
     /* phj */ NOT_BEGIN | BREAK | NOT_END,
     /* phk */ NOT_BEGIN | BREAK | NOT_END,
     /* phl */ BEGIN | SUFFIX | NOT_END,
     /* phm */ NOT_BEGIN | BREAK | NOT_END,
     /* phn */ NOT_BEGIN | BREAK | NOT_END,
     /* pho */ ANY_COMBINATION,
     /* php */ NOT_BEGIN | BREAK | NOT_END,
     /* phr */ NOT_END,
     /* phs */ NOT_BEGIN,
     /* pht */ NOT_BEGIN,
     /* phu */ ANY_COMBINATION,
     /* phv */ NOT_BEGIN | NOT_END,
     /* phw */ NOT_BEGIN | NOT_END,
     /* phx */ ILLEGAL_PAIR,
     /* phy */ NOT_BEGIN,
     /* phz */ NOT_BEGIN | BREAK | NOT_END,
     /* phch */ NOT_BEGIN | BREAK | NOT_END,
     /* phgh */ NOT_BEGIN | BREAK | NOT_END,
     /* phph */ ILLEGAL_PAIR,
     /* phrh */ ILLEGAL_PAIR,
     /* phsh */ NOT_BEGIN | BREAK | NOT_END,
     /* phth */ NOT_BEGIN | BREAK | NOT_END,
     /* phwh */ ILLEGAL_PAIR,
     /* phqu */ NOT_BEGIN | BREAK | NOT_END,
     /* phck */ ILLEGAL_PAIR},
     /* rha */ {BEGIN | NOT_END,
     /* rhb */ ILLEGAL_PAIR,
     /* rhc */ ILLEGAL_PAIR,
     /* rhd */ ILLEGAL_PAIR,
     /* rhe */ BEGIN | NOT_END,
     /* rhf */ ILLEGAL_PAIR,
     /* rhg */ ILLEGAL_PAIR,
     /* rhh */ ILLEGAL_PAIR,
     /* rhi */ BEGIN | NOT_END,
     /* rhj */ ILLEGAL_PAIR,
     /* rhk */ ILLEGAL_PAIR,
     /* rhl */ ILLEGAL_PAIR,
     /* rhm */ ILLEGAL_PAIR,
     /* rhn */ ILLEGAL_PAIR,
     /* rho */ BEGIN | NOT_END,
     /* rhp */ ILLEGAL_PAIR,
     /* rhr */ ILLEGAL_PAIR,
     /* rhs */ ILLEGAL_PAIR,
     /* rht */ ILLEGAL_PAIR,
     /* rhu */ BEGIN | NOT_END,
     /* rhv */ ILLEGAL_PAIR,
     /* rhw */ ILLEGAL_PAIR,
     /* rhx */ ILLEGAL_PAIR,
     /* rhy */ BEGIN | NOT_END,
     /* rhz */ ILLEGAL_PAIR,
     /* rhch */ ILLEGAL_PAIR,
     /* rhgh */ ILLEGAL_PAIR,
     /* rhph */ ILLEGAL_PAIR,
     /* rhrh */ ILLEGAL_PAIR,
     /* rhsh */ ILLEGAL_PAIR,
     /* rhth */ ILLEGAL_PAIR,
     /* rhwh */ ILLEGAL_PAIR,
     /* rhqu */ ILLEGAL_PAIR,
     /* rhck */ ILLEGAL_PAIR},
     /* sha */ {ANY_COMBINATION,
     /* shb */ NOT_BEGIN | BREAK | NOT_END,
     /* shc */ NOT_BEGIN | BREAK | NOT_END,
     /* shd */ NOT_BEGIN | BREAK | NOT_END,
     /* she */ ANY_COMBINATION,
     /* shf */ NOT_BEGIN | BREAK | NOT_END,
     /* shg */ NOT_BEGIN | BREAK | NOT_END,
     /* shh */ ILLEGAL_PAIR,
     /* shi */ ANY_COMBINATION,
     /* shj */ NOT_BEGIN | BREAK | NOT_END,
     /* shk */ NOT_BEGIN,
     /* shl */ BEGIN | SUFFIX | NOT_END,
     /* shm */ BEGIN | SUFFIX | NOT_END,
     /* shn */ BEGIN | SUFFIX | NOT_END,
     /* sho */ ANY_COMBINATION,
     /* shp */ NOT_BEGIN,
     /* shr */ BEGIN | SUFFIX | NOT_END,
     /* shs */ NOT_BEGIN | BREAK | NOT_END,
     /* sht */ SUFFIX,
     /* shu */ ANY_COMBINATION,
     /* shv */ NOT_BEGIN | BREAK | NOT_END,
     /* shw */ SUFFIX | NOT_END,
     /* shx */ ILLEGAL_PAIR,
     /* shy */ ANY_COMBINATION,
     /* shz */ NOT_BEGIN | BREAK | NOT_END,
     /* shch */ NOT_BEGIN | BREAK | NOT_END,
     /* shgh */ NOT_BEGIN | BREAK | NOT_END,
     /* shph */ NOT_BEGIN | BREAK | NOT_END,
     /* shrh */ ILLEGAL_PAIR,
     /* shsh */ ILLEGAL_PAIR,
     /* shth */ NOT_BEGIN | BREAK | NOT_END,
     /* shwh */ ILLEGAL_PAIR,
     /* shqu */ NOT_BEGIN | BREAK | NOT_END,
     /* shck */ ILLEGAL_PAIR},
     /* tha */ {ANY_COMBINATION,
     /* thb */ NOT_BEGIN | BREAK | NOT_END,
     /* thc */ NOT_BEGIN | BREAK | NOT_END,
     /* thd */ NOT_BEGIN | BREAK | NOT_END,
     /* the */ ANY_COMBINATION,
     /* thf */ NOT_BEGIN | BREAK | NOT_END,
     /* thg */ NOT_BEGIN | BREAK | NOT_END,
     /* thh */ NOT_BEGIN | BREAK | NOT_END,
     /* thi */ ANY_COMBINATION,
     /* thj */ NOT_BEGIN | BREAK | NOT_END,
     /* thk */ NOT_BEGIN | BREAK | NOT_END,
     /* thl */ NOT_BEGIN | BREAK | NOT_END,
     /* thm */ NOT_BEGIN | BREAK | NOT_END,
     /* thn */ NOT_BEGIN | BREAK | NOT_END,
     /* tho */ ANY_COMBINATION,
     /* thp */ NOT_BEGIN | BREAK | NOT_END,
     /* thr */ NOT_END,
     /* ths */ NOT_BEGIN | END,
     /* tht */ NOT_BEGIN | BREAK | NOT_END,
     /* thu */ ANY_COMBINATION,
     /* thv */ NOT_BEGIN | BREAK | NOT_END,
     /* thw */ SUFFIX | NOT_END,
     /* thx */ ILLEGAL_PAIR,
     /* thy */ ANY_COMBINATION,
     /* thz */ NOT_BEGIN | BREAK | NOT_END,
     /* thch */ NOT_BEGIN | BREAK | NOT_END,
     /* thgh */ NOT_BEGIN | BREAK | NOT_END,
     /* thph */ NOT_BEGIN | BREAK | NOT_END,
     /* thrh */ ILLEGAL_PAIR,
     /* thsh */ NOT_BEGIN | BREAK | NOT_END,
     /* thth */ ILLEGAL_PAIR,
     /* thwh */ ILLEGAL_PAIR,
     /* thqu */ NOT_BEGIN | BREAK | NOT_END,
     /* thck */ ILLEGAL_PAIR},
     /* wha */ {BEGIN | NOT_END,
     /* whb */ ILLEGAL_PAIR,
     /* whc */ ILLEGAL_PAIR,
     /* whd */ ILLEGAL_PAIR,
     /* whe */ BEGIN | NOT_END,
     /* whf */ ILLEGAL_PAIR,
     /* whg */ ILLEGAL_PAIR,
     /* whh */ ILLEGAL_PAIR,
     /* whi */ BEGIN | NOT_END,
     /* whj */ ILLEGAL_PAIR,
     /* whk */ ILLEGAL_PAIR,
     /* whl */ ILLEGAL_PAIR,
     /* whm */ ILLEGAL_PAIR,
     /* whn */ ILLEGAL_PAIR,
     /* who */ BEGIN | NOT_END,
     /* whp */ ILLEGAL_PAIR,
     /* whr */ ILLEGAL_PAIR,
     /* whs */ ILLEGAL_PAIR,
     /* wht */ ILLEGAL_PAIR,
     /* whu */ ILLEGAL_PAIR,
     /* whv */ ILLEGAL_PAIR,
     /* whw */ ILLEGAL_PAIR,
     /* whx */ ILLEGAL_PAIR,
     /* why */ BEGIN | NOT_END,
     /* whz */ ILLEGAL_PAIR,
     /* whch */ ILLEGAL_PAIR,
     /* whgh */ ILLEGAL_PAIR,
     /* whph */ ILLEGAL_PAIR,
     /* whrh */ ILLEGAL_PAIR,
     /* whsh */ ILLEGAL_PAIR,
     /* whth */ ILLEGAL_PAIR,
     /* whwh */ ILLEGAL_PAIR,
     /* whqu */ ILLEGAL_PAIR,
     /* whck */ ILLEGAL_PAIR},
     /* qua */ {ANY_COMBINATION,
     /* qub */ ILLEGAL_PAIR,
     /* quc */ ILLEGAL_PAIR,
     /* qud */ ILLEGAL_PAIR,
     /* que */ ANY_COMBINATION,
     /* quf */ ILLEGAL_PAIR,
     /* qug */ ILLEGAL_PAIR,
     /* quh */ ILLEGAL_PAIR,
     /* qui */ ANY_COMBINATION,
     /* quj */ ILLEGAL_PAIR,
     /* quk */ ILLEGAL_PAIR,
     /* qul */ ILLEGAL_PAIR,
     /* qum */ ILLEGAL_PAIR,
     /* qun */ ILLEGAL_PAIR,
     /* quo */ ANY_COMBINATION,
     /* qup */ ILLEGAL_PAIR,
     /* qur */ ILLEGAL_PAIR,
     /* qus */ ILLEGAL_PAIR,
     /* qut */ ILLEGAL_PAIR,
     /* quu */ ILLEGAL_PAIR,
     /* quv */ ILLEGAL_PAIR,
     /* quw */ ILLEGAL_PAIR,
     /* qux */ ILLEGAL_PAIR,
     /* quy */ ILLEGAL_PAIR,
     /* quz */ ILLEGAL_PAIR,
     /* quch */ ILLEGAL_PAIR,
     /* qugh */ ILLEGAL_PAIR,
     /* quph */ ILLEGAL_PAIR,
     /* qurh */ ILLEGAL_PAIR,
     /* qush */ ILLEGAL_PAIR,
     /* quth */ ILLEGAL_PAIR,
     /* quwh */ ILLEGAL_PAIR,
     /* ququ */ ILLEGAL_PAIR,
     /* quck */ ILLEGAL_PAIR},
     /* cka */ {NOT_BEGIN | BREAK | NOT_END,
     /* ckb */ NOT_BEGIN | BREAK | NOT_END,
     /* ckc */ NOT_BEGIN | BREAK | NOT_END,
     /* ckd */ NOT_BEGIN | BREAK | NOT_END,
     /* cke */ NOT_BEGIN | BREAK | NOT_END,
     /* ckf */ NOT_BEGIN | BREAK | NOT_END,
     /* ckg */ NOT_BEGIN | BREAK | NOT_END,
     /* ckh */ NOT_BEGIN | BREAK | NOT_END,
     /* cki */ NOT_BEGIN | BREAK | NOT_END,
     /* ckj */ NOT_BEGIN | BREAK | NOT_END,
     /* ckk */ NOT_BEGIN | BREAK | NOT_END,
     /* ckl */ NOT_BEGIN | BREAK | NOT_END,
     /* ckm */ NOT_BEGIN | BREAK | NOT_END,
     /* ckn */ NOT_BEGIN | BREAK | NOT_END,
     /* cko */ NOT_BEGIN | BREAK | NOT_END,
     /* ckp */ NOT_BEGIN | BREAK | NOT_END,
     /* ckr */ NOT_BEGIN | BREAK | NOT_END,
     /* cks */ NOT_BEGIN,
     /* ckt */ NOT_BEGIN | BREAK | NOT_END,
     /* cku */ NOT_BEGIN | BREAK | NOT_END,
     /* ckv */ NOT_BEGIN | BREAK | NOT_END,
     /* ckw */ NOT_BEGIN | BREAK | NOT_END,
     /* ckx */ ILLEGAL_PAIR,
     /* cky */ NOT_BEGIN,
     /* ckz */ NOT_BEGIN | BREAK | NOT_END,
     /* ckch */ NOT_BEGIN | BREAK | NOT_END,
     /* ckgh */ NOT_BEGIN | BREAK | NOT_END,
     /* ckph */ NOT_BEGIN | BREAK | NOT_END,
     /* ckrh */ ILLEGAL_PAIR,
     /* cksh */ NOT_BEGIN | BREAK | NOT_END,
     /* ckth */ NOT_BEGIN | BREAK | NOT_END,
     /* ckwh */ ILLEGAL_PAIR,
     /* ckqu */ NOT_BEGIN | BREAK | NOT_END,
     /* ckck */ ILLEGAL_PAIR}
};




#ifdef	  RAN_DEBUG
void generate_pwd (
    unsigned32	    plcy_args,
    sec_attr_t	    plcy[],
    unsigned char   **gen_pwd,
    error_status_t  *status
)
{
    register unsigned int pwlen;
    register unsigned int minimum;
    boolean no_legal_words;
    register char  *unhyphenated_word;
    register char  *hyphenated_word;
    time_t ltime;
#ifdef IBMOS2  /* CMVC 10856 */
#ifdef OS2_EXAMPLE
    utc_t	utc_buf;
    timespec_t	time_component;
    timespec_t	inacc_component;
    long	tdf;
#else
    struct   timeval  time_for_os2;
#endif
#endif /* IBMOS2 */

    /* type of generation algorithm to use */
#ifdef B1
    int algorithm = 0;
#endif

    *status = error_status_ok;

    /* should we check against dictionary? */
    no_legal_words = FALSE;

    /* maximum generated password length */
    pwlen = 8;

    /* minimum generated password length */
    minimum = 6;

    /*
     * Set min/max length based on registry policy
     */

    /*
     * If min length is < 6, ignore. Returning passwords less
     * than 6 characters is probably not a good idea.
     */
    if (plcy[0].attr_value.tagged_union.signed_int > minimum) {
	minimum = plcy[0].attr_value.tagged_union.signed_int;
	pwlen = minimum + 2;
    }

    /*
     * Check password policy flags. If all spaces is prohibited,
     * ignore because the generator will never generate a password
     * with all spaces.
     */
    if ((plcy[1].attr_value.tagged_union.signed_int & sec_rgy_plcy_pwd_no_spaces) != 0)
    {
	/* no spaces in password */
    }
    else
    {
	/* spaces allowed */
    }

    /*
     * During debugging (RAN_DEBUG is set), we generate the seed from here
     * rather than the first entry to randomword() .
     */
    if (seed == 0L){
#ifdef IBMOS2  /* CMVC 10856 */
#ifdef OS2_EXAMPLE
	if (utc_gettime(&utc_buf) == -1 ||
	    utc_bintime(&time_component,&inacc_component,&tdf,&utc_buf)==-1) {
	    *status = sec_s_no_memory;	/* just say no mem if time failure. */
	    return;
	} else {
	    ltime = time_component.tv_sec;
	}
#else
/* Avoid OS2 time() function, which is not completely trustworthy. */
#ifdef SNI_SVR4_POSIX
	gettimeofday(&time_for_os2);
#else
	gettimeofday(&time_for_os2, 0);
#endif
	ltime = (time_t)time_for_os2.tv_sec;
#endif	/* OS2_EXAMPLE */
#else
	time(&ltime);
#endif	/* IBMOS2 */
	set_seed((long) ltime);
    }

    unhyphenated_word = calloc(sizeof (char), pwlen + 1);
    hyphenated_word = calloc(sizeof (char), 2 * pwlen);
#ifdef B1
    switch (algorithm)	{
	default:
	case 0:
	    (void) randomword(unhyphenated_word, hyphenated_word, minimum, pwlen, no_legal_words, 0L);
	    break;
	case 1:
	    (void) randomchars(unhyphenated_word, minimum, pwlen, no_legal_words, 0L);
	    break;
	case 2:
	    (void) randomletters(unhyphenated_word, minimum, pwlen, no_legal_words, 0L);
	    break;
    }
#else
    (void) randomword(unhyphenated_word, hyphenated_word, minimum, pwlen, no_legal_words, 0L);
#endif
    /*
     * If password policy prohibits a password with all alphanumeric characters,
     * return the hyphenated word. This is not the greatest solution (it increases
     * the password's length) but it is good enough for a sample server.
     */
    if ((plcy[1].attr_value.tagged_union.signed_int & sec_rgy_plcy_pwd_non_alpha) != 0) {
	*gen_pwd = (unsigned char *) rpc_ss_allocate(strlen(hyphenated_word) + 1);
	if (*gen_pwd == NULL) {
	    *status = sec_s_no_memory;
	} else {
	    (void) strcpy((char *)*gen_pwd, hyphenated_word);
	}
    } else {
	*gen_pwd = (unsigned char *) rpc_ss_allocate(strlen(unhyphenated_word) + 1);
	if (*gen_pwd == NULL) {
	    *status = sec_s_no_memory;
	} else {
	    (void) strcpy((char *)*gen_pwd, unhyphenated_word);
	}
    }
    free(hyphenated_word);
    free(unhyphenated_word);
}
#endif


#ifdef B1
/*
 * Randomchars will generate a random string and place it in the
 * buffer word.  The word must be pre-allocated.  The words generated
 * will have sizes between minlen and maxlen.  If restrict is TRUE,
 * words will not be generated that appear as login names or as entries
 * in the on-line dictionary.  The seed is used on first use of the routine.
 * The length of the word is returned, or -1 if there were an error
 * (length settings are wrong or dictionary checking could not be done).
 * The seed is used on first use of the routine.
 */
static int randomchars (
    register char  *string,
    register unsigned int minlen,
    register unsigned int maxlen,
    register boolean restrict,
    long seed
)
{
    register int loop_count;
    register unsigned int string_size;
    register unsigned int build;
    static  been_here_before = FALSE;

    /*
     * Execute this upon startup.  This initializes the
     * environment, including seed'ing the random number
     * generator and loading the on-line dictionary.
     */
    if (!been_here_before) {
	been_here_before = TRUE;

#ifndef RAN_DEBUG
	set_seed(seed);
#endif
     }
    /*
     * Check for minlen > maxlen.  This is an error.
     */
    if (minlen > maxlen)
	return(-1);


    loop_count = 0;
    string_size = get_random(minlen, maxlen);

    do {
	for (build = 0; build < string_size; build++)  {
	    string[build] = (char) get_random((unsigned int) '!',
		(unsigned int) '~');
	}

	restrict = 0;

	loop_count ++;
    } while (restrict && (loop_count <= MAX_UNACCEPTABLE));

    string[string_size] = '\0';

    return string_size;
}


/*
 * Randomletters will generate a random string of letters and place it in the
 * buffer word.  The word must be pre-allocated.  The words generated
 * will have sizes between minlen and maxlen.  If restrict is TRUE,
 * words will not be generated that appear as login names or as entries
 * in the on-line dictionary.  The seed is used on first use of the routine.
 * The length of the word is returned, or -1 if there were an error
 * (length settings are wrong or dictionary checking could not be done).
 * The seed is used on first use of the routine.
 */
static int randomletters (
    register char  *string,
    register unsigned int minlen,
    register unsigned int maxlen,
    register boolean restrict,
    long seed
)
{
     register int loop_count;
     register unsigned int string_size;
     register unsigned int build;
     static  been_here_before = FALSE;

     /*
      * Execute this upon startup.  This initializes the
      * environment, including seed'ing the random number
      * generator and loading the on-line dictionary.
      */
     if (!been_here_before) {
	 been_here_before = TRUE;

#ifndef RAN_DEBUG
	  set_seed(seed);
#endif
     }
     /*
      * Check for minlen > maxlen.  This is an error.
      */
     if (minlen > maxlen)
	 return(-1);

     loop_count = 0;
     string_size = get_random(minlen, maxlen);

     do {
	 for (build = 0; build < string_size; build++)	{
	     string[build] = (char) get_random((unsigned int) 'a',
		 (unsigned int) 'z');
	 }

	 restrict = 0;
	 loop_count ++;
     } while (restrict && (loop_count <= MAX_UNACCEPTABLE));

     string[string_size] = '\0';

     return string_size;
}
#endif


/*
 * Randomword will generate a random word and place it in the
 * buffer word.  Also, the hyphenated word will be placed into
 * the buffer hyphenated_word.	Both word and hyphenated_word must
 * be pre-allocated.  The words generated will have sizes between
 * minlen and maxlen.  If restrict is TRUE, words will not be generated that
 * appear as login names or as entries in the on-line dictionary.
 * This algorithm was initially worded out by Morrie Gasser in 1975.
 * Any changes here are minimal so that as many word combinations
 * can be produced as possible (and thus keep the words random).
 * The seed is used on first use of the routine.
 * The length of the unhyphenated word is returned, or -1 if there
 * were an error (length settings are wrong or dictionary checking
 * could not be done.
 */
static int randomword (
    register char  *word,
    register char  *hyphenated_word,
    register unsigned int minlen,
    register unsigned int maxlen,
    register boolean restrict,
    long seed
)
{
    register int     pwlen;
    register int     loop_count;
    static  been_here_before = FALSE;

    /*
     * Execute this upon startup.  This initializes the
     * environment, including seed'ing the random number
     * generator and loading the on-line dictionary.
     */
    if (!been_here_before) {
	been_here_before = TRUE;


#ifndef RAN_DEBUG
	set_seed(seed);
#endif
    }

    /*
     * Check for minlen>maxlen.  This is an error.
     * and a length of 0.
     */
    if (minlen > maxlen)
	return(-1);

    /*
     * Check for zero length words.  This is technically not an error,
     * so we take the cut and return a null word and a length of 0.
     */
    if (maxlen == 0) {
	word[0] = '\0';
	hyphenated_word[0] = '\0';
	return(0);
    }

    /*
     * Continue finding words until the criteria are satisfied.
     * The criteria are, if restrict is set, that if the word appears
     * as either a login name or as part of the on-line dictionary,
     * throw out the word and look for another.
     */
    loop_count = 0;

    do {
	/*
	 * Get a random word.  Its length is a random quantity
	 * from with the limits specified in the call to
	 * randomword().
	 */
	pwlen = get_word(word, hyphenated_word, get_random(minlen, maxlen));
	restrict = 0;
	loop_count++;
    }
    while (restrict && (loop_count <= MAX_UNACCEPTABLE));

/*
    if (restrict)  {
	(void) fflush(stdout);
	(void) fprintf(stderr, "could not find acceptable random password\n");
	(void) fflush(stderr);
	exit(1);
    } */

    return(pwlen);
}


/*
 * This is the routine that returns a random word -- as
 * yet unchecked against the passwd file or the dictionary.
 * It collects random syllables until a predetermined
 * word length is found.  If a retry threshold is reached,
 * another word is tried.  Given that the random number
 * generator is uniformly distributed, eventually a word
 * will be found if the retry limit is adequately large enough.
 */
static int get_word (
    char   *word,
    char   *hyphenated_word,
    unsigned int  pwlen
)
{
    register unsigned int word_length;
    register unsigned int syllable_length;
    register char *new_syllable;
    register unsigned int *syllable_units;
    register unsigned int word_size;
    register unsigned int word_place;
    int unsigned *word_units;
    int unsigned syllable_size;
    int unsigned tries;

    /*
     * Keep count of retries.
     */
    tries = 0;

    /*
     * The length of the word in characters.
     */
    word_length = 0;

    /*
     * The length of the word in character units (each of which is one or
     * two characters long.
     */
    word_size = 0;

    /*
     * Initialize the array storing the word units.  Since we know the
     * length of the word, we only need one of that length.  This method is
     * preferable to a static array, since it allows us flexibility in
     * choosing arbitrarily long word lengths.	Since a word can contain one
     * syllable, we should make syllable_units, the array holding the
     * analogous units for an individual syllable, the same length.  No
     * explicit rule limits the length of syllables, but digram rules and
     * heuristics do so indirectly.
     */
    word_units = (unsigned int *)
	calloc(sizeof (unsigned int), pwlen);
    syllable_units = (unsigned int *)
	calloc(sizeof (unsigned int), pwlen);
    new_syllable = calloc(sizeof (unsigned int), pwlen);

    /*
     * Find syllables until the entire word is constructed.
     */
    while (word_length < pwlen) {
	/*
	 * Get the syllable and find its length.
	 */
	(void) get_syllable(new_syllable, pwlen - word_length,
	    syllable_units, &syllable_size);
	syllable_length = strlen(new_syllable);

	/*
	 * Append the syllable units to the word units.
	 */
	for (word_place = 0; word_place <= syllable_size; word_place++)
	    word_units[word_size + word_place] = syllable_units[word_place];
	word_size += syllable_size + 1;

	/*
	 * If the word has been improperly formed, throw out
	 * the syllable.  The checks performed here are those
	 * that must be formed on a word basis.  The other
	 * tests are performed entirely within the syllable.
	 * Otherwise, append the syllable to the word and
	 * append the syllable to the hyphenated version of
	 * the word.
	 */
	if (improper_word(word_units, word_size) ||
	    ((word_length == 0) &&
	    have_initial_y(syllable_units, syllable_size)) ||
	    ((word_length + syllable_length == pwlen) &&
	    have_final_split(syllable_units, syllable_size)))
	    word_size -= syllable_size + 1;
	else {
	    if (word_length == 0) {
		(void) strcpy(word, new_syllable);
		(void) strcpy(hyphenated_word, new_syllable);
	    } else {
		(void) strcat(word, new_syllable);
		(void) strcat(hyphenated_word, "-");
		(void) strcat(hyphenated_word, new_syllable);
	    }
	    word_length += syllable_length;
	}

	/*
	 * Keep track of the times we have tried to get
	 * syllables.  If we have exceeded the threshold,
	 * reinitialize the pwlen and word_size variables, clear
	 * out the word arrays, and start from scratch.
	 */
	tries++;
	if (tries > MAX_RETRIES) {
	    word_length = 0;
	    word_size = 0;
	    tries = 0;
	    (void) strcpy(word, "");
	    (void) strcpy(hyphenated_word, "");
	}
    }

    /*
     * The units arrays and syllable storage are internal to this
     * routine.  Since the caller has no need for them, we
     * release the space.
     */
    free((char *) new_syllable);
    free((char *) syllable_units);
    free((char *) word_units);

    return((int) word_length);
}



/*
 * Check that the word does not contain illegal combinations
 * that may span syllables.  Specifically, these are:
 *   1. An illegal pair of units between syllables.
 *   2. Three consecutive vowel units.
 *   3. Three consecutive consonant units.
 * The checks are made against units (1 or 2 letters), not against
 * the individual letters, so three consecutive units can have
 * the length of 6 at most.
 */
static boolean improper_word (
    register unsigned int *units,
    register unsigned int word_size
)
{
    register unsigned int unit_count;
    register	boolean failure;

    failure = FALSE;

    for (unit_count = 0; !failure && (unit_count < word_size);
	 unit_count++) {
	/*
	 * Check for ILLEGAL_PAIR.  This should have been caught
	 * for units within a syllable, but in some cases it
	 * would have gone unnoticed for units between syllables
	 * (e.g., when saved_unit's in get_syllable() were not
	 * used).
	 */
	if ((unit_count != 0) &&
	    (digram[units[unit_count - 1]][units[unit_count]] &
	    ILLEGAL_PAIR))
	    failure = TRUE;

	/*
	 * Check for consecutive vowels or consonants.	Because
	 * the initial y of a syllable is treated as a consonant
	 * rather than as a vowel, we exclude y from the first
	 * vowel in the vowel test.  The only problem comes when
	 * y ends a syllable and two other vowels start the next,
	 * like fly-oint.  Since such words are still
	 * pronounceable, we accept this.
	 */
	if (!failure && (unit_count >= 2)) {
	    /*
	     * Vowel check.
	     */
	    if ((((rules[units[unit_count - 2]].flags & VOWEL) &&
		!(rules[units[unit_count - 2]].flags &
		ALTERNATE_VOWEL)) &&
		(rules[units[unit_count - 1]].flags & VOWEL) &&
		(rules[units[unit_count]].flags & VOWEL)) ||
		/*
		 * Consonant check.
		 */
		(!(rules[units[unit_count - 2]].flags & VOWEL) &&
		!(rules[units[unit_count - 1]].flags & VOWEL) &&
		!(rules[units[unit_count]].flags & VOWEL)))
		failure = TRUE;
	}
    }

    return (failure);
}


/*
 * Treating y as a vowel is sometimes a problem.  Some words
 * get formed that look irregular.  One special group is when
 * y starts a word and is the only vowel in the first syllable.
 * The word ycl is one example.  We discard words like these.
 */
static boolean have_initial_y (
    register unsigned int *units,
    register unsigned int unit_size
)
{
    register unsigned int unit_count;
    register unsigned int vowel_count;
    register unsigned int normal_vowel_count;

    vowel_count = 0;
    normal_vowel_count = 0;

    for (unit_count = 0; unit_count <= unit_size; unit_count++)
	/*
	 * Count vowels.
	 */
	if (rules[units[unit_count]].flags & VOWEL) {
	    vowel_count++;

	    /*
	     * Count the vowels that are not: 1. y, 2. at the start of
	     * the word.
	     */
	    if (!(rules[units[unit_count]].flags & ALTERNATE_VOWEL)
		|| (unit_count != 0))
		normal_vowel_count++;
	}

    return ((vowel_count <= 1) && (normal_vowel_count == 0));
}


/*
 * Besides the problem with the letter y, there is one with
 * a silent e at the end of words, like face or nice.  We
 * allow this silent e, but we do not allow it as the only
 * vowel at the end of the word or syllables like ble will
 * be generated.
 */
static boolean have_final_split (
    register unsigned int *units,
    register unsigned int unit_size
)
{
    register unsigned int unit_count;
    register unsigned int vowel_count;

    vowel_count = 0;

    /*
     *	  Count all the vowels in the word.
     */
    for (unit_count = 0; unit_count <= unit_size; unit_count++)
	if (rules[units[unit_count]].flags & VOWEL)
	    vowel_count++;

    /*
     * Return TRUE iff the only vowel was e, found at the end if the
     * word.
     */
    return ((vowel_count == 1) &&
	(rules[units[unit_size]].flags & NO_FINAL_SPLIT));
}


/*
 * Generate next unit to password, making sure that it follows
 * these rules:
 *   1. Each syllable must contain exactly 1 or 2 consecutive
 *	vowels, where y is considered a vowel.
 *   2. Syllable end is determined as follows:
 *	  a. Vowel is generated and previous unit is a
 *	     consonant and syllable already has a vowel.  In
 *	     this case, new syllable is started and already
 *	     contains a vowel.
 *	  b. A pair determined to be a "break" pair is encountered.
 *	     In this case new syllable is started with second unit
 *	     of this pair.
 *	  c. End of password is encountered.
 *	  d. "begin" pair is encountered legally.  New syllable is
 *	     started with this pair.
 *	  e. "end" pair is legally encountered.  New syllable has
 *	     nothing yet.
 *   3. Try generating another unit if:
 *	  a. third consecutive vowel and not y.
 *	  b. "break" pair generated but no vowel yet in current
 *	     or previous 2 units are "not_end".
 *	  c. "begin" pair generated but no vowel in syllable
 *	     preceding begin pair, or both previous 2 pairs are
 *	    designated "not_end".
 *	  d. "end" pair generated but no vowel in current syllable
 *	     or in "end" pair.
 *	  e. "not_begin" pair generated but new syllable must
 *	     begin (because previous syllable ended as defined in
 *	     2 above).
 *	  f. vowel is generated and 2a is satisfied, but no syllable
 *	     break is possible in previous 3 pairs.
 *	  g. Second and third units of syllable must begin, and
 *	     first unit is "alternate_vowel".
 */
static char * get_syllable (
    char   *syllable,
    unsigned int  pwlen,
    unsigned int *units_in_syllable,
    unsigned int *syllable_length
)
{
    register unsigned int unit;
    register int  current_unit;
    register unsigned int vowel_count;
    register	boolean rule_broken;
    register	boolean want_vowel;
    register	boolean want_another_unit;
    int unsigned    tries;
    int unsigned  last_unit;
    int   length_left;
    unsigned int  hold_saved_unit;
    static unsigned int   saved_unit;
    static unsigned int   saved_pair[2];

    /*
     * This is needed if the saved_unit is tries and the syllable then
     * discarded because of the retry limit. Since the saved_unit is OK and
     * fits in nicely with the preceding syllable, we will always use it.
     */
    hold_saved_unit = saved_unit;

    /*
     * Loop until valid syllable is found.
     */
    do {
	/*
	 * Try for a new syllable.  Initialize all pertinent
	 * syllable variables.
	 */
	tries = 0;
	saved_unit = hold_saved_unit;
	(void) strcpy(syllable, "");
	vowel_count = 0;
	current_unit = 0;
	length_left = (int) pwlen;
	want_another_unit = TRUE;

	/*
	 * This loop finds all the units for the syllable.
	 */
	do {
	    want_vowel = FALSE;

	    /*
	     * This loop continues until a valid unit is found for the
	     * current position within the syllable.
	     */
	    do {
		/*
		 * If there are saved_unit's from the previous
		 * syllable, use them up first.
		 */
		if (saved_unit != 0) {
		    /*
		     * If there were two saved units, the first is
		     * guaranteed (by checks performed in the previous
		     * syllable) to be valid.  We ignore the checks
		     * and place it in this syllable manually.
		     */
		    if (saved_unit == 2) {
			units_in_syllable[0] = saved_pair[1];
			if (rules[saved_pair[1]].flags & VOWEL)
			    vowel_count++;
			current_unit++;
			(void) strcpy(syllable, rules[saved_pair[1]].unit_code);
			length_left -= strlen(syllable);
		    }

		    /*
		     * The unit becomes the last unit checked in the
		     * previous syllable.
		     */
		    unit = saved_pair[0];

		    /*
		     * The saved units have been used.	Do not try to
		     * reuse them in this syllable (unless this particular
		     * syllable is rejected at which point we start to rebuild
		     * it with these same saved units.
		     */
		    saved_unit = 0;
		} else
		    /*
		     * If we don't have to scoff the saved units,
		     * we generate a random one.  If we know it has
		     * to be a vowel, we get one rather than looping
		     * through until one shows up.
		     */
		    if (want_vowel)
			unit = random_unit(VOWEL);
		    else
			unit = random_unit(NO_SPECIAL_RULE);

		length_left -= (int) strlen(rules[unit].unit_code);

		/*
		 * Prevent having a word longer than expected.
		 */
		if (length_left < 0)
		    rule_broken = TRUE;
		else
		    rule_broken = FALSE;

		/*
		 * First unit of syllable.  This is special because the
		 * digram tests require 2 units and we don't have that yet.
		 * Nevertheless, we can perform some checks.
		 */
		if (current_unit == 0) {
		    /*
		     * If the shouldn't begin a syllable, don't
		     * use it.
		     */
		    if (rules[unit].flags & NOT_BEGIN_SYLLABLE)
			rule_broken = TRUE;
		    else
			/*
			 * If this is the last unit of a word,
		* we have a one unit syllable.	Since each
		* syllable must have a vowel, we make sure
		* the unit is a vowel.	Otherwise, we
		* discard it.
		*/
	       if (length_left == 0)
		   if (rules[unit].flags & VOWEL)
		    want_another_unit = FALSE;
		   else
		    rule_broken = TRUE;
	  }
	  else
	  {
	      /*
	       * There are some digram tests that are
	       * universally true.  We test them out.
	       */

	      /*
	       * Reject ILLEGAL_PAIRS of units.
	       */
	      if ((ALLOWED (ILLEGAL_PAIR)) ||

	      /*
	       * Reject units that will be split between syllables
	       * when the syllable has no vowels in it.
	       */
		   (ALLOWED (BREAK) && (vowel_count == 0)) ||

	      /*
	       * Reject a unit that will end a syllable when no
	       * previous unit was a vowel and neither is this one.
	       */
		   (ALLOWED (END) && (vowel_count == 0) &&
		    !(rules[unit].flags & VOWEL)))
	       rule_broken = TRUE;

	      if (current_unit == 1)
	      {
	       /*
		* Reject the unit if we are at te starting digram of
		* a syllable and it does not fit.
		*/
	       if (ALLOWED (NOT_BEGIN))
		   rule_broken = TRUE;
	      }
	      else
	      {
	       /*
		* We are not at the start of a syllable.
		* Save the previous unit for later tests.
		*/
	       last_unit = units_in_syllable[current_unit - 1];

	       /*
		* Do not allow syllables where the first letter is y
		* and the next pair can begin a syllable.  This may
		* lead to splits where y is left alone in a syllable.
		* Also, the combination does not sound to good even
		* if not split.
		*/
	       if (((current_unit == 2) &&
			(ALLOWED (BEGIN)) &&
			(rules[units_in_syllable[0]].flags &
			 ALTERNATE_VOWEL)) ||

		    /*
		     * If this is the last unit of a word, we should
		     * reject any digram that cannot end a syllable.
		     */
		    (ALLOWED (NOT_END) &&
			(length_left == 0)) ||

		    /*
		     * Reject the unit if the digram it forms wants
		     * to break the syllable, but the resulting
		     * digram that would end the syllable is not
		     * allowed to end a syllable.
		     */
		    (ALLOWED (BREAK) &&
			(digram[units_in_syllable
			     [current_unit - 2]]
			 [last_unit] &
			 NOT_END)) ||

		    /*
		     * Reject the unit if the digram it forms
		     * expects a vowel preceding it and there is
		     * none.
		     */
		    (ALLOWED (PREFIX) &&
			!(rules[units_in_syllable
			     [current_unit - 2]].flags &
			 VOWEL)))
		   rule_broken = TRUE;

	       /*
		* The following checks occur when the current unit
		* is a vowel and we are not looking at a word ending
		* with an e.
		*/
	       if (!rule_broken &&
		    (rules[unit].flags & VOWEL) &&
		    ((length_left > 0) ||
			!(rules[last_unit].flags &
			 NO_FINAL_SPLIT)))

		   /*
		    * Don't allow 3 consecutive vowels in a
		    * syllable.  Although some words formed like this
		    * are OK, like beau, most are not.
		    */
		   if ((vowel_count > 1) &&
			(rules[last_unit].flags & VOWEL))
		    rule_broken = TRUE;
		   else
		    /*
		     * Check for the case of
		     * vowels-consonants-vowel, which is only
		     * legal if the last vowel is an e and we are
		     * the end of the word (wich is not
		     * happening here due to a previous check.
		     */
		    if ((vowel_count != 0) &&
			 !(rules[last_unit].flags & VOWEL))
		    {
			/*
			 * Try to save the vowel for the next
			 * syllable, but if the syllable left here
			 * is not proper (i.e., the resulting last
			 * digram cannot legally end it), just
			 * discard it and try for another.
			 */
			if (digram[units_in_syllable
			      [current_unit - 2]]
			     [last_unit] &
			     NOT_END)
			 rule_broken = TRUE;
			else
			{
			 saved_unit = 1;
			 saved_pair[0] = unit;
			 want_another_unit = FALSE;
			}
		    }
	      }

	      /*
	       * The unit picked and the digram formed are legal.
	       * We now determine if we can end the syllable.  It may,
	       * in some cases, mean the last unit(s) may be deferred to
	       * the next syllable.  We also check here to see if the
	       * digram formed expects a vowel to follow.
	       */
	      if (!rule_broken && want_another_unit)
	      {
	       /*
		* This word ends in a silent e.
		*/
	       if (((vowel_count != 0) &&
			(rules[unit].flags & NO_FINAL_SPLIT) &&
			(length_left == 0) &&
			!(rules[last_unit].flags &
			 VOWEL)) ||

		    /*
		     * This syllable ends either because the digram
		     * is an END pair or we would otherwise exceed
		     * the length of the word.
		     */
		    (ALLOWED (END) || (length_left == 0)))
		   want_another_unit = FALSE;
	       else
		   /*
		    * Since we have a vowel in the syllable
		    * already, if the digram calls for the end of the
		    * syllable, we can legally split it off. We also
		    * make sure that we are not at the end of the
		    * dangerous because that syllable may not have
		    * vowels, or it may not be a legal syllable end,
		    * and the retrying mechanism will loop infinitely
		    * with the same digram.
		    */
		   if ((vowel_count != 0) && (length_left > 0))
		   {
		    /*
		     * If we must begin a syllable, we do so if
		     * the only vowel in THIS syllable is not part
		     * of the digram we are pushing to the next
		     * syllable.
		     */
		    if (ALLOWED (BEGIN) &&
			 (current_unit > 1) &&
			 !((vowel_count == 1) &&
			     (rules[last_unit].flags &
			      VOWEL)))
		    {
			saved_unit = 2;
			saved_pair[0] = unit;
			saved_pair[1] = last_unit;
			want_another_unit = FALSE;
		    }
		    else
			if (ALLOWED (BREAK))
			{
			 saved_unit = 1;
			 saved_pair[0] = unit;
			 want_another_unit = FALSE;
			}
		   }
		   else
		    if (ALLOWED (SUFFIX))
			want_vowel = TRUE;
	      }
	  }

	  tries++;

	  /*
	   * If this unit was illegal, redetermine the amount of
	   * letters left to go in the word.
	   */
	  if (rule_broken)
	      length_left += (int) strlen (rules[unit].unit_code);
	 }
	 while (rule_broken && (tries <= MAX_RETRIES));

	 /*
	  * The unit fit OK.
	  */
	 if (tries <= MAX_RETRIES)
	 {
	  /*
	   * If the unit were a vowel, count it in.
	   * However, if the unit were a y and appear
	   * at the start of the syllable, treat it
	   * like a constant (so that words like year can
	   * appear and not conflict with the 3 consecutive
	   * vowel rule.
	   */
	  if ((rules[unit].flags & VOWEL) &&
	       ((current_unit > 0) ||
		   !(rules[unit].flags & ALTERNATE_VOWEL)))
	      vowel_count++;

	  /*
	   * If a unit or units were to be saved, we must
	   * adjust the syllable formed.  Otherwise, we
	   * append the current unit to the syllable.
	   */
	  switch (saved_unit)
	  {
	      case 0:
	       units_in_syllable[current_unit] = unit;
	       (void) strcat (syllable, rules[unit].unit_code);
	       break;
	      case 1:
	       current_unit--;
	       break;
	      case 2:
	       (void) strcpy (&syllable[strlen (syllable) -
			strlen (rules[last_unit].
			 unit_code)],
		    "");
	       length_left += (int) strlen (rules[last_unit].unit_code);
	       current_unit -= 2;
	       break;
	  }
	 }
	 else
	 /*
	  * Whoops!  Too many tries.  We set rule_broken so we can
	  * loop in the outer loop and try another syllable.
	  */
	  rule_broken = TRUE;

	 /*
	  * ...and the syllable length grows.
	  */
	 *syllable_length = current_unit;

	 current_unit++;
     }
     while ((tries <= MAX_RETRIES) && want_another_unit);
    }
    while (rule_broken ||
	 illegal_placement (units_in_syllable, *syllable_length));

    return (syllable);
}


/*
 * This routine goes through an individual syllable and checks
 * for illegal combinations of letters that go beyond looking
 * at digrams.	We look at things like 3 consecutive vowels or
 * consonants, or syllables with consonants between vowels (unless
 * one of them is the final silent e).
 */
static boolean illegal_placement (
    register unsigned int *units,
    register unsigned int pwlen
)
{
    register unsigned int vowel_count;
    register unsigned int unit_count;
    register boolean failure;

    vowel_count = 0;
    failure = FALSE;

    for (unit_count = 0; !failure && (unit_count <= pwlen);
	unit_count++) {
	if (unit_count >= 1) {
	    /*
	     * Don't allow vowels to be split with consonants in
	     * a single syllable.  If we find such a combination
	     * (except for the silent e) we have to discard the
	     * syllable).
	     */
	    if ((!(rules[units[unit_count - 1]].flags & VOWEL) &&
		 (rules[units[unit_count]].flags & VOWEL) &&
		 !((rules[units[unit_count]].flags &
		 NO_FINAL_SPLIT) &&
		 (unit_count == pwlen)) &&
		 (vowel_count != 0)) ||

	    /*
	     * Perform these checks when we have at least 3 units.
	     */
		((unit_count >= 2) &&

	    /*
	     * Disallow 3 consecutive consonants.
	     */
		((!(rules[units[unit_count - 2]].flags & VOWEL) &&
		  !(rules[units[unit_count - 1]].flags &
		  VOWEL) &&
		  !(rules[units[unit_count]].flags &
		  VOWEL)) ||

	    /*
	     * Disallow 3 consecutive vowels, where the first is
	     * not a y.
	     */
		(((rules[units[unit_count - 2]].flags &
		  VOWEL) &&
		  !((rules[units[0]].flags &
		  ALTERNATE_VOWEL) &&
		  (unit_count == 2))) &&
		  (rules[units[unit_count - 1]].flags &
		  VOWEL) &&
		  (rules[units[unit_count]].flags &
		  VOWEL)))))

		failure = TRUE;
	}

	/*
	 * Count the vowels in the syllable.  As mentioned somewhere
	 * above, exclude the initial y of a syllable.	Instead,
	 * treat it as a consonant.
	 */
	if ((rules[units[unit_count]].flags & VOWEL) &&
	    !((rules[units[0]].flags & ALTERNATE_VOWEL) &&
	    (unit_count == 0) && (pwlen != 0)))

	    vowel_count++;
    }

    return (failure);
}



/*
 * This is the standard random unit generating routine for
 * get_syllable().  It does not reference the digrams, but
 * assumes that it contains 34 units in a particular order.
 * This routine attempts to return unit indexes with a distribution
 * approaching that of the distribution of the 34 units in
 * English.  In order to do this, a random number (supposedly
 * uniformly distributed) is used to do a table lookup into an
 * array containing unit indices.  There are 211 entries in
 * the array for the random_unit entry point.  The probability
 * of a particular unit being generated is equal to the
 * fraction of those 211 entries that contain that unit index.
 * For example, the letter `a' is unit number 1.  Since unit
 * index 1 appears 10 times in the array, the probability of
 * selecting an `a' is 10/211.
 *
 * Changes may be made to the digram table without affect to this
 * procedure providing the letter-to-number correspondence of
 * the units does not change.  Likewise, the distribution of the
 * 34 units may be altered (and the array size may be changed)
 * in this procedure without affecting the digram table or any other
 * programs using the random_word subroutine.
 */
static unsigned int  numbers[] =
{
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    1, 1, 1, 1, 1, 1, 1, 1,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
    5, 5, 5, 5, 5, 5, 5, 5,
    6, 6, 6, 6, 6, 6, 6, 6,
    7, 7, 7, 7, 7, 7,
    8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
    9, 9, 9, 9, 9, 9, 9, 9,
    10, 10, 10, 10, 10, 10, 10, 10,
    11, 11, 11, 11, 11, 11,
    12, 12, 12, 12, 12, 12,
    13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
    14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
    15, 15, 15, 15, 15, 15,
    16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
    17, 17, 17, 17, 17, 17, 17, 17,
    18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
    19, 19, 19, 19, 19, 19,
    20, 20, 20, 20, 20, 20, 20, 20,
    21, 21, 21, 21, 21, 21, 21, 21,
    22,
    23, 23, 23, 23, 23, 23, 23, 23,
    24,
    25,
    26,
    27,
    28,
    29, 29,
    30,
    31,
    32,
    33
};


/*
 * This structure has a typical English frequency of vowels.
 * The value of an entry is the vowel position (a=0, e=4, i=8,
 * o=14, u=19, y=23) in the rules array.  The number of times
 * the value appears is the frequency.	Thus, the letter "a"
 * is assumed to appear 2/12 = 1/6 of the time.  This array
 * may be altered if better data is obtained.  The routines that
 * use vowel_numbers will adjust to the size difference automatically.
 */
static unsigned int  vowel_numbers[] =
{
    0, 0, 4, 4, 4, 8, 8, 14, 14, 19, 19, 23
};


/*
 * Select a unit (a letter or a consonant group).  If a vowel is
 * expected, use the vowel_numbers array rather than looping through
 * the numbers array until a vowel is found.
 */
static unsigned int random_unit (
    register unsigned int type
)
{
    register unsigned int number;

    /*
     * Sometimes, we are asked to explicitly get a vowel (i.e., if
     * a digram pair expects one following it).  This is a shortcut
     * to do that and avoid looping with rejected consonants.
     */
    if (type & VOWEL)
	number = vowel_numbers[get_random (0, sizeof (vowel_numbers) / sizeof (unsigned int))];
    else
	/*
	 * Get any letter according to the English distribution.
	 */
	number = numbers[get_random (0, sizeof (numbers) / sizeof (unsigned int))];
    return (number);
}


/*
 * This routine should return a uniformly distributed random number between
 * minlen and maxlen inclusive.
*/

static unsigned int get_random (
    register unsigned int  minlen,
    register unsigned int  maxlen
)
{
    return minlen + (unsigned int) randint ((int) (maxlen - minlen + 1));
}


/*
 * Produces a random number from 0 to n-1 .
 */
static unsigned int randint (
    int n
)
{
    error_status_t   status;
    sec_passwd_rec_t *pwd;
    sec_passwd_type_t keytype = sec_passwd_des;
    int randnum;

    sec_key_mgmt_gen_rand_key(rpc_c_authn_dce_secret, NULL, NULL,
	(void *)&keytype , 0, (void **)&pwd, &status);

    /* XXX Check error? */

    /* convert within range */
    randnum = answer(pwd->key.tagged_union.des_key, n);
    sec_key_mgmt_free_key(pwd, &status);
    return(randnum);
}

/* answer takes the array out and creates variable sum by adding
   certain values within the array together.  To get a number from 0 to
   n-1, it returns sum mod n (sum%n) */

static int answer (
    unsigned char *out,
    int n
)
{
    unsigned int sum;

    /*
     * every time this function is called, it adds the first
     * three positions of out to get sum.
     */

    sum = out[0] + out[1] +out[2];
    return (sum%n);
}

/* Set the seed.  This routine will only set the seed once, even if
 * called from multiple sources.
 */
static void set_seed (
    long seed
)
{
#ifdef IBMOS2
/* OS/2 does not support rand48 functions */
    srand(seed);
#else
    srand48(seed);
#endif /* IBMOS2 */
}
