/* COPYRIGHT, LICENSE AND VERSION {{{ */
/* Copyright (C) 2004 by Steve Litt
 *
 * All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the
 * Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute,
 * and/or sell copies of the Software, and to permit persons to
 * whom the Software is furnished to do so, provided that the
 * above copyright notice(s) and this permission notice appear
 * in all copies of the Software and that both the above
 * copyright notice(s) and this permission notice appear in
 * supporting documentation.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
 * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO
 * EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
 * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR
 * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 * 
 * Except as contained in this notice, the name of a copyright
 * holder shall not be used in advertising or otherwise to
 * promote the sale, use or other dealings in this Software
 * without prior written authorization of the copyright holder.
 *
 * VERSION: 0.0.1, June 2004
 */
/*}}}*/
/* INCLUDES {{{ */
#include <ncurses.h>
#include <menu.h>	/* Gives you menuing capabilities */
#include <assert.h>		/*assert*/
#include <malloc.h>		/*malloc*/
#include <string.h>		/*strlen*/
#include <stdlib.h>		/*exit*/
#include <math.h>		/*ltoa*/
/*}}}*/
/* #DEFINES AND ENUMS {{{ */
#define WHITEONRED 1
#define WHITEONBLUE 2
#define WHITEONBLACK 3
#define BLACKONWHITE 4
#define REDONWHITE 5
#define GREENONBLACK 6
#define CYANONRED 7


enum KBDKEYS {ENTER, CTRL_A, CTRL_B, CTRL_C, CTRL_D, CTRL_E,
	CTRL_F, CTRL_G, CTRL_H, CTRL_I, CTRL_J, CTRL_K,
	CTRL_L, CTRL_M, CTRL_N, CTRL_O, CTRL_P, CTRL_Q,
	CTRL_R, CTRL_S, CTRL_T, CTRL_U, CTRL_V, CTRL_W,
	CTRL_X, CTRL_Y, CTRL_Z, ESC, BACKSPACE, TAB, NULLCHAR};

typedef enum KBDKEYS KBDKEYS8[8];

enum ACTIONTYPES {PICK, ADD, CHANGE, DELETE, BAIL, REFRESH, NULLACTIONTYPE};
/* #DEFINES AND ENUMS }}} */
/* STRUCT FORWARD DECLARATIONS {{{ */
struct ROWINFO;
struct ROWNODE;
struct ROWSINFO;
struct KEYSTROKES;
struct SUBROUTINES;
struct WINDOWS;
struct PICKINFO;
struct SLLNODE;
/* END STRUCT FORWARD DECLARATIONS }}} */
/* FUNCTION PROTOTYPES {{{ */
/* OBSOLETE ROUTINE PROTOTYPES {{{*/
struct PICKINFO * setUpMenu();				/*{{{*/
	/*}}}*/
char * buildKeyChars();					/*{{{*/
	/*}}}*/
char ** buildKeySymbols();				/*{{{*/
	/*}}}*/
enum KBDKEYS * mallocActionKeyList(const enum KBDKEYS *argk); /*{{{*/
	/*}}}*/
/* END OBSOLETE ROUTINE PROTOTYPES }}}*/
/* UTILITY ROUTINE PROTOTYPES {{{*/
void showAscii();					/*{{{*/
	/*}}}*/
char * mallocString(const char *msg);			/*{{{*/
	/*}}}*/
const char * ltoa(const long l);				/*{{{*/
	/*}}}*/
/* END UTILITY ROUTINE PROTOTYPES }}} */
/* KEYSTROKE ROUTINE PROTOTYPES {{{ */
void testKeySymbol();					/*{{{*/
	/*}}}*/
void testAllKeySymbols();				/*{{{*/
	/*}}}*/
struct KEYSTROKES * newKeystrokes();			/*{{{*/
	/*}}}*/
void setKeySymbol(					/*{{{*/
		struct KEYSTROKES * keystrokes,
		enum KBDKEYS kbdkey,
		const char *symbol); /*}}}*/
void setKeyChar( 					/*{{{*/
		struct KEYSTROKES * keystrokes,
		enum KBDKEYS kbdkey,
		const int keychar); /*}}}*/
void freeKeystrokes(struct KEYSTROKES * keystrokes);	/*{{{*/
/*}}}*/
void setKeySymbolAndChar(				 /*{{{*/
	struct KEYSTROKES * keystrokes,
	enum KBDKEYS kbdkey,
	const int keychar,
	const char * symbol
	);	/*}}}*/
void setActionKey(					 /*{{{*/
	struct KEYSTROKES * keystrokes,
	enum KBDKEYS kbdkey,
	enum ACTIONTYPES actiontype,
	const int ss
	); /*END }}}*/
void buildKeyDefaults(struct KEYSTROKES * keystrokes);	/*{{{*/
	/*}}}*/
void assignDefaultActionKeys(struct KEYSTROKES * keystrokes);	/*{{{*/
	/*}}}*/
/* END KEYSTROKE ROUTINE PROTOTYPES }}} */
/* ROW ROUTINE PROTOTYPES  {{{ */
void freeRowsInfo(struct ROWSINFO *rowsInfo);		/*{{{*/
	/*}}}*/
void addRow(						/*{{{*/
	struct ROWSINFO * rowsInfo,
	const char *displayString,
	const char *sortString,
	const bool sortPointsToDisplay,
	const char *uid
	); /*}}}*/
struct ROWSINFO * newRowsInfo(long increase_maxrows_by); /*{{{*/
	/*}}}*/
void testRowInfo();					/*{{{*/
	/*}}}*/
void freeRowInfo(struct ROWINFO * rowInfo);		/*{{{*/
	/*}}}*/
struct ROWINFO * newRowInfo(				/*{{{*/
	const char *displayString,
	const char *sortString,
	const bool sortPointsToDisplay,
	const char *uid
		); /*}}}*/
/* END ROW ROUTINE PROTOTYPES }}}  */
/* WINDOW ROUTINE PROTOTYPES {{{ */
void setUpWindows(struct PICKINFO *pickInfo);		/*{{{*/
	/*}}}*/
/* END WINDOW ROUTINE PROTOTYPES }}} */
/* PICKINFO ROUTINE PROTOTYPES {{{ */
void destroyPickInfo(struct PICKINFO * pickInfo);	/*{{{*/
	/*}}}*/
struct PICKINFO *newPickInfo();				/*{{{*/
	/*}}}*/
