/*
 |	new_curse.c
 |
 |	A subset of curses developed for use with ae.
 |
 |	written by Hugh Mahon
 |
 |	THIS MATERIAL IS PROVIDED "AS IS".  THERE ARE
 |	NO WARRANTIES OF ANY KIND WITH REGARD TO THIS
 |	MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE
 |	IMPLIED WARRANTIES OF MERCHANTABILITY AND
 |	FITNESS FOR A PARTICULAR PURPOSE.  Neither
 |	Hewlett-Packard nor Hugh Mahon shall be liable
 |	for errors contained herein, nor for
 |	incidental or consequential damages in
 |	connection with the furnishing, performance or
 |	use of this material.  Neither Hewlett-Packard
 |	nor Hugh Mahon assumes any responsibility for
 |	the use or reliability of this software or
 |	documentation.  This software and
 |	documentation is totally UNSUPPORTED.  There
 |	is no support contract available.  Hewlett-
 |	Packard has done NO Quality Assurance on ANY
 |	of the program or documentation.  You may find
 |	the quality of the materials inferior to
 |	supported materials.
 |
 |	This software is not a product of Hewlett-Packard, Co., or any 
 |	other company.  No support is implied or offered with this software.
 |	You've got the source, and you're on your own.
 |
 |	This software may be distributed under the terms of Larry Wall's 
 |	Artistic license, a copy of which is included in this distribution. 
 |
 |	This notice must be included with this software and any derivatives.
 |
 |	Copyright (c) 1986, 1987, 1988, 1991, 1992, 1993, 1994, 1995 Hugh Mahon
 |	All are rights reserved.
 |
 |	$Header: /home/hugh/sources/old_ae/RCS/new_curse.c,v 1.54 2002/09/21 00:47:14 hugh Exp $
 |
 */

char *copyright_message[] = { "Copyright (c) 1986, 1987, 1988, 1991, 1992, 1993, 1994, 1995 Hugh Mahon",
				"All rights are reserved."};

char * new_curse_name= "@(#) new_curse.c $Revision: 1.54 $";

#include "new_curse.h"
#include <signal.h>
#include <fcntl.h>

#ifdef SYS5
#include <string.h>
#else
#include <strings.h>
#endif

#ifdef BSD_SELECT
#include <sys/types.h>
#include <sys/time.h>

#ifdef SLCT_HDR
#include <sys/select.h>  /* on AIX */
#endif /* SLCT_HDR */

#endif /* BSD_SELECT */

#ifdef HAS_STDLIB
#include <stdlib.h>
#endif

#if defined(__STDC__)
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#ifdef HAS_UNISTD
#include <unistd.h>
#endif

#ifdef HAS_SYS_IOCTL
#include <sys/ioctl.h>
#endif


WINDOW *curscr;
static WINDOW *virtual_scr;
WINDOW *stdscr;
WINDOW *last_window_refreshed;

#ifdef TIOCGWINSZ
	struct winsize ws;
#endif

#define min(a, b)	(a < b ? a : b)
#define highbitset(a)	((a) & 0x80)

#ifndef CAP
#define String_Out(table, stack, place) Info_Out(table, stack, place)
#else
#define String_Out(table, stack, place) Cap_Out(table, stack, place)
#endif

#define bw__ 0	/* booleans	*/
#define am__ 1
#define xb__ 2
#define xs__ 3	/* hp glitch (standout not erased by overwrite)	*/
#define xn__ 4
#define eo__ 5
#define gn__ 6	/* generic type terminal	*/
#define hc__ 7	/* hardcopy terminal		*/
#define km__ 8
#define hs__ 9
#define in__ 10
#define da__ 11
#define db__ 12
#define mi__ 13	/* safe to move during insert mode	*/
#define ms__ 14	/* safe to move during standout mode	*/
#define os__ 15
#define es__ 16
#define xt__ 17
#define hz__ 18	/* hazeltine glitch	*/
#define ul__ 19
#define xo__ 20
#define chts__ 21
#define nxon__ 22
#define nrrmc__ 23
#define npc__ 24
#define mc5i__ 25

#define co__ 0	/* number of columns	*/	/* numbers		*/
#define it__ 1	/* spaces per tab	*/
#define li__ 2	/* number of lines	*/
#define lm__ 3
#define sg__ 4	/* magic cookie glitch	*/
#define pb__ 5
#define vt__ 6
#define ws__ 7

#define cols__ 0
#define lines__ 2
#define xmc__ 4
#define vt__ 6
#define wsl__ 7
#define nlab__ 8
#define lh__ 9
#define lw__ 10

#define bt__ 0	/* back tab		*/	/* strings	*/
#define bl__ 1	/* bell			*/
#define cr__ 2	/* carriage return	*/
#define cs__ 3	/* change scroll region	*/
#define ct__ 4	/* clear all tab stops	*/
#define cl__ 5	/* clear screen and home cursor	*/
#define ce__ 6	/* clear to end of line	*/
#define cd__ 7	/* clear to end of display	*/
#define ch__ 8	/* set cursor column	*/
#define CC__ 9	/* term, settable cmd char in 	*/
#define cm__ 10	/* screen rel cursor motion, row, column	*/
#define do__ 11	/* down one line	*/
#define ho__ 12	/* home cursor	*/
#define vi__ 13	/* make cursor invisible	*/
#define le__ 14	/* move cursor left one space	*/
#define CM__ 15	/* memory rel cursor addressing	*/
#define ve__ 16	/* make cursor appear normal	*/
#define nd__ 17	/* non-destructive space (cursor right)	*/
#define ll__ 18	/* last line, first col	*/
#define up__ 19	/* cursor up		*/
#define vs__ 20
#define dc__ 21	/* delete character	*/
#define dl__ 22	/* delete line		*/
#define ds__ 23
#define hd__ 24
#define as__ 25
#define mb__ 26
#define md__ 27	/* turn on bold		*/
#define ti__ 28
#define dm__ 29	/* turn on delete mode	*/
#define mh__ 30	/* half bright mode	*/
#define im__ 31	/* insert mode		*/
#define mk__ 32
#define mp__ 33
#define mr__ 34
#define so__ 35	/* enter standout mode	*/
#define us__ 36
#define ec__ 37
#define ae__ 38
#define me__ 39
#define te__ 40
#define ed__ 41
#define ei__ 42	/* exit insert mode	*/
#define se__ 43	/* exit standout mode	*/
#define ue__ 44
#define vb__ 45
#define ff__ 46
#define fs__ 47
#define i1__ 48
#define i2__ 49
#define i3__ 50
#define if__ 51
#define ic__ 52
#define al__ 53
#define ip__ 54
#define kb__ 55		/* backspace key	*/
#define ka__ 56
#define kC__ 57
#define kt__ 58
#define kD__ 59
#define kL__ 60
#define kd__ 61
#define kM__ 62
#define kE__ 63
#define kS__ 64
#define k0__ 65
#define k1__ 66
#define kf10__ 67
#define k2__ 68
#define k3__ 69
#define k4__ 70
#define k5__ 71
#define k6__ 72
#define k7__ 73
#define k8__ 74
#define k9__ 75
#define kh__ 76
#define kI__ 77
#define kA__ 78
#define kl__ 79
#define kH__ 80
#define kN__ 81
#define kP__ 82
#define kr__ 83
#define kF__ 84
#define kR__ 85
#define kT__ 86
#define ku__ 87	/* key up	*/
#define ke__ 88
#define ks__ 89
#define l0__ 90
#define l1__ 91
#define la__ 92
#define l2__ 93
#define l3__ 94
#define l4__ 95
#define l5__ 96
#define l6__ 97
#define l7__ 98
#define l8__ 99
#define l9__ 100
#define mo__ 101
#define mm__ 102
#define nw__ 103
#define pc__ 104
#define DC__ 105
#define DL__ 106
#define DO__ 107
#define IC__ 118
#define SF__ 109
#define AL__ 110
#define LE__ 111
#define RI__ 112
#define SR__ 113
#define UP__ 114
#define pk__ 115
#define pl__ 116
#define px__ 117
#define ps__ 118
#define pf__ 119
#define po__ 120
#define rp__ 121
#define r1__ 122
#define r2__ 123
#define r3__ 124
#define rf__ 125
#define rc__ 126
#define cv__ 127
#define sc__ 128
#define sf__ 129
#define sr__ 130
#define sa__ 131	/* sgr	*/
#define st__ 132
#define wi__ 133
#define ta__ 134
#define ts__ 135
#define uc__ 136
#define hu__ 137
#define iP__ 138
#define K1__ 139
#define K2__ 140
#define K3__ 141
#define K4__ 142
#define K5__ 143
#define pO__ 144
#define ml__ 145
#define mu__ 146
#define rmp__ 145
#define acsc__ 146
#define pln__ 147
#define kcbt__ 148
#define smxon__ 149
#define rmxon__ 150
#define smam__ 151
#define rmam__ 152
#define xonc__ 153
#define xoffc__ 154
#define enacs__ 155
#define smln__ 156
#define rmln__ 157
#define kbeg__ 158
#define kcan__ 159
#define kclo__ 160
#define kcmd__ 161
#define kcpy__ 162
#define kcrt__ 163
#define kend__ 164
#define kent__ 165
#define kext__ 166
#define kfnd__ 167
#define khlp__ 168
#define kmrk__ 169
#define kmsg__ 170
#define kmov__ 171
#define knxt__ 172
#define kopn__ 173
#define kopt__ 174
#define kprv__ 175
#define kprt__ 176
#define krdo__ 177
#define kref__ 178
#define krfr__ 179
#define krpl__ 180
#define krst__ 181
#define kres__ 182
#define ksav__ 183
#define kspd__ 184
#define kund__ 185
#define kBEG__ 186
#define kCAN__ 187
#define kCMD__ 188
#define kCPY__ 189
#define kCRT__ 190
#define kDC__ 191
#define kDL__ 192
#define kslt__ 193
#define kEND__ 194
#define kEOL__ 195
#define kEXT__ 196
#define kFND__ 197
#define kHLP__ 198
#define kHOM__ 199
#define kIC__ 200
#define kLFT__ 201
#define kMSG__ 202
#define kMOV__ 203
#define kNXT__ 204
#define kOPT__ 205
#define kPRV__ 206
#define kPRT__ 207
#define kRDO__ 208
#define kRPL__ 209
#define kRIT__ 210
#define kRES__ 211
#define kSAV__ 212
#define kSPD__ 213
#define kUND__ 214
#define rfi__ 215
#define kf11__ 216
#define kf12__ 217
#define kf13__ 218
#define kf14__ 219
#define kf15__ 220
#define kf16__ 221
#define kf17__ 222
#define kf18__ 223
#define kf19__ 224
#define kf20__ 225
#define kf21__ 226
#define kf22__ 227
#define kf23__ 228
#define kf24__ 229
#define kf25__ 230
#define kf26__ 231
#define kf27__ 232
#define kf28__ 233
#define kf29__ 234
#define kf30__ 235
#define kf31__ 236
#define kf32__ 237
#define kf33__ 238
#define kf34__ 239
#define kf35__ 240
#define kf36__ 241
#define kf37__ 242
#define kf38__ 243
#define kf39__ 244
#define kf40__ 245
#define kf41__ 246
#define kf42__ 247
#define kf43__ 248
#define kf44__ 249
#define kf45__ 250
#define kf46__ 251
#define kf47__ 252
#define kf48__ 253
#define kf49__ 254
#define kf50__ 255
#define kf51__ 256
#define kf52__ 257
#define kf53__ 258
#define kf54__ 259
#define kf55__ 260
#define kf56__ 261
#define kf57__ 262
#define kf58__ 263
#define kf59__ 264
#define kf60__ 265
#define kf61__ 266
#define kf62__ 267
#define kf63__ 268
#define el1__ 269
#define mgc__ 270
#define smgl__ 271
#define smgr__ 272

#ifdef CAP
char *Boolean_names[] = {
"bw", "am", "xb", "xs", "xn", "eo", "gn", "hc", "km", "hs", "in", "da", "db", 
"mi", "ms", "os", "es", "xt", "hz", "ul", "xo", "HC", "nx", "NR", "NP", "5i"
}; 

char *Number_names[] = { 
"co#", "it#", "li#", "lm#", "sg#", "pb#", "vt#", "ws#", "Nl#", "lh#", "lw#"
};

char *String_names[] = {
"bt=", "bl=", "cr=", "cs=", "ct=", "cl=", "ce=", "cd=", "ch=", "CC=", "cm=", 
"do=", "ho=", "vi=", "le=", "CM=", "ve=", "nd=", "ll=", "up=", "vs=", "dc=", 
"dl=", "ds=", "hd=", "as=", "mb=", "md=", "ti=", "dm=", "mh=", "im=", "mk=", 
"mp=", "mr=", "so=", "us=", "ec=", "ae=", "me=", "te=", "ed=", "ei=", "se=", 
"ue=", "vb=", "ff=", "fs=", "i1=", "i2=", "i3=", "if=", "ic=", "al=", "ip=", 
"kb=", "ka=", "kC=", "kt=", "kD=", "kL=", "kd=", "kM=", "kE=", "kS=", "k0=", 
"k1=", "k;=", "k2=", "k3=", "k4=", "k5=", "k6=", "k7=", "k8=", "k9=", "kh=", 
"kI=", "kA=", "kl=", "kH=", "kN=", "kP=", "kr=", "kF=", "kR=", "kT=", "ku=", 
"ke=", "ks=", "l0=", "l1=", "la=", "l2=", "l3=", "l4=", "l5=", "l6=", "l7=", 
"l8=", "l9=", "mo=", "mm=", "nw=", "pc=", "DC=", "DL=", "DO=", "IC=", "SF=", 
"AL=", "LE=", "RI=", "SR=", "UP=", "pk=", "pl=", "px=", "ps=", "pf=", "po=", 
"rp=", "r1=", "r2=", "r3=", "rf=", "rc=", "cv=", "sc=", "sf=", "sr=", "sa=", 
"st=", "wi=", "ta=", "ts=", "uc=", "hu=", "iP=", "K1=", "K3=", "K2=", "K4=", 
"K5=", "pO=", "rP=", "ac=", "pn=", "kB=", "SX=", "RX=", "SA=", "RA=", "XN=", 
"XF=", "eA=", "LO=", "LF=", "@1=", "@2=", "@3=", "@4=", "@5=", "@6=", "@7=", 
"@8=", "@9=", "@0=", "%1=", "%2=", "%3=", "%4=", "%5=", "%6=", "%7=", "%8=", 
"%9=", "%0=", "&1=", "&2=", "&3=", "&4=", "&5=", "&6=", "&7=", "&8=", "&9=", 
"&0=", "*1=", "*2=", "*3=", "*4=", "*5=", "*6=", "*7=", "*8=", "*9=", "*0=", 
"#1=", "#2=", "#3=", "#4=", "%a=", "%b=", "%c=", "%d=", "%e=", "%f=", "%g=", 
"%h=", "%i=", "%j=", "!1=", "!2=", "!3=", "RF=", "F1=", "F2=", "F3=", "F4=", 
"F5=", "F6=", "F7=", "F8=", "F9=", "FA=", "FB=", "FC=", "FD=", "FE=", "FF=", 
"FG=", "FH=", "FI=", "FJ=", "FK=", "FL=", "FM=", "FN=", "FO=", "FP=", "FQ=", 
"FR=", "FS=", "FT=", "FU=", "FV=", "FW=", "FX=", "FY=", "FZ=", "Fa=", "Fb=", 
"Fc=", "Fd=", "Fe=", "Ff=", "Fg=", "Fh=", "Fi=", "Fj=", "Fk=", "Fl=", "Fm=", 
"Fn=", "Fo=", "Fp=", "Fq=", "Fr=", "cb=", "MC=", "ML=", "MR="
};
#endif

