Blame ReadKey.xs

Packit 910689
/* -*-C-*- */
Packit 910689
Packit 910689
#define PERL_NO_GET_CONTEXT     /* we want efficiency */
Packit 910689
#include "EXTERN.h"
Packit 910689
#include "perl.h"
Packit 910689
#include "XSUB.h"
Packit 910689
#include "ppport.h"
Packit 910689
Packit 910689
#define InputStream PerlIO *
Packit 910689
Packit 910689
/*******************************************************************
Packit 910689
Packit 910689
 Copyright (C) 1994,1995,1996,1997 Kenneth Albanowski. Unlimited
Packit 910689
 distribution and/or modification is allowed as long as this copyright
Packit 910689
 notice remains intact.
Packit 910689
Packit 910689
 Written by Kenneth Albanowski on Thu Oct  6 11:42:20 EDT 1994
Packit 910689
 Contact at kjahds@kjahds.com or CIS:70705,126
Packit 910689
Packit 910689
 Maintained by Jonathan Stowe <jns@gellyfish.co.uk>
Packit 910689
Packit 910689
 The below captures the history prior to it being in full time version
Packit 910689
 control:
Packit 910689
Packit 910689
 $Id: ReadKey.xs,v 2.22 2005/01/11 21:15:17 jonathan Exp $
Packit 910689
Packit 910689
 Version 2.21, Sun Jul 28 12:57:56 BST 2002
Packit 910689
    Fix to improve the chances of automated testing succeeding
Packit 910689
Packit 910689
 Version 2.20, Tue May 21 07:52:47 BST 2002
Packit 910689
    Patch from Autrijus Tang fixing Win32 Breakage with bleadperl
Packit 910689
    
Packit 910689
 Version 2.19, Thu Mar 21 07:25:31 GMT 2002
Packit 910689
    Added check for definedness of $_[0] in comparisons in ReadKey, ReadLine
Packit 910689
    after reports of warnings.
Packit 910689
Packit 910689
 Version 2.18, Sun Feb 10 13:06:57 GMT 2002
Packit 910689
    Altered prototyping style after reports of compile failures on
Packit 910689
    Windows.
Packit 910689
Packit 910689
 Version 2.17, Fri Jan 25 06:58:47 GMT 2002
Packit 910689
    The '_' macro for non-ANSI compatibility was removed in 5.7.2
Packit 910689
Packit 910689
 Version 2.16, Thu Nov 29 21:19:03 GMT 2001
Packit 910689
    It appears that the genchars.pl bit of the patch didnt apply
Packit 910689
    Applied the new ppport.h from Devel::PPPort
Packit 910689
Packit 910689
 Version 2.15, Sun Nov  4 15:02:37 GMT 2001 (jns)
Packit 910689
    Applied the patch in 
Packit 910689
    http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2001-01/msg01588.html
Packit 910689
    for PerlIO compatibility.
Packit 910689
Packit 910689
 Version 2.14, Sun Mar 28 23:26:13 EST 1999
Packit 910689
    ppport.h 1.007 fixed for 5.005_55.
Packit 910689
 
Packit 910689
 Version 2.13, Wed Mar 24 20:46:06 EST 1999
Packit 910689
 	Adapted to ppport.h 1.006.
Packit 910689
Packit 910689
 Version 2.12, Wed Jan  7 10:33:11 EST 1998
Packit 910689
 	Slightly modified test and error reporting for Win32.
Packit 910689
 
Packit 910689
 Version 2.11, Sun Dec 14 00:39:12 EST 1997
Packit 910689
    First attempt at Win32 support.
Packit 910689
Packit 910689
 Version 2.10, skipped
Packit 910689
Packit 910689
 Version 2.09, Tue Oct  7 13:07:43 EDT 1997
Packit 910689
    Grr. Added explicit detection of sys/poll.h and poll.h.
Packit 910689
Packit 910689
 Version 2.08, Mon Oct  6 16:07:44 EDT 1997
Packit 910689
    Changed poll.h to sys/poll.h.
Packit 910689
Packit 910689
 Version 2.07, Sun Jan 26 19:11:56 EST 1997
Packit 910689
    Added $VERSION to .pm.
Packit 910689
Packit 910689
 Version 2.06, Tue Nov 26 01:47:09 EST 1996
Packit 910689
    Added PERLIO support and removed duplicate declaration in .pm.
Packit 910689
Packit 910689
 Version 2.05, Tue Mar 12 19:08:33 EST 1996
Packit 910689
 	Changed poll support so it works. Cleaned up .pm a little.
Packit 910689
 	
Packit 910689
 Version 2.04, Tue Oct 10 05:35:48 EDT 1995
Packit 910689
 	Whoops. Changed GetTermSize back so that GSIZE code won't be
Packit 910689
 	compiled if GWINSZ is being used. Also took ts_xxx and ts_yyy
Packit 910689
 	out of GSIZE.
Packit 910689
Packit 910689
 Version 2.03, Thu Sep 21 21:53:16 EDT 1995
Packit 910689
	Fixed up debugging info in Readkey.pm, and changed TermSizeVIO
Packit 910689
	to use _scrsize(). Hopefully this is GO for both Solaris and OS/2.
Packit 910689
Packit 910689
 Version 2.02, Mon Sep 18 22:17:57 EDT 1995
Packit 910689
	Workaround for Solaris bug wasn't sufficient. Modularlized
Packit 910689
	GetTermSize into perl code, and added support for the 
Packit 910689
	`resize` executable. Hard coded path for Solaris machines.
Packit 910689
Packit 910689
 Version 2.01, Wed Sep 13 22:22:23 EDT 1995
Packit 910689
	Change error reporting around in getscreensize so that if
Packit 910689
 	an ioctl fails but getenv succeeds, no warning will be 
Packit 910689
	printed. This is an attempt to work around a Solaris bug where
Packit 910689
	TIOCGWINSZ fails in telnet sessions.
Packit 910689
 
Packit 910689
 Version 2.00, Mon Sep  4 06:37:24 EDT 1995
Packit 910689
	Added timeouts to select/poll, added USE_STDIO_PTR support
Packit 910689
	(required for recent perl revisions), and fixed up compilation
Packit 910689
	under OS/2.
Packit 910689
Packit 910689
 Version 1.99, Fri Aug 11 20:18:11 EDT 1995
Packit 910689
	Add file handles to ReadMode.
Packit 910689
Packit 910689
 Version 1.97, Mon Apr 10 21:41:52 EDT 1995
Packit 910689
	Changed mode 5 to disable UC & delays. Added more ECHO flags.
Packit 910689
        Tested termio[s] & sgtty.
Packit 910689
	Added termoptions so test.pl can give more info.
Packit 910689
Packit 910689
 Version 1.96,
Packit 910689
	Mucked with filehandle selection in ReadKey.pm.
Packit 910689
Packit 910689
 Version 1.95,
Packit 910689
	Cleaning up for distribution.
Packit 910689
Packit 910689
 Version 1.94,
Packit 910689
	Dealt with get/settermsize sillyness.
Packit 910689
Packit 910689
 Version 1.91, Sat Mar 11 23:47:04 EST 1995:
Packit 910689
	Andy's patches, and a bit of termsize finesse.
Packit 910689
Packit 910689
 Version 1.9, Thu Mar  9 14:11:49 EST 1995:
Packit 910689
	Modifying for portability. Prototypes, singed chars, etc.
Packit 910689
Packit 910689
 Version 1.8, Mon Jan  9 23:18:14 EST 1995:
Packit 910689
	Added use of Configure.pm. No changes to ReadKey.
Packit 910689
Packit 910689
 Version 1.7, Fri Dec 16 13:48:14 EST 1994:
Packit 910689
   Getting closer to release. Added new readmode 2. Had to bump up other
Packit 910689
   modes, unfortunately. This is the _last_ time I do that. If I have to
Packit 910689
   bump up the modes again, I'm switching to a different scheme.
Packit 910689
Packit 910689
 Version 1.6, Wed Dec 14 17:36:59 EST 1994:
Packit 910689
	Completly reorganized the control-char support (twice!) so that
Packit 910689
	it is automatically ported by the preproccessor for termio[s], or
Packit 910689
	by an included script for sgtty. Logical defaults for sgtty are included
Packit 910689
	too. Added Sun TermSize support. (Hope I got it right.)
Packit 910689
Packit 910689
 Version 1.5, Fri Dec  9 16:07:49 EST 1994:
Packit 910689
	Added SetTermSize, GetSpeeds, Get/SetControlChars, PerlIO support.
Packit 910689
Packit 910689
 Version 1.01, Thu Oct 20 23:32:39 EDT 1994:
Packit 910689
	Added Select_fd_set_t casts to select() call.
Packit 910689
Packit 910689
 Version 1.0: First "real" release. Everything seems cool.
Packit 910689
Packit 910689
Packit 910689
*******************************************************************/
Packit 910689
Packit 910689
/***
Packit 910689
Packit 910689
 Things to do:
Packit 910689
Packit 910689
	Make sure the GetSpeed function is doing it's best to separate ispeed
Packit 910689
	from ospeed.
Packit 910689
	
Packit 910689
	Separate the stty stuff from ReadMode, so that stty -a can be easily
Packit 910689
	used, among other things.
Packit 910689
Packit 910689
***/
Packit 910689
Packit 910689
Packit 910689
Packit 910689
/* Using these defines, you can elide anything you know 
Packit 910689
   won't work properly */
Packit 910689
Packit 910689
/* Methods of doing non-blocking reads */
Packit 910689
Packit 910689
/*#define DONT_USE_SELECT*/
Packit 910689
/*#define DONT_USE_POLL*/
Packit 910689
/*#define DONT_USE_NODELAY*/
Packit 910689
Packit 910689
Packit 910689
/* Terminal I/O packages */
Packit 910689
Packit 910689
/*#define DONT_USE_TERMIOS*/
Packit 910689
/*#define DONT_USE_TERMIO*/
Packit 910689
/*#define DONT_USE_SGTTY*/
Packit 910689
Packit 910689
/* IOCTLs that can be used for GetTerminalSize */
Packit 910689
Packit 910689
/*#define DONT_USE_GWINSZ*/
Packit 910689
/*#define DONT_USE_GSIZE*/
Packit 910689
Packit 910689
/* IOCTLs that can be used for SetTerminalSize */
Packit 910689
Packit 910689
/*#define DONT_USE_SWINSZ*/
Packit 910689
/*#define DONT_USE_SSIZE*/
Packit 910689
Packit 910689
Packit 910689
/* This bit is for OS/2 */
Packit 910689
Packit 910689
#ifdef OS2
Packit 910689
#       define I_FCNTL
Packit 910689
#       define HAS_FCNTL
Packit 910689
Packit 910689
#       define O_NODELAY O_NDELAY
Packit 910689
Packit 910689
#       define DONT_USE_SELECT
Packit 910689
#       define DONT_USE_POLL
Packit 910689
Packit 910689
#       define DONT_USE_TERMIOS
Packit 910689
#       define DONT_USE_SGTTY
Packit 910689
#       define I_TERMIO
Packit 910689
#       define CC_TERMIO
Packit 910689
Packit 910689
/* This flag should be off in the lflags when we enable termio mode */
Packit 910689
#      define TRK_IDEFAULT     IDEFAULT
Packit 910689
Packit 910689
#       define INCL_SUB
Packit 910689
#       define INCL_DOS
Packit 910689
Packit 910689
#       include <os2.h>
Packit 910689
#	include <stdlib.h>
Packit 910689
Packit 910689
#       define VIOMODE
Packit 910689
#else
Packit 910689
        /* no os2 */