void testMenuStructure(struct PICKINFO * pickInfo);	/*{{{*/
	/*}}}*/
/* END PICKINFO ROUTINE PROTOTYPES }}} */
/* MENU FILL ROUTINE PROTOTYPES {{{ */
void readRecords( 					/*{{{*/
		struct PICKINFO * pickInfo,
		const char * filename
		); /*}}}*/
/* END MENU FILL ROUTINE PROTOTYPES }}} */
/* MENU RUNNING ROUTINE PROTOTYPES {{{ */
/* END MENU RUNNING ROUTINE PROTOTYPES }}} */
/* TEST JIG ROUTINE PROTOTYPES NOT DIRECTLY ASSOCIATED WITH SPECIFIC STRUCTS {{{*/
void testRowsInfo();					/*{{{*/
	/*}}}*/
/* TEST JIG ROUTINE PROTOTYPES NOT DIRECTLY ASSOCIATED WITH SPECIFIC STRUCTS }}}*/
/* MAIN {{{ */
int main(int argc, char *argv[]); /* {{{ */
	/*}}}*/
/* END MAIN }}} */
/* END FUNCTION PROTOTYPES }}} */
/* STRUCTURE DEFINITIONS {{{ */
struct ROWNODE						/*{{{*/
	{
	struct ROWNODE *left;
	struct ROWNODE *right;
	struct ROWNODE *parent;
	struct ROWINFO *row;
	}; /*}}}*/
struct SUBROUTINES					/*{{{*/
	{
	/*
	add_sub;
	change_sub;
	delete_sub;
	*/
	}; /*}}}*/
struct WINDOWS						/*{{{*/
	{
	int uiTopLeftY;
	int uiTopLeftX;
	int ui_height;
	int ui_width;
	int ui_color_combo_constant;
	int ui_attrib;
	int ui_highlight_color_combo_constant;
	int ui_highlight_attrib;
	int borderTopLeftY;
	int borderTopLeftX;
	int border_height;
	int border_width;
	int border_color_combo_constant;
	int border_attrib;
	char *title;
	int firstPromptY;
	int firstPromptX;
	int prompt_color_combo_constant;
	int prompt_attrib;
	}; /*}}}*/
struct ROWINFO						/*{{{*/
	{
	char *displayString;
	char *sortString;
	bool sortPointsToDisplay;
	char *uid;
	}; /*}}}*/
struct ROWSINFO						/*{{{*/
	{
	long numrows; /* number of rows currently consumed */
	long maxrows; /* maximum rows in array */
	long increase_maxrows_by; /* number of rows to add to array when full */
	struct ROWNODE *headNode;
	struct ROWINFO **rows;
	}; /*}}}*/
struct KEYINFO              /* UNUSED RIGHT NOW */	/*{{{*/
	{
	char * symbol;
	char ch;
	char * name;
	}; /*}}}*/
struct KEYSTROKES					/*{{{*/
	{
	char * keySymbols[NULLCHAR + 1];
	char keyChars[NULLCHAR + 1];
	KBDKEYS8 action_keys[NULLACTIONTYPE]; 
	}; /*}}}*/
struct PICKINFO						/*{{{*/
	{
	struct ROWSINFO *rowsInfo;
	struct KEYSTROKES *keystrokes;
	struct SUBROUTINES *subroutines;
	struct WINDOWS *windows;
	char ** actionNames;
	}; /*}}}*/
/* END STRUCTURE DEFINITIONS }}} */
/* FUNCTION DEFINITIONS {{{ */
/* OBSOLETE ROUTINES {{{*/
struct PICKINFO * setUpMenu()				/*{{{*/
	{
	struct PICKINFO * pickInfo = newPickInfo();
	setUpWindows(pickInfo);
	return pickInfo;
	} /*}}}*/
char * buildKeyChars()					/*{{{*/
	{
	int n;
	char keys[100];

	keys[0] = 'x'; keys[1] = '\0';
	return(mallocString(keys));
	for(n=1; n <= 26; n++)
		{
		keys[n] = n;
		}
	keys[ESC] = '\033';
	keys[BACKSPACE] = '\010';
	keys[TAB] = '\011';
	keys[ENTER] = '\015';
	keys[NULLCHAR] = '\0';
	return(mallocString(keys));
	} /*}}}*/
char ** buildKeySymbols()				/*{{{*/
	{
	int elementCount;
	char **ppc;
	char **ppc2;
	char **returnArray;
	char *temp[] = {
	"ENTER",
	"CTRL+A",
	"CTRL+B",
	"CTRL+C",
	"CTRL+D",
	"CTRL+E",
	"CTRL+F",
	"CTRL+G",
	"CTRL+H",
	"CTRL+I",
	"CTRL+J",
	"CTRL+K",
	"CTRL+L",
	"CTRL+M",
	"CTRL+N",
	"CTRL+O",
	"CTRL+P",
	"CTRL+Q",
	"CTRL+R",
	"CTRL+S",
	"CTRL+T",
	"CTRL+U",
	"CTRL+V",
	"CTRL+W",
	"CTRL+X",
	"CTRL+Y",
	"CTRL+Z",
	"ESC",
	"BACKSPACE",
	"TAB",
	NULL
	}; 

	elementCount=0;
	ppc = temp;
	while(*ppc != NULL)
		{
		elementCount++;
		ppc++;
		}
	returnArray = (char **) malloc ((elementCount + 1) * sizeof(char *));
	assert(returnArray != NULL);
	for(ppc = temp, ppc2 = returnArray; *ppc != NULL; ppc++, ppc2++)
		{
		*ppc2 = mallocString(*ppc);
		}
	*ppc2 = NULL;
	return returnArray;
	} /*}}}*/

enum KBDKEYS * mallocActionKeyList(const enum KBDKEYS *argk)
	{
	int count = 0;
	const enum KBDKEYS *pk;
	enum KBDKEYS *pk2, *returnList;
	for(pk = argk; *pk != NULLCHAR; pk++) count++;
	returnList = (enum KBDKEYS *) malloc((count+1) * sizeof(enum KBDKEYS));
	pk = argk; 
	pk2 = returnList;
	while(*pk != NULLCHAR)
		*pk2++ = *pk++;
	*pk2 = NULLCHAR;
	return returnList;
	}
/* END OBSOLETE ROUTINES }}}*/
/* UTILITY ROUTINES {{{*/
void showAscii()					/*{{{*/
	{
	int c;
	int n;
	for(n=0; n<20; n++)
		{
		c = getchar();
		if(c == 'q') break;
		printf("hux>%d<harc\n", c);
		}
	} /*}}}*/

