File Coverage

ReadKey.xs
Criterion Covered Total %
statement 6 186 3.2
branch 0 78 0.0
condition n/a
subroutine n/a
pod n/a
total 6 264 2.2


line stmt bran cond sub pod time code
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
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
219             # include
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
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
257             # endif
258             # ifdef I_SYS_FILE
259             # include
260             # endif
261             # ifdef I_UNISTD
262             # include
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
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
297             # define Have_poll
298             # endif
299             # ifdef HAVE_SYS_POLL_H
300             # include
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 .
325             No, Configure (dist3.051) doesn't know how to check for this.
326             */
327             #ifdef I_SYS_STREAM
328             # include
329             #endif
330             #ifdef I_SYS_PTEM
331             # include
332             #endif
333              
334             #ifdef I_TERMIOS
335             # include
336             #else
337             # ifdef I_TERMIO
338             # include
339             # else
340             # ifdef I_SGTTY
341             # include
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
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
438 0           int GetTermSizeVIO(pTHX_ PerlIO *file,int * retwidth,int *retheight, int *xpix,int *ypix)
439             {
440 0           croak("TermSizeVIO is not implemented on this architecture");
441             return 0;
442             }
443             #endif
444              
445              
446             #if defined(TIOCGWINSZ) && !defined(DONT_USE_GWINSZ)
447 0           int GetTermSizeGWINSZ(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
448             {
449 0           int handle=PerlIO_fileno(file);
450             struct winsize w;
451              
452 0 0         if (ioctl (handle, TIOCGWINSZ, &w) == 0) {
453 0           *retwidth=w.ws_col; *retheight=w.ws_row;
454 0           *xpix=w.ws_xpixel; *ypix=w.ws_ypixel; return 0;
455             }
456             else {
457 0           return -1; /* failure */
458             }
459              
460             }
461             #else
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))
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
485 0           int GetTermSizeGSIZE(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
486             {
487 0           croak("TermSizeGSIZE is not implemented on this architecture");
488             return 0;
489             }
490             #endif
491              
492             #ifdef USE_WIN32
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
516 0           int GetTermSizeWin32(pTHX_ PerlIO *file,int *retwidth,int *retheight,int *xpix,int *ypix)
517             {
518 0           croak("TermSizeWin32 is not implemented on this architecture");
519             return 0;
520             }
521             #endif /* USE_WIN32 */
522              
523              
524 0           STATIC int termsizeoptions() {
525 0           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              
542 0           int SetTerminalSize(pTHX_ PerlIO *file,int width,int height,int xpix,int ypix)
543             {
544 0           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 0           w.ws_col=width;
555 0           w.ws_row=height;
556 0           w.ws_xpixel=xpix;
557 0           w.ws_ypixel=ypix;
558 0 0         if (ioctl (handle, TIOCSWINSZ, &w) == 0) {
559 0           sprintf(buffer,"%d",width); /* Be polite to our children */
560 0           my_setenv("COLUMNS",buffer);
561 0           sprintf(buffer,"%d",height);
562 0           my_setenv("LINES",buffer);
563 0           return 0;
564             }
565             else {
566 0           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              
666 0           int getspeed(pTHX_ PerlIO *file,I32 *in, I32 *out)
667             {
668 0           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 0           tcgetattr(handle,&buf);
677              
678 0           *in = *out = -1;
679 0           *in = cfgetispeed(&buf);
680 0           *out = cfgetospeed(&buf);
681 0 0         for(i=0;terminal_speeds[i]!=-1;i+=2) {
682 0 0         if(*in == terminal_speeds[i+1])
683 0           { *in = terminal_speeds[i]; break; }
684             }
685 0 0         for(i=0;terminal_speeds[i]!=-1;i+=2) {
686 0 0         if(*out == terminal_speeds[i+1])
687 0           { *out = terminal_speeds[i]; break; }
688             }
689 0           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              
775 0           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 0           handle=PerlIO_fileno(file);
786            
787 0           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 0           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 0 0         if(firsttime) {
831 0           firsttime=0;
832 0           memcpy((void*)&savebuf,(void*)&work,sizeof(struct tbuffer));
833 0 0         if(!hv_store(filehash,(char*)&handle,sizeof(int),
834             newSVpv((char*)&savebuf,sizeof(struct tbuffer)),0))
835 0           croak("Unable to stash terminal settings.\n");
836 0 0         if(!hv_store(modehash,(char*)&handle,sizeof(int),newSViv(0),0))
837 0           croak("Unable to stash terminal settings.\n");
838             } else {
839             SV ** temp;
840 0 0         if(!(temp=hv_fetch(filehash,(char*)&handle,sizeof(int),0)))
841 0           croak("Unable to retrieve stashed terminal settings.\n");
842 0 0         memcpy(&savebuf,SvPV(*temp,PL_na),sizeof(struct tbuffer));
843 0 0         if(!(temp=hv_fetch(modehash,(char*)&handle,sizeof(int),0)))
844 0           croak("Unable to retrieve stashed terminal mode.\n");
845 0 0         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 0 0         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 0           memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
976              
977 0           work.c_lflag &= ~(ICANON|ISIG|IEXTEN );
978 0           work.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ECHOCTL);
979 0           work.c_lflag &= ~(ECHOPRT|ECHOKE|FLUSHO|PENDIN|XCASE);
980 0           work.c_lflag |= NOFLSH;
981 0           work.c_iflag &= ~(IXOFF|IXON|IXANY|ICRNL|IMAXBEL|BRKINT);
982              
983 0 0         if(((work.c_iflag & INPCK) != INPCK) ||
    0          
984 0           ((work.c_cflag & PARENB) != PARENB)) {
985 0           work.c_iflag &= ~ISTRIP;
986 0           work.c_iflag |= IGNPAR;
987 0           work.c_iflag &= ~PARMRK;
988             }
989 0           work.c_oflag &= ~(OPOST |ONLCR|OCRNL|ONLRET);
990              
991 0           work.c_cc[VTIME] = 0;
992 0           work.c_cc[VMIN] = 1;
993             }
994 0 0         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 0           memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1001              
1002             /*work.c_iflag = savebuf.c_iflag;*/
1003 0           work.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO);
1004 0           work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
1005 0           work.c_iflag &= ~(IXON | IXANY | BRKINT);
1006 0           work.c_oflag = savebuf.c_oflag;
1007 0           work.c_cc[VTIME] = 0;
1008 0           work.c_cc[VMIN] = 1;
1009             }
1010 0 0         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 0           memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1017              
1018 0           work.c_iflag = savebuf.c_iflag;
1019 0           work.c_lflag &= ~(ICANON | ECHO);
1020 0           work.c_lflag &= ~(ECHOE | ECHOK | ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
1021 0           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 0           work.c_cc[VTIME] = 0;
1026 0           work.c_cc[VMIN] = 1;
1027             }
1028 0 0         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 0           memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1035              
1036 0           work.c_iflag = savebuf.c_iflag;
1037 0           work.c_lflag |= ICANON|ISIG|IEXTEN;
1038 0           work.c_lflag &= ~ECHO;
1039 0           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 0 0         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 0           memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1053              
1054 0           work.c_iflag = savebuf.c_iflag;
1055 0           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 0 0         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 0           memcpy((void*)&work,(void*)&savebuf,sizeof(struct tbuffer));
1072             /*Copy(&work,&savebuf,1,sizeof(struct tbuffer));*/
1073              
1074 0           firsttime=1;
1075             }
1076             else
1077             {
1078 0           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 0           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 0 0         if( firsttime ) {
1407 0           (void)hv_delete(filehash,(char*)&handle,sizeof(int),0);
1408 0           (void)hv_delete(modehash,(char*)&handle,sizeof(int),0);
1409             } else {
1410 0 0         if(!hv_store(modehash,(char*)&handle,sizeof(int),
1411             newSViv(mode),0))
1412 0           croak("Unable to stash terminal settings.\n");
1413             }
1414              
1415 0           }
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
1460 0           int selectfile(pTHX_ PerlIO *file,double delay)
1461             {
1462             struct timeval t;
1463 0           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 0 0         if (PerlIO_fast_gets(file) && PerlIO_get_cnt(file) > 0)
    0          
1470 0           return 1;
1471              
1472             /*t.tv_sec=t.tv_usec=0;*/
1473              
1474 0 0         if (delay < 0.0)
1475 0           delay = 0.0;
1476 0           t.tv_sec = (long)delay;
1477 0           delay -= (double)t.tv_sec;
1478 0           t.tv_usec = (long)(delay * 1000000.0);
1479              
1480 0           FD_ZERO(&fd);
1481 0           FD_SET(handle,&fd);
1482 0 0         if(select(handle+1,(Select_fd_set_t)&fd,
1483             (Select_fd_set_t)0,
1484 0           (Select_fd_set_t)&fd, &t)) return -1;
1485 0           else return 0;
1486             }
1487              
1488             #else
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
1497 0           int setnodelay(pTHX_ PerlIO *file, int mode)
1498             {
1499 0           int handle=PerlIO_fileno(file);
1500             int flags;
1501 0           flags=fcntl(handle,F_GETFL,0);
1502 0 0         if(mode)
1503 0           flags|=O_NODELAY;
1504             else
1505 0           flags&=~O_NODELAY;
1506 0           fcntl(handle,F_SETFL,flags);
1507 0           return 0;
1508             }
1509              
1510             #else
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
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
1532 0           int pollfile(pTHX_ PerlIO *file,double delay)
1533             {
1534 0           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              
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
1713 0           int Win32PeekChar(pTHX_ PerlIO *file, double delay,char *key)
1714             {
1715 0           croak("Win32PeekChar is not supported on this architecture");
1716             return 0;
1717             }
1718             #endif
1719              
1720              
1721 4           STATIC int blockoptions() {
1722 4           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              
1738 0           STATIC int termoptions() {
1739 0           int i=0;
1740             #ifdef USE_TERMIOS
1741 0           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 0           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 0           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 0           ReadMode(aTHX_ file,mode);
1779             }
1780              
1781             int
1782             setnodelay(file,mode)
1783             InputStream file
1784             int mode
1785             CODE:
1786 0           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 0           RETVAL = pollfile(aTHX_ file, delay);
1796             OUTPUT:
1797             RETVAL
1798              
1799             SV *
1800             Win32PeekChar(file, delay)
1801             InputStream file
1802             double delay
1803             CODE:
1804             {
1805             char key;
1806 0 0         if (Win32PeekChar(aTHX_ file, delay, &key))
1807 0           RETVAL = newSVpv(&key, 1);
1808             else
1809 0           RETVAL = newSVsv(&PL_sv_undef);
1810             }
1811             OUTPUT:
1812             RETVAL
1813              
1814             int
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 0 0         if( GetTermSizeWin32(aTHX_ file,&x,&y,&xpix,&ypix)==0)
1830             {
1831 0 0         EXTEND(sp, 4);
1832 0           PUSHs(sv_2mortal(newSViv((IV)x)));
1833 0           PUSHs(sv_2mortal(newSViv((IV)y)));
1834 0           PUSHs(sv_2mortal(newSViv((IV)xpix)));
1835 0           PUSHs(sv_2mortal(newSViv((IV)ypix)));
1836             }
1837             else
1838             {
1839 0           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 0 0         if( GetTermSizeVIO(aTHX_ file,&x,&y,&xpix,&ypix)==0)
1850             {
1851 0 0         EXTEND(sp, 4);
1852 0           PUSHs(sv_2mortal(newSViv((IV)x)));
1853 0           PUSHs(sv_2mortal(newSViv((IV)y)));
1854 0           PUSHs(sv_2mortal(newSViv((IV)xpix)));
1855 0           PUSHs(sv_2mortal(newSViv((IV)ypix)));
1856             }
1857             else
1858             {
1859 0           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 0 0         if( GetTermSizeGWINSZ(aTHX_ file,&x,&y,&xpix,&ypix)==0)
1870             {
1871 0 0         EXTEND(sp, 4);
1872 0           PUSHs(sv_2mortal(newSViv((IV)x)));
1873 0           PUSHs(sv_2mortal(newSViv((IV)y)));
1874 0           PUSHs(sv_2mortal(newSViv((IV)xpix)));
1875 0           PUSHs(sv_2mortal(newSViv((IV)ypix)));
1876             }
1877             else
1878             {
1879 0           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 0 0         if( GetTermSizeGSIZE(aTHX_ file,&x,&y,&xpix,&ypix)==0)
1890             {
1891 0 0         EXTEND(sp, 4);
1892 0           PUSHs(sv_2mortal(newSViv((IV)x)));
1893 0           PUSHs(sv_2mortal(newSViv((IV)y)));
1894 0           PUSHs(sv_2mortal(newSViv((IV)xpix)));
1895 0           PUSHs(sv_2mortal(newSViv((IV)ypix)));
1896             }
1897             else
1898             {
1899 0           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 0           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 0 0         if(getspeed(aTHX_ file,&in,&out)) {
1931             /* Failure */
1932 0           ST( 0) = sv_newmortal();
1933             } else {
1934 0 0         EXTEND(sp, 2);
1935 0           PUSHs(sv_2mortal(newSViv((IV)in)));
1936 0           PUSHs(sv_2mortal(newSViv((IV)out)));
1937             }
1938             }
1939              
1940              
1941              
1942             BOOT:
1943 3           newXS("Term::ReadKey::GetControlChars", XS_Term__ReadKey_GetControlChars, file);
1944 3           newXS("Term::ReadKey::SetControlChars", XS_Term__ReadKey_SetControlChars, file);
1945 3           filehash=newHV();
1946 3           modehash=newHV();