home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
EFFO
/
pd8.lzh
/
SRC
/
io.c
< prev
next >
Wrap
Text File
|
1990-03-25
|
11KB
|
443 lines
/* this file (in principle) contains all the device-dependent code for
* handling screen movement and reading the keyboard. public routines are:
* c_pos(r,c), c_erase(), c_eol();
* chk_char(), read_char(), read_line (buf, max); and
* byetty().
* N.B. we assume output may be performed by printf(), putchar() and
* fputs(stdout). since these are buffered we flush first in read_char().
*/
/* explanation of various conditional #define options:
* UNIX: uses termcap for screen management.
* USE_NDELAY: does non-blocking tty reads with fcntl(O_NDELAY); otherwise
* this is done with ioctl(..,FIONREAD..). Use which ever works on your
* system.
* TURBO_C: compiles for Turbo C 2.0. I'm told it works for Lattice and
* Microsoft too.
* USE_ANSISYS: default PC cursor control uses direct BIOS calls (thanks to
* Mr. Doug McDonald). If your PC does not work with this, however, add
* "device ANSI.SYS" to your config.sys file and build ephem with
* USE_ANSISYS.
*/
/* #define UNIX */
/* #define USE_NDELAY */
/* #define TURBO_C */
/* #define USE_ANSISYS */
#include <stdio.h>
#include "screen.h"
#if defined(UNIX) | defined(OSK)
#ifdef UNIX
# include <sgtty.h>
# include <signal.h>
# ifdef USE_NDELAY
# include <fcntl.h>
# endif
#endif
#ifdef OSK
# include <sgstat.h>
char *UP,*BC;
#endif
extern char *tgoto();
static char *cm, *ce, *cl, *kl, *kr, *ku, *kd; /* curses sequences */
static int tloaded;
static int ttysetup;
#ifdef UNIX
static struct sgttyb orig_sgtty;
#endif
#ifdef OSK
static struct sgbuf sg_buf;
#endif
/* move cursor to row, col, 1-based.
* we assume this also moves a visible cursor to this location.
*/
c_pos (r, c)
int r, c;
{
if (!tloaded) tload();
fputs (tgoto (cm, c-1, r-1), stdout);
}
/* erase entire screen. */
c_erase()
{
if (!tloaded) tload();
fputs (cl, stdout);
}
/* erase to end of line */
c_eol()
{
if (!tloaded) tload();
fputs (ce, stdout);
}
#ifdef USE_NDELAY
static char sav_char; /* one character read-ahead for chk_char() */
#endif
/* return 0 if there is a char that may be read without blocking, else -1 */
chk_char()
{
#ifndef OSK
#ifdef USE_NDELAY
if (!ttysetup) setuptty();
if (sav_char)
return (0);
fcntl (0, F_SETFL, O_NDELAY); /* non-blocking read. FNDELAY on BSD */
if (read (0, &sav_char, 1) != 1)
sav_char = 0;
return (sav_char ? 0 : -1);
#else
long n;
if (!ttysetup) setuptty();
ioctl (0, FIONREAD, &n);
return (n > 0 ? 0 : -1);
#endif
#else
if (!ttysetup) setuptty();
return (_gs_rdy(0) > 0 ? 0 : -1);
#endif
}
/* read the next char, blocking if necessary, and return it. don't echo.
* map the arrow keys if we can too into hjkl
*/
read_char()
{
char c;
if (!ttysetup) setuptty();
fflush (stdout);
#ifdef USE_NDELAY
fcntl (0, F_SETFL, 0); /* blocking read */
if (sav_char) {
c = sav_char;
sav_char = 0;
} else
#endif
read (0, &c, 1);
#ifndef OSK
c = chk_arrow (c & 0177); /* just ASCII, please */
return (c);
#else
return(chk_arrow(c));
#endif
}
/* used to time out of a read */
static got_alrm;
static
on_alrm()
{
got_alrm = 1;
}
/* see if c is the first of any of the curses arrow key sequences.
* if it is, read the rest of the sequence, and return the hjkl code
* that corresponds.
* if no match, just return c.
*/
static
chk_arrow (c)
register char c;
{
register char *seq;
if (c == *(seq = kl) || c == *(seq = kd) || c == *(seq = ku)
|| c == *(seq = kr)) {
char seqa[32]; /* maximum arrow escape sequence ever expected */
unsigned l = strlen(seq);
seqa[0] = c;
if (l > 1) {
extern unsigned alarm();
/* cautiously read rest of arrow sequence */
got_alrm = 0;
#ifndef OSK
signal (SIGALRM, on_alrm);
alarm(2);
#endif
read (0, seqa+1, l-1);
#ifndef OSK
alarm(0);
#endif
if (got_alrm)
return (c);
}
seqa[l] = '\0';
if (strcmp (seqa, kl) == 0)
return ('h');
if (strcmp (seqa, kd) == 0)
return ('j');
if (strcmp (seqa, ku) == 0)
return ('k');
if (strcmp (seqa, kr) == 0)
return ('l');
}
return (c);
}
/* do whatever might be necessary to get the screen and/or tty back into shape.
*/
byetty()
{
#ifdef UNIX
ioctl (0, TIOCSETP, &orig_sgtty);
#ifdef USE_NDELAY
fcntl (0, F_SETFL, 0); /* be sure to go back to blocking read */
#endif
#else /* UNIX */
_ss_opt(0,&sg_buf);
#endif
}
static
tload()
{
extern char *getenv(), *tgetstr();
extern char *UP, *BC;
char *egetstr();
static char tbuf[512];
char rawtbuf[1024];
char *tp;
char *ptr;
if (!(tp = getenv ("TERM"))) {
printf ("Must have addressable cursor\n");
exit(1);
}
if (!ttysetup) setuptty();
if (tgetent (rawtbuf, tp) != 1) {
printf ("Can't find termcap for %s\n", tp);
exit (1);
}
ptr = tbuf;
ku = egetstr ("ku", &ptr);
kd = egetstr ("kd", &ptr);
kl = egetstr ("kl", &ptr);
kr = egetstr ("kr", &ptr);
cm = egetstr ("cm", &ptr);
ce = egetstr ("ce", &ptr);
cl = egetstr ("cl", &ptr);
UP = egetstr ("up", &ptr);
if (!tgetflag ("bs"))
BC = egetstr ("bc", &ptr);
tloaded = 1;
}
/* like tgetstr() but discard curses delay codes, for now anyways */
static char *
egetstr (name, sptr)
char *name;
char **sptr;
{
extern char *tgetstr();
register char c, *s;
s = tgetstr (name, sptr);
while (((c = *s) >= '0' && c <= '9') || c == '*')
s += 1;
return (s);
}
/* set up tty for char-by-char read, non-blocking */
static
setuptty()
{
#ifdef UNIX
struct sgttyb sg;
ioctl (0, TIOCGETP, &orig_sgtty);
sg = orig_sgtty;
sg.sg_flags &= ~ECHO; /* do our own echoing */
sg.sg_flags &= ~CRMOD; /* leave CR and LF unchanged */
sg.sg_flags |= XTABS; /* no tabs with termcap */
sg.sg_flags |= CBREAK; /* wake up on each char but can still kill */
ioctl (0, TIOCSETP, &sg);
#else
struct sgbuf sg_b;
_gs_opt(0,&sg_buf);
_gs_opt(0,&sg_b);
sg_b.sg_echo = 0;
sg_b.sg_eofch = 0;
sg_b.sg_pause = 0;
_ss_opt(0,&sg_b);
#endif
ttysetup = 1;
}
#endif
#ifdef TURBO_C
#ifdef USE_ANSISYS
#define ESC '\033'
/* position cursor.
* (ANSI: ESC [ r ; c f) (r/c are numbers given in ASCII digits)
*/
c_pos (r, c)
int r, c;
{
printf ("%c[%d;%df", ESC, r, c);
}
/* erase entire screen. (ANSI: ESC [ 2 J) */
c_erase()
{
printf ("%c[2J", ESC);
}
/* erase to end of line. (ANSI: ESC [ K) */
c_eol()
{
printf ("%c[K", ESC);
}
#else
#include <dos.h>
union REGS rg;
/* position cursor.
*/
c_pos (r, c)
int r, c;
{
rg.h.ah = 2;
rg.h.bh = 0;
rg.h.dh = r-1;
rg.h.dl = c-1;
int86(16,&rg,&rg);
}
/* erase entire screen. */
c_erase()
{
int cur_cursor, i;
rg.h.ah = 3;
rg.h.bh = 0;
int86(16,&rg,&rg);
cur_cursor = rg.x.dx;
for(i = 0; i < 25; i++){
c_pos(i+1,1);
rg.h.ah = 10;
rg.h.bh = 0;
rg.h.al = 32;
rg.x.cx = 80;
int86(16,&rg,&rg);
}
rg.h.ah = 2;
rg.h.bh = 0;
rg.x.dx = cur_cursor;
int86(16,&rg,&rg);
}
/* erase to end of line.*/
c_eol()
{
int cur_cursor, i;
rg.h.ah = 3;
rg.h.bh = 0;
int86(16,&rg,&rg);
cur_cursor = rg.x.dx;
rg.h.ah = 10;
rg.h.bh = 0;
rg.h.al = 32;
rg.x.cx = 80 - rg.h.dl;
int86(16,&rg,&rg);
rg.h.ah = 2;
rg.h.bh = 0;
rg.x.dx = cur_cursor;
int86(16,&rg,&rg);
}
#endif
/* return 0 if there is a char that may be read without blocking, else -1 */
chk_char()
{
return (kbhit() == 0 ? -1 : 0);
}
/* read the next char, blocking if necessary, and return it. don't echo.
* map the arrow keys if we can too into hjkl
*/
read_char()
{
int c;
fflush (stdout);
c = getch();
if (c == 0) {
/* get scan code; convert to direction hjkl if possible */
c = getch();
switch (c) {
case 0x4b: c = 'h'; break;
case 0x50: c = 'j'; break;
case 0x48: c = 'k'; break;
case 0x4d: c = 'l'; break;
}
}
return (c);
}
/* do whatever might be necessary to get the screen and/or tty back into shape.
*/
byetty()
{
}
#endif
/* read up to max chars into buf, with cannonization.
* add trailing '\0' (buf is really max+1 chars long).
* return count of chars read (not counting '\0').
* assume cursor is already positioned as desired.
* if type END when n==0 then return -1.
*/
read_line (buf, max)
char buf[];
int max;
{
static char erase[] = "\b \b";
int n, c;
int done;
#ifdef UNIX
if (!ttysetup) setuptty();
#endif
for (done = 0, n = 0; !done; )
switch (c = read_char()) { /* does not echo */
case cntrl('h'): /* backspace or */
case 0177: /* delete are each char erase */
if (n > 0) {
fputs (erase, stdout);
n -= 1;
}
break;
case cntrl('u'): /* line erase */
while (n > 0) {
fputs (erase, stdout);
n -= 1;
}
break;
case '\r': /* EOL */
done++;
break;
default: /* echo and store, if ok */
if (n == 0 && c == END)
return (-1);
if (n >= max)
putchar (cntrl('g'));
else if (c >= ' ') {
putchar (c);
buf[n++] = c;
}
}
buf[n] = '\0';
return (n);
}