char * mallocString(const char *msg)			/*{{{*/
	{
	char *newlyCreatedString = (char *) malloc((strlen(msg) + 1) * sizeof(char));
	assert(newlyCreatedString != NULL);
	strcpy(newlyCreatedString, msg);
	return(newlyCreatedString);
	} /*}}}*/

const char * ltoa(const long l)				/*{{{*/
	{
	static char buf[31];
	int ss;
	long lT = l;

	buf[30] = '\0';
	ss = 29;
	while(lT)
		{
		buf[ss] = '0' + (lT % 10);
		lT /= 10;
		ss--;
		}
	return(&buf[ss+1]);
	} /*}}}*/

/* END UTILITY ROUTINES }}} */
/* KEYSTROKE ROUTINES {{{ */
struct KEYSTROKES * newKeystrokes()			/*{{{*/
	{
	enum KBDKEYS kbdkey;
	enum ACTIONTYPES actiontype;
	int n;
	struct KEYSTROKES * keystrokes = malloc(sizeof(struct KEYSTROKES));
	for(kbdkey = ENTER; kbdkey <= NULLCHAR; kbdkey++)
		{
		keystrokes->keySymbols[kbdkey] = NULL;
		keystrokes->keyChars[kbdkey] = '\0';
		}

	/**************************************************************
	The following loop should go up to n < 8, but it causes the ensuing
	free to segfault, so it is n < 7.
	**************************************************************/
	for(actiontype=PICK; actiontype < NULLACTIONTYPE; actiontype++)
		{
		for(n = 0; n < 7; n++);
			{
			setActionKey(keystrokes, NULLCHAR, actiontype, n);
			}
		}
	return(keystrokes);
	}						/*END }}}*/
void freeKeySymbol(struct KEYSTROKES * keystrokes, enum KBDKEYS kbdkey) /*{{{*/
	{
	if(keystrokes->keySymbols[kbdkey] != NULL)
		free(keystrokes->keySymbols[kbdkey]);
	} /*}}}*/
void setKeySymbol( 					/*{{{*/
	struct KEYSTROKES * keystrokes,
	enum KBDKEYS kbdkey,
	const char *symbol
	)
	{
	keystrokes->keySymbols[kbdkey] = mallocString(symbol); 
	}						/*END }}}*/
void testKeySymbol()					/*{{{*/
	{
	struct KEYSTROKES * keystrokes;
	long lT;
	keystrokes = newKeystrokes();
	for(lT = 0; lT < 100000000; lT++)
		{
		if(lT % 1000000 == 0) printf("%ld\n", lT);
		setKeySymbol(keystrokes, CTRL_J, "my test");
		freeKeySymbol(keystrokes, CTRL_J);
		}
	freeKeystrokes(keystrokes);
	}/*}}}*/
void setKeyChar(struct KEYSTROKES * keystrokes, enum KBDKEYS kbdkey, const int keychar) /*{{{*/
	{
	keystrokes->keyChars[kbdkey] =  keychar;
	}						/*END }}}*/
void setKeySymbolAndChar(				 /*{{{*/
	struct KEYSTROKES * keystrokes,
	enum KBDKEYS kbdkey,
	const int keychar,
	const char * symbol
	)
	{
	setKeySymbol(keystrokes, kbdkey, symbol);
	setKeyChar(keystrokes, kbdkey, keychar);
	}						/*END }}}*/
void setActionKey(					 /*{{{*/
	struct KEYSTROKES * keystrokes,
	enum KBDKEYS kbdkey,
	enum ACTIONTYPES actiontype,
	const int ss
	)
	{
	keystrokes->action_keys[actiontype][ss] = kbdkey;
	}						/*END }}}*/
void buildKeyDefaults(struct KEYSTROKES * keystrokes)	/*{{{*/
	{
	setKeySymbolAndChar(keystrokes, ENTER, 13, "ENTER");
	setKeySymbolAndChar(keystrokes, CTRL_A, 1, "CTRL+A");
	setKeySymbolAndChar(keystrokes, CTRL_B, 2, "CTRL+B");
	setKeySymbolAndChar(keystrokes, CTRL_C, 3, "CTRL+C");
	setKeySymbolAndChar(keystrokes, CTRL_D, 4, "CTRL+D");
	setKeySymbolAndChar(keystrokes, CTRL_E, 5, "CTRL+E");
	setKeySymbolAndChar(keystrokes, CTRL_F, 6, "CTRL+F");
	setKeySymbolAndChar(keystrokes, CTRL_G, 7, "CTRL+G");
	setKeySymbolAndChar(keystrokes, CTRL_H, 8, "CTRL+H");
	setKeySymbolAndChar(keystrokes, CTRL_I, 9, "CTRL+I");
	setKeySymbolAndChar(keystrokes, CTRL_J, 10, "CTRL+J");
	setKeySymbolAndChar(keystrokes, CTRL_K, 11, "CTRL+K");
	setKeySymbolAndChar(keystrokes, CTRL_L, 12, "CTRL+L");
	setKeySymbolAndChar(keystrokes, CTRL_M, 13, "CTRL+M");
	setKeySymbolAndChar(keystrokes, CTRL_N, 14, "CTRL+N");
	setKeySymbolAndChar(keystrokes, CTRL_O, 15, "CTRL+O");
	setKeySymbolAndChar(keystrokes, CTRL_P, 16, "CTRL+P");
	setKeySymbolAndChar(keystrokes, CTRL_Q, 17, "CTRL+Q");
	setKeySymbolAndChar(keystrokes, CTRL_R, 18, "CTRL+R");
	setKeySymbolAndChar(keystrokes, CTRL_S, 19, "CTRL+S");
	setKeySymbolAndChar(keystrokes, CTRL_T, 20, "CTRL+T");
	setKeySymbolAndChar(keystrokes, CTRL_U, 21, "CTRL+U");
	setKeySymbolAndChar(keystrokes, CTRL_V, 22, "CTRL+V");
	setKeySymbolAndChar(keystrokes, CTRL_W, 23, "CTRL+W");
	setKeySymbolAndChar(keystrokes, CTRL_X, 24, "CTRL+X");
	setKeySymbolAndChar(keystrokes, CTRL_Y, 25, "CTRL+Y");
	setKeySymbolAndChar(keystrokes, CTRL_Z, 26, "CTRL+Z");
	setKeySymbolAndChar(keystrokes, ESC, 27, "ESC");
	setKeySymbolAndChar(keystrokes, BACKSPACE, 8, "BACKSPACE");
	setKeySymbolAndChar(keystrokes, TAB, 9, "TAB");
	} /*}}}*/