Packit 910689
#endif
Packit 910689
Packit 910689
/* This bit is for Windows 95/NT */
Packit 910689
Packit 910689
#ifdef WIN32
Packit 910689
#		define DONT_USE_TERMIO
Packit 910689
#		define DONT_USE_TERMIOS
Packit 910689
#		define DONT_USE_SGTTY
Packit 910689
#		define DONT_USE_POLL
Packit 910689
#		define DONT_USE_SELECT
Packit 910689
#		define DONT_USE_NODELAY
Packit 910689
#		define USE_WIN32
Packit 910689
#		include <io.h>
Packit 910689
#		if defined(_get_osfhandle) && (PERL_VERSION == 4) && (PERL_SUBVERSION < 5)
Packit 910689
#			undef _get_osfhandle
Packit 910689
#			if defined(_MSC_VER)
Packit 910689
#				define level _cnt
Packit 910689
#			endif
Packit 910689
#		endif
Packit 910689
#endif
Packit 910689
Packit 910689
/* This bit for NeXT */
Packit 910689
Packit 910689
#ifdef _NEXT_SOURCE
Packit 910689
  /* fcntl with O_NDELAY (FNDELAY, actually) is broken on NeXT */
Packit 910689
# define DONT_USE_NODELAY
Packit 910689
#endif
Packit 910689
Packit 910689
#if !defined(DONT_USE_NODELAY)
Packit 910689
# ifdef HAS_FCNTL
Packit 910689
#  define Have_nodelay
Packit 910689
#  ifdef I_FCNTL
Packit 910689
#   include <fcntl.h>
Packit 910689
#  endif
Packit 910689
#  ifdef I_SYS_FILE
Packit 910689
#   include <sys/file.h>
Packit 910689
#  endif
Packit 910689
#  ifdef I_UNISTD
Packit 910689
#   include <unistd.h>
Packit 910689
#  endif
Packit 910689
Packit 910689
/* If any other headers are needed for fcntl or O_NODELAY, they need to get
Packit 910689
   included right here */
Packit 910689
Packit 910689
#  if !defined(O_NODELAY)
Packit 910689
#   if !defined(FNDELAY)
Packit 910689
#    undef Have_nodelay
Packit 910689
#   else
Packit 910689
#    define O_NODELAY FNDELAY
Packit 910689
#   endif
Packit 910689
#  else
Packit 910689
#   define O_NODELAY O_NDELAY
Packit 910689
#  endif
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
Packit 910689
#if !defined(DONT_USE_SELECT)
Packit 910689
# ifdef HAS_SELECT
Packit 910689
#  ifdef I_SYS_SELECT
Packit 910689
#   include <sys/select.h>
Packit 910689
#  endif
Packit 910689
Packit 910689
/* If any other headers are likely to be needed for select, they need to be
Packit 910689
   included right here */
Packit 910689
Packit 910689
#  define Have_select
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
Packit 910689
#if !defined(DONT_USE_POLL)
Packit 910689
# ifdef HAS_POLL
Packit 910689
#  ifdef HAVE_POLL_H
Packit 910689
#   include <poll.h>
Packit 910689
#   define Have_poll
Packit 910689
#  endif
Packit 910689
#  ifdef HAVE_SYS_POLL_H
Packit 910689
#   include <sys/poll.h>
Packit 910689
#   define Have_poll
Packit 910689
#  endif
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
Packit 910689
#ifdef DONT_USE_TERMIOS
Packit 910689
# ifdef I_TERMIOS
Packit 910689
#  undef I_TERMIOS
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
#ifdef DONT_USE_TERMIO
Packit 910689
# ifdef I_TERMIO
Packit 910689
#  undef I_TERMIO
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
#ifdef DONT_USE_SGTTY
Packit 910689
# ifdef I_SGTTY
Packit 910689
#  undef I_SGTTY
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
Packit 910689
/* Pre-POSIX SVR3 systems sometimes define struct winsize in
Packit 910689
   sys/ptem.h.  However, sys/ptem.h needs a type mblk_t (?) which
Packit 910689
   is defined in <sys/stream.h>.
Packit 910689
   No, Configure (dist3.051) doesn't know how to check for this.
Packit 910689
*/
Packit 910689
#ifdef I_SYS_STREAM
Packit 910689
# include <sys/stream.h>
Packit 910689
#endif
Packit 910689
#ifdef I_SYS_PTEM
Packit 910689
# include <sys/ptem.h>
Packit 910689
#endif
Packit 910689
Packit 910689
#ifdef I_TERMIOS
Packit 910689
# include <termios.h>
Packit 910689
#else
Packit 910689
# ifdef I_TERMIO
Packit 910689
#  include <termio.h>
Packit 910689
# else
Packit 910689
#  ifdef I_SGTTY
Packit 910689
#   include <sgtty.h>
Packit 910689
#  endif
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
Packit 910689
#ifdef I_TERMIOS
Packit 910689
# define CC_TERMIOS
Packit 910689
#else
Packit 910689
# ifdef I_TERMIO
Packit 910689
#  define CC_TERMIO
Packit 910689
# else
Packit 910689
#  ifdef I_SGTTY
Packit 910689
#   define CC_SGTTY
Packit 910689
#  endif
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
Packit 910689
#ifndef TRK_IDEFAULT
Packit 910689
/* This flag should be off in the lflags when we enable termio mode */
Packit 910689
#      define TRK_IDEFAULT     0
Packit 910689
#endif
Packit 910689
Packit 910689
/* Fix up the disappearance of the '_' macro in Perl 5.7.2 */
Packit 910689
Packit 910689
#ifndef _
Packit 910689
#  ifdef CAN_PROTOTYPE
Packit 910689
#    define _(args) args
Packit 910689
#  else
Packit 910689
#    define _(args) ()
Packit 910689
#  endif
Packit 910689
#endif
Packit 910689
Packit 910689
#define DisableFlush (1) /* Should flushing mode changes be enabled?
Packit 910689
		            I think not for now. */
Packit 910689
Packit 910689
Packit 910689
#define STDIN PerlIO_stdin()
Packit 910689
Packit 910689
#include "cchars.h"
Packit 910689
Packit 910689
Packit 910689
STATIC int GetTermSizeVIO _((pTHX_ PerlIO * file,
Packit 910689
	int * retwidth, int * retheight, 
Packit 910689
	int * xpix, int * ypix));
Packit 910689
Packit 910689
STATIC int GetTermSizeGWINSZ _((pTHX_ PerlIO * file,
Packit 910689
	int * retwidth, int * retheight, 
Packit 910689
	int * xpix, int * ypix));
Packit 910689
Packit 910689
STATIC int GetTermSizeGSIZE _((pTHX_ PerlIO * file,
Packit 910689
	int * retwidth, int * retheight, 
Packit 910689
	int * xpix, int * ypix));
Packit 910689
Packit 910689
STATIC int GetTermSizeWin32 _((pTHX_ PerlIO * file,
Packit 910689
	int * retwidth, int * retheight,
Packit 910689
	int * xpix, int * ypix));
Packit 910689
Packit 910689
STATIC int SetTerminalSize _((pTHX_ PerlIO * file,
Packit 910689
	int width, int height, 
Packit 910689
	int xpix, int ypix));