char *new_curse = "October 1987";

char in_buff[100];	/* buffer for ungetch			*/
int bufp;		/* next free position in in_buff	*/

char *TERMINAL_TYPE = NULL; /* terminal type to be gotten from environment	*/
int CFOUND = FALSE;
int Data_Line_len = 0;
int Max_Key_len;	/* max length of a sequence sent by a key	*/
char *Data_Line = NULL;
char *TERM_PATH = NULL;
char *TERM_data_ptr = NULL;
char *Term_File_name = NULL;	/* name of file containing terminal description	*/
FILE *TFP;		/* file pointer to file with terminal des.	*/
int Fildes;		/* file descriptor for terminfo file		*/
int STAND = FALSE;	/* is standout mode activated?			*/
int TERM_INFO = FALSE;	/* is terminfo being used (TRUE), or termcap (FALSE) */
int Time_Out;	/* set when time elapsed while trying to read function key */
int Curr_x;		/* current x position on screen			*/
int Curr_y;		/* current y position on the screen		*/
int LINES;
int COLS;
int Move_It;		/* flag to move cursor if magic cookie glitch	*/
int initialized = FALSE;	/* tells whether new_curse is initialized	*/
float speed;
float chars_per_millisecond;
int Repaint_screen;	/* if an operation to change screen impossible, repaint screen	*/
int Intr;		/* storeage for interrupt character		*/
int Parity;		/* 0 = no parity, 1 = odd parity, 2 = even parity */
int Noblock;		/* for BSD systems				*/
int Num_bits;	/* number of bits per character	*/
int Flip_Bytes;	/* some systems have byte order reversed	*/
int interrupt_flag = FALSE;	/* set true if SIGWINCH received	*/

#ifndef CAP
char *Strings;
#endif

#if !defined(TERMCAP)
#define TERMCAP "/etc/termcap"
#endif 

struct KEYS {
	int length;	/* length of string sent by key			*/
	char *string;	/* string sent by key				*/
	int value;	/* CURSES value of key (9-bit)			*/
	};

struct KEY_STACK {
	struct KEYS *element;
	struct KEY_STACK *next;
	};

struct KEY_STACK *KEY_TOS = NULL;
struct KEY_STACK *KEY_POINT;

/*
 |
 |	Not all systems have good terminal information, so we will define 
 |	keyboard information here for the most widely used terminal type, 
 |	the VT100.
 |
 */

struct KEYS vt100[] = 
	{
		{ 3, "\033[A", 0403 },	/* key up 	*/
		{ 3, "\033[C", 0405 },	/* key right	*/
		{ 3, "\033[D", 0404 },	/* key left	*/

		{ 4, "\033[6~", 0522 },	/* key next page	*/
		{ 4, "\033[5~", 0523 },	/* key prev page	*/
		{ 3, "\033[[", 0550 },	/* key end	*/
		{ 3, "\033[@", 0406 },	/* key home	*/
		{ 4, "\033[2~", 0513 },	/* key insert char	*/

		{ 3, "\033[y", 0410 },	/* key F0	*/
		{ 3, "\033[P", 0411 },	/* key F1	*/
		{ 3, "\033[Q", 0412 },	/* key F2	*/
		{ 3, "\033[R", 0413 },	/* key F3	*/
		{ 3, "\033[S", 0414 },	/* key F4	*/
		{ 3, "\033[t", 0415 },	/* key F5	*/
		{ 3, "\033[u", 0416 },	/* key F6	*/
		{ 3, "\033[v", 0417 },	/* key F7	*/
		{ 3, "\033[l", 0420 },	/* key F8	*/
		{ 3, "\033[w", 0421 },	/* key F9	*/
		{ 3, "\033[x", 0422 },	/* key F10	*/

		{ 5, "\033[10~", 0410 },	/* key F0	*/
		{ 5, "\033[11~", 0411 },	/* key F1	*/
		{ 5, "\033[12~", 0412 },	/* key F2	*/
		{ 5, "\033[13~", 0413 },	/* key F3	*/
		{ 5, "\033[14~", 0414 },	/* key F4	*/
		{ 5, "\033[15~", 0415 },	/* key F5	*/
		{ 5, "\033[17~", 0416 },	/* key F6	*/
		{ 5, "\033[18~", 0417 },	/* key F7	*/
		{ 5, "\033[19~", 0420 },	/* key F8	*/
		{ 5, "\033[20~", 0421 },	/* key F9	*/
		{ 5, "\033[21~", 0422 },	/* key F10	*/
		{ 5, "\033[23~", 0423 },	/* key F11	*/
		{ 5, "\033[24~", 0424 },	/* key F12	*/
		{ 3, "\033[q", 0534 },	/* ka1 upper-left of keypad	*/
		{ 3, "\033[s", 0535 },	/* ka3 upper-right of keypad	*/
		{ 3, "\033[r", 0536 },	/* kb2 center of keypad	*/
 		{ 3, "\033[p", 0537 },	/* kc1 lower-left of keypad	*/
		{ 3, "\033[n", 0540 },	/* kc3 lower-right of keypad	*/

		/*
		 |	The following are the same keys as above, but with 
		 |	a different character following the escape char.
		 */

		{ 3, "\033OA", 0403 },	/* key up 	*/
		{ 3, "\033OC", 0405 },	/* key right	*/
		{ 3, "\033OD", 0404 },	/* key left	*/
		{ 3, "\033OB", 0402 },	/* key down	*/
		{ 4, "\033O6~", 0522 },	/* key next page	*/
		{ 4, "\033O5~", 0523 },	/* key prev page	*/
		{ 3, "\033O[", 0550 },	/* key end	*/
		{ 3, "\033O@", 0406 },	/* key home	*/
		{ 4, "\033O2~", 0513 },	/* key insert char	*/

		{ 3, "\033Oy", 0410 },	/* key F0	*/
		{ 3, "\033OP", 0411 },	/* key F1	*/
		{ 3, "\033OQ", 0412 },	/* key F2	*/
		{ 3, "\033OR", 0413 },	/* key F3	*/
		{ 3, "\033OS", 0414 },	/* key F4	*/
		{ 3, "\033Ot", 0415 },	/* key F5	*/
		{ 3, "\033Ou", 0416 },	/* key F6	*/
		{ 3, "\033Ov", 0417 },	/* key F7	*/
		{ 3, "\033Ol", 0420 },	/* key F8	*/
		{ 3, "\033Ow", 0421 },	/* key F9	*/
		{ 3, "\033Ox", 0422 },	/* key F10	*/

		{ 5, "\033O10~", 0410 },	/* key F0	*/
		{ 5, "\033O11~", 0411 },	/* key F1	*/
		{ 5, "\033O12~", 0412 },	/* key F2	*/
		{ 5, "\033O13~", 0413 },	/* key F3	*/
		{ 5, "\033O14~", 0414 },	/* key F4	*/
		{ 5, "\033O15~", 0415 },	/* key F5	*/
		{ 5, "\033O17~", 0416 },	/* key F6	*/
		{ 5, "\033O18~", 0417 },	/* key F7	*/
		{ 5, "\033O19~", 0420 },	/* key F8	*/
		{ 5, "\033O20~", 0421 },	/* key F9	*/
		{ 5, "\033O21~", 0422 },	/* key F10	*/
		{ 5, "\033O23~", 0423 },	/* key F11	*/
		{ 5, "\033O24~", 0424 },	/* key F12	*/
		{ 3, "\033Oq", 0534 },	/* ka1 upper-left of keypad	*/
		{ 3, "\033Os", 0535 },	/* ka3 upper-right of keypad	*/
		{ 3, "\033Or", 0536 },	/* kb2 center of keypad	*/
 		{ 3, "\033Op", 0537 },	/* kc1 lower-left of keypad	*/
		{ 3, "\033On", 0540 },	/* kc3 lower-right of keypad	*/

		{ 0, "", 0 }	/* end	*/
	};

struct Parameters {
	int value;
	struct Parameters *next;
	};

int Key_vals[] = { 
	0407, 0526, 0515, 0525, 0512, 0510, 0402, 0514, 0517, 0516, 0410, 0411, 
	0422, 0412, 0413, 0414, 0415, 0416, 0417, 0420, 0421, 0406, 0513, 0511, 
	0404, 0533, 0522, 0523, 0405, 0520, 0521, 0524, 0403, 
	0534, 0535, 0536, 0537, 0540, 0541, 0542, 0543, 0544, 0545, 0546, 0547, 
	0550, 0527, 0551, 0552, 0553, 0554, 0555, 0556, 0557, 0560, 0561, 0562, 
	0532, 0563, 0564, 0565, 0566, 0567, 0570, 0571, 0627, 0630, 0572, 0573, 
	0574, 0575, 0576, 0577, 0600, 0601, 0602, 0603, 0604, 0605, 0606, 0607, 
	0610, 0611, 0612, 0613, 0614, 0615, 0616, 0617, 0620, 0621, 0622, 0623, 
	0624, 0625, 0626, 0423, 0424, 0425, 0426, 0427, 0430, 0431, 
	0432, 0433, 0434, 0435, 0436, 0437, 0440, 0441, 0442, 0443, 0444, 0445, 
	0446, 0447, 0450, 0451, 0452, 0453, 0454, 0455, 0456, 0457, 0460, 0461, 
	0462, 0463, 0464, 0465, 0466, 0467, 0470, 0471, 0472, 0473, 0474, 0475, 
	0476, 0477, 0500, 0501, 0502, 0503, 0504, 0505, 0506, 0507
};

int attributes_set[9];

static int nc_attributes = 0;	/* global attributes for new_curse to observe */

#ifdef SYS5
struct termio Terminal;
struct termio Saved_tty;
#else
struct sgttyb Terminal;
struct sgttyb Saved_tty;
#endif

char *tc_;

int Booleans[128];	
int Numbers[128];
char *String_table[1024];

int *virtual_lines;

static char nc_scrolling_ability = FALSE;

char *terminfo_path[] = {
        "/usr/lib/terminfo", 
        "/usr/share/lib/terminfo", 
        "/usr/share/terminfo", 
        NULL 
        };

#ifdef CAP

#if defined(__STDC__) || defined(__cplusplus)
#define P_(s) s
#else
#define P_(s) ()
#endif /* __STDC__ */

int tc_Get_int P_((int));
void CAP_PARSE P_((void));
void Find_term P_((void));

#undef P_

#endif /* CAP */


#ifndef __STDC__
#ifndef HAS_STDLIB
extern char *fgets();
extern char *malloc();
extern char *getenv();
FILE *fopen();			/* declaration for open function	*/
#endif /* HAS_STDLIB */
#endif /* __STDC__ */

#ifdef SIGWINCH

/*
 |	Copy the contents of one window to another.
 */

void 
copy_window(origin, destination)
WINDOW *origin, *destination;
{
	int row, column;
	struct _line *orig, *dest;

	orig = origin->first_line;
	dest = destination->first_line;

	for (row = 0; 
		row < (min(origin->Num_lines, destination->Num_lines)); 
			row++)
	{
		for (column = 0; 
		    column < (min(origin->Num_cols, destination->Num_cols)); 
			column++)
		{
			dest->row[column] = orig->row[column];
			dest->attributes[column] = orig->attributes[column];
		}
		dest->changed = orig->changed;
		dest->scroll = orig->scroll;
		dest->last_char = min(orig->last_char, destination->Num_cols);
		orig = orig->next_screen;
		dest = dest->next_screen;
	}
	destination->LX = min((destination->Num_cols - 1), origin->LX);
	destination->LY = min((destination->Num_lines - 1), origin->LY);
	destination->Attrib = origin->Attrib;
	destination->scroll_up = origin->scroll_up;
	destination->scroll_down = origin->scroll_down;
	destination->SCROLL_CLEAR = origin->SCROLL_CLEAR;
}

void 
reinitscr(foo)
int foo; 
{
	WINDOW *local_virt;
	WINDOW *local_std;
	WINDOW *local_cur;

	signal(SIGWINCH, reinitscr);
#ifdef TIOCGWINSZ
	if (ioctl(0, TIOCGWINSZ, &ws) >= 0)
	{
		if (ws.ws_row == LINES && ws.ws_col == COLS) 
			return;
		if (ws.ws_row > 0) 
			LINES = ws.ws_row;
		if (ws.ws_col > 0) 
			COLS = ws.ws_col;
	}
#endif /* TIOCGWINSZ */
	local_virt = newwin(LINES, COLS, 0, 0);
	local_std = newwin(LINES, COLS, 0, 0);
	local_cur = newwin(LINES, COLS, 0, 0);
	copy_window(virtual_scr, local_virt);
	copy_window(stdscr, local_std);
	copy_window(curscr, local_cur);
	delwin(virtual_scr);
	delwin(stdscr);
	delwin(curscr);
	virtual_scr = local_virt;
	stdscr = local_std;
	curscr = local_cur;
	free(virtual_lines);
	virtual_lines = (int *) malloc(LINES * (sizeof(int)));
	interrupt_flag = TRUE;
}
#endif /* SIGWINCH */