void assignDefaultActionKeys(struct KEYSTROKES * keystrokes)	/*{{{*/
	{
	setActionKey(keystrokes,    CTRL_P,    PICK, 0);
	setActionKey(keystrokes,  NULLCHAR,    PICK, 1);
	setActionKey(keystrokes,    CTRL_A,     ADD, 0);
	setActionKey(keystrokes,  NULLCHAR,     ADD, 1);
	setActionKey(keystrokes,    CTRL_M,  CHANGE, 0);
	setActionKey(keystrokes,  NULLCHAR,  CHANGE, 1);
	setActionKey(keystrokes,    CTRL_D,  DELETE, 0);
	setActionKey(keystrokes,  NULLCHAR,  DELETE, 1);
	setActionKey(keystrokes,    CTRL_B,    BAIL, 0);
	setActionKey(keystrokes,       ESC,    BAIL, 1);
	setActionKey(keystrokes,  NULLCHAR,    BAIL, 2);
	setActionKey(keystrokes,    CTRL_L, REFRESH, 0);
	setActionKey(keystrokes,    CTRL_R, REFRESH, 1);
	setActionKey(keystrokes,  NULLCHAR, REFRESH, 2);
	} /*}}}*/
void freeKeystrokes(struct KEYSTROKES * keystrokes)	/*{{{*/
	{
	enum KBDKEYS kbdkey;
	for(kbdkey = ENTER; kbdkey <= NULLCHAR; kbdkey++)
		freeKeySymbol(keystrokes, kbdkey);
	free(keystrokes);
	keystrokes = NULL;
	} /*}}}*/
void testKeystrokes()					/*{{{*/
	{
	struct KEYSTROKES * keystrokes;
	long lT;

	for(lT = 0; lT < 10000000; lT++)
		{
		if(lT % 100000 == 0) printf("%ld\n", lT);
		keystrokes = newKeystrokes();
		setKeySymbol(keystrokes, ENTER, "ENTER");
		buildKeyDefaults(keystrokes);
		assignDefaultActionKeys(keystrokes);
/*		keystrokes = malloc(sizeof(struct KEYSTROKES));*/ 
		freeKeystrokes(keystrokes);
		}
	} /*}}}*/
void testAllKeySymbols()					/*{{{*/
	{
	struct KEYSTROKES * keystrokes;
	long lT;
	for(lT = 0; lT < 10000000; lT++)
		{
		if(lT % 1 == 0) printf("%ld\n", lT);
		keystrokes = newKeystrokes();
/*		setKeySymbol(keystrokes, ENTER, "my test"); */
		keystrokes->keySymbols[0] = malloc(10);
		assert(keystrokes->keySymbols[0] != NULL);
/*		freeKeySymbol(keystrokes, ENTER); */
		/*
		for(kbdkey=ENTER; kbdkey <= NULLCHAR; kbdkey++)
			{
			setKeySymbol(keystrokes, kbdkey, "my test");
			}
		for(kbdkey=ENTER; kbdkey <= NULLCHAR; kbdkey++)
			{
			freeKeySymbol(keystrokes, kbdkey);
			}
		*/
		freeKeystrokes(keystrokes);
		}
	}/*}}}*/
/* END KEYSTROKE ROUTINES }}} */
/* ROW ROUTINES  {{{ */
void freeRowsInfo(struct ROWSINFO *rowsInfo)		/*{{{*/
	{
	long lT;
	for(lT = 0; lT < rowsInfo->numrows; lT++)
		{
		freeRowInfo(rowsInfo->rows[lT]);
		} 
	/* PLACE ROWNODE DELETION CODE HERE LATER */
	free(rowsInfo->rows);
	free(rowsInfo);
	} /*}}}*/
void addRow(						/*{{{*/
	struct ROWSINFO * rowsInfo,
	const char *displayString,
	const char *sortString,
	const bool sortPointsToDisplay,
	const char *uid
	)
	{
	rowsInfo->numrows++;
	if(rowsInfo->numrows > rowsInfo->maxrows)
		{
		rowsInfo->maxrows += rowsInfo->increase_maxrows_by;
		if(rowsInfo->rows == NULL)
			{
			rowsInfo->rows =
				malloc(rowsInfo->maxrows *
				sizeof(struct ROWINFO *));
			}
		else
			{
			rowsInfo->rows = realloc(rowsInfo->rows,
				rowsInfo->maxrows *
				sizeof(struct ROWINFO *));
			}
		assert(rowsInfo->rows != NULL);
		}
	rowsInfo->rows[rowsInfo->numrows - 1] =
		newRowInfo(
			displayString,
			sortString,
			sortPointsToDisplay,
			uid
			);
	} /*}}}*/
struct ROWSINFO * newRowsInfo(long increase_maxrows_by)	/*{{{*/
	{
	struct ROWSINFO * rowsInfo;
	rowsInfo = malloc(sizeof(struct ROWSINFO));
	assert(rowsInfo != NULL);
	rowsInfo->numrows = 0;
	rowsInfo->maxrows = 0;
	rowsInfo->increase_maxrows_by = increase_maxrows_by;
	rowsInfo->rows = NULL;
	rowsInfo->headNode = NULL;
	return rowsInfo;
	} /*}}}*/
void testRowInfo()					/*{{{*/
	{
	struct ROWINFO * rowInfo;
	long lT;
	for(lT = 0; lT < 10000000; lT++)
		{
		if(lT % 100000 == 0) printf("%ld\n", lT);
		rowInfo = newRowInfo("display", "sort", false, "1");
		freeRowInfo(rowInfo);
		}
	} /*}}}*/
void freeRowInfo(struct ROWINFO * rowInfo)		/*{{{*/
	{
	if(rowInfo->displayString != NULL) free(rowInfo->displayString);
	if(rowInfo->sortString != NULL) free(rowInfo->sortString);
	if(rowInfo->uid != NULL) free(rowInfo->uid);
	free(rowInfo);
	} /*}}}*/
