#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#define InputStream PerlIO *
#ifdef OS2
# define I_FCNTL
# define HAS_FCNTL
# define O_NODELAY O_NDELAY
# define DONT_USE_SELECT
# define DONT_USE_POLL
# define DONT_USE_TERMIOS
# define DONT_USE_SGTTY
# define I_TERMIO
# define CC_TERMIO
# define TRK_IDEFAULT IDEFAULT
# define INCL_SUB
# define INCL_DOS
# include <os2.h>
# include <stdlib.h>
# define VIOMODE
#else
#endif
#ifdef WIN32
# define DONT_USE_TERMIO
# define DONT_USE_TERMIOS
# define DONT_USE_SGTTY
# define DONT_USE_POLL
# define DONT_USE_SELECT
# define DONT_USE_NODELAY
# define USE_WIN32
# include <io.h>
# if defined(_get_osfhandle) && (PERL_VERSION == 4) && (PERL_SUBVERSION < 5)
# undef _get_osfhandle
# if defined(_MSC_VER)
# define level _cnt
# endif
# endif
#endif
#ifdef _NEXT_SOURCE
# define DONT_USE_NODELAY
#endif
#if !defined(DONT_USE_NODELAY)
# ifdef HAS_FCNTL
# define Have_nodelay
# ifdef I_FCNTL
# include <fcntl.h>
# endif
# ifdef I_SYS_FILE
# include <sys/file.h>
# endif
# ifdef I_UNISTD
# include <unistd.h>
# endif
# if !defined(O_NODELAY)
# if !defined(FNDELAY)
# undef Have_nodelay
# else
# define O_NODELAY FNDELAY
# endif
# else
# define O_NODELAY O_NDELAY
# endif
# endif
#endif
#if !defined(DONT_USE_SELECT)
# ifdef HAS_SELECT
# ifdef I_SYS_SELECT
# include <sys/select.h>
# endif
# define Have_select
# endif
#endif
#if !defined(DONT_USE_POLL)
# ifdef HAS_POLL
# ifdef HAVE_POLL_H
# include <poll.h>
# define Have_poll
# endif
# ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
# define Have_poll
# endif
# endif
#endif
#ifdef DONT_USE_TERMIOS
# ifdef I_TERMIOS
# undef I_TERMIOS
# endif
#endif
#ifdef DONT_USE_TERMIO
# ifdef I_TERMIO
# undef I_TERMIO
# endif
#endif
#ifdef DONT_USE_SGTTY
# ifdef I_SGTTY
# undef I_SGTTY
# endif
#endif
#ifdef I_SYS_STREAM
# include <sys/stream.h>
#endif
#ifdef I_SYS_PTEM
# include <sys/ptem.h>
#endif
#ifdef I_TERMIOS
# include <termios.h>
#else
# ifdef I_TERMIO
# include <termio.h>
# else
# ifdef I_SGTTY
# include <sgtty.h>
# endif
# endif
#endif
#ifdef I_TERMIOS
# define CC_TERMIOS
#else
# ifdef I_TERMIO
# define CC_TERMIO
# else
# ifdef I_SGTTY
# define CC_SGTTY
# endif
# endif
#endif
#ifndef TRK_IDEFAULT
# define TRK_IDEFAULT 0
#endif
#ifndef _
# ifdef CAN_PROTOTYPE
# define _(args) args
# else
# define _(args) ()
# endif
#endif
#define DisableFlush (1) /* Should flushing mode changes be enabled?
I think not
for
now. */
#define STDIN PerlIO_stdin()
#include "cchars.h"
int
GetTermSizeVIO _((PerlIO * file,
int
* retwidth,
int
* retheight,
int
* xpix,
int
* ypix));
int
GetTermSizeGWINSZ _((PerlIO * file,
int
* retwidth,
int
* retheight,
int
* xpix,
int
* ypix));
int
GetTermSizeGSIZE _((PerlIO * file,
int
* retwidth,
int
* retheight,
int
* xpix,
int
* ypix));
int
GetTermSizeWin32 _((PerlIO * file,
int
* retwidth,
int
* retheight,
int
* xpix,
int
* ypix));
int
SetTerminalSize _((PerlIO * file,
int
width,
int
height,
int
xpix,
int
ypix));
void
ReadMode _((PerlIO * file,
int
mode));
int
pollfile _((PerlIO * file,
double
delay));
int
setnodelay _((PerlIO * file,
int
mode));
int
selectfile _((PerlIO * file,
double
delay));
int
Win32PeekChar _((PerlIO * file,
double
delay,
char
* key));
int
getspeed _((PerlIO * file, I32 *in, I32 * out ));
#ifdef VIOMODE
int
GetTermSizeVIO(PerlIO *file,
int
*retwidth,
int
*retheight,
int
*xpix,
int
*ypix)
{
int
buf[2];
_scrsize(&buf[0]);
*retwidth = buf[0]; *retheight = buf[1];
*xpix = *ypix = 0;
return
0;
}
#else
int
GetTermSizeVIO(PerlIO *file,
int
* retwidth,
int
*retheight,
int
*xpix,
int
*ypix)
{
croak(
"TermSizeVIO is not implemented on this architecture"
);
return
0;
}
#endif
#if defined(TIOCGWINSZ) && !defined(DONT_USE_GWINSZ)
int
GetTermSizeGWINSZ(PerlIO *file,
int
*retwidth,
int
*retheight,
int
*xpix,
int
*ypix)
{
int
handle=PerlIO_fileno(file);
struct
winsize w;
if
(ioctl (handle, TIOCGWINSZ, &w) == 0) {
*retwidth=w.ws_col; *retheight=w.ws_row;
*xpix=w.ws_xpixel; *ypix=w.ws_ypixel;
return
0;
}
else
{
return
-1;
}
}
#else
int
GetTermSizeGWINSZ(PerlIO *file,
int
*retwidth,
int
*retheight,
int
*xpix,
int
*ypix)
{
croak(
"TermSizeGWINSZ is not implemented on this architecture"
);
return
0;
}
#endif
#if (!defined(TIOCGWINSZ) || defined(DONT_USE_GWINSZ)) && (defined(TIOCGSIZE) && !defined(DONT_USE_GSIZE))
int
GetTermSizeGSIZE(PerlIO *file,
int
*retwidth,
int
*retheight,
int
*xpix,
int
*ypix)
{
int
handle=PerlIO_fileno(file);
struct
ttysize w;
if
(ioctl (handle, TIOCGSIZE, &w) == 0) {
*retwidth=w.ts_cols; *retheight=w.ts_lines;
*xpix=0
; *ypix=0
;
return
0;
}
else
{
return
-1;
}
}
#else
int
GetTermSizeGSIZE(PerlIO *file,
int
*retwidth,
int
*retheight,
int
*xpix,
int
*ypix)
{
croak(
"TermSizeGSIZE is not implemented on this architecture"
);
return
0;
}
#endif
#ifdef USE_WIN32
int
GetTermSizeWin32(PerlIO *file,
int
*retwidth,
int
*retheight,
int
*xpix,
int
*ypix)
{
int
handle=PerlIO_fileno(file);
HANDLE
whnd = (
HANDLE
)_get_osfhandle(handle);
CONSOLE_SCREEN_BUFFER_INFO info;
if
(GetConsoleScreenBufferInfo(whnd, &info)) {
if
(retwidth)
*retwidth = info.dwMaximumWindowSize.X;
if
(retheight)
*retheight = info.srWindow.Bottom - info.srWindow.Top;
if
(xpix)
*xpix = 0;
if
(ypix)
*ypix = 0;
return
0;
}
else
return
-1;
}
#else
int
GetTermSizeWin32(PerlIO *file,
int
*retwidth,
int
*retheight,
int
*xpix,
int
*ypix)
{
croak(
"TermSizeWin32 is not implemented on this architecture"
);
return
0;
}
#endif /* USE_WIN32 */
int
termsizeoptions() {
return
0
#ifdef VIOMODE
| 1
#endif
#if defined(TIOCGWINSZ) && !defined(DONT_USE_GWINSZ)
| 2
#endif
#if defined(TIOCGSIZE) && !defined(DONT_USE_GSIZE)
| 4
#endif
#if defined(USE_WIN32)
| 8
#endif
;
}
int
SetTerminalSize(PerlIO *file,
int
width,
int
height,
int
xpix,
int
ypix)
{
char
buffer[10];
int
handle=PerlIO_fileno(file);
#ifdef VIOMODE
return
-1;
#else
#if defined(TIOCSWINSZ) && !defined(DONT_USE_SWINSZ)
struct
winsize w;
w.ws_col=width;
w.ws_row=height;
w.ws_xpixel=xpix;
w.ws_ypixel=ypix;
if
(ioctl (handle, TIOCSWINSZ, &w) == 0) {
sprintf
(buffer,
"%d"
,width);
my_setenv(
"COLUMNS"
,buffer);
sprintf
(buffer,
"%d"
,height);
my_setenv(
"LINES"
,buffer);
return
0;
}
else
{
croak(
"TIOCSWINSZ ioctl call to set terminal size failed: %s"
,Strerror(
errno
));
return
-1;
}
#else
# if defined(TIOCSSIZE) && !defined(DONT_USE_SSIZE)
struct
ttysize w;
w.ts_lines=height;
w.ts_cols=width;
w.ts_xxx=xpix;
w.ts_yyy=ypix;
if
(ioctl (handle, TIOCSSIZE, &w) == 0) {
sprintf
(buffer,
"%d"
,width);
my_setenv(
"COLUMNS"
,buffer);
sprintf
(buffer,
"%d"
,height);
my_setenv(
"LINES"
,buffer);
return
0;
}
else
{
croak(
"TIOCSSIZE ioctl call to set terminal size failed: %s"
,Strerror(
errno
));
return
-1;
}
# else
return
-1;
# endif
#endif
#endif
}
I32 terminal_speeds[] = {
#ifdef B50
50, B50,
#endif
#ifdef B75
75, B75,
#endif
#ifdef B110
110, B110,
#endif
#ifdef B134
134, B134,
#endif
#ifdef B150
150, B150,
#endif
#ifdef B200
200, B200,
#endif
#ifdef B300
300, B300,
#endif
#ifdef B600
600, B600,
#endif
#ifdef B1200
1200, B1200,
#endif
#ifdef B1800
1800, B1800,
#endif
#ifdef B2400
2400, B2400,
#endif
#ifdef B4800
4800, B4800,
#endif
#ifdef B9600
9600, B9600,
#endif
#ifdef B19200
19200, B19200,
#endif
#ifdef B38400
38400, B38400,
#endif
#ifdef B57600
57600, B57600,
#endif
#ifdef B115200
115200, B115200,
#endif
#ifdef EXTA
19200, EXTA,
#endif
#ifdef EXTB
38400, EXTB,
#endif
#ifdef B0
0, B0,
#endif
-1,-1
};
int
getspeed(PerlIO *file,I32 *in, I32 *out)
{
int
handle=PerlIO_fileno(file);
int
i;
# ifdef I_TERMIOS
struct
termios buf;
tcgetattr(handle,&buf);
*in = *out = -1;
*in = cfgetispeed(&buf);
*out = cfgetospeed(&buf);
for
(i=0;terminal_speeds[i]!=-1;i+=2) {
if
(*in == terminal_speeds[i+1])
{ *in = terminal_speeds[i];
break
; }
}
for
(i=0;terminal_speeds[i]!=-1;i+=2) {
if
(*out == terminal_speeds[i+1])
{ *out = terminal_speeds[i];
break
; }
}
return
0;
# else
# ifdef I_TERMIO
struct
termio buf;
ioctl(handle,TCGETA,&buf);
*in=*out=-1;
for
(i=0;terminal_speeds[i]!=-1;i+=2) {
if
((buf.c_cflag & CBAUD) == terminal_speeds[i+1])
{ *in=*out=terminal_speeds[i];
break
; }
}
return
0;
# else
# ifdef I_SGTTY
struct
sgttyb buf;
ioctl(handle,TIOCGETP,&buf);
*in=*out=-1;
for
(i=0;terminal_speeds[i]!=-1;i+=2)
if
(buf.sg_ospeed == terminal_speeds[i+1])
{ *out = terminal_speeds[i];
break
; }
for
(i=0;terminal_speeds[i]!=-1;i+=2)
if
(buf.sg_ispeed == terminal_speeds[i+1])
{ *in = terminal_speeds[i];
break
; }
return
0;
# else
return
-1;
# endif
# endif
# endif
}
#ifdef WIN32
struct
tbuffer {
DWORD
Mode; };
#else
#ifdef I_TERMIOS
#define USE_TERMIOS
#define tbuffer termios
#else
#ifdef I_TERMIO
#define USE_TERMIO
#define tbuffer termio
#else
#ifdef I_SGTTY
#define USE_SGTTY
struct
tbuffer {
struct
sgttyb buf;
#if defined(TIOCGETC)
struct
tchars tchar;
#endif
#if defined(TIOCGLTC)
struct
ltchars ltchar;
#endif
#if defined(TIOCLGET)
int
local;
#endif
};
#else
#define USE_STTY
struct
tbuffer {
int
dummy;
};
#endif
#endif
#endif
#endif
HV * filehash;
HV * modehash;
void
ReadMode(PerlIO *file,
int
mode)
{
dTHR;
int
handle;
int
firsttime;
int
oldmode;
struct
tbuffer work;
struct
tbuffer savebuf;
handle=PerlIO_fileno(file);
firsttime=!hv_exists(filehash, (
char
*)&handle,
sizeof
(
int
));
# ifdef WIN32
if
(!GetConsoleMode((
HANDLE
)_get_osfhandle(handle), &work.Mode))
croak(
"GetConsoleMode failed, LastError=|%d|"
,GetLastError());
# endif /* WIN32 */
# ifdef USE_TERMIOS
tcgetattr(handle,&work);
#endif
#ifdef USE_TERMIO
ioctl(handle,TCGETA,&work);
#endif
#ifdef USE_SGTTY
ioctl(handle,TIOCGETP,&work.buf);
# if defined(TIOCGETC)
ioctl(handle,TIOCGETC,&work.tchar);
# endif
# if defined(TIOCLGET)
ioctl(handle,TIOCLGET,&work.local);
# endif
# if defined(TIOCGLTC)
ioctl(handle,TIOCGLTC,&work.ltchar);
# endif
#endif
if
(firsttime) {
firsttime=0;
memcpy
((
void
*)&savebuf,(
void
*)&work,
sizeof
(
struct
tbuffer));
if
(!hv_store(filehash,(
char
*)&handle,
sizeof
(
int
),
newSVpv((
char
*)&savebuf,
sizeof
(
struct
tbuffer)),0))
croak(
"Unable to stash terminal settings.\n"
);
if
(!hv_store(modehash,(
char
*)&handle,
sizeof
(
int
),newSViv(0),0))
croak(
"Unable to stash terminal settings.\n"
);
}
else
{
SV ** temp;
if
(!(temp=hv_fetch(filehash,(
char
*)&handle,
sizeof
(
int
),0)))
croak(
"Unable to retrieve stashed terminal settings.\n"
);
memcpy
(&savebuf,SvPV(*temp,PL_na),
sizeof
(
struct
tbuffer));
if
(!(temp=hv_fetch(modehash,(
char
*)&handle,
sizeof
(
int
),0)))
croak(
"Unable to retrieve stashed terminal mode.\n"
);
oldmode=SvIV(*temp);
}
#ifdef WIN32
switch
(mode) {
case
5:
case
4:
work.Mode &= ~(ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_OUTPUT);
work.Mode |= 0;
break
;
case
3:
work.Mode &= ~(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT);
work.Mode |= ENABLE_PROCESSED_INPUT|ENABLE_PROCESSED_OUTPUT;
break
;
case
2:
work.Mode &= ~(ENABLE_ECHO_INPUT);
work.Mode |= ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_PROCESSED_OUTPUT;
break
;
case
1:
work.Mode &= ~(0);
work.Mode |= ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_PROCESSED_OUTPUT;
break
;
case
0:
work = savebuf;
firsttime = 1;
break
;
}
if
(!SetConsoleMode((
HANDLE
)_get_osfhandle(handle), work.Mode))
croak(
"SetConsoleMode failed, LastError=|%d|"
,GetLastError());
#endif /* WIN32 */
#ifdef USE_TERMIOS
# if !defined (VMIN)
# define VMIN VEOF
# endif
# if !defined (VTIME)
# define VTIME VEOL
# endif
# if !defined (IXANY)
# define IXANY (0)
# endif
#ifndef IEXTEN
#ifdef IDEFAULT
#define IEXTEN IDEFAULT
#endif
#endif
#ifndef ONLCR
# define ONLCR 4
#endif
#ifndef IMAXBEL
#define IMAXBEL 0
#endif
#ifndef ECHOE
#define ECHOE 0
#endif
#ifndef ECHOK
#define ECHOK 0
#endif
#ifndef ECHONL
#define ECHONL 0
#endif
#ifndef ECHOPRT
#define ECHOPRT 0
#endif
#ifndef FLUSHO
#define FLUSHO 0
#endif
#ifndef PENDIN
#define PENDIN 0
#endif
#ifndef ECHOKE
#define ECHOKE 0
#endif
#ifndef ONLCR
#define ONLCR 0
#endif
#ifndef OCRNL
#define OCRNL 0
#endif
#ifndef ONLRET
#define ONLRET 0
#endif
#ifndef IUCLC
#define IUCLC 0
#endif
#ifndef OPOST
#define OPOST 0
#endif
#ifndef OLCUC
#define OLCUC 0
#endif
#ifndef ECHOCTL
#define ECHOCTL 0
#endif
#ifndef XCASE
#define XCASE 0
#endif
#ifndef BRKINT
#define BRKINT 0
#endif
if
(mode==5) {
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
work.c_lflag &= ~(ICANON|ISIG|IEXTEN );
work.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ECHOCTL);
work.c_lflag &= ~(ECHOPRT|ECHOKE|FLUSHO|PENDIN|XCASE);
work.c_lflag |= NOFLSH;
work.c_iflag &= ~(IXOFF|IXON|IXANY|ICRNL|IMAXBEL|BRKINT);
if
(((work.c_iflag & INPCK) != INPCK) ||
((work.c_cflag & PARENB) != PARENB)) {
work.c_iflag &= ~ISTRIP;
work.c_iflag |= IGNPAR;
work.c_iflag &= ~PARMRK;
}
work.c_oflag &= ~(OPOST |ONLCR|OCRNL|ONLRET);
work.c_cc[VTIME] = 0;
work.c_cc[VMIN] = 1;
}
else
if
(mode==4) {
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
work.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO);
work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
work.c_iflag &= ~(IXON | IXANY | BRKINT);
work.c_oflag = savebuf.c_oflag;
work.c_cc[VTIME] = 0;
work.c_cc[VMIN] = 1;
}
else
if
(mode==3)
{
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
work.c_iflag = savebuf.c_iflag;
work.c_lflag &= ~(ICANON | ECHO);
work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
work.c_lflag |= ISIG | IEXTEN;
work.c_cc[VTIME] = 0;
work.c_cc[VMIN] = 1;
}
else
if
(mode==2)
{
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
work.c_iflag = savebuf.c_iflag;
work.c_lflag |= ICANON|ISIG|IEXTEN;
work.c_lflag &= ~ECHO;
work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
}
else
if
(mode==1)
{
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
work.c_iflag = savebuf.c_iflag;
work.c_lflag |= ICANON|ECHO|ISIG|IEXTEN;
}
else
if
(mode==0){
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
firsttime=1;
}
else
{
croak(
"ReadMode %d is not implemented on this architecture."
,mode);
return
;
}
if
(DisableFlush || oldmode<=mode)
tcsetattr(handle,TCSANOW,&work);
else
tcsetattr(handle,TCSAFLUSH,&work);
#endif
#ifdef USE_TERMIO
# if !defined (IXANY)
# define IXANY (0)
# endif
#ifndef ECHOE
#define ECHOE 0
#endif
#ifndef ECHOK
#define ECHOK 0
#endif
#ifndef ECHONL
#define ECHONL 0
#endif
#ifndef XCASE
#define XCASE 0
#endif
#ifndef BRKINT
#define BRKINT 0
#endif
if
(mode==5) {
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
work.c_lflag &= ~(ECHO | ISIG | ICANON | XCASE);
work.c_lflag &= ~(ECHOE | ECHOK | ECHONL | TRK_IDEFAULT);
work.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | BRKINT);
if
((work.c_cflag | PARENB)!=PARENB ) {
work.c_iflag &= ~(ISTRIP|INPCK);
work.c_iflag |= IGNPAR;
}
work.c_oflag &= ~(OPOST|ONLCR);
work.c_cc[VMIN] = 1;
work.c_cc[VTIME] = 1;
}
else
if
(mode==4) {
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
work.c_lflag &= ~(ECHO | ISIG | ICANON);
work.c_lflag &= ~(ECHOE | ECHOK | ECHONL TRK_IDEFAULT);
work.c_iflag = savebuf.c_iflag;
work.c_iflag &= ~(IXON | IXOFF | IXANY | BRKINT);
work.c_oflag = savebuf.c_oflag;
work.c_cc[VMIN] = 1;
work.c_cc[VTIME] = 1;
}
else
if
(mode==3) {
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
work.c_lflag &= ~(ECHO | ICANON);
work.c_lflag &= ~(ECHOE | ECHOK | ECHONL | TRK_IDEFAULT);
work.c_lflag |= ISIG;
work.c_iflag = savebuf.c_iflag;
work.c_iflag &= ~(IXON | IXOFF | IXANY);
work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
work.c_oflag = savebuf.c_oflag;
work.c_cc[VMIN] = 1;
work.c_cc[VTIME] = 1;
}
else
if
(mode==2) {
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
work.c_lflag |= (ISIG | ICANON);
work.c_lflag &= ~ECHO;
work.c_lflag &= ~(ECHOE | ECHOK | ECHONL | TRK_IDEFAULT);
work.c_iflag = savebuf.c_iflag;
work.c_iflag &= ~(IXON | IXOFF | IXANY);
work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
work.c_oflag = savebuf.c_oflag;
work.c_cc[VMIN] = savebuf.c_cc[VMIN];
work.c_cc[VTIME] = savebuf.c_cc[VTIME];
}
else
if
(mode==1) {
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
work.c_lflag |= (ECHO | ISIG | ICANON);
work.c_iflag &= ~TRK_IDEFAULT;
work.c_iflag = savebuf.c_iflag;
work.c_iflag &= ~(IXON | IXOFF | IXANY);
work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
work.c_oflag = savebuf.c_oflag;
work.c_cc[VMIN] = savebuf.c_cc[VMIN];
work.c_cc[VTIME] = savebuf.c_cc[VTIME];
}
else
if
(mode==0) {
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
firsttime=1;
}
else
{
croak(
"ReadMode %d is not implemented on this architecture."
,mode);
return
;
}
if
(DisableFlush || oldmode<=mode)
ioctl(handle,TCSETA,&work);
else
ioctl(handle,TCSETAF,&work);
#endif
#ifdef USE_SGTTY
if
(mode==5) {
# if defined(TIOCLGET) && defined(LPASS8)
if
((work.buf.sg_flags & (EVENP|ODDP))==0 ||
(work.buf.sg_flags & (EVENP|ODDP))==(EVENP|ODDP))
work.local |= LPASS8;
# endif
work.buf.sg_flags &= ~(ECHO|CRMOD);
work.buf.sg_flags |= (RAW|CBREAK);
# if defined(TIOCGETC)
work.tchar.t_intrc = -1;
work.tchar.t_quitc = -1;
work.tchar.t_startc= -1;
work.tchar.t_stopc = -1;
work.tchar.t_eofc = -1;
work.tchar.t_brkc = -1;
# endif
# if defined(TIOCGLTC)
work.ltchar.t_suspc= -1;
work.ltchar.t_dsuspc= -1;
work.ltchar.t_rprntc= -1;
work.ltchar.t_flushc= -1;
work.ltchar.t_werasc= -1;
work.ltchar.t_lnextc= -1;
# endif
}
else
if
(mode==4) {
work.buf.sg_flags &= ~(ECHO|RAW);
work.buf.sg_flags |= (CBREAK|CRMOD);
# if defined(TIOCLGET)
work.local=savebuf.local;
# endif
# if defined(TIOCGETC)
work.tchar.t_intrc = -1;
work.tchar.t_quitc = -1;
work.tchar.t_startc= -1;
work.tchar.t_stopc = -1;
work.tchar.t_eofc = -1;
work.tchar.t_brkc = -1;
# endif
# if defined(TIOCGLTC)
work.ltchar.t_suspc= -1;
work.ltchar.t_dsuspc= -1;
work.ltchar.t_rprntc= -1;
work.ltchar.t_flushc= -1;
work.ltchar.t_werasc= -1;
work.ltchar.t_lnextc= -1;
# endif
}
else
if
(mode==3) {
work.buf.sg_flags &= ~(RAW|ECHO);
work.buf.sg_flags |= CBREAK|CRMOD;
# if defined(TIOCLGET)
work.local=savebuf.local;
# endif
# if defined(TIOCGLTC)
work.tchar = savebuf.tchar;
# endif
# if defined(TIOCGLTC)
work.ltchar = savebuf.ltchar;
# endif
}
else
if
(mode==2) {
work.buf.sg_flags &= ~(RAW|CBREAK);
work.buf.sg_flags |= CRMOD;
work.buf.sg_flags &= ~ECHO;
# if defined(TIOCLGET)
work.local=savebuf.local;
# endif
# if defined(TIOCGLTC)
work.tchar = savebuf.tchar;
# endif
# if defined(TIOCGLTC)
work.ltchar = savebuf.ltchar;
# endif
}
else
if
(mode==1) {
work.buf.sg_flags &= ~(RAW|CBREAK);
work.buf.sg_flags |= ECHO|CRMOD;
# if defined(TIOCLGET)
work.local=savebuf.local;
# endif
# if defined(TIOCGLTC)
work.tchar = savebuf.tchar;
# endif
# if defined(TIOCGLTC)
work.ltchar = savebuf.ltchar;
# endif
}
else
if
(mode==0){
#if 0
work.buf.sg_flags &= ~(RAW|CBREAK|ECHO|CRMOD);
work.buf.sg_flags |= savebuf.sg_flags & (RAW|CBREAK|ECHO|CRMOD);
# if defined(TIOCLGET)
work.local=savebuf.local;
# endif
# if defined(TIOCGLTC)
work.tchar = savebuf.tchar;
# endif
# if defined(TIOCGLTC)
work.ltchar = savebuf.ltchar;
# endif
#endif
memcpy
((
void
*)&work,(
void
*)&savebuf,
sizeof
(
struct
tbuffer));
firsttime=1;
}
else
{
croak(
"ReadMode %d is not implemented on this architecture."
,mode);
return
;
}
#if defined(TIOCLSET)
ioctl(handle,TIOCLSET,&work.local);
#endif
#if defined(TIOCSETC)
ioctl(handle,TIOCSETC,&work.tchar);
#endif
# if defined(TIOCGLTC)
ioctl(handle,TIOCSLTC,&work.ltchar);
# endif
if
(DisableFlush || oldmode<=mode)
ioctl(handle,TIOCSETN,&work.buf);
else
ioctl(handle,TIOCSETP,&work.buf);
#endif
#ifdef USE_STTY
if
(mode==5)
system
(
"/bin/stty raw -cbreak -isig -echo -ixon -onlcr -icrnl -brkint"
);
else
if
(mode==4)
system
(
"/bin/stty -raw cbreak -isig -echo -ixon onlcr icrnl -brkint"
);
else
if
(mode==3)
system
(
"/bin/stty -raw cbreak isig -echo ixon onlcr icrnl brkint"
);
else
if
(mode==2)
system
(
"/bin/stty -raw -cbreak isig echo ixon onlcr icrnl brkint"
);
else
if
(mode==1)
system
(
"/bin/stty -raw -cbreak isig -echo ixon onlcr icrnl brkint"
);
else
if
(mode==0)
system
(
"/bin/stty -raw -cbreak isig echo ixon onlcr icrnl brkint"
);
#endif
if
( firsttime ) {
hv_delete(filehash,(
char
*)&handle,
sizeof
(
int
),0);
hv_delete(modehash,(
char
*)&handle,
sizeof
(
int
),0);
}
else
{
if
(!hv_store(modehash,(
char
*)&handle,
sizeof
(
int
),
newSViv(mode),0))
croak(
"Unable to stash terminal settings.\n"
);
}
}
#ifdef USE_PERLIO
# define FCOUNT(f) PerlIO_get_cnt(f)
#else
# ifdef USE_STDIO_PTR
# define FCOUNT(f) PerlIO_get_cnt(f)
# else
# if defined(USE_STD_STDIO) || defined(atarist) /* this will work with atariST */
# define FBASE(f) ((f)->_base)
# define FSIZE(f) ((f)->_cnt + ((f)->_ptr - (f)->_base))
# define FPTR(f) ((f)->_ptr)
# define FCOUNT(f) ((f)->_cnt)
# else
# if defined(USE_LINUX_STDIO)
# define FBASE(f) ((f)->_IO_read_base)
# define FSIZE(f) ((f)->_IO_read_end - FBASE(f))
# define FPTR(f) ((f)->_IO_read_ptr)
# define FCOUNT(f) ((f)->_IO_read_end - FPTR(f))
# endif
# endif
# endif
#endif
#if !defined(FCOUNT)
# ifdef Have_select
# undef Have_select
# endif
# ifdef Have_poll
# undef Have_poll
# endif
#endif
#ifdef Have_select
int
selectfile(PerlIO *file,
double
delay)
{
struct
timeval t;
int
handle=PerlIO_fileno(file);
fd_set fd;
if
(PerlIO_fast_gets(file) && PerlIO_get_cnt(file) > 0)
return
1;
if
(delay < 0.0)
delay = 0.0;
t.tv_sec = (
long
)delay;
delay -= (
double
)t.tv_sec;
t.tv_usec = (
long
)(delay * 1000000.0);
FD_ZERO(&fd);
FD_SET(handle,&fd);
if
(select(handle+1,(Select_fd_set_t)&fd,
(Select_fd_set_t)0,
(Select_fd_set_t)&fd, &t))
return
-1;
else
return
0;
}
#else
int
selectfile(PerlIO *file,
double
delay)
{
croak(
"select is not supported on this architecture"
);
return
0;
}
#endif
#ifdef Have_nodelay
int
setnodelay(PerlIO *file,
int
mode)
{
int
handle=PerlIO_fileno(file);
int
flags;
flags=fcntl(handle,F_GETFL,0);
if
(mode)
flags|=O_NODELAY;
else
flags&=~O_NODELAY;
fcntl(handle,F_SETFL,flags);
return
0;
}
#else
int
setnodelay(PerlIO *file,
int
mode)
{
croak(
"setnodelay is not supported on this architecture"
);
return
0;
}
#endif
#ifdef Have_poll
int
pollfile(PerlIO *file,
double
delay)
{
int
handle=PerlIO_fileno(file);
struct
pollfd fds;
if
(PerlIO_fast_gets(f) && PerlIO_get_cnt(f) > 0)
return
1;
if
(delay<0.0) delay = 0.0;
fds.fd=handle;
fds.events=POLLIN;
fds.revents=0;
return
(poll(&fds,1,(
long
)(delay * 1000.0))>0);
}
#else
int
pollfile(PerlIO *file,
double
delay)
{
croak(
"pollfile is not supported on this architecture"
);
return
0;
}
#endif
#ifdef WIN32
int
Win32PeekChar(PerlIO *file,
double
delay,
char
*key)
{
int
handle;
HANDLE
whnd;
INPUT_RECORD record;
DWORD
readRecords;
static
int
keyCount = 0;
static
char
lastKey = 0;
file = STDIN;
handle = PerlIO_fileno(file);
whnd =
(
HANDLE
)_get_osfhandle(handle);
again:
if
(keyCount > 0) {
keyCount--;
*key = lastKey;
return
TRUE;
}
if
(delay > 0) {
if
(WaitForSingleObject(whnd, delay * 1000.0) != WAIT_OBJECT_0)
{
return
FALSE;
}
}
if
(delay != 0) {
PeekConsoleInput(whnd, &record, 1, &readRecords);
if
(readRecords == 0)
return
(FALSE);
}
ReadConsoleInput(whnd, &record, 1, &readRecords);
switch
(record.EventType)
{
case
KEY_EVENT:
if
(record.Event.KeyEvent.bKeyDown == FALSE)
goto
again;
if
(record.Event.KeyEvent.wVirtualKeyCode == 16
|| record.Event.KeyEvent.wVirtualKeyCode == 17
|| record.Event.KeyEvent.wVirtualKeyCode == 18
|| record.Event.KeyEvent.wVirtualKeyCode == 20
|| record.Event.KeyEvent.wVirtualKeyCode == 144
|| record.Event.KeyEvent.wVirtualKeyCode == 145)
goto
again;
keyCount = record.Event.KeyEvent.wRepeatCount;
break
;
default
:
keyCount = 0;
goto
again;
break
;
}
*key = lastKey = record.Event.KeyEvent.uChar.AsciiChar;
keyCount--;
return
(TRUE);
}
#else
int
Win32PeekChar(PerlIO *file,
double
delay,
char
*key)
{
croak(
"Win32PeekChar is not supported on this architecture"
);
return
0;
}
#endif
int
blockoptions() {
return
0
#ifdef Have_nodelay
| 1
#endif
#ifdef Have_poll
| 2
#endif
#ifdef Have_select
| 4
#endif
#ifdef USE_WIN32
| 8
#endif
;
}
int
termoptions() {
int
i=0;
#ifdef USE_TERMIOS
i=1;
#endif
#ifdef USE_TERMIO
i=2;
#endif
#ifdef USE_SGTTY
i=3;
#endif
#ifdef USE_STTY
i=4;
#endif
#ifdef USE_WIN32
i=5;
#endif
return
i;
}
MODULE = Term::ReadKey PACKAGE = Term::ReadKey
int
selectfile(file,delay)
InputStream file
double
delay
# Clever, eh?
void
SetReadMode(mode,file=STDIN)
int
mode
InputStream file
CODE:
{
ReadMode(file,mode);
}
int
setnodelay(file,mode)
InputStream file
int
mode
int
pollfile(file,delay)
InputStream file
double
delay
SV *
Win32PeekChar(file, delay)
InputStream file
double
delay
CODE:
{
char
key;
if
(Win32PeekChar(file, delay, &key))
RETVAL = newSVpv(&key, 1);
else
RETVAL = newSVsv(&PL_sv_undef);
}
OUTPUT:
RETVAL
int
blockoptions()
int
termoptions()
int
termsizeoptions()
void
GetTermSizeWin32(file=STDIN)
InputStream file
PPCODE:
{
int
x,y,xpix,ypix;
if
( GetTermSizeWin32(file,&x,&y,&xpix,&ypix)==0)
{
EXTEND(sp, 4);
PUSHs(sv_2mortal(newSViv((IV)x)));
PUSHs(sv_2mortal(newSViv((IV)y)));
PUSHs(sv_2mortal(newSViv((IV)xpix)));
PUSHs(sv_2mortal(newSViv((IV)ypix)));
}
else
{
ST(0) = sv_newmortal();
}
}
void
GetTermSizeVIO(file=STDIN)
InputStream file
PPCODE:
{
int
x,y,xpix,ypix;
if
( GetTermSizeVIO(file,&x,&y,&xpix,&ypix)==0)
{
EXTEND(sp, 4);
PUSHs(sv_2mortal(newSViv((IV)x)));
PUSHs(sv_2mortal(newSViv((IV)y)));
PUSHs(sv_2mortal(newSViv((IV)xpix)));
PUSHs(sv_2mortal(newSViv((IV)ypix)));
}
else
{
ST(0) = sv_newmortal();
}
}
void
GetTermSizeGWINSZ(file=STDIN)
InputStream file
PPCODE:
{
int
x,y,xpix,ypix;
if
( GetTermSizeGWINSZ(file,&x,&y,&xpix,&ypix)==0)
{
EXTEND(sp, 4);
PUSHs(sv_2mortal(newSViv((IV)x)));
PUSHs(sv_2mortal(newSViv((IV)y)));
PUSHs(sv_2mortal(newSViv((IV)xpix)));
PUSHs(sv_2mortal(newSViv((IV)ypix)));
}
else
{
ST(0) = sv_newmortal();
}
}
void
GetTermSizeGSIZE(file=STDIN)
InputStream file
PPCODE:
{
int
x,y,xpix,ypix;
if
( GetTermSizeGSIZE(file,&x,&y,&xpix,&ypix)==0)
{
EXTEND(sp, 4);
PUSHs(sv_2mortal(newSViv((IV)x)));
PUSHs(sv_2mortal(newSViv((IV)y)));
PUSHs(sv_2mortal(newSViv((IV)xpix)));
PUSHs(sv_2mortal(newSViv((IV)ypix)));
}
else
{
ST(0) = sv_newmortal();
}
}
int
SetTerminalSize(width,height,xpix,ypix,file=STDIN)
int
width
int
height
int
xpix
int
ypix
InputStream file
CODE:
{
RETVAL=SetTerminalSize(file,width,height,xpix,ypix);
}
void
GetSpeed(file=STDIN)
InputStream file
PPCODE:
{
I32 in,out;
if
(items!=0) {
croak(
"Usage: Term::ReadKey::GetSpeed()"
);
}
if
(getspeed(file,&in,&out)) {
ST( 0) = sv_newmortal();
}
else
{
EXTEND(sp, 2);
PUSHs(sv_2mortal(newSViv((IV)in)));
PUSHs(sv_2mortal(newSViv((IV)out)));
}
}
BOOT:
newXS(
"Term::ReadKey::GetControlChars"
, XS_Term__ReadKey_GetControlChars, file);
newXS(
"Term::ReadKey::SetControlChars"
, XS_Term__ReadKey_SetControlChars, file);
filehash=newHV();
modehash=newHV();