Packit 910689
Packit 910689
STATIC void ReadMode _((pTHX_ PerlIO * file,int mode));
Packit 910689
Packit 910689
STATIC int pollfile _((pTHX_ PerlIO * file, double delay));
Packit 910689
Packit 910689
STATIC int setnodelay _((pTHX_ PerlIO * file, int mode));
Packit 910689
Packit 910689
STATIC int selectfile _((pTHX_ PerlIO * file, double delay));
Packit 910689
Packit 910689
STATIC int Win32PeekChar _((pTHX_ PerlIO * file, U32 delay, char * key));
Packit 910689
Packit 910689
STATIC int getspeed _((pTHX_ PerlIO * file, I32 *in, I32 * out ));
Packit 910689
Packit 910689
Packit 910689
#ifdef VIOMODE
Packit 910689
int GetTermSizeVIO(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
Packit 910689
{
Packit 910689
	/*int handle=PerlIO_fileno(file);
Packit 910689
Packit 910689
        static VIOMODEINFO *modeinfo = NULL;
Packit 910689
Packit 910689
        if (modeinfo == NULL)
Packit 910689
                modeinfo = (VIOMODEINFO *)malloc(sizeof(VIOMODEINFO));
Packit 910689
Packit 910689
        VioGetMode(modeinfo,0);
Packit 910689
        *retheight = modeinfo->row ?: 25;
Packit 910689
        *retwidth = modeinfo->col ?: 80;*/
Packit 910689
	int buf[2];
Packit 910689
Packit 910689
	_scrsize(&buf[0]);
Packit 910689
Packit 910689
	*retwidth = buf[0]; *retheight = buf[1];
Packit 910689
Packit 910689
        *xpix = *ypix = 0;
Packit 910689
        return 0;
Packit 910689
}
Packit 910689
#else
Packit 910689
int GetTermSizeVIO(pTHX_ PerlIO *file,int * retwidth,int *retheight, int *xpix,int *ypix)
Packit 910689
{
Packit 910689
	croak("TermSizeVIO is not implemented on this architecture");
Packit 910689
        return 0;
Packit 910689
}
Packit 910689
#endif
Packit 910689
Packit 910689
Packit 910689
#if defined(TIOCGWINSZ) && !defined(DONT_USE_GWINSZ)
Packit 910689
int GetTermSizeGWINSZ(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
Packit 910689
{
Packit 910689
	int handle=PerlIO_fileno(file);
Packit 910689
	struct winsize w;
Packit 910689
Packit 910689
	if (ioctl (handle, TIOCGWINSZ, &w) == 0) {
Packit 910689
		*retwidth=w.ws_col; *retheight=w.ws_row; 
Packit 910689
		*xpix=w.ws_xpixel; *ypix=w.ws_ypixel; return 0;
Packit 910689
	}
Packit 910689
	else {
Packit 910689
		return -1; /* failure */
Packit 910689
	}
Packit 910689
Packit 910689
}
Packit 910689
#else
Packit 910689
int GetTermSizeGWINSZ(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
Packit 910689
{
Packit 910689
	croak("TermSizeGWINSZ is not implemented on this architecture");
Packit 910689
        return 0;
Packit 910689
}
Packit 910689
#endif
Packit 910689
Packit 910689
#if (!defined(TIOCGWINSZ) || defined(DONT_USE_GWINSZ)) && (defined(TIOCGSIZE) && !defined(DONT_USE_GSIZE))
Packit 910689
int GetTermSizeGSIZE(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
Packit 910689
{
Packit 910689
	int handle=PerlIO_fileno(file);
Packit 910689
Packit 910689
	struct ttysize w;
Packit 910689
Packit 910689
	if (ioctl (handle, TIOCGSIZE, &w) == 0) {
Packit 910689
		*retwidth=w.ts_cols; *retheight=w.ts_lines; 
Packit 910689
		*xpix=0/*w.ts_xxx*/; *ypix=0/*w.ts_yyy*/; return 0;
Packit 910689
	}
Packit 910689
	else {
Packit 910689
		return -1; /* failure */
Packit 910689
	}
Packit 910689
}
Packit 910689
#else
Packit 910689
int GetTermSizeGSIZE(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
Packit 910689
{
Packit 910689
	croak("TermSizeGSIZE is not implemented on this architecture");
Packit 910689
        return 0;
Packit 910689
}
Packit 910689
#endif
Packit 910689
Packit 910689
#ifdef USE_WIN32
Packit 910689
int GetTermSizeWin32(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
Packit 910689
{
Packit 910689
	int handle=PerlIO_fileno(file);
Packit 910689
	HANDLE whnd = (HANDLE)_get_osfhandle(handle);
Packit 910689
	CONSOLE_SCREEN_BUFFER_INFO info;
Packit 910689
Packit 910689
	if (GetConsoleScreenBufferInfo(whnd, &info)) {
Packit 910689
		/* Logic: return maximum possible screen width, but return
Packit 910689
		   only currently selected height */
Packit 910689
		if (retwidth)
Packit 910689
			*retwidth = info.dwMaximumWindowSize.X; 
Packit 910689
			/*info.srWindow.Right - info.srWindow.Left;*/
Packit 910689
		if (retheight)
Packit 910689
			*retheight = info.srWindow.Bottom - info.srWindow.Top;
Packit 910689
		if (xpix)
Packit 910689
			*xpix = 0;
Packit 910689
		if (ypix)
Packit 910689
			*ypix = 0;
Packit 910689
		return 0;
Packit 910689
	} else
Packit 910689
		return -1;
Packit 910689
}
Packit 910689
#else
Packit 910689
int GetTermSizeWin32(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
Packit 910689
{
Packit 910689
	croak("TermSizeWin32 is not implemented on this architecture");
Packit 910689
        return 0;
Packit 910689
}
Packit 910689
#endif /* USE_WIN32 */
Packit 910689
Packit 910689
Packit 910689
STATIC int termsizeoptions() {
Packit 910689
	return	0
Packit 910689
#ifdef VIOMODE
Packit 910689
		| 1
Packit 910689
#endif
Packit 910689
#if defined(TIOCGWINSZ) && !defined(DONT_USE_GWINSZ)
Packit 910689
		| 2
Packit 910689
#endif
Packit 910689
#if defined(TIOCGSIZE) && !defined(DONT_USE_GSIZE)
Packit 910689
		| 4
Packit 910689
#endif
Packit 910689
#if defined(USE_WIN32)
Packit 910689
		| 8
Packit 910689
#endif
Packit 910689
		;
Packit 910689
}
Packit 910689
Packit 910689
Packit 910689
int SetTerminalSize(pTHX_ PerlIO *file,int width,int height,int xpix,int ypix)
Packit 910689
{
Packit 910689
	int handle=PerlIO_fileno(file);
Packit 910689
Packit 910689
#ifdef VIOMODE
Packit 910689
        return -1;
Packit 910689
#else
Packit 910689
Packit 910689
#if defined(TIOCSWINSZ) && !defined(DONT_USE_SWINSZ)
Packit 910689
	char buffer[10];
Packit 910689
	struct winsize w;
Packit 910689
Packit 910689
	w.ws_col=width;
Packit 910689
	w.ws_row=height;
Packit 910689
	w.ws_xpixel=xpix;
Packit 910689
	w.ws_ypixel=ypix;
Packit 910689
	if (ioctl (handle, TIOCSWINSZ, &w) == 0) {
Packit 910689
		sprintf(buffer,"%d",width); /* Be polite to our children */
Packit 910689
		my_setenv("COLUMNS",buffer);
Packit 910689
		sprintf(buffer,"%d",height);
Packit 910689
		my_setenv("LINES",buffer);
Packit 910689
		return 0;
Packit 910689
	}
Packit 910689
	else {
Packit 910689
		croak("TIOCSWINSZ ioctl call to set terminal size failed: %s",Strerror(errno));
Packit 910689
		return -1;
Packit 910689
	}
Packit 910689
#else
Packit 910689
# if defined(TIOCSSIZE) && !defined(DONT_USE_SSIZE)
Packit 910689
	char buffer[10];
Packit 910689
	struct ttysize w;
Packit 910689
Packit 910689
	w.ts_lines=height;
Packit 910689
	w.ts_cols=width;
Packit 910689
	w.ts_xxx=xpix;
Packit 910689
	w.ts_yyy=ypix;
Packit 910689
	if (ioctl (handle, TIOCSSIZE, &w) == 0) {
Packit 910689
		sprintf(buffer,"%d",width);
Packit 910689
		my_setenv("COLUMNS",buffer);
Packit 910689
		sprintf(buffer,"%d",height);
Packit 910689
		my_setenv("LINES",buffer);
Packit 910689
		return 0;
Packit 910689
	}
Packit 910689
	else {
Packit 910689
		croak("TIOCSSIZE ioctl call to set terminal size failed: %s",Strerror(errno));
Packit 910689
		return -1;
Packit 910689
	}
Packit 910689
# else
Packit 910689
	/*sprintf(buffer,"%d",width)   * Should we could do this and then *
Packit 910689
	my_setenv("COLUMNS",buffer)    * said we succeeded?               *
Packit 910689
	sprintf(buffer,"%d",height);
Packit 910689
	my_setenv("LINES",buffer)*/
Packit 910689
Packit 910689
	return -1; /* Fail */
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
#endif
Packit 910689
Packit 910689
}
Packit 910689
Packit 910689
STATIC const I32 terminal_speeds[] = {
Packit 910689
#ifdef B50
Packit 910689
	50, B50,
Packit 910689
#endif
Packit 910689
#ifdef B75
Packit 910689
	75, B75,
Packit 910689
#endif
Packit 910689
#ifdef B110
Packit 910689
	110, B110,
Packit 910689
#endif
Packit 910689
#ifdef B134
Packit 910689
	134, B134,
Packit 910689
#endif
Packit 910689
#ifdef B150
Packit 910689
	150, B150,
Packit 910689
#endif
Packit 910689
#ifdef B200
Packit 910689
	200, B200,
Packit 910689
#endif
Packit 910689
#ifdef B300
Packit 910689
	300, B300,
Packit 910689
#endif
Packit 910689
#ifdef B600
Packit 910689
	600, B600,
Packit 910689
#endif
Packit 910689
#ifdef B1200
Packit 910689
	1200, B1200,
Packit 910689
#endif
Packit 910689
#ifdef B1800
Packit 910689
	1800, B1800,
Packit 910689
#endif
Packit 910689
#ifdef B2400
Packit 910689
	2400, B2400,
Packit 910689
#endif
Packit 910689
#ifdef B4800
Packit 910689
	4800, B4800,
Packit 910689
#endif
Packit 910689
#ifdef B9600
Packit 910689
	9600, B9600,
Packit 910689
#endif
Packit 910689
#ifdef B19200
Packit 910689
	19200, B19200,
Packit 910689
#endif
Packit 910689
#ifdef B38400
Packit 910689
	38400, B38400,
Packit 910689
#endif
Packit 910689
#ifdef B57600
Packit 910689
	57600, B57600,
Packit 910689
#endif
Packit 910689
#ifdef B115200
Packit 910689
	115200, B115200,
Packit 910689
#endif
Packit 910689
#ifdef EXTA
Packit 910689
	19200, EXTA,
Packit 910689
#endif
Packit 910689
#ifdef EXTB
Packit 910689
	38400, EXTB,
Packit 910689
#endif
Packit 910689
#ifdef B0
Packit 910689
	0,  B0,
Packit 910689
#endif
Packit 910689
	-1,-1
Packit 910689
};
Packit 910689
Packit 910689
int getspeed(pTHX_ PerlIO *file,I32 *in, I32 *out)
Packit 910689
{
Packit 910689
	int handle=PerlIO_fileno(file);
Packit 910689
#if defined(I_TERMIOS) || defined(I_TERMIO) || defined(I_SGTTY)
Packit 910689
	int i;
Packit 910689
#endif
Packit 910689
#       ifdef I_TERMIOS
Packit 910689
	/* Posixy stuff */
Packit 910689
Packit 910689
	struct termios buf;
Packit 910689
	tcgetattr(handle,&buf;;
Packit 910689
Packit 910689
	*in = *out = -1;
Packit 910689
	*in = cfgetispeed(&buf;;
Packit 910689
	*out = cfgetospeed(&buf;;
Packit 910689
	for(i=0;terminal_speeds[i]!=-1;i+=2) {
Packit 910689
		if(*in == terminal_speeds[i+1])
Packit 910689
			{ *in = terminal_speeds[i]; break; }
Packit 910689
	}
Packit 910689
	for(i=0;terminal_speeds[i]!=-1;i+=2) {
Packit 910689
		if(*out == terminal_speeds[i+1])
Packit 910689
			{ *out = terminal_speeds[i]; break; }
Packit 910689
	}
Packit 910689
	return 0;	 	
Packit 910689
Packit 910689
#       else
Packit 910689
#        ifdef I_TERMIO
Packit 910689
	 /* SysV stuff */
Packit 910689
	 struct termio buf;
Packit 910689
Packit 910689
	 ioctl(handle,TCGETA,&buf;;
Packit 910689
Packit 910689
	*in=*out=-1;
Packit 910689
	for(i=0;terminal_speeds[i]!=-1;i+=2) {
Packit 910689
		if((buf.c_cflag & CBAUD) == terminal_speeds[i+1])
Packit 910689
			{ *in=*out=terminal_speeds[i]; break; }
Packit 910689
	}
Packit 910689
	return 0;	 	
Packit 910689
Packit 910689
#        else
Packit 910689
#         ifdef I_SGTTY
Packit 910689
	  /* BSD stuff */
Packit 910689
	  struct sgttyb buf;
Packit 910689
Packit 910689
	  ioctl(handle,TIOCGETP,&buf;;
Packit 910689
Packit 910689
	*in=*out=-1;
Packit 910689
Packit 910689
	for(i=0;terminal_speeds[i]!=-1;i+=2) 
Packit 910689
		if(buf.sg_ospeed == terminal_speeds[i+1])
Packit 910689
			{ *out = terminal_speeds[i]; break; }
Packit 910689
Packit 910689
	for(i=0;terminal_speeds[i]!=-1;i+=2) 
Packit 910689
		if(buf.sg_ispeed == terminal_speeds[i+1])
Packit 910689
			{ *in = terminal_speeds[i]; break; }
Packit 910689
Packit 910689
	return 0;	 	
Packit 910689
Packit 910689
Packit 910689
#         else
Packit 910689
Packit 910689
	   /* No termio, termios or sgtty. I suppose we can try stty,
Packit 910689
	      but it would be nice if you could get a better OS */
Packit 910689
Packit 910689
	return -1;
Packit 910689
Packit 910689
#         endif
Packit 910689
#        endif
Packit 910689
#       endif
Packit 910689
}
Packit 910689
Packit 910689
#ifdef WIN32
Packit 910689
struct tbuffer { DWORD Mode; };
Packit 910689
#else
Packit 910689
#ifdef I_TERMIOS
Packit 910689
#define USE_TERMIOS
Packit 910689
#define tbuffer termios
Packit 910689
#else
Packit 910689
#ifdef I_TERMIO
Packit 910689
#define USE_TERMIO
Packit 910689
#define tbuffer termio
Packit 910689
#else
Packit 910689
#ifdef I_SGTTY
Packit 910689
#define USE_SGTTY
Packit 910689
struct tbuffer {
Packit 910689
	  struct sgttyb buf;
Packit 910689
#if defined(TIOCGETC)
Packit 910689
	  struct tchars tchar;
Packit 910689
#endif
Packit 910689
#if defined(TIOCGLTC)
Packit 910689
	  struct ltchars ltchar;
Packit 910689
#endif
Packit 910689
#if defined(TIOCLGET)
Packit 910689
	  int local;
Packit 910689
#endif
Packit 910689
};
Packit 910689
#else
Packit 910689
#define USE_STTY
Packit 910689
struct tbuffer {
Packit 910689
	int dummy;
Packit 910689
};
Packit 910689
#endif
Packit 910689
#endif
Packit 910689
#endif
Packit 910689
#endif
Packit 910689
Packit 910689
static HV * filehash; /* Used to store the original terminal settings for each handle*/
Packit 910689
static HV * modehash; /* Used to record the current terminal "mode" for each handle*/
Packit 910689
Packit 910689
void ReadMode(pTHX_ PerlIO *file,int mode)
Packit 910689
{
Packit 910689
	dTHR;
Packit 910689
	int handle;
Packit 910689
	int firsttime;
Packit 910689
	int oldmode;
Packit 910689
	struct tbuffer work;
Packit 910689
	struct tbuffer	savebuf;
Packit 910689
Packit 910689
	
Packit 910689
	handle=PerlIO_fileno(file);
Packit 910689
	
Packit 910689
	firsttime=!hv_exists(filehash, (char*)&handle, sizeof(int));
Packit 910689
Packit 910689
Packit 910689
#	ifdef WIN32
Packit 910689
Packit 910689
	if (!GetConsoleMode((HANDLE)_get_osfhandle(handle), &work.Mode))
Packit 910689
	    croak("GetConsoleMode failed, LastError=|%d|",GetLastError());
Packit 910689
Packit 910689
#	endif /* WIN32 */
Packit 910689
Packit 910689
#       ifdef USE_TERMIOS
Packit 910689
	/* Posixy stuff */
Packit 910689
	
Packit 910689
	tcgetattr(handle,&work);
Packit 910689
Packit 910689
Packit 910689
Packit 910689
#endif
Packit 910689
#ifdef USE_TERMIO
Packit 910689
	 /* SysV stuff */
Packit 910689
Packit 910689
	 ioctl(handle,TCGETA,&work);
Packit 910689
Packit 910689
Packit 910689
#endif
Packit 910689
#ifdef USE_SGTTY
Packit 910689
	  /* BSD stuff */
Packit 910689
Packit 910689
	  ioctl(handle,TIOCGETP,&work.buf);
Packit 910689
# 	  if defined(TIOCGETC)
Packit 910689
	   ioctl(handle,TIOCGETC,&work.tchar);
Packit 910689
#	  endif
Packit 910689
#         if defined(TIOCLGET)
Packit 910689
	   ioctl(handle,TIOCLGET,&work.local);
Packit 910689
#	  endif
Packit 910689
#	  if defined(TIOCGLTC)
Packit 910689
	   ioctl(handle,TIOCGLTC,&work.ltchar);
Packit 910689
#	  endif
Packit 910689
Packit 910689
Packit 910689
#endif
Packit 910689
Packit 910689
Packit 910689
	if(firsttime) {
Packit 910689
		firsttime=0; 
Packit 910689
		memcpy((void*)&savebuf,(void*)&work,sizeof(struct tbuffer));
Packit 910689
		if(!hv_store(filehash,(char*)&handle,sizeof(int),
Packit 910689
			newSVpv((char*)&savebuf,sizeof(struct tbuffer)),0))
Packit 910689
			croak("Unable to stash terminal settings.\n");
Packit 910689
		if(!hv_store(modehash,(char*)&handle,sizeof(int),newSViv(0),0))
Packit 910689
			croak("Unable to stash terminal settings.\n");
Packit 910689
	} else {
Packit 910689
		SV ** temp;
Packit 910689
		if(!(temp=hv_fetch(filehash,(char*)&handle,sizeof(int),0))) 
Packit 910689
			croak("Unable to retrieve stashed terminal settings.\n");
Packit 910689
		memcpy(&savebuf,SvPV(*temp,PL_na),sizeof(struct tbuffer));
Packit 910689
		if(!(temp=hv_fetch(modehash,(char*)&handle,sizeof(int),0))) 
Packit 910689
			croak("Unable to retrieve stashed terminal mode.\n");
Packit 910689
		oldmode=SvIV(*temp);
Packit 910689
	}
Packit 910689
Packit 910689
#ifdef WIN32
Packit 910689
Packit 910689
	switch (mode) {
Packit 910689
		case 5:
Packit 910689
			/* Should 5 disable ENABLE_WRAP_AT_EOL_OUTPUT? */
Packit 910689
		case 4:
Packit 910689
			work.Mode &= ~(ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_OUTPUT);
Packit 910689
			work.Mode |= 0;
Packit 910689
			break;
Packit 910689
		case 3:
Packit 910689
			work.Mode &= ~(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT);
Packit 910689
			work.Mode |= ENABLE_PROCESSED_INPUT|ENABLE_PROCESSED_OUTPUT;
Packit 910689
			break;
Packit 910689
		case 2:
Packit 910689
			work.Mode &= ~(ENABLE_ECHO_INPUT);
Packit 910689
			work.Mode |= ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_PROCESSED_OUTPUT;
Packit 910689
			break;
Packit 910689
		case 1:
Packit 910689
			work.Mode &= ~(0);
Packit 910689
			work.Mode |= ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_PROCESSED_OUTPUT;
Packit 910689
			break;
Packit 910689
		case 0:
Packit 910689
			work = savebuf;
Packit 910689
			firsttime = 1;
Packit 910689
			break;
Packit 910689
	}
Packit 910689
Packit 910689
	if (!SetConsoleMode((HANDLE)_get_osfhandle(handle), work.Mode))
Packit 910689
	    croak("SetConsoleMode failed, LastError=|%d|",GetLastError());
Packit 910689
Packit 910689
#endif /* WIN32 */
Packit 910689
Packit 910689
Packit 910689
#ifdef USE_TERMIOS
Packit 910689
Packit 910689
Packit 910689
/* What, me worry about standards? */
Packit 910689
Packit 910689
#       if !defined (VMIN)
Packit 910689
#		define VMIN VEOF
Packit 910689
#       endif
Packit 910689
Packit 910689
#	if !defined (VTIME)
Packit 910689
#		define VTIME VEOL
Packit 910689
#	endif
Packit 910689
Packit 910689
#	if !defined (IXANY)
Packit 910689
#		define IXANY (0)
Packit 910689
#	endif
Packit 910689
Packit 910689
#ifndef IEXTEN
Packit 910689
#ifdef IDEFAULT
Packit 910689
#define IEXTEN IDEFAULT
Packit 910689
#endif
Packit 910689
#endif
Packit 910689
Packit 910689
/* XXX Is ONLCR in POSIX?.  The value of '4' seems to be the same for
Packit 910689
   both SysV and Sun, so it's probably rather general, and I'm not
Packit 910689
   aware of a POSIX way to do this otherwise.
Packit 910689
*/
Packit 910689
#ifndef ONLCR
Packit 910689
# define ONLCR 4
Packit 910689
#endif
Packit 910689
Packit 910689
#ifndef IMAXBEL
Packit 910689
#define IMAXBEL 0
Packit 910689
#endif
Packit 910689
#ifndef ECHOE
Packit 910689
#define ECHOE 0
Packit 910689
#endif
Packit 910689
#ifndef ECHOK
Packit 910689
#define ECHOK 0
Packit 910689
#endif
Packit 910689
#ifndef ECHONL
Packit 910689
#define ECHONL 0
Packit 910689
#endif 
Packit 910689
#ifndef ECHOPRT
Packit 910689
#define ECHOPRT 0
Packit 910689
#endif
Packit 910689
#ifndef FLUSHO
Packit 910689
#define FLUSHO 0
Packit 910689
#endif
Packit 910689
#ifndef PENDIN
Packit 910689
#define PENDIN 0
Packit 910689
#endif
Packit 910689
#ifndef ECHOKE
Packit 910689
#define ECHOKE 0
Packit 910689
#endif
Packit 910689
#ifndef ONLCR
Packit 910689
#define ONLCR 0
Packit 910689
#endif
Packit 910689
#ifndef OCRNL
Packit 910689
#define OCRNL 0
Packit 910689
#endif
Packit 910689
#ifndef ONLRET
Packit 910689
#define ONLRET 0
Packit 910689
#endif
Packit 910689
#ifndef IUCLC
Packit 910689
#define IUCLC 0
Packit 910689
#endif
Packit 910689
#ifndef OPOST
Packit 910689
#define OPOST 0
Packit 910689
#endif
Packit 910689
#ifndef OLCUC
Packit 910689
#define OLCUC 0
Packit 910689
#endif
Packit 910689
#ifndef ECHOCTL
Packit 910689
#define ECHOCTL 0
Packit 910689
#endif
Packit 910689
#ifndef XCASE
Packit 910689
#define XCASE 0
Packit 910689
#endif
Packit 910689
#ifndef BRKINT
Packit 910689
#define BRKINT 0
Packit 910689
#endif
Packit 910689
Packit 910689
Packit 910689
	if(mode==5) {
Packit 910689
		/*\
Packit 910689
		 *  Disable everything except parity if needed.
Packit 910689
		\*/
Packit 910689
Packit 910689
		/* Hopefully, this should put the tty into unbuffered mode
Packit 910689
		with signals and control characters (both posixy and normal)
Packit 910689
		disabled, along with flow control. Echo should be off.
Packit 910689
		CR/LF is not translated, along with 8-bit/parity */
Packit 910689
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
Packit 910689
		work.c_lflag &= ~(ICANON|ISIG|IEXTEN );
Packit 910689
		work.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ECHOCTL);
Packit 910689
		work.c_lflag &= ~(ECHOPRT|ECHOKE|FLUSHO|PENDIN|XCASE);
Packit 910689
		work.c_lflag |= NOFLSH;
Packit 910689
        work.c_iflag &= ~(IXOFF|IXON|IXANY|ICRNL|IMAXBEL|BRKINT);
Packit 910689
Packit 910689
		if(((work.c_iflag & INPCK) != INPCK) ||
Packit 910689
                   ((work.c_cflag & PARENB) != PARENB)) {
Packit 910689
			work.c_iflag &= ~ISTRIP;
Packit 910689
			work.c_iflag |= IGNPAR;
Packit 910689
			work.c_iflag &= ~PARMRK;
Packit 910689
		} 
Packit 910689
		work.c_oflag &= ~(OPOST |ONLCR|OCRNL|ONLRET);
Packit 910689
Packit 910689
		work.c_cc[VTIME] = 0;
Packit 910689
		work.c_cc[VMIN] = 1;
Packit 910689
	}
Packit 910689
	else if(mode==4) {
Packit 910689
		/* Hopefully, this should put the tty into unbuffered mode
Packit 910689
		with signals and control characters (both posixy and normal)
Packit 910689
		disabled, along with flow control. Echo should be off.
Packit 910689
		About the only thing left unchanged is 8-bit/parity */
Packit 910689
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
Packit 910689
		/*work.c_iflag = savebuf.c_iflag;*/
Packit 910689
		work.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO);
Packit 910689
		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
Packit 910689
        work.c_iflag &= ~(IXON | IXANY | BRKINT);
Packit 910689
		work.c_oflag = savebuf.c_oflag;
Packit 910689
		work.c_cc[VTIME] = 0;
Packit 910689
		work.c_cc[VMIN] = 1;
Packit 910689
	}
Packit 910689
	else if(mode==3)
Packit 910689
	{
Packit 910689
		/* This should be an unbuffered mode with signals and control	
Packit 910689
		characters enabled, as should be flow control. Echo should
Packit 910689
		still be off */
Packit 910689
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
Packit 910689
		work.c_iflag = savebuf.c_iflag;
Packit 910689
		work.c_lflag &= ~(ICANON | ECHO);
Packit 910689
		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
Packit 910689
		work.c_lflag |= ISIG | IEXTEN;
Packit 910689
		/*work.c_iflag &= ~(IXON | IXOFF | IXANY);
Packit 910689
		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
Packit 910689
		work.c_oflag = savebuf.c_oflag;*/
Packit 910689
		work.c_cc[VTIME] = 0;
Packit 910689
		work.c_cc[VMIN] = 1;
Packit 910689
	}
Packit 910689
	else if(mode==2)
Packit 910689
	{
Packit 910689
		/* This should be an unbuffered mode with signals and control	
Packit 910689
		characters enabled, as should be flow control. Echo should
Packit 910689
		still be off */
Packit 910689
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
Packit 910689
		work.c_iflag = savebuf.c_iflag;
Packit 910689
		work.c_lflag |= ICANON|ISIG|IEXTEN;
Packit 910689
		work.c_lflag &= ~ECHO;
Packit 910689
		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
Packit 910689
		/*work.c_iflag &= ~(IXON |IXOFF|IXANY);
Packit 910689
		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
Packit 910689
		work.c_oflag = savebuf.c_oflag;
Packit 910689
		work.c_cc[VTIME] = savebuf.c_cc[VTIME];
Packit 910689
		work.c_cc[VMIN] = savebuf.c_cc[VMIN];*/
Packit 910689
	}
Packit 910689
	else if(mode==1)
Packit 910689
	{
Packit 910689
		/* This should be an unbuffered mode with signals and control	
Packit 910689
		characters enabled, as should be flow control. Echo should
Packit 910689
		still be off */
Packit 910689
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
Packit 910689
		work.c_iflag = savebuf.c_iflag;
Packit 910689
		work.c_lflag |= ICANON|ECHO|ISIG|IEXTEN;
Packit 910689
		/*work.c_iflag &= ~(IXON |IXOFF|IXANY);
Packit 910689
		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
Packit 910689
		work.c_oflag = savebuf.c_oflag;
Packit 910689
		work.c_cc[VTIME] = savebuf.c_cc[VTIME];
Packit 910689
		work.c_cc[VMIN] = savebuf.c_cc[VMIN];*/
Packit 910689
	}
Packit 910689
	else if(mode==0){
Packit 910689
		/*work.c_lflag &= ~BITMASK; 
Packit 910689
		work.c_lflag |= savebuf.c_lflag & BITMASK;
Packit 910689
		work.c_oflag = savebuf.c_oflag;
Packit 910689
		work.c_cc[VTIME] = savebuf.c_cc[VTIME];
Packit 910689
		work.c_cc[VMIN] = savebuf.c_cc[VMIN];
Packit 910689
		work.c_iflag = savebuf.c_iflag;
Packit 910689
		work.c_iflag &= ~(IXON|IXOFF|IXANY);
Packit 910689
		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);*/
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
		/*Copy(&work,&savebuf,1,sizeof(struct tbuffer));*/
Packit 910689
Packit 910689
		firsttime=1;
Packit 910689
	}	
Packit 910689
	else
Packit 910689
	{
Packit 910689
		croak("ReadMode %d is not implemented on this architecture.",mode);
Packit 910689
		return;		
Packit 910689
	}
Packit 910689
Packit 910689
Packit 910689
	/* If switching from a "lower power" mode to a higher one, keep the
Packit 910689
	data that may be in the queue, as it can easily be type-ahead. On
Packit 910689
	switching to a lower mode from a higher one, however, flush the queue
Packit 910689
	so that raw keystrokes won't hit an unexpecting program */
Packit 910689
	
Packit 910689
	if(DisableFlush || oldmode<=mode)
Packit 910689
		tcsetattr(handle,TCSANOW,&work);
Packit 910689
	else
Packit 910689
		tcsetattr(handle,TCSAFLUSH,&work);
Packit 910689
Packit 910689
	/*tcsetattr(handle,TCSANOW,&work);*/ /* It might be better to FLUSH
Packit 910689
					   when changing gears to a lower mode,
Packit 910689
					   and only use NOW for higher modes. 
Packit 910689
					*/
Packit 910689
Packit 910689
Packit 910689
#endif
Packit 910689
#ifdef USE_TERMIO
Packit 910689
Packit 910689
/* What, me worry about standards? */
Packit 910689
Packit 910689
#	 if !defined (IXANY)
Packit 910689
#                define IXANY (0)
Packit 910689
#        endif
Packit 910689
Packit 910689
#ifndef ECHOE
Packit 910689
#define ECHOE 0
Packit 910689
#endif
Packit 910689
#ifndef ECHOK
Packit 910689
#define ECHOK 0
Packit 910689
#endif
Packit 910689
#ifndef ECHONL
Packit 910689
#define ECHONL 0
Packit 910689
#endif
Packit 910689
#ifndef XCASE
Packit 910689
#define XCASE 0
Packit 910689
#endif
Packit 910689
#ifndef BRKINT
Packit 910689
#define BRKINT 0
Packit 910689
#endif
Packit 910689
Packit 910689
Packit 910689
Packit 910689
	 if(mode==5) {
Packit 910689
		/* This mode should be echo disabled, signals disabled,
Packit 910689
		flow control disabled, and unbuffered. CR/LF translation 
Packit 910689
   	 	is off, and 8 bits if possible */
Packit 910689
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
Packit 910689
		work.c_lflag &= ~(ECHO | ISIG | ICANON | XCASE);
Packit 910689
		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL | TRK_IDEFAULT);
Packit 910689
		work.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | BRKINT);
Packit 910689
		if((work.c_cflag | PARENB)!=PARENB ) {
Packit 910689
			work.c_iflag &= ~(ISTRIP|INPCK);
Packit 910689
			work.c_iflag |= IGNPAR;
Packit 910689
		} 
Packit 910689
		work.c_oflag &= ~(OPOST|ONLCR);
Packit 910689
		work.c_cc[VMIN] = 1;
Packit 910689
		work.c_cc[VTIME] = 1;
Packit 910689
	 } 
Packit 910689
	 else if(mode==4) {
Packit 910689
		/* This mode should be echo disabled, signals disabled,
Packit 910689
		flow control disabled, and unbuffered. Parity is not
Packit 910689
		touched. */
Packit 910689
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
Packit 910689
		work.c_lflag &= ~(ECHO | ISIG | ICANON);
Packit 910689
		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL TRK_IDEFAULT);
Packit 910689
		work.c_iflag = savebuf.c_iflag;
Packit 910689
		work.c_iflag &= ~(IXON | IXOFF | IXANY | BRKINT);
Packit 910689
		work.c_oflag = savebuf.c_oflag;
Packit 910689
		work.c_cc[VMIN] = 1;
Packit 910689
		work.c_cc[VTIME] = 1;
Packit 910689
	 } 
Packit 910689
	 else if(mode==3) {
Packit 910689
		/* This mode tries to have echo off, signals enabled,
Packit 910689
		flow control as per the original setting, and unbuffered. */
Packit 910689
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
Packit 910689
		work.c_lflag &= ~(ECHO | ICANON);
Packit 910689
		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL | TRK_IDEFAULT);
Packit 910689
		work.c_lflag |= ISIG;
Packit 910689
		work.c_iflag = savebuf.c_iflag;
Packit 910689
		work.c_iflag &= ~(IXON | IXOFF | IXANY);
Packit 910689
		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
Packit 910689
		work.c_oflag = savebuf.c_oflag;
Packit 910689
		work.c_cc[VMIN] = 1;
Packit 910689
		work.c_cc[VTIME] = 1;
Packit 910689
	 }
Packit 910689
	 else if(mode==2) {
Packit 910689
		/* This mode tries to set echo on, signals on, and buffering
Packit 910689
		on, with flow control set to whatever it was originally. */
Packit 910689
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
Packit 910689
		work.c_lflag |= (ISIG | ICANON);
Packit 910689
		work.c_lflag &= ~ECHO;
Packit 910689
		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL | TRK_IDEFAULT);
Packit 910689
		work.c_iflag = savebuf.c_iflag;
Packit 910689
		work.c_iflag &= ~(IXON | IXOFF | IXANY);
Packit 910689
		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
Packit 910689
		work.c_oflag = savebuf.c_oflag;
Packit 910689
		work.c_cc[VMIN] = savebuf.c_cc[VMIN];
Packit 910689
		work.c_cc[VTIME] = savebuf.c_cc[VTIME];
Packit 910689
		
Packit 910689
		/* This assumes turning ECHO and ICANON back on is
Packit 910689
		   sufficient to re-enable cooked mode. If this is a 
Packit 910689
		   problem, complain to me */
Packit 910689
Packit 910689
		/* What the heck. We're already saving the entire buf, so
Packit 910689
		I'm now going to reset VMIN and VTIME too. Hope this works 
Packit 910689
		properly */
Packit 910689
		
Packit 910689
	 } 
Packit 910689
	 else if(mode==1) {
Packit 910689
		/* This mode tries to set echo on, signals on, and buffering
Packit 910689
		on, with flow control set to whatever it was originally. */
Packit 910689
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
Packit 910689
		work.c_lflag |= (ECHO | ISIG | ICANON);
Packit 910689
      work.c_iflag &= ~TRK_IDEFAULT;
Packit 910689
		work.c_iflag = savebuf.c_iflag;
Packit 910689
		work.c_iflag &= ~(IXON | IXOFF | IXANY);
Packit 910689
		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
Packit 910689
		work.c_oflag = savebuf.c_oflag;
Packit 910689
		work.c_cc[VMIN] = savebuf.c_cc[VMIN];
Packit 910689
		work.c_cc[VTIME] = savebuf.c_cc[VTIME];
Packit 910689
		
Packit 910689
		/* This assumes turning ECHO and ICANON back on is
Packit 910689
		   sufficient to re-enable cooked mode. If this is a 
Packit 910689
		   problem, complain to me */
Packit 910689
Packit 910689
		/* What the heck. We're already saving the entire buf, so
Packit 910689
		I'm now going to reset VMIN and VTIME too. Hope this works 
Packit 910689
		properly */
Packit 910689
	}		
Packit 910689
	 else if(mode==0) {
Packit 910689
		/* Put things back the way they were */
Packit 910689
Packit 910689
		/*work.c_lflag = savebuf.c_lflag;
Packit 910689
		work.c_iflag = savebuf.c_iflag;
Packit 910689
		work.c_oflag = savebuf.c_oflag;
Packit 910689
		work.c_cc[VMIN] = savebuf.c_cc[VMIN];
Packit 910689
		work.c_cc[VTIME] = savebuf.c_cc[VTIME];*/
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
		firsttime=1;
Packit 910689
	 }
Packit 910689
 	 else
Packit 910689
 	 {
Packit 910689
		croak("ReadMode %d is not implemented on this architecture.",mode);
Packit 910689
		return;		
Packit 910689
	 }
Packit 910689
Packit 910689
Packit 910689
	 if(DisableFlush || oldmode<=mode) 
Packit 910689
		ioctl(handle,TCSETA,&work);
Packit 910689
	 else
Packit 910689
		ioctl(handle,TCSETAF,&work);
Packit 910689
Packit 910689
#endif
Packit 910689
#ifdef USE_SGTTY
Packit 910689
Packit 910689
Packit 910689
	  if(mode==5) {
Packit 910689
		/* Unbuffered, echo off, signals off, flow control off */
Packit 910689
		/* CR-CR/LF mode off too, and 8-bit path enabled. */
Packit 910689
#	 	if defined(TIOCLGET) && defined(LPASS8)
Packit 910689
		 if((work.buf.sg_flags & (EVENP|ODDP))==0 ||
Packit 910689
		    (work.buf.sg_flags & (EVENP|ODDP))==(EVENP|ODDP))
Packit 910689
		 	 work.local |= LPASS8; /* If parity isn't being used, use 8 bits */
Packit 910689
#		endif
Packit 910689
	  	work.buf.sg_flags &= ~(ECHO|CRMOD);
Packit 910689
	  	work.buf.sg_flags |= (RAW|CBREAK);
Packit 910689
# 	  	if defined(TIOCGETC)
Packit 910689
		 work.tchar.t_intrc = -1;
Packit 910689
		 work.tchar.t_quitc = -1;
Packit 910689
		 work.tchar.t_startc= -1;
Packit 910689
		 work.tchar.t_stopc = -1;
Packit 910689
		 work.tchar.t_eofc  = -1;
Packit 910689
		 work.tchar.t_brkc  = -1;
Packit 910689
#		endif
Packit 910689
#		if defined(TIOCGLTC)
Packit 910689
		 work.ltchar.t_suspc= -1;
Packit 910689
		 work.ltchar.t_dsuspc= -1;
Packit 910689
		 work.ltchar.t_rprntc= -1;
Packit 910689
		 work.ltchar.t_flushc= -1;
Packit 910689
		 work.ltchar.t_werasc= -1;
Packit 910689
		 work.ltchar.t_lnextc= -1;
Packit 910689
#		endif
Packit 910689
	  }
Packit 910689
	  else if(mode==4) {
Packit 910689
		/* Unbuffered, echo off, signals off, flow control off */
Packit 910689
	  	work.buf.sg_flags &= ~(ECHO|RAW);
Packit 910689
	  	work.buf.sg_flags |= (CBREAK|CRMOD);
Packit 910689
#	 	if defined(TIOCLGET)
Packit 910689
		 work.local=savebuf.local;
Packit 910689
#		endif
Packit 910689
# 	  	if defined(TIOCGETC)
Packit 910689
		 work.tchar.t_intrc = -1;
Packit 910689
		 work.tchar.t_quitc = -1;
Packit 910689
		 work.tchar.t_startc= -1;
Packit 910689
		 work.tchar.t_stopc = -1;
Packit 910689
		 work.tchar.t_eofc  = -1;
Packit 910689
		 work.tchar.t_brkc  = -1;
Packit 910689
#		endif
Packit 910689
#		if defined(TIOCGLTC)
Packit 910689
		 work.ltchar.t_suspc= -1;
Packit 910689
		 work.ltchar.t_dsuspc= -1;
Packit 910689
		 work.ltchar.t_rprntc= -1;
Packit 910689
		 work.ltchar.t_flushc= -1;
Packit 910689
		 work.ltchar.t_werasc= -1;
Packit 910689
		 work.ltchar.t_lnextc= -1;
Packit 910689
#		endif
Packit 910689
	  }
Packit 910689
	  else if(mode==3) {
Packit 910689
		/* Unbuffered, echo off, signals on, flow control on */
Packit 910689
		work.buf.sg_flags &= ~(RAW|ECHO);
Packit 910689
	  	work.buf.sg_flags |= CBREAK|CRMOD;
Packit 910689
#	 	if defined(TIOCLGET)
Packit 910689
		 work.local=savebuf.local;
Packit 910689
#		endif
Packit 910689
#		if defined(TIOCGLTC)
Packit 910689
		 work.tchar = savebuf.tchar;
Packit 910689
#		endif
Packit 910689
#		if defined(TIOCGLTC)
Packit 910689
		 work.ltchar = savebuf.ltchar;
Packit 910689
#		endif
Packit 910689
 	  }
Packit 910689
	  else if(mode==2) {
Packit 910689
		/* Buffered, echo on, signals on, flow control on */
Packit 910689
		work.buf.sg_flags &= ~(RAW|CBREAK);
Packit 910689
		work.buf.sg_flags |= CRMOD;
Packit 910689
		work.buf.sg_flags &= ~ECHO;
Packit 910689
#	 	if defined(TIOCLGET)
Packit 910689
		 work.local=savebuf.local;
Packit 910689
#		endif
Packit 910689
#		if defined(TIOCGLTC)
Packit 910689
		 work.tchar = savebuf.tchar;
Packit 910689
#		endif
Packit 910689
#		if defined(TIOCGLTC)
Packit 910689
		 work.ltchar = savebuf.ltchar;
Packit 910689
#		endif
Packit 910689
	  }
Packit 910689
	  else if(mode==1) {
Packit 910689
		/* Buffered, echo on, signals on, flow control on */
Packit 910689
		work.buf.sg_flags &= ~(RAW|CBREAK);
Packit 910689
		work.buf.sg_flags |= ECHO|CRMOD;
Packit 910689
#	 	if defined(TIOCLGET)
Packit 910689
		 work.local=savebuf.local;
Packit 910689
#		endif
Packit 910689
#		if defined(TIOCGLTC)
Packit 910689
		 work.tchar = savebuf.tchar;
Packit 910689
#		endif
Packit 910689
#		if defined(TIOCGLTC)
Packit 910689
		 work.ltchar = savebuf.ltchar;
Packit 910689
#		endif
Packit 910689
	  }
Packit 910689
	  else if(mode==0){
Packit 910689
		/* Original settings */
Packit 910689
#if 0
Packit 910689
		work.buf.sg_flags &= ~(RAW|CBREAK|ECHO|CRMOD);
Packit 910689
		work.buf.sg_flags |= savebuf.sg_flags & (RAW|CBREAK|ECHO|CRMOD);
Packit 910689
#	 	if defined(TIOCLGET)
Packit 910689
		 work.local=savebuf.local;
Packit 910689
#		endif
Packit 910689
#		if defined(TIOCGLTC)
Packit 910689
		 work.tchar = savebuf.tchar;
Packit 910689
#		endif
Packit 910689
#		if defined(TIOCGLTC)
Packit 910689
		 work.ltchar = savebuf.ltchar;
Packit 910689
#		endif
Packit 910689
#endif
Packit 910689
		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
Packit 910689
		firsttime=1;
Packit 910689
	  }
Packit 910689
 	  else
Packit 910689
 	  {
Packit 910689
		croak("ReadMode %d is not implemented on this architecture.",mode);
Packit 910689
		return;		
Packit 910689
	  }
Packit 910689
#if defined(TIOCLSET)
Packit 910689
	  ioctl(handle,TIOCLSET,&work.local);
Packit 910689
#endif
Packit 910689
#if defined(TIOCSETC)
Packit 910689
	  ioctl(handle,TIOCSETC,&work.tchar);
Packit 910689
#endif
Packit 910689
#	  if defined(TIOCGLTC)
Packit 910689
	   ioctl(handle,TIOCSLTC,&work.ltchar);
Packit 910689
#	  endif
Packit 910689
	  if(DisableFlush || oldmode<=mode)
Packit 910689
	  	ioctl(handle,TIOCSETN,&work.buf);
Packit 910689
	  else
Packit 910689
		ioctl(handle,TIOCSETP,&work.buf);
Packit 910689
#endif
Packit 910689
#ifdef USE_STTY
Packit 910689
Packit 910689
	   /* No termio, termios or sgtty. I suppose we can try stty,
Packit 910689
	      but it would be nice if you could get a better OS */
Packit 910689
Packit 910689
	   if(mode==5)
Packit 910689
		system("/bin/stty  raw -cbreak -isig -echo -ixon -onlcr -icrnl -brkint");
Packit 910689
	   else if(mode==4)
Packit 910689
		system("/bin/stty -raw  cbreak -isig -echo -ixon  onlcr  icrnl -brkint");
Packit 910689
	   else if(mode==3)
Packit 910689
		system("/bin/stty -raw  cbreak  isig -echo  ixon  onlcr  icrnl  brkint");
Packit 910689
	   else if(mode==2) 
Packit 910689
		system("/bin/stty -raw -cbreak  isig  echo  ixon  onlcr  icrnl  brkint");
Packit 910689
	   else if(mode==1)
Packit 910689
		system("/bin/stty -raw -cbreak  isig -echo  ixon  onlcr  icrnl  brkint");
Packit 910689
	   else if(mode==0)
Packit 910689
		system("/bin/stty -raw -cbreak  isig  echo  ixon  onlcr  icrnl  brkint");
Packit 910689
Packit 910689
	   /* Those probably won't work, but they couldn't hurt 
Packit 910689
              at this point */
Packit 910689
Packit 910689
#endif
Packit 910689
Packit 910689
	/*warn("Mode set to %d.\n",mode);*/
Packit 910689
Packit 910689
	if( firsttime ) {
Packit 910689
		(void)hv_delete(filehash,(char*)&handle,sizeof(int),0);
Packit 910689
		(void)hv_delete(modehash,(char*)&handle,sizeof(int),0);
Packit 910689
	} else {
Packit 910689
		if(!hv_store(modehash,(char*)&handle,sizeof(int),
Packit 910689
			newSViv(mode),0))
Packit 910689
			croak("Unable to stash terminal settings.\n");
Packit 910689
	}
Packit 910689
Packit 910689
}
Packit 910689
Packit 910689
#ifdef USE_PERLIO
Packit 910689
Packit 910689
/* Make use of a recent addition to Perl, if possible */
Packit 910689
# define FCOUNT(f) PerlIO_get_cnt(f)
Packit 910689
#else
Packit 910689
Packit 910689
 /* Make use of a recent addition to Configure, if possible */
Packit 910689
# ifdef USE_STDIO_PTR
Packit 910689
#  define FCOUNT(f) PerlIO_get_cnt(f)
Packit 910689
# else
Packit 910689
  /* This bit borrowed from pp_sys.c. Complain to Larry if it's broken. */
Packit 910689
  /* If any of this works PerlIO_get_cnt() will too ... NI-S */
Packit 910689
#  if defined(USE_STD_STDIO) || defined(atarist) /* this will work with atariST */
Packit 910689
#   define FBASE(f) ((f)->_base)
Packit 910689
#   define FSIZE(f) ((f)->_cnt + ((f)->_ptr - (f)->_base))
Packit 910689
#   define FPTR(f) ((f)->_ptr)
Packit 910689
#   define FCOUNT(f) ((f)->_cnt)
Packit 910689
#  else
Packit 910689
#   if defined(USE_LINUX_STDIO)
Packit 910689
#     define FBASE(f) ((f)->_IO_read_base)
Packit 910689
#     define FSIZE(f) ((f)->_IO_read_end - FBASE(f))
Packit 910689
#     define FPTR(f) ((f)->_IO_read_ptr)
Packit 910689
#     define FCOUNT(f) ((f)->_IO_read_end - FPTR(f))
Packit 910689
#   endif
Packit 910689
#  endif
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
Packit 910689
/* This is for the best, I'm afraid. */
Packit 910689
#if !defined(FCOUNT)
Packit 910689
# ifdef Have_select
Packit 910689
#  undef Have_select
Packit 910689
# endif
Packit 910689
# ifdef Have_poll
Packit 910689
#  undef Have_poll
Packit 910689
# endif
Packit 910689
#endif
Packit 910689
Packit 910689
/* Note! If your machine has a bolixed up select() call that doesn't
Packit 910689
understand this syntax, either fix the checkwaiting call below, or define
Packit 910689
DONT_USE_SELECT. */
Packit 910689
Packit 910689
#ifdef Have_select
Packit 910689
int selectfile(pTHX_ PerlIO *file,double delay)
Packit 910689
{
Packit 910689
	struct timeval t;
Packit 910689
	int handle=PerlIO_fileno(file);
Packit 910689
Packit 910689
	/*char buf[32];    
Packit 910689
	Select_fd_set_t fd=(Select_fd_set_t)&buf[0];*/
Packit 910689
Packit 910689
	fd_set fd;
Packit 910689
	if (PerlIO_fast_gets(file) && PerlIO_get_cnt(file) > 0)
Packit 910689
		return 1;
Packit 910689
Packit 910689
	/*t.tv_sec=t.tv_usec=0;*/
Packit 910689
Packit 910689
        if (delay < 0.0)
Packit 910689
            delay = 0.0;
Packit 910689
        t.tv_sec = (long)delay;
Packit 910689
        delay -= (double)t.tv_sec;
Packit 910689
        t.tv_usec = (long)(delay * 1000000.0);
Packit 910689
Packit 910689
	FD_ZERO(&fd;;
Packit 910689
	FD_SET(handle,&fd;;
Packit 910689
	if(select(handle+1,(Select_fd_set_t)&fd,
Packit 910689
			   (Select_fd_set_t)0,
Packit 910689
			   (Select_fd_set_t)&fd, &t)) return -1; 
Packit 910689
	else return 0;
Packit 910689
}
Packit 910689
Packit 910689
#else
Packit 910689
int selectfile(pTHX_ PerlIO *file, double delay)
Packit 910689
{
Packit 910689
	croak("select is not supported on this architecture");
Packit 910689
	return 0;
Packit 910689
}
Packit 910689
#endif
Packit 910689
Packit 910689
#ifdef Have_nodelay
Packit 910689
int setnodelay(pTHX_ PerlIO *file, int mode)
Packit 910689
{
Packit 910689
	int handle=PerlIO_fileno(file);
Packit 910689
	int flags;
Packit 910689
	flags=fcntl(handle,F_GETFL,0);
Packit 910689
	if(mode)
Packit 910689
		flags|=O_NODELAY;
Packit 910689
	else
Packit 910689
		flags&=~O_NODELAY;
Packit 910689
	fcntl(handle,F_SETFL,flags);
Packit 910689
	return 0;
Packit 910689
}
Packit 910689
Packit 910689
#else
Packit 910689
int setnodelay(pTHX_ PerlIO *file, int mode)
Packit 910689
{
Packit 910689
	croak("setnodelay is not supported on this architecture");
Packit 910689
	return 0;
Packit 910689
}
Packit 910689
#endif
Packit 910689
Packit 910689
#ifdef Have_poll
Packit 910689
int pollfile(pTHX_ pTHX_ PerlIO *file,double delay)
Packit 910689
{
Packit 910689
	int handle=PerlIO_fileno(file);
Packit 910689
	struct pollfd fds;
Packit 910689
	if (PerlIO_fast_gets(f) && PerlIO_get_cnt(f) > 0)
Packit 910689
		return 1;
Packit 910689
	if(delay<0.0) delay = 0.0;
Packit 910689
	fds.fd=handle;
Packit 910689
	fds.events=POLLIN;
Packit 910689
	fds.revents=0;
Packit 910689
	return (poll(&fds,1,(long)(delay * 1000.0))>0);
Packit 910689
} 
Packit 910689
#else
Packit 910689
int pollfile(pTHX_ PerlIO *file,double delay)
Packit 910689
{
Packit 910689
	croak("pollfile is not supported on this architecture");
Packit 910689
	return 0;
Packit 910689
}
Packit 910689
#endif
Packit 910689
Packit 910689
#ifdef WIN32
Packit 910689
Packit 910689
/*
Packit 910689
Packit 910689
 This portion of the Win32 code is partially borrowed from a version of PDCurses.
Packit 910689
Packit 910689
*/
Packit 910689
Packit 910689
typedef struct {
Packit 910689
    int repeatCount;
Packit 910689
    int vKey;
Packit 910689
    int vScan;
Packit 910689
    int ascii;
Packit 910689
    int control;
Packit 910689
} win32_key_event_t;
Packit 910689
Packit 910689
#define KEY_PUSH(I, K) { events[I].repeatCount = 1; events[I].ascii = K; }
Packit 910689
#define KEY_PUSH3(K1, K2, K3) \
Packit 910689
    do { \
Packit 910689
             eventCount = 0;            \
Packit 910689
             KEY_PUSH(2, K1);           \
Packit 910689
             KEY_PUSH(1, K2);           \
Packit 910689
             KEY_PUSH(0, K3);           \
Packit 910689
             eventCount = 3;            \
Packit 910689
             goto again;                \
Packit 910689
    } while (0)
Packit 910689
Packit 910689
#define KEY_PUSH4(K1, K2, K3, K4) \
Packit 910689
    do { \
Packit 910689
             eventCount = 0;            \
Packit 910689
             KEY_PUSH(3, K1);           \
Packit 910689
             KEY_PUSH(2, K2);           \
Packit 910689
             KEY_PUSH(1, K3);           \
Packit 910689
             KEY_PUSH(0, K4);           \
Packit 910689
             eventCount = 4;            \
Packit 910689
             goto again;                \
Packit 910689
    } while (0)
Packit 910689
Packit 910689
int Win32PeekChar(pTHX_ PerlIO *file,U32 delay,char *key)
Packit 910689
{
Packit 910689
	int handle;
Packit 910689
	HANDLE whnd;
Packit 910689
	INPUT_RECORD record;
Packit 910689
	DWORD readRecords;
Packit 910689
Packit 910689
#if 0
Packit 910689
	static int keyCount = 0;
Packit 910689
	static char lastKey = 0;
Packit 910689
#endif
Packit 910689
Packit 910689
#define MAX_EVENTS 4
Packit 910689
    static int eventCount = 0;
Packit 910689
    static win32_key_event_t events[MAX_EVENTS];
Packit 910689
    int keyCount;
Packit 910689
Packit 910689
	file = STDIN;
Packit 910689
Packit 910689
	handle = PerlIO_fileno(file);
Packit 910689
	whnd = /*GetStdHandle(STD_INPUT_HANDLE)*/(HANDLE)_get_osfhandle(handle);
Packit 910689
Packit 910689
Packit 910689
again:
Packit 910689
#if 0
Packit 910689
	if (keyCount > 0) {
Packit 910689
		keyCount--;
Packit 910689
		*key = lastKey;
Packit 910689
	    return TRUE;
Packit 910689
	}
Packit 910689
#endif
Packit 910689
Packit 910689
    /* printf("eventCount: %d\n", eventCount); */
Packit 910689
    if (eventCount) {
Packit 910689
        /* printf("key %d; repeatCount %d\n", *key, events[eventCount - 1].repeatCount); */
Packit 910689
        *key = events[eventCount - 1].ascii;
Packit 910689
        events[eventCount - 1].repeatCount--;
Packit 910689
        if (events[eventCount - 1].repeatCount <= 0) {
Packit 910689
            eventCount--;
Packit 910689
        }
Packit 910689
        return TRUE;
Packit 910689
    }
Packit 910689
Packit 910689
	if (delay > 0) {
Packit 910689
		if (WaitForSingleObject(whnd, delay * 1000) != WAIT_OBJECT_0)
Packit 910689
		{
Packit 910689
			return FALSE;
Packit 910689
		}
Packit 910689
	}
Packit 910689
Packit 910689
	if (delay != 0) {
Packit 910689
		PeekConsoleInput(whnd, &record, 1, &readRecords);
Packit 910689
		if (readRecords == 0) {
Packit 910689
			return(FALSE);
Packit 910689
        }
Packit 910689
	}
Packit 910689
Packit 910689
	ReadConsoleInput(whnd, &record, 1, &readRecords);
Packit 910689
	switch(record.EventType)
Packit 910689
   {
Packit 910689
    case KEY_EVENT:
Packit 910689
		/* printf("\nkeyDown = %d, repeat = %d, vKey = %d, vScan = %d, ASCII = %d, Control = %d\n",
Packit 910689
			record.Event.KeyEvent.bKeyDown,
Packit 910689
			record.Event.KeyEvent.wRepeatCount,
Packit 910689
			record.Event.KeyEvent.wVirtualKeyCode,
Packit 910689
			record.Event.KeyEvent.wVirtualScanCode,
Packit 910689
			record.Event.KeyEvent.uChar.AsciiChar,
Packit 910689
			record.Event.KeyEvent.dwControlKeyState); */
Packit 910689
Packit 910689
         if (record.Event.KeyEvent.bKeyDown == FALSE)
Packit 910689
            goto again;                        /* throw away KeyUp events */
Packit 910689
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 38) { /* up */
Packit 910689
             KEY_PUSH3(27, 91, 65);
Packit 910689
         }
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 40) { /* down */
Packit 910689
             KEY_PUSH3(27, 91, 66);
Packit 910689
         }
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 39) { /* right */
Packit 910689
             KEY_PUSH3(27, 91, 67);
Packit 910689
         }
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 37) { /* left */
Packit 910689
             KEY_PUSH3(27, 91, 68);
Packit 910689
         }
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 33) { /* page up */
Packit 910689
             KEY_PUSH3(27, 79, 121);
Packit 910689
         }
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 34) { /* page down */
Packit 910689
             KEY_PUSH3(27, 79, 115);
Packit 910689
         }
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 36) { /* home */
Packit 910689
             KEY_PUSH4(27, 91, 49, 126);
Packit 910689
         }
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 35) { /* end */
Packit 910689
             KEY_PUSH4(27, 91, 52, 126);
Packit 910689
         }
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 45) { /* insert */
Packit 910689
             KEY_PUSH4(27, 91, 50, 126);
Packit 910689
         }
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 46) { /* delete */
Packit 910689
             KEY_PUSH4(27, 91, 51, 126);
Packit 910689
         }