struct ROWINFO * newRowInfo(				/*{{{*/
	const char *displayString,
	const char *sortString,
	const bool sortPointsToDisplay,
	const char *uid
		)
	{
	struct ROWINFO * rowInfo;
	rowInfo = malloc(sizeof(struct ROWINFO));
	assert(rowInfo != NULL);
	rowInfo->displayString = mallocString(displayString);
	rowInfo->sortPointsToDisplay = sortPointsToDisplay;
	if(sortPointsToDisplay)
		rowInfo->sortString = NULL;
	else
		rowInfo->sortString = mallocString(sortString);
	rowInfo->uid = mallocString(uid);
	return(rowInfo);
	} /*}}}*/
void testRowsInfo()					/*{{{*/
	{
	struct ROWSINFO *rowsInfo;
	long lT;
	int nT;

	for(lT = 0; lT < 1000000; lT++)
		{
		if(lT % 100000 == 0) printf("%ld\n", lT);
		rowsInfo = newRowsInfo(10);
		for(nT = 0; nT < 30; nT++)
			{
			addRow(
				rowsInfo,
				"display",
				"sort",
				false,
				ltoa(rowsInfo->numrows)
				);
			}
		freeRowsInfo(rowsInfo);
		}
	} /*}}}*/
/* END ROW ROUTINES }}}  */
/* WINDOW ROUTINES {{{ */
void setUpWindows(struct PICKINFO *pickInfo)		/*{{{*/
	{
	pickInfo->windows->borderTopLeftY = 2;
	pickInfo->windows->borderTopLeftX = 5;
	pickInfo->windows->border_height = 20;
	pickInfo->windows->border_width = 65;
	pickInfo->windows->border_color_combo_constant = WHITEONRED;
	pickInfo->windows->border_attrib = WA_BOLD;
	pickInfo->windows->uiTopLeftY = 1;
	pickInfo->windows->uiTopLeftX = 1;
	pickInfo->windows->ui_height = 18;
	pickInfo->windows->ui_width = 19;
	pickInfo->windows->ui_color_combo_constant = WHITEONRED;
	pickInfo->windows->ui_attrib = WA_BOLD;
	pickInfo->windows->ui_highlight_color_combo_constant = REDONWHITE;
	pickInfo->windows->ui_highlight_attrib = 0;
	pickInfo->windows->title = " CHOOSE ONE ";
	pickInfo->windows->firstPromptY = 10;
	pickInfo->windows->firstPromptX = 35;
	pickInfo->windows->prompt_color_combo_constant = CYANONRED;
	pickInfo->windows->prompt_attrib = WA_BOLD;
	} /*}}}*/
bool checkDimensions(struct PICKINFO *pickInfo)		/*{{{*/
	{
	if(pickInfo->windows->ui_height + pickInfo->windows->uiTopLeftY >
		pickInfo->windows->border_height)
		{
		printf("MENU DIMENSIONING ERROR\n");
		printf("ui window bottom goes past border window bottom.\n");
		return(false);
		}
	if(pickInfo->windows->ui_width + pickInfo->windows->uiTopLeftX > 
		pickInfo->windows->border_width)
		{
		printf("MENU DIMENSIONING ERROR\n");
		printf("ui window right edge goes past border window right edge.\n");
		return(false);
		}
	return(true);
	} /*}}}*/
/* END WINDOW ROUTINES }}} */
/* PICKINFO ROUTINES {{{ */
void destroyPickInfo(struct PICKINFO * pickInfo)	/*{{{*/
	{
	char **ppc;

	/* DESTROY HEADNODE POINTER */
	free(pickInfo->rowsInfo->headNode);
	
	/* DESTROY ROWSINFO POINTER AND ROWS ARRAY */
	freeRowsInfo(pickInfo->rowsInfo); 
	
	/* DESTROY KEYSTROKES POINTER AND ITS CONTENTS */
	freeKeystrokes(pickInfo->keystrokes);

	/* DESTROY SUBROUTINES POINTER */
	free(pickInfo->subroutines);

	/* DESTROY WINDOWS POINTER */
	free(pickInfo->windows);

	/* DESTROY ACTION NAMES ARRAY */
	for(ppc = pickInfo->actionNames; *ppc != NULL; ppc++)
		free(*ppc++);
	free(pickInfo->actionNames);

	/* DESTROY PICKINFO */
	free(pickInfo);
	} /*}}}*/
struct PICKINFO *newPickInfo()				/*{{{*/
	{
	struct PICKINFO * pickInfo;

	/* ALLOCATE PICKINFO */
	pickInfo = (struct PICKINFO *) malloc(sizeof(struct PICKINFO));
	assert(pickInfo != NULL);

	/* ****************************** */
	/* SET ACTION NAME DEFAULTS       */
	/* ****************************** */
	pickInfo->actionNames = malloc(NULLACTIONTYPE * sizeof(char *));
	pickInfo->actionNames[PICK] = mallocString("Pick");
	pickInfo->actionNames[ADD] = mallocString("Add");
	pickInfo->actionNames[CHANGE] = mallocString("Modify");
	pickInfo->actionNames[DELETE] = mallocString("Delete");
	pickInfo->actionNames[BAIL] = mallocString("Abort");
	pickInfo->actionNames[REFRESH] = mallocString("Refresh");
	pickInfo->actionNames[NULLACTIONTYPE] = NULL;

	/* ALLOCATE ROWSINFO POINTER */
	pickInfo->rowsInfo = newRowsInfo(1000);  

	/* ALLOCATE KEYSTROKES POINTER */
	pickInfo->keystrokes = newKeystrokes();
	buildKeyDefaults(pickInfo->keystrokes);
	assignDefaultActionKeys(pickInfo->keystrokes);  
	

	/* ALLOCATE SUBROUTINES POINTER */
	pickInfo->subroutines = (struct SUBROUTINES *)
		malloc(sizeof(struct SUBROUTINES));
	assert(pickInfo->subroutines != NULL);

	/* ALLOCATE WINDOWS POINTER */
	pickInfo->windows = (struct WINDOWS *)
		malloc(sizeof(struct WINDOWS));
	assert(pickInfo->windows != NULL);


	/* ****************************** */
	/* ALLOCATE ALL ROWSINFO POINTERS */
	/* ****************************** */

	/* ALLOCATE HEADNODE POINTER */
	/* Nodes are not used in this program */
/*	pickInfo->rowsInfo->headNode = (struct ROWNODE *)
		malloc(sizeof(struct ROWNODE));
	assert(pickInfo->rowsInfo->headNode != NULL); */
	
	/* ALLOCATE ROWS ARRAY POINTER */
	/* this is done by the readRecords() routine */
/*	pickInfo->rowsInfo->rows = (struct ROWINFO **)
		malloc(sizeof(struct ROWINFO *));
	assert(pickInfo->rowsInfo->rows != NULL); 
*/
	/* ****************************** */
	/* ALLOCATE ALL CONSTANT KEYSTROKES POINTERS */
	/* ****************************** */
/*	pickInfo->keystrokes->keyChars = buildKeyChars(); */
/*	pickInfo->keystrokes->keySymbols = buildKeySymbols(); */


	return(pickInfo);
	} /*}}}*/