void 
initscr()		/* initialize terminal for operations	*/
{
	int value;
	int counter;
	char *lines_string;
	char *columns_string;
#ifdef CAP
	char *pointer;
#endif /* CAP */

#ifdef DIAG
printf("starting initscr \n");fflush(stdout);
#endif
	if (initialized)
		return;
#ifdef BSD_SELECT
	setbuf(stdin, NULL);
#endif /* BSD_SELECT */
	Flip_Bytes = FALSE;
	Parity = 0;
	Time_Out = FALSE;
	bufp = 0;
	Move_It = FALSE;
	Noblock = FALSE;
#ifdef SYS5
	value = ioctl(0, TCGETA, &Terminal);
	if (Terminal.c_cflag & PARENB)
	{
		if (Terminal.c_cflag & PARENB)
			Parity = 1;
		else
			Parity = 2;
	}
	if ((Terminal.c_cflag & CS8) == CS8)
	{
		Num_bits = 8;
	}
	else if ((Terminal.c_cflag & CS7) == CS7)
		Num_bits = 7;
	else if ((Terminal.c_cflag & CS6) == CS6)
		Num_bits = 6;
	else
		Num_bits = 5;
	value = Terminal.c_cflag & 037;
	switch (value) {
	case 01:	speed = 50.0;
		break;
	case 02:	speed = 75.0;
		break;
	case 03:	speed = 110.0;
		break;
	case 04:	speed = 134.5;
		break;
	case 05:	speed = 150.0;
		break;
	case 06:	speed = 200.0;
		break;
	case 07:	speed = 300.0;
		break;
	case 010:	speed = 600.0;
		break;
	case 011:	speed = 900.0;
		break;
	case 012:	speed = 1200.0;
		break;
	case 013:	speed = 1800.0;
		break;
	case 014:	speed = 2400.0;
		break;
	case 015:	speed = 3600.0;
		break;
	case 016:	speed = 4800.0;
		break;
	case 017:	speed = 7200.0;
		break;
	case 020:	speed = 9600.0;
		break;
	case 021:	speed = 19200.0;
		break;
	case 022:	speed = 38400.0;
		break;
	default:	speed = 0.0;
	}
#else
	value = ioctl(0, TIOCGETP, &Terminal);
	if (Terminal.sg_flags & EVENP)
		Parity = 2;
	else if (Terminal.sg_flags & ODDP)
		Parity = 1;
	value = Terminal.sg_ospeed;
	switch (value) {
	case 01:	speed = 50.0;
		break;
	case 02:	speed = 75.0;
		break;
	case 03:	speed = 110.0;
		break;
	case 04:	speed = 134.5;
		break;
	case 05:	speed = 150.0;
		break;
	case 06:	speed = 200.0;
		break;
	case 07:	speed = 300.0;
		break;
	case 010:	speed = 600.0;
		break;
	case 011:	speed = 1200.0;
		break;
	case 012:	speed = 1800.0;
		break;
	case 013:	speed = 2400.0;
		break;
	case 014:	speed = 4800.0;
		break;
	case 015:	speed = 9600.0;
		break;
	default:	speed = 0.0;
	}
#endif
	chars_per_millisecond = (0.001 * speed) / 8.0;
	TERMINAL_TYPE = getenv("TERM");
	if (TERMINAL_TYPE == NULL)
	{
		printf("unknown terminal type\n");
		exit(0);
	}
#ifndef CAP
	Fildes = -1;
	TERM_PATH = getenv("TERMINFO");
	if (TERM_PATH != NULL)
	{
		Data_Line_len = 23 + strlen(TERM_PATH) + strlen(TERMINAL_TYPE);
		Term_File_name = malloc(Data_Line_len);
		sprintf(Term_File_name, "%s/%c/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
		Fildes = open(Term_File_name, O_RDONLY);
		if (Fildes == -1)
		{
        		sprintf(Term_File_name, "%s/%x/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
        		Fildes = open(Term_File_name, O_RDONLY);
		}
	}
	counter = 0;
	while ((Fildes == -1) && (terminfo_path[counter] != NULL))
	{
		TERM_PATH = terminfo_path[counter];
		Data_Line_len = 23 + strlen(TERM_PATH) + strlen(TERMINAL_TYPE);
		Term_File_name = malloc(Data_Line_len);
		sprintf(Term_File_name, "%s/%c/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
		Fildes = open(Term_File_name, O_RDONLY);
		if (Fildes == -1)
		{
        		sprintf(Term_File_name, "%s/%x/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
        		Fildes = open(Term_File_name, O_RDONLY);
		}
		counter++;
	}
	if (Fildes == -1)
	{
		free(Term_File_name);
		Term_File_name = NULL;
	}
	else
		TERM_INFO = INFO_PARSE();
#else
	/*
	 |	termcap information can be in the TERMCAP env variable, if so 
	 |	use that, otherwise check the /etc/termcap file
	 */
	if ((pointer = Term_File_name = getenv("TERMCAP")) != NULL)
	{
		if (*Term_File_name != '/')
			Term_File_name = TERMCAP;
	}
	else
	{
		Term_File_name = TERMCAP;
	}
	if ((TFP = fopen(Term_File_name, "r")) == NULL)
	{
		printf("unable to open %s file \n", TERMCAP);
		exit(0);
	}
 	for (value = 0; value < 1024; value++)	
		String_table[value] = NULL;
	for (value = 0; value < 128; value++)	
		Booleans[value] = 0;
	for (value = 0; value < 128; value++)	
		Numbers[value] = 0;
	Data_Line = malloc(512);
	if (pointer && *pointer != '/')
	{
		TERM_data_ptr = pointer;
		CAP_PARSE();
	}
	else
	{
		Find_term();
		CAP_PARSE();
	}
#endif
	if (String_table[pc__] == NULL) 
		String_table[pc__] = "\0";
	if ((String_table[cm__] == NULL) || (Booleans[hc__]))
	{
		fprintf(stderr, "sorry, unable to use this terminal type for screen editing\n");
		exit(0);
	}
	Key_Get();
	keys_vt100();
	LINES = Numbers[li__];
	COLS = Numbers[co__];
	if ((lines_string = getenv("LINES")) != NULL)
	{
		value = atoi(lines_string);
		if (value > 0)
			LINES = value;
	}
	if ((columns_string = getenv("COLUMNS")) != NULL)
	{
		value = atoi(columns_string);
		if (value > 0)
			COLS = value;
	}
#ifdef TIOCGWINSZ
	/*
	 |	get the window size
	 */
	if (ioctl(0, TIOCGWINSZ, &ws) >= 0)
	{
		if (ws.ws_row > 0)
			LINES = ws.ws_row;
		if (ws.ws_col > 0)
			COLS = ws.ws_col;
	}
#endif
	virtual_scr = newwin(LINES, COLS, 0, 0);
	stdscr = newwin(LINES, COLS, 0, 0);
	curscr = newwin(LINES, COLS, 0, 0);
	wmove(stdscr, 0, 0);
	werase(stdscr);
	Repaint_screen = TRUE;
	initialized = TRUE;
	virtual_lines = (int *) malloc(LINES * (sizeof(int)));

#ifdef SIGWINCH
	/*
	 |	reset size of windows and LINES and COLS if term window 
	 |	changes size
	 */
	signal(SIGWINCH, reinitscr);
#endif /* SIGWINCH */

	/*
	 |	check if scrolling is available
	 */

	nc_scrolling_ability = ((String_table[al__] != NULL) && 
				(String_table[dl__])) || ((String_table[cs__]) 
				&& (String_table[sr__]));

}

#ifndef CAP
int 
Get_int()		/* get a two-byte integer from the terminfo file */
{
	int High_byte;
	int Low_byte;
	int temp;

	Low_byte = *((unsigned char *) TERM_data_ptr++);
	High_byte = *((unsigned char *) TERM_data_ptr++);
	if (Flip_Bytes)
	{
		temp = Low_byte;
		Low_byte = High_byte;
		High_byte = temp;
	}
	if ((High_byte == 255) && (Low_byte == 255))
		return (-1);
	else
		return(Low_byte + (High_byte * 256));
}

int 
INFO_PARSE()		/* parse off the data in the terminfo data file	*/
{
	int offset;
	int magic_number = 0;
	int counter = 0;
	int Num_names = 0;
	int Num_bools = 0;
	int Num_ints = 0;
	int Num_strings = 0;
	int string_table_len = 0;
	char *temp_ptr;

	TERM_data_ptr = Data_Line = malloc((10240 * (sizeof(char))));
	Data_Line_len = read(Fildes, Data_Line, 10240);
	if ((Data_Line_len >= 10240) || (Data_Line_len < 0))
		return(0);
	/*
	 |	get magic number
	 */
	magic_number = Get_int();
	/*
	 |	if magic number not right, reverse byte order and check again
	 */
	if (magic_number != 282)
	{
		Flip_Bytes = TRUE;
		TERM_data_ptr--;
		TERM_data_ptr--;
		magic_number = Get_int();
		if (magic_number != 282)
			return(0);
	}
	/*
	 |	get the number of each type in the terminfo data file
	 */
	Num_names = Get_int();
	Num_bools = Get_int();
	Num_ints = Get_int();
	Num_strings = Get_int();
	string_table_len = Get_int();
	Strings = malloc(string_table_len);
	while (Num_names > 0)
	{
		TERM_data_ptr++;
		Num_names--;
	}
	counter = 0;
	while (Num_bools)
	{
		Num_bools--;
		Booleans[counter++] = *TERM_data_ptr++;
	}
	if (((unsigned int) TERM_data_ptr) & 1)	/* force alignment	*/
		TERM_data_ptr++;
	counter = 0;
	while (Num_ints)
	{
		Num_ints--;
		Numbers[counter] = Get_int();
		counter++;
	}
	temp_ptr = TERM_data_ptr + Num_strings + Num_strings;
	memcpy(Strings, temp_ptr, string_table_len);
	counter = bt__;
	while (Num_strings)
	{
		Num_strings--;
		if ((offset=Get_int()) != -1)
		{
			if (String_table[counter] == NULL)
				String_table[counter] = Strings + offset;
		}
		else
			String_table[counter] = NULL;
		counter++;
	}
	close(Fildes);
	free(Data_Line);
	return(TRUE);
}
#endif		/* ifndef CAP	*/

int 
AtoI()		/* convert ascii text to integers	*/
{
	int Temp;

	Temp = 0;
	while ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9'))
	{
		Temp = (Temp * 10) + (*TERM_data_ptr - '0');
		TERM_data_ptr++;
	}
	return(Temp);
}

void 
Key_Get()		/* create linked list with all key sequences obtained from terminal database	*/
{
	int Counter;
	int Klen;
	int key_def;
	struct KEY_STACK *Spoint;

	Max_Key_len = 0;
	Counter = 0;
	key_def = kb__;
	while (key_def <= kf63__)
	{
		if (key_def == ke__)
			key_def = K1__;
		else if (key_def == (K5__ + 1))
			key_def = kcbt__;
		else if (key_def == (kcbt__ + 1))
			key_def = kbeg__;
		else if (key_def == (kUND__ + 1))
			key_def = kf11__;
		if (String_table[key_def] != NULL)
		{
			if (KEY_TOS == NULL)
				Spoint = KEY_TOS = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
			else
			{
				Spoint = KEY_TOS;
				while (Spoint->next != NULL)
					Spoint = Spoint->next;
				Spoint->next = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
				Spoint = Spoint->next;
			}
			Spoint->next = NULL;
			Spoint->element = (struct KEYS *) malloc(sizeof(struct KEYS));
			Spoint->element->string = String_table[key_def];
			Spoint->element->length = strlen(String_table[key_def]);
			Spoint->element->value = Key_vals[Counter];
			Klen = strlen(Spoint->element->string);
			if (Klen > Max_Key_len)
				Max_Key_len = Klen;
			/*
			 |  Some terminal types accept keystrokes of the form
			 |  \E[A and \EOA, substituting '[' for 'O'.  Make a 
			 |  duplicate of such key strings (since the 
			 |  database will only have one version) so new_curse 
			 |  can understand both.
			 */
			if ((Spoint->element->length > 1) && 
			    ((String_table[key_def][1] == '[') || 
			     (String_table[key_def][1] == 'O')))
			{
				Spoint->next = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
				Spoint = Spoint->next;
				Spoint->next = NULL;
				Spoint->element = (struct KEYS *) malloc(sizeof(struct KEYS));
				Spoint->element->length = strlen(String_table[key_def]);
				Spoint->element->string = malloc(Spoint->element->length + 1);
				strcpy(Spoint->element->string, String_table[key_def]);
				Spoint->element->value = Key_vals[Counter];
				Klen = strlen(Spoint->element->string);
				if (Klen > Max_Key_len)
					Max_Key_len = Klen;
			
				if (String_table[key_def][1] == '[')
					Spoint->element->string[1] = 'O';
				else
					Spoint->element->string[1] = '[';
			}
		}
		key_def++;
		Counter++;
	}
}

/*
 |	insert information about keys for a vt100 terminal
 */

void
keys_vt100()
{
	int counter;
	int Klen;
	struct KEY_STACK *Spoint;

	Spoint = KEY_TOS;
	while (Spoint->next != NULL)
		Spoint = Spoint->next;
	for (counter = 0; vt100[counter].length != 0; counter++)
	{
		Spoint->next = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
		Spoint = Spoint->next;
		Spoint->next = NULL;
		Spoint->element = &vt100[counter];
		Klen = strlen(Spoint->element->string);
		if (Klen > Max_Key_len)
			Max_Key_len = Klen;
	}
}

#ifdef CAP
char *
String_Get(param)		/* read the string */
char *param;
{
	char *String;
	char *Temp;
	int Counter;

	if (param == NULL)
	{
		while (*TERM_data_ptr != '=')
			TERM_data_ptr++;
		Temp = ++TERM_data_ptr;
		Counter = 1;
		while ((*Temp != ':') && (*Temp != (char)NULL))
		{
			Counter++;
			Temp++;
		}
		if (Counter == 1)	/* no data */
			return(NULL);
		String = Temp = malloc(Counter);
		while ((*TERM_data_ptr != ':') && (*TERM_data_ptr != (char)NULL))
		{
			if (*TERM_data_ptr == '\\')
			{
				TERM_data_ptr++;
				if (*TERM_data_ptr == 'n')
					*Temp = '\n';
				else if (*TERM_data_ptr == 't')
					*Temp = '\t';
				else if (*TERM_data_ptr == 'b')
					*Temp = '\b';
				else if (*TERM_data_ptr == 'r')
					*Temp = '\r';
				else if (*TERM_data_ptr == 'f')
					*Temp = '\f';
				else if ((*TERM_data_ptr == 'e') || (*TERM_data_ptr == 'E'))
					*Temp = '\033';		/* escape */
				else if (*TERM_data_ptr == '\\')
					*Temp = '\\';
				else if (*TERM_data_ptr == '\'')
					*Temp = '\'';
				else if ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9'))
				{
					Counter = 0;
					while ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9'))
					{
						Counter = (8 * Counter) + (*TERM_data_ptr - '0');
						TERM_data_ptr++;  /* ? */
					}
					*Temp = Counter;
					TERM_data_ptr--;
				}
				TERM_data_ptr++;
				Temp++;
			}
			else if (*TERM_data_ptr == '^')
			{
				TERM_data_ptr++;
				if ((*TERM_data_ptr >= '@') && (*TERM_data_ptr <= '_'))
					*Temp = *TERM_data_ptr - '@';
				else if (*TERM_data_ptr == '?')
					*Temp = 127;
				TERM_data_ptr++;
				Temp++;
			}
			else
				*Temp++ = *TERM_data_ptr++;
		}
		*Temp = (char)NULL;
		param = String;
	}
	else
	{
		while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != ':'))
			TERM_data_ptr++;
	}
	return(param);
}

int 
tc_Get_int(param)		/* read the integer			*/
int param;
{
	int Itemp;

	if (param == 0)
	{
		while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != '#'))
			TERM_data_ptr++;
		TERM_data_ptr++;
		Itemp = AtoI();
		param = Itemp;
	}
	else
	{
		while (*TERM_data_ptr != ':')
			TERM_data_ptr++;
	}
	return(param);
}

