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