/* -*-C-*- */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#define InputStream PerlIO *
/*******************************************************************
Copyright (C) 1994,1995,1996,1997 Kenneth Albanowski. Unlimited
distribution and/or modification is allowed as long as this copyright
notice remains intact.
Written by Kenneth Albanowski on Thu Oct 6 11:42:20 EDT 1994
Contact at kjahds@kjahds.com or CIS:70705,126
Maintained by Jonathan Stowe <jns@gellyfish.com>
$Id: ReadKey.xs,v 2.22 2005/01/11 21:15:17 jonathan Exp $
Version 2.21, Sun Jul 28 12:57:56 BST 2002
Fix to improve the chances of automated testing succeeding
Version 2.20, Tue May 21 07:52:47 BST 2002
Patch from Autrijus Tang fixing Win32 Breakage with bleadperl
Version 2.19, Thu Mar 21 07:25:31 GMT 2002
Added check for definedness of $_[0] in comparisons in ReadKey, ReadLine
after reports of warnings.
Version 2.18, Sun Feb 10 13:06:57 GMT 2002
Altered prototyping style after reports of compile failures on
Windows.
Version 2.17, Fri Jan 25 06:58:47 GMT 2002
The '_' macro for non-ANSI compatibility was removed in 5.7.2
Version 2.16, Thu Nov 29 21:19:03 GMT 2001
It appears that the genchars.pl bit of the patch didnt apply
Applied the new ppport.h from Devel::PPPort
Version 2.15, Sun Nov 4 15:02:37 GMT 2001 (jns)
Applied the patch in
for PerlIO compatibility.
Version 2.14, Sun Mar 28 23:26:13 EST 1999
ppport.h 1.007 fixed for 5.005_55.
Version 2.13, Wed Mar 24 20:46:06 EST 1999
Adapted to ppport.h 1.006.
Version 2.12, Wed Jan 7 10:33:11 EST 1998
Slightly modified test and error reporting for Win32.
Version 2.11, Sun Dec 14 00:39:12 EST 1997
First attempt at Win32 support.
Version 2.10, skipped
Version 2.09, Tue Oct 7 13:07:43 EDT 1997
Grr. Added explicit detection of sys/poll.h and poll.h.
Version 2.08, Mon Oct 6 16:07:44 EDT 1997
Changed poll.h to sys/poll.h.
Version 2.07, Sun Jan 26 19:11:56 EST 1997
Added $VERSION to .pm.
Version 2.06, Tue Nov 26 01:47:09 EST 1996
Added PERLIO support and removed duplicate declaration in .pm.
Version 2.05, Tue Mar 12 19:08:33 EST 1996
Changed poll support so it works. Cleaned up .pm a little.
Version 2.04, Tue Oct 10 05:35:48 EDT 1995
Whoops. Changed GetTermSize back so that GSIZE code won't be
compiled if GWINSZ is being used. Also took ts_xxx and ts_yyy
out of GSIZE.
Version 2.03, Thu Sep 21 21:53:16 EDT 1995
Fixed up debugging info in Readkey.pm, and changed TermSizeVIO
to use _scrsize(). Hopefully this is GO for both Solaris and OS/2.
Version 2.02, Mon Sep 18 22:17:57 EDT 1995
Workaround for Solaris bug wasn't sufficient. Modularlized
GetTermSize into perl code, and added support for the
`resize` executable. Hard coded path for Solaris machines.
Version 2.01, Wed Sep 13 22:22:23 EDT 1995
Change error reporting around in getscreensize so that if
an ioctl fails but getenv succeeds, no warning will be
printed. This is an attempt to work around a Solaris bug where
TIOCGWINSZ fails in telnet sessions.
Version 2.00, Mon Sep 4 06:37:24 EDT 1995
Added timeouts to select/poll, added USE_STDIO_PTR support
(required for recent perl revisions), and fixed up compilation
under OS/2.
Version 1.99, Fri Aug 11 20:18:11 EDT 1995
Add file handles to ReadMode.
Version 1.97, Mon Apr 10 21:41:52 EDT 1995
Changed mode 5 to disable UC & delays. Added more ECHO flags.
Tested termio[s] & sgtty.
Added termoptions so test.pl can give more info.
Version 1.96,
Mucked with filehandle selection in ReadKey.pm.
Version 1.95,
Cleaning up for distribution.
Version 1.94,
Dealt with get/settermsize sillyness.
Version 1.91, Sat Mar 11 23:47:04 EST 1995:
Andy's patches, and a bit of termsize finesse.
Version 1.9, Thu Mar 9 14:11:49 EST 1995:
Modifying for portability. Prototypes, singed chars, etc.
Version 1.8, Mon Jan 9 23:18:14 EST 1995:
Added use of Configure.pm. No changes to ReadKey.
Version 1.7, Fri Dec 16 13:48:14 EST 1994:
Getting closer to release. Added new readmode 2. Had to bump up other
modes, unfortunately. This is the _last_ time I do that. If I have to
bump up the modes again, I'm switching to a different scheme.
Version 1.6, Wed Dec 14 17:36:59 EST 1994:
Completly reorganized the control-char support (twice!) so that
it is automatically ported by the preproccessor for termio[s], or
by an included script for sgtty. Logical defaults for sgtty are included
too. Added Sun TermSize support. (Hope I got it right.)
Version 1.5, Fri Dec 9 16:07:49 EST 1994:
Added SetTermSize, GetSpeeds, Get/SetControlChars, PerlIO support.
Version 1.01, Thu Oct 20 23:32:39 EDT 1994:
Added Select_fd_set_t casts to select() call.
Version 1.0: First "real" release. Everything seems cool.
*******************************************************************/
/***
Things to do:
Make sure the GetSpeed function is doing it's best to separate ispeed
from ospeed.
Separate the stty stuff from ReadMode, so that stty -a can be easily
used, among other things.
***/
/* Using these defines, you can elide anything you know
won't work properly */
/* Methods of doing non-blocking reads */
/*#define DONT_USE_SELECT*/
/*#define DONT_USE_POLL*/
/*#define DONT_USE_NODELAY*/
/* Terminal I/O packages */
/*#define DONT_USE_TERMIOS*/
/*#define DONT_USE_TERMIO*/
/*#define DONT_USE_SGTTY*/
/* IOCTLs that can be used for GetTerminalSize */
/*#define DONT_USE_GWINSZ*/
/*#define DONT_USE_GSIZE*/
/* IOCTLs that can be used for SetTerminalSize */
/*#define DONT_USE_SWINSZ*/
/*#define DONT_USE_SSIZE*/
/* This bit is for OS/2 */
#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
/* This flag should be off in the lflags when we enable termio mode */
# define TRK_IDEFAULT IDEFAULT
# define INCL_SUB
# define INCL_DOS
# include <os2.h>
# include <stdlib.h>
# define VIOMODE
#else
/* no os2 */
#endif
/* This bit is for Windows 95/NT */
#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
/* This bit for NeXT */
#ifdef _NEXT_SOURCE
/* fcntl with O_NDELAY (FNDELAY, actually) is broken on NeXT */
# 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 any other headers are needed for fcntl or O_NODELAY, they need to get
included right here */
# 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
/* If any other headers are likely to be needed for select, they need to be
included right here */
# 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
/* Pre-POSIX SVR3 systems sometimes define struct winsize in
sys/ptem.h. However, sys/ptem.h needs a type mblk_t (?) which
is defined in <sys/stream.h>.
No, Configure (dist3.051) doesn't know how to check for this.
*/
#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
/* This flag should be off in the lflags when we enable termio mode */
# define TRK_IDEFAULT 0
#endif
/* Fix up the disappearance of the '_' macro in Perl 5.7.2 */
#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 handle=PerlIO_fileno(file);
static VIOMODEINFO *modeinfo = NULL;
if (modeinfo == NULL)
modeinfo = (VIOMODEINFO *)malloc(sizeof(VIOMODEINFO));
VioGetMode(modeinfo,0);
*retheight = modeinfo->row ?: 25;
*retwidth = modeinfo->col ?: 80;*/
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; /* failure */
}
}
#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/*w.ts_xxx*/; *ypix=0/*w.ts_yyy*/; return 0;
}
else {
return -1; /* failure */
}
}
#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)) {
/* Logic: return maximum possible screen width, but return
only currently selected height */
if (retwidth)
*retwidth = info.dwMaximumWindowSize.X;
/*info.srWindow.Right - info.srWindow.Left;*/
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); /* Be polite to our children */
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
/*sprintf(buffer,"%d",width) * Should we could do this and then *
my_setenv("COLUMNS",buffer) * said we succeeded? *
sprintf(buffer,"%d",height);
my_setenv("LINES",buffer)*/
return -1; /* Fail */
# 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
/* Posixy stuff */
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
/* SysV stuff */
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
/* BSD stuff */
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
/* No termio, termios or sgtty. I suppose we can try stty,
but it would be nice if you could get a better OS */
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; /* Used to store the original terminal settings for each handle*/
HV * modehash; /* Used to record the current terminal "mode" for each handle*/
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
/* Posixy stuff */
tcgetattr(handle,&work);
#endif
#ifdef USE_TERMIO
/* SysV stuff */
ioctl(handle,TCGETA,&work);
#endif
#ifdef USE_SGTTY
/* BSD stuff */
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:
/* Should 5 disable ENABLE_WRAP_AT_EOL_OUTPUT? */
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
/* What, me worry about standards? */
# 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
/* XXX Is ONLCR in POSIX?. The value of '4' seems to be the same for
both SysV and Sun, so it's probably rather general, and I'm not
aware of a POSIX way to do this otherwise.
*/
#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) {
/*\
* Disable everything except parity if needed.
\*/
/* Hopefully, this should put the tty into unbuffered mode
with signals and control characters (both posixy and normal)
disabled, along with flow control. Echo should be off.
CR/LF is not translated, along with 8-bit/parity */
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) {
/* Hopefully, this should put the tty into unbuffered mode
with signals and control characters (both posixy and normal)
disabled, along with flow control. Echo should be off.
About the only thing left unchanged is 8-bit/parity */
memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
/*work.c_iflag = savebuf.c_iflag;*/
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)
{
/* This should be an unbuffered mode with signals and control
characters enabled, as should be flow control. Echo should
still be off */
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_iflag &= ~(IXON | IXOFF | IXANY);
work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
work.c_oflag = savebuf.c_oflag;*/
work.c_cc[VTIME] = 0;
work.c_cc[VMIN] = 1;
}
else if(mode==2)
{
/* This should be an unbuffered mode with signals and control
characters enabled, as should be flow control. Echo should
still be off */
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);
/*work.c_iflag &= ~(IXON |IXOFF|IXANY);
work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
work.c_oflag = savebuf.c_oflag;
work.c_cc[VTIME] = savebuf.c_cc[VTIME];
work.c_cc[VMIN] = savebuf.c_cc[VMIN];*/
}
else if(mode==1)
{
/* This should be an unbuffered mode with signals and control
characters enabled, as should be flow control. Echo should
still be off */
memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
work.c_iflag = savebuf.c_iflag;
work.c_lflag |= ICANON|ECHO|ISIG|IEXTEN;
/*work.c_iflag &= ~(IXON |IXOFF|IXANY);
work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
work.c_oflag = savebuf.c_oflag;
work.c_cc[VTIME] = savebuf.c_cc[VTIME];
work.c_cc[VMIN] = savebuf.c_cc[VMIN];*/
}
else if(mode==0){
/*work.c_lflag &= ~BITMASK;
work.c_lflag |= savebuf.c_lflag & BITMASK;
work.c_oflag = savebuf.c_oflag;
work.c_cc[VTIME] = savebuf.c_cc[VTIME];
work.c_cc[VMIN] = savebuf.c_cc[VMIN];
work.c_iflag = savebuf.c_iflag;
work.c_iflag &= ~(IXON|IXOFF|IXANY);
work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);*/
memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
/*Copy(&work,&savebuf,1,sizeof(struct tbuffer));*/
firsttime=1;
}
else
{
croak("ReadMode %d is not implemented on this architecture.",mode);
return;
}
/* If switching from a "lower power" mode to a higher one, keep the
data that may be in the queue, as it can easily be type-ahead. On
switching to a lower mode from a higher one, however, flush the queue
so that raw keystrokes won't hit an unexpecting program */
if(DisableFlush || oldmode<=mode)
tcsetattr(handle,TCSANOW,&work);
else
tcsetattr(handle,TCSAFLUSH,&work);
/*tcsetattr(handle,TCSANOW,&work);*/ /* It might be better to FLUSH
when changing gears to a lower mode,
and only use NOW for higher modes.
*/
#endif
#ifdef USE_TERMIO
/* What, me worry about standards? */
# 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) {
/* This mode should be echo disabled, signals disabled,
flow control disabled, and unbuffered. CR/LF translation
is off, and 8 bits if possible */
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) {
/* This mode should be echo disabled, signals disabled,
flow control disabled, and unbuffered. Parity is not
touched. */
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) {
/* This mode tries to have echo off, signals enabled,
flow control as per the original setting, and unbuffered. */
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) {
/* This mode tries to set echo on, signals on, and buffering
on, with flow control set to whatever it was originally. */
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];
/* This assumes turning ECHO and ICANON back on is
sufficient to re-enable cooked mode. If this is a
problem, complain to me */
/* What the heck. We're already saving the entire buf, so
I'm now going to reset VMIN and VTIME too. Hope this works
properly */
}
else if(mode==1) {
/* This mode tries to set echo on, signals on, and buffering
on, with flow control set to whatever it was originally. */
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];
/* This assumes turning ECHO and ICANON back on is
sufficient to re-enable cooked mode. If this is a
problem, complain to me */
/* What the heck. We're already saving the entire buf, so
I'm now going to reset VMIN and VTIME too. Hope this works
properly */
}
else if(mode==0) {
/* Put things back the way they were */
/*work.c_lflag = savebuf.c_lflag;
work.c_iflag = savebuf.c_iflag;
work.c_oflag = savebuf.c_oflag;
work.c_cc[VMIN] = savebuf.c_cc[VMIN];
work.c_cc[VTIME] = savebuf.c_cc[VTIME];*/
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) {
/* Unbuffered, echo off, signals off, flow control off */
/* CR-CR/LF mode off too, and 8-bit path enabled. */
# if defined(TIOCLGET) && defined(LPASS8)
if((work.buf.sg_flags & (EVENP|ODDP))==0 ||
(work.buf.sg_flags & (EVENP|ODDP))==(EVENP|ODDP))
work.local |= LPASS8; /* If parity isn't being used, use 8 bits */
# 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) {
/* Unbuffered, echo off, signals off, flow control off */
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) {
/* Unbuffered, echo off, signals on, flow control on */
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) {
/* Buffered, echo on, signals on, flow control on */
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) {
/* Buffered, echo on, signals on, flow control on */
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){
/* Original settings */
#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
/* No termio, termios or sgtty. I suppose we can try stty,
but it would be nice if you could get a better OS */
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");
/* Those probably won't work, but they couldn't hurt
at this point */
#endif
/*warn("Mode set to %d.\n",mode);*/
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
/* Make use of a recent addition to Perl, if possible */
# define FCOUNT(f) PerlIO_get_cnt(f)
#else
/* Make use of a recent addition to Configure, if possible */
# ifdef USE_STDIO_PTR
# define FCOUNT(f) PerlIO_get_cnt(f)
# else
/* This bit borrowed from pp_sys.c. Complain to Larry if it's broken. */
/* If any of this works PerlIO_get_cnt() will too ... NI-S */
# 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
/* This is for the best, I'm afraid. */
#if !defined(FCOUNT)
# ifdef Have_select
# undef Have_select
# endif
# ifdef Have_poll
# undef Have_poll
# endif
#endif
/* Note! If your machine has a bolixed up select() call that doesn't
understand this syntax, either fix the checkwaiting call below, or define
DONT_USE_SELECT. */
#ifdef Have_select
int selectfile(PerlIO *file,double delay)
{
struct timeval t;
int handle=PerlIO_fileno(file);
/*char buf[32];
Select_fd_set_t fd=(Select_fd_set_t)&buf[0];*/
fd_set fd;
if (PerlIO_fast_gets(file) && PerlIO_get_cnt(file) > 0)
return 1;
/*t.tv_sec=t.tv_usec=0;*/
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
/*
This portion of the Win32 code is partially borrowed from a version of PDCurses.
*/
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 = /*GetStdHandle(STD_INPUT_HANDLE)*/(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:
/*printf("\nkeyDown = %d, repeat = %d, vKey = %d, vScan = %d, ASCII = %d, Control = %d\n",
record.Event.KeyEvent.bKeyDown,
record.Event.KeyEvent.wRepeatCount,
record.Event.KeyEvent.wVirtualKeyCode,
record.Event.KeyEvent.wVirtualScanCode,
record.Event.KeyEvent.uChar.AsciiChar,
record.Event.KeyEvent.dwControlKeyState);*/
if (record.Event.KeyEvent.bKeyDown == FALSE)
goto again; /* throw away KeyUp events */
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; /* throw away shift/alt/ctrl key only key events */
keyCount = record.Event.KeyEvent.wRepeatCount;
break;
default:
keyCount = 0;
goto again;
break;
}
*key = lastKey = record.Event.KeyEvent.uChar.AsciiChar;
keyCount--;
return(TRUE);
/* again:
return (FALSE);
*/
}
#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)) {
/* Failure */
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();