File Coverage

blib/lib/IO/Stty.pm
Criterion Covered Total %
statement 88 326 26.9
branch 56 274 20.4
condition 15 28 53.5
subroutine 7 8 87.5
pod 2 2 100.0
total 168 638 26.3


line stmt bran cond sub pod time code
1             package IO::Stty;
2              
3 8     8   1493857 use strict;
  8         16  
  8         340  
4 8     8   38 use warnings;
  8         13  
  8         606  
5              
6 8     8   15085 use POSIX;
  8         42613  
  8         69  
7              
8             our $VERSION = '0.07';
9              
10             # Baud rate constants: standard POSIX rates plus modern rates.
11             # Modern rates (B57600, B115200, B230400) are not available on all platforms,
12             # so we use eval guards to include only what the current system supports.
13             my %BAUD_RATES;
14             my %BAUD_SPEEDS;
15             BEGIN {
16 8     8   22911 my @standard = qw(0 50 75 110 134 150 200 300 600 1200 1800 2400 4800 9600 19200 38400);
17 8         25 my @modern = qw(57600 115200 230400);
18 8         38 for my $rate (@standard, @modern) {
19 152         321 my $val = eval { POSIX->can("B$rate") };
  152         846  
20 152 100 66     29245 next unless $val && ref($val) eq 'CODE';
21 128         155 $val = eval { $val->() };
  128         208  
22 128 50       209 if (defined $val) {
23 128         314 $BAUD_RATES{$rate} = $val;
24 128         376 $BAUD_SPEEDS{$val} = $rate;
25             }
26             }
27             }
28              
29             =for markdown [![testsuite](https://github.com/cpan-authors/IO-Stty/actions/workflows/testsuite.yml/badge.svg)](https://github.com/cpan-authors/IO-Stty/actions/workflows/testsuite.yml)
30              
31             =head1 NAME
32              
33             IO::Stty - Change and print terminal line settings
34              
35             =head1 SYNOPSIS
36              
37             # calling the script directly
38             stty.pl [setting...]
39             stty.pl {-a,-g,-v,--version}
40            
41             # Calling Stty module
42             use IO::Stty;
43             IO::Stty::stty(\*TTYHANDLE, @modes);
44              
45             use IO::Stty;
46             $old_mode=IO::Stty::stty(\*STDIN,'-g');
47              
48             # Turn off echoing.
49             IO::Stty::stty(\*STDIN,'-echo');
50              
51             # Do whatever.. grab input maybe?
52             $read_password = <>;
53              
54             # Now restore the old mode.
55             IO::Stty::stty(\*STDIN,$old_mode);
56              
57             # What settings do we have anyway?
58             print IO::Stty::stty(\*STDIN,'-a');
59              
60             =head1 DESCRIPTION
61              
62             This is the PERL POSIX compliant stty.
63              
64             =head1 INTRO
65              
66             This has not been tailored to the IO::File stuff but will work with it as
67             indicated. Before you go futzing with term parameters it's a good idea to grab
68             the current settings and restore them when you finish.
69              
70             stty accepts the following non-option arguments that change aspects of the
71             terminal line operation. A `[-]' before a capability means that it can be
72             turned off by preceding it with a `-'.
73              
74             =head1 stty parameters
75              
76             =head2 Control settings
77              
78             =over 4
79              
80             =item [-]parenb
81              
82             Generate parity bit in output and expect parity bit in input.
83              
84             =item [-]parodd
85              
86             Set odd parity (even with `-').
87              
88             =item cs5 cs6 cs7 cs8
89              
90             Set character size to 5, 6, 7, or 8 bits.
91              
92             =item [-]hupcl [-]hup
93              
94             Send a hangup signal when the last process closes the tty.
95              
96             =item [-]cstopb
97              
98             Use two stop bits per character (one with `-').
99              
100             =item [-]cread
101              
102             Allow input to be received.
103              
104             =item [-]clocal
105              
106             Disable modem control signals.
107              
108             =back
109              
110             =head2 Input settings
111              
112             =over 4
113              
114             =item [-]ignbrk
115              
116             Ignore break characters.
117              
118             =item [-]brkint
119              
120             Breaks cause an interrupt signal.
121              
122             =item [-]ignpar
123              
124             Ignore characters with parity errors.
125              
126             =item [-]parmrk
127              
128             Mark parity errors (with a 255-0-character sequence).
129              
130             =item [-]inpck
131              
132             Enable input parity checking.
133              
134             =item [-]istrip
135              
136             Clear high (8th) bit of input characters.
137              
138             =item [-]inlcr
139              
140             Translate newline to carriage return.
141              
142             =item [-]igncr
143              
144             Ignore carriage return.
145              
146             =item [-]icrnl
147              
148             Translate carriage return to newline.
149              
150             =item [-]ixon
151              
152             Enable XON/XOFF flow control.
153              
154             =item [-]ixoff
155              
156             Enable sending of stop character when the system
157             input buffer is almost full, and start character
158             when it becomes almost empty again.
159              
160             =back
161              
162             =head2 Output settings
163              
164             =over 4
165              
166             =item [-]opost
167              
168             Postprocess output.
169              
170             =back
171              
172             =head2 Local settings
173              
174             =over 4
175              
176             =item [-]isig
177              
178             Enable interrupt, quit, and suspend special characters.
179              
180             =item [-]icanon
181              
182             Enable erase, kill, werase, and rprnt special characters.
183              
184             =item [-]echo
185              
186             Echo input characters.
187              
188             =item [-]echoe, [-]crterase
189              
190             Echo erase characters as backspace-space-backspace.
191              
192             =item [-]echok
193              
194             Echo a newline after a kill character.
195              
196             =item [-]echonl
197              
198             Echo newline even if not echoing other characters.
199              
200             =item [-]noflsh
201              
202             Disable flushing after interrupt and quit special characters.
203              
204             * Though this claims non-posixhood it is supported by the perl POSIX.pm.
205              
206             =item [-]tostop (np)
207              
208             Stop background jobs that try to write to the terminal.
209              
210             =back
211              
212             =head2 Combination settings
213              
214             =over 4
215              
216             =item ek
217              
218             Reset the erase and kill special characters to their default values.
219              
220             =item sane
221              
222             Same as:
223              
224             cread -ignbrk brkint -inlcr -igncr icrnl -ixoff opost
225             isig icanon iexten echo echoe echok -echonl -noflsh -tostop
226              
227             also sets all special characters to their default
228             values.
229              
230             =item [-]cooked
231              
232             Same as:
233              
234             brkint ignpar istrip icrnl ixon opost isig icanon
235              
236             plus sets the eof and eol characters to their default values
237             if they are the same as the min and time characters.
238             With `-', same as raw.
239              
240             =item [-]raw
241              
242             Same as:
243              
244             -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr
245             -icrnl -ixon -ixoff -opost -isig -icanon min 1 time 0
246              
247             With `-', same as cooked.
248              
249             =item [-]pass8
250              
251             Same as:
252              
253             -parenb -istrip cs8
254              
255             With `-', same as parenb istrip cs7.
256              
257             =item dec
258              
259             Same as:
260              
261             echoe echoctl echoke -ixany
262              
263             Also sets the interrupt special character to Ctrl-C, erase to
264             Del, and kill to Ctrl-U.
265              
266             =back
267              
268             =head2 Special characters
269              
270             The special characters' default values vary from system to
271             system. They are set with the syntax `name value', where
272             the names are listed below and the value can be given
273             either literally, in hat notation (`^c'), or as an integer
274             which may start with `0x' to indicate hexadecimal, `0' to
275             indicate octal, or any other digit to indicate decimal.
276             Giving a value of `^-' or `undef' disables that special
277             character.
278              
279             =over 4
280              
281             =item intr
282              
283             Send an interrupt signal.
284              
285             =item quit
286              
287             Send a quit signal.
288              
289             =item erase
290              
291             Erase the last character typed.
292              
293             =item kill
294              
295             Erase the current line.
296              
297             =item eof
298              
299             Send an end of file (terminate the input).
300              
301             =item eol
302              
303             End the line.
304              
305             =item start
306              
307             Restart the output after stopping it.
308              
309             =item stop
310              
311             Stop the output.
312              
313             =item susp
314              
315             Send a terminal stop signal.
316              
317             =back
318              
319             =head2 Special settings
320              
321             =over 4
322              
323             =item min N
324              
325             Set the minimum number of characters that will satisfy a read
326             until the time value has expired, when C<-icanon> is set.
327              
328             =item time N
329              
330             Set the number of tenths of a second before reads
331             time out if the min number of characters have not
332             been read, when -icanon is set.
333              
334             =item N
335              
336             Set the input and output speeds to N. N can be one
337             of: 0 50 75 110 134 134.5 150 200 300 600 1200 1800
338             2400 4800 9600 19200 38400 exta extb. exta is the
339             same as 19200; extb is the same as 38400. 0 hangs
340             up the line if -clocal is set.
341              
342             =back
343              
344             =head2 OPTIONS
345              
346             =over 4
347              
348             =item -a
349              
350             Print all current settings in human-readable form.
351              
352             =item -g
353              
354             Print all current settings in a form that can be
355             used as an argument to another stty command to
356             restore the current settings.
357              
358             =item -v,--version
359              
360             Print version info.
361              
362             =back
363              
364             =head1 Direct Subroutines
365              
366             =over 4
367              
368             =item B<_parse_char_value()>
369              
370             my $numeric = IO::Stty::_parse_char_value($value);
371              
372             Parse a special character value from any of the supported notations:
373             literal integers, hat notation (C<^c>), hexadecimal (C<0x...>),
374             octal (C<0...>), or C/C<^-> to disable.
375              
376             =cut
377              
378             sub _parse_char_value {
379 24     24   266072 my ($val) = @_;
380              
381             # undef or ^- means disable the character
382 24 100 100     197 if ( $val eq 'undef' || $val eq '^-' ) {
383 2         6 return 0;
384             }
385              
386             # Hat notation: ^c means Ctrl-C (0x03), ^? means DEL (0x7F)
387 22 100       93 if ( $val =~ /^\^(.)$/ ) {
388 8         25 my $ch = $1;
389 8 100       22 if ( $ch eq '?' ) {
390 1         5 return 0x7F;
391             }
392 7         29 return ord( uc($ch) ) & 0x1F;
393             }
394              
395             # Hexadecimal: 0x...
396 14 100       79 if ( $val =~ /^0x([0-9a-fA-F]+)$/ ) {
397 6         59 return hex($1);
398             }
399              
400             # Octal: 0 followed by digits (but not plain "0" which is decimal zero)
401 8 100       33 if ( $val =~ /^0(\d+)$/ ) {
402 4         20 return oct($1);
403             }
404              
405             # Decimal integer (including plain 0)
406 4 50       71 if ( $val =~ /^\d+$/ ) {
407 4         20 return $val + 0;
408             }
409              
410             # Single literal character
411 0 0       0 if ( length($val) == 1 ) {
412 0         0 return ord($val);
413             }
414              
415 0         0 warn "IO::Stty: unrecognized character value '$val'\n";
416 0         0 return 0;
417             }
418              
419             =item B
420              
421             IO::Stty::stty(\*STDIN, @params);
422              
423             From comments:
424              
425             I'm not feeling very inspired about this. Terminal parameters are obscure
426             and boring. Basically what this will do is get the current setting,
427             take the parameters, modify the setting and write it back. Zzzz.
428             This is not especially efficent and probably not too fast. Assuming the POSIX
429             spec has been implemented properly it should mostly work.
430              
431             =cut
432              
433             sub stty {
434 0     0 1 0 my $tty_handle = shift; # This should be a \*HANDLE
435              
436 0 0       0 @_ or die("No parameters passed to stty");
437              
438             # Notice fileno() instead of handle->fileno(). I want it to work with
439             # normal fhs.
440 0         0 my ($file_num) = fileno($tty_handle);
441              
442             # Is it a terminal?
443 0 0       0 return undef unless isatty($file_num);
444 0         0 my ($tty_name) = ttyname($file_num);
445              
446             # make a terminal object.
447 0         0 my ($termios) = POSIX::Termios->new();
448 0 0       0 $termios->getattr($file_num) || warn "Couldn't get terminal parameters for '$tty_name', file num ($file_num)";
449 0         0 my ($c_cflag) = $termios->getcflag;
450 0         0 my ($c_iflag) = $termios->getiflag;
451 0         0 my ($ispeed) = $termios->getispeed;
452 0         0 my ($c_lflag) = $termios->getlflag;
453 0         0 my ($c_oflag) = $termios->getoflag;
454 0         0 my ($ospeed) = $termios->getospeed;
455 0         0 my (%control_chars);
456 0         0 $control_chars{'INTR'} = $termios->getcc(VINTR);
457 0         0 $control_chars{'QUIT'} = $termios->getcc(VQUIT);
458 0         0 $control_chars{'ERASE'} = $termios->getcc(VERASE);
459 0         0 $control_chars{'KILL'} = $termios->getcc(VKILL);
460 0         0 $control_chars{'EOF'} = $termios->getcc(VEOF);
461 0         0 $control_chars{'TIME'} = $termios->getcc(VTIME);
462 0         0 $control_chars{'MIN'} = $termios->getcc(VMIN);
463 0         0 $control_chars{'START'} = $termios->getcc(VSTART);
464 0         0 $control_chars{'STOP'} = $termios->getcc(VSTOP);
465 0         0 $control_chars{'SUSP'} = $termios->getcc(VSUSP);
466 0         0 $control_chars{'EOL'} = $termios->getcc(VEOL);
467              
468             # OK.. we have our crap.
469              
470 0         0 my @parameters;
471              
472 0 0       0 if ( @_ == 1 ) {
473              
474             # handle the one-arg cases specifically
475             # Version info
476 0 0       0 if ( $_[0] =~ /^(-v|--version|version)$/ ) {
    0          
    0          
    0          
477 0         0 return $IO::Stty::VERSION . "\n";
478             }
479             elsif ( $_[0] =~ /^\d+$/ ) {
480 0         0 push( @parameters, 'ispeed', $_[0], 'ospeed', $_[0] );
481             }
482              
483             # Do we want to know what the crap is?
484             elsif ( $_[0] eq '-a' ) {
485 0         0 return show_me_the_crap(
486             $c_cflag, $c_iflag, $ispeed, $c_lflag, $c_oflag,
487             $ospeed, \%control_chars
488             );
489             }
490              
491             # did we get the '-g' flag?
492             elsif ( $_[0] eq '-g' ) {
493             return
494             "$c_cflag:$c_iflag:$ispeed:$c_lflag:$c_oflag:$ospeed:"
495             . $control_chars{'INTR'} . ":"
496             . $control_chars{'QUIT'} . ":"
497             . $control_chars{'ERASE'} . ":"
498             . $control_chars{'KILL'} . ":"
499             . $control_chars{'EOF'} . ":"
500             . $control_chars{'TIME'} . ":"
501             . $control_chars{'MIN'} . ":"
502             . $control_chars{'START'} . ":"
503             . $control_chars{'STOP'} . ":"
504             . $control_chars{'SUSP'} . ":"
505 0         0 . $control_chars{'EOL'};
506             }
507             else {
508             # Or the converse.. -g used before and we're getting the return.
509             # Note that this uses the functionality of stty -g, not any specific
510             # method. Don't take the output here and feed it to the OS stty.
511              
512             # This will make perl -w happy.
513 0         0 my (@g_params) = split( ':', $_[0] );
514 0 0       0 if ( @g_params == 17 ) {
515              
516             # print "Feeding back...\n";
517 0         0 ( $c_cflag, $c_iflag, $ispeed, $c_lflag, $c_oflag, $ospeed ) = (@g_params);
518 0         0 $control_chars{'INTR'} = $g_params[6];
519 0         0 $control_chars{'QUIT'} = $g_params[7];
520 0         0 $control_chars{'ERASE'} = $g_params[8];
521 0         0 $control_chars{'KILL'} = $g_params[9];
522 0         0 $control_chars{'EOF'} = $g_params[10];
523 0         0 $control_chars{'TIME'} = $g_params[11];
524 0         0 $control_chars{'MIN'} = $g_params[12];
525 0         0 $control_chars{'START'} = $g_params[13];
526 0         0 $control_chars{'STOP'} = $g_params[14];
527 0         0 $control_chars{'SUSP'} = $g_params[15];
528 0         0 $control_chars{'EOL'} = $g_params[16];
529              
530             # leave parameters empty
531             }
532             else {
533             # a simple single option
534 0         0 @parameters = @_;
535             }
536             }
537             }
538             else {
539 0         0 @parameters = @_;
540             }
541              
542             # So.. what shall we set?
543 0         0 my ($set_value);
544 0         0 local ($_);
545 0         0 while ( defined( $_ = shift(@parameters) ) ) {
546              
547             # print "Param:$_:\n";
548             # Build the 'this really means this' cases.
549 0 0       0 if ( $_ eq 'ek' ) {
550 0         0 unshift( @parameters, 'erase', 8, 'kill', 21 );
551 0         0 next;
552             }
553 0 0       0 if ( $_ eq 'sane' ) {
554 0         0 unshift(
555             @parameters, 'cread', '-ignbrk', 'brkint', '-inlcr', '-igncr', 'icrnl',
556             '-ixoff', 'opost', 'isig', 'icanon', 'iexten', 'echo', 'echoe', 'echok',
557             '-echonl', '-noflsh', '-tostop', 'echok', 'intr', 3, 'quit', 28, 'erase',
558             8, 'kill', 21, 'eof', 4, 'eol', 0, 'stop', 19, 'start', 17, 'susp', 26,
559             'time', 0, 'min', 0
560             );
561 0         0 next;
562              
563             # Ugh.
564             }
565 0 0 0     0 if ( $_ eq 'cooked' || $_ eq '-raw' ) {
566              
567             # Is this right?
568 0         0 unshift(
569             @parameters, 'brkint', 'ignpar', 'istrip', 'icrnl', 'ixon', 'opost',
570             'isig', 'icanon',
571             'intr', 3, 'quit', 28, 'erase', 8, 'kill', 21, 'eof',
572             4, 'eol', 0, 'stop', 19, 'start', 17, 'susp', 26, 'time', 0, 'min', 0
573             );
574 0         0 next;
575             }
576 0 0 0     0 if ( $_ eq 'raw' || $_ eq '-cooked' ) {
577 0         0 unshift(
578             @parameters, '-ignbrk', '-brkint', '-ignpar', '-parmrk', '-inpck',
579             '-istrip', '-inlcr', '-igncr', '-icrnl', '-ixon', '-ixoff',
580             '-opost', '-isig', '-icanon', 'min', 1, 'time', 0
581             );
582 0         0 next;
583             }
584 0 0       0 if ( $_ eq 'pass8' ) {
585 0         0 unshift( @parameters, '-parenb', '-istrip', 'cs8' );
586 0         0 next;
587             }
588 0 0       0 if ( $_ eq '-pass8' ) {
589 0         0 unshift( @parameters, 'parenb', 'istrip', 'cs7' );
590 0         0 next;
591             }
592 0 0       0 if ( $_ eq 'crt' ) {
593 0         0 unshift( @parameters, 'echoe', 'echok' );
594 0         0 next;
595             }
596 0 0       0 if ( $_ eq 'dec' ) {
597              
598             # 127 == delete, no?
599 0         0 unshift( @parameters, 'echoe', 'echok', 'intr', 3, 'erase', 127, 'kill', 21 );
600 0         0 next;
601             }
602 0         0 $set_value = 1; # On by default...
603             # unset if starts w/ -, as in -crtscts
604 0 0       0 $set_value = 0 if s/^\-//;
605              
606             # Now the fun part.
607              
608             # c_cc field crap.
609 0 0       0 if ( $_ eq 'intr' ) { $control_chars{'INTR'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
610 0 0       0 if ( $_ eq 'quit' ) { $control_chars{'QUIT'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
611 0 0       0 if ( $_ eq 'erase' ) { $control_chars{'ERASE'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
612 0 0       0 if ( $_ eq 'kill' ) { $control_chars{'KILL'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
613 0 0       0 if ( $_ eq 'eof' ) { $control_chars{'EOF'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
614 0 0       0 if ( $_ eq 'eol' ) { $control_chars{'EOL'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
615 0 0       0 if ( $_ eq 'start' ) { $control_chars{'START'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
616 0 0       0 if ( $_ eq 'stop' ) { $control_chars{'STOP'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
617 0 0       0 if ( $_ eq 'susp' ) { $control_chars{'SUSP'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
618 0 0       0 if ( $_ eq 'min' ) { $control_chars{'MIN'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
619 0 0       0 if ( $_ eq 'time' ) { $control_chars{'TIME'} = _parse_char_value( shift @parameters ); next; }
  0         0  
  0         0  
620              
621             # c_cflag crap
622 0 0       0 if ( $_ eq 'clocal' ) { $c_cflag = ( $set_value ? ( $c_cflag | CLOCAL ) : ( $c_cflag & ( ~CLOCAL ) ) ); next; }
  0 0       0  
  0         0  
623 0 0       0 if ( $_ eq 'cread' ) { $c_cflag = ( $set_value ? ( $c_cflag | CREAD ) : ( $c_cflag & ( ~CREAD ) ) ); next; }
  0 0       0  
  0         0  
624              
625             # As best I can tell, doing |~CS8 will clear the bits.. under solaris
626             # anyway, where CS5 = 0, CS6 = 0x20, CS7= 0x40, CS8=0x60
627 0 0       0 if ( $_ eq 'cs5' ) { $c_cflag = ( ( $c_cflag & ~CS8 ) | CS5 ); next; }
  0         0  
  0         0  
628 0 0       0 if ( $_ eq 'cs6' ) { $c_cflag = ( ( $c_cflag & ~CS8 ) | CS6 ); next; }
  0         0  
  0         0  
629 0 0       0 if ( $_ eq 'cs7' ) { $c_cflag = ( ( $c_cflag & ~CS8 ) | CS7 ); next; }
  0         0  
  0         0  
630 0 0       0 if ( $_ eq 'cs8' ) { $c_cflag = ( $c_cflag | CS8 ); next; }
  0         0  
  0         0  
631 0 0       0 if ( $_ eq 'cstopb' ) { $c_cflag = ( $set_value ? ( $c_cflag | CSTOPB ) : ( $c_cflag & ( ~CSTOPB ) ) ); next; }
  0 0       0  
  0         0  
632 0 0 0     0 if ( $_ eq 'hupcl' || $_ eq 'hup' ) { $c_cflag = ( $set_value ? ( $c_cflag | HUPCL ) : ( $c_cflag & ( ~HUPCL ) ) ); next; }
  0 0       0  
  0         0  
633 0 0       0 if ( $_ eq 'parenb' ) { $c_cflag = ( $set_value ? ( $c_cflag | PARENB ) : ( $c_cflag & ( ~PARENB ) ) ); next; }
  0 0       0  
  0         0  
634 0 0       0 if ( $_ eq 'parodd' ) { $c_cflag = ( $set_value ? ( $c_cflag | PARODD ) : ( $c_cflag & ( ~PARODD ) ) ); next; }
  0 0       0  
  0         0  
635              
636             # That was fun. Still awake? c_iflag time.
637 0 0       0 if ( $_ eq 'brkint' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | BRKINT ) : ( $c_iflag & ( ~BRKINT ) ) ) ); next; }
  0 0       0  
  0         0  
638 0 0       0 if ( $_ eq 'icrnl' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | ICRNL ) : ( $c_iflag & ( ~ICRNL ) ) ) ); next; }
  0 0       0  
  0         0  
639 0 0       0 if ( $_ eq 'ignbrk' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | IGNBRK ) : ( $c_iflag & ( ~IGNBRK ) ) ) ); next; }
  0 0       0  
  0         0  
640 0 0       0 if ( $_ eq 'igncr' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | IGNCR ) : ( $c_iflag & ( ~IGNCR ) ) ) ); next; }
  0 0       0  
  0         0  
641 0 0       0 if ( $_ eq 'ignpar' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | IGNPAR ) : ( $c_iflag & ( ~IGNPAR ) ) ) ); next; }
  0 0       0  
  0         0  
642 0 0       0 if ( $_ eq 'inlcr' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | INLCR ) : ( $c_iflag & ( ~INLCR ) ) ) ); next; }
  0 0       0  
  0         0  
643 0 0       0 if ( $_ eq 'inpck' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | INPCK ) : ( $c_iflag & ( ~INPCK ) ) ) ); next; }
  0 0       0  
  0         0  
644 0 0       0 if ( $_ eq 'istrip' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | ISTRIP ) : ( $c_iflag & ( ~ISTRIP ) ) ) ); next; }
  0 0       0  
  0         0  
645 0 0       0 if ( $_ eq 'ixoff' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | IXOFF ) : ( $c_iflag & ( ~IXOFF ) ) ) ); next; }
  0 0       0  
  0         0  
