1 /* -*-C-*- */
2 
3 #define PERL_NO_GET_CONTEXT     /* we want efficiency */
4 #include "EXTERN.h"
5 #include "perl.h"
6 #include "XSUB.h"
7 #include "ppport.h"
8 
9 #define InputStream PerlIO *
10 
11 /*******************************************************************
12 
13  Copyright (C) 1994,1995,1996,1997 Kenneth Albanowski. Unlimited
14  distribution and/or modification is allowed as long as this copyright
15  notice remains intact.
16 
17  Written by Kenneth Albanowski on Thu Oct  6 11:42:20 EDT 1994
18  Contact at kjahds@kjahds.com or CIS:70705,126
19 
20  Maintained by Jonathan Stowe <jns@gellyfish.co.uk>
21 
22  The below captures the history prior to it being in full time version
23  control:
24 
25  $Id: ReadKey.xs,v 2.22 2005/01/11 21:15:17 jonathan Exp $
26 
27  Version 2.21, Sun Jul 28 12:57:56 BST 2002
28     Fix to improve the chances of automated testing succeeding
29 
30  Version 2.20, Tue May 21 07:52:47 BST 2002
31     Patch from Autrijus Tang fixing Win32 Breakage with bleadperl
32 
33  Version 2.19, Thu Mar 21 07:25:31 GMT 2002
34     Added check for definedness of $_[0] in comparisons in ReadKey, ReadLine
35     after reports of warnings.
36 
37  Version 2.18, Sun Feb 10 13:06:57 GMT 2002
38     Altered prototyping style after reports of compile failures on
39     Windows.
40 
41  Version 2.17, Fri Jan 25 06:58:47 GMT 2002
42     The '_' macro for non-ANSI compatibility was removed in 5.7.2
43 
44  Version 2.16, Thu Nov 29 21:19:03 GMT 2001
45     It appears that the genchars.pl bit of the patch didnt apply
46     Applied the new ppport.h from Devel::PPPort
47 
48  Version 2.15, Sun Nov  4 15:02:37 GMT 2001 (jns)
49     Applied the patch in
50     http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2001-01/msg01588.html
51     for PerlIO compatibility.
52 
53  Version 2.14, Sun Mar 28 23:26:13 EST 1999
54     ppport.h 1.007 fixed for 5.005_55.
55 
56  Version 2.13, Wed Mar 24 20:46:06 EST 1999
57  	Adapted to ppport.h 1.006.
58 
59  Version 2.12, Wed Jan  7 10:33:11 EST 1998
60  	Slightly modified test and error reporting for Win32.
61 
62  Version 2.11, Sun Dec 14 00:39:12 EST 1997
63     First attempt at Win32 support.
64 
65  Version 2.10, skipped
66 
67  Version 2.09, Tue Oct  7 13:07:43 EDT 1997
68     Grr. Added explicit detection of sys/poll.h and poll.h.
69 
70  Version 2.08, Mon Oct  6 16:07:44 EDT 1997
71     Changed poll.h to sys/poll.h.
72 
73  Version 2.07, Sun Jan 26 19:11:56 EST 1997
74     Added $VERSION to .pm.
75 
76  Version 2.06, Tue Nov 26 01:47:09 EST 1996
77     Added PERLIO support and removed duplicate declaration in .pm.
78 
79  Version 2.05, Tue Mar 12 19:08:33 EST 1996
80  	Changed poll support so it works. Cleaned up .pm a little.
81 
82  Version 2.04, Tue Oct 10 05:35:48 EDT 1995
83  	Whoops. Changed GetTermSize back so that GSIZE code won't be
84  	compiled if GWINSZ is being used. Also took ts_xxx and ts_yyy
85  	out of GSIZE.
86 
87  Version 2.03, Thu Sep 21 21:53:16 EDT 1995
88 	Fixed up debugging info in Readkey.pm, and changed TermSizeVIO
89 	to use _scrsize(). Hopefully this is GO for both Solaris and OS/2.
90 
91  Version 2.02, Mon Sep 18 22:17:57 EDT 1995
92 	Workaround for Solaris bug wasn't sufficient. Modularlized
93 	GetTermSize into perl code, and added support for the
94 	`resize` executable. Hard coded path for Solaris machines.
95 
96  Version 2.01, Wed Sep 13 22:22:23 EDT 1995
97 	Change error reporting around in getscreensize so that if
98  	an ioctl fails but getenv succeeds, no warning will be
99 	printed. This is an attempt to work around a Solaris bug where
100 	TIOCGWINSZ fails in telnet sessions.
101 
102  Version 2.00, Mon Sep  4 06:37:24 EDT 1995
103 	Added timeouts to select/poll, added USE_STDIO_PTR support
104 	(required for recent perl revisions), and fixed up compilation
105 	under OS/2.
106 
107  Version 1.99, Fri Aug 11 20:18:11 EDT 1995
108 	Add file handles to ReadMode.
109 
110  Version 1.97, Mon Apr 10 21:41:52 EDT 1995
111 	Changed mode 5 to disable UC & delays. Added more ECHO flags.
112         Tested termio[s] & sgtty.
113 	Added termoptions so test.pl can give more info.
114 
115  Version 1.96,
116 	Mucked with filehandle selection in ReadKey.pm.
117 
118  Version 1.95,
119 	Cleaning up for distribution.
120 
121  Version 1.94,
122 	Dealt with get/settermsize sillyness.
123 
124  Version 1.91, Sat Mar 11 23:47:04 EST 1995:
125 	Andy's patches, and a bit of termsize finesse.
126 
127  Version 1.9, Thu Mar  9 14:11:49 EST 1995:
128 	Modifying for portability. Prototypes, singed chars, etc.
129 
130  Version 1.8, Mon Jan  9 23:18:14 EST 1995:
131 	Added use of Configure.pm. No changes to ReadKey.
132 
133  Version 1.7, Fri Dec 16 13:48:14 EST 1994:
134    Getting closer to release. Added new readmode 2. Had to bump up other
135    modes, unfortunately. This is the _last_ time I do that. If I have to
136    bump up the modes again, I'm switching to a different scheme.
137 
138  Version 1.6, Wed Dec 14 17:36:59 EST 1994:
139 	Completly reorganized the control-char support (twice!) so that
140 	it is automatically ported by the preproccessor for termio[s], or
141 	by an included script for sgtty. Logical defaults for sgtty are included
142 	too. Added Sun TermSize support. (Hope I got it right.)
143 
144  Version 1.5, Fri Dec  9 16:07:49 EST 1994:
145 	Added SetTermSize, GetSpeeds, Get/SetControlChars, PerlIO support.
146 
147  Version 1.01, Thu Oct 20 23:32:39 EDT 1994:
148 	Added Select_fd_set_t casts to select() call.
149 
150  Version 1.0: First "real" release. Everything seems cool.
151 
152 
153 *******************************************************************/
154 
155 /***
156 
157  Things to do:
158 
159 	Make sure the GetSpeed function is doing it's best to separate ispeed
160 	from ospeed.
161 
162 	Separate the stty stuff from ReadMode, so that stty -a can be easily
163 	used, among other things.
164 
165 ***/
166 
167 
168 
169 /* Using these defines, you can elide anything you know
170    won't work properly */
171 
172 /* Methods of doing non-blocking reads */
173 
174 /*#define DONT_USE_SELECT*/
175 /*#define DONT_USE_POLL*/
176 /*#define DONT_USE_NODELAY*/
177 
178 
179 /* Terminal I/O packages */
180 
181 /*#define DONT_USE_TERMIOS*/
182 /*#define DONT_USE_TERMIO*/
183 /*#define DONT_USE_SGTTY*/
184 
185 /* IOCTLs that can be used for GetTerminalSize */
186 
187 /*#define DONT_USE_GWINSZ*/
188 /*#define DONT_USE_GSIZE*/
189 
190 /* IOCTLs that can be used for SetTerminalSize */
191 
192 /*#define DONT_USE_SWINSZ*/
193 /*#define DONT_USE_SSIZE*/
194 
195 
196 /* This bit is for OS/2 */
197 
198 #ifdef OS2
199 #       define I_FCNTL
200 #       define HAS_FCNTL
201 
202 #       define O_NODELAY O_NDELAY
203 
204 #       define DONT_USE_SELECT
205 #       define DONT_USE_POLL
206 
207 #       define DONT_USE_TERMIOS
208 #       define DONT_USE_SGTTY
209 #       define I_TERMIO
210 #       define CC_TERMIO
211 
212 /* This flag should be off in the lflags when we enable termio mode */
213 #      define TRK_IDEFAULT     IDEFAULT
214 
215 #       define INCL_SUB
216 #       define INCL_DOS
217 
218 #       include <os2.h>
219 #	include <stdlib.h>
220 
221 #       define VIOMODE
222 #else
223         /* no os2 */
224 #endif
225 
226 /* This bit is for Windows 95/NT */
227 
228 #ifdef WIN32
229 #		define DONT_USE_TERMIO
230 #		define DONT_USE_TERMIOS
231 #		define DONT_USE_SGTTY
232 #		define DONT_USE_POLL
233 #		define DONT_USE_SELECT
234 #		define DONT_USE_NODELAY
235 #		define USE_WIN32
236 #		include <io.h>
237 #		if defined(_get_osfhandle) && (PERL_VERSION == 4) && (PERL_SUBVERSION < 5)
238 #			undef _get_osfhandle
239 #			if defined(_MSC_VER)
240 #				define level _cnt
241 #			endif
242 #		endif
243 #endif
244 
245 /* This bit for NeXT */
246 
247 #ifdef _NEXT_SOURCE
248   /* fcntl with O_NDELAY (FNDELAY, actually) is broken on NeXT */
249 # define DONT_USE_NODELAY
250 #endif
251 
252 #if !defined(DONT_USE_NODELAY)
253 # ifdef HAS_FCNTL
254 #  define Have_nodelay
255 #  ifdef I_FCNTL
256 #   include <fcntl.h>
257 #  endif
258 #  ifdef I_SYS_FILE
259 #   include <sys/file.h>
260 #  endif
261 #  ifdef I_UNISTD
262 #   include <unistd.h>
263 #  endif
264 
265 /* If any other headers are needed for fcntl or O_NODELAY, they need to get
266    included right here */
267 
268 #  if !defined(O_NODELAY)
269 #   if !defined(FNDELAY)
270 #    undef Have_nodelay
271 #   else
272 #    define O_NODELAY FNDELAY
273 #   endif
274 #  else
275 #   define O_NODELAY O_NDELAY
276 #  endif
277 # endif
278 #endif
279 
280 #if !defined(DONT_USE_SELECT)
281 # ifdef HAS_SELECT
282 #  ifdef I_SYS_SELECT
283 #   include <sys/select.h>
284 #  endif
285 
286 /* If any other headers are likely to be needed for select, they need to be
287    included right here */
288 
289 #  define Have_select
290 # endif
291 #endif
292 
293 #if !defined(DONT_USE_POLL)
294 # ifdef HAS_POLL
295 #  ifdef HAVE_POLL_H
296 #   include <poll.h>
297 #   define Have_poll
298 #  endif
299 #  ifdef HAVE_SYS_POLL_H
300 #   include <sys/poll.h>
301 #   define Have_poll
302 #  endif
303 # endif
304 #endif
305 
306 #ifdef DONT_USE_TERMIOS
307 # ifdef I_TERMIOS
308 #  undef I_TERMIOS
309 # endif
310 #endif
311 #ifdef DONT_USE_TERMIO
312 # ifdef I_TERMIO
313 #  undef I_TERMIO
314 # endif
315 #endif
316 #ifdef DONT_USE_SGTTY
317 # ifdef I_SGTTY
318 #  undef I_SGTTY
319 # endif
320 #endif
321 
322 /* Pre-POSIX SVR3 systems sometimes define struct winsize in
323    sys/ptem.h.  However, sys/ptem.h needs a type mblk_t (?) which
324    is defined in <sys/stream.h>.
325    No, Configure (dist3.051) doesn't know how to check for this.
326 */
327 #ifdef I_SYS_STREAM
328 # include <sys/stream.h>
329 #endif
330 #ifdef I_SYS_PTEM
331 # include <sys/ptem.h>
332 #endif
333 
334 #ifdef I_TERMIOS
335 # include <termios.h>
336 #else
337 # ifdef I_TERMIO
338 #  include <termio.h>
339 # else
340 #  ifdef I_SGTTY
341 #   include <sgtty.h>
342 #  endif
343 # endif
344 #endif
345 
346 #ifdef I_TERMIOS
347 # define CC_TERMIOS
348 #else
349 # ifdef I_TERMIO
350 #  define CC_TERMIO
351 # else
352 #  ifdef I_SGTTY
353 #   define CC_SGTTY
354 #  endif
355 # endif
356 #endif
357 
358 #ifndef TRK_IDEFAULT
359 /* This flag should be off in the lflags when we enable termio mode */
360 #      define TRK_IDEFAULT     0
361 #endif
362 
363 /* Fix up the disappearance of the '_' macro in Perl 5.7.2 */
364 
365 #ifndef _
366 #  ifdef CAN_PROTOTYPE
367 #    define _(args) args
368 #  else
369 #    define _(args) ()
370 #  endif
371 #endif
372 
373 #define DisableFlush (1) /* Should flushing mode changes be enabled?
374 		            I think not for now. */
375 
376 
377 #define STDIN PerlIO_stdin()
378 
379 #include "cchars.h"
380 
381 
382 STATIC int GetTermSizeVIO _((pTHX_ PerlIO * file,
383 	int * retwidth, int * retheight,
384 	int * xpix, int * ypix));
385 
386 STATIC int GetTermSizeGWINSZ _((pTHX_ PerlIO * file,
387 	int * retwidth, int * retheight,
388 	int * xpix, int * ypix));
389 
390 STATIC int GetTermSizeGSIZE _((pTHX_ PerlIO * file,
391 	int * retwidth, int * retheight,
392 	int * xpix, int * ypix));
393 
394 STATIC int GetTermSizeWin32 _((pTHX_ PerlIO * file,
395 	int * retwidth, int * retheight,
396 	int * xpix, int * ypix));
397 
398 STATIC int SetTerminalSize _((pTHX_ PerlIO * file,
399 	int width, int height,
400 	int xpix, int ypix));
401 
402 STATIC void ReadMode _((pTHX_ PerlIO * file,int mode));
403 
404 STATIC int pollfile _((pTHX_ PerlIO * file, double delay));
405 
406 STATIC int setnodelay _((pTHX_ PerlIO * file, int mode));
407 
408 STATIC int selectfile _((pTHX_ PerlIO * file, double delay));
409 
410 STATIC int Win32PeekChar _((pTHX_ PerlIO * file, double delay, char * key));
411 
412 STATIC int getspeed _((pTHX_ PerlIO * file, I32 *in, I32 * out ));
413 
414 
415 #ifdef VIOMODE
GetTermSizeVIO(pTHX_ PerlIO * file,int * retwidth,int * retheight,int * xpix,int * ypix)416 int GetTermSizeVIO(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
417 {
418 	/*int handle=PerlIO_fileno(file);
419 
420         static VIOMODEINFO *modeinfo = NULL;
421 
422         if (modeinfo == NULL)
423                 modeinfo = (VIOMODEINFO *)malloc(sizeof(VIOMODEINFO));
424 
425         VioGetMode(modeinfo,0);
426         *retheight = modeinfo->row ?: 25;
427         *retwidth = modeinfo->col ?: 80;*/
428 	int buf[2];
429 
430 	_scrsize(&buf[0]);
431 
432 	*retwidth = buf[0]; *retheight = buf[1];
433 
434         *xpix = *ypix = 0;
435         return 0;
436 }
437 #else
GetTermSizeVIO(pTHX_ PerlIO * file,int * retwidth,int * retheight,int * xpix,int * ypix)438 int GetTermSizeVIO(pTHX_ PerlIO *file,int * retwidth,int *retheight, int *xpix,int *ypix)
439 {
440 	croak("TermSizeVIO is not implemented on this architecture");
441         return 0;
442 }
443 #endif
444 
445 
446 #if defined(TIOCGWINSZ) && !defined(DONT_USE_GWINSZ)
GetTermSizeGWINSZ(pTHX_ PerlIO * file,int * retwidth,int * retheight,int * xpix,int * ypix)447 int GetTermSizeGWINSZ(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
448 {
449 	int handle=PerlIO_fileno(file);
450 	struct winsize w;
451 
452 	if (ioctl (handle, TIOCGWINSZ, &w) == 0) {
453 		*retwidth=w.ws_col; *retheight=w.ws_row;
454 		*xpix=w.ws_xpixel; *ypix=w.ws_ypixel; return 0;
455 	}
456 	else {
457 		return -1; /* failure */
458 	}
459 
460 }
461 #else
GetTermSizeGWINSZ(pTHX_ PerlIO * file,int * retwidth,int * retheight,int * xpix,int * ypix)462 int GetTermSizeGWINSZ(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
463 {
464 	croak("TermSizeGWINSZ is not implemented on this architecture");
465         return 0;
466 }
467 #endif
468 
469 #if (!defined(TIOCGWINSZ) || defined(DONT_USE_GWINSZ)) && (defined(TIOCGSIZE) && !defined(DONT_USE_GSIZE))
GetTermSizeGSIZE(pTHX_ PerlIO * file,int * retwidth,int * retheight,int * xpix,int * ypix)470 int GetTermSizeGSIZE(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
471 {
472 	int handle=PerlIO_fileno(file);
473 
474 	struct ttysize w;
475 
476 	if (ioctl (handle, TIOCGSIZE, &w) == 0) {
477 		*retwidth=w.ts_cols; *retheight=w.ts_lines;
478 		*xpix=0/*w.ts_xxx*/; *ypix=0/*w.ts_yyy*/; return 0;
479 	}
480 	else {
481 		return -1; /* failure */
482 	}
483 }
484 #else
GetTermSizeGSIZE(pTHX_ PerlIO * file,int * retwidth,int * retheight,int * xpix,int * ypix)485 int GetTermSizeGSIZE(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
486 {
487 	croak("TermSizeGSIZE is not implemented on this architecture");
488         return 0;
489 }
490 #endif
491 
492 #ifdef USE_WIN32
GetTermSizeWin32(pTHX_ PerlIO * file,int * retwidth,int * retheight,int * xpix,int * ypix)493 int GetTermSizeWin32(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
494 {
495 	int handle=PerlIO_fileno(file);
496 	HANDLE whnd = (HANDLE)_get_osfhandle(handle);
497 	CONSOLE_SCREEN_BUFFER_INFO info;
498 
499 	if (GetConsoleScreenBufferInfo(whnd, &info)) {
500 		/* Logic: return maximum possible screen width, but return
501 		   only currently selected height */
502 		if (retwidth)
503 			*retwidth = info.dwMaximumWindowSize.X;
504 			/*info.srWindow.Right - info.srWindow.Left;*/
505 		if (retheight)
506 			*retheight = info.srWindow.Bottom - info.srWindow.Top;
507 		if (xpix)
508 			*xpix = 0;
509 		if (ypix)
510 			*ypix = 0;
511 		return 0;
512 	} else
513 		return -1;
514 }
515 #else
GetTermSizeWin32(pTHX_ PerlIO * file,int * retwidth,int * retheight,int * xpix,int * ypix)516 int GetTermSizeWin32(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
517 {
518 	croak("TermSizeWin32 is not implemented on this architecture");
519         return 0;
520 }
521 #endif /* USE_WIN32 */
522 
523 
termsizeoptions()524 STATIC int termsizeoptions() {
525 	return	0
526 #ifdef VIOMODE
527 		| 1
528 #endif
529 #if defined(TIOCGWINSZ) && !defined(DONT_USE_GWINSZ)
530 		| 2
531 #endif
532 #if defined(TIOCGSIZE) && !defined(DONT_USE_GSIZE)
533 		| 4
534 #endif
535 #if defined(USE_WIN32)
536 		| 8
537 #endif
538 		;
539 }
540 
541 
SetTerminalSize(pTHX_ PerlIO * file,int width,int height,int xpix,int ypix)542 int SetTerminalSize(pTHX_ PerlIO *file,int width,int height,int xpix,int ypix)
543 {
544 	int handle=PerlIO_fileno(file);
545 
546 #ifdef VIOMODE
547         return -1;
548 #else
549 
550 #if defined(TIOCSWINSZ) && !defined(DONT_USE_SWINSZ)
551 	char buffer[10];
552 	struct winsize w;
553 
554 	w.ws_col=width;
555 	w.ws_row=height;
556 	w.ws_xpixel=xpix;
557 	w.ws_ypixel=ypix;
558 	if (ioctl (handle, TIOCSWINSZ, &w) == 0) {
559 		sprintf(buffer,"%d",width); /* Be polite to our children */
560 		my_setenv("COLUMNS",buffer);
561 		sprintf(buffer,"%d",height);
562 		my_setenv("LINES",buffer);
563 		return 0;
564 	}
565 	else {
566 		croak("TIOCSWINSZ ioctl call to set terminal size failed: %s",Strerror(errno));
567 		return -1;
568 	}
569 #else
570 # if defined(TIOCSSIZE) && !defined(DONT_USE_SSIZE)
571 	char buffer[10];
572 	struct ttysize w;
573 
574 	w.ts_lines=height;
575 	w.ts_cols=width;
576 	w.ts_xxx=xpix;
577 	w.ts_yyy=ypix;
578 	if (ioctl (handle, TIOCSSIZE, &w) == 0) {
579 		sprintf(buffer,"%d",width);
580 		my_setenv("COLUMNS",buffer);
581 		sprintf(buffer,"%d",height);
582 		my_setenv("LINES",buffer);
583 		return 0;
584 	}
585 	else {
586 		croak("TIOCSSIZE ioctl call to set terminal size failed: %s",Strerror(errno));
587 		return -1;
588 	}
589 # else
590 	/*sprintf(buffer,"%d",width)   * Should we could do this and then *
591 	my_setenv("COLUMNS",buffer)    * said we succeeded?               *
592 	sprintf(buffer,"%d",height);
593 	my_setenv("LINES",buffer)*/
594 
595 	return -1; /* Fail */
596 # endif
597 #endif
598 #endif
599 
600 }
601 
602 STATIC const I32 terminal_speeds[] = {
603 #ifdef B50
604 	50, B50,
605 #endif
606 #ifdef B75
607 	75, B75,
608 #endif
609 #ifdef B110
610 	110, B110,
611 #endif
612 #ifdef B134
613 	134, B134,
614 #endif
615 #ifdef B150
616 	150, B150,
617 #endif
618 #ifdef B200
619 	200, B200,
620 #endif
621 #ifdef B300
622 	300, B300,
623 #endif
624 #ifdef B600
625 	600, B600,
626 #endif
627 #ifdef B1200
628 	1200, B1200,
629 #endif
630 #ifdef B1800
631 	1800, B1800,
632 #endif
633 #ifdef B2400
634 	2400, B2400,
635 #endif
636 #ifdef B4800
637 	4800, B4800,
638 #endif
639 #ifdef B9600
640 	9600, B9600,
641 #endif
642 #ifdef B19200
643 	19200, B19200,
644 #endif
645 #ifdef B38400
646 	38400, B38400,
647 #endif
648 #ifdef B57600
649 	57600, B57600,
650 #endif
651 #ifdef B115200
652 	115200, B115200,
653 #endif
654 #ifdef EXTA
655 	19200, EXTA,
656 #endif
657 #ifdef EXTB
658 	38400, EXTB,
659 #endif
660 #ifdef B0
661 	0,  B0,
662 #endif
663 	-1,-1
664 };
665 
getspeed(pTHX_ PerlIO * file,I32 * in,I32 * out)666 int getspeed(pTHX_ PerlIO *file,I32 *in, I32 *out)
667 {
668 	int handle=PerlIO_fileno(file);
669 #if defined(I_TERMIOS) || defined(I_TERMIO) || defined(I_SGTTY)
670 	int i;
671 #endif
672 #       ifdef I_TERMIOS
673 	/* Posixy stuff */
674 
675 	struct termios buf;
676 	tcgetattr(handle,&buf);
677 
678 	*in = *out = -1;
679 	*in = cfgetispeed(&buf);
680 	*out = cfgetospeed(&buf);
681 	for(i=0;terminal_speeds[i]!=-1;i+=2) {
682 		if(*in == terminal_speeds[i+1])
683 			{ *in = terminal_speeds[i]; break; }
684 	}
685 	for(i=0;terminal_speeds[i]!=-1;i+=2) {
686 		if(*out == terminal_speeds[i+1])
687 			{ *out = terminal_speeds[i]; break; }
688 	}
689 	return 0;
690 
691 #       else
692 #        ifdef I_TERMIO
693 	 /* SysV stuff */
694 	 struct termio buf;
695 
696 	 ioctl(handle,TCGETA,&buf);
697 
698 	*in=*out=-1;
699 	for(i=0;terminal_speeds[i]!=-1;i+=2) {
700 		if((buf.c_cflag & CBAUD) == terminal_speeds[i+1])
701 			{ *in=*out=terminal_speeds[i]; break; }
702 	}
703 	return 0;
704 
705 #        else
706 #         ifdef I_SGTTY
707 	  /* BSD stuff */
708 	  struct sgttyb buf;
709 
710 	  ioctl(handle,TIOCGETP,&buf);
711 
712 	*in=*out=-1;
713 
714 	for(i=0;terminal_speeds[i]!=-1;i+=2)
715 		if(buf.sg_ospeed == terminal_speeds[i+1])
716 			{ *out = terminal_speeds[i]; break; }
717 
718 	for(i=0;terminal_speeds[i]!=-1;i+=2)
719 		if(buf.sg_ispeed == terminal_speeds[i+1])
720 			{ *in = terminal_speeds[i]; break; }
721 
722 	return 0;
723 
724 
725 #         else
726 
727 	   /* No termio, termios or sgtty. I suppose we can try stty,
728 	      but it would be nice if you could get a better OS */
729 
730 	return -1;
731 
732 #         endif
733 #        endif
734 #       endif
735 }
736 
737 #ifdef WIN32
738 struct tbuffer { DWORD Mode; };
739 #else
740 #ifdef I_TERMIOS
741 #define USE_TERMIOS
742 #define tbuffer termios
743 #else
744 #ifdef I_TERMIO
745 #define USE_TERMIO
746 #define tbuffer termio
747 #else
748 #ifdef I_SGTTY
749 #define USE_SGTTY
750 struct tbuffer {
751 	  struct sgttyb buf;
752 #if defined(TIOCGETC)
753 	  struct tchars tchar;
754 #endif
755 #if defined(TIOCGLTC)
756 	  struct ltchars ltchar;
757 #endif
758 #if defined(TIOCLGET)
759 	  int local;
760 #endif
761 };
762 #else
763 #define USE_STTY
764 struct tbuffer {
765 	int dummy;
766 };
767 #endif
768 #endif
769 #endif
770 #endif
771 
772 static HV * filehash; /* Used to store the original terminal settings for each handle*/
773 static HV * modehash; /* Used to record the current terminal "mode" for each handle*/
774 
ReadMode(pTHX_ PerlIO * file,int mode)775 void ReadMode(pTHX_ PerlIO *file,int mode)
776 {
777 	dTHR;
778 	int handle;
779 	int firsttime;
780 	int oldmode;
781 	struct tbuffer work;
782 	struct tbuffer	savebuf;
783 
784 
785 	handle=PerlIO_fileno(file);
786 
787 	firsttime=!hv_exists(filehash, (char*)&handle, sizeof(int));
788 
789 
790 #	ifdef WIN32
791 
792 	if (!GetConsoleMode((HANDLE)_get_osfhandle(handle), &work.Mode))
793 	    croak("GetConsoleMode failed, LastError=|%d|",GetLastError());
794 
795 #	endif /* WIN32 */
796 
797 #       ifdef USE_TERMIOS
798 	/* Posixy stuff */
799 
800 	tcgetattr(handle,&work);
801 
802 
803 
804 #endif
805 #ifdef USE_TERMIO
806 	 /* SysV stuff */
807 
808 	 ioctl(handle,TCGETA,&work);
809 
810 
811 #endif
812 #ifdef USE_SGTTY
813 	  /* BSD stuff */
814 
815 	  ioctl(handle,TIOCGETP,&work.buf);
816 # 	  if defined(TIOCGETC)
817 	   ioctl(handle,TIOCGETC,&work.tchar);
818 #	  endif
819 #         if defined(TIOCLGET)
820 	   ioctl(handle,TIOCLGET,&work.local);
821 #	  endif
822 #	  if defined(TIOCGLTC)
823 	   ioctl(handle,TIOCGLTC,&work.ltchar);
824 #	  endif
825 
826 
827 #endif
828 
829 
830 	if(firsttime) {
831 		firsttime=0;
832 		memcpy((void*)&savebuf,(void*)&work,sizeof(struct tbuffer));
833 		if(!hv_store(filehash,(char*)&handle,sizeof(int),
834 			newSVpv((char*)&savebuf,sizeof(struct tbuffer)),0))
835 			croak("Unable to stash terminal settings.\n");
836 		if(!hv_store(modehash,(char*)&handle,sizeof(int),newSViv(0),0))
837 			croak("Unable to stash terminal settings.\n");
838 	} else {
839 		SV ** temp;
840 		if(!(temp=hv_fetch(filehash,(char*)&handle,sizeof(int),0)))
841 			croak("Unable to retrieve stashed terminal settings.\n");
842 		memcpy(&savebuf,SvPV(*temp,PL_na),sizeof(struct tbuffer));
843 		if(!(temp=hv_fetch(modehash,(char*)&handle,sizeof(int),0)))
844 			croak("Unable to retrieve stashed terminal mode.\n");
845 		oldmode=SvIV(*temp);
846 	}
847 
848 #ifdef WIN32
849 
850 	switch (mode) {
851 		case 5:
852 			/* Should 5 disable ENABLE_WRAP_AT_EOL_OUTPUT? */
853 		case 4:
854 			work.Mode &= ~(ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_OUTPUT);
855 			work.Mode |= 0;
856 			break;
857 		case 3:
858 			work.Mode &= ~(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT);
859 			work.Mode |= ENABLE_PROCESSED_INPUT|ENABLE_PROCESSED_OUTPUT;
860 			break;
861 		case 2:
862 			work.Mode &= ~(ENABLE_ECHO_INPUT);
863 			work.Mode |= ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_PROCESSED_OUTPUT;
864 			break;
865 		case 1:
866 			work.Mode &= ~(0);
867 			work.Mode |= ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT|ENABLE_PROCESSED_OUTPUT;
868 			break;
869 		case 0:
870 			work = savebuf;
871 			firsttime = 1;
872 			break;
873 	}
874 
875 	if (!SetConsoleMode((HANDLE)_get_osfhandle(handle), work.Mode))
876 	    croak("SetConsoleMode failed, LastError=|%d|",GetLastError());
877 
878 #endif /* WIN32 */
879 
880 
881 #ifdef USE_TERMIOS
882 
883 
884 /* What, me worry about standards? */
885 
886 #       if !defined (VMIN)
887 #		define VMIN VEOF
888 #       endif
889 
890 #	if !defined (VTIME)
891 #		define VTIME VEOL
892 #	endif
893 
894 #	if !defined (IXANY)
895 #		define IXANY (0)
896 #	endif
897 
898 #ifndef IEXTEN
899 #ifdef IDEFAULT
900 #define IEXTEN IDEFAULT
901 #endif
902 #endif
903 
904 /* XXX Is ONLCR in POSIX?.  The value of '4' seems to be the same for
905    both SysV and Sun, so it's probably rather general, and I'm not
906    aware of a POSIX way to do this otherwise.
907 */
908 #ifndef ONLCR
909 # define ONLCR 4
910 #endif
911 
912 #ifndef IMAXBEL
913 #define IMAXBEL 0
914 #endif
915 #ifndef ECHOE
916 #define ECHOE 0
917 #endif
918 #ifndef ECHOK
919 #define ECHOK 0
920 #endif
921 #ifndef ECHONL
922 #define ECHONL 0
923 #endif
924 #ifndef ECHOPRT
925 #define ECHOPRT 0
926 #endif
927 #ifndef FLUSHO
928 #define FLUSHO 0
929 #endif
930 #ifndef PENDIN
931 #define PENDIN 0
932 #endif
933 #ifndef ECHOKE
934 #define ECHOKE 0
935 #endif
936 #ifndef ONLCR
937 #define ONLCR 0
938 #endif
939 #ifndef OCRNL
940 #define OCRNL 0
941 #endif
942 #ifndef ONLRET
943 #define ONLRET 0
944 #endif
945 #ifndef IUCLC
946 #define IUCLC 0
947 #endif
948 #ifndef OPOST
949 #define OPOST 0
950 #endif
951 #ifndef OLCUC
952 #define OLCUC 0
953 #endif
954 #ifndef ECHOCTL
955 #define ECHOCTL 0
956 #endif
957 #ifndef XCASE
958 #define XCASE 0
959 #endif
960 #ifndef BRKINT
961 #define BRKINT 0
962 #endif
963 
964 
965 	if(mode==5) {
966 		/*\
967 		 *  Disable everything except parity if needed.
968 		\*/
969 
970 		/* Hopefully, this should put the tty into unbuffered mode
971 		with signals and control characters (both posixy and normal)
972 		disabled, along with flow control. Echo should be off.
973 		CR/LF is not translated, along with 8-bit/parity */
974 
975 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
976 
977 		work.c_lflag &= ~(ICANON|ISIG|IEXTEN );
978 		work.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ECHOCTL);
979 		work.c_lflag &= ~(ECHOPRT|ECHOKE|FLUSHO|PENDIN|XCASE);
980 		work.c_lflag |= NOFLSH;
981         work.c_iflag &= ~(IXOFF|IXON|IXANY|ICRNL|IMAXBEL|BRKINT);
982 
983 		if(((work.c_iflag & INPCK) != INPCK) ||
984                    ((work.c_cflag & PARENB) != PARENB)) {
985 			work.c_iflag &= ~ISTRIP;
986 			work.c_iflag |= IGNPAR;
987 			work.c_iflag &= ~PARMRK;
988 		}
989 		work.c_oflag &= ~(OPOST |ONLCR|OCRNL|ONLRET);
990 
991 		work.c_cc[VTIME] = 0;
992 		work.c_cc[VMIN] = 1;
993 	}
994 	else if(mode==4) {
995 		/* Hopefully, this should put the tty into unbuffered mode
996 		with signals and control characters (both posixy and normal)
997 		disabled, along with flow control. Echo should be off.
998 		About the only thing left unchanged is 8-bit/parity */
999 
1000 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1001 
1002 		/*work.c_iflag = savebuf.c_iflag;*/
1003 		work.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO);
1004 		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
1005         work.c_iflag &= ~(IXON | IXANY | BRKINT);
1006 		work.c_oflag = savebuf.c_oflag;
1007 		work.c_cc[VTIME] = 0;
1008 		work.c_cc[VMIN] = 1;
1009 	}
1010 	else if(mode==3)
1011 	{
1012 		/* This should be an unbuffered mode with signals and control
1013 		characters enabled, as should be flow control. Echo should
1014 		still be off */
1015 
1016 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1017 
1018 		work.c_iflag = savebuf.c_iflag;
1019 		work.c_lflag &= ~(ICANON | ECHO);
1020 		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
1021 		work.c_lflag |= ISIG | IEXTEN;
1022 		/*work.c_iflag &= ~(IXON | IXOFF | IXANY);
1023 		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
1024 		work.c_oflag = savebuf.c_oflag;*/
1025 		work.c_cc[VTIME] = 0;
1026 		work.c_cc[VMIN] = 1;
1027 	}
1028 	else if(mode==2)
1029 	{
1030 		/* This should be an unbuffered mode with signals and control
1031 		characters enabled, as should be flow control. Echo should
1032 		still be off */
1033 
1034 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1035 
1036 		work.c_iflag = savebuf.c_iflag;
1037 		work.c_lflag |= ICANON|ISIG|IEXTEN;
1038 		work.c_lflag &= ~ECHO;
1039 		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
1040 		/*work.c_iflag &= ~(IXON |IXOFF|IXANY);
1041 		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
1042 		work.c_oflag = savebuf.c_oflag;
1043 		work.c_cc[VTIME] = savebuf.c_cc[VTIME];
1044 		work.c_cc[VMIN] = savebuf.c_cc[VMIN];*/
1045 	}
1046 	else if(mode==1)
1047 	{
1048 		/* This should be an unbuffered mode with signals and control
1049 		characters enabled, as should be flow control. Echo should
1050 		still be off */
1051 
1052 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1053 
1054 		work.c_iflag = savebuf.c_iflag;
1055 		work.c_lflag |= ICANON|ECHO|ISIG|IEXTEN;
1056 		/*work.c_iflag &= ~(IXON |IXOFF|IXANY);
1057 		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
1058 		work.c_oflag = savebuf.c_oflag;
1059 		work.c_cc[VTIME] = savebuf.c_cc[VTIME];
1060 		work.c_cc[VMIN] = savebuf.c_cc[VMIN];*/
1061 	}
1062 	else if(mode==0){
1063 		/*work.c_lflag &= ~BITMASK;
1064 		work.c_lflag |= savebuf.c_lflag & BITMASK;
1065 		work.c_oflag = savebuf.c_oflag;
1066 		work.c_cc[VTIME] = savebuf.c_cc[VTIME];
1067 		work.c_cc[VMIN] = savebuf.c_cc[VMIN];
1068 		work.c_iflag = savebuf.c_iflag;
1069 		work.c_iflag &= ~(IXON|IXOFF|IXANY);
1070 		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);*/
1071 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1072 		/*Copy(&work,&savebuf,1,sizeof(struct tbuffer));*/
1073 
1074 		firsttime=1;
1075 	}
1076 	else
1077 	{
1078 		croak("ReadMode %d is not implemented on this architecture.",mode);
1079 		return;
1080 	}
1081 
1082 
1083 	/* If switching from a "lower power" mode to a higher one, keep the
1084 	data that may be in the queue, as it can easily be type-ahead. On
1085 	switching to a lower mode from a higher one, however, flush the queue
1086 	so that raw keystrokes won't hit an unexpecting program */
1087 
1088 	if(DisableFlush || oldmode<=mode)
1089 		tcsetattr(handle,TCSANOW,&work);
1090 	else
1091 		tcsetattr(handle,TCSAFLUSH,&work);
1092 
1093 	/*tcsetattr(handle,TCSANOW,&work);*/ /* It might be better to FLUSH
1094 					   when changing gears to a lower mode,
1095 					   and only use NOW for higher modes.
1096 					*/
1097 
1098 
1099 #endif
1100 #ifdef USE_TERMIO
1101 
1102 /* What, me worry about standards? */
1103 
1104 #	 if !defined (IXANY)
1105 #                define IXANY (0)
1106 #        endif
1107 
1108 #ifndef ECHOE
1109 #define ECHOE 0
1110 #endif
1111 #ifndef ECHOK
1112 #define ECHOK 0
1113 #endif
1114 #ifndef ECHONL
1115 #define ECHONL 0
1116 #endif
1117 #ifndef XCASE
1118 #define XCASE 0
1119 #endif
1120 #ifndef BRKINT
1121 #define BRKINT 0
1122 #endif
1123 
1124 
1125 
1126 	 if(mode==5) {
1127 		/* This mode should be echo disabled, signals disabled,
1128 		flow control disabled, and unbuffered. CR/LF translation
1129    	 	is off, and 8 bits if possible */
1130 
1131 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1132 
1133 		work.c_lflag &= ~(ECHO | ISIG | ICANON | XCASE);
1134 		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL | TRK_IDEFAULT);
1135 		work.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | BRKINT);
1136 		if((work.c_cflag | PARENB)!=PARENB ) {
1137 			work.c_iflag &= ~(ISTRIP|INPCK);
1138 			work.c_iflag |= IGNPAR;
1139 		}
1140 		work.c_oflag &= ~(OPOST|ONLCR);
1141 		work.c_cc[VMIN] = 1;
1142 		work.c_cc[VTIME] = 1;
1143 	 }
1144 	 else if(mode==4) {
1145 		/* This mode should be echo disabled, signals disabled,
1146 		flow control disabled, and unbuffered. Parity is not
1147 		touched. */
1148 
1149 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1150 
1151 		work.c_lflag &= ~(ECHO | ISIG | ICANON);
1152 		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL TRK_IDEFAULT);
1153 		work.c_iflag = savebuf.c_iflag;
1154 		work.c_iflag &= ~(IXON | IXOFF | IXANY | BRKINT);
1155 		work.c_oflag = savebuf.c_oflag;
1156 		work.c_cc[VMIN] = 1;
1157 		work.c_cc[VTIME] = 1;
1158 	 }
1159 	 else if(mode==3) {
1160 		/* This mode tries to have echo off, signals enabled,
1161 		flow control as per the original setting, and unbuffered. */
1162 
1163 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1164 
1165 		work.c_lflag &= ~(ECHO | ICANON);
1166 		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL | TRK_IDEFAULT);
1167 		work.c_lflag |= ISIG;
1168 		work.c_iflag = savebuf.c_iflag;
1169 		work.c_iflag &= ~(IXON | IXOFF | IXANY);
1170 		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
1171 		work.c_oflag = savebuf.c_oflag;
1172 		work.c_cc[VMIN] = 1;
1173 		work.c_cc[VTIME] = 1;
1174 	 }
1175 	 else if(mode==2) {
1176 		/* This mode tries to set echo on, signals on, and buffering
1177 		on, with flow control set to whatever it was originally. */
1178 
1179 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1180 
1181 		work.c_lflag |= (ISIG | ICANON);
1182 		work.c_lflag &= ~ECHO;
1183 		work.c_lflag &= ~(ECHOE | ECHOK | ECHONL | TRK_IDEFAULT);
1184 		work.c_iflag = savebuf.c_iflag;
1185 		work.c_iflag &= ~(IXON | IXOFF | IXANY);
1186 		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
1187 		work.c_oflag = savebuf.c_oflag;
1188 		work.c_cc[VMIN] = savebuf.c_cc[VMIN];
1189 		work.c_cc[VTIME] = savebuf.c_cc[VTIME];
1190 
1191 		/* This assumes turning ECHO and ICANON back on is
1192 		   sufficient to re-enable cooked mode. If this is a
1193 		   problem, complain to me */
1194 
1195 		/* What the heck. We're already saving the entire buf, so
1196 		I'm now going to reset VMIN and VTIME too. Hope this works
1197 		properly */
1198 
1199 	 }
1200 	 else if(mode==1) {
1201 		/* This mode tries to set echo on, signals on, and buffering
1202 		on, with flow control set to whatever it was originally. */
1203 
1204 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1205 
1206 		work.c_lflag |= (ECHO | ISIG | ICANON);
1207       work.c_iflag &= ~TRK_IDEFAULT;
1208 		work.c_iflag = savebuf.c_iflag;
1209 		work.c_iflag &= ~(IXON | IXOFF | IXANY);
1210 		work.c_iflag |= savebuf.c_iflag & (IXON|IXOFF|IXANY);
1211 		work.c_oflag = savebuf.c_oflag;
1212 		work.c_cc[VMIN] = savebuf.c_cc[VMIN];
1213 		work.c_cc[VTIME] = savebuf.c_cc[VTIME];
1214 
1215 		/* This assumes turning ECHO and ICANON back on is
1216 		   sufficient to re-enable cooked mode. If this is a
1217 		   problem, complain to me */
1218 
1219 		/* What the heck. We're already saving the entire buf, so
1220 		I'm now going to reset VMIN and VTIME too. Hope this works
1221 		properly */
1222 	}
1223 	 else if(mode==0) {
1224 		/* Put things back the way they were */
1225 
1226 		/*work.c_lflag = savebuf.c_lflag;
1227 		work.c_iflag = savebuf.c_iflag;
1228 		work.c_oflag = savebuf.c_oflag;
1229 		work.c_cc[VMIN] = savebuf.c_cc[VMIN];
1230 		work.c_cc[VTIME] = savebuf.c_cc[VTIME];*/
1231 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1232 		firsttime=1;
1233 	 }
1234  	 else
1235  	 {
1236 		croak("ReadMode %d is not implemented on this architecture.",mode);
1237 		return;
1238 	 }
1239 
1240 
1241 	 if(DisableFlush || oldmode<=mode)
1242 		ioctl(handle,TCSETA,&work);
1243 	 else
1244 		ioctl(handle,TCSETAF,&work);
1245 
1246 #endif
1247 #ifdef USE_SGTTY
1248 
1249 
1250 	  if(mode==5) {
1251 		/* Unbuffered, echo off, signals off, flow control off */
1252 		/* CR-CR/LF mode off too, and 8-bit path enabled. */
1253 #	 	if defined(TIOCLGET) && defined(LPASS8)
1254 		 if((work.buf.sg_flags & (EVENP|ODDP))==0 ||
1255 		    (work.buf.sg_flags & (EVENP|ODDP))==(EVENP|ODDP))
1256 		 	 work.local |= LPASS8; /* If parity isn't being used, use 8 bits */
1257 #		endif
1258 	  	work.buf.sg_flags &= ~(ECHO|CRMOD);
1259 	  	work.buf.sg_flags |= (RAW|CBREAK);
1260 # 	  	if defined(TIOCGETC)
1261 		 work.tchar.t_intrc = -1;
1262 		 work.tchar.t_quitc = -1;
1263 		 work.tchar.t_startc= -1;
1264 		 work.tchar.t_stopc = -1;
1265 		 work.tchar.t_eofc  = -1;
1266 		 work.tchar.t_brkc  = -1;
1267 #		endif
1268 #		if defined(TIOCGLTC)
1269 		 work.ltchar.t_suspc= -1;
1270 		 work.ltchar.t_dsuspc= -1;
1271 		 work.ltchar.t_rprntc= -1;
1272 		 work.ltchar.t_flushc= -1;
1273 		 work.ltchar.t_werasc= -1;
1274 		 work.ltchar.t_lnextc= -1;
1275 #		endif
1276 	  }
1277 	  else if(mode==4) {
1278 		/* Unbuffered, echo off, signals off, flow control off */
1279 	  	work.buf.sg_flags &= ~(ECHO|RAW);
1280 	  	work.buf.sg_flags |= (CBREAK|CRMOD);
1281 #	 	if defined(TIOCLGET)
1282 		 work.local=savebuf.local;
1283 #		endif
1284 # 	  	if defined(TIOCGETC)
1285 		 work.tchar.t_intrc = -1;
1286 		 work.tchar.t_quitc = -1;
1287 		 work.tchar.t_startc= -1;
1288 		 work.tchar.t_stopc = -1;
1289 		 work.tchar.t_eofc  = -1;
1290 		 work.tchar.t_brkc  = -1;
1291 #		endif
1292 #		if defined(TIOCGLTC)
1293 		 work.ltchar.t_suspc= -1;
1294 		 work.ltchar.t_dsuspc= -1;
1295 		 work.ltchar.t_rprntc= -1;
1296 		 work.ltchar.t_flushc= -1;
1297 		 work.ltchar.t_werasc= -1;
1298 		 work.ltchar.t_lnextc= -1;
1299 #		endif
1300 	  }
1301 	  else if(mode==3) {
1302 		/* Unbuffered, echo off, signals on, flow control on */
1303 		work.buf.sg_flags &= ~(RAW|ECHO);
1304 	  	work.buf.sg_flags |= CBREAK|CRMOD;
1305 #	 	if defined(TIOCLGET)
1306 		 work.local=savebuf.local;
1307 #		endif
1308 #		if defined(TIOCGLTC)
1309 		 work.tchar = savebuf.tchar;
1310 #		endif
1311 #		if defined(TIOCGLTC)
1312 		 work.ltchar = savebuf.ltchar;
1313 #		endif
1314  	  }
1315 	  else if(mode==2) {
1316 		/* Buffered, echo on, signals on, flow control on */
1317 		work.buf.sg_flags &= ~(RAW|CBREAK);
1318 		work.buf.sg_flags |= CRMOD;
1319 		work.buf.sg_flags &= ~ECHO;
1320 #	 	if defined(TIOCLGET)
1321 		 work.local=savebuf.local;
1322 #		endif
1323 #		if defined(TIOCGLTC)
1324 		 work.tchar = savebuf.tchar;
1325 #		endif
1326 #		if defined(TIOCGLTC)
1327 		 work.ltchar = savebuf.ltchar;
1328 #		endif
1329 	  }
1330 	  else if(mode==1) {
1331 		/* Buffered, echo on, signals on, flow control on */
1332 		work.buf.sg_flags &= ~(RAW|CBREAK);
1333 		work.buf.sg_flags |= ECHO|CRMOD;
1334 #	 	if defined(TIOCLGET)
1335 		 work.local=savebuf.local;
1336 #		endif
1337 #		if defined(TIOCGLTC)
1338 		 work.tchar = savebuf.tchar;
1339 #		endif
1340 #		if defined(TIOCGLTC)
1341 		 work.ltchar = savebuf.ltchar;
1342 #		endif
1343 	  }
1344 	  else if(mode==0){
1345 		/* Original settings */
1346 #if 0
1347 		work.buf.sg_flags &= ~(RAW|CBREAK|ECHO|CRMOD);
1348 		work.buf.sg_flags |= savebuf.sg_flags & (RAW|CBREAK|ECHO|CRMOD);
1349 #	 	if defined(TIOCLGET)
1350 		 work.local=savebuf.local;
1351 #		endif
1352 #		if defined(TIOCGLTC)
1353 		 work.tchar = savebuf.tchar;
1354 #		endif
1355 #		if defined(TIOCGLTC)
1356 		 work.ltchar = savebuf.ltchar;
1357 #		endif
1358 #endif
1359 		memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1360 		firsttime=1;
1361 	  }
1362  	  else
1363  	  {
1364 		croak("ReadMode %d is not implemented on this architecture.",mode);
1365 		return;
1366 	  }
1367 #if defined(TIOCLSET)
1368 	  ioctl(handle,TIOCLSET,&work.local);
1369 #endif
1370 #if defined(TIOCSETC)
1371 	  ioctl(handle,TIOCSETC,&work.tchar);
1372 #endif
1373 #	  if defined(TIOCGLTC)
1374 	   ioctl(handle,TIOCSLTC,&work.ltchar);
1375 #	  endif
1376 	  if(DisableFlush || oldmode<=mode)
1377 	  	ioctl(handle,TIOCSETN,&work.buf);
1378 	  else
1379 		ioctl(handle,TIOCSETP,&work.buf);
1380 #endif
1381 #ifdef USE_STTY
1382 
1383 	   /* No termio, termios or sgtty. I suppose we can try stty,
1384 	      but it would be nice if you could get a better OS */
1385 
1386 	   if(mode==5)
1387 		system("/bin/stty  raw -cbreak -isig -echo -ixon -onlcr -icrnl -brkint");
1388 	   else if(mode==4)
1389 		system("/bin/stty -raw  cbreak -isig -echo -ixon  onlcr  icrnl -brkint");
1390 	   else if(mode==3)
1391 		system("/bin/stty -raw  cbreak  isig -echo  ixon  onlcr  icrnl  brkint");
1392 	   else if(mode==2)
1393 		system("/bin/stty -raw -cbreak  isig  echo  ixon  onlcr  icrnl  brkint");
1394 	   else if(mode==1)
1395 		system("/bin/stty -raw -cbreak  isig -echo  ixon  onlcr  icrnl  brkint");
1396 	   else if(mode==0)
1397 		system("/bin/stty -raw -cbreak  isig  echo  ixon  onlcr  icrnl  brkint");
1398 
1399 	   /* Those probably won't work, but they couldn't hurt
1400               at this point */
1401 
1402 #endif
1403 
1404 	/*warn("Mode set to %d.\n",mode);*/
1405 
1406 	if( firsttime ) {
1407 		(void)hv_delete(filehash,(char*)&handle,sizeof(int),0);
1408 		(void)hv_delete(modehash,(char*)&handle,sizeof(int),0);
1409 	} else {
1410 		if(!hv_store(modehash,(char*)&handle,sizeof(int),
1411 			newSViv(mode),0))
1412 			croak("Unable to stash terminal settings.\n");
1413 	}
1414 
1415 }
1416 
1417 #ifdef USE_PERLIO
1418 
1419 /* Make use of a recent addition to Perl, if possible */
1420 # define FCOUNT(f) PerlIO_get_cnt(f)
1421 #else
1422 
1423  /* Make use of a recent addition to Configure, if possible */
1424 # ifdef USE_STDIO_PTR
1425 #  define FCOUNT(f) PerlIO_get_cnt(f)
1426 # else
1427   /* This bit borrowed from pp_sys.c. Complain to Larry if it's broken. */
1428   /* If any of this works PerlIO_get_cnt() will too ... NI-S */
1429 #  if defined(USE_STD_STDIO) || defined(atarist) /* this will work with atariST */
1430 #   define FBASE(f) ((f)->_base)
1431 #   define FSIZE(f) ((f)->_cnt + ((f)->_ptr - (f)->_base))
1432 #   define FPTR(f) ((f)->_ptr)
1433 #   define FCOUNT(f) ((f)->_cnt)
1434 #  else
1435 #   if defined(USE_LINUX_STDIO)
1436 #     define FBASE(f) ((f)->_IO_read_base)
1437 #     define FSIZE(f) ((f)->_IO_read_end - FBASE(f))
1438 #     define FPTR(f) ((f)->_IO_read_ptr)
1439 #     define FCOUNT(f) ((f)->_IO_read_end - FPTR(f))
1440 #   endif
1441 #  endif
1442 # endif
1443 #endif
1444 
1445 /* This is for the best, I'm afraid. */
1446 #if !defined(FCOUNT)
1447 # ifdef Have_select
1448 #  undef Have_select
1449 # endif
1450 # ifdef Have_poll
1451 #  undef Have_poll
1452 # endif
1453 #endif
1454 
1455 /* Note! If your machine has a bolixed up select() call that doesn't
1456 understand this syntax, either fix the checkwaiting call below, or define
1457 DONT_USE_SELECT. */
1458 
1459 #ifdef Have_select
selectfile(pTHX_ PerlIO * file,double delay)1460 int selectfile(pTHX_ PerlIO *file,double delay)
1461 {
1462 	struct timeval t;
1463 	int handle=PerlIO_fileno(file);
1464 
1465 	/*char buf[32];
1466 	Select_fd_set_t fd=(Select_fd_set_t)&buf[0];*/
1467 
1468 	fd_set fd;
1469 	if (PerlIO_fast_gets(file) && PerlIO_get_cnt(file) > 0)
1470 		return 1;
1471 
1472 	/*t.tv_sec=t.tv_usec=0;*/
1473 
1474         if (delay < 0.0)
1475             delay = 0.0;
1476         t.tv_sec = (long)delay;
1477         delay -= (double)t.tv_sec;
1478         t.tv_usec = (long)(delay * 1000000.0);
1479 
1480 	FD_ZERO(&fd);
1481 	FD_SET(handle,&fd);
1482 	if(select(handle+1,(Select_fd_set_t)&fd,
1483 			   (Select_fd_set_t)0,
1484 			   (Select_fd_set_t)&fd, &t)) return -1;
1485 	else return 0;
1486 }
1487 
1488 #else
selectfile(pTHX_ PerlIO * file,double delay)1489 int selectfile(pTHX_ PerlIO *file, double delay)
1490 {
1491 	croak("select is not supported on this architecture");
1492 	return 0;
1493 }
1494 #endif
1495 
1496 #ifdef Have_nodelay
setnodelay(pTHX_ PerlIO * file,int mode)1497 int setnodelay(pTHX_ PerlIO *file, int mode)
1498 {
1499 	int handle=PerlIO_fileno(file);
1500 	int flags;
1501 	flags=fcntl(handle,F_GETFL,0);
1502 	if(mode)
1503 		flags|=O_NODELAY;
1504 	else
1505 		flags&=~O_NODELAY;
1506 	fcntl(handle,F_SETFL,flags);
1507 	return 0;
1508 }
1509 
1510 #else
setnodelay(pTHX_ PerlIO * file,int mode)1511 int setnodelay(pTHX_ PerlIO *file, int mode)
1512 {
1513 	croak("setnodelay is not supported on this architecture");
1514 	return 0;
1515 }
1516 #endif
1517 
1518 #ifdef Have_poll
pollfile(pTHX_ pTHX_ PerlIO * file,double delay)1519 int pollfile(pTHX_ pTHX_ PerlIO *file,double delay)
1520 {
1521 	int handle=PerlIO_fileno(file);
1522 	struct pollfd fds;
1523 	if (PerlIO_fast_gets(f) && PerlIO_get_cnt(f) > 0)
1524 		return 1;
1525 	if(delay<0.0) delay = 0.0;
1526 	fds.fd=handle;
1527 	fds.events=POLLIN;
1528 	fds.revents=0;
1529 	return (poll(&fds,1,(long)(delay * 1000.0))>0);
1530 }
1531 #else
pollfile(pTHX_ PerlIO * file,double delay)1532 int pollfile(pTHX_ PerlIO *file,double delay)
1533 {
1534 	croak("pollfile is not supported on this architecture");
1535 	return 0;
1536 }
1537 #endif
1538 
1539 #ifdef WIN32
1540 
1541 /*
1542 
1543  This portion of the Win32 code is partially borrowed from a version of PDCurses.
1544 
1545 */
1546 
1547 typedef struct {
1548     int repeatCount;
1549     int vKey;
1550     int vScan;
1551     int ascii;
1552     int control;
1553 } win32_key_event_t;
1554 
1555 #define KEY_PUSH(I, K) { events[I].repeatCount = 1; events[I].ascii = K; }
1556 #define KEY_PUSH3(K1, K2, K3) \
1557     do { \
1558              eventCount = 0;            \
1559              KEY_PUSH(2, K1);           \
1560              KEY_PUSH(1, K2);           \
1561              KEY_PUSH(0, K3);           \
1562              eventCount = 3;            \
1563              goto again;                \
1564     } while (0)
1565 
1566 #define KEY_PUSH4(K1, K2, K3, K4) \
1567     do { \
1568              eventCount = 0;            \
1569              KEY_PUSH(3, K1);           \
1570              KEY_PUSH(2, K2);           \
1571              KEY_PUSH(1, K3);           \
1572              KEY_PUSH(0, K4);           \
1573              eventCount = 4;            \
1574              goto again;                \
1575     } while (0)
1576 
Win32PeekChar(pTHX_ PerlIO * file,double delay,char * key)1577 int Win32PeekChar(pTHX_ PerlIO *file,double delay,char *key)
1578 {
1579 	int handle;
1580 	HANDLE whnd;
1581 	INPUT_RECORD record;
1582 	DWORD readRecords;
1583 
1584 #if 0
1585 	static int keyCount = 0;
1586 	static char lastKey = 0;
1587 #endif
1588 
1589 #define MAX_EVENTS 4
1590     static int eventCount = 0;
1591     static win32_key_event_t events[MAX_EVENTS];
1592     int keyCount;
1593 
1594 	file = STDIN;
1595 
1596 	handle = PerlIO_fileno(file);
1597 	whnd = /*GetStdHandle(STD_INPUT_HANDLE)*/(HANDLE)_get_osfhandle(handle);
1598 
1599 
1600 again:
1601 #if 0
1602 	if (keyCount > 0) {
1603 		keyCount--;
1604 		*key = lastKey;
1605 	    return TRUE;
1606 	}
1607 #endif
1608 
1609     /* printf("eventCount: %d\n", eventCount); */
1610     if (eventCount) {
1611         /* printf("key %d; repeatCount %d\n", *key, events[eventCount - 1].repeatCount); */
1612         *key = events[eventCount - 1].ascii;
1613         events[eventCount - 1].repeatCount--;
1614         if (events[eventCount - 1].repeatCount <= 0) {
1615             eventCount--;
1616         }
1617         return TRUE;
1618     }
1619 
1620 	if (delay > 0) {
1621 		if (WaitForSingleObject(whnd, delay * 1000) != WAIT_OBJECT_0)
1622 		{
1623 			return FALSE;
1624 		}
1625 	}
1626 
1627 	if (delay != 0) {
1628 		PeekConsoleInput(whnd, &record, 1, &readRecords);
1629 		if (readRecords == 0) {
1630 			return(FALSE);
1631         }
1632 	}
1633 
1634 	ReadConsoleInput(whnd, &record, 1, &readRecords);
1635 	switch(record.EventType)
1636    {
1637     case KEY_EVENT:
1638 		/* printf("\nkeyDown = %d, repeat = %d, vKey = %d, vScan = %d, ASCII = %d, Control = %d\n",
1639 			record.Event.KeyEvent.bKeyDown,
1640 			record.Event.KeyEvent.wRepeatCount,
1641 			record.Event.KeyEvent.wVirtualKeyCode,
1642 			record.Event.KeyEvent.wVirtualScanCode,
1643 			record.Event.KeyEvent.uChar.AsciiChar,
1644 			record.Event.KeyEvent.dwControlKeyState); */
1645 
1646          if (record.Event.KeyEvent.bKeyDown == FALSE)
1647             goto again;                        /* throw away KeyUp events */
1648 
1649          if (record.Event.KeyEvent.wVirtualKeyCode == 38) { /* up */
1650              KEY_PUSH3(27, 91, 65);
1651          }
1652          if (record.Event.KeyEvent.wVirtualKeyCode == 40) { /* down */
1653              KEY_PUSH3(27, 91, 66);
1654          }
1655          if (record.Event.KeyEvent.wVirtualKeyCode == 39) { /* right */
1656              KEY_PUSH3(27, 91, 67);
1657          }
1658          if (record.Event.KeyEvent.wVirtualKeyCode == 37) { /* left */
1659              KEY_PUSH3(27, 91, 68);
1660          }
1661          if (record.Event.KeyEvent.wVirtualKeyCode == 33) { /* page up */
1662              KEY_PUSH3(27, 79, 121);
1663          }
1664          if (record.Event.KeyEvent.wVirtualKeyCode == 34) { /* page down */
1665              KEY_PUSH3(27, 79, 115);
1666          }
1667          if (record.Event.KeyEvent.wVirtualKeyCode == 36) { /* home */
1668              KEY_PUSH4(27, 91, 49, 126);
1669          }
1670          if (record.Event.KeyEvent.wVirtualKeyCode == 35) { /* end */
1671              KEY_PUSH4(27, 91, 52, 126);
1672          }
1673          if (record.Event.KeyEvent.wVirtualKeyCode == 45) { /* insert */
1674              KEY_PUSH4(27, 91, 50, 126);
1675          }
1676          if (record.Event.KeyEvent.wVirtualKeyCode == 46) { /* delete */
1677              KEY_PUSH4(27, 91, 51, 126);
1678          }
1679 
1680          if (record.Event.KeyEvent.wVirtualKeyCode == 16
1681          ||  record.Event.KeyEvent.wVirtualKeyCode == 17
1682          ||  record.Event.KeyEvent.wVirtualKeyCode == 18
1683          ||  record.Event.KeyEvent.wVirtualKeyCode == 20
1684          ||  record.Event.KeyEvent.wVirtualKeyCode == 144
1685          ||  record.Event.KeyEvent.wVirtualKeyCode == 145)
1686             goto again;  /* throw away shift/alt/ctrl key only key events */
1687          keyCount = record.Event.KeyEvent.wRepeatCount;
1688 		 break;
1689     default:
1690          keyCount = 0;
1691          goto again;
1692          break;
1693    }
1694 
1695  *key = record.Event.KeyEvent.uChar.AsciiChar;
1696  keyCount--;
1697 
1698  if (keyCount) {
1699      events[0].repeatCount = keyCount;
1700      events[0].ascii = *key;
1701      eventCount = 1;
1702  }
1703 
1704  return(TRUE);
1705 
1706  /* again:
1707 	return (FALSE);
1708 	*/
1709 
1710 
1711 }
1712 #else
Win32PeekChar(pTHX_ PerlIO * file,double delay,char * key)1713 int Win32PeekChar(pTHX_ PerlIO *file, double delay,char *key)
1714 {
1715 	croak("Win32PeekChar is not supported on this architecture");
1716 	return 0;
1717 }
1718 #endif
1719 
1720 
blockoptions()1721 STATIC int blockoptions() {
1722 	return	0
1723 #ifdef Have_nodelay
1724 		| 1
1725 #endif
1726 #ifdef Have_poll
1727 		| 2
1728 #endif
1729 #ifdef Have_select
1730 		| 4
1731 #endif
1732 #ifdef USE_WIN32
1733 		| 8
1734 #endif
1735 		;
1736 }
1737 
termoptions()1738 STATIC int termoptions() {
1739 	int i=0;
1740 #ifdef USE_TERMIOS
1741 	i=1;
1742 #endif
1743 #ifdef USE_TERMIO
1744 	i=2;
1745 #endif
1746 #ifdef USE_SGTTY
1747 	i=3;
1748 #endif
1749 #ifdef USE_STTY
1750 	i=4;
1751 #endif
1752 #ifdef USE_WIN32
1753 	i=5;
1754 #endif
1755 	return i;
1756 }
1757 
1758 
1759 
1760 MODULE = Term::ReadKey		PACKAGE = Term::ReadKey
1761 
1762 int
1763 selectfile(file,delay)
1764 	InputStream	file
1765 	double	delay
1766 CODE:
1767 	RETVAL = selectfile(aTHX_ file, delay);
1768 OUTPUT:
1769 	RETVAL
1770 
1771 # Clever, eh?
1772 void
1773 SetReadMode(mode,file=STDIN)
1774 	int	mode
1775 	InputStream	file
1776 	CODE:
1777 	{
1778 		ReadMode(aTHX_ file,mode);
1779 	}
1780 
1781 int
1782 setnodelay(file,mode)
1783 	InputStream	file
1784 	int	mode
1785 CODE:
1786 	RETVAL = setnodelay(aTHX_ file, mode);
1787 OUTPUT:
1788 	RETVAL
1789 
1790 int
1791 pollfile(file,delay)
1792 	InputStream	file
1793 	double	delay
1794 CODE:
1795 	RETVAL = pollfile(aTHX_ file, delay);
1796 OUTPUT:
1797 	RETVAL
1798 
1799 SV *
Win32PeekChar(file,delay)1800 Win32PeekChar(file, delay)
1801 	InputStream	file
1802 	double	delay
1803 	CODE:
1804 	{
1805 		char key;
1806 		if (Win32PeekChar(aTHX_ file, delay, &key))
1807 			RETVAL = newSVpv(&key, 1);
1808 		else
1809 			RETVAL = newSVsv(&PL_sv_undef);
1810 	}
1811 	OUTPUT:
1812 	RETVAL
1813 
1814 int
blockoptions()1815 blockoptions()
1816 
1817 int
1818 termoptions()
1819 
1820 int
1821 termsizeoptions()
1822 
1823 void
1824 GetTermSizeWin32(file=STDIN)
1825 	InputStream	file
1826 	PPCODE:
1827 	{
1828 		int x,y,xpix,ypix;
1829 		if( GetTermSizeWin32(aTHX_ file,&x,&y,&xpix,&ypix)==0)
1830 		{
1831 			EXTEND(sp, 4);
1832 			PUSHs(sv_2mortal(newSViv((IV)x)));
1833 			PUSHs(sv_2mortal(newSViv((IV)y)));
1834 			PUSHs(sv_2mortal(newSViv((IV)xpix)));
1835 			PUSHs(sv_2mortal(newSViv((IV)ypix)));
1836 		}
1837 		else
1838 		{
1839 			ST(0) = sv_newmortal();
1840 		}
1841 	}
1842 
1843 void
1844 GetTermSizeVIO(file=STDIN)
1845 	InputStream	file
1846 	PPCODE:
1847 	{
1848 		int x,y,xpix,ypix;
1849 		if( GetTermSizeVIO(aTHX_ file,&x,&y,&xpix,&ypix)==0)
1850 		{
1851 			EXTEND(sp, 4);
1852 			PUSHs(sv_2mortal(newSViv((IV)x)));
1853 			PUSHs(sv_2mortal(newSViv((IV)y)));
1854 			PUSHs(sv_2mortal(newSViv((IV)xpix)));
1855 			PUSHs(sv_2mortal(newSViv((IV)ypix)));
1856 		}
1857 		else
1858 		{
1859 			ST(0) = sv_newmortal();
1860 		}
1861 	}
1862 
1863 void
1864 GetTermSizeGWINSZ(file=STDIN)
1865 	InputStream	file
1866 	PPCODE:
1867 	{
1868 		int x,y,xpix,ypix;
1869 		if( GetTermSizeGWINSZ(aTHX_ file,&x,&y,&xpix,&ypix)==0)
1870 		{
1871 			EXTEND(sp, 4);
1872 			PUSHs(sv_2mortal(newSViv((IV)x)));
1873 			PUSHs(sv_2mortal(newSViv((IV)y)));
1874 			PUSHs(sv_2mortal(newSViv((IV)xpix)));
1875 			PUSHs(sv_2mortal(newSViv((IV)ypix)));
1876 		}
1877 		else
1878 		{
1879 			ST(0) = sv_newmortal();
1880 		}
1881 	}
1882 
1883 void
1884 GetTermSizeGSIZE(file=STDIN)
1885 	InputStream	file
1886 	PPCODE:
1887 	{
1888 		int x,y,xpix,ypix;
1889 		if( GetTermSizeGSIZE(aTHX_ file,&x,&y,&xpix,&ypix)==0)
1890 		{
1891 			EXTEND(sp, 4);
1892 			PUSHs(sv_2mortal(newSViv((IV)x)));
1893 			PUSHs(sv_2mortal(newSViv((IV)y)));
1894 			PUSHs(sv_2mortal(newSViv((IV)xpix)));
1895 			PUSHs(sv_2mortal(newSViv((IV)ypix)));
1896 		}
1897 		else
1898 		{
1899 			ST(0) = sv_newmortal();
1900 		}
1901 	}
1902 
1903 int
1904 SetTerminalSize(width,height,xpix,ypix,file=STDIN)
1905 	int	width
1906 	int	height
1907 	int	xpix
1908 	int	ypix
1909 	InputStream	file
1910 	CODE:
1911 	{
1912 		RETVAL=SetTerminalSize(aTHX_ file,width,height,xpix,ypix);
1913 	}
1914 	OUTPUT:
1915 		RETVAL
1916 
1917 void
1918 GetSpeed(file=STDIN)
1919 	InputStream	file
1920 	PPCODE:
1921 	{
1922 		I32 in,out;
1923 /*
1924  *    experimentally relaxed for
1925  *    https://rt.cpan.org/Ticket/Display.html?id=88050
1926 		if(items!=0) {
1927 			croak("Usage: Term::ReadKey::GetSpeed()");
1928 		}
1929 */
1930 		if(getspeed(aTHX_ file,&in,&out)) {
1931 			/* Failure */
1932 			ST( 0) = sv_newmortal();
1933 		} else {
1934 			EXTEND(sp, 2);
1935 			PUSHs(sv_2mortal(newSViv((IV)in)));
1936 			PUSHs(sv_2mortal(newSViv((IV)out)));
1937 		}
1938 	}
1939 
1940 
1941 
1942 BOOT:
1943 newXS("Term::ReadKey::GetControlChars", XS_Term__ReadKey_GetControlChars, file);
1944 newXS("Term::ReadKey::SetControlChars", XS_Term__ReadKey_SetControlChars, file);
1945 filehash=newHV();
1946 modehash=newHV();
1947