void 
Find_term()		/* find terminal description in termcap file	*/
{
	char *Name;
	char *Ftemp;

	Ftemp = Name = malloc(strlen(TERMINAL_TYPE) + 2);
	strcpy(Name, TERMINAL_TYPE);
	while (*Ftemp != (char)NULL)
		Ftemp++;
	*Ftemp++ = '|';
	*Ftemp = (char)NULL;
	CFOUND = FALSE;
	Data_Line_len = strlen(TERMINAL_TYPE) + 1;
	while ((!CFOUND) && ((TERM_data_ptr=fgets(Data_Line, 512, TFP)) != NULL))
	{
		if ((*TERM_data_ptr != ' ') && (*TERM_data_ptr != '\t') && (*TERM_data_ptr != '#'))
		{
			while ((!CFOUND) && (*TERM_data_ptr != (char)NULL))
			{
				CFOUND = !strncmp(TERM_data_ptr, Name, Data_Line_len);
				while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != '|') && (*TERM_data_ptr != '#') && (*TERM_data_ptr != ':'))
					TERM_data_ptr++;
				if (*TERM_data_ptr == '|')
					TERM_data_ptr++;
				else if (!CFOUND)
					*TERM_data_ptr = (char)NULL;
			}
		}
	}
	if (!CFOUND)
	{
		printf("terminal type %s not found\n", TERMINAL_TYPE);
		exit(0);
	}
}

void 
CAP_PARSE()		/* parse off the data in the termcap data file	*/
{
	int offset;
	int found;

	do
	{
		while (*TERM_data_ptr != (char)NULL)
		{
			for (found = FALSE, offset = 0; (!found) && (offset < 26); offset++)
			{
				if (!strncmp(TERM_data_ptr, Boolean_names[offset], 2))
				{
					found = TRUE;
					Booleans[offset] = TRUE;
				}
			}
			if (!found)
			{
				for (found = FALSE, offset = 0; (!found) && (offset < lw__); offset++)
				{
					if (!strncmp(TERM_data_ptr, Number_names[offset], 3))
					{
						found = TRUE;
						Numbers[offset] = tc_Get_int(Numbers[offset]);
					}
				}
			}
			if (!found)
			{
				for (found = FALSE, offset = 0; (!found) && (offset < smgr__); offset++)
				{
					if (!strncmp(TERM_data_ptr, String_names[offset], 3))
					{
						found = TRUE;
						String_table[offset] = String_Get(String_table[offset]);
					}
				}
			}

			if (!strncmp(TERM_data_ptr, "tc=", 3))
				tc_ = String_Get(NULL);
			while ((*TERM_data_ptr != ':') && (*TERM_data_ptr != (char)NULL))
				TERM_data_ptr++;
			if (*TERM_data_ptr == ':')
				TERM_data_ptr++;
		}
	} while (((TERM_data_ptr = fgets(Data_Line, 512, TFP)) != NULL) && ((*TERM_data_ptr == ' ') || (*TERM_data_ptr == '\t')));
	if (tc_ != NULL)
	{
		TERMINAL_TYPE = tc_;
		rewind(TFP);
		Find_term();
		tc_ = NULL;
		CAP_PARSE();
	}
	else
		fclose(TFP);
}
#endif		/* ifdef CAP	*/

struct _line *
Screenalloc(columns)
int columns;
{
	int i;
	struct _line *tmp;

	tmp = (struct _line *) malloc(sizeof (struct _line));
	tmp->row = malloc(columns + 1);
	tmp->attributes = malloc(columns + 1);
	tmp->prev_screen = NULL;
	tmp->next_screen = NULL;
	for (i = 0; i < columns; i++)
	{
		tmp->row[i] = ' ';
		tmp->attributes[i] = (char) NULL;
	}
	tmp->scroll = tmp->changed = FALSE;
	tmp->row[0] = (char) NULL;
	tmp->attributes[0] = (char) NULL;
	tmp->row[columns] = (char) NULL;
	tmp->attributes[columns] = (char) NULL;
	tmp->last_char = 0;
	return(tmp);
}

WINDOW *newwin(lines, cols, start_l, start_c)
int lines, cols;	/* number of lines and columns to be in window	*/
int start_l, start_c;	/* starting line and column to be inwindow	*/
{
	WINDOW *Ntemp;
	struct _line *temp_screen;
	int i;

	Ntemp = (WINDOW *) malloc(sizeof(WINDOW));
	Ntemp->SR = start_l;
	Ntemp->SC = start_c;
	Ntemp->Num_lines = lines;
	Ntemp->Num_cols = cols;
	Ntemp->LX = 0;
	Ntemp->LY = 0;
	Ntemp->scroll_down = Ntemp->scroll_up = 0;
	Ntemp->SCROLL_CLEAR = FALSE;
	Ntemp->Attrib = FALSE;
	Ntemp->first_line = temp_screen = Screenalloc(cols);
	Ntemp->first_line->number = 0;
	Ntemp->line_array = (struct _line **) malloc(LINES * sizeof(struct _line *));
	
	Ntemp->line_array[0] = Ntemp->first_line;

	for (i = 1; i < lines; i++)
	{
		temp_screen->next_screen = Screenalloc(cols);
		temp_screen->next_screen->number = i;
		temp_screen->next_screen->prev_screen = temp_screen;
		temp_screen = temp_screen->next_screen;
		Ntemp->line_array[i] = temp_screen;
	}
	Ntemp->first_line->prev_screen = NULL;
	temp_screen->next_screen = NULL;
	return(Ntemp);
}

#ifdef CAP
void 
Cap_Out(string, p_list, place)	/* interpret the output string if necessary */
char *string;
int p_list[];			/* stack of values	*/
int place;			/* place keeper of top of stack	*/
{
	char *Otemp;		/* temporary string pointer to parse output */
	int delay;
	int p1, p2, temp;
	float chars;

	if (string == NULL)
		return;

	if (p_list != NULL)
	{
		p1 = p_list[--place];
		p2 = p_list[--place];
	}
	delay = 0;
	Otemp = string;
	if ((*Otemp >= '0') && (*Otemp <= '9'))
	{
		delay = atoi(Otemp);
		while ((*Otemp >= '0') && (*Otemp <= '9'))
			Otemp++;
		if (*Otemp == '*')
			Otemp++;
	}
	while (*Otemp != (char)NULL)
	{
		if (*Otemp == '%')
		{
			Otemp++;
			if ((*Otemp == 'd') || (*Otemp == '2') || (*Otemp == '3') || (*Otemp == '.') || (*Otemp == '+')) 
			{
				if (*Otemp == 'd')
				 	printf("%d", p1);
				else if (*Otemp == '2')
					printf("%02d", p1);
				else if (*Otemp == '3')
					printf("%03d", p1);
				else if (*Otemp == '+')
				{
					Otemp++;
					p1 += *Otemp;
					putchar(p1);
				}
				else if (*Otemp == '.')
					putchar(p1);
				p1 = p2;
				p2 = 0;
			}
			else if (*Otemp == '>')
			{
				Otemp++;
				if (p1 > *Otemp)
				{
					Otemp++;
					p1 += *Otemp;
				}
				else
					Otemp++;
			}
			else if (*Otemp == 'r')
			{
				temp = p1;
				p1 = p2;
				p2 = temp;
			}
			else if (*Otemp == 'i')
			{
				p1++;
				p2++;
			}
			else if (*Otemp == '%')
				putchar(*Otemp);
			else if (*Otemp == 'n')
			{
				p1 ^= 0140;
				p2 ^= 0140;
			}
			else if (*Otemp == 'B')
			{
				p1 = (16 * (p1/10)) + (p1 % 10);
				p2 = (16 * (p2/10)) + (p2 % 10);
			}
			else if (*Otemp == 'D')
			{
				p1 = (p1 - 2 * (p1 % 16));
				p2 = (p2 - 2 * (p2 % 16));
			}
		}
		else
			putchar (*Otemp);
		Otemp++;
	}
	if (delay != 0)
	{
		chars = delay * chars_per_millisecond;
		delay = chars;
		if ((chars - delay) > 0.0)
			delay++;
		for (; delay > 0; delay--)
			putchar(*String_table[pc__]);
	}
	fflush(stdout);
}

#else

	char *Otemp;		/* temporary string pointer to parse output */
	float chars;
	int p[10];
	int variable[27];

int 
Operation(Temp_Stack, place)	/* handle conditional operations	*/
int Temp_Stack[];
int place;
{
	int temp;

	if (*Otemp == 'd')
	{
		Otemp++;
		temp = Temp_Stack[--place];
	 	printf("%d", temp);
	}
	else if (!strncmp(Otemp, "2d", 2))
	{
		temp = Temp_Stack[--place];
		printf("%2d", temp);
		Otemp++;
		Otemp++;
	}
	else if (!strncmp(Otemp, "3d", 2))
	{
		temp = Temp_Stack[--place];
		printf("%0d", temp);
		Otemp++;
		Otemp++;
	}
	else if (!strncmp(Otemp, "02d", 3))
	{
		temp = Temp_Stack[--place];
		printf("%02d", temp);
		Otemp++;
		Otemp++;
		Otemp++;
	}
	else if (!strncmp(Otemp, "03d", 3))
	{
		temp = Temp_Stack[--place];
		printf("%03d", temp);
		Otemp++;
		Otemp++;
		Otemp++;
	}
	else if (*Otemp == '+')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp += Temp_Stack[--place];
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == '-')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp -= Temp_Stack[--place];
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == '*')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp *= Temp_Stack[--place];
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == '/')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp /= Temp_Stack[--place];
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == 'm')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp %= Temp_Stack[--place];
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == '&')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp &= Temp_Stack[--place];
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == '|')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp |= Temp_Stack[--place];
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == '^')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp ^= Temp_Stack[--place];
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == '=')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp = (temp == Temp_Stack[--place]);
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == '>')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp = temp > Temp_Stack[--place];
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == '<')
	{
		Otemp++;
		temp = Temp_Stack[--place];
		temp = temp < Temp_Stack[--place];
		Temp_Stack[place++] = temp;
	}
	else if (*Otemp == 'c')
	{
		Otemp++;
		putchar(Temp_Stack[--place]);
	}
	else if (*Otemp == 'i')
	{
		Otemp++;
		p[1]++;
		p[2]++;
	}
	else if (*Otemp == '%')
	{
		putchar(*Otemp);
		Otemp++;
	}
	else if (*Otemp == '!')
	{
		temp = ! Temp_Stack[--place];
		Temp_Stack[place++] = temp;
		Otemp++;
	}
	else if (*Otemp == '~')
	{
		temp = ~Temp_Stack[--place];
		Temp_Stack[place++] = temp;
		Otemp++;
	}
	else if (*Otemp == 'p')
	{
		Otemp++;
		Temp_Stack[place++] = p[*Otemp - '0'];
		Otemp++;
	}
	else if (*Otemp == 'P')
	{
		Otemp++;
		Temp_Stack[place++] = variable[*Otemp - 'a'];
		Otemp++;
	}
	else if (*Otemp == 'g')
	{
		Otemp++;
		variable[*Otemp - 'a'] = Temp_Stack[--place];
		Otemp++;
	}
	else if (*Otemp == '\'')
	{
		Otemp++;
		Temp_Stack[place++] = *Otemp;
		Otemp++;
		Otemp++;
	}
	else if (*Otemp == '{')
	{
		Otemp++;
		temp = atoi(Otemp);
		Temp_Stack[place++] = temp;
		while (*Otemp != '}')
			Otemp++;
		Otemp++;
	}
	return(place);
}