Packit 910689
Packit 910689
         if (record.Event.KeyEvent.wVirtualKeyCode == 16
Packit 910689
         ||  record.Event.KeyEvent.wVirtualKeyCode == 17
Packit 910689
         ||  record.Event.KeyEvent.wVirtualKeyCode == 18
Packit 910689
         ||  record.Event.KeyEvent.wVirtualKeyCode == 20
Packit 910689
         ||  record.Event.KeyEvent.wVirtualKeyCode == 144
Packit 910689
         ||  record.Event.KeyEvent.wVirtualKeyCode == 145)
Packit 910689
            goto again;  /* throw away shift/alt/ctrl key only key events */
Packit 910689
         keyCount = record.Event.KeyEvent.wRepeatCount;
Packit 910689
		 break;
Packit 910689
    default:
Packit 910689
         keyCount = 0;
Packit 910689
         goto again;
Packit 910689
         break;
Packit 910689
   }
Packit 910689
Packit 910689
 *key = record.Event.KeyEvent.uChar.AsciiChar; 
Packit 910689
 keyCount--;
Packit 910689
Packit 910689
 if (keyCount) {
Packit 910689
     events[0].repeatCount = keyCount;
Packit 910689
     events[0].ascii = *key;
Packit 910689
     eventCount = 1;
Packit 910689
 }