void testMenuStructure(struct PICKINFO * pickInfo)	/*{{{*/
	{
	enum KBDKEYS *pkbdkey;
	enum ACTIONTYPES actionType;
	char **ppc;
	char *pc;
	int n;
	long lT;

	printf("\n\nDISPLAYING pickInfo->rowsInfo INFORMATION *************\n");

	for(lT = 0; lT < pickInfo->rowsInfo->numrows; lT++)
		{
		printf("\t%8ld: %s\n", lT, 
			pickInfo->rowsInfo->rows[lT]->sortString);
		}


	printf("\n\nDISPLAYING pickInfo->keystrokes INFORMATION *************\n");
	printf("\n\tDISPLAYING pickInfo->keystrokes->keySymbols INFORMATION\n");
	ppc = pickInfo->keystrokes->keySymbols;
	n = 0;
	while(*ppc != NULL)
		{
		if(n > 0) printf(", ");
		if(n % 5 == 0) printf("\n\t\t");
		printf("%s", *ppc);
		ppc++;
		n++;
		}

	printf("\n\nDISPLAYING pickInfo->keystrokes->keyChars INFORMATION\n");
	pc = pickInfo->keystrokes->keyChars;
	n = 0;
	while(*pc != '\0')
		{
		if(n > 0) printf(", ");
		if(n % 5 == 0) printf("\n\t\t");
		printf("%d", *pc);
		pc++;
		n++;
		}
	printf("\n\nDISPLAYING pickInfo->keystrokes->action_keys INFORMATION\n");
	actionType = PICK;
	while(actionType < NULLACTIONTYPE)
		{
		printf("\t");
		printf("%s:\t", pickInfo->actionNames[actionType]);
		pkbdkey = pickInfo->keystrokes->action_keys[actionType];
		n=0;
		while(pkbdkey[n] >= '\0')
			{
			if(n > 0) printf(", ");
			printf("%s", pickInfo->keystrokes->keySymbols[pkbdkey[n]]); 
			n++;
			if(pkbdkey[n] == NULLCHAR) break;
			if(n >= 8)
				{
				printf ("ERROR: Unterminated by NULLCHAR\n");
				break;
				}
			}
		printf("\n");
		actionType++;
		}


	printf("\n\nDISPLAYING pickInfo->subroutines INFORMATION *************\n");
	printf("\n\nDISPLAYING pickInfo->windows INFORMATION *************\n");

	printf("\ttitle=%s.\n",  pickInfo->windows->title);
	printf("\tBORDER WINDOW STATS...\n");
	printf("\t\tborderTopLeftY=%d.\n",  pickInfo->windows->borderTopLeftY);
	printf("\t\tborderTopLeftX=%d.\n",  pickInfo->windows->borderTopLeftX);
	printf("\t\tborder_color_combo_constant=%d.\n",  pickInfo->windows->border_color_combo_constant);
	printf("\t\tborder_attrib=%d.\n",  pickInfo->windows->border_attrib);
	printf("\t\tborder_height=%d.\n",  pickInfo->windows->border_height);
	printf("\t\tborder_width=%d.\n",  pickInfo->windows->border_width);
	printf("\tUI WINDOW STATS...\n");
	printf("\t\tuiTopLeftY=%d.\n",  pickInfo->windows->uiTopLeftY);
	printf("\t\tuiTopLeftX=%d.\n",  pickInfo->windows->uiTopLeftX);
	printf("\t\tui_height=%d.\n",  pickInfo->windows->ui_height);
	printf("\t\tui_width=%d.\n",  pickInfo->windows->ui_width);
	printf("\t\tui_color_combo_constant=%d.\n",  pickInfo->windows->ui_color_combo_constant);
	printf("\t\tui_attrib=%d.\n",  pickInfo->windows->ui_attrib);
	printf("\tPROMPT STATS...\n");
	printf("\t\tfirstPromptY=%d.\n",  pickInfo->windows->firstPromptY);
	printf("\t\tfirstPromptX=%d.\n",  pickInfo->windows->firstPromptX);
	printf("\n\nDISPLAYING pickInfo->actionNames INFORMATION *************\n");
	actionType = PICK;
	while((pc = pickInfo->actionNames[actionType]) != NULL)
		{
		if(actionType == NULLACTIONTYPE)
			{
			printf ("ERROR: Unterminated by NULL\n");
			break;
			}
		printf("\t%s\n", pc);
		actionType++;
		}
	} /*}}}*/
void testPickInfo()					/*{{{*/
	{
	long lT;
	struct PICKINFO *pickInfo;
	for(lT=0; lT < 10000000; lT++)
		{
		if((lT % 100000) == 0)
			printf("%7ld\n", lT);
		pickInfo = newPickInfo();
/*		setUpWindows(pickInfo); */
/*		printf("dia b4 readRecords() %ld\n", lT);*/
	/*	readRecords(pickInfo, "presidents.txt"); */

/*		printf("dia b4 destroy %ld\n", lT);*/
		destroyPickInfo(pickInfo);
		}
	} /*}}}*/