646 0 0       0 if ( $_ eq 'ixon' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | IXON ) : ( $c_iflag & ( ~IXON ) ) ) ); next; }
  0 0       0  
  0         0  
647 0 0       0 if ( $_ eq 'parmrk' ) { $c_iflag = ( ( $set_value ? ( $c_iflag | PARMRK ) : ( $c_iflag & ( ~PARMRK ) ) ) ); next; }
  0 0       0  
  0         0  
648              
649             # Are we there yet? No. Are we there yet? No. Are we there yet...
650             # print "Values: $c_lflag,".($c_lflag | ECHO)." ".($c_lflag & (~ECHO))."\n";
651 0 0       0 if ( $_ eq 'echo' ) { $c_lflag = ( ( $set_value ? ( $c_lflag | ECHO ) : ( $c_lflag & ( ~ECHO ) ) ) ); next; }
  0 0       0  
  0         0  
652 0 0       0 if ( $_ eq 'echoe' ) { $c_lflag = ( ( $set_value ? ( $c_lflag | ECHOE ) : ( $c_lflag & ( ~ECHOE ) ) ) ); next; }
  0 0       0  
  0         0  
653 0 0       0 if ( $_ eq 'echok' ) { $c_lflag = ( ( $set_value ? ( $c_lflag | ECHOK ) : ( $c_lflag & ( ~ECHOK ) ) ) ); next; }
  0 0       0  
  0         0  