Packit 910689
 
Packit 910689
 return(TRUE);
Packit 910689
Packit 910689
 /* again:
Packit 910689
	return (FALSE);
Packit 910689
	*/
Packit 910689
Packit 910689
Packit 910689
} 
Packit 910689
#else
Packit 910689
int Win32PeekChar(pTHX_ PerlIO *file, U32 delay,char *key)
Packit 910689
{
Packit 910689
	croak("Win32PeekChar is not supported on this architecture");
Packit 910689
	return 0;
Packit 910689
}
Packit 910689
#endif
Packit 910689
Packit 910689
Packit 910689
STATIC int blockoptions() {
Packit 910689
	return	0
Packit 910689
#ifdef Have_nodelay
Packit 910689
		| 1
Packit 910689
#endif
Packit 910689
#ifdef Have_poll
Packit 910689
		| 2
Packit 910689
#endif
Packit 910689
#ifdef Have_select
Packit 910689
		| 4
Packit 910689
#endif
Packit 910689
#ifdef USE_WIN32
Packit 910689
		| 8
Packit 910689
#endif
Packit 910689
		;
Packit 910689
}
Packit 910689
Packit 910689
STATIC int termoptions() {
Packit 910689
	int i=0;
Packit 910689
#ifdef USE_TERMIOS
Packit 910689
	i=1;		
Packit 910689
#endif
Packit 910689
#ifdef USE_TERMIO
Packit 910689
	i=2;
Packit 910689
#endif
Packit 910689
#ifdef USE_SGTTY
Packit 910689
	i=3;
Packit 910689
#endif
Packit 910689
#ifdef USE_STTY
Packit 910689
	i=4;
Packit 910689
#endif
Packit 910689
#ifdef USE_WIN32
Packit 910689
	i=5;
Packit 910689
#endif
Packit 910689
	return i;
Packit 910689
}
Packit 910689
Packit 910689
Packit 910689
Packit 910689
MODULE = Term::ReadKey		PACKAGE = Term::ReadKey
Packit 910689
Packit 910689
int
Packit 910689
selectfile(file,delay)
Packit 910689
	InputStream	file