void 
Info_Out(string, p_list, place)	/* interpret the output string if necessary */
char *string;
int p_list[];
int place;
{
	char *tchar;
	int delay;
	int temp;
	int Cond_FLAG;
	int EVAL;
	int Cond_Stack[128];
	int Cond_place;
	int Stack[128];
	int Top_of_stack;

	if (string == NULL)
		return;

	Cond_FLAG = FALSE;
	Cond_place = 0;
	Top_of_stack = 0;
	p[0] = 0;
	p[1] = 0;
	p[2] = 0;
	p[3] = 0;
	p[4] = 0;
	p[5] = 0;
	p[6] = 0;
	p[7] = 0;
	p[8] = 0;
	p[9] = 0;
	if (p_list != NULL)
	{
		for (temp = 1; (place != 0); temp++)
		{
			p[temp] = p_list[--place];
		}
	}
	delay = 0;
	Otemp = string;
	while (*Otemp != (char) NULL)
	{
		if (*Otemp == '%')
		{
			Otemp++;
			if ((*Otemp == '?') || (*Otemp == 't') || (*Otemp == 'e') || (*Otemp == ';'))
			{
				if (*Otemp == '?')
				{
					Otemp++;
					Cond_FLAG = TRUE;
					EVAL = TRUE;
					while (EVAL)
					{
						/*
						 |  find the end of the 
						 |  conditional statement
						 */
						while ((strncmp(Otemp, "%t", 2)) && (*Otemp != (char) NULL))
						{
							/*
							 |  move past '%'
							 */
							Otemp++;
							Cond_place = Operation(Cond_Stack, Cond_place);
						}

						/*
						 |  if condition is true
						 */
						if ((Cond_place > 0) && (Cond_Stack[Cond_place-1]))
						{
							/*
							 |  end conditional 
							 |  parsing
							 */
							EVAL = FALSE;
							Otemp++;
							Otemp++;
						}
						else	/* condition is false */
						{
							/*
							 |  find 'else' or end 
							 |  of if statement
							 */
							while ((strncmp(Otemp, "%e", 2)) && (strncmp(Otemp, "%;", 2)) && (*Otemp != (char) NULL))
								Otemp++;
							/*
							 |  if an 'else' found
							 */
							if ((*Otemp != (char) NULL) && (!strncmp(Otemp, "%e", 2)))
							{
								Otemp++;
								Otemp++;
								tchar = Otemp;
								/*
								 |  check for 'then' part
								 */
								while ((*tchar != (char) NULL) && (strncmp(tchar, "%t", 2)) && (strncmp(tchar, "%;", 2)))
									tchar++;
								/*
								 |  if end of string
								 */
								if (*tchar == (char) NULL)
								{
									EVAL = FALSE;
									Cond_FLAG = FALSE;
									Otemp = tchar;
								}
								/*
								 |  if end of if found,
								 |  set up to parse 
								 |  info
								 */
								else if (!strncmp(tchar, "%;", 2))
									EVAL = FALSE;
								/*
								 |  otherwise, check 
								 |  conditional in 
								 |  'else'
								 */
							}
							/*
							 |  if end of if found,
							 |  get out of if 
							 |  statement
							 */
							else if ((*Otemp != (char) NULL) && (!strncmp(Otemp, "%;", 2)))
							{
								EVAL = FALSE;
								Otemp++;
								Otemp++;
							}
							else /* Otemp == NULL */
							{
								EVAL = FALSE;
								Cond_FLAG = FALSE;
							}
						}
					}
				}
				else
				{
					Otemp++;
					Cond_FLAG = FALSE;
					if (*Otemp != ';')
					{
						while ((*Otemp != (char) NULL) && (strncmp(Otemp, "%;", 2)))
							Otemp++;
						if (*Otemp != (char) NULL)
						{
							Otemp++;
							Otemp++;
						}
					}
					else
						Otemp++;
				}
			}
			else
			{
				Top_of_stack = Operation(Stack, Top_of_stack);
			}
		}
		else if (!strncmp(Otemp, "$<", 2))
		{
			Otemp++;
			Otemp++;
			delay = atoi(Otemp);
			while (*Otemp != '>')
				Otemp++;
			Otemp++;
			chars = delay * chars_per_millisecond;
			delay = chars;
			if ((chars - delay) > 0.0)
				delay++;
			if (String_table[pc__] == NULL)
				temp = 0;
			else
				temp = *String_table[pc__];
			for (; delay > 0; delay--)
				putc(temp, stdout);
		}
		else
		{
			putchar(*Otemp);
			Otemp++;
		}
	}
	fflush(stdout);
}
#endif

void 
wmove(window, row, column)	/* move cursor to indicated position in window */
WINDOW *window;
int row, column;
{
	if ((row < window->Num_lines) && (column < window->Num_cols))
	{
		window->LX = column;
		window->LY = row;
	}
}

void 
clear_line(line, column, cols)
struct _line *line;
int column;
int cols;
{
	int j;

	if (column > line->last_char)
	{
		for (j = line->last_char; j < column; j++)
		{
			line->row[j] = ' ';
			line->attributes[j] = (char) NULL;
		}
	}
	line->last_char = column;
	line->row[column] = (char) NULL;
	line->attributes[column] = (char) NULL;
	line->changed = TRUE;
}

void 
werase(window)			/* clear the specified window		*/
WINDOW *window;
{
	int i;
	struct _line *tmp;

	window->SCROLL_CLEAR = CLEAR;
	window->scroll_up = window->scroll_down = 0;
	for (i = 0, tmp = window->first_line; i < window->Num_lines; i++, tmp = tmp->next_screen)
		clear_line(tmp, 0, window->Num_cols);
}

void 
wclrtoeol(window)	/* erase from current cursor position to end of line */
WINDOW *window;
{
	int column, row;
	struct _line *tmp;

	window->SCROLL_CLEAR = CHANGE;
	column = window->LX;
	row = window->LY;
	for (row = 0, tmp = window->first_line; row < window->LY; row++)
		tmp = tmp->next_screen;
	clear_line(tmp, column, window->Num_cols);
}

void 
wrefresh(window)		/* flush all previous output		*/
WINDOW *window;
{
	wnoutrefresh(window);
#ifdef DIAG
{
	struct _line *temp;
	int value;
	fprintf(stderr, "columns=%d, lines=%d, SC=%d, SR=%d\n",window->Num_cols, window->Num_lines, window->SC, window->SR);
	for (value = 0, temp = window->first_line; value < window->Num_lines; value++, temp = temp->next_screen)
	{
		if (temp->number == -1)
			fprintf(stderr, "line moved ");
		if (temp->scroll)
			fprintf(stderr, "scroll_x is set:  ");
		fprintf(stderr, "lc%d=%s|\n", temp->last_char, temp->row);
	}
	fprintf(stderr, "+-------------------- virtual screen ----------------------------------------+\n");
	fprintf(stderr, "columns=%d, lines=%d \n",virtual_scr->Num_cols, virtual_scr->Num_lines);
	for (value = 0, temp = virtual_scr->first_line; value < virtual_scr->Num_lines; value++, temp = temp->next_screen)
	{
		if (temp->number == -1)
			fprintf(stderr, "line moved ");
		if (temp->scroll)
			fprintf(stderr, "scroll_x is set:  ");
		fprintf(stderr, "lc%d=%s|\n", temp->last_char, temp->row);
	}
	fprintf(stderr, "columns=%d, lines=%d \n",curscr->Num_cols, curscr->Num_lines);
	for (value = 0, temp = curscr->first_line; value < curscr->Num_lines; value++, temp = temp->next_screen)
		fprintf(stderr, "line=%s|\n", temp->row);
}
#endif
	doupdate();
	virtual_scr->SCROLL_CLEAR = FALSE;
	virtual_scr->scroll_down = virtual_scr->scroll_up = 0;
	fflush(stdout);
}

void 
touchwin(window)
WINDOW *window;
{
	struct _line *user_line;
	int line_counter = 0;

	for (line_counter = 0, user_line = window->first_line; 
		line_counter < window->Num_lines; line_counter++)
	{
		user_line->changed = TRUE;
	}
	window->SCROLL_CLEAR = TRUE;
}

void 
wnoutrefresh(window)
WINDOW *window;
{
	struct _line *user_line;
	struct _line *virtual_line;
	int line_counter = 0;
	int user_col = 0;
	int virt_col = 0;

	if (window->SR >= virtual_scr->Num_lines)
		return;
	user_line = window->first_line;
	virtual_line = virtual_scr->first_line;
	virtual_scr->SCROLL_CLEAR = window->SCROLL_CLEAR;
	virtual_scr->LX = window->LX + window->SC;
	virtual_scr->LY = window->LY + window->SR;
	virtual_scr->scroll_up = window->scroll_up;
	virtual_scr->scroll_down = window->scroll_down;
	if ((last_window_refreshed == window) && (!window->SCROLL_CLEAR))
		return;
	for (line_counter = 0; line_counter < window->SR; line_counter++)
	{
		virtual_line = virtual_line->next_screen;
	}
	for (line_counter = 0; (line_counter < window->Num_lines)
		&& ((line_counter + window->SR) < virtual_scr->Num_lines); 
			line_counter++)
	{
		if ((last_window_refreshed != window) || (user_line->changed) || ((SCROLL | CLEAR) & window->SCROLL_CLEAR))
		{
			for (user_col = 0, virt_col = window->SC; 
				(virt_col < virtual_scr->Num_cols) 
				  && (user_col < user_line->last_char); 
				  	virt_col++, user_col++)
			{
				virtual_line->row[virt_col] = user_line->row[user_col];
				virtual_line->attributes[virt_col] = user_line->attributes[user_col];
			}
			for (user_col = user_line->last_char, 
			     virt_col = window->SC + user_line->last_char; 
				(virt_col < virtual_scr->Num_cols) 
				  && (user_col < window->Num_cols); 
				  	virt_col++, user_col++)
			{
				virtual_line->row[virt_col] = ' ';
				virtual_line->attributes[virt_col] = (char) NULL;
			}
		}
		if (virtual_scr->Num_cols != window->Num_cols)
		{
			if (virtual_line->last_char < (user_line->last_char + window->SC))
			{
				if (virtual_line->row[virtual_line->last_char] == (char) NULL)
					virtual_line->row[virtual_line->last_char] = ' ';
				virtual_line->last_char = 
					min(virtual_scr->Num_cols, 
					  (user_line->last_char + window->SC));
			}
		}
		else
			virtual_line->last_char = user_line->last_char;
		virtual_line->row[virtual_line->last_char] = (char) NULL;
		virtual_line->changed = user_line->changed;
		virtual_line = virtual_line->next_screen;
		user_line = user_line->next_screen;
	}
	window->SCROLL_CLEAR = FALSE;
	window->scroll_up = window->scroll_down = 0;
	last_window_refreshed = window;
}

void 
flushinp()			/* flush input				*/
{
}

void 
ungetch(c)			/* push a character back on input	*/
int c;
{
	if (bufp < 100)
		in_buff[bufp++] = c;
}

#ifdef BSD_SELECT
int 
timed_getchar()
{
	struct timeval tv;
	fd_set fds;
	int ret_val;
	int nfds = 1;
	char temp;

	FD_ZERO(&fds);
	tv.tv_sec = 0;
	tv.tv_usec = 500000;  /* half a second */
	FD_SET(0, &fds);
	Time_Out = FALSE; /* just in case */

	ret_val = select(nfds, &fds, 0, 0, &tv);

	/*
	 |	if ret_val is less than zero, there was no input
	 |	otherwise, get a character and return it
	 */

	if (ret_val <= 0)
	{ 
		Time_Out = TRUE;
		return(-1);
	}

	return(read(0, &temp, 1)? temp : -1);
}
#endif

int 
wgetch(window)			/* get character from specified window	*/
WINDOW *window;
{
	int in_value;
	char temp;
#ifndef SYS5
	int old_arg;
#endif /* SYS5 */

#ifdef BSD_SELECT
	if (Noblock)
		in_value = ((bufp > 0) ? in_buff[--bufp] : timed_getchar());
	else
		in_value = ((bufp > 0) ? in_buff[--bufp] : read(0, &temp, 1)? temp : -1);
#else /* BSD_SELECT */
#ifdef SYS5
	in_value = ((bufp > 0) ? in_buff[--bufp] : 
					(read(0, &temp, 1)> 0) ? temp : -1);
#else /* SYS5 */
	if (Noblock)
	{
		Time_Out = FALSE;
		old_arg = fcntl(0, F_GETFL, 0);
		in_value = fcntl(0, F_SETFL, old_arg | FNDELAY);
	}
	in_value = ((bufp > 0) ? in_buff[--bufp] : read(0, &temp, 1)? temp : -1);
	if (Noblock)
	{
		fcntl(0, F_SETFL, old_arg);
		if (Time_Out)
			in_value = -1;
	}
#endif /* SYS5 */
#endif /* BSD_SELECT */

	if (in_value != -1) 
	{
		in_value &= 0xff;
		if ((Parity) && (Num_bits < 8))	
				/* strip eighth bit if parity in use */
		in_value &= 0177;
	}
	else if (interrupt_flag)
	{
		interrupt_flag = FALSE;
		in_value = wgetch(window);
	}

	if ((in_value == '\033') || (in_value == '\037'))/* escape character */
		in_value = Get_key(in_value);
	return(in_value);
}

#ifndef BSD_SELECT
void 
Clear(arg)		/* notify that time out has occurred	*/
int arg;
{
	Time_Out = TRUE;
#ifdef DEBUG
fprintf(stderr, "inside Clear()\n");
fflush(stderr);
#endif /* DEBUG */
}
#endif /* BSD_SELECT */

