/**************************************************************
 *
 *	CRISP - Custom Reduced Instruction Set Programmers Editor
 *
 *	(C) Paul Fox, 1989
 *
 *    Please See COPYLEFT notice.
 *
 **************************************************************/

# include       "list.h"
# include	"alt.h"
# include	"clk.h"
# include	"tty.h"
# define INCL_BASE
# define INCL_NOPM
# include "os2.h" 

char	*termcap_dir = "/etc/termcap";
char	*bhelp = "ROOT/help";
char	*bpath = "ROOT/macros;.;ROOT/src";



# define	CENTISECONDS	5	/* x0.1 seconds */
void	scr_cursor();
void	scr_8bit();
void	scr_repeat();
int	console_mode = -1;	/* Only used on EGA screen. */
USHORT	fansi;			/* Saved ANSI state. */
BYTE	kbd_thread_stack[2048];
TID	tid;
int	timed_out = FALSE;
ULONG	main_sem = 0;
ULONG	kbd_sem = 0;
KBDKEYINFO	keyinfo;
DISPLAY *global_dp;	/* Global variable needed for pty thread. */
ULONG	pty_sem;	/* Thread to synchronise between main and pty threads. */

int kbdflgs = 0;                    /* saved keyboard fd flags      */

KEY dos_keys[] = {
/* 0x00*/	0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, 0x00,
    		0x00, 0x00, 0x00, 0x00, 
		0x00, 0x00, 0x00, BACK_TAB,
/* 0x10 */	ALT_Q,	ALT_W,	ALT_E,	ALT_R, 
		ALT_T,	ALT_Y,	ALT_U,	ALT_I,
		ALT_O, 	ALT_P,	0x00, 	0x00,
		0x00,	0x00,	ALT_A,	ALT_S,
/* 0x20 */	ALT_D,	ALT_F,	ALT_G,	ALT_H,
		ALT_J,	ALT_K,	ALT_L,	0x00,
		0x00,	0x00,	0x00,	0x00,
		ALT_Z,	ALT_X,	ALT_C,	ALT_V,
/* 0x30 */	ALT_B,	ALT_N,	ALT_M,	0x00,
		0x00,	0x00,	0x00,	0x00,
		0x00,	0x00,	0x00,	F(1),
		F(2),	F(3),	F(4),	F(5),
/* 0x40 */	F(6),	F(7),	F(8),	F(9),
		F(10),	0x00,	0x00, 	209,
		210,	211,	0x00,	206, 
		0x00,	208,	0x00, 	203,
/* 0x50 */	204,	205,	202,	212, 
		SF(1), 	SF(2), 	SF(3), 	SF(4),
		SF(5), 	SF(6), 	SF(7), 	SF(8), 
		SF(9), 	SF(10),	CF(1), 	CF(2),
/* 0x60 */	CF(3), 	CF(4), 	CF(5), 	CF(6), 
		CF(7), 	CF(8), 	CF(9), 	CF(10),
		AF(1), 	AF(2), 	AF(3), 	AF(4), 
		AF(5), 	AF(6), 	AF(7), 	AF(8),
/* 0x70 */	AF(9), 	AF(10), 	0, 		220,  
		222, 		0xd9, 		0xdb, 		0xdf,
		0x00, 		0x00, 		0x00, 		0x00, 
		0x00, 		0x00, 		0x00, 		0x00,
/* 0x80 */	0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00,
    };
    