Packit 910689
	double	delay
Packit 910689
CODE:
Packit 910689
	RETVAL = selectfile(aTHX_ file, delay);
Packit 910689
OUTPUT:
Packit 910689
	RETVAL
Packit 910689
Packit 910689
# Clever, eh?
Packit 910689
void
Packit 910689
SetReadMode(mode,file=STDIN)
Packit 910689
	int	mode
Packit 910689
	InputStream	file
Packit 910689
	CODE:
Packit 910689
	{
Packit 910689
		ReadMode(aTHX_ file,mode);
Packit 910689
	}
Packit 910689
Packit 910689
int
Packit 910689
setnodelay(file,mode)
Packit 910689
	InputStream	file
Packit 910689
	int	mode
Packit 910689
CODE:
Packit 910689
	RETVAL = setnodelay(aTHX_ file, mode);
Packit 910689
OUTPUT:
Packit 910689
	RETVAL
Packit 910689
Packit 910689
int
Packit 910689
pollfile(file,delay)
Packit 910689
	InputStream	file
Packit 910689
	double	delay
Packit 910689
CODE:
Packit 910689
	RETVAL = pollfile(aTHX_ file, delay);
Packit 910689
OUTPUT:
Packit 910689
	RETVAL
Packit 910689
Packit 910689
SV *
Packit 910689
Win32PeekChar(file, delay)
Packit 910689
	InputStream	file
