home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet MPEG Audio Archive
/
IMAA.mdf
/
util
/
dos
/
l3v100n
/
rsx
/
source
/
termio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-19
|
8KB
|
373 lines
/* This file is TERMIO.C
**
** - ioctl() terminal functions
**
** ( termio functions are modified from the Linux-kernel 0.99 )
**
** Copyright (c) Rainer Schnitker 91,92,93
*/
#include <stdio.h>
#include <stdlib.h>
#include <bios.h>
#include "DPMI.H"
#include "DPMIDOS.H"
#include "SIGNALS.H"
#include "PROCESS.H"
#include "START32.H"
#include "COPY32.H"
#include "RSX.H"
#include "EXCEP32.H"
#include "TERMIO.H"
#include "DOSERRNO.H"
static void keyboard_flush(void);
static int keyboard_read(void);
static void put_kbd_queue(int);
static int get_kbd_queue(void);
static void flush_input(void);
static int copy_to_cooked(void);
static int available_canon_input(void);
static void wait_for_canon_input(void);
static DWORD do_fionread(void);
static char control_c;
static unsigned long timeout;
static unsigned delay_flag;
struct termio termios =
{
/* iflag */ BRKINT | ICRNL | IXON | IXANY,
/* oflag */ 0,
/* cflag */ B9600 | CS8 | CREAD | HUPCL,
/* lflag */ ISIG | ICANON | ECHO | ECHOE | ECHOK | IDEFAULT,
/* line */ 0,
/* c_cc */ 003, 034, 010, 025, 004, 000, 006, 001};
/* INTR, QUIT,ERASE, KILL, EOF , EOL , VMIN, VTIME */
/* C-C , C-\ , C-H , C-U , C-D , EOL , VMIN, VTIME */
#define QUEUE_BUF_SIZE 128
struct queue {
int data;
int head;
int tail;
char buf[QUEUE_BUF_SIZE];
} kbd_queue;
#define INC(a) (a = (a+1) & (QUEUE_BUF_SIZE-1))
#define DEC(a) (a = (a-1) & (QUEUE_BUF_SIZE-1))
#define EMPTY(a) (a.head == a.tail)
#define LEFT(a) ((a.tail-a.head-1)&(QUEUE_BUF_SIZE-1))
#define LAST(a) (a.buf[(QUEUE_BUF_SIZE-1)&(a.head-1)])
#define FULL(a) (!LEFT(a))
#define CHARS(a) ((a.head-a.tail)&(QUEUE_BUF_SIZE-1))
/* flush keyboard buffer */
static void keyboard_flush(void)
{
while (_bios_keybrd(kready))
_bios_keybrd(kread);
}
/* read a key ; extended = 0,next call scan-code */
static int keyboard_read()
{
static int next_key = 0;
int key, scan, ascii;
if (next_key) {
ascii = next_key;
next_key = 0;
} else {
if (!_bios_keybrd(kready)) {
if (timeout)
if (timeout <= time_tic)
timeout = 0;
return -1;
}
key = _bios_keybrd(kread);
ascii = key & 0xff;
scan = key >> 8;
if (ascii == 0xE0)
ascii = 0;
if (ascii == 0)
next_key = scan;
}
return ascii;
}
/* put one char into kbd_queue */
static void put_kbd_queue(int c)
{
int head = (kbd_queue.head + 1) & (QUEUE_BUF_SIZE - 1);
if (head != kbd_queue.tail) {
kbd_queue.buf[kbd_queue.head] = (char) c;
kbd_queue.head = head;
}
}
/* get one char from kbd_queue ; -1 = no char */
static int get_kbd_queue()
{
int result = -1;
if (kbd_queue.tail != kbd_queue.head) {
result = 0xff & kbd_queue.buf[kbd_queue.tail];
kbd_queue.tail = (kbd_queue.tail + 1) & (QUEUE_BUF_SIZE - 1);
}
return result;
}
static void flush_input(void)
{
keyboard_flush();
kbd_queue.head = kbd_queue.tail;
kbd_queue.data = 0;
}
#define TTY_READ_FLUSH copy_to_cooked();
int copy_to_cooked(void)
{
int c;
for (;;) {
c = LEFT(kbd_queue);
if (c == 0)
return 0;
c = keyboard_read();
if (c < 0)
return 0;
if (c == 0) /* extended key */
if (L_CANON) { /* CANON ignores it */
keyboard_read();/* forget scan code */
continue;
} else {
put_kbd_queue(c); /* put char 0,scan */
c = keyboard_read();
put_kbd_queue(c);
continue;
}
if (I_STRP)
c &= 0x7f;
if (c == 13) {
if (I_CRNL)
c = 10;
else if (I_NOCR)
continue;
} else if (c == 10 && I_NLCR)
c = 13;
if (I_UCLC)
c = tolower(c);
if (L_CANON) {
if ((char) c == KILL_CHAR) {
while (!(EMPTY(kbd_queue) || (c = LAST(kbd_queue)) == 10 ||
c == EOF_CHAR)) {
if (L_ECHO) {
if (c < 32) {
putchar('\b');
putchar(' ');
putchar('\b');
}
putchar('\b');
putchar(' ');
putchar('\b');
}
DEC(kbd_queue.head);
}
continue;
}
if (c == ERASE_CHAR) {
if (EMPTY(kbd_queue) || (c = LAST(kbd_queue)) == 10 || c == EOF_CHAR)
continue;
if (L_ECHO) {
if (c < 32) {
putchar('\b');
putchar(' ');
putchar('\b');
}
putchar('\b');
putchar(' ');
putchar('\b');
}
DEC(kbd_queue.head);
continue;
}
} /* ICANON */
if (L_ISIG) {
if (c == INTR_CHAR) {
control_c = 1;
send_signal(npz, SIGINT);
flush_input();
return 1;
}
}
/* linefeed: new data */
if (c == 10 || c == EOF_CHAR)
kbd_queue.data++;
/* write char */
if ((c == 10) && (L_ECHO || (L_CANON && L_ECHONL))) {
putchar(10);
putchar(13);
} else if (L_ECHO)
putchar(c);
put_kbd_queue(c);
}
}
static int available_canon_input()
{
TTY_READ_FLUSH;
if (kbd_queue.data)
return 1;
else
return 0;
}
static void wait_for_canon_input()
{
if (!available_canon_input()) {
if (control_c)
return;
while (1) {
if (available_canon_input())
break;
if (control_c)
break;
}
}
}
int termio_read(unsigned dataseg, unsigned long buf, int nr)
{
int c;
unsigned long b = buf;
int minimum, time;
control_c = 0;
if (L_CANON) {
minimum = time = 0;
timeout = 0L;
} else {
time = termios.c_cc[VTIME] * 10;
minimum = termios.c_cc[VMIN];
if (minimum)
timeout = 0xffffffff;
else {
if (time)
timeout = (unsigned long) time / 55L + time_tic;
else
timeout = 0;
time = 0;
minimum = 1;
}
}
if (delay_flag) {
time = 0;
timeout = 0;
if (L_CANON) {
if (!available_canon_input())
return -EMX_EAGAIN;
}
} else if (L_CANON) {
wait_for_canon_input();
}
if (minimum > nr)
minimum = nr;
while (nr > 0) {
while (nr > 0 && ((c = get_kbd_queue()) >= 0)) {
TTY_READ_FLUSH;
if (control_c)
return 0;
if (c == EOF_CHAR || c == 10)
kbd_queue.data--;
if (c == EOF_CHAR && L_CANON)
break;
cpy16_32(dataseg, b, &c, 1L);
b++;
nr--;
if (time)
timeout = (unsigned long) time / 55L + time_tic;
if (c == 10 && L_CANON)
break;
}
if ((int) (b - buf) >= minimum || !timeout)
break;
TTY_READ_FLUSH;
if (control_c)
return 0;
if (!EMPTY(kbd_queue))
continue;
}
TTY_READ_FLUSH;
timeout = 0;
if (b - buf)
return (unsigned) (b - buf);
if (delay_flag)
return -EMX_EAGAIN;
return 0;
}
void set_fcntl_flag(unsigned flag)
{
delay_flag = flag & FCNTL_NDELAY;
}
static DWORD do_fionread()
{
TTY_READ_FLUSH;
return (DWORD) (CHARS(kbd_queue));
}
int kbd_ioctl(unsigned cmd, unsigned long termio_arg)
{
switch (cmd) {
case TCGETA:
if (verify_illegal(npz, termio_arg, sizeof(struct termio)))
return EMX_EINVAL;
cpy16_32(npz->data32sel, termio_arg,
&termios, sizeof(struct termio));
return 0;
case TCSETAF:
flush_input();
/* fall through */
case TCSETAW:
case TCSETA:
if (verify_illegal(npz, termio_arg, sizeof(struct termio)))
return EMX_EINVAL;
cpy32_16(npz->data32sel, termio_arg,
&termios, sizeof(struct termio));
if (!L_IDEFAULT) /* enable termio */
npz->p_flags |= PF_TERMIO;
return 0;
case TCFLSH:
if (termio_arg == 0)
flush_input();
return 0;
case FIONREAD:
if (verify_illegal(npz, termio_arg, sizeof(long)))
return EMX_EINVAL;
store32(npz->data32sel, termio_arg, do_fionread());
default:
return EMX_EINVAL;
}
}