void
sys_open()
{	void	kbd_thread();

	VioGetAnsi(&fansi, 0);
	scrfn.scr_cursor = scr_cursor;
	scrfn.scr_8bit = scr_8bit;
	/***********************************************/
	/*   next   line   doesnt   work  because  it  */
	/*   doesnt use the attributes properly	       */
	/***********************************************/
/*	scrfn.scr_repeat = scr_repeat;*/

	DosSemSet(&kbd_sem);
	DosSemSet(&main_sem);
	if (DosCreateThread(kbd_thread, &tid, kbd_thread_stack) != 0)
		panic("Cannot create keyboard thread.");
} 
int
create_pty_thread(dp)
DISPLAY *dp;
{	void	pty_thread();

	global_dp = dp;
	dp->d_dead = FALSE;
	DosSemSet(&pty_sem);
	dp->d_sema = 0;
	dp->d_wait = 0;
	DosSemSet(&dp->d_sema);
	DosSemSet(&dp->d_wait);
	if (DosCreateThread(pty_thread, &tid, &dp->d_stack[PTY_STACK]) != 0) {
		ewprintf("Cannot create thread.");
		return -1;
		}
	DosSemWait(&pty_sem, SEM_INDEFINITE_WAIT);
	return 0;
} 
void
pty_thread()
{	DISPLAY *dp = global_dp;
	DosSemClear(&pty_sem);
	while (1) {
		if (DosRead(dp->d_pipe_in, 
			dp->d_buf,
			PTY_BUFSIZ - 1,
			&dp->d_rcvlen) != 0) {
				dp->d_dead = TRUE;
				return;
				}
		DosSemClear(&dp->d_sema);
		
		DosSemRequest(&dp->d_wait, SEM_INDEFINITE_WAIT);
		}
	
}
dos_read_pty(bp)
BUFFER *bp;
{	DISPLAY	*dp = bp->b_display;

	if (dp->d_sema)
		return 0;

	DosSemSet(&dp->d_sema);
	dp->d_buf[dp->d_rcvlen] = NULL;
	p_update(bp, dp->d_buf);
	DosSemClear(&dp->d_wait);
	DosSleep(0L);	/* Give other thread chance to run. */

	return 1;
}
main_thread_read_kbd(tmo)
long tmo;
{
	int	ch;
	
	if (timed_out) {
		timed_out = FALSE;
		if (main_sem == 0) {
return_char:
			ch = keyinfo.chChar;
			/* Handle keypad +, -, * in-line. They are annoying */
			if (keyinfo.chChar == 43 && keyinfo.chScan == 78)
				return KEY_COPY;
			if (keyinfo.chChar == 45 && keyinfo.chScan == 74)
				return KEY_CUT;
			if (keyinfo.chChar == 42 && keyinfo.chScan == 55)
				return KEY_UNDO;
			if (keyinfo.chChar == 0 && keyinfo.chScan == 76)
				return KEY_5;
			if (keyinfo.chChar == 56 && keyinfo.chScan == 72)
				return SHIFT_KEYPAD_8;
			if (keyinfo.chChar == 52 && keyinfo.chScan == 75)
				return SHIFT_KEYPAD_4;
			if (keyinfo.chChar == 54 && keyinfo.chScan == 77)
				return SHIFT_KEYPAD_6;
			if (keyinfo.chChar == 50 && keyinfo.chScan == 80)
				return SHIFT_KEYPAD_2;
			if (ch && ch != 0xe0)
				return ch;
			return dos_keys[keyinfo.chScan];
			}
		DosResumeThread(tid);
		}
	else
		DosSemClear(&kbd_sem);

	if (DosSemWait(&main_sem, tmo) == 0) {
		DosSemSet(&main_sem);
		goto return_char;
		}

	timed_out = TRUE;
	DosSuspendThread(tid);
	return -1;
}
/**********************************************************************/
/*   Code for thread handling keyboard input.			      */
/**********************************************************************/
void
kbd_thread()
{
	static KBDINFO	kinfo = {16};
		      
	KbdGetStatus(&kinfo, TTY_FD);
	if ((kinfo.fsMask & KEYBOARD_BINARY_MODE) == 0) {
		kinfo.fsMask = KEYBOARD_BINARY_MODE;
		KbdSetStatus(&kinfo, TTY_FD);
		}

	while (1) {
		DosSemWait(&kbd_sem, SEM_INDEFINITE_WAIT);
		DosSemSet(&kbd_sem);
		KbdCharIn(&keyinfo, IO_WAIT, 0);
		DosSemClear(&main_sem);
		}
}

/**********************************************************************/
/*   Make  sure  we don't inherit the specified file descriptor when  */
/*   we create a new process.					      */
/**********************************************************************/
void
noinherit(fd)
int	fd;
{
	DosSetFHandState(fd, OPEN_FLAGS_NOINHERIT);
}
void
sys_close()
{
	VioSetAnsi(fansi, 0);
}
dos_write(buf, len)
char *buf;
int	len;
{
	return VioWrtTTY(buf, len, 0);
}
static
sys_getc1()
{   int ch = getch();
    if (ch && ch != 0xe0)
	return ch;
    return dos_keys[getch()];
}
int
sys_checkc()
{ 
	if (timed_out)
		return 0;
	if (kbhit())
	    return sys_getc1();
	return 0;
}
int
sys_getchar(fd, buf, tmo)
int	*buf;
long	tmo;
{ 
	buf[0] = sys_getc1();
	return 1;
}

char *
sys_delim()
{
	return "/";
}
void
scr_cursor(insmode, virtual_space)
int	insmode;
int	virtual_space;
{	VIOCURSORINFO cursorinfo;

	VioGetCurType(&cursorinfo, 0);
	if (insmode) {
		if (virtual_space) {
			cursorinfo.yStart = 8;
			cursorinfo.cEnd = 15;
			}
		else {
			cursorinfo.yStart = 14;
			cursorinfo.cEnd = 15;
			}
		}
	else {
		if (virtual_space) {
			cursorinfo.yStart = 1;
			cursorinfo.cEnd = 7;
			}
		else {
			cursorinfo.yStart = 1;
			cursorinfo.cEnd = 15;
			}
		}
	VioSetCurType(&cursorinfo, 0);
}
void
scr_8bit(ch)
{
	ttflush();
	VioSetAnsi(ANSI_OFF, 0);
	ttputpad(ch);
	ttflush();
	VioSetAnsi(ANSI_ON, 0);
}
void
scr_repeat(c, n, row, col)
{	char ch = c;

	VioWrtNChar(&ch, n, row, col, 0);
}
pause()
{
}
fork()
{
    return -1;
}
_cleanup()
{
}
link(str1, str2)
char *str1, *str2;
{
    return -1;
}
kill(pid, sig)
int pid, sig;
{	int ret;

	if (pid < 0)
		ret = DosKillProcess(0, -pid);
	else
		ret = DosKillProcess(1, pid);
	return ret;
}
int
pipe(p)
int	*p;
{
	return -1;
}
/**********************************************************************/
/*   Get current drive.						      */
/**********************************************************************/
int
get_current_drive()
{	USHORT cur_drive;
	ULONG	drives;
	DosQCurDisk(&cur_drive, &drives);

	return cur_drive + 'A' - 1;
}

/**********************************************************************/
/*   Set the current drive.					      */
/**********************************************************************/
void
set_current_drive(ch)
int	ch;
{
	if (islower(ch))
		ch = toupper(ch);
# if CR_DOS
	DosSelectDisk(ch - 'A' + 1);
# else
	{
	union	REGS	regs;

	regs.h.ah = SELECT;
	regs.h.dl = ch - 'A';
	intdos(&regs, &regs);
	}
# endif
}

int
sys_enable_char(ch, enable)
int	flag;
{	
	return 1;
}