Packit 910689
	U32	delay
Packit 910689
	CODE:
Packit 910689
	{
Packit 910689
		char key;
Packit 910689
		if (Win32PeekChar(aTHX_ file, delay, &key))
Packit 910689
			RETVAL = newSVpv(&key, 1);
Packit 910689
		else
Packit 910689
			RETVAL = newSVsv(&PL_sv_undef);
Packit 910689
	}
Packit 910689
	OUTPUT:
Packit 910689
	RETVAL
Packit 910689
Packit 910689
int
Packit 910689
blockoptions()
Packit 910689
Packit 910689
int
Packit 910689
termoptions()
Packit 910689
Packit 910689
int
Packit 910689
termsizeoptions()
Packit 910689
Packit 910689
void
Packit 910689
GetTermSizeWin32(file=STDIN)
Packit 910689
	InputStream	file
Packit 910689
	PPCODE:
Packit 910689
	{
Packit 910689
		int x,y,xpix,ypix;
Packit 910689
		if( GetTermSizeWin32(aTHX_ file,&x,&y,&xpix,&ypix)==0)
Packit 910689
		{
Packit 910689
			EXTEND(sp, 4);
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)x)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)y)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)xpix)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)ypix)));
Packit 910689
		}
Packit 910689
		else
Packit 910689
		{
Packit 910689
			ST(0) = sv_newmortal();
Packit 910689
		}
