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