654 0 0       0 if ( $_ eq 'echonl' ) { $c_lflag = ( ( $set_value ? ( $c_lflag | ECHONL ) : ( $c_lflag & ( ~ECHONL ) ) ) ); next; }
  0 0       0  
  0         0  
655 0 0       0 if ( $_ eq 'icanon' ) { $c_lflag = ( ( $set_value ? ( $c_lflag | ICANON ) : ( $c_lflag & ( ~ICANON ) ) ) ); next; }
  0 0       0  
  0         0  
656 0 0       0 if ( $_ eq 'iexten' ) { $c_lflag = ( ( $set_value ? ( $c_lflag | IEXTEN ) : ( $c_lflag & ( ~IEXTEN ) ) ) ); next; }
  0 0       0  
  0         0  
657 0 0       0 if ( $_ eq 'isig' ) { $c_lflag = ( ( $set_value ? ( $c_lflag | ISIG ) : ( $c_lflag & ( ~ISIG ) ) ) ); next; }
  0 0       0  
  0         0  
658 0 0       0 if ( $_ eq 'noflsh' ) { $c_lflag = ( ( $set_value ? ( $c_lflag | NOFLSH ) : ( $c_lflag & ( ~NOFLSH ) ) ) ); next; }
  0 0       0  
  0         0  