Packit 910689
	}
Packit 910689
Packit 910689
void
Packit 910689
GetTermSizeVIO(file=STDIN)
Packit 910689
	InputStream	file
Packit 910689
	PPCODE:
Packit 910689
	{
Packit 910689
		int x,y,xpix,ypix;
Packit 910689
		if( GetTermSizeVIO(aTHX_ file,&x,&y,&xpix,&ypix)==0)
Packit 910689
		{
Packit 910689
			EXTEND(sp, 4);
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)x)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)y)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)xpix)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)ypix)));
Packit 910689
		}
Packit 910689
		else
Packit 910689
		{
Packit 910689
			ST(0) = sv_newmortal();
Packit 910689
		}
Packit 910689
	}
Packit 910689
Packit 910689
void
Packit 910689
GetTermSizeGWINSZ(file=STDIN)
Packit 910689
	InputStream	file
Packit 910689
	PPCODE:
Packit 910689
	{
Packit 910689
		int x,y,xpix,ypix;
Packit 910689
		if( GetTermSizeGWINSZ(aTHX_ file,&x,&y,&xpix,&ypix)==0)
Packit 910689
		{
Packit 910689
			EXTEND(sp, 4);
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)x)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)y)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)xpix)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)ypix)));
Packit 910689
		}
Packit 910689
		else
Packit 910689
		{
Packit 910689
			ST(0) = sv_newmortal();
Packit 910689
		}
Packit 910689
	}
Packit 910689
Packit 910689
void
Packit 910689
GetTermSizeGSIZE(file=STDIN)
Packit 910689
	InputStream	file
Packit 910689
	PPCODE:
Packit 910689
	{
Packit 910689
		int x,y,xpix,ypix;
Packit 910689
		if( GetTermSizeGSIZE(aTHX_ file,&x,&y,&xpix,&ypix)==0)
Packit 910689
		{
Packit 910689
			EXTEND(sp, 4);
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)x)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)y)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)xpix)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)ypix)));
Packit 910689
		}
Packit 910689
		else
Packit 910689
		{
Packit 910689
			ST(0) = sv_newmortal();
Packit 910689
		}
Packit 910689
	}
Packit 910689
Packit 910689
int
Packit 910689
SetTerminalSize(width,height,xpix,ypix,file=STDIN)
Packit 910689
	int	width
Packit 910689
	int	height
Packit 910689
	int	xpix
Packit 910689
	int	ypix
Packit 910689
	InputStream	file
Packit 910689
	CODE:
Packit 910689
	{
Packit 910689
		RETVAL=SetTerminalSize(aTHX_ file,width,height,xpix,ypix);
Packit 910689
	}
Packit 910689
	OUTPUT:
Packit 910689
		RETVAL
Packit 910689
Packit 910689
void
Packit 910689
GetSpeed(file=STDIN)
Packit 910689
	InputStream	file
Packit 910689
	PPCODE:
Packit 910689
	{
Packit 910689
		I32 in,out;
Packit 910689
/*
Packit 910689
 *    experimentally relaxed for 
Packit 910689
 *    https://rt.cpan.org/Ticket/Display.html?id=88050
Packit 910689
		if(items!=0) {
Packit 910689
			croak("Usage: Term::ReadKey::GetSpeed()");
Packit 910689
		}
Packit 910689
*/
Packit 910689
		if(getspeed(aTHX_ file,&in,&out)) {
Packit 910689
			/* Failure */
Packit 910689
			ST( 0) = sv_newmortal();
Packit 910689
		} else {
Packit 910689
			EXTEND(sp, 2);
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)in)));
Packit 910689
			PUSHs(sv_2mortal(newSViv((IV)out)));
Packit 910689
		}
Packit 910689
	}
Packit 910689
Packit 910689
Packit 910689
Packit 910689
BOOT: 
Packit 910689
newXS("Term::ReadKey::GetControlChars", XS_Term__ReadKey_GetControlChars, file);
Packit 910689
newXS("Term::ReadKey::SetControlChars", XS_Term__ReadKey_SetControlChars, file);
Packit 910689
filehash=newHV();
Packit 910689
modehash=newHV();