ISXDDataEssenceDescriptor_NamespaceURI UL fixed
[asdcplib.git] / src / kmrandgen.cpp
1 /*
2 Copyright (c) 2005-2018, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27   /*! \file    kmrandgen.cpp
28     \version $Id$
29     \brief   psuedo-random number generation utility
30   */
31
32 #include "AS_DCP.h"
33 #include <KM_fileio.h>
34 #include <KM_prng.h>
35 #include <ctype.h>
36
37 using namespace Kumu;
38
39 const ui32_t RandBlockSize = 16;
40 const char* PROGRAM_NAME = "kmrandgen";
41
42 // Increment the iterator, test for an additional non-option command line argument.
43 // Causes the caller to return if there are no remaining arguments or if the next
44 // argument begins with '-'.
45 #define TEST_EXTRA_ARG(i,c)    if ( ++i >= argc || argv[(i)][0] == '-' ) \
46                                  { \
47                                    fprintf(stderr, "Argument not found for option -%c.\n", (c)); \
48                                    return; \
49                                  }
50
51 static const char* _letterwords_list[] = {
52   "Alfa", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf",
53   "Hotel", "India", "Juliett", "Kilo",
54   "Lima", "Mike", "November", "Oscar", "Papa",
55   "Quebec", "Romeo", "Sierra",
56   "Tango", "Uniform", "Victor",
57   "Whiskey", "X-ray",
58   "Yankee", "Zulu"
59 };
60
61
62 static const char* _word_list[] = {
63   "ABED", "ABET", "ABEY", "ABLE", "ABUT",  "ACE", "ACHE", "ACID", 
64   "ACME", "ACRE",  "ACT", "ACTS",  "ADD", "ADDS",  "ADO", "ADRY", 
65   "AEON", "AERO", "AFAR", "AFRO", "AGAR",  "AGE", "AGED", "AGIO", 
66   "AGO" , "AHEM", "AHOY",  "AID", "AIDE",  "AIL",  "AIM",  "AIR", 
67   "AIRY", "AJAR", "AKIN", "ALAS", "ALCO",  "ALE",  "ALF", "ALFA", 
68   "ALL" , "ALLY", "ALMA", "ALMS", "ALOE", "ALOW", "ALSO",  "ALT", 
69   "ALTO", "ALUM",   "AM", "AMES", "AMID",   "AN",  "AND", "ANEW", 
70   "ANT" , "ANTE",  "ANY",  "APE", "APEX",  "APT", "AQUA",  "ARC", 
71   "ARCH",  "ARE", "AREA", "ARGO", "ARID",  "ARK",  "ARM", "ARMS", 
72   "ART" , "ARTS", "ARTY",   "AS",  "ASH",  "ASK", "ASKS",  "ASP", 
73   "AT"  ,  "ATE", "ATOM", "ATOP", "AUNT", "AURA", "AUTO", "AVER", 
74   "AVID", "AVOW", "AWAY",  "AWE",  "AWL",  "AXE", "AXED", "AXES", 
75   "AXIS", "AXLE", "AXON",  "AYE", "BABE", "BABU", "BABY", "BACK", 
76   "BAD" , "BADE",  "BAG", "BAIL", "BAIT", "BAKE", "BALD", "BALE", 
77   "BALK", "BALL", "BALM",  "BAM",  "BAN", "BAND", "BANE", "BANG", 
78   "BANK",  "BAR", "BARB", "BARD", "BARE", "BARK", "BARM", "BARN", 
79   "BARU", "BASE", "BASH", "BASK", "BASS",  "BAT", "BATH", "BATS", 
80   "BAWL",  "BAY",   "BE", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", 
81   "BEAT", "BEAU", "BECK",  "BED",  "BEE", "BEEF", "BEEK", "BEEN", 
82   "BEER", "BEES", "BEET",  "BEG", "BELL", "BELT", "BEND", "BENT", 
83   "BERG", "BERM", "BEST",  "BET", "BETA", "BIAS",  "BIB",  "BID", 
84   "BIDE", "BIER",  "BIG", "BIKE", "BILE", "BILK", "BILL",  "BIN", 
85   "BIND", "BING", "BIOS", "BIRD",  "BIT", "BITE", "BITS",  "BIZ", 
86   "BLAB", "BLED", "BLOB", "BLOC", "BLOK", "BLOT", "BLUE", "BLUR", 
87   "BOA" , "BOAR", "BOAT",  "BOB", "BOCE", "BOCK", "BODE", "BODY", 
88   "BOG" , "BOIL", "BOLD", "BOLO", "BOLT", "BOND", "BONE", "BONY", 
89   "BOO" , "BOOK", "BOOL", "BOOM", "BOON", "BOOR", "BOOT", "BORE", 
90   "BORG", "BORN", "BOSS", "BOTH", "BOUT",  "BOW", "BOWL", "BOXY", 
91   "BOY" , "BRAG", "BRAN", "BRAT", "BRAY", "BRED", "BREW", "BRIE", 
92   "BRIG", "BRIM", "BRIT", "BROW", "BUCK",  "BUD", "BUFF",  "BUG", 
93   "BULB", "BULK", "BULL", "BUMP",  "BUN", "BUNK", "BUNT", "BUOY", 
94   "BUR" , "BURG", "BURL", "BURN", "BURP", "BURR", "BURY",  "BUS", 
95   "BUSH", "BUSK", "BUSS", "BUSY",  "BUT",  "BUY",   "BY",  "BYE", 
96   "BYTE",  "CAB",  "CAD", "CAFE", "CAGE", "CAIN", "CAKE",  "CAL", 
97   "CALF", "CALL", "CALM",  "CAM", "CAMP",  "CAN", "CANE", "CANT", 
98   "CAP" , "CAPE",  "CAR", "CARD", "CARE", "CARP", "CART", "CASE", 
99   "CASH", "CASK", "CAST",  "CAT", "CAVE", "CEDE", "CEIL", "CELL", 
100   "CENT", "CHAP", "CHAT", "CHEF", "CHEW", "CHIC", "CHIN", "CHIP", 
101   "CHIT", "CHOP", "CHOW", "CHUG", "CHUM", "CINE", "CITE", "CITY", 
102   "CLAD", "CLAM", "CLAN", "CLAP", "CLAW", "CLAY", "CLEF", "CLIP", 
103   "CLOD", "CLOG", "CLOT", "CLOY", "CLUB", "CLUE", "COAL", "COAT", 
104   "COAX",  "COB",  "COD", "CODA", "CODE",  "COG", "COIL", "COIN", 
105   "COKE", "COLA", "COLD", "COLE", "COLT", "COMB", "COOK", "COOL", 
106   "COP" , "COPE", "COPY", "CORD", "CORE", "CORK", "CORN", "CORP", 
107   "COST", "COSY",  "COT", "COUP", "COVE",  "COW", "COWL",  "COY", 
108   "COZY", "CRAB", "CRAG", "CRAM", "CRAW", "CRAY", "CREW", "CRIB", 
109   "CROC", "CROP", "CROW", "CRUX",  "CRY",  "CUB", "CUBE",  "CUE", 
110   "CUFF",  "CUP",  "CUR", "CURB", "CURD", "CURE", "CURL", "CURT", 
111   "CUT" , "CUTE", "CYAN", "CYST", "CZAR",  "DAB",  "DAD", "DADA", 
112   "DADO", "DAIS", "DALE", "DALI",  "DAM", "DAME", "DAMP", "DARE", 
113   "DARK", "DARN", "DART", "DASH", "DATA", "DATE", "DAUB", "DAWN", 
114   "DAY" , "DAYS", "DAZE", "DAZY", "DEAL", "DEAR", "DEBT", "DECK", 
115   "DEED", "DEEM", "DEER", "DEFT", "DEFY", "DELI", "DELL", "DEMO", 
116   "DEN" , "DENT", "DENY", "DESK",  "DEW", "DIAL", "DIBS", "DICE", 
117   "DID" ,  "DIG", "DIGS", "DILL",  "DIM", "DIME",  "DIN", "DINE", 
118   "DIP" , "DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE",   "DO", 
119   "DOCK",  "DOE", "DOES",  "DOG", "DOGS", "DOLE", "DOLL", "DOME", 
120   "DON" , "DONE", "DOOM", "DOOR", "DORM", "DOSE",  "DOT", "DOTE", 
121   "DOUR", "DOVE", "DOWN", "DOZE", "DRAB", "DRAG", "DRAM", "DRAT", 
122   "DRAW", "DREW", "DRIB", "DRIP", "DROP", "DRUB", "DRUM",  "DRY", 
123   "DUAL",  "DUB", "DUBS", "DUCK", "DUCT",  "DUD",  "DUE", "DUET", 
124   "DUG" , "DUKE", "DULL", "DULY", "DUMP", "DUNE", "DUNK", "DUPE", 
125   "DUSK", "DUST", "DUTY", "DYAD", "EACH",  "EAR", "EARL", "EARN", 
126   "EASE", "EAST", "EASY",  "EAT", "EATS",  "EBB", "ECHO", "EDDY", 
127   "EDGE", "EDGY", "EDIT",  "EEL",  "EGG",  "EGO",  "ELF",  "ELK", 
128   "ELM" , "ELSE", "EMIT",  "END", "ENDS", "ENSE", "ENVY", "EPIC", 
129   "ERA" ,  "ERG",  "EVE", "EVEN", "EVER",  "EWE", "EXAM", "EXIT", 
130   "EYE" , "EYED", "FACE", "FACT",  "FAD", "FADE", "FADY", "FAIL", 
131   "FAIR", "FAKE", "FALL", "FAME",  "FAN", "FANG",  "FAR", "FARE", 
132   "FARM", "FAST", "FATE", "FAWN", "FAZE", "FEAR", "FEAT",  "FED", 
133   "FEE" , "FEED", "FEEL", "FEET", "FELL", "FELT", "FEND", "FERN", 
134   "FEST", "FEUD",  "FEW",  "FEZ", "FIAT",  "FIB", "FIFE",  "FIG", 
135   "FIGS", "FILE", "FILL", "FILM",  "FIN", "FIND", "FINE", "FINK", 
136   "FIR" , "FIRE", "FIRM", "FISH",  "FIT", "FITS", "FIVE",  "FIX", 
137   "FLAG", "FLAK", "FLAP", "FLAT", "FLAW", "FLAX", "FLED", "FLEE", 
138   "FLEW", "FLEX", "FLIP", "FLIT", "FLOE", "FLOG", "FLOP", "FLOW", 
139   "FLU" , "FLUB", "FLUE", "FLUX",  "FLY", "FOAL", "FOAM",  "FOE", 
140   "FOG" , "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", 
141   "FOOT", "FORD", "FORE", "FORK", "FORM", "FORT", "FOUL", "FOUR", 
142   "FOW" , "FOWL",  "FOX", "FRAY", "FRED", "FREE", "FRET", "FROG", 
143   "FROM",  "FRY", "FUEL", "FUGU", "FULL", "FUME",  "FUN", "FUND", 
144   "FUNK",  "FUR", "FURY", "FUSE", "FUSS", "FUZZ",  "GAB",  "GAG", 
145   "GAGE", "GAIN", "GAIT",  "GAL", "GALA", "GALE", "GALL", "GAME", 
146   "GAMY", "GANG",  "GAP", "GARB",  "GAS", "GASP", "GATE", "GAVE", 
147   "GAWK", "GAZE", "GEAR", "GEEK",  "GEL",  "GEM", "GENE", "GENT", 
148   "GERM",  "GET", "GETS", "GIFT",  "GIG", "GILD", "GILL", "GILT", 
149   "GIN" , "GIRD", "GIRL", "GIST",  "GIT", "GIVE", "GLAD", "GLAM", 
150   "GLEE", "GLEN", "GLIB", "GLOB", "GLOM", "GLOP", "GLOW", "GLUE", 
151   "GLUG", "GLUM", "GLUT", "GNAT", "GNAW",  "GNU",   "GO", "GOAD", 
152   "GOAL", "GOAT",  "GOB", "GOBO", "GOES", "GOLD", "GOLF", "GONE", 
153   "GONG",  "GOO", "GOOD", "GOOF", "GOON", "GOSH",  "GOT", "GOWN", 
154   "GRAB", "GRAD", "GRAM", "GRAY", "GREW", "GREY", "GRID", "GRIM", 
155   "GRIN", "GRIP", "GRIT", "GROG", "GROW", "GRUB", "GRUE", "GULF", 
156   "GULL", "GULP",  "GUM", "GUNK", "GURU", "GUSH", "GUST",  "GUT", 
157   "GUY" ,  "GYM", "HACK",  "HAD",  "HAH", "HAIL", "HAIR", "HALE", 
158   "HALF", "HALL", "HALO", "HALT",  "HAM", "HAND", "HANG", "HANK", 
159   "HARD", "HARE", "HARK", "HARM", "HARP",  "HAS", "HASH", "HASP", 
160   "HAT" , "HATH", "HAUL", "HAVE", "HAWK",  "HAY", "HAZE", "HAZY", 
161   "HE"  , "HEAL", "HEAP", "HEAR", "HEAT", "HECK", "HEED", "HEEL", 
162   "HEFT", "HEIR", "HELD", "HELM", "HELP",  "HEM", "HEMP",  "HEN", 
163   "HER" , "HERB", "HERD", "HERE", "HERO", "HERS",  "HEW", "HEWN", 
164   "HEX" ,  "HEY",   "HI",  "HID", "HIDE", "HIGH", "HIKE", "HILL", 
165   "HILT",  "HIM", "HIND", "HINT",  "HIP", "HIRE",  "HIS", "HISS", 
166   "HIT" , "HIVE", "HOAX", "HOCK",  "HOE",  "HOG", "HOLD", "HOLE", 
167   "HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK", "HOOP", "HOOT", 
168   "HOP" , "HOPE", "HORN", "HOSE", "HOST",  "HOT", "HOUR",  "HOW", 
169   "HOWL",  "HUB",  "HUE", "HUED", "HUFF",  "HUG", "HUGE",  "HUH", 
170   "HULK", "HULL",  "HUM", "HUNK", "HUNT", "HURL", "HURT", "HUSH", 
171   "HUSK",  "HUT", "HYMN", "HYPO",  "ICE", "ICON",  "ICY",   "ID", 
172   "IDEA", "IDES", "IDLE", "IDLY", "IDOL",   "IF", "IFFY",  "ILK", 
173   "ILL" ,  "IMP",   "IN", "INCH", "INDY",  "INK",  "INN", "INTO", 
174   "ION" , "IONS", "IOTA", "IRIS", "IRON",   "IS", "ISLE",   "IT", 
175   "ITEM",  "IVY", "JADE",  "JAG",  "JAM",  "JAR", "JAVA",  "JAW", 
176   "JAZZ", "JEDI", "JEEP", "JEST",  "JET",  "JIB",  "JIG", "JILT", 
177   "JIVE",  "JOB", "JOBS",  "JOG", "JOIN", "JOKE", "JOLT",  "JOT", 
178   "JUDO",  "JUG", "JULY", "JUMP", "JUNE", "JUNK", "JURY", "JUST", 
179   "JUT" , "KAHN", "KALE", "KANE", "KEEL", "KEEN", "KEEP",  "KEG", 
180   "KELP", "KENO", "KEPT", "KERF", "KERN",  "KEY", "KEYS", "KHAN", 
181   "KICK",  "KID", "KILN", "KILO", "KILT",  "KIN", "KIND", "KING", 
182   "KINO",  "KIT", "KITE", "KNEE", "KNEW", "KNIT", "KNOT", "KNOW", 
183   "KOI" ,  "LAB", "LACE", "LACK",  "LAD", "LADY",  "LAG", "LAIR", 
184   "LAKE",  "LAM", "LAMB", "LAME", "LAMP", "LAND", "LANE",  "LAP", 
185   "LARD", "LARK", "LASH", "LASS", "LAST", "LATE", "LAUD", "LAVA", 
186   "LAW" , "LAWN", "LAWS",  "LAX",  "LAY", "LAZY", "LEAD", "LEAF", 
187   "LEAK", "LEAN", "LEAP",  "LED", "LEDE", "LEED", "LEEK", "LEFT", 
188   "LEG" , "LEND", "LENS", "LENT", "LESS", "LEST",  "LET", "LETS", 
189   "LIAR",  "LID", "LIEN", "LIEU", "LIFE", "LIFO", "LIFT", "LIKE", 
190   "LILT", "LILY", "LIMA", "LIME", "LINE", "LINK", "LINT", "LION", 
191   "LIP" , "LIST",  "LIT", "LIVE", "LOAD", "LOAF", "LOAN",  "LOB", 
192   "LOBE", "LOCK", "LODE", "LOFT",  "LOG", "LOGE", "LOIN", "LONE", 
193   "LONG", "LOOK", "LOON", "LOOP", "LOOT", "LORE", "LOSE", "LOSS", 
194   "LOST",  "LOT", "LOTS", "LOUD", "LOVE",  "LOW",  "LOX", "LUCK", 
195   "LUG" , "LULL", "LUMP", "LUSH", "LUTE",  "LUX",  "LYE", "LYNX", 
196   "MAD" , "MADE", "MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALL", 
197   "MALT",  "MAN", "MANY",  "MAP", "MARE", "MARK", "MART", "MASH", 
198   "MASK", "MASS", "MAST",  "MAT", "MATE", "MATH", "MAUL",  "MAW", 
199   "MAY" , "MAZE",   "ME", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", 
200   "MEET", "MELD", "MELT", "MEME", "MEMO",  "MEN", "MEND", "MENU", 
201   "MERE", "MESH", "MESS",  "MET", "MICA", "MICE",  "MID", "MIKE", 
202   "MILD", "MILE", "MILK", "MILL", "MIME", "MIND", "MINE", "MINK", 
203   "MINT", "MIRE", "MISS", "MIST", "MITE", "MITT",  "MIX", "MOAT", 
204   "MOB" , "MOCK",  "MOD", "MODE", "MOLD", "MOLE", "MOLT", "MONK", 
205   "MONO", "MOOD", "MOON", "MOOT",  "MOP", "MOPE", "MORE", "MORN", 
206   "MOSS", "MOST", "MOTE", "MOTH", "MOVE",  "MOW", "MOWN", "MUCH", 
207   "MUCK",  "MUD",  "MUG", "MULE", "MULL", "MULT",  "MUM", "MUMP", 
208   "MURK", "MUSE", "MUSH", "MUSK", "MUSS", "MUST", "MUTE", "MUTT", 
209   "MY"  , "MYTH",  "NAB",  "NAG", "NAIF", "NAIL", "NAME",  "NAP", 
210   "NAPE", "NARY", "NEAR", "NEAT",  "NEE", "NEED", "NEON", "NEST", 
211   "NET" ,  "NEW", "NEWS", "NEWT", "NEXT",  "NIB", "NIBS", "NICE", 
212   "NICK",  "NIL", "NINE",  "NIX",   "NO",  "NOD", "NODE", "NONE", 
213   "NOOK", "NOON", "NOPE",  "NOR", "NORI", "NORM", "NOSE", "NOSY", 
214   "NOT" , "NOTE", "NOUN", "NOVA",  "NOW", "NULL", "NUMB",  "NUN", 
215   "OAK" ,  "OAR",  "OAT", "OATH", "OBOE",  "ODD", "ODDS",  "ODE", 
216   "OF"  ,  "OFF",  "OFT", "OGRE",   "OH", "OHIO",  "OHM",  "OIL", 
217   "OILY",   "OK", "OKAY", "OKRA",  "OLD", "OMEN", "OMIT",   "ON", 
218   "ONCE",  "ONE", "ONES", "ONLY", "ONTO", "ONUS", "ONYX", "OPAL", 
219   "OPEN",  "OPT", "OPUS",   "OR",  "ORB",  "ORC",  "ORE", "OUCH", 
220   "OUR" , "OURS", "OUST",  "OUT", "OUTS", "OVAL", "OVEN", "OVER", 
221   "OWE" ,  "OWL",  "OWN", "OWNS",   "OX", "PACK", "PACT",  "PAD", 
222   "PAGE", "PAIL", "PAIN", "PAIR",  "PAL", "PALE", "PALL", "PALM", 
223   "PAN" , "PANE", "PAPA",  "PAR", "PARK", "PART", "PASS", "PAST", 
224   "PAT" , "PATE", "PATH", "PAVE",  "PAW", "PAWN",  "PAX",  "PAY", 
225   "PEA" , "PEAK", "PEAL", "PEAR", "PEAT", "PECK", "PEEL", "PEEN", 
226   "PEER", "PELT",  "PEN", "PEND", "PENT",  "PEP",  "PER", "PERK", 
227   "PEST",  "PET",  "PEW",  "PHI",   "PI", "PICK",  "PIE", "PIER", 
228   "PIG" , "PIKE", "PILE", "PILL",  "PIN", "PINE", "PING", "PINT", 
229   "PIPE",  "PIT", "PITY", "PLAN", "PLAY", "PLEA", "PLED", "PLOD", 
230   "PLOP", "PLOT", "PLOW", "PLOY", "PLUG", "PLUM", "PLUS",  "PLY", 
231   "POD" , "POEM", "POET", "POKE", "POLE", "POLL", "POLO", "POMP", 
232   "POND", "PONY", "POOF", "POOL", "POOR",  "POP", "PORE", "PORK", 
233   "PORT", "POSE", "POSH", "POST",  "POT", "POUR",  "POW",  "POX", 
234   "POXY", "PRAM", "PRAT", "PRAY", "PREP", "PREY", "PRIG", "PRIM", 
235   "PROP",  "PRY",  "PUB", "PUCE", "PUCK", "PUFF",  "PUG", "PULL", 
236   "PULP", "PUMP",  "PUN", "PUNK", "PUNT", "PUNY",  "PUP", "PURE", 
237   "PURR", "PUSH",  "PUT", "PUTT", "QUAD", "QUIP", "QUIT", "QUIZ", 
238   "QUO" , "RACE", "RAFT", "RAID", "RAIL", "RAIN", "RAKE",  "RAM", 
239   "RAMP",  "RAN", "RANG", "RANK",  "RAP", "RAPT", "RARE", "RASH", 
240   "RASP",  "RAT", "RATE", "RATH", "RAVE",  "RAW",  "RAY", "RAZE", 
241   "RAZZ", "READ", "REAK", "REAL", "REAM", "REAP", "REAR",  "RED", 
242   "REDO", "REED", "REEF", "REEL", "REIN", "REND", "RENT", "REST", 
243   "REV" ,  "RIB", "RICE", "RICH", "RICK",  "RID", "RIDE", "RIFE", 
244   "RIFF", "RIFT",  "RIG", "RILE",  "RIM", "RIND", "RING", "RINK", 
245   "RIOT",  "RIP", "RIPE", "RISE", "RISK", "RITE", "ROAD", "ROAM", 
246   "ROAR", "ROBE", "ROCK",  "ROD", "RODE",  "ROE", "ROIL", "ROLL", 
247   "ROME", "ROOF", "ROOM", "ROOT", "ROPE", "ROSE", "ROSY",  "ROT", 
248   "ROUT", "ROVE",  "ROW", "ROWS",  "RUB", "RUBY",  "RUG", "RUIN", 
249   "RULE",  "RUM",  "RUN", "RUNE", "RUNG", "RUNS", "RUNT", "RUSE", 
250   "RUSH", "RUST",  "RUT",  "RYE", "SACK",  "SAD", "SAFE", "SAGA", 
251   "SAGE", "SAID", "SAIL", "SAKE", "SALE", "SALT", "SAME", "SAND", 
252   "SANE", "SANG", "SANK", "SANS",  "SAP", "SASH",  "SAT", "SATE", 
253   "SAVE",  "SAW", "SAWN",  "SAX",  "SAY", "SAYS", "SCAD", "SCAM", 
254   "SCAN", "SCAR", "SCUM",  "SEA", "SEAL", "SEAM", "SEAR", "SEAT", 
255   "SEE" , "SEED", "SEEK", "SEEM", "SEEN", "SEEP", "SEES", "SELF", 
256   "SELL", "SEND", "SENT",  "SET", "SETS",  "SEW", "SEWN", "SHAW", 
257   "SHE" , "SHED", "SHIM", "SHIN", "SHIP", "SHOD", "SHOE", "SHOO", 
258   "SHOP", "SHOT", "SHOW", "SHUN", "SHUT",  "SHY",  "SIC", "SICK", 
259   "SIDE", "SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", 
260   "SIN" , "SINE", "SING", "SINK",  "SIR", "SIRE",  "SIS",  "SIT", 
261   "SITE", "SITH", "SITS", "SITU",  "SIX", "SIZE", "SKEW",  "SKI", 
262   "SKID", "SKIM", "SKIN", "SKIP", "SKIT",  "SKY", "SLAB", "SLAG", 
263   "SLAM", "SLAP", "SLAT", "SLAW", "SLAY", "SLED", "SLEW", "SLID", 
264   "SLIM", "SLIP", "SLOG", "SLOP", "SLOT", "SLOW", "SLUG", "SLUM", 
265   "SLUR",  "SLY", "SMOG", "SMUG", "SNAG", "SNAP", "SNOB", "SNOT", 
266   "SNOW", "SNUB", "SNUG",   "SO", "SOAK", "SOAP", "SOAR",  "SOB", 
267   "SOCK",  "SOD", "SODA", "SOFA", "SOFT", "SOHO", "SOIL", "SOLD", 
268   "SOLE", "SOLO", "SOME",  "SON", "SONG", "SONS", "SOON", "SOOT", 
269   "SOP" , "SOPE", "SORE", "SORT", "SORY", "SOUL", "SOUP", "SOUR", 
270   "SOW" , "SOWN",  "SOY",  "SPA", "SPAN", "SPAR", "SPAT", "SPAY", 
271   "SPEC", "SPED", "SPEW", "SPIN", "SPIT", "SPOT", "SPRY", "SPUD", 
272   "SPUR",  "SPY", "STAB", "STAG", "STAR", "STAY", "STEM", "STEP", 
273   "STEW", "STIM", "STIR", "STOP", "STOW", "STUB", "STUD", "STUN", 
274   "SUB" , "SUCH", "SUDS",  "SUE", "SUET", "SUIT", "SULK",  "SUM", 
275   "SUMP", "SUMS",  "SUN", "SUNG", "SUNK", "SURE", "SURF", "SWAB", 
276   "SWAD", "SWAG", "SWAM", "SWAN", "SWAP", "SWAT", "SWAY", "SWIG", 
277   "SWIM", "SWUM", "SYNC",  "TAB", "TACK", "TACT",  "TAD",  "TAG", 
278   "TAIL", "TAKE", "TALC", "TALE", "TALK", "TALL", "TAME", "TAMP", 
279   "TAN" , "TANG", "TANK",  "TAP", "TAPE", "TAPS",  "TAR", "TARE", 
280   "TARP", "TART", "TASK", "TAUT",  "TAX", "TAXI",  "TEA", "TEAK", 
281   "TEAL", "TEAM", "TEAR", "TECH",  "TEE", "TEEM", "TEEN", "TELL", 
282   "TEMP",  "TEN", "TEND", "TENT", "TERM", "TEST", "TEXT", "THAN", 
283   "THAT", "THAW",  "THE", "THEE", "THEM", "THEN", "THEY", "THIN", 
284   "THIS", "THOU", "THOW", "THUD",  "THY",  "TIC", "TICK", "TIDE", 
285   "TIDY",  "TIE", "TIED", "TIER", "TIFF", "TILE", "TILL", "TILT", 
286   "TIME",  "TIN", "TINE", "TINT", "TINY",  "TIP", "TIRE",   "TO", 
287   "TOAD",  "TOE", "TOFU",  "TOG", "TOGA", "TOGS", "TOIL", "TOKE", 
288   "TOLD", "TOLE", "TOLL", "TOMB",  "TON", "TONE", "TONG", "TONY", 
289   "TOO" , "TOOK", "TOOL", "TOOT",  "TOP", "TOPS", "TORE", "TORN", 
290   "TORT", "TOTE", "TOTO", "TOUR", "TOUT",  "TOW", "TOWN",  "TOY", 
291   "TRAM", "TRAP", "TRAY", "TREE", "TREK", "TRIM", "TRIO", "TROD", 
292   "TROT", "TRUE",  "TRY",  "TUB", "TUBA", "TUBE", "TUCK", "TUFT", 
293   "TUG" , "TULE", "TUNA", "TUNE", "TURF", "TURN", "TUSK",  "TUT", 
294   "TUTU",  "TUX", "TWAS", "TWEE", "TWIG", "TWIN", "TWIT",  "TWO", 
295   "TYPE", "TYPO", "UGLY", "UNDO", "UNIT", "UNTO",   "UP", "UPON", 
296   "URGE",  "URN",   "US",  "USE", "USED", "USER", "USES", "VAIN", 
297   "VALE",  "VAN", "VANE", "VARY", "VASE", "VAST",  "VAT", "VEAL", 
298   "VEER", "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", "VEST", 
299   "VET" , "VETO",  "VEX",  "VIA", "VICE",  "VIE", "VIEW", "VILA", 
300   "VINE", "VISA", "VISE", "VOID", "VOLT", "VOTE",  "VOW",  "WAD", 
301   "WADE", "WAFT",  "WAG", "WAGE", "WAIK", "WAIL", "WAIT", "WAKE", 
302   "WALK", "WALL", "WAND", "WANE", "WANT",  "WAR", "WARD", "WARE", 
303   "WARM", "WARN", "WARP", "WART", "WARY",  "WAS", "WASH", "WASP", 
304   "WATT", "WAVE", "WAVY",  "WAX", "WAXY",  "WAY", "WAYS",   "WE", 
305   "WEAK", "WEAL", "WEAN", "WEAR",  "WEB",  "WED",  "WEE", "WEED", 
306   "WEEK", "WEEP", "WEIR", "WELD", "WELL", "WELT", "WEND", "WENT", 
307   "WEPT", "WERE", "WEST",  "WET", "WEVE", "WHAM", "WHAT", "WHEN", 
308   "WHET", "WHEY", "WHIM", "WHIP", "WHIZ",  "WHO", "WHOA", "WHOM", 
309   "WHY" , "WICK", "WIDE", "WIFE",  "WIG", "WILD", "WILL", "WILT", 
310   "WILY",  "WIN", "WIND", "WINE", "WING", "WINK", "WIPE", "WIRE", 
311   "WISE", "WISH", "WISP",  "WIT", "WITH",  "WOK", "WOKE", "WOLF", 
312   "WON" , "WONT",  "WOO", "WOOD", "WOOL", "WORD", "WORE", "WORK", 
313   "WORM", "WORN", "WORT",  "WOT",  "WOW", "WRAP", "WREN", "WRIT", 
314   "WRY" , "WUSS", "YAGI",  "YAK",  "YAM", "YANK",  "YAP", "YARD", 
315   "YARN",  "YAW", "YAWN",  "YEA", "YEAH", "YEAR", "YELL", "YELP", 
316   "YES" ,  "YET", "YOGA", "YOGI", "YOKE", "YOLK", "YORE", "YORK", 
317   "YOU" , "YOUD", "YOUR", "YOWL", "YURT", "ZERO", "ZEST", "ZETA",
318   "ZINC", "ZING", "ZINK",  "ZIP", "ZONE",  "ZOO", "ZORK", "ZOOM"
319
320 };
321
322 //
323 void
324 banner(FILE* stream = stdout)
325 {
326   fprintf(stream, "\n\
327 %s (asdcplib %s)\n\n\
328 Copyright (c) 2003-2018 John Hurst\n\n\
329 %s is part of the asdcp DCP tools package.\n\
330 asdcplib may be copied only under the terms of the license found at\n\
331 the top of every file in the asdcplib distribution kit.\n\n\
332 Specify the -h (help) option for further information about %s\n\n",
333           PROGRAM_NAME, Kumu::Version(), PROGRAM_NAME, PROGRAM_NAME);
334 }
335
336 //
337 void
338 usage(FILE* stream = stdout)
339 {
340   fprintf(stream, "\
341 USAGE: %s [-b|-B|-c|-x] [-n] [-s <size>] [-v]\n\
342 \n\
343        %s [-h|-help] [-V]\n\
344 \n\
345   -b          - Output a stream of binary data\n\
346   -B          - Output a Base64 string\n\
347   -c          - Output a C-language struct containing the values\n\
348   -C          - Encode as a list of code words (for each code word, 20 bits of\n\
349                 entropy are consumed, 4 are discarded)\n\
350   -h | -help  - Show help\n\
351   -n          - Suppress newlines\n\
352   -s <size>   - Number of random bytes to generate (default 32)\n\
353   -v          - Verbose. Prints informative messages to stderr\n\
354   -V          - Show version information\n\
355   -w          - Encode as a list of dictionary words (for each dictionary word,\n\
356                 11 bits of entropy are consumed, 1 is discarded)\n\
357   -W <expr>   - Word separator, for use with -C and -w (default '-')\n\
358   -x          - Output hexadecimal (default)\n\
359 \n\
360   NOTES: o There is no option grouping, all options must be distinct arguments.\n\
361          o All option arguments must be separated from the option by whitespace.\n\
362 \n", PROGRAM_NAME, PROGRAM_NAME);
363 }
364
365 enum OutputFormat_t {
366   OF_HEX,
367   OF_BINARY,
368   OF_BASE64,
369   OF_CSTRUCT,
370   OF_DICTWORD,
371   OF_CODEWORD
372 };
373
374 //
375 class CommandOptions
376 {
377   CommandOptions();
378
379 public:
380   bool   error_flag;      // true if the given options are in error or not complete
381   bool   no_newline_flag; // 
382   bool   verbose_flag;    // true if the verbose option was selected
383   bool   version_flag;    // true if the version display option was selected
384   bool   help_flag;       // true if the help display option was selected
385   OutputFormat_t format;  // 
386   ui32_t request_size;
387   bool size_provided;     // if true, the -s option has been used
388   std::string separator;  // word separator value for OF_DICTWORD and CODEWORD modes
389
390  //
391   CommandOptions(int argc, const char** argv) :
392     error_flag(true), no_newline_flag(false), verbose_flag(false),
393     version_flag(false), help_flag(false), format(OF_HEX), request_size(RandBlockSize*2),
394     size_provided(false), separator("-")
395   {
396     for ( int i = 1; i < argc; i++ )
397       {
398
399          if ( (strcmp( argv[i], "-help") == 0) )
400            {
401              help_flag = true;
402              continue;
403            }
404      
405         if ( argv[i][0] == '-' && isalpha(argv[i][1]) && argv[i][2] == 0 )
406           {
407             switch ( argv[i][1] )
408               {
409               case 'b': format = OF_BINARY; break;
410               case 'B': format = OF_BASE64; break;
411               case 'c': format = OF_CSTRUCT; break;
412               case 'C': format = OF_CODEWORD; break;
413               case 'n': no_newline_flag = true; break;
414               case 'h': help_flag = true; break;
415
416               case 's':
417                 TEST_EXTRA_ARG(i, 's');
418                 request_size = Kumu::xabs(strtol(argv[i], 0, 10));
419                 size_provided = true;
420                 break;
421
422               case 'v': verbose_flag = true; break;
423               case 'V': version_flag = true; break;
424               case 'w': format = OF_DICTWORD; break;
425
426               case 'W':
427                 TEST_EXTRA_ARG(i, 'W');
428                 separator = argv[i];
429                 break;
430
431               case 'x': format = OF_HEX; break;
432
433               default:
434                 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
435                 return;
436               }
437           }
438         else
439           {
440             fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
441             return;
442           }
443       }
444
445     if ( help_flag || version_flag )
446       return;
447
448     if ( ! size_provided )
449       {
450         if ( format == OF_CODEWORD )
451           {
452             request_size = 20;
453           }
454         else if ( format == OF_DICTWORD )
455           {
456             request_size = 16;
457           }
458       }
459     else if ( request_size == 0 )
460       {
461         fprintf(stderr, "Please use a non-zero request size\n");
462         return;
463       }
464
465     error_flag = false;
466   }
467 };
468
469
470 //
471 int
472 main(int argc, const char** argv)
473 {
474   CommandOptions Options(argc, argv);
475
476    if ( Options.version_flag )
477     banner();
478
479   if ( Options.help_flag )
480     usage();
481
482   if ( Options.version_flag || Options.help_flag )
483     return 0;
484
485   if ( Options.error_flag )
486     {
487       fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
488       return 3;
489     }
490
491   FortunaRNG    RandGen;
492   ByteString    Buf(Kumu::Kilobyte);
493
494   if ( Options.verbose_flag )
495     fprintf(stderr, "Generating %d random byte%s.\n", Options.request_size, (Options.request_size == 1 ? "" : "s"));
496
497   if ( Options.format == OF_BINARY )
498     {
499       if ( KM_FAILURE(Buf.Capacity(Options.request_size)) )
500         {
501           fprintf(stderr, "randbuf: %s\n", RESULT_ALLOC.Label());
502           return 1;
503         }
504
505       RandGen.FillRandom(Buf.Data(), Options.request_size);
506       fwrite((byte_t*)Buf.Data(), 1, Options.request_size, stdout);
507     }
508   else if ( Options.format == OF_CSTRUCT )
509     {
510       ui32_t line_count = 0;
511       byte_t* p = Buf.Data();
512       printf("byte_t rand_buf[%u] = {\n", Options.request_size);
513
514       if ( Options.request_size > 128 )
515         fputs("  // 0x00000000\n", stdout);
516
517       while ( Options.request_size > 0 )
518         {
519           if ( line_count > 0 && (line_count % (RandBlockSize*8)) == 0 )
520             fprintf(stdout, "  // 0x%08x\n", line_count);
521
522           RandGen.FillRandom(p, RandBlockSize);
523           fputc(' ', stdout);
524
525           for ( ui32_t i = 0; i < RandBlockSize && Options.request_size > 0; i++, Options.request_size-- )
526             printf(" 0x%02x,", p[i]);
527
528           fputc('\n', stdout);
529           line_count += RandBlockSize;
530         }
531
532       fputs("};", stdout);
533
534       if ( ! Options.no_newline_flag )
535         fputc('\n', stdout);
536     }
537   else if ( Options.format == OF_BASE64 )
538     {
539       if ( KM_FAILURE(Buf.Capacity(Options.request_size)) )
540         {
541           fprintf(stderr, "randbuf: %s\n", RESULT_ALLOC.Label());
542           return 1;
543         }
544
545       ByteString Strbuf;
546       ui32_t e_len = base64_encode_length(Options.request_size) + 1;
547
548       if ( KM_FAILURE(Strbuf.Capacity(e_len)) )
549         {
550           fprintf(stderr, "strbuf: %s\n", RESULT_ALLOC.Label());
551           return 1;
552         }
553
554       RandGen.FillRandom(Buf.Data(), Options.request_size);
555
556       if ( base64encode(Buf.RoData(), Options.request_size, (char*)Strbuf.Data(), Strbuf.Capacity()) == 0 )
557         {
558           fprintf(stderr, "encode error\n");
559           return 2;
560         } 
561
562       fputs((const char*)Strbuf.RoData(), stdout);
563
564       if ( ! Options.no_newline_flag )
565         fputs("\n", stdout);
566     }
567   else if ( Options.format == OF_DICTWORD )
568     {
569       byte_t* p = Buf.Data();
570       char hex_buf[64];
571       int word_count = 0;
572
573       while ( Options.request_size > 0 )
574         {
575           ui32_t x_len = xmin(Options.request_size, RandBlockSize);
576           RandGen.FillRandom(p, RandBlockSize);
577
578           // process 3 words at a time, each containing two 12-bit segments
579           for ( int i = 0; i+3 < x_len; i+=3 )
580             {
581               // ignore the high bit of each 12-bit segment, thus each output
582               // word has 11 bits of the entropy
583               int index1 = ( ( p[i] & 0x07f ) << 4 ) | ( p[i+1] >> 4 );
584               assert(index1<2048);
585               int index2 = ( ( p[i+1] & 0x07 ) << 8 ) | p[i+2];
586               assert(index2<2048);
587
588               printf("%s%s%s%s",
589                      (word_count==0?"":Options.separator.c_str()),
590                      _word_list[index1],
591                      Options.separator.c_str(),
592                      _word_list[index2]);
593
594               word_count += 2;
595             }
596
597           Options.request_size -= x_len;
598         }
599
600       if ( ! Options.no_newline_flag )
601         {
602           fputc('\n', stdout);
603         }
604     }
605   else if ( Options.format == OF_CODEWORD )
606     {
607       const char word_chars[] = "123456789ABCDEFGHJKLMNPRSTUVWXYZ";
608       byte_t* p = Buf.Data();
609       char hex_buf[64];
610       int word_count = 0;
611
612       while ( Options.request_size > 0 )
613         {
614           ui32_t x_len = xmin(Options.request_size, RandBlockSize);
615           RandGen.FillRandom(p, RandBlockSize);
616
617           // process 3 words at a time, derive a code word with 20 bits of entropy.
618           for ( int i = 0; i+3 < x_len; i+=3 )
619             {
620               int index1 = p[i] >> 3;                 // MSB bits 87654
621               assert(index1<32);
622               int index2 = ( ( p[i]  & 0x07 ) << 2 ) | ( p[i+1] >> 6 );    // MSB bits 321 & MSB+1 bits 78
623               assert(index2<32);
624               int index3 = ( p[i+1] & 0x3e ) >> 1;    // MSB+1 bits 65432
625               assert(index3<32);
626               int index4 = p[i+2]  & 0x1f;            // MSB+2 bits 54321
627               assert(index4<32);
628
629               printf("%s%c%c%c%c",
630                      (word_count==0?"":Options.separator.c_str()),
631                      word_chars[index1], word_chars[index2],
632                      word_chars[index3], word_chars[index4]);
633
634               ++word_count;
635             }
636
637           Options.request_size -= x_len;
638         }
639
640       if ( ! Options.no_newline_flag )
641         {
642           fputc('\n', stdout);
643         }
644     }
645  else // OF_HEX
646     {
647       byte_t* p = Buf.Data();
648       char hex_buf[64];
649
650       while ( Options.request_size > 0 )
651         {
652           ui32_t x_len = xmin(Options.request_size, RandBlockSize);
653           RandGen.FillRandom(p, RandBlockSize);
654           bin2hex(p, x_len, hex_buf, 64);
655           fputs(hex_buf, stdout);
656
657           Options.request_size -= x_len;
658
659           if ( ! Options.no_newline_flag )
660             {
661               fputc('\n', stdout);
662             }
663         }
664     }
665
666   return 0;
667 }
668
669
670 //
671 // end kmrandgen.cpp
672 //