/* END PICKINFO ROUTINES }}} */
/* MENU FILL ROUTINES {{{ */
void readRecords(struct PICKINFO * pickInfo, const char * filename) /*{{{*/
	{
	int BUFSIZE = 101;
	FILE * fp;
	char buf[BUFSIZE];
	char *pc;
	int maxLength = pickInfo->windows->ui_width - 1;

		
	fp = fopen(filename, "r");
	if(fp == NULL)
		{
		printf("Cannot open %s for read, aborting...\n", filename);
		}
	while((pc = fgets(buf, BUFSIZE, fp)) != NULL)
		{
		int len;

		/* PREVENT OVERFLOW AND TOO WIDE STRINGS */
		buf[BUFSIZE - 1] = '\0';
		len = strlen(buf);
		buf[len - 1] = '\0';  /* TRIM NEWLINE */
		if(len > maxLength )
			buf[maxLength - 1] = '\0';

		/* CONTINUE */
		pickInfo->rowsInfo->numrows++;  

		if(pickInfo->rowsInfo->numrows > pickInfo->rowsInfo->maxrows)
			{
			pickInfo->rowsInfo->maxrows +=
				pickInfo->rowsInfo->increase_maxrows_by;
			pickInfo->rowsInfo->rows =
				realloc(pickInfo->rowsInfo->rows,
				pickInfo->rowsInfo->maxrows *
				sizeof(struct ROWINFO *)); 
			assert(pickInfo->rowsInfo->rows != NULL);
			}

		pickInfo->rowsInfo->rows[pickInfo->rowsInfo->numrows - 1] = 
			newRowInfo(
				mallocString(pc),
				mallocString(pc),
				false,
				mallocString(ltoa((long)pickInfo->rowsInfo->numrows))
			);

		} 
	fclose(fp);
	} /*}}}*/
/* END MENU FILL ROUTINES }}} */
/* MENU RUNNING ROUTINES {{{ */
void wCenterTitle(WINDOW *pwin, const char * title)	/*{{{*/
	{
	int x, maxy, maxx, stringsize;
	getmaxyx(pwin, maxy, maxx);
	stringsize = 4 + strlen(title);
	x = (maxx - stringsize)/2;
	mvwaddch(pwin, 0, x, ACS_RTEE);
	waddch(pwin, ' ');
	waddstr(pwin, title);
	waddch(pwin, ' ');
	waddch(pwin, ACS_LTEE);
	} /*}}}*/
void wclrscr(WINDOW * pwin)				/*{{{*/
	{
	int y, x, maxy, maxx;
	getmaxyx(pwin, maxy, maxx);
	for(y=0; y < maxy; y++)
		for(x=0; x < maxx; x++)
			mvwaddch(pwin, y, x, ' ');
	} /*}}}*/
bool initColors()					/*{{{*/
	{
	if(has_colors())
		{
		start_color();
		init_pair(WHITEONRED, COLOR_WHITE, COLOR_RED);
		init_pair(WHITEONBLUE, COLOR_WHITE, COLOR_BLUE);
		init_pair(WHITEONBLACK, COLOR_WHITE, COLOR_BLACK);
		init_pair(BLACKONWHITE, COLOR_BLACK, COLOR_WHITE);
		init_pair(REDONWHITE, COLOR_RED, COLOR_WHITE);
		init_pair(GREENONBLACK, COLOR_GREEN, COLOR_BLACK);
		init_pair(CYANONRED, COLOR_CYAN, COLOR_RED);
		return(true);
		}
	else
		return(false);
	} /*}}}*/
int runMenu(						/*{{{*/
		struct PICKINFO *pickInfo,
		WINDOW *wParent
		)
	{
	int c;			/* key pressed */	
	ITEM **my_items;	/* list of items on this menu */
	MENU *my_menu;		/* the menu structure */

	WINDOW *wUI;		/* window on which the user
					interacts with the menu */
	WINDOW *wBorder;	/* window containing the wUI window
					and the border and title */

        int n_choices;		/* number of items on menu */
        int ssChoice;		/* subscript to run around the choices array */
	int my_choice = -1;	/* the zero based numeric user choice */
	int y;
	enum ACTIONTYPES actiontype;


	/* CALCULATE NUMBER OF MENU CHOICES */
	n_choices = pickInfo->rowsInfo->numrows;

	/* ALLOCATE ITEM ARRAY AND INDIVIDUAL ITEMS */
        my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
        for(ssChoice = 0; ssChoice < n_choices; ++ssChoice)
		{
                my_items[ssChoice] = new_item(
			pickInfo->rowsInfo->rows[ssChoice]->displayString, NULL);
		}
	my_items[n_choices] = (ITEM *)NULL;

	/* CREATE THE MENU STRUCTURE */
	my_menu = new_menu((ITEM **)my_items);

	/* PUT > TO THE LEFT OF HIGHLIGHTED ITEM */
	set_menu_mark(my_menu, "> ");

	/* SET UP WINDOW FOR MENU'S BORDER */
	wBorder = newwin(
			pickInfo->windows->border_height,
			pickInfo->windows->border_width,
			pickInfo->windows->borderTopLeftY,
			pickInfo->windows->borderTopLeftX); 
	wattrset(
		wBorder,
		COLOR_PAIR(pickInfo->windows->border_color_combo_constant) |
		pickInfo->windows->border_attrib);
	wclrscr(wBorder); 
	box(wBorder, 0, 0);
	wCenterTitle(wBorder, pickInfo->windows->title);

	/* SET UP WINDOW FOR THE MENU'S USER INTERFACE */
	wUI = derwin(
		wBorder,
		pickInfo->windows->ui_height,
		pickInfo->windows->ui_width,
		pickInfo->windows->uiTopLeftY,
		pickInfo->windows->uiTopLeftX
		);

	/* ASSOCIATE THESE WINDOWS WITH THE MENU */
	set_menu_win(my_menu, wBorder);
	set_menu_sub(my_menu, wUI);
	set_menu_format(my_menu, pickInfo->windows->ui_height, 1);

	/* MATCH MENU'S COLORS TO THAT OF ITS WINDOWS */
	set_menu_fore(
		my_menu,
		COLOR_PAIR(pickInfo->windows->ui_highlight_color_combo_constant) |
		pickInfo->windows->ui_highlight_attrib
		);
	set_menu_back(
		my_menu,
		COLOR_PAIR(pickInfo->windows->ui_color_combo_constant) |
		pickInfo->windows->ui_attrib
		);

	/* SET UP AN ENVIRONMENT CONDUCIVE TO MENUING */
	keypad(wUI, TRUE);	/* enable detection of function keys */
	noecho();		/* user keystrokes don't echo */
	curs_set(0);		/* make cursor invisible */
	menu_opts_on(my_menu, O_SHOWMATCH);
	menu_opts_on(my_menu, O_IGNORECASE);
	menu_opts_on(my_menu, O_NONCYCLIC);

	/* DISPLAY THE MENU */
	post_menu(my_menu);

	/* DISPLAY THE PROMPTS */
	wattrset(
		wBorder,
		COLOR_PAIR(pickInfo->windows->prompt_color_combo_constant) |
		pickInfo->windows->prompt_attrib
		);
	y = pickInfo->windows->firstPromptY;
	for(actiontype=PICK; actiontype < NULLACTIONTYPE; actiontype++)
		{
		enum KBDKEYS *kbdkeys = pickInfo->keystrokes->action_keys[actiontype];
		if(kbdkeys[0] != NULLCHAR)
			{
			int ssKeySymbol;
			mvwaddstr(
				wBorder,
				y,
				pickInfo->windows->firstPromptX,
				pickInfo->actionNames[actiontype]
				);
			waddstr(wBorder, ": ");
			for(ssKeySymbol = 0; ssKeySymbol < 7; ssKeySymbol++)
				{
				enum KBDKEYS thisKey = kbdkeys[ssKeySymbol];
				if(thisKey == NULLCHAR)
					break;
				else
					{
					char *pc;

					if(ssKeySymbol > 0) waddstr(wBorder, ", ");
					pc = pickInfo->keystrokes->keySymbols[thisKey];
					waddstr(wBorder, pc);
					}
				}  
			y++;

			} 
		}
	wattrset(
		wBorder,
		COLOR_PAIR(pickInfo->windows->border_color_combo_constant) |
		pickInfo->windows->border_attrib
		);

	/* REFRESH THE BORDER WINDOW PRIOR TO ACCEPTING USER INTERACTION */
	touchwin(wBorder);
	wrefresh(wBorder);  

	/* HANDLE USER KEYSTROKES */
	while(my_choice == -1)
		{
		touchwin(wUI);	/* refresh prior to getch() */
		wrefresh(wUI); 	/* refresh prior to getch() */
		c = getch();
		switch(c)
			{
			case KEY_DOWN:
				menu_driver(my_menu, REQ_DOWN_ITEM);
				break;
			case KEY_UP:
				menu_driver(my_menu, REQ_UP_ITEM);
				break;
			case KEY_NPAGE:
				menu_driver(my_menu, REQ_SCR_DPAGE);
				break;
			case KEY_PPAGE:
				menu_driver(my_menu, REQ_SCR_UPAGE);
				break;
			case 10:	/* Enter */
				my_choice = item_index(current_item(my_menu));

				/* RESET CURSOR IN CASE MORE SELECTION IS NECESSARY */
				pos_menu_cursor(my_menu);
				break;
			}
		}	

	/* FREE ALL ALLOCATED MENU AND ITEM RESOURCES */
	unpost_menu(my_menu);
        for(ssChoice = 0; ssChoice < n_choices; ++ssChoice)
                free_item(my_items[ssChoice]);
	free_menu(my_menu);

	/* DESTROY MENU WINDOW AND BORDER WINDOWS */
	delwin(wUI);
	delwin(wBorder);

	/* UNDO MENU SPECIFIC ENVIRONMENT */
	curs_set(1);			/* make cursor visible again */
	
	/* REPAINT THE CALLING SCREEN IN PREPARATION FOR RETURN */
	touchwin(wParent);
	wrefresh(wParent);

	/* RETURN THE ZERO BASED NUMERIC USER CHOICE */
	return(my_choice);
	} /*}}}*/