int 
Get_key(first_char)			/* try to decode key sequence	*/
int first_char;				/* first character of sequence	*/
{
	int in_char;
	int Count;
	char string[128];
	char *Gtemp;
	int Found;
#ifdef SYS5
	struct termio Gterminal;
#else
	struct sgttyb Gterminal;
#endif
	struct KEY_STACK *St_point;
#if (!defined( BSD_SELECT)) || (!defined(SYS5))
	int value;
#endif /* BSD_SELECT */

	Count = 0;
	Gtemp = string;
	string[Count++] = first_char;
	string[Count] = (char) NULL;
	Time_Out = FALSE;
#ifndef BSD_SELECT
	signal(SIGALRM, Clear);
	value = alarm(1);
#endif /* BSD_SELECT */
	Noblock = TRUE;
#ifdef SYS5
	Gterminal.c_cc[VTIME] = 0;		/* timeout value	*/
	Gterminal.c_lflag &= ~ICANON;	/* disable canonical operation	*/
	Gterminal.c_lflag &= ~ECHO;		/* disable echo		*/
#endif
	Count = 1;
	Found = FALSE;
	while ((Count < Max_Key_len) && (!Time_Out) && (!Found))
	{
		in_char = wgetch(stdscr);
#ifdef DEBUG
fprintf(stderr, "back in GetKey()\n");
fflush(stderr);
#endif /* DEBUG */
		if (in_char != -1)
		{
			string[Count++] = in_char;
			string[Count] = (char) NULL;
			St_point = KEY_TOS;
			while ((St_point != NULL) && (!Found))
			{
				if (!strcmp(string, St_point->element->string))
					Found = TRUE;
				else
					St_point = St_point->next;
			}
		}
	}
#ifndef BSD_SELECT
	if (!Time_Out)
		value = alarm(0);
#endif /* BSD_SELECT */
#ifdef SYS5
/*	value = ioctl(0, TCSETA, &Terminal);*/
#else
	value = ioctl(0, TIOCSETP, &Terminal);
/*	value = fcntl(0, F_SETFL, old_arg);*/
#endif
	Noblock = FALSE;
	if (Found)
	{
		return(St_point->element->value);
	}
	else
	{
		while (Count > 1)
		{
			if ((string[--Count] != -1) && 
					((unsigned char) (string[Count]) != 255))
			{
#ifdef DIAG
fprintf(stderr, "ungetting character %d\n", string[Count]);fflush(stdout);
#endif
				ungetch(string[Count]);
			}
		}
		return(first_char);
	}
}

void 
waddch(window, c)	/* output the character in the specified window	*/
WINDOW *window;
int c;
{
	int column, j;
	int shift;	/* number of spaces to shift if a tab		*/
	struct _line *tmpline;

#ifdef DIAG
/*printf("starting waddch \n");fflush(stdout);*/
#endif
	column = window->LX;
	if (c == '\t')
	{
		shift = (column + 1) % 8;
		if (shift == 0)
			shift++;
		else
			shift = 9 - shift;
		while (shift > 0)
		{
			shift--;
			waddch(window, ' ');
		}
	}
	else if ((column < window->Num_cols) && (window->LY < window->Num_lines))
	{
		if ((c == '~') && (Booleans[hz__]))
			c = '@';

		if (( c != '\b') && (c != '\n') && (c != '\r'))
		{
			tmpline = window->line_array[window->LY];
			tmpline->row[column] = c;
			tmpline->attributes[column] = window->Attrib;
			tmpline->changed = TRUE;
			if (column >= tmpline->last_char)
			{
				if (column > tmpline->last_char)
					for (j = tmpline->last_char; j < column; j++)
					{
						tmpline->row[j] = ' ';
						tmpline->attributes[j] = (char) NULL;
					}
				tmpline->row[column + 1] = (char) NULL;
				tmpline->attributes[column + 1] = (char) NULL;
				tmpline->last_char = column + 1;
			}
		}
		if (c == '\n')
		{
			wclrtoeol(window);
			window->LX = window->Num_cols;
		}
		else if (c == '\r')
			window->LX = 0;
		else if (c == '\b')
			window->LX--;
		else
			window->LX++;
	}
	if (window->LX >= window->Num_cols)
	{
		window->LX = 0;
		window->LY++;
		if (window->LY >= window->Num_lines)
		{
			window->LY = window->Num_lines - 1;
/*			window->LY = row;
			wmove(window, 0, 0);
			wdeleteln(window);
			wmove(window, row, 0);*/
		}
	}
	window->SCROLL_CLEAR = CHANGE;
}

void 
winsertln(window)	/* insert a blank line into the specified window */
WINDOW *window;
{
	int row, column;
	struct _line *tmp;
	struct _line *tmp1;

	window->scroll_down += 1;
	window->SCROLL_CLEAR = SCROLL;
	column = window->LX;
	row = window->LY;
	for (row = 0, tmp = window->first_line; (row < window->Num_lines) && (tmp->next_screen != NULL); row++)
		tmp = tmp->next_screen;
	if (tmp->prev_screen != NULL)
		tmp->prev_screen->next_screen = NULL;
	tmp1 = tmp;
	clear_line(tmp1, 0, window->Num_cols);
	tmp1->number = -1;
	for (row = 0, tmp = window->first_line; (row < window->LY) && (tmp->next_screen != NULL); row++)
		tmp = tmp->next_screen;
	if ((window->LY == (window->Num_lines - 1)) && (window->Num_lines > 1))
	{
		tmp1->next_screen = tmp->next_screen;
		tmp->next_screen = tmp1;
		tmp->changed = TRUE;
		tmp->next_screen->prev_screen = tmp;
	}
	else if (window->Num_lines > 1)
	{
		if (tmp->prev_screen != NULL)
			tmp->prev_screen->next_screen = tmp1;
		tmp1->prev_screen = tmp->prev_screen;
		tmp->prev_screen = tmp1;
		tmp1->next_screen = tmp;
		tmp->changed = TRUE;
		tmp->scroll = DOWN;
	}
	if (window->LY == 0)
		window->first_line = tmp1;

	for (row = 0, tmp1 = window->first_line; 
		row < window->Num_lines; row++)
	{
		window->line_array[row] = tmp1;
		tmp1 = tmp1->next_screen;
	}
}

void 
wdeleteln(window)	/* delete a line in the specified window */
WINDOW *window;
{
	int row, column;
	struct _line *tmp;
	struct _line  *tmpline;

	if (window->Num_lines > 1)
	{
		window->scroll_up += 1;
		window->SCROLL_CLEAR = SCROLL;
		column = window->LX;
		row = window->LY;
		for (row = 0, tmp = window->first_line; row < window->LY; row++)
			tmp = tmp->next_screen;
		if (window->LY == 0)
			window->first_line = tmp->next_screen;
		if (tmp->prev_screen != NULL)
			tmp->prev_screen->next_screen = tmp->next_screen;
		if (tmp->next_screen != NULL)
		{
			tmp->next_screen->changed = TRUE;
			tmp->next_screen->scroll = UP;
			tmp->next_screen->prev_screen = tmp->prev_screen;
		}
		tmpline = tmp;
		clear_line(tmpline, 0, window->Num_cols);
		tmpline->number = -1;
		for (row = 0, tmp = window->first_line; tmp->next_screen != NULL; row++)
			tmp = tmp->next_screen;
		if (tmp != NULL)
		{
			tmp->next_screen = tmpline;
			tmp->next_screen->prev_screen = tmp;
			tmp->changed = TRUE;
			tmp = tmp->next_screen;
		}
		else
			tmp = tmpline;
		tmp->next_screen = NULL;

		for (row = 0, tmp = window->first_line; row < window->Num_lines; row++)
		{
			window->line_array[row] = tmp;
			tmp = tmp->next_screen;
		}
	}
	else
	{
		clear_line(window->first_line, 0, window->Num_cols);
	}
}

void 
wclrtobot(window)	/* delete from current position to end of the window */
WINDOW *window;
{
	int row, column;
	struct _line *tmp;

	window->SCROLL_CLEAR |= CLEAR;
	column = window->LX;
	row = window->LY;
	for (row = 0, tmp = window->first_line; row < window->LY; row++)
		tmp = tmp->next_screen;
	clear_line(tmp, column, window->Num_cols);
	for (row = (window->LY + 1); row < window->Num_lines; row++)
	{
		tmp = tmp->next_screen;
		clear_line(tmp, 0, window->Num_cols);
	}
	wmove(window, row, column);
}

void 
wstandout(window)	/* begin standout mode in window	*/
WINDOW *window;
{
	if (Numbers[sg__] < 1)	/* if not magic cookie glitch	*/
		window->Attrib |= A_STANDOUT;
}

void 
wstandend(window)	/* end standout mode in window	*/
WINDOW *window;
{
	window->Attrib &= ~A_STANDOUT;
}

void 
waddstr(window, string)	/* write 'string' in window	*/
WINDOW *window;
char *string;
{
	char *wstring;

	for (wstring = string; *wstring != (char) NULL; wstring++)
		waddch(window, *wstring);
}

void 
clearok(window, flag)	/* erase screen and redraw at next refresh	*/
WINDOW *window;
int flag;
{
	Repaint_screen = TRUE;
}


void 
echo()			/* turn on echoing				*/
{
	int value;

#ifdef SYS5
	Terminal.c_lflag |= ECHO;		/* enable echo		*/
	value = ioctl(0, TCSETA, &Terminal);	/* set characteristics	*/
#else
	Terminal.sg_flags |= ECHO;		/* enable echo		*/
	value = ioctl(0, TIOCSETP, &Terminal);	/* set characteristics	*/
#endif
}

void 
noecho()		/* turn off echoing				*/
{
	int value;

#ifdef SYS5
	Terminal.c_lflag &= ~ECHO;		/* disable echo		*/
	value = ioctl(0, TCSETA, &Terminal);	/* set characteristics	*/
#else
	Terminal.sg_flags &= ~ECHO;		/* disable echo		*/
	value = ioctl(0, TIOCSETP, &Terminal);	/* set characteristics	*/
#endif
}

void 
raw()			/* set to read characters immediately		*/
{
	int value;

#ifdef SYS5
	Intr = Terminal.c_cc[VINTR];	/* get the interrupt character	*/
	Terminal.c_lflag &= ~ICANON;	/* disable canonical operation	*/
	Terminal.c_lflag &= ~ISIG;	/* disable signal checking	*/
#ifdef FLUSHO
	Terminal.c_lflag &= ~FLUSHO;
#endif
#ifdef PENDIN
	Terminal.c_lflag &= ~PENDIN;
#endif
#ifdef IEXTEN
	Terminal.c_lflag &= ~IEXTEN;
#endif
	Terminal.c_cc[VMIN] = 1;		/* minimum of one character */
	Terminal.c_cc[VTIME] = 0;		/* timeout value	*/
	Terminal.c_cc[VINTR] = 0;		/* eliminate interrupt	*/
	value = ioctl(0, TCSETA, &Terminal);	/* set characteristics	*/
#else
	Terminal.sg_flags |= RAW;	/* enable raw mode		*/
	value = ioctl(0, TIOCSETP, &Terminal);	/* set characteristics	*/
#endif
}

void 
noraw()			/* set to normal character read mode		*/
{
	int value;

#ifdef SYS5
	Terminal.c_lflag |= ICANON;	/* enable canonical operation	*/
	Terminal.c_lflag |= ISIG;	/* enable signal checking	*/
	Terminal.c_cc[VEOF] = 4;		/* EOF character = 4	*/
	Terminal.c_cc[VEOL] = (char) NULL;	/* EOL = 0		*/
	Terminal.c_cc[VINTR] = Intr;		/* reset interrupt char	*/
	value = ioctl(0, TCSETA, &Terminal);	/* set characteristics	*/
#else
	Terminal.sg_flags &= ~RAW;	/* disable raw mode		*/
	value = ioctl(0, TIOCSETP, &Terminal);	/* set characteristics	*/
/*	old_arg = fcntl(0, F_GETFL, 0);
	value = fcntl(0, F_SETFL, old_arg & ~FNDELAY);*/
#endif
}

void 
nl()
{
	int value;

#ifdef SYS5
	Terminal.c_iflag |= ICRNL;	/* enable carriage-return to line-feed mapping	*/
	value = ioctl(0, TCSETA, &Terminal);	/* set characteristics	*/
#endif
}

void 
nonl()
{
	int value;

#ifdef SYS5
	Terminal.c_iflag &= ~ICRNL;	/* disable carriage-return to line-feed mapping	*/
	Terminal.c_iflag &= ~IGNCR;	/* do not ignore carriage-return	*/
	value = ioctl(0, TCSETA, &Terminal);	/* set characteristics	*/
#endif
}

void 
saveterm()
{
}

void 
fixterm()
{
}

void 
resetterm()
{
}

void 
nodelay(window, flag)
WINDOW *window;
int flag;
{
}

void 
idlok(window, flag)
WINDOW *window;
int flag;
{
}

void 
keypad(window, flag)
WINDOW *window;
int flag;
{
	if (flag)
		String_Out(String_table[ks__], NULL, 0);
	else
		String_Out(String_table[ke__], NULL, 0);
}

void 
savetty()		/* save current tty stats			*/
{
	int value;

#ifdef SYS5
	value = ioctl(0, TCGETA, &Saved_tty);	/* set characteristics	*/
#else
	value = ioctl(0, TIOCGETP, &Saved_tty);	/* set characteristics	*/
#endif
}

void 
resetty()		/* restore previous tty stats			*/
{
	int value;

#ifdef SYS5
	value = ioctl(0, TCSETA, &Saved_tty);	/* set characteristics	*/
#else
	value = ioctl(0, TIOCSETP, &Saved_tty);	/* set characteristics	*/
#endif
}

void 
endwin()		/* end windows					*/
{
	keypad(stdscr, FALSE);
	initialized = FALSE;
	delwin(curscr);
	delwin(virtual_scr);
	delwin(stdscr);
#ifndef SYS5
{
	int old_arg, value;
/*	old_arg = fcntl(0, F_GETFL, 0);
	value = fcntl(0, F_SETFL, old_arg & ~FNDELAY);*/
}
#endif
}

void 
delwin(window)		/* delete the window structure			*/
WINDOW *window;
{
	int i;

	for (i = 1; (i < window->Num_lines) && (window->first_line->next_screen != NULL); i++)
	{
		window->first_line = window->first_line->next_screen;
		free(window->first_line->prev_screen->row);
		free(window->first_line->prev_screen->attributes);
		free(window->first_line->prev_screen);
	}
	if (window == last_window_refreshed)
		last_window_refreshed = 0;
	if (window->first_line != NULL)
	{
		free(window->first_line->row);
		free(window->first_line->attributes);
		free(window->first_line);
		free(window);
	}
}

