From 0921c57064526f87f6ec7f301667ee38ed07cee2 Mon Sep 17 00:00:00 2001
From: deuce <>
Date: Wed, 21 May 2003 03:35:25 +0000
Subject: [PATCH] New unified uifc/uifcc sources.  Eventually will use same
 source for both Win32/conio and *nix/curses implementations.

---
 src/uifc/ciowrap.c |  629 +++++++++++++++
 src/uifc/ciowrap.h |   49 ++
 src/uifc/uifc32.c  | 1889 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 2567 insertions(+)
 create mode 100644 src/uifc/ciowrap.c
 create mode 100644 src/uifc/ciowrap.h
 create mode 100644 src/uifc/uifc32.c

diff --git a/src/uifc/ciowrap.c b/src/uifc/ciowrap.c
new file mode 100644
index 0000000000..3c39a4b172
--- /dev/null
+++ b/src/uifc/ciowrap.c
@@ -0,0 +1,629 @@
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "ciowrap.h"
+#include "uifc.h"		/* UIFC_IBM */
+
+static int lastattr=0;
+static long mode;
+
+int inkey(int mode)
+{
+	if(mode)
+		return(kbhit());
+	return(getch());
+}
+
+short curses_color(short color)
+{
+	switch(color)
+	{
+		case 0 :
+			return(COLOR_BLACK);
+		case 1 :
+			return(COLOR_BLUE);
+		case 2 :
+			return(COLOR_GREEN);
+		case 3 :
+			return(COLOR_CYAN);
+		case 4 :
+			return(COLOR_RED);
+		case 5 :
+			return(COLOR_MAGENTA);
+		case 6 :
+			return(COLOR_YELLOW);
+		case 7 :
+			return(COLOR_WHITE);
+		case 8 :
+			return(COLOR_BLACK);
+		case 9 :
+			return(COLOR_BLUE);
+		case 10 :
+			return(COLOR_GREEN);
+		case 11 :
+			return(COLOR_CYAN);
+		case 12 :
+			return(COLOR_RED);
+		case 13 :
+			return(COLOR_MAGENTA);
+		case 14 :
+			return(COLOR_YELLOW);
+		case 15 :
+			return(COLOR_WHITE);
+	}
+	return(0);
+}
+
+int puttext(int sx, int sy, int ex, int ey, unsigned char *fill)
+{
+	int x,y;
+	int fillpos=0;
+	unsigned char attr;
+	unsigned char fill_char;
+	unsigned char orig_attr;
+	int oldx, oldy;
+
+	getyx(stdscr,oldy,oldx);	
+	orig_attr=lastattr;
+	for(y=sy-1;y<=ey-1;y++)
+	{
+		for(x=sx-1;x<=ex-1;x++)
+		{
+			fill_char=fill[fillpos++];
+			attr=fill[fillpos++];
+			textattr(attr);
+			move(y, x);
+			_putch(fill_char,FALSE);
+		}
+	}
+	textattr(orig_attr);
+	move(oldy, oldx);
+	refresh();
+	return(1);
+}
+
+int gettext(int sx, int sy, int ex, int ey, unsigned char *fill)
+{
+	int x,y;
+	int fillpos=0;
+	chtype attr;
+	unsigned char attrib;
+	unsigned char colour;
+	int oldx, oldy;
+	unsigned char thischar;
+	int	ext_char;
+
+	getyx(stdscr,oldy,oldx);	
+	for(y=sy-1;y<=ey-1;y++)
+	{
+		for(x=sx-1;x<=ex-1;x++)
+		{
+			attr=mvinch(y, x);
+			if(attr&A_ALTCHARSET && !(mode&UIFC_IBM)){
+				ext_char=A_ALTCHARSET|(attr&255);
+				/* likely ones */
+				if (ext_char == ACS_CKBOARD)
+				{
+					thischar=176;
+				}
+				else if (ext_char == ACS_BOARD)
+				{
+					thischar=177;
+				}
+				else if (ext_char == ACS_BSSB)
+				{
+					thischar=218;
+				}
+				else if (ext_char == ACS_SSBB)
+				{
+					thischar=192;
+				}
+				else if (ext_char == ACS_BBSS)
+				{
+					thischar=191;
+				}
+				else if (ext_char == ACS_SBBS)
+				{
+					thischar=217;
+				}
+				else if (ext_char == ACS_SBSS)
+				{
+					thischar=180;
+				}
+				else if (ext_char == ACS_SSSB)
+				{
+					thischar=195;
+				}
+				else if (ext_char == ACS_SSBS)
+				{
+					thischar=193;
+				}
+				else if (ext_char == ACS_BSSS)
+				{
+					thischar=194;
+				}
+				else if (ext_char == ACS_BSBS)
+				{
+					thischar=196;
+				}
+				else if (ext_char == ACS_SBSB)
+				{
+					thischar=179;
+				}
+				else if (ext_char == ACS_SSSS)
+				{
+					thischar=197;
+				}
+				else if (ext_char == ACS_BLOCK)
+				{
+					thischar=219;
+				}
+				else if (ext_char == ACS_UARROW)
+				{
+					thischar=30;
+				}
+				else if (ext_char == ACS_DARROW)
+				{
+					thischar=31;
+				}
+				
+				/* unlikely (Not in ncurses) */
+				else if (ext_char == ACS_SBSD)
+				{
+					thischar=181;
+				}
+				else if (ext_char == ACS_DBDS)
+				{
+					thischar=182;
+				}
+				else if (ext_char == ACS_BBDS)
+				{
+					thischar=183;
+				}
+				else if (ext_char == ACS_BBSD)
+				{
+					thischar=184;
+				}
+				else if (ext_char == ACS_DBDD)
+				{
+					thischar=185;
+				}
+				else if (ext_char == ACS_DBDB)
+				{
+					thischar=186;
+				}
+				else if (ext_char == ACS_BBDD)
+				{
+					thischar=187;
+				}
+				else if (ext_char == ACS_DBBD)
+				{
+					thischar=188;
+				}
+				else if (ext_char == ACS_DBBS)
+				{
+					thischar=189;
+				}
+				else if (ext_char == ACS_SBBD)
+				{
+					thischar=190;
+				}
+				else if (ext_char == ACS_SDSB)
+				{
+					thischar=198;
+				}
+				else if (ext_char == ACS_DSDB)
+				{
+					thischar=199;
+				}
+				else if (ext_char == ACS_DDBB)
+				{
+					thischar=200;
+				}
+				else if (ext_char == ACS_BDDB)
+				{
+					thischar=201;
+				}
+				else if (ext_char == ACS_DDBD)
+				{
+					thischar=202;
+				}
+				else if (ext_char == ACS_BDDD)
+				{
+					thischar=203;
+				}
+				else if (ext_char == ACS_DDDB)
+				{
+					thischar=204;
+				}
+				else if (ext_char == ACS_BDBD)
+				{
+					thischar=205;
+				}
+				else if (ext_char == ACS_DDDD)
+				{
+					thischar=206;
+				}
+				else if (ext_char == ACS_SDBD)
+				{
+					thischar=207;
+				}
+				else if (ext_char == ACS_DSBS)
+				{
+					thischar=208;
+				}
+				else if (ext_char == ACS_BDSD)
+				{
+					thischar=209;
+				}
+				else if (ext_char == ACS_BSDS)
+				{
+					thischar=210;
+				}
+				else if (ext_char == ACS_DSBB)
+				{
+					thischar=211;
+				}
+				else if (ext_char == ACS_SDBB)
+				{
+					thischar=212;
+				}
+				else if (ext_char == ACS_BDSB)
+				{
+					thischar=213;
+				}
+				else if (ext_char == ACS_BSDB)
+				{
+					thischar=214;
+				}
+				else if (ext_char == ACS_DSDS)
+				{
+					thischar=215;
+				}
+				else if (ext_char == ACS_SDSD)
+				{
+					thischar=216;
+				}
+				else
+				{
+					thischar=attr&255;
+				}
+			}
+			else
+				thischar=attr;
+			fill[fillpos++]=(unsigned char)(thischar);
+			attrib=0;
+			if (attr & A_BOLD)  
+			{
+				attrib |= 8;
+			}
+			if (attr & A_BLINK)
+			{
+				attrib |= 128;
+			}
+			colour=PAIR_NUMBER(attr&A_COLOR)-1;
+			colour=((colour&56)<<1)|(colour&7);
+			fill[fillpos++]=colour|attrib;
+		}
+	}
+	move(oldy, oldx);
+	return(1);
+}
+
+void textattr(unsigned char attr)
+{
+	int   attrs=A_NORMAL;
+	short	colour;
+
+	if (lastattr==attr)
+		return;
+
+	lastattr=attr;
+	
+	if (attr & 8)  {
+		attrs |= A_BOLD;
+	}
+	if (attr & 128)
+	{
+		attrs |= A_BLINK;
+	}
+	attrset(attrs);
+	colour = COLOR_PAIR( ((attr&7)|((attr>>1)&56))+1 );
+	#ifdef NCURSES_VERSION_MAJOR
+	color_set(colour,NULL);
+	#endif
+	bkgdset(colour);
+}
+
+int _kbhit(void)
+{
+	struct timeval timeout;
+	fd_set	rfds;
+	
+	timeout.tv_sec=1;
+	timeout.tv_usec=0;
+	FD_ZERO(&rfds);
+	FD_SET(fileno(stdin),&rfds);
+
+	return(select(fileno(stdin)+1,&rfds,NULL,NULL,&timeout));
+}
+
+#ifndef __QNX__
+void delay(long msec)
+{
+	usleep(msec*1000);
+}
+#endif
+
+int wherey(void)
+{
+	int x,y;
+	getyx(stdscr,y,x);
+	return(y+1);
+}
+
+int wherex(void)
+{
+	int x,y;
+	getyx(stdscr,y,x);
+	return(x+1);
+}
+
+void _putch(unsigned char ch, BOOL refresh_now)
+{
+	int	cha;
+
+	if(!(mode&UIFC_IBM))
+	{
+		switch(ch)
+		{
+			case 30:
+				cha=ACS_UARROW;
+				break;
+			case 31:
+				cha=ACS_DARROW;
+				break;
+			case 176:
+				cha=ACS_CKBOARD;
+				break;
+			case 177:
+				cha=ACS_BOARD;
+				break;
+			case 178:
+				cha=ACS_BOARD;
+				break;
+			case 179:
+				cha=ACS_SBSB;
+				break;
+			case 180:
+				cha=ACS_SBSS;
+				break;
+			case 181:
+				cha=ACS_SBSD;
+				break;
+			case 182:
+				cha=ACS_DBDS;
+				break;
+			case 183:
+				cha=ACS_BBDS;
+				break;
+			case 184:
+				cha=ACS_BBSD;
+				break;
+			case 185:
+				cha=ACS_DBDD;
+				break;
+			case 186:
+				cha=ACS_DBDB;
+				break;
+			case 187:
+				cha=ACS_BBDD;
+				break;
+			case 188:
+				cha=ACS_DBBD;
+				break;
+			case 189:
+				cha=ACS_DBBS;
+				break;
+			case 190:
+				cha=ACS_SBBD;
+				break;
+			case 191:
+				cha=ACS_BBSS;
+				break;
+			case 192:
+				cha=ACS_SSBB;
+				break;
+			case 193:
+				cha=ACS_SSBS;
+				break;
+			case 194:
+				cha=ACS_BSSS;
+				break;
+			case 195:
+				cha=ACS_SSSB;
+				break;
+			case 196:
+				cha=ACS_BSBS;
+				break;
+			case 197:
+				cha=ACS_SSSS;
+				break;
+			case 198:
+				cha=ACS_SDSB;
+				break;
+			case 199:
+				cha=ACS_DSDB;
+				break;
+			case 200:
+				cha=ACS_DDBB;
+				break;
+			case 201:
+				cha=ACS_BDDB;
+				break;
+			case 202:
+				cha=ACS_DDBD;
+				break;
+			case 203:
+				cha=ACS_BDDD;
+				break;
+			case 204:
+				cha=ACS_DDDB;
+				break;
+			case 205:
+				cha=ACS_BDBD;
+				break;
+			case 206:
+				cha=ACS_DDDD;
+				break;
+			case 207:
+				cha=ACS_SDBD;
+				break;
+			case 208:
+				cha=ACS_DSBS;
+				break;
+			case 209:
+				cha=ACS_BDSD;
+				break;
+			case 210:
+				cha=ACS_BSDS;
+				break;
+			case 211:
+				cha=ACS_DSBB;
+				break;
+			case 212:
+				cha=ACS_SDBB;
+				break;
+			case 213:
+				cha=ACS_BDSB;
+				break;
+			case 214:
+				cha=ACS_BSDB;
+				break;
+			case 215:
+				cha=ACS_DSDS;
+				break;
+			case 216:
+				cha=ACS_SDSD;
+				break;
+			case 217:
+				cha=ACS_SBBS;
+				break;
+			case 218:
+				cha=ACS_BSSB;
+				break;
+			case 219:
+				cha=ACS_BLOCK;
+				break;
+			default:
+				cha=ch;
+		}
+	}
+	else
+	{
+		switch(ch) {
+			case 30:
+				cha=ACS_UARROW;
+				break;
+			case 31:
+				cha=ACS_DARROW;
+				break;
+			default:
+				cha=ch;
+		}
+	}
+			
+
+	addch(cha);
+	if(refresh_now)
+		refresh();
+}
+
+int cprintf(char *fmat, ...)
+{
+    va_list argptr;
+	char	str[MAX_BFLN];
+	int		pos;
+
+    va_start(argptr,fmat);
+    vsprintf(str,fmat,argptr);
+    va_end(argptr);
+	for(pos=0;str[pos];pos++)
+	{
+		_putch(str[pos],FALSE);
+	}
+	refresh();
+    return(1);
+}
+
+void cputs(char *str)
+{
+	int		pos;
+
+	for(pos=0;str[pos];pos++)
+	{
+		_putch(str[pos],FALSE);
+	}
+	refresh();
+}
+
+void gotoxy(int x, int y)
+{
+	move(y-1,x-1);
+	refresh();
+}
+
+void clrscr(void)
+{
+    clear();
+	refresh();
+}
+
+void initciowrap(long inmode)
+{
+	short	fg, bg, pair=0;
+
+	initscr();
+	start_color();
+	cbreak();
+	noecho();
+	nonl();
+	keypad(stdscr, TRUE);
+	scrollok(stdscr,FALSE);
+	raw();
+
+	/* Set up color pairs */
+	for(bg=0;bg<8;bg++)  {
+		for(fg=0;fg<8;fg++) {
+			init_pair(++pair,curses_color(fg),curses_color(bg));
+		}
+	}
+	mode = inmode;
+}
+
+void gettextinfo(struct text_info *info)
+{
+	getmaxyx(stdscr, info->screenheight, info->screenwidth);
+	if(has_colors())
+		info->currmode=COLOR_MODE;
+	else
+		info->currmode=MONO;
+}
+
+void _setcursortype(int type) {
+	switch(type) {
+		case _NOCURSOR:
+			curs_set(0);
+			break;
+		
+		case _SOLIDCURSOR:
+			curs_set(2);
+			break;
+		
+		default:	/* Normal cursor */
+			curs_set(1);
+			break;
+			
+	}
+	refresh();
+}
diff --git a/src/uifc/ciowrap.h b/src/uifc/ciowrap.h
new file mode 100644
index 0000000000..0dd67c43de
--- /dev/null
+++ b/src/uifc/ciowrap.h
@@ -0,0 +1,49 @@
+#include "curs_fix.h"
+
+#define MONO	1
+#define	BW80	MONO
+#define COLOR_MODE	2
+#define kbhit()		_kbhit()
+
+#ifndef BOOL
+#define BOOL    int
+#ifndef TRUE
+#define TRUE    1
+#endif
+#ifndef FALSE
+#define FALSE   0
+#endif
+#endif
+
+enum
+{
+	_NOCURSOR,
+	_SOLIDCURSOR,
+	_NORMALCURSOR
+};
+
+struct text_info {
+    unsigned char currmode;
+    unsigned char screenheight;
+	unsigned char screenwidth;
+};
+
+int inkey(int mode);
+short curses_color(short color);
+int puttext(int sx, int sy, int ex, int ey, unsigned char *fill);
+int gettext(int sx, int sy, int ex, int ey, unsigned char *fill);
+void textattr(unsigned char attr);
+int _kbhit(void);
+#ifndef __QNX__
+void delay(long msec);
+#endif
+int wherey(void);
+int wherex(void);
+void _putch(unsigned char ch, BOOL refresh_now);
+int cprintf(char *fmat, ...);
+void cputs(char *str);
+void gotoxy(int x, int y);
+void clrscr(void);
+void initciowrap(long inmode);
+void gettextinfo(struct text_info *info);
+void _setcursortype(int type);
diff --git a/src/uifc/uifc32.c b/src/uifc/uifc32.c
new file mode 100644
index 0000000000..9692228765
--- /dev/null
+++ b/src/uifc/uifc32.c
@@ -0,0 +1,1889 @@
+/* uifcc.c */
+
+/* Curses implementation of UIFC (user interface) library based on uifc.c */
+
+/****************************************************************************
+ * @format.tab-size 4		(Plain Text/Source Code File Header)			*
+ * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
+ *																			*
+ * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html		*
+ *																			*
+ * This library is free software; you can redistribute it and/or			*
+ * modify it under the terms of the GNU Lesser General Public License		*
+ * as published by the Free Software Foundation; either version 2			*
+ * of the License, or (at your option) any later version.					*
+ * See the GNU Lesser General Public License for more details: lgpl.txt or	*
+ * http://www.fsf.org/copyleft/lesser.html									*
+ *																			*
+ * Anonymous FTP access to the most recent released source is available at	*
+ * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
+ *																			*
+ * Anonymous CVS access to the development source and modification history	*
+ * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
+ * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
+ *     (just hit return, no password is necessary)							*
+ * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
+ *																			*
+ * For Synchronet coding style and modification guidelines, see				*
+ * http://www.synchro.net/source.html										*
+ *																			*
+ * You are encouraged to submit any modifications (preferably in Unix diff	*
+ * format) via e-mail to mods@synchro.net									*
+ *																			*
+ * Note: If this box doesn't appear square, then you need to fix your tabs.	*
+ ****************************************************************************/
+
+#ifdef __unix__
+	#include <stdio.h>
+	#include <unistd.h>
+	#ifdef __QNX__
+		#include <strings.h>
+	#endif
+	#include "ciowrap.h"
+    #define mswait(x) delay(x)
+#elif defined(_WIN32)
+	#include <share.h>
+	#include <conio.h>
+	#include <windows.h>
+	#define mswait(x) Sleep(x)
+#endif
+
+#include "uifc.h"
+
+							/* Bottom line elements */
+#define BL_INS      (1<<0)  /* INS key */
+#define BL_DEL      (1<<1)  /* DEL key */
+#define BL_GET      (1<<2)  /* Get key */
+#define BL_PUT      (1<<3)  /* Put key */
+
+enum {
+	 BLACK
+	,BLUE	
+	,GREEN	
+	,CYAN	
+	,RED		
+	,MAGENTA	
+	,BROWN	
+	,LIGHTGRAY	
+	,DARKGRAY	
+	,LIGHTBLUE	
+	,LIGHTGREEN	
+	,LIGHTCYAN	
+	,LIGHTRED	
+	,LIGHTMAGENTA
+	,YELLOW
+	,WHITE
+};
+
+#define BLINK	128
+
+static char  hfclr,hbclr,hclr,lclr,bclr,cclr;
+static int   cursor;
+static char* helpfile=0;
+static uint  helpline=0;
+static char  blk_scrn[MAX_BFLN];
+static win_t sav[MAX_BUFS];
+static uint  max_opts=MAX_OPTS;
+static uifcapi_t* api;
+
+/* Prototypes */
+static int   uprintf(int x, int y, unsigned char attr, char *fmt,...);
+static void  bottomline(int line);
+static char  *utimestr(time_t *intime);
+static void  help();
+static int   ugetstr(char *outstr, int max, long mode);
+static void  timedisplay(void);
+#define putch(x)	_putch(x,TRUE)
+
+/* API routines */
+static void uifcbail(void);
+static int  uscrn(char *str);
+static int  ulist(int mode, int left, int top, int width, int *dflt, int *bar
+	,char *title, char **option);
+static int  uinput(int imode, int left, int top, char *prompt, char *str
+	,int len ,int kmode);
+static void umsg(char *str);
+static void upop(char *str);
+static void sethelp(int line, char* file);
+static void showbuf(int mode, int left, int top, int width, int height, char *title
+	, char *hbuf, int *curp, int *barp);
+
+/* Dynamic menu support */
+static int *last_menu_cur=NULL;
+static int *last_menu_bar=NULL;
+static int save_menu_cur=-1;
+static int save_menu_bar=-1;
+
+static void reset_dynamic(void) {
+	last_menu_cur=NULL;
+	last_menu_bar=NULL;
+	save_menu_cur=-1;
+	save_menu_bar=-1;
+}
+
+/****************************************************************************/
+/* Initialization function, see uifc.h for details.							*/
+/* Returns 0 on success.													*/
+/****************************************************************************/
+
+int uifcini32(uifcapi_t* uifcapi)
+{
+	int 	i;
+	struct	text_info txtinfo;
+
+    if(uifcapi==NULL || uifcapi->size!=sizeof(uifcapi_t))
+        return(-1);
+
+    api=uifcapi;
+
+    /* install function handlers */            
+    api->bail=uifcbail;
+    api->scrn=uscrn;
+    api->msg=umsg;
+    api->pop=upop;
+    api->list=ulist;
+    api->input=uinput;
+    api->sethelp=sethelp;
+    api->showhelp=help;
+	api->showbuf=NULL;
+	api->timedisplay=timedisplay;
+
+#ifdef __unix__
+	initciowrap(api->mode);
+	#ifdef NCURSES_VERSION_MAJOR
+		ESCDELAY=api->esc_delay;
+	#endif
+#else
+    if(api->scrn_len!=0) {
+        switch(api->scrn_len) {
+            case 14:
+                textmode(C80X14);
+                break;
+            case 21:
+                textmode(C80X21);
+                break;
+            case 25:
+                textmode(C80);
+                break;
+            case 28:
+                textmode(C80X28);
+                break;
+            case 43:
+                textmode(C80X43);
+                break;
+            case 50:
+                textmode(C80X50);
+                break;
+            case 60:
+                textmode(C80X60);
+                break;
+            default:
+                textmode(C4350);
+                break;
+        }
+    }
+#endif
+
+    clrscr();
+
+    gettextinfo(&txtinfo);
+#ifdef _WIN32
+    /* unsupported mode? */
+    if(txtinfo.screenheight<MIN_LINES
+        || txtinfo.screenheight>MAX_LINES
+        || txtinfo.screenwidth<80) {
+        textmode(C80);  /* set mode to 80x25*/
+        gettextinfo(&txtinfo);
+    }
+#endif
+
+    api->scrn_len=txtinfo.screenheight;
+    if(api->scrn_len<MIN_LINES || api->scrn_len>MAX_LINES) {
+        cprintf("\7UIFC: Screen length (%u) must be between %d and %d lines\r\n"
+            ,api->scrn_len,MIN_LINES,MAX_LINES);
+        return(-2);
+    }
+    api->scrn_len--; /* account for status line */
+
+    if(txtinfo.screenwidth<80) {
+        cprintf("\7UIFC: Screen width (%u) must be at least 80 characters\r\n"
+            ,txtinfo.screenwidth);
+        return(-3);
+    }
+	api->scrn_width=txtinfo.screenwidth;
+
+    if(!(api->mode&UIFC_COLOR)
+        && (api->mode&UIFC_MONO
+            || txtinfo.currmode==MONO || txtinfo.currmode==BW80)) {
+        bclr=BLACK;
+        hclr=WHITE;
+        lclr=LIGHTGRAY;
+        cclr=LIGHTGRAY;
+		hbclr=BLACK;		/* Highlight Background Colour */
+		hfclr=WHITE;		/* Highlight Foreground Colour */
+    } else {
+        bclr=BLUE;
+        hclr=YELLOW;
+        lclr=WHITE;
+        cclr=CYAN;
+		hbclr=LIGHTGRAY;
+		hfclr=YELLOW;
+    }
+    for(i=0;i<MAX_BFLN;i+=2) {
+        blk_scrn[i]='°';
+        blk_scrn[i+1]=cclr|(bclr<<4);
+    }
+
+    cursor=_NOCURSOR;
+    _setcursortype(cursor);
+
+    return(0);
+}
+
+void uifcbail(void)
+{
+	_setcursortype(_NORMALCURSOR);
+	textattr(LIGHTGRAY);
+	clrscr();
+#ifdef __unix__
+	nl();
+	nocbreak();
+	noraw();
+	refresh();
+	endwin();
+#endif
+}
+
+/****************************************************************************/
+/* Clear screen, fill with background attribute, display application title.	*/
+/* Returns 0 on success.													*/
+/****************************************************************************/
+int uscrn(char *str)
+{
+    textattr(bclr|(cclr<<4));
+    gotoxy(1,1);
+    clrtoeol();
+    gotoxy(3,1);
+	cputs(str);
+    if(!puttext(1,2,api->scrn_width,api->scrn_len,blk_scrn))
+        return(-1);
+    gotoxy(1,api->scrn_len+1);
+    clrtoeol();
+	refresh();
+	reset_dynamic();
+    return(0);
+}
+
+/****************************************************************************/
+/****************************************************************************/
+static void scroll_text(int x1, int y1, int x2, int y2, int down)
+{
+	uchar buf[MAX_BFLN];
+
+	gettext(x1,y1,x2,y2,buf);
+	if(down)
+		puttext(x1,y1+1,x2,y2,buf);
+	else
+		puttext(x1,y1,x2,y2-1,buf+(((x2-x1)+1)*2));
+}
+
+/****************************************************************************/
+/* Updates time in upper left corner of screen with current time in ASCII/  */
+/* Unix format																*/
+/****************************************************************************/
+static void timedisplay()
+{
+	static time_t savetime;
+	time_t now;
+
+	now=time(NULL);
+	if(difftime(now,savetime)>=60) {
+		uprintf(55,1,bclr|(cclr<<4),utimestr(&now));
+		savetime=now; 
+	}
+}
+
+/****************************************************************************/
+/* Truncates white-space chars off end of 'str'								*/
+/****************************************************************************/
+static void truncsp(char *str)
+{
+	uint c;
+
+	c=strlen(str);
+	while(c && (uchar)str[c-1]<=SP) c--;
+	if(str[c]!=0)	/* don't write to string constants */
+		str[c]=0;
+}
+
+/****************************************************************************/
+/* General menu function, see uifc.h for details.							*/
+/****************************************************************************/
+int ulist(int mode, int left, int top, int width, int *cur, int *bar
+	, char *title, char **option)
+{
+	uchar line[256],shade[256],win[MAX_BFLN],*ptr,a,b,c,longopt
+		,search[MAX_OPLN],bline=0;
+	int height,y;
+	int i,j,opts=0,s=0; /* s=search index into options */
+	int	is_redraw=0;
+
+	if(mode&WIN_SAV && api->savnum>=MAX_BUFS-1)
+		putch(7);
+	i=0;
+	if(mode&WIN_INS) bline|=BL_INS;
+	if(mode&WIN_DEL) bline|=BL_DEL;
+	if(mode&WIN_GET) bline|=BL_GET;
+	if(mode&WIN_PUT) bline|=BL_PUT;
+	bottomline(bline);
+	while(opts<max_opts && opts<MAX_OPTS)
+		if(option[opts][0]==0)
+			break;
+		else opts++;
+	if(mode&WIN_XTR && opts<max_opts && opts<MAX_OPTS)
+		option[opts++][0]=0;
+	height=opts+4;
+	if(top+height>api->scrn_len-3)
+		height=(api->scrn_len-3)-top;
+	if(!width || width<strlen(title)+6) {
+		width=strlen(title)+6;
+		for(i=0;i<opts;i++) {
+			truncsp(option[i]);
+			if((j=strlen(option[i])+5)>width)
+				width=j; 
+		}
+	}
+	if(width>(SCRN_RIGHT+1)-SCRN_LEFT)
+		width=(SCRN_RIGHT+1)-SCRN_LEFT;
+	if(mode&WIN_L2R)
+		left=36-(width/2);
+	else if(mode&WIN_RHT)
+		left=SCRN_RIGHT-(width+4+left);
+	if(mode&WIN_T2B)
+		top=(api->scrn_len/2)-(height/2)-2;
+	else if(mode&WIN_BOT)
+		top=api->scrn_len-height-3-top;
+
+	/* Dynamic Menus */
+	if(mode&WIN_DYN
+			&& cur != NULL 
+			&& bar != NULL 
+			&& last_menu_cur==cur 
+			&& last_menu_bar==bar
+			&& save_menu_cur==*cur
+			&& save_menu_bar==*bar)
+		is_redraw=1;
+
+	if(!is_redraw) {
+		if(mode&WIN_SAV && api->savdepth==api->savnum) {
+			if((sav[api->savnum].buf=(char *)MALLOC((width+3)*(height+2)*2))==NULL) {
+				cprintf("UIFC line %d: error allocating %u bytes."
+					,__LINE__,(width+3)*(height+2)*2);
+				return(-1); 
+			}
+			gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width+1
+				,SCRN_TOP+top+height,sav[api->savnum].buf);
+			sav[api->savnum].left=SCRN_LEFT+left;
+			sav[api->savnum].top=SCRN_TOP+top;
+			sav[api->savnum].right=SCRN_LEFT+left+width+1;
+			sav[api->savnum].bot=SCRN_TOP+top+height;
+			api->savdepth++; 
+		}
+		else if(mode&WIN_SAV
+			&& (sav[api->savnum].left!=SCRN_LEFT+left
+			|| sav[api->savnum].top!=SCRN_TOP+top
+			|| sav[api->savnum].right!=SCRN_LEFT+left+width+1
+			|| sav[api->savnum].bot!=SCRN_TOP+top+height)) { /* dimensions have changed */
+			puttext(sav[api->savnum].left,sav[api->savnum].top,sav[api->savnum].right,sav[api->savnum].bot
+				,sav[api->savnum].buf);	/* put original window back */
+			FREE(sav[api->savnum].buf);
+			if((sav[api->savnum].buf=(char *)MALLOC((width+3)*(height+2)*2))==NULL) {
+				cprintf("UIFC line %d: error allocating %u bytes."
+					,__LINE__,(width+3)*(height+2)*2);
+				return(-1); 
+			}
+			gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width+1
+				,SCRN_TOP+top+height,sav[api->savnum].buf);	  /* save again */
+			sav[api->savnum].left=SCRN_LEFT+left;
+			sav[api->savnum].top=SCRN_TOP+top;
+			sav[api->savnum].right=SCRN_LEFT+left+width+1;
+			sav[api->savnum].bot=SCRN_TOP+top+height; 
+		} 
+	}
+
+	if(!is_redraw) {
+		if(mode&WIN_ORG) { /* Clear around menu */
+			if(top)
+				puttext(SCRN_LEFT,SCRN_TOP,SCRN_RIGHT+2,SCRN_TOP+top-1,blk_scrn);
+			if(SCRN_TOP+height+top<=api->scrn_len)
+				puttext(SCRN_LEFT,SCRN_TOP+height+top,SCRN_RIGHT+2,api->scrn_len,blk_scrn);
+			if(left)
+				puttext(SCRN_LEFT,SCRN_TOP+top,SCRN_LEFT+left-1,SCRN_TOP+height+top
+					,blk_scrn);
+			if(SCRN_LEFT+left+width<=SCRN_RIGHT)
+				puttext(SCRN_LEFT+left+width,SCRN_TOP+top,SCRN_RIGHT+2
+					,SCRN_TOP+height+top,blk_scrn); 
+		}
+		ptr=win;
+		*(ptr++)='É';
+		*(ptr++)=hclr|(bclr<<4);
+
+		i=0;
+		for(;i<width-2;i++) {
+			*(ptr++)='Í';
+			*(ptr++)=hclr|(bclr<<4); 
+		}
+		*(ptr++)='»';
+		*(ptr++)=hclr|(bclr<<4);
+		*(ptr++)='º';
+		*(ptr++)=hclr|(bclr<<4);
+		a=strlen(title);
+		b=(width-a-1)/2;
+		for(i=0;i<b;i++) {
+			*(ptr++)=' ';
+			*(ptr++)=hclr|(bclr<<4); 
+		}
+		for(i=0;i<a;i++) {
+			*(ptr++)=title[i];
+			*(ptr++)=hclr|(bclr<<4); 
+		}
+		for(i=0;i<width-(a+b)-2;i++) {
+			*(ptr++)=' ';
+			*(ptr++)=hclr|(bclr<<4); 
+		}
+		*(ptr++)='º';
+		*(ptr++)=hclr|(bclr<<4);
+		*(ptr++)='Ì';
+		*(ptr++)=hclr|(bclr<<4);
+		for(i=0;i<width-2;i++) {
+			*(ptr++)='Í';
+			*(ptr++)=hclr|(bclr<<4); 
+		}
+		*(ptr++)='¹';
+		*(ptr++)=hclr|(bclr<<4);
+
+		if((*cur)>=opts)
+			(*cur)=opts-1;			/* returned after scrolled */
+
+		if(!bar) {
+			if((*cur)>height-5)
+				(*cur)=height-5;
+			i=0; 
+		}
+		else {
+			if((*bar)>=opts)
+				(*bar)=opts-1;
+			if((*bar)>height-5)
+				(*bar)=height-5;
+			if((*cur)==opts-1)
+				(*bar)=height-5;
+			if((*bar)<0)
+				(*bar)=0;
+			if((*cur)<(*bar))
+				(*cur)=(*bar);
+			i=(*cur)-(*bar);
+			if(i+(height-5)>=opts) {
+				i=opts-(height-4);
+				(*cur)=i+(*bar);
+				}
+			}
+			if((*cur)<0)
+				(*cur)=0;
+
+			j=0;
+			if(i<0) i=0;
+			longopt=0;
+			while(j<height-4 && i<opts) {
+				*(ptr++)='º';
+				*(ptr++)=hclr|(bclr<<4);
+				*(ptr++)=' ';
+				*(ptr++)=hclr|(bclr<<4);
+				*(ptr++)='³';
+				*(ptr++)=lclr|(bclr<<4);
+				if(i==(*cur))
+					a=hfclr|(hbclr<<4);
+				else
+					a=lclr|(bclr<<4);
+				b=strlen(option[i]);
+				if(b>longopt)
+					longopt=b;
+				if(b+4>width)
+					b=width-4;
+				for(c=0;c<b;c++) {
+					*(ptr++)=option[i][c];
+					*(ptr++)=a; 
+				}
+				while(c<width-4) {
+					*(ptr++)=' ';
+					*(ptr++)=a;
+					c++; 
+				}
+				*(ptr++)='º';
+				*(ptr++)=hclr|(bclr<<4);
+				i++;
+				j++; 
+			}
+			*(ptr++)='È';
+			*(ptr++)=hclr|(bclr<<4);
+			for(i=0;i<width-2;i++) {
+				*(ptr++)='Í';
+				*(ptr++)=hclr|(bclr<<4); 
+			}
+			*(ptr++)='¼';
+			*(ptr++)=hclr|(bclr<<4);
+			puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width-1
+				,SCRN_TOP+top+height-1,win);
+			if(bar)
+				y=top+3+(*bar);
+			else
+				y=top+3+(*cur);
+			if(opts+4>height && ((!bar && (*cur)!=opts-1)
+				|| (bar && ((*cur)-(*bar))+(height-4)<opts))) {
+				gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
+				textattr(lclr|(bclr<<4));
+				putch(31);	   /* put down arrow */
+				textattr(hclr|(bclr<<4)); 
+			}
+
+			if(bar && (*bar)!=(*cur)) {
+				gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
+				textattr(lclr|(bclr<<4));
+				putch(30);	   /* put the up arrow */
+				textattr(hclr|(bclr<<4)); 
+			}
+
+			if(bclr==BLUE) {
+				gettext(SCRN_LEFT+left+width,SCRN_TOP+top+1,SCRN_LEFT+left+width+1
+					,SCRN_TOP+top+height-1,shade);
+				for(i=1;i<height*4;i+=2)
+					shade[i]=DARKGRAY;
+				puttext(SCRN_LEFT+left+width,SCRN_TOP+top+1,SCRN_LEFT+left+width+1
+					,SCRN_TOP+top+height-1,shade);
+				gettext(SCRN_LEFT+left+2,SCRN_TOP+top+height,SCRN_LEFT+left+width+1
+					,SCRN_TOP+top+height,shade);
+				for(i=1;i<width*2;i+=2)
+					shade[i]=DARKGRAY;
+				puttext(SCRN_LEFT+left+2,SCRN_TOP+top+height,SCRN_LEFT+left+width+1
+					,SCRN_TOP+top+height,shade); 
+			}
+	}
+	else {	/* Is a redraw */
+		i=(*cur)-(*bar);
+		j=2;
+
+		longopt=0;
+		while(j<height-2 && i<opts) {
+			ptr=win;
+			if(i==(*cur))
+				a=hfclr|(hbclr<<4);
+			else
+				a=lclr|(bclr<<4);
+			b=strlen(option[i]);
+			if(b>longopt)
+				longopt=b;
+			if(b+4>width)
+				b=width-4;
+			for(c=0;c<b;c++) {
+				*(ptr++)=option[i][c];
+				*(ptr++)=a; 
+			}
+			while(c<width-4) {
+				*(ptr++)=' ';
+				*(ptr++)=a;
+				c++; 
+			}
+			i++;
+			j++; 
+			puttext(SCRN_LEFT+left+3,SCRN_TOP+top+j,SCRN_LEFT+left+width-2
+				,SCRN_TOP+top+j,win); 
+		}
+		if(bar)
+			y=top+3+(*bar);
+		else
+			y=top+3+(*cur);
+	}
+
+	last_menu_cur=cur;
+	last_menu_bar=bar;
+	while(1) {
+	#if 0					/* debug */
+		gotoxy(30,1);
+		cprintf("y=%2d h=%2d c=%2d b=%2d s=%2d o=%2d"
+			,y,height,*cur,bar ? *bar :0xff,api->savdepth,opts);
+	#endif
+		timedisplay();
+		i=0;
+		if(inkey(1)) {
+			i=inkey(0);
+			if(i==KEY_BACKSPACE || i==BS)
+				i=ESC;
+			if(i>255) {
+				s=0;
+				switch(i) {
+					/* ToDo extended keys */
+					case KEY_HOME:	/* home */
+						if(!opts)
+							break;
+						if(opts+4>height) {
+							gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
+							textattr(lclr|(bclr<<4));
+							putch(' ');    /* Delete the up arrow */
+							gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
+							putch(31);	   /* put the down arrow */
+							uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3
+								,hfclr|(hbclr<<4)
+								,"%-*.*s",width-4,width-4,option[0]);
+							for(i=1;i<height-4;i++)    /* re-display options */
+								uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+i
+									,lclr|(bclr<<4)
+									,"%-*.*s",width-4,width-4,option[i]);
+							(*cur)=0;
+							if(bar)
+								(*bar)=0;
+							y=top+3;
+							break; 
+						}
+						gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						for(i=1;i<width*2;i+=2)
+							line[i]=lclr|(bclr<<4);
+						puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						(*cur)=0;
+						if(bar)
+							(*bar)=0;
+						y=top+3;
+						gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						for(i=1;i<width*2;i+=2)
+							line[i]=hfclr|(hbclr<<4);
+						puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						break;
+					case KEY_UP:	/* up arrow */
+						if(!opts)
+							break;
+						if(!(*cur) && opts+4>height) {
+							gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3); /* like end */
+							textattr(lclr|(bclr<<4));
+							putch(30);	   /* put the up arrow */
+							gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
+							putch(' ');    /* delete the down arrow */
+							for(i=(opts+4)-height,j=0;i<opts;i++,j++)
+								uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+j
+									,i==opts-1 ? hfclr|(hbclr<<4)
+										: lclr|(bclr<<4)
+									,"%-*.*s",width-4,width-4,option[i]);
+							(*cur)=opts-1;
+							if(bar)
+								(*bar)=height-5;
+							y=top+height-2;
+							break; 
+						}
+						gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						for(i=1;i<width*2;i+=2)
+							line[i]=lclr|(bclr<<4);
+						puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						if(!(*cur)) {
+							y=top+height-2;
+							(*cur)=opts-1;
+							if(bar)
+								(*bar)=height-5; 
+						}
+						else {
+							(*cur)--;
+							y--;
+							if(bar && *bar)
+								(*bar)--; 
+						}
+						if(y<top+3) {	/* scroll */
+							if(!(*cur)) {
+								gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
+								textattr(lclr|(bclr<<4));
+								putch(' '); /* delete the up arrow */
+							}  
+							if((*cur)+height-4==opts-1) {
+								gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
+								textattr(lclr|(bclr<<4));
+								putch(31);	/* put the dn arrow */
+							}
+							y++;
+							scroll_text(SCRN_LEFT+left+2,SCRN_TOP+top+3
+								,SCRN_LEFT+left+width-3,SCRN_TOP+top+height-2,1);
+							uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3
+								,hfclr|(hbclr<<4)
+								,"%-*.*s",width-4,width-4,option[*cur]);
+						}
+						else {
+							gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+								,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+							for(i=1;i<width*2;i+=2)
+								line[i]=hfclr|(hbclr<<4);
+							puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+								,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						}
+						break;
+#if 0
+					case KEY_PPAGE;	/* PgUp */
+					case KEY_NPAGE;	/* PgDn */
+						if(!opts || (*cur)==(opts-1))
+							break;
+						(*cur)+=(height-4);
+						if((*cur)>(opts-1))
+							(*cur)=(opts-1);
+
+						gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						for(i=1;i<width*2;i+=2)
+							line[i]=lclr|(bclr<<4);
+						puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+
+						for(i=(opts+4)-height,j=0;i<opts;i++,j++)
+							uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+j
+								,i==(*cur) hfclr|(hbclr<<4) : lclr|(bclr<<4)
+								,"%-*.*s",width-4,width-4,option[i]);
+						y=top+height-2;
+						if(bar)
+							(*bar)=height-5;
+						gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						for(i=1;i<148;i+=2)
+							line[i]=hfclr|(hbclr<<4);
+						puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						break;
+#endif
+					case KEY_END:	/* end */
+						if(!opts)
+							break;
+						if(opts+4>height) {	/* Scroll mode */
+							gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
+							textattr(lclr|(bclr<<4));
+							putch(30);	   /* put the up arrow */
+							gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
+							putch(' ');    /* delete the down arrow */
+							for(i=(opts+4)-height,j=0;i<opts;i++,j++)
+								uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+j
+									,i==opts-1 ? hfclr|(hbclr<<4)
+										: lclr|(bclr<<4)
+									,"%-*.*s",width-4,width-4,option[i]);
+							(*cur)=opts-1;
+							y=top+height-2;
+							if(bar)
+								(*bar)=height-5;
+							break; 
+						}
+						gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						for(i=1;i<width*2;i+=2)
+							line[i]=lclr|(bclr<<4);
+						puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						(*cur)=opts-1;
+						y=top+height-2;
+						if(bar)
+							(*bar)=height-5;
+						gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						for(i=1;i<148;i+=2)
+							line[i]=hfclr|(hbclr<<4);
+						puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						break;
+					case KEY_DOWN:	/* dn arrow */
+						if(!opts)
+							break;
+						if((*cur)==opts-1 && opts+4>height) { /* like home */
+							gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
+							textattr(lclr|(bclr<<4));
+							putch(' ');    /* Delete the up arrow */
+							gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
+							putch(31);	   /* put the down arrow */
+							uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3
+								,hfclr|(hbclr<<4)
+								,"%-*.*s",width-4,width-4,option[0]);
+							for(i=1;i<height-4;i++)    /* re-display options */
+								uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+i
+									,lclr|(bclr<<4)
+									,"%-*.*s",width-4,width-4,option[i]);
+							(*cur)=0;
+							y=top+3;
+							if(bar)
+								(*bar)=0;
+							break; 
+						}
+						gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						for(i=1;i<width*2;i+=2)
+							line[i]=lclr|(bclr<<4);
+						puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+							,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+						if((*cur)==opts-1) {
+							(*cur)=0;
+							y=top+3;
+							if(bar) {
+								/* gotoxy(1,1); cprintf("bar=%08lX ",bar); */
+								(*bar)=0; 
+							} 
+						}
+						else {
+							(*cur)++;
+							y++;
+							if(bar && (*bar)<height-5) {
+								/* gotoxy(1,1); cprintf("bar=%08lX ",bar); */
+								(*bar)++; 
+							} 
+						}
+						if(y==top+height-1) {	/* scroll */
+							if(*cur==opts-1) {
+								gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
+								textattr(lclr|(bclr<<4));
+								putch(' ');	/* delete the down arrow */
+							}
+							if((*cur)+4==height) {
+								gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
+								textattr(lclr|(bclr<<4));
+								putch(30);	/* put the up arrow */
+							}
+							y--;
+							/* gotoxy(1,1); cprintf("\rdebug: %4d ",__LINE__); */
+							scroll_text(SCRN_LEFT+left+2,SCRN_TOP+top+3
+								,SCRN_LEFT+left+width-3,SCRN_TOP+top+height-2,0);
+							/* gotoxy(1,1); cprintf("\rdebug: %4d ",__LINE__); */
+							uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+height-2
+								,hfclr|(hbclr<<4)
+								,"%-*.*s",width-4,width-4,option[*cur]);
+						}
+						else {
+							gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+								,SCRN_LEFT+left+width-2,SCRN_TOP+y
+								,line);
+							for(i=1;i<width*2;i+=2)
+								line[i]=hfclr|(hbclr<<4);
+							puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+								,SCRN_LEFT+left+width-2,SCRN_TOP+y
+								,line);
+						}
+						break;
+					case KEY_F(1):	/* F1 */
+						help();
+						break;
+					case KEY_F(5):	/* F5 */
+						if(mode&WIN_GET && !(mode&WIN_XTR && (*cur)==opts-1)) {
+							return((*cur)|MSK_GET); 
+						}
+						break;
+					case KEY_F(6):	/* F6 */
+						if(mode&WIN_PUT && !(mode&WIN_XTR && (*cur)==opts-1)) {
+							return((*cur)|MSK_PUT); 
+						}
+						break;
+					case KEY_IC:	/* insert */
+						if(mode&WIN_INS) {
+							if(mode&WIN_INSACT) {
+								gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+									+left+width-1,SCRN_TOP+top+height-1,win);
+								for(i=1;i<(width*height*2);i+=2)
+									win[i]=lclr|(cclr<<4);
+								if(opts) {
+									j=(((y-top)*width)*2)+7+((width-4)*2);
+									for(i=(((y-top)*width)*2)+7;i<j;i+=2)
+										win[i]=hclr|(cclr<<4); 
+								}
+								puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+									+left+width-1,SCRN_TOP+top+height-1,win);
+							}
+							if(!opts) {
+								return(MSK_INS); 
+							}
+							return((*cur)|MSK_INS); 
+						}
+						break;
+					case KEY_DC:	/* delete */
+						if(mode&WIN_XTR && (*cur)==opts-1)	/* can't delete */
+							break;							/* extra line */
+						if(mode&WIN_DEL) {
+							if(mode&WIN_DELACT) {
+								gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+									+left+width-1,SCRN_TOP+top+height-1,win);
+								for(i=1;i<(width*height*2);i+=2)
+									win[i]=lclr|(cclr<<4);
+								j=(((y-top)*width)*2)+7+((width-4)*2);
+								for(i=(((y-top)*width)*2)+7;i<j;i+=2)
+									win[i]=hclr|(cclr<<4);
+								puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+									+left+width-1,SCRN_TOP+top+height-1,win);
+							}
+							return((*cur)|MSK_DEL); 
+						}
+						break;
+				} 
+			}
+			else {
+				i&=0xff;
+				if(isalnum(i) && opts && option[0][0]) {
+					search[s]=i;
+					search[s+1]=0;
+					for(j=(*cur)+1,a=b=0;a<2;j++) {   /* a = search count */
+						if(j==opts) {					/* j = option count */
+							j=-1;						/* b = letter count */
+							continue; 
+						}
+						if(j==(*cur)) {
+							b++;
+							continue; 
+						}
+						if(b>=longopt) {
+							b=0;
+							a++; 
+						}
+						if(a==1 && !s)
+							break;
+						if(strlen(option[j])>b
+							&& ((!a && s && !strncasecmp(option[j]+b,search,s+1))
+							|| ((a || !s) && toupper(option[j][b])==toupper(i)))) {
+							if(a) s=0;
+							else s++;
+							if(y+(j-(*cur))+2>height+top) {
+								(*cur)=j;
+								gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
+								textattr(lclr|(bclr<<4));
+								putch(30);	   /* put the up arrow */
+								if((*cur)==opts-1) {
+									gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
+									putch(' ');	/* delete the down arrow */
+								}
+								for(i=((*cur)+5)-height,j=0;i<(*cur)+1;i++,j++)
+									uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+j
+										,i==(*cur) ? hfclr|(hbclr<<4)
+											: lclr|(bclr<<4)
+										,"%-*.*s",width-4,width-4,option[i]);
+								y=top+height-2;
+								if(bar)
+									(*bar)=height-5;
+								break; 
+							}
+							if(y-((*cur)-j)<top+3) {
+								(*cur)=j;
+								gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+3);
+								textattr(lclr|(bclr<<4));
+								if(!(*cur))
+									putch(' ');    /* Delete the up arrow */
+								gotoxy(SCRN_LEFT+left+1,SCRN_TOP+top+height-2);
+								putch(31);	   /* put the down arrow */
+								uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3
+									,hfclr|(hbclr<<4)
+									,"%-*.*s",width-4,width-4,option[(*cur)]);
+								for(i=1;i<height-4;i++) 	/* re-display options */
+									uprintf(SCRN_LEFT+left+3,SCRN_TOP+top+3+i
+										,lclr|(bclr<<4)
+										,"%-*.*s",width-4,width-4
+										,option[(*cur)+i]);
+								y=top+3;
+								if(bar)
+									(*bar)=0;
+								break; 
+							}
+							gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+								,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+							for(i=1;i<width*2;i+=2)
+								line[i]=lclr|(bclr<<4);
+							puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+								,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+							if((*cur)>j)
+								y-=(*cur)-j;
+							else
+								y+=j-(*cur);
+							if(bar) {
+								if((*cur)>j)
+									(*bar)-=(*cur)-j;
+								else
+									(*bar)+=j-(*cur); 
+							}
+							(*cur)=j;
+							gettext(SCRN_LEFT+3+left,SCRN_TOP+y
+								,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+							for(i=1;i<width*2;i+=2)
+								line[i]=hfclr|(hbclr<<4);
+							puttext(SCRN_LEFT+3+left,SCRN_TOP+y
+								,SCRN_LEFT+left+width-2,SCRN_TOP+y,line);
+							break; 
+						} 
+					}
+					if(a==2)
+						s=0; 
+				}
+				else
+					switch(i) {
+						case CR:
+							if(!opts || (mode&WIN_XTR && (*cur)==opts-1))
+								break;
+							if(mode&WIN_ACT) {
+								gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+									+left+width-1,SCRN_TOP+top+height-1,win);
+								for(i=1;i<(width*height*2);i+=2)
+									win[i]=lclr|(cclr<<4);
+								j=(((y-top)*width)*2)+7+((width-4)*2);
+								for(i=(((y-top)*width)*2)+7;i<j;i+=2)
+									win[i]=hclr|(cclr<<4);
+
+								puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+									+left+width-1,SCRN_TOP+top+height-1,win);
+							}
+							else if(mode&WIN_SAV) {
+								puttext(sav[api->savnum].left,sav[api->savnum].top
+									,sav[api->savnum].right,sav[api->savnum].bot
+									,sav[api->savnum].buf);
+								FREE(sav[api->savnum].buf);
+								api->savdepth--; 
+							}
+							return(*cur);
+						case 3:
+						case ESC:
+							if((mode&WIN_ESC || (mode&WIN_CHE && api->changes))
+								&& !(mode&WIN_SAV)) {
+								gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+									+left+width-1,SCRN_TOP+top+height-1,win);
+								for(i=1;i<(width*height*2);i+=2)
+									win[i]=lclr|(cclr<<4);
+								puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT
+									+left+width-1,SCRN_TOP+top+height-1,win);
+							}
+							else if(mode&WIN_SAV) {
+								puttext(sav[api->savnum].left,sav[api->savnum].top
+									,sav[api->savnum].right,sav[api->savnum].bot
+									,sav[api->savnum].buf);
+								FREE(sav[api->savnum].buf);
+								api->savdepth--; 
+							}
+							return(-1);
+				} 
+			} 
+		}
+		else
+			mswait(1);
+		if(mode&WIN_DYN) {
+			save_menu_cur=*cur;
+			save_menu_bar=*bar;
+			return(-2-i);
+		}
+	}
+}
+
+
+/*************************************************************************/
+/* This function is a windowed input string input routine.               */
+/*************************************************************************/
+int uinput(int mode, int left, int top, char *prompt, char *str,
+	int max, int kmode)
+{
+	unsigned char c,save_buf[2048],in_win[2048]
+		,shade[160],width,height=3;
+	int i,plen,slen;
+
+	reset_dynamic();
+	plen=strlen(prompt);
+	if(!plen)
+		slen=4;
+	else
+		slen=6;
+	width=plen+slen+max;
+	if(mode&WIN_T2B)
+		top=(api->scrn_len/2)-(height/2)-2;
+	if(mode&WIN_L2R)
+		left=36-(width/2);
+	if(mode&WIN_SAV)
+		gettext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width+1
+			,SCRN_TOP+top+height,save_buf);
+	i=0;
+	in_win[i++]='É';
+	in_win[i++]=hclr|(bclr<<4);
+	for(c=1;c<width-1;c++) {
+		in_win[i++]='Í';
+		in_win[i++]=hclr|(bclr<<4); 
+	}
+	in_win[i++]='»';
+	in_win[i++]=hclr|(bclr<<4);
+	in_win[i++]='º';
+	in_win[i++]=hclr|(bclr<<4);
+
+	if(plen) {
+		in_win[i++]=SP;
+		in_win[i++]=lclr|(bclr<<4); 
+	}
+
+	for(c=0;prompt[c];c++) {
+		in_win[i++]=prompt[c];
+		in_win[i++]=lclr|(bclr<<4); 
+	}
+
+	if(plen) {
+		in_win[i++]=':';
+		in_win[i++]=lclr|(bclr<<4);
+		c++; 
+	}
+
+	for(c=0;c<max+2;c++) {
+		in_win[i++]=SP;
+		in_win[i++]=lclr|(bclr<<4); 
+	}
+
+	in_win[i++]='º';
+	in_win[i++]=hclr|(bclr<<4);
+	in_win[i++]='È';
+	in_win[i++]=hclr|(bclr<<4);
+	for(c=1;c<width-1;c++) {
+		in_win[i++]='Í';
+		in_win[i++]=hclr|(bclr<<4); 
+	}
+	in_win[i++]='¼';
+	in_win[i++]=hclr|(bclr<<4);
+	puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width-1
+		,SCRN_TOP+top+height-1,in_win);
+
+	if(bclr==BLUE) {
+		gettext(SCRN_LEFT+left+width,SCRN_TOP+top+1,SCRN_LEFT+left+width+1
+			,SCRN_TOP+top+(height-1),shade);
+		for(c=1;c<12;c+=2)
+			shade[c]=DARKGRAY;
+		puttext(SCRN_LEFT+left+width,SCRN_TOP+top+1,SCRN_LEFT+left+width+1
+			,SCRN_TOP+top+(height-1),shade);
+		gettext(SCRN_LEFT+left+2,SCRN_TOP+top+3,SCRN_LEFT+left+width+1
+			,SCRN_TOP+top+height,shade);
+		for(c=1;c<width*2;c+=2)
+			shade[c]=DARKGRAY;
+		puttext(SCRN_LEFT+left+2,SCRN_TOP+top+3,SCRN_LEFT+left+width+1
+			,SCRN_TOP+top+height,shade); 
+	}
+
+	textattr(lclr|(bclr<<4));
+	if(!plen)
+		gotoxy(SCRN_LEFT+left+2,SCRN_TOP+top+1);
+	else
+		gotoxy(SCRN_LEFT+left+plen+4,SCRN_TOP+top+1);
+	i=ugetstr(str,max,kmode);
+	if(mode&WIN_SAV)
+		puttext(SCRN_LEFT+left,SCRN_TOP+top,SCRN_LEFT+left+width+1
+			,SCRN_TOP+top+height,save_buf);
+	return(i);
+}
+
+/****************************************************************************/
+/* Displays the message 'str' and waits for the user to select "OK"         */
+/****************************************************************************/
+void umsg(char *str)
+{
+	int i=0;
+	char *ok[2]={"OK",""};
+
+	if(api->mode&UIFC_INMSG)	/* non-cursive */
+		return;
+	api->mode|=UIFC_INMSG;
+	if(api->savdepth) api->savnum++;
+	ulist(WIN_SAV|WIN_MID,0,0,0,&i,0,str,ok);
+	if(api->savdepth) api->savnum--;
+	api->mode&=~UIFC_INMSG;
+}
+
+/****************************************************************************/
+/* Gets a string of characters from the user. Turns cursor on. Allows 	    */
+/* Different modes - K_* macros. ESC aborts input.                          */
+/* Cursor should be at END of where string prompt will be placed.           */
+/****************************************************************************/
+static int ugetstr(char *outstr, int max, long mode)
+{
+	uchar   str[256],ins=0,buf[256],y;
+	int		ch;
+	int     i,j,k,f=0;	/* i=offset, j=length */
+
+	cursor=_NORMALCURSOR;
+	_setcursortype(cursor);
+	y=wherey();
+	if(mode&K_EDIT && outstr[0]) {
+	/***
+		truncsp(outstr);
+	***/
+		outstr[max]=0;
+		textattr(hfclr|(hbclr<<4));
+		cputs(outstr);
+		textattr(lclr|(bclr<<4));
+		strcpy(str,outstr);
+		i=j=strlen(str);
+#if 0
+		while(inkey(1)==0) {
+			mswait(1);
+		}
+#endif
+		f=inkey(0);
+		gotoxy(wherex()-i,y);
+		if(f == CR || f >= 0xff)
+		{
+			cputs(outstr);
+		}
+		else
+		{
+			cprintf("%*s",i,"");
+			gotoxy(wherex()-i,y);
+			i=j=0;
+		}
+	}
+	else
+		i=j=0;
+
+	ch=0;
+	while(ch!=CR)
+	{
+		if(i>j) j=i;
+		if(f || inkey(1))
+		{
+			if(f)
+				ch=f;
+			else
+				ch=inkey(0);
+			f=0;
+			switch(ch)
+			{
+				case KEY_F(1):	/* F1 Help */
+					help();
+					continue;
+				case KEY_LEFT:	/* left arrow */
+					if(i)
+					{
+						gotoxy(wherex()-1,y);
+						i--;
+					}
+					continue;
+				case KEY_RIGHT:	/* right arrow */
+					if(i<j)
+					{
+						gotoxy(wherex()+1,y);
+						i++;
+					}
+					continue;
+				case KEY_HOME:	/* home */
+					if(i)
+					{
+						gotoxy(wherex()-i,y);
+						i=0;
+					}
+					continue;
+				case KEY_END:	/* end */
+					if(i<j)
+					{
+						gotoxy(wherex()+(j-i),y);
+						i=j;
+					}
+					continue;
+				case KEY_IC:	/* insert */
+					ins=!ins;
+					if(ins)
+						cursor=_SOLIDCURSOR;
+					else
+						cursor=_NORMALCURSOR;
+					_setcursortype(cursor);
+					continue;
+				case BS:
+				case KEY_BACKSPACE:
+					if(i)
+					{
+						if(i==j)
+						{
+							cputs("\b \b");
+							j--;
+							i--;
+						}
+						else {
+							gettext(wherex(),y,wherex()+(j-i),y,buf);
+							puttext(wherex()-1,y,wherex()+(j-i)-1,y,buf);
+							gotoxy(wherex()+(j-i),y);
+							putch(SP);
+							gotoxy(wherex()-((j-i)+2),y);
+							i--;
+							j--;
+							for(k=i;k<j;k++)
+								str[k]=str[k+1]; 
+						}
+						continue; 
+					}
+				case KEY_DC:	/* delete */
+					if(i<j)
+					{
+						gettext(wherex()+1,y,wherex()+(j-i),y,buf);
+						puttext(wherex(),y,wherex()+(j-i)-1,y,buf);
+						gotoxy(wherex()+(j-i),y);
+						putch(SP);
+						gotoxy(wherex()-((j-i)+1),y);
+						for(k=i;k<j;k++)
+							str[k]=str[k+1];
+						j--;
+					}
+					continue;
+				case 3:
+				case ESC:
+					{
+						cursor=_NOCURSOR;
+						_setcursortype(cursor);
+						return(-1);
+					}
+				case CR:
+					break;
+				case 24:   /* ctrl-x  */
+					if(j)
+					{
+						gotoxy(wherex()-i,y);
+						cprintf("%*s",j,"");
+						gotoxy(wherex()-j,y);
+						i=j=0;
+					}
+					continue;
+				case 25:   /* ctrl-y */
+					if(i<j)
+					{
+						cprintf("%*s",(j-i),"");
+						gotoxy(wherex()-(j-i),y);
+						j=i;
+					}
+					continue;
+			}
+			if(mode&K_NUMBER && !isdigit(ch))
+				continue;
+			if(mode&K_ALPHA && !isalpha(ch))
+				continue;
+			if((ch>=SP || (ch==1 && mode&K_MSG)) && i<max && (!ins || j<max) && isprint(ch))
+			{
+				if(mode&K_UPPER)
+					ch=toupper(ch);
+				if(ins)
+				{
+					gettext(wherex(),y,wherex()+(j-i),y,buf);
+					puttext(wherex()+1,y,wherex()+(j-i)+1,y,buf);
+					for(k=++j;k>i;k--)
+						str[k]=str[k-1];
+				}
+				putch(ch);
+				str[i++]=ch; 
+			} 
+		}
+		else
+			mswait(1);
+	}
+
+
+	str[j]=0;
+	if(mode&K_EDIT)
+	{
+		truncsp(str);
+		if(strcmp(outstr,str))
+			api->changes=1;
+	}
+	else
+	{
+		if(j)
+			api->changes=1;
+	}
+	strcpy(outstr,str);
+	cursor=_NOCURSOR;
+	_setcursortype(cursor);
+	return(j);
+}
+
+/****************************************************************************/
+/* Performs printf() through puttext() routine								*/
+/****************************************************************************/
+static int uprintf(int x, int y, unsigned char attr, char *fmat, ...)
+{
+	va_list argptr;
+	char str[256],buf[512];
+	int i,j;
+
+    va_start(argptr,fmat);
+    vsprintf(str,fmat,argptr);
+    va_end(argptr);
+    for(i=j=0;str[i];i++) {
+        buf[j++]=str[i];
+        buf[j++]=attr; 
+	}
+    puttext(x,y,x+(i-1),y,buf);
+    return(i);
+}
+
+
+/****************************************************************************/
+/* Display bottom line of screen in inverse                                 */
+/****************************************************************************/
+void bottomline(int line)
+{
+	int i=4;
+
+	uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"F1 ");
+	i+=3;
+	uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Help  ");
+	i+=6;
+	if(line&BL_GET) {
+		uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"F5 ");
+		i+=3;
+		uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Copy Item  ");
+		i+=11; 
+	}
+	if(line&BL_PUT) {
+		uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"F6 ");
+		i+=3;
+		uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Paste  ");
+		i+=7; 
+	}
+	if(line&BL_INS) {
+		uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"INS ");
+		i+=4;
+		uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Add Item  ");
+		i+=10; 
+	}
+	if(line&BL_DEL) {
+		uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"DEL ");
+		i+=4;
+		uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Delete Item  ");
+		i+=13; 
+	}
+	uprintf(i,api->scrn_len+1,bclr|(cclr<<4),"ESC ");	/* Backspace is no good no way to abort editing */
+	i+=4;
+	uprintf(i,api->scrn_len+1,BLACK|(cclr<<4),"Exit");
+	i+=4;
+	gotoxy(i,api->scrn_len+1);
+	textattr(BLACK|(cclr<<4));
+	clrtoeol();
+}
+
+
+/*****************************************************************************/
+/* Generates a 24 character ASCII string that represents the time_t pointer  */
+/* Used as a replacement for ctime()                                         */
+/*****************************************************************************/
+char *utimestr(time_t *intime)
+{
+	static char str[25];
+	char wday[4],mon[4],mer[3],hour;
+	struct tm *gm;
+
+	gm=localtime(intime);
+	switch(gm->tm_wday) {
+		case 0:
+			strcpy(wday,"Sun");
+			break;
+		case 1:
+			strcpy(wday,"Mon");
+			break;
+		case 2:
+			strcpy(wday,"Tue");
+			break;
+		case 3:
+			strcpy(wday,"Wed");
+			break;
+		case 4:
+			strcpy(wday,"Thu");
+			break;
+		case 5:
+			strcpy(wday,"Fri");
+			break;
+		case 6:
+			strcpy(wday,"Sat");
+			break; 
+	}
+	switch(gm->tm_mon) {
+		case 0:
+			strcpy(mon,"Jan");
+			break;
+		case 1:
+			strcpy(mon,"Feb");
+			break;
+		case 2:
+			strcpy(mon,"Mar");
+			break;
+		case 3:
+			strcpy(mon,"Apr");
+			break;
+		case 4:
+			strcpy(mon,"May");
+			break;
+		case 5:
+			strcpy(mon,"Jun");
+			break;
+		case 6:
+			strcpy(mon,"Jul");
+			break;
+		case 7:
+			strcpy(mon,"Aug");
+			break;
+		case 8:
+			strcpy(mon,"Sep");
+			break;
+		case 9:
+			strcpy(mon,"Oct");
+			break;
+		case 10:
+			strcpy(mon,"Nov");
+			break;
+		case 11:
+			strcpy(mon,"Dec");
+			break; 
+	}
+	if(gm->tm_hour>12) {
+		strcpy(mer,"pm");
+		hour=gm->tm_hour-12; 
+	}
+	else {
+		if(!gm->tm_hour)
+			hour=12;
+		else
+			hour=gm->tm_hour;
+		strcpy(mer,"am"); 
+	}
+	sprintf(str,"%s %s %02d %4d %02d:%02d %s",wday,mon,gm->tm_mday,1900+gm->tm_year
+		,hour,gm->tm_min,mer);
+	return(str);
+}
+
+/****************************************************************************/
+/* Status popup/down function, see uifc.h for details.						*/
+/****************************************************************************/
+void upop(char *str)
+{
+	static char sav[26*3*2];
+	char buf[26*3*2];
+	int i,j,k;
+
+	reset_dynamic();
+	if(!str) {
+		puttext(28,12,53,14,sav);
+		return; 
+	}
+	gettext(28,12,53,14,sav);
+	memset(buf,SP,25*3*2);
+	for(i=1;i<26*3*2;i+=2)
+		buf[i]=(hclr|(bclr<<4));
+		buf[0]='Ú';
+	for(i=2;i<25*2;i+=2)
+        buf[i]='Ä';
+		buf[i]='¿'; i+=2;
+        buf[i]='³'; i+=2;
+	i+=2;
+	k=strlen(str);
+	i+=(((23-k)/2)*2);
+	for(j=0;j<k;j++,i+=2) {
+		buf[i]=str[j];
+		buf[i+1]|=BLINK; 
+	}
+	i=((25*2)+1)*2;
+        buf[i]='³'; i+=2;
+        buf[i]='À'; i+=2;
+	for(;i<((26*3)-1)*2;i+=2)
+        buf[i]='Ä';
+    buf[i]='Ù';
+
+	puttext(28,12,53,14,buf);
+}
+
+/****************************************************************************/
+/* Sets the current help index by source code file and line number.			*/
+/****************************************************************************/
+void sethelp(int line, char* file)
+{
+    helpline=line;
+    helpfile=file;
+}
+
+/****************************************************************************/
+/* Shows a scrollable text buffer - optionally parsing "help markup codes"	*/
+/****************************************************************************/
+void showbuf(int mode, int left, int top, int width, int height, char *title, char *hbuf, int *curp, int *barp)
+{
+	char *savscrn,inverse=0,high=0;
+	char *buf;
+	char *textbuf;
+    char *p;
+	uint i,j,k,len;
+	int	 lines;
+	int pad=1;
+	int	is_redraw=0;
+
+	_setcursortype(_NOCURSOR);
+
+	if(top+height>api->scrn_len-3)
+		height=(api->scrn_len-3)-top;
+	if(!width || width<strlen(title)+6)
+		width=strlen(title)+6;
+	if(width>api->scrn_width)
+		width=api->scrn_width;
+	if(mode&WIN_L2R)
+		left=(api->scrn_width-width)/2+1;
+	else if(mode&WIN_RHT)
+		left=api->scrn_width-(width+4+left);
+	if(mode&WIN_T2B)
+		top=(api->scrn_len/2)-(height/2)-2;
+	else if(mode&WIN_BOT)
+		top=api->scrn_len-height-3-top;
+
+	if(mode&WIN_PACK)
+		pad=0;
+
+	/* Dynamic Menus */
+	if(mode&WIN_DYN
+			&& curp != NULL 
+			&& barp != NULL 
+			&& last_menu_cur==curp
+			&& last_menu_bar==barp
+			&& save_menu_cur==*curp
+			&& save_menu_bar==*barp)
+		is_redraw=1;
+
+	if((savscrn=(char *)MALLOC(api->scrn_width*api->scrn_len*2))==NULL) {
+		cprintf("UIFC line %d: error allocating %u bytes\r\n"
+			,__LINE__,api->scrn_width*25*2);
+		_setcursortype(cursor);
+		return; 
+	}
+	if((buf=(char *)MALLOC(width*height*2))==NULL) {
+		cprintf("UIFC line %d: error allocating %u bytes\r\n"
+			,__LINE__,width*21*2);
+		FREE(savscrn);
+		_setcursortype(cursor);
+		return; 
+	}
+	gettext(1,1,api->scrn_width,api->scrn_len,savscrn);
+
+	if(!is_redraw) {
+		memset(buf,SP,width*height*2);
+		for(i=1;i<width*height*2;i+=2)
+			buf[i]=(hclr|(bclr<<4));
+	    buf[0]='Ú';
+		j=strlen(title);
+		if(j>width-6)
+			*(title+width-6)=0;
+		for(i=2;i<((width-6)/2-(j/2))*2;i+=2)
+   		      buf[i]='Ä';
+	    buf[i]='´'; i+=4;
+		for(p=title;*p;p++) {
+			buf[i]=*p;
+			i+=2;
+		}
+		i+=2;
+   		buf[i]='Ã'; i+=2;
+		for(j=i;j<((width-1)*2);j+=2)
+   		    buf[j]='Ä';
+		i=j;
+    	buf[i]='¿'; i+=2;
+		j=i;	/* leave i alone */
+		for(k=0;k<(height-2);k++) { 		/* the sides of the box */
+	        buf[j]='³'; j+=2;
+			j+=((width-2)*2);
+        	buf[j]='³'; j+=2; 
+		}
+	    buf[j]='À'; j+=2;
+		if(!(mode&WIN_DYN) && (width>31)) {
+			for(k=j;k<j+(((width-4)/2-13)*2);k+=2)
+				buf[k]='Ä';
+			buf[k]='´'; k+=4;
+			buf[k]='H'; k+=2;
+			buf[k]='i'; k+=2;
+			buf[k]='t'; k+=4;
+			buf[k]='a'; k+=2;
+			buf[k]='n'; k+=2;
+			buf[k]='y'; k+=4;
+			buf[k]='k'; k+=2;
+			buf[k]='e'; k+=2;
+			buf[k]='y'; k+=4;
+			buf[k]='t'; k+=2;
+			buf[k]='o'; k+=4;
+			buf[k]='c'; k+=2;
+			buf[k]='o'; k+=2;
+			buf[k]='n'; k+=2;
+			buf[k]='t'; k+=2;
+			buf[k]='i'; k+=2;
+			buf[k]='n'; k+=2;
+			buf[k]='u'; k+=2;
+			buf[k]='e'; k+=4;
+	    	buf[k]='Ã'; k+=2;
+			for(j=k;j<k+(((width-4)/2-12)*2);j+=2)
+		        buf[j]='Ä';
+		}	
+		else {
+			for(k=j;k<j+((width-2)*2);k+=2)
+				buf[k]='Ä';
+			j=k;
+		}
+	    buf[j]='Ù';
+		puttext(left,top+1,left+width-1,top+height,buf);
+	}
+	len=strlen(hbuf);
+	
+	i=0;
+	lines=1;		/* The first one is free */
+	k=0;
+	for(j=0;j<len;j++) {
+		k++;
+		if(hbuf[j]==LF)
+			lines++;
+		if(k>72) {
+			k=0;
+			lines++;
+		}
+	}
+	if(lines < height-2-pad-pad)
+		lines=height-2-pad-pad;
+
+	if((buf=(char *)textbuf=MALLOC((width-2-pad-pad)*lines*2))==NULL) {
+		cprintf("UIFC line %d: error allocating %u bytes\r\n"
+			,__LINE__,(width-2-pad-pad)*lines*2);
+		FREE(savscrn);
+		FREE(buf);
+		_setcursortype(cursor);
+		return; 
+	}
+	memset(textbuf,SP,(width-2-pad-pad)*lines*2);
+	for(i=1;i<(width-2-pad-pad)*lines*2;i+=2)
+		buf[i]=(hclr|(bclr<<4));
+	i=0;
+	for(j=0;j<len;j++,i+=2) {
+		if(hbuf[j]==LF) {
+			i+=2;
+			while(i%((width-2-pad-pad)*2)) i++; i-=2; 
+		}
+		else if(mode&WIN_HLP && (hbuf[j]==2 || hbuf[j]=='~')) {		 /* Ctrl-b toggles inverse */
+			inverse=!inverse;
+			i-=2; 
+		}
+		else if(mode&WIN_HLP && (hbuf[j]==1 || hbuf[j]=='`')) {		 /* Ctrl-a toggles high intensity */
+			high=!high;
+			i-=2; 
+		}
+		else if(hbuf[j]!=CR) {
+			textbuf[i]=hbuf[j];
+			textbuf[i+1]=inverse ? (bclr|(cclr<<4))
+				: high ? (hclr|(bclr<<4)) : (lclr|(bclr<<4)); 
+		} 
+	}
+	i=0;
+	p=textbuf;
+	if(mode&WIN_DYN) {
+		puttext(left+1+pad,top+2+pad,left+width-2-pad,top+height-1-pad,p);
+	}
+	else {
+		while(i==0) {
+			puttext(left+1+pad,top+2+pad,left+width-2-pad,top+height-1-pad,p);
+			if(inkey(1)) {
+				switch(inkey(0)) {
+					case KEY_HOME:	/* home */
+						p=textbuf;
+						break;
+
+					case KEY_UP:	/* up arrow */
+						p = p-((width-4)*2);
+						if(p<textbuf)
+							p=textbuf;
+						break;
+					
+					case KEY_PPAGE:	/* PgUp */
+						p = p-((width-4)*2*(height-5));
+						if(p<textbuf)
+							p=textbuf;
+						break;
+
+					case KEY_NPAGE:	/* PgDn */
+						p=p+(width-4)*2*(height-5);
+						if(p > textbuf+(lines-height+1)*(width-4)*2)
+							p=textbuf+(lines-height+1)*(width-4)*2;
+						if(p<textbuf)
+							p=textbuf;
+						break;
+
+					case KEY_END:	/* end */
+						p=textbuf+(lines-height+1)*(width-4)*2;
+						if(p<textbuf)
+							p=textbuf;
+						break;
+
+					case KEY_DOWN:	/* dn arrow */
+						p = p+((width-4)*2);
+						if(p > textbuf+(lines-height+1)*(width-4)*2)
+							p=textbuf+(lines-height+1)*(width-4)*2;
+						if(p<textbuf)
+							p=textbuf;
+						break;
+
+					default:
+						i=1;
+				}
+			}
+			mswait(1);
+		}
+
+		puttext(1,1,api->scrn_width,api->scrn_len,savscrn);
+	}
+	if(is_redraw)			/* Force redraw of menu also. */
+		reset_dynamic();
+	FREE(savscrn);
+	FREE(buf);
+	_setcursortype(cursor);
+}
+
+/************************************************************/
+/* Help (F1) key function. Uses helpbuf as the help input.	*/
+/************************************************************/
+void help()
+{
+	char hbuf[HELPBUF_SIZE],str[256];
+    char *p;
+	unsigned short line;
+	long l;
+	FILE *fp;
+
+	_setcursortype(_NOCURSOR);
+
+	if(!api->helpbuf) {
+		if((fp=fopen(api->helpixbfile,"rb"))==NULL) {
+			sprintf(hbuf," ERROR  Cannot open help index:\r\n          %s"
+				,api->helpixbfile);
+		}
+		else {
+			p=strrchr(helpfile,'/');
+			if(p==NULL)
+				p=strrchr(helpfile,'\\');
+			if(p==NULL)
+				p=helpfile;
+			else
+				p++;
+			l=-1L;
+			while(!feof(fp)) {
+				if(!fread(str,12,1,fp))
+					break;
+				str[12]=0;
+				fread(&line,2,1,fp);
+				if(stricmp(str,p) || line!=helpline) {
+					fseek(fp,4,SEEK_CUR);
+					continue; 
+				}
+				fread(&l,4,1,fp);
+				break; 
+			}
+			fclose(fp);
+			if(l==-1L)
+				sprintf(hbuf," ERROR  Cannot locate help key (%s:%u) in:\r\n"
+					"         %s",p,helpline,api->helpixbfile);
+			else {
+				if((fp=fopen(api->helpdatfile,"rb"))==NULL)
+					sprintf(hbuf," ERROR  Cannot open help file:\r\n          %s"
+						,api->helpdatfile);
+				else {
+					fseek(fp,l,SEEK_SET);
+					fread(hbuf,HELPBUF_SIZE,1,fp);
+					fclose(fp); 
+				} 
+			} 
+		} 
+	}
+	else
+		strcpy(hbuf,api->helpbuf);
+
+	showbuf(WIN_MID|WIN_HLP, 0, 0, 76, api->scrn_len-2, "Online Help", hbuf, NULL, NULL);
+}
-- 
GitLab