/* END MENU RUNNING ROUTINES }}} */
/* TEST JIG ROUTINES NOT DIRECTLY ASSOCIATED WITH SPECIFIC STRUCTS {{{*/
int testx()						/*{{{*/
	{
	long lT;
	int n;
	struct KEYSTROKES * keystrokes;
	for(lT = 0; lT < 100; lT++)
		{
		printf("%ld\n", lT);
		keystrokes = newKeystrokes();
		assert(keystrokes != NULL);
		for(n=0; n < 20; n++)
			{
			keystrokes->keySymbols[n] = malloc(120);
			sprintf(keystrokes->keySymbols[n], ">%ld<>%d<", lT, n);
			}
		for(n=0; n < 20; n++)
			{
			printf("%s\n", keystrokes->keySymbols[n]);
			free(keystrokes->keySymbols[n]);
			}
		free(keystrokes); 
		}
	return(0);
	} /*}}}*/
/* TEST JIG ROUTINES NOT DIRECTLY ASSOCIATED WITH SPECIFIC STRUCTS }}}*/
/* MAIN() {{{ */
int main(int argc, char *argv[]) /* {{{ */
	{
	struct PICKINFO * pickInfo;
	int choiceno;

	printf("Begin\n");

	pickInfo = newPickInfo();
	setUpWindows(pickInfo);
	readRecords(pickInfo, "presidents.txt");
	if(!checkDimensions(pickInfo)) exit(1);


	initscr();		/* start ncurses */
        cbreak();		/* immediately acquire each keystroke */
        noecho();		/* do not echo user keystrokes */
	keypad(stdscr, TRUE);	/* enable detection of function keys */
	initColors();		/* enable colors and initialize pairs */

	/* SET UP AND PAINT STANDARD SCREEN */
	wattrset(stdscr, COLOR_PAIR(WHITEONBLUE) | WA_BOLD);
	wclrscr(stdscr);
	mvwaddstr(stdscr, 10, 10, "Simple color menu");
	touchwin(stdscr);
	wrefresh(stdscr);


	/* ACQUIRE THE USER'S CHOICE */
	choiceno = runMenu(pickInfo, stdscr);
	mvwaddstr(stdscr, 22, 0, "Hit any key to finish==>");
	touchwin(stdscr);
	wrefresh(stdscr);
	getch();
	endwin();
	printf("\n\nYou chose item %d\n", choiceno);
/*	printf("\n\nYou chose item %d, %s\n", choiceno,
		pickInfo->rowsInfo->rows[choiceno]->displayString); */
	destroyPickInfo(pickInfo);
	return(0);

	exit(1);
	testMenuStructure(pickInfo);
	testPickInfo();
	exit(1);
	printf("sizeof KBDKEYS8 is %d\n", sizeof(KBDKEYS8));
	printf("sizeof struct KEYSTROKES is %d\n", sizeof(struct KEYSTROKES));
	printf("Int value of NULLCHAR is %d\n", (int) NULLCHAR);
	printf("Int value of NULLACTIONTYPE is %d\n", (int) NULLACTIONTYPE);
	testKeystrokes();
	testx();
	testAllKeySymbols();
	testKeySymbol();
/*	testRowsInfo();
	exit(1); */


	exit(2);

	printf("End\n");
	return(0);
	} /*}}}*/
/* END MAIN() }}} */
/* END FUNCTION DEFINITIONS }}} */