#ifndef __STDC__
void 
wprintw(va_alist)
va_dcl
#else /* __STDC__ */
void 
wprintw(WINDOW *window, const char *format, ...)
#endif /* __STDC__ */
{
#ifndef __STDC__
	WINDOW *window;
	char *format;
	va_list ap;
#else
	va_list ap;
#endif
	int value;
	char *fpoint;
	char *wtemp;

#ifndef __STDC__
	va_start(ap);
	window = va_arg(ap, WINDOW *);
	format = va_arg(ap, char *);
#else /* __STDC__ */
	va_start(ap, format);
#endif /* __STDC__ */

	fpoint = (char *) format;
	while (*fpoint != (char) NULL)
	{
		if (*fpoint == '%')
		{
			fpoint++;
			if (*fpoint == 'd')
			{
				value = va_arg(ap, int);
				iout(window, value);
			}
			else if (*fpoint == 'c')
			{
				value = va_arg(ap, int);
				waddch(window, value);
			}
			else if (*fpoint == 's')
			{
				wtemp = va_arg(ap, char *);
					waddstr(window, wtemp);
			}
			fpoint++;
		}
		else if (*fpoint == '\\')
		{
			fpoint++;
			if (*fpoint == 'n')
				waddch(window, '\n');
			else if ((*fpoint >= '0') && (*fpoint <= '9'))
			{
				value = 0;
				while ((*fpoint >= '0') && (*fpoint <= '9'))
				{
					value = (value * 8) + (*fpoint - '0');
					fpoint++;
				}
				waddch(window, value);
			}
			fpoint++;
		}
		else
			waddch(window, *fpoint++);
	}
#ifdef __STDC__
	va_end(ap);
#endif /* __STDC__ */
}

void 
iout(window, value)	/* output characters		*/
WINDOW *window;
int value;
{
	int i;

	if ((i = value / 10) != 0)
		iout(window, i);
	waddch(window, ((value % 10) + '0'));
}

int 
Comp_line(line1, line2)		/* compare lines	*/
struct _line *line1;
struct _line *line2;
{
	int count1;
	int i;
	char *att1, *att2;
	char *c1, *c2;

	if (line1->last_char != line2->last_char)
		return(2);

	c1 = line1->row;
	c2 = line2->row;
	att1 = line1->attributes;
	att2 = line2->attributes;
	i = 0;
	while ((c1[i] != (char) NULL) && (c2[i] != (char) NULL) && (c1[i] == c2[i]) && (att1[i] == att2[i]))
		i++;
	count1 = i + 1;
	if ((count1 == 1) && (c1[i] == (char) NULL) && (c2[i] == (char) NULL))
		count1 = 0;			/* both lines blank	*/
	else if ((c1[i] == (char) NULL) && (c2[i] == (char) NULL))
		count1 = -1;			/* equal		*/
	else
		count1 = 1;			/* lines unequal	*/
	return(count1);
}

struct _line *
Insert_line(row, end_row, window)	/* insert line into screen */
int row;
int end_row;
WINDOW *window;
{
	int i;
	struct _line *tmp;
	struct _line *tmp1;

	for (i = 0, tmp = curscr->first_line; i < window->SR; i++)
		tmp = tmp->next_screen;
	if ((end_row + window->SR) == 0)
		curscr->first_line = curscr->first_line->next_screen;
	top_of_win = tmp;
	/*
	 |	find bottom line to delete
	 */
	for (i = 0, tmp = top_of_win; (tmp->next_screen != NULL) && (i < end_row); i++)
		tmp = tmp->next_screen;
	if (tmp->prev_screen != NULL)
		tmp->prev_screen->next_screen = tmp->next_screen;
	if (tmp->next_screen != NULL)
		tmp->next_screen->prev_screen = tmp->prev_screen;
	tmp1 = tmp;
	/*
	 |	clear deleted line
	 */
	clear_line(tmp, 0, window->Num_cols);
	tmp1->number = -1;
	for (i = 0, tmp = curscr->first_line; (tmp->next_screen != NULL) && (i < window->SR); i++)
		tmp = tmp->next_screen;
	top_of_win = tmp;
	for (i = 0, tmp = top_of_win; i < row; i++)
		tmp = tmp->next_screen;
	if ((tmp->prev_screen != NULL) && (window->Num_lines > 0))
		tmp->prev_screen->next_screen = tmp1;
	tmp1->prev_screen = tmp->prev_screen;
	tmp->prev_screen = tmp1;
	tmp1->next_screen = tmp;
	if ((row + window->SR) == 0)
		curscr->first_line = tmp1;
	if (tmp1->next_screen != NULL)
		tmp1 = tmp1->next_screen;

	if ((!String_table[cs__]) && (end_row < window->Num_lines))
	{
		Position(window, (window->SR + end_row), 0);
		String_Out(String_table[dl__], NULL, 0);
	}
	Position(window, (window->SR + row), 0);
	if (String_table[al__] != NULL)
		String_Out(String_table[al__], NULL, 0);
	else
		String_Out(String_table[sr__], NULL, 0);

	for (i = 0, top_of_win = curscr->first_line; (top_of_win->next_screen != NULL) && (i < window->SR); i++)
		top_of_win = top_of_win->next_screen;
	return(tmp1);
}


struct _line *
Delete_line(row, end_row, window)	/* delete a line on screen */
int row;
int end_row;
WINDOW *window;
{
	int i;
	struct _line *tmp;
	struct _line *tmp1;
	struct _line *tmp2;

	i = 0;
	tmp = curscr->first_line;
	while (i < window->SR)
	{
		i++;
		tmp = tmp->next_screen;
	}
	/*
	 |	find line to delete
	 */
	top_of_win = tmp;
	if ((row + window->SR) == 0)
		curscr->first_line = top_of_win->next_screen;
	for (i = 0, tmp = top_of_win; i < row; i++)
		tmp = tmp->next_screen;
	if (tmp->prev_screen != NULL)
		tmp->prev_screen->next_screen = tmp->next_screen;
	if (tmp->next_screen != NULL)
		tmp->next_screen->prev_screen = tmp->prev_screen;
	tmp2 = tmp->next_screen;
	tmp1 = tmp;
	/*
	 |	clear deleted line
	 */
	clear_line(tmp1, 0, window->Num_cols);
	tmp1->number = -1;
	/*
	 |	find location to insert deleted line
	 */
	for (i = 0, tmp = curscr->first_line; (tmp->next_screen != NULL) && (i < window->SR); i++)
		tmp = tmp->next_screen;
	top_of_win = tmp;
	for (i = 0, tmp = top_of_win; (i < end_row) && (tmp->next_screen != NULL); i++)
		tmp = tmp->next_screen;
	tmp1->next_screen = tmp;
	tmp1->prev_screen = tmp->prev_screen;
	if (tmp1->prev_screen != NULL)
		tmp1->prev_screen->next_screen = tmp1;
	tmp->prev_screen = tmp1;

	Position(window, (window->SR + row), 0);
	String_Out(String_table[dl__], NULL, 0);
	if ((!String_table[cs__]) && (end_row < window->Num_lines))
	{
		Position(window, (window->SR + end_row), 0);
		String_Out(String_table[al__], NULL, 0);
	}
	else if ((String_table[cs__] != NULL) && (String_table[dl__] == NULL))
	{
		Position(window, (window->SR + end_row), 0);
		putchar('\n');
	}

	if (row == (window->Num_lines-1))
		tmp2 = tmp1;
	if ((row + window->SR) == 0)
		curscr->first_line = top_of_win = tmp2;
	return(tmp2);
}

void 
CLEAR_TO_EOL(window, row, column)
WINDOW *window;
int row, column;
{
	int x, y;
	struct _line *tmp1;

	for (y = 0, tmp1 = curscr->first_line; (y < (window->SR+row)) && (tmp1->next_screen != NULL); y++)
		tmp1 = tmp1->next_screen;
	for (x = column; x<window->Num_cols; x++)
	{
		tmp1->row[x] = ' ';
		tmp1->attributes[x] = (char) NULL;
	}
	tmp1->row[column] = (char) NULL;
	tmp1->last_char = column;
	if (column < COLS)
	{
		if (STAND)
		{
			STAND = FALSE;
			Position(window, row, column);
			attribute_off();
		}
		if (String_table[ce__] != NULL)
			String_Out(String_table[ce__], NULL, 0);
		else
		{
			for (x = column; x < window->Num_cols; x++)
				putchar(' ');
			Curr_x = x;
		}
	}
}

int 
check_delete(window, line, offset, pointer_new, pointer_old)
WINDOW *window;
int line, offset;
struct _line *pointer_new, *pointer_old;
{
	int end_old;
	int end_new;
	int k;
	int changed;
	char *old_lin;
	char *new_lin;
	char *old_att;
	char *new_att;
	
	changed = FALSE;
	new_lin = pointer_new->row;
	new_att = pointer_new->attributes;
	old_lin = pointer_old->row;
	old_att = pointer_old->attributes;
	end_old = end_new = offset;
	while (((new_lin[end_new] != old_lin[end_old]) || (new_att[end_new] != old_att[end_old])) && (old_lin[end_old] != (char) NULL) && (new_lin[end_old] != (char) NULL))
		end_old++;
	if (old_lin[end_old] != (char) NULL)
	{
		k = 0;
		while ((old_lin[end_old+k] == new_lin[end_new+k]) && (new_att[end_new+k] == old_att[end_old+k]) && (new_lin[end_new+k] != (char) NULL) && (old_lin[end_old+k] != (char) NULL) && (k < 10))
			k++;
		if ((k > 8) || ((new_lin[end_new+k] == (char) NULL) && (k != 0)))
		{
			if (new_lin[end_new+k] == (char) NULL)
			{
				Position(window, line, (end_new+k));
				CLEAR_TO_EOL(window, line, (end_new+k));
			}
			Position(window, line, offset);
			for (k = offset; k < end_old; k++)
				Char_del(old_lin, old_att, offset, window->Num_cols);
			while ((old_lin[offset] != (char) NULL) && (offset < COLS))
				offset++;
			pointer_old->last_char = offset;
			changed = TRUE;
		}
	}
	return(changed);
}

/*
 |	Check if characters were inserted in the middle of a line, and if 
 |	so, insert them.
 */

int 
check_insert(window, line, offset, pointer_new, pointer_old)
WINDOW *window;
int line, offset;
struct _line *pointer_new, *pointer_old;
{
	int changed;
	int end_old, end_new;
	int k;
	int same = FALSE;
	int old_off;
	int insert;
	char *old_lin;
	char *new_lin;
	char *old_att;
	char *new_att;

	changed = FALSE;
	new_lin = pointer_new->row;
	new_att = pointer_new->attributes;
	old_lin = pointer_old->row;
	old_att = pointer_old->attributes;
	end_old = end_new = offset;
	while (((new_lin[end_new] != old_lin[end_old]) || (new_att[end_new] != old_att[end_old])) && (new_lin[end_new] != (char) NULL) && (old_lin[end_new] != (char) NULL))
		end_new++;
	if (new_lin[end_new] != (char) NULL)
	{
		k = 0;
		while ((old_lin[end_old+k] == new_lin[end_new+k]) && (old_att[end_old+k] == new_att[end_new+k]) && (new_lin[end_new+k] != (char) NULL) && (old_lin[end_old+k] != (char) NULL) && (k < 10))
			k++;
		/*
		 |  check for commonality between rest of lines (are the old 
		 |  and new lines the same, except for a chunk in the middle?)
		 |  if the rest of the lines are common, do not insert text
		 */
		old_off = end_new;
		while ((old_lin[old_off] != (char) NULL) && (new_lin[old_off] != (char) NULL) && (old_lin[old_off] == new_lin[old_off]) && (old_att[old_off] == new_att[old_off]))
			old_off++;
		if ((old_lin[old_off] == new_lin[old_off]) && (old_att[old_off] == new_att[old_off]))
			same = TRUE;
		if ((!same) && ((k > 8) || ((new_lin[end_new+k] == (char) NULL) && (k != 0))))
		{
			Position(window, line, offset);
			insert = FALSE;
			if (String_table[ic__] == NULL)
			{
				String_Out(String_table[im__], NULL, 0);
				insert = TRUE;
			}
			for (k = offset; k < end_new; k++)
			{
				if (!insert)
					String_Out(String_table[ic__], NULL, 0);
				Char_ins(old_lin, old_att, new_lin[k], new_att[k], k, window->Num_cols);
			}
			if (insert)
				String_Out(String_table[ei__], NULL, 0);
			while ((old_lin[offset] != (char) NULL) && (offset < COLS))
				offset++;
			pointer_old->last_char = offset;
			changed = TRUE;
		}
	}
	return(changed);
}