659 0 0       0 if ( $_ eq 'tostop' ) { $c_lflag = ( ( $set_value ? ( $c_lflag | TOSTOP ) : ( $c_lflag & ( ~TOSTOP ) ) ) ); next; }
  0 0       0  
  0         0  
660              
661             # Make it stop! Make it stop!
662             # c_oflag crap.
663 0 0       0 if ( $_ eq 'opost' ) { $c_oflag = ( ( $set_value ? ( $c_oflag | OPOST ) : ( $c_oflag & ( ~OPOST ) ) ) ); next; }
  0 0       0  
  0         0  
664              
665             # Speed?
666 0 0       0 if ( $_ eq 'ospeed' ) {
667 0         0 my $rate = shift(@parameters);
668 0 0       0 exists $BAUD_RATES{$rate} or warn "IO::Stty::stty: unknown baud rate '$rate'\n";
669 0 0       0 $ospeed = $BAUD_RATES{$rate} if exists $BAUD_RATES{$rate};
670 0         0 next;
671             }
672 0 0       0 if ( $_ eq 'ispeed' ) {
673 0         0 my $rate = shift(@parameters);
674 0 0       0 exists $BAUD_RATES{$rate} or warn "IO::Stty::stty: unknown baud rate '$rate'\n";
675 0 0       0 $ispeed = $BAUD_RATES{$rate} if exists $BAUD_RATES{$rate};
676 0         0 next;
677             }
678              
679             # Default.. parameter hasn't matched anything
680             # print "char:".sprintf("%lo",ord($_))."\n";
681 0         0 warn "IO::Stty::stty passed invalid parameter '$_'\n";
682             }
683              
684             # What a pain in the ass! Ok.. let's write the crap back.
685 0         0 $termios->setcflag($c_cflag);
686 0         0 $termios->setiflag($c_iflag);
687 0         0 $termios->setispeed($ispeed);
688 0         0 $termios->setlflag($c_lflag);
689 0         0 $termios->setoflag($c_oflag);
690 0         0 $termios->setospeed($ospeed);
691 0         0 $termios->setcc( VINTR, $control_chars{'INTR'} );
692 0         0 $termios->setcc( VQUIT, $control_chars{'QUIT'} );
693 0         0 $termios->setcc( VERASE, $control_chars{'ERASE'} );
694 0         0 $termios->setcc( VKILL, $control_chars{'KILL'} );
695 0         0 $termios->setcc( VEOF, $control_chars{'EOF'} );
696 0         0 $termios->setcc( VTIME, $control_chars{'TIME'} );
697 0         0 $termios->setcc( VMIN, $control_chars{'MIN'} );
698 0         0 $termios->setcc( VSTART, $control_chars{'START'} );
699 0         0 $termios->setcc( VSTOP, $control_chars{'STOP'} );
700 0         0 $termios->setcc( VSUSP, $control_chars{'SUSP'} );
701 0         0 $termios->setcc( VEOL, $control_chars{'EOL'} );
702 0         0 $termios->setattr( $file_num, TCSANOW ); # TCSANOW = do immediately. don't unbuffer first.
703             # OK.. that sucked.
704             }
705              
706             =item B
707              
708             my $output = IO::Stty::show_me_the_crap(
709             $c_cflag, $c_iflag, $ispeed, $c_lflag, $c_oflag,
710             $ospeed, \%control_chars
711             );
712              
713             Format terminal settings as a human-readable string, equivalent to
714             C output. Returns a multi-line string showing the current baud
715             rate, special character assignments (in hat notation), and the state of
716             all control, input, output, and local flags.
717              
718             This is the back-end for C.
719              
720             =cut
721              
722             sub _cc_to_hat {
723 202     202   255522 my ($val) = @_;
724 202 100 100     898 return '' if !defined $val || $val == 0 || $val == 255;
      100        
725 178 100       357 return '^?' if $val == 127;
726 156 100 66     727 return '^' . chr( ord('@') + $val ) if $val >= 0 && $val < 32;
727 2         11 return chr($val);
728             }
729              
730             sub show_me_the_crap {
731             my (
732 21     21 1 212804 $c_cflag, $c_iflag, $ispeed, $c_lflag, $c_oflag,
733             $ospeed, $control_chars
734             ) = @_;
735 21         178 my (%cc) = %$control_chars;
736              
737             # rs = return string
738 21         65 my ($rs) = '';
739 21         48 $rs .= 'speed ';
740 21 100       100 if ( exists $BAUD_SPEEDS{$ospeed} ) {
741 20         46 $rs .= $BAUD_SPEEDS{$ospeed};
742             }
743             else {
744 1         4 $rs .= $ospeed;
745             }
746 21         44 $rs .= " baud;";
747 21 100       59 if ( $ispeed != $ospeed ) {
748 2         5 $rs .= ' ispeed ';
749 2 100       10 if ( exists $BAUD_SPEEDS{$ispeed} ) {
750 1         4 $rs .= $BAUD_SPEEDS{$ispeed};
751             }
752             else {
753 1         4 $rs .= $ispeed;
754             }
755 2         5 $rs .= ' baud;';
756             }
757 21         42 $rs .= "\n";
758 21         59 $rs .= 'intr = ' . _cc_to_hat($cc{'INTR'}) . '; quit = ' . _cc_to_hat($cc{'QUIT'}) . '; erase = ' . _cc_to_hat($cc{'ERASE'}) . '; kill = ' . _cc_to_hat($cc{'KILL'}) . ";\n";
759 21         56 $rs .= 'eof = ' . _cc_to_hat($cc{'EOF'}) . '; eol = ' . _cc_to_hat($cc{'EOL'}) . '; start = ' . _cc_to_hat($cc{'START'}) . '; stop = ' . _cc_to_hat($cc{'STOP'}) . '; susp = ' . _cc_to_hat($cc{'SUSP'}) . ";\n";
760 21   50     125 $rs .= 'min = ' . ($cc{'MIN'} // 0) . '; time = ' . ($cc{'TIME'} // 0) . ";\n";
      50        
761              
762             # c flags.
763 21 50       56 $rs .= ( ( $c_cflag & CLOCAL ) ? '' : '-' ) . 'clocal ';
764 21 50       48 $rs .= ( ( $c_cflag & CREAD ) ? '' : '-' ) . 'cread ';
765 21 50       48 $rs .= ( ( $c_cflag & CSTOPB ) ? '' : '-' ) . 'cstopb ';
766 21 50       65 $rs .= ( ( $c_cflag & HUPCL ) ? '' : '-' ) . 'hupcl ';
767 21 50       57 $rs .= ( ( $c_cflag & PARENB ) ? '' : '-' ) . 'parenb ';
768 21 50       42 $rs .= ( ( $c_cflag & PARODD ) ? '' : '-' ) . 'parodd ';
769 21         35 $c_cflag = $c_cflag & CS8;
770              
771 21 100       54 if ( $c_cflag == CS8 ) {
    50          
    50          
772 5         12 $rs .= "cs8\n";
773             }
774             elsif ( $c_cflag == CS7 ) {
775 0         0 $rs .= "cs7\n";
776             }
777             elsif ( $c_cflag == CS6 ) {
778 0         0 $rs .= "cs6\n";
779             }
780             else {
781 16         24 $rs .= "cs5\n";
782             }
783              
784             # l flags.
785 21 50       55 $rs .= ( ( $c_lflag & ECHO ) ? '' : '-' ) . 'echo ';
786 21 50       51 $rs .= ( ( $c_lflag & ECHOE ) ? '' : '-' ) . 'echoe ';
787 21 50       41 $rs .= ( ( $c_lflag & ECHOK ) ? '' : '-' ) . 'echok ';
788 21 50       48 $rs .= ( ( $c_lflag & ECHONL ) ? '' : '-' ) . 'echonl ';
789 21 50       64 $rs .= ( ( $c_lflag & ICANON ) ? '' : '-' ) . 'icanon ';
790 21 50       40 $rs .= ( ( $c_lflag & ISIG ) ? '' : '-' ) . 'isig ';
791 21 50       44 $rs .= ( ( $c_lflag & NOFLSH ) ? '' : '-' ) . 'noflsh ';
792 21 50       48 $rs .= ( ( $c_lflag & TOSTOP ) ? '' : '-' ) . 'tostop ';
793 21 50       43 $rs .= ( ( $c_lflag & IEXTEN ) ? '' : '-' ) . 'iexten ';
794              
795             # o flag. jam it after the l flags so it looks more compact.
796 21 50       43 $rs .= ( ( $c_oflag & OPOST ) ? '' : '-' ) . "opost\n";
797              
798             # i flags.
799 21 50       45 $rs .= ( ( $c_iflag & BRKINT ) ? '' : '-' ) . 'brkint ';
800 21 50       59 $rs .= ( ( $c_iflag & IGNBRK ) ? '' : '-' ) . 'ignbrk ';
801 21 50       72 $rs .= ( ( $c_iflag & IGNPAR ) ? '' : '-' ) . 'ignpar ';
802 21 50       51 $rs .= ( ( $c_iflag & PARMRK ) ? '' : '-' ) . 'parmrk ';
803 21 50       47 $rs .= ( ( $c_iflag & INPCK ) ? '' : '-' ) . 'inpck ';
804 21 50       40 $rs .= ( ( $c_iflag & ISTRIP ) ? '' : '-' ) . 'istrip ';
805 21 50       47 $rs .= ( ( $c_iflag & INLCR ) ? '' : '-' ) . 'inlcr ';
806 21 50       43 $rs .= ( ( $c_iflag & ICRNL ) ? '' : '-' ) . 'icrnl ';
807 21 50       52 $rs .= ( ( $c_iflag & IXON ) ? '' : '-' ) . 'ixon ';
808 21 50       46 $rs .= ( ( $c_iflag & IXOFF ) ? '' : '-' ) . "ixoff\n";
809 21         131 return $rs;
810             }
811              
812             =back
813              
814             =head1 AUTHOR
815              
816             Austin Schutz (Initial version and maintenance)
817              
818             Todd Rinaldo (Maintenance)
819              
820             =head1 BUGS
821              
822             This is use at your own risk software. Do anything you want with it except
823             blame me for it blowing up your machine because it's full of bugs.
824              
825             See above for what functions are supported. It's mostly standard POSIX
826             stuff. If any of the settings are wrong and you actually know what some of
827             these extremely arcane settings (like what 'sane' should be in POSIX land)
828             really should be, please open an RT ticket.
829              
830             =head1 ACKNOWLEDGEMENTS
831              
832             None
833              
834             =head1 COPYRIGHT & LICENSE
835              
836             Copyright 1997 Austin Schutz, all rights reserved.
837              
838             This program is free software; you can redistribute it and/or modify it
839             under the same terms as Perl itself.
840              
841             =cut
842              
843             1;