void 
doupdate()
{
	WINDOW *window;
	int similar;
	int diff;
	int begin_old, begin_new;
	int end_old, end_new;
	int count1, j;
	int from_top, tmp_ft, offset;
	int changed;
	int first_time;
	int first_same;
	int last_same;
	int list[10];
	int bottom;

	struct _line *curr;
	struct _line *virt;
	struct _line *old;

	struct _line *new;

	struct _line *old1, *new1;

	char *cur_lin;
	char *vrt_lin;
	char *cur_att;
	char *vrt_att;
	char *att1, *att2;
	char *c1, *c2;

	char NC_chinese = FALSE;	/* flag to indicate handling Chinese */

	window = virtual_scr;

	if ((nc_attributes & A_NC_BIG5) != 0)
		NC_chinese = TRUE;

	if (Repaint_screen)
	{
		if (String_table[cl__])
			String_Out(String_table[cl__], NULL, 0);
		else
		{
			from_top = 0;
			while (from_top < LINES)
			{
				Position(curscr, from_top, 0);
				if (String_table[ce__] != NULL)
					String_Out(String_table[ce__], NULL, 0);
				else
				{
					for (j = 0; j < window->Num_cols; j++)
						putchar(' ');
				}
				from_top++;
			}
		}
		for (from_top = 0, curr = curscr->first_line; from_top < curscr->Num_lines; from_top++, curr = curr->next_screen)
		{
			Position(curscr, from_top, 0);
			for (j = 0; (curr->row[j] != (char) NULL) && (j < curscr->Num_cols); j++)
			{
				Char_out(curr->row[j], curr->attributes[j], curr->row, curr->attributes, j);
			}
			if (STAND)
			{
				STAND = FALSE;
				Position(curscr, from_top, j);
				attribute_off();
			}
		}
		Repaint_screen = FALSE;
	}

	similar = 0;
	diff = FALSE;
	top_of_win = curscr->first_line;

	for (from_top = 0, curr = top_of_win, virt = window->first_line; 
			from_top < window->Num_lines; from_top++)
	{
		virtual_lines[from_top] = TRUE;
		if ((similar = Comp_line(curr, virt)) > 0)
		{
			virtual_lines[from_top] = FALSE;
			diff = TRUE;
		}
		curr = curr->next_screen;
		virt = virt->next_screen;
	}

	from_top = 0;
	virt = window->first_line;
	curr = top_of_win;
	similar = 0;
	/*
	 |  if the window has lines that are different, check for scrolling
	 */
	if (diff)
	{
		last_same = -1;
		changed = FALSE;
		for (first_same = window->Num_lines; 
		    (first_same > from_top) && (virtual_lines[first_same - 1]);
		     first_same--)
			;
		for (last_same = 0;
		    (last_same < window->Num_lines) && (virtual_lines[last_same]== FALSE);
		     last_same++)
			;
		while ((from_top < first_same) && nc_scrolling_ability)
					/* check entire lines for diffs	*/
		{

			if (from_top >= last_same)
			{
				for (last_same = from_top; 
				     (last_same < window->Num_lines) && 
				     (virtual_lines[last_same] == FALSE);
				      last_same++)
					;
			}
			if (!virtual_lines[from_top])
			{
				diff = TRUE;
				/*
				 |	check for lines deleted (scroll up)
				 */
				for (tmp_ft = from_top+1, old = curr->next_screen; 
					((window->scroll_up) && (diff) && 
					(tmp_ft < last_same) && 
					(!virtual_lines[tmp_ft]));
						tmp_ft++)
				{
					if ((Comp_line(old, virt) == -1) && (!virtual_lines[from_top]))
					{
						/*
						 |	Find the bottom of the 
						 |	area that should be 
						 |	scrolled.
						 */
						for (bottom = tmp_ft, old1 = old, 
						     new1 = virt, count1 = 0;
							(bottom < window->Num_lines) && 
								(Comp_line(old1, new1) <= 0);
								bottom++, old1 = old1->next_screen, 
								new1 = new1->next_screen, 
								count1++)
							;
						if (count1 > 3)
						{
							if (String_table[cs__]) /* scrolling region */
							{
								list[1] = from_top;
								list[0] = min((bottom - 1), (window->Num_lines - 1));
								String_Out(String_table[cs__], list, 2);
								Curr_y = Curr_x = -1;
							}

							for (offset = (tmp_ft - from_top); (offset > 0); offset--)
							{
								old = Delete_line(from_top, min((bottom - 1), (window->Num_lines - 1)), window);
								diff = FALSE;
							}

							if (String_table[cs__]) /* scrolling region */
							{
								list[1] = 0;
								list[0] = LINES - 1;
								String_Out(String_table[cs__], list, 2);
								Curr_y = Curr_x = -1;
							}

							top_of_win = curscr->first_line;
							curr = top_of_win;
							for (offset = 0; offset < from_top; offset++)
								curr = curr->next_screen;
							for (offset = from_top, old=curr, new=virt; 
							   offset < window->Num_lines; 
							   old=old->next_screen, new=new->next_screen,
							   offset++)
							{
								similar = Comp_line(old, new);
								virtual_lines[offset] = (similar > 0 ? FALSE : TRUE);
							}
						}
					}
					else
						old = old->next_screen;
				}
				/*
				 |	check for lines inserted (scroll down)
				 */
				for (tmp_ft = from_top-1, old = curr->prev_screen; 
					((window->scroll_down) && (tmp_ft >= 0) && 
					(diff) && 
					(!virtual_lines[tmp_ft])); 
					  tmp_ft--)
				{
					if (Comp_line(old, virt) == -1)
					{
						/*
						 |	Find the bottom of the 
						 |	area that should be 
						 |	scrolled.
						 */
						for (bottom = from_top, old1 = old, 
						     new1 = virt, count1 = 0;
							(bottom < window->Num_lines) && 
								(Comp_line(old1, new1) <= 0);
								bottom++, old1 = old1->next_screen, 
								new1 = new1->next_screen, 
								count1++)
							;
						if (count1 > 3)
						{
							if (String_table[cs__]) /* scrolling region */
							{
								list[1] = tmp_ft;
								list[0] = min((bottom - 1), (window->Num_lines - 1));
								String_Out(String_table[cs__], list, 2);
								Curr_y = Curr_x = -1;
							}

							for (offset = (from_top - tmp_ft); (offset > 0); offset--)
							{
								old = Insert_line(tmp_ft, min((bottom - 1), (window->Num_lines -1)), window);
								diff = FALSE;
							}

							if (String_table[cs__]) /* scrolling region */
							{
								list[1] = 0;
								list[0] = LINES - 1;
								String_Out(String_table[cs__], list, 2);
								Curr_y = Curr_x = -1;
							}

							top_of_win = curscr->first_line;
							curr = top_of_win;
							for (offset = 0; offset < from_top; offset++)
								curr = curr->next_screen;
							for (offset = from_top, old=curr, new=virt; 
							   offset < window->Num_lines; 
							   old=old->next_screen, new=new->next_screen,
							   offset++)
							{
								similar = Comp_line(old, new);
								virtual_lines[offset] = (similar > 0 ? FALSE : TRUE);
							}
						}
					}
					else
						old = old->prev_screen;
				}
			}
			from_top++;
			curr = curr->next_screen;
			virt = virt->next_screen;
		}
	}


	/*
	 |	Scrolling done, now need to insert, delete, or modify text 
	 |	within lines.
	 */

	for (from_top = 0, curr = curscr->first_line; from_top < window->SR; from_top++)
		curr = curr->next_screen;
	top_of_win = curr;
	for (from_top = 0, curr = top_of_win, virt = window->first_line; from_top < window->Num_lines; from_top++, curr = curr->next_screen, virt = virt->next_screen)
	{

		/*
		 |	If either 'insert mode' or 'insert char' are 
		 |	available, enter the following 'if' statement, 
		 |	else, need to simply rewrite the contents of the line
		 |	at the point where the contents of the line change.
		 */

		if (((String_table[ic__]) || (String_table[im__])) && 
		    (String_table[dc__]) && (curr->row[0] != (char) NULL) &&
		    (!NC_chinese))
		{
			j = 0;
			first_time = TRUE;
			vrt_lin = virt->row;
			vrt_att = virt->attributes;
			cur_lin = curr->row;
			cur_att = curr->attributes;
			while ((vrt_lin[j] != (char) NULL) && (j < window->Num_cols))
			{
				if ((STAND) && (Booleans[xs__]))
				{
					while ((vrt_lin[j] == cur_lin[j]) && (vrt_att[j] == cur_att[j]) && (vrt_lin[j] != (char) NULL) && (vrt_att[j]))
						j++;
					if ((STAND) && (!vrt_att[j]))
					{
						STAND = FALSE;
						Position(window, from_top, j);
						attribute_off();
						attribute_off();
					}
				}
				else
				{
					while ((vrt_lin[j] == cur_lin[j]) && (vrt_att[j] == cur_att[j]) && (vrt_lin[j] != (char) NULL))
						j++;
				}
				if ((vrt_att[j] != cur_att[j]) && (cur_att[j]) && (Booleans[xs__]))
				{
					Position(window, from_top, j);
/*					CLEAR_TO_EOL(window, from_top, j);*/
					attribute_off();
					attribute_off();
				}
				if (vrt_lin[j] != (char) NULL)
				{
					begin_new = j;
					begin_old = j;
					end_old = j;
					end_new = j;
					if ((first_time) && (virt->changed))
					{
						if (curr->last_char <= virt->last_char)
							changed = check_insert(window, from_top, j, virt, curr);
					}
					changed = check_delete(window, from_top, j, virt, curr);
					first_time = FALSE;
					virt->changed = FALSE;
					if (!changed)
						changed = check_insert(window, from_top, j, virt, curr);
					if (((!changed) || (cur_lin[j] != vrt_lin[j]) || (cur_att[j] != vrt_att[j])) && (j < window->Num_cols))
					{
						if ((vrt_lin[j] == ' ') && (cur_lin[j] == (char) NULL) && (vrt_att[j] == cur_att[j]))
							cur_lin[j] = ' ';
						else
						{
							Position(window, from_top, j);
							Char_out(vrt_lin[j], vrt_att[j], cur_lin, cur_att, j);
						}
					}
					if ((vrt_lin[j] != (char) NULL))
						j++;
				}
				if ((STAND) && (!vrt_att[j]))
				{
					STAND = FALSE;
					Position(window, from_top, j);
					attribute_off();
				}
			}
			if ((vrt_lin[j] == (char) NULL) && (cur_lin[j] != (char) NULL))
			{
				Position(window, from_top, j);
				CLEAR_TO_EOL(window, from_top, j);
			}
		}
		else /*if ((similar != -1) && (similar != 0))*/
		{
			j = 0;
			c1 = curr->row;
			att1 = curr->attributes;
			c2 = virt->row;
			att2 = virt->attributes;
			while ((j < window->Num_cols) && (c2[j] != (char) NULL))
			{
				while ((c1[j] == c2[j]) && (att1[j] == att2[j]) && (j < window->Num_cols) && (c2[j] != (char) NULL))
					j++;

				/*
				 |	if previous character is an eight bit 
				 |	char, start redraw from that character
				 */

				if ((NC_chinese) && (highbitset(c1[j - 1])))
					j--;
				begin_old = j;
				begin_new = j;
				if ((j < window->Num_cols) && (c2[j] != (char) NULL))
				{
					Position(window, from_top, begin_old);
					CLEAR_TO_EOL(window, from_top, j);
					Position(window, from_top, begin_old);
					for (j = begin_old; (c2[j] != (char) NULL) && (j < window->Num_cols); j++)
						Char_out(c2[j], att2[j], c1, att1, j);
				}
			}
			if ((c2[j] == (char) NULL) && (c1[j] != (char) NULL))
			{
				Position(window, from_top, j);
				CLEAR_TO_EOL(window, from_top, j);
			}
		}
		if (STAND)
		{
			STAND = FALSE;
			Position(window, from_top, j);
			attribute_off();
		}
		virt->number = from_top;
	}
	Position(window, window->LY, window->LX);
}

void 
Position(window, row, col)	/* position the cursor for output on the screen	*/
WINDOW *window;
int row;
int col;
{
	int list[10];
	int place;

	int pos_row;
	int pos_column;

	pos_row = row + window->SR;
	pos_column = col + window->SC;
	if ((pos_row != Curr_y) || (pos_column != Curr_x))
	{
		if (String_table[cm__] != NULL) /* && (row < window->Num_lines) && (column < window->Num_cols))*/ 
		{
			place = 0;
			list[place++] = pos_column;
			list[place++] = pos_row;
			String_Out(String_table[cm__], list, place);
			if ((STAND) && (!Booleans[ms__]))
				attribute_on();
		}
		Curr_x = pos_column;
		Curr_y = pos_row;
	}
}

void 
Char_del(line, attrib, offset, maxlen)	/* delete chars from line	*/
char *line;
char *attrib;
int offset;
int maxlen;
{
	int one, two;

	for (one = offset, two = offset+1; (line[one] != (char) NULL) && (one < maxlen); one++, two++)
	{
		line[one] = line[two];
		attrib[one] = attrib[two];
	}
	String_Out(String_table[dc__], NULL, 0);
}

void 
Char_ins(line, attrib, newc, newatt, offset, maxlen)	/* insert chars in line	*/
char *line;
char *attrib;
char newc;
char newatt;
int offset;
int maxlen;
{
	int one, two;

	one = 0;
	while ((line[one] != (char) NULL) && (one < (maxlen - 2)))
		one++;
	for (two = one + 1; (two > offset); one--, two--)
	{
		line[two] = line[one];
		attrib[two] = attrib[one];
	}
	line[offset] = newc;
	attrib[offset] = newatt;
	Char_out(newc, newatt, line, attrib, offset);
}

void 
attribute_on()
{
	if (String_table[sa__])
	{
		attributes_set[0] = 1;
		String_Out(String_table[sa__], attributes_set, 1);
	}
	else if (String_table[so__])
		String_Out(String_table[so__], NULL, 0);
}

void 
attribute_off()
{
	if (String_table[me__])
		String_Out(String_table[me__], NULL, 0);
	else if (String_table[sa__])
	{
		attributes_set[0] = 0;
		String_Out(String_table[sa__], attributes_set, 1);
	}
	else if (String_table[se__])
		String_Out(String_table[se__], NULL, 0);
}

void 
Char_out(newc, newatt, line, attrib, offset)	/* output character with proper attribute	*/
char newc;
char newatt;
char *line;
char *attrib;
int offset;
{


	if ((newatt) && (!STAND))
	{
		STAND = TRUE;
		attribute_on();
	}
	else if ((STAND) && (!newatt))
	{
		STAND = FALSE;
		attribute_off();
	}

	if ((newatt) && (STAND) && (Booleans[xs__]))
	{
		attribute_on();
	}

	if (!((Curr_y >= (LINES - 1)) && (Curr_x >= (COLS - 1))))
	{
		putchar(newc);
		line[offset] = newc;
		attrib[offset] = newatt;
	}
	Curr_x++;
}

/*
 |
 |	The two routines that follow, nc_setattrib(), nc_clearattrib(), are 
 |	hacks that notify new_curse to handle characters that have the high 
 |	bit set as the first of two bytes of a multi-byte string.
 |
 */

void 
nc_setattrib(flag)
int flag;
{
	nc_attributes |= flag;
}

void 
nc_clearattrib(flag)
int flag;
{
	nc_attributes &= ~flag;
}

