4
4
// file that was distributed with this source code.
5
5
6
6
// spell-checker:ignore clocal erange tcgetattr tcsetattr tcsanow tiocgwinsz tiocswinsz cfgetospeed cfsetospeed ushort vmin vtime cflag lflag ispeed ospeed
7
+ // spell-checker:ignore parenb parodd cmspar hupcl cstopb cread clocal crtscts CSIZE
8
+ // spell-checker:ignore ignbrk brkint ignpar parmrk inpck istrip inlcr igncr icrnl ixoff ixon iuclc ixany imaxbel iutf
9
+ // spell-checker:ignore opost olcuc ocrnl onlcr onocr onlret ofdel nldly crdly tabdly bsdly vtdly ffdly ofill
10
+ // spell-checker:ignore isig icanon iexten echoe crterase echok echonl noflsh xcase tostop echoprt prterase echoctl ctlecho echoke crtkill flusho extproc
11
+ // spell-checker:ignore lnext rprnt susp swtch vdiscard veof veol verase vintr vkill vlnext vquit vreprint vstart vstop vsusp vswtc vwerase werase
12
+ // spell-checker:ignore sigquit sigtstp
13
+ // spell-checker:ignore cbreak decctlq evenp litout oddp
7
14
8
15
mod flags;
9
16
10
17
use crate :: flags:: AllFlags ;
18
+ use crate :: flags:: COMBINATION_SETTINGS ;
11
19
use clap:: { Arg , ArgAction , ArgMatches , Command } ;
12
20
use nix:: libc:: { O_NONBLOCK , TIOCGWINSZ , TIOCSWINSZ , c_ushort} ;
13
21
use nix:: sys:: termios:: {
14
- ControlFlags , InputFlags , LocalFlags , OutputFlags , SpecialCharacterIndices , Termios ,
22
+ ControlFlags , InputFlags , LocalFlags , OutputFlags , SpecialCharacterIndices as S , Termios ,
15
23
cfgetospeed, cfsetospeed, tcgetattr, tcsetattr,
16
24
} ;
17
25
use nix:: { ioctl_read_bad, ioctl_write_ptr_bad} ;
@@ -104,6 +112,7 @@ enum Device {
104
112
Stdout ( Stdout ) ,
105
113
}
106
114
115
+ #[ derive( Debug ) ]
107
116
enum ControlCharMappingError {
108
117
IntOutOfRange ( String ) ,
109
118
MultipleChars ( String ) ,
@@ -120,7 +129,7 @@ enum PrintSetting {
120
129
121
130
enum ArgOptions < ' a > {
122
131
Flags ( AllFlags < ' a > ) ,
123
- Mapping ( ( SpecialCharacterIndices , u8 ) ) ,
132
+ Mapping ( ( S , u8 ) ) ,
124
133
Special ( SpecialSetting ) ,
125
134
Print ( PrintSetting ) ,
126
135
}
@@ -321,6 +330,9 @@ fn stty(opts: &Options) -> UResult<()> {
321
330
) ) ;
322
331
}
323
332
valid_args. push ( flag. into ( ) ) ;
333
+ // combination setting
334
+ } else if let Some ( combo) = string_to_combo ( arg) {
335
+ valid_args. append ( & mut combo_to_flags ( combo) ) ;
324
336
} else if * arg == "rows" {
325
337
if let Some ( rows) = args_iter. next ( ) {
326
338
if let Some ( n) = parse_rows_cols ( rows) {
@@ -510,7 +522,7 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
510
522
Ok ( ( ) )
511
523
}
512
524
513
- fn cc_to_index ( option : & str ) -> Option < SpecialCharacterIndices > {
525
+ fn cc_to_index ( option : & str ) -> Option < S > {
514
526
for cc in CONTROL_CHARS {
515
527
if option == cc. 0 {
516
528
return Some ( cc. 1 ) ;
@@ -519,6 +531,15 @@ fn cc_to_index(option: &str) -> Option<SpecialCharacterIndices> {
519
531
None
520
532
}
521
533
534
+ fn string_to_combo ( arg : & str ) -> Option < & str > {
535
+ let is_negated = arg. starts_with ( '-' ) ;
536
+ let name = arg. trim_start_matches ( '-' ) ;
537
+ COMBINATION_SETTINGS
538
+ . iter ( )
539
+ . find ( |& & ( combo_name, is_negatable) | name == combo_name && ( !is_negated || is_negatable) )
540
+ . map ( |_| arg)
541
+ }
542
+
522
543
fn string_to_baud ( arg : & str ) -> Option < AllFlags > {
523
544
// BSDs use a u32 for the baud rate, so any decimal number applies.
524
545
#[ cfg( any(
@@ -622,11 +643,11 @@ fn print_control_chars(termios: &Termios, opts: &Options) -> nix::Result<()> {
622
643
HashMap :: from( [
623
644
(
624
645
"min" . to_string( ) ,
625
- termios. control_chars[ SpecialCharacterIndices :: VMIN as usize ] . to_string( )
646
+ termios. control_chars[ S :: VMIN as usize ] . to_string( )
626
647
) ,
627
648
(
628
649
"time" . to_string( ) ,
629
- termios. control_chars[ SpecialCharacterIndices :: VTIME as usize ] . to_string( )
650
+ termios. control_chars[ S :: VTIME as usize ] . to_string( )
630
651
)
631
652
] )
632
653
)
@@ -741,7 +762,7 @@ fn apply_baud_rate_flag(termios: &mut Termios, input: &AllFlags) {
741
762
}
742
763
}
743
764
744
- fn apply_char_mapping ( termios : & mut Termios , mapping : & ( SpecialCharacterIndices , u8 ) ) {
765
+ fn apply_char_mapping ( termios : & mut Termios , mapping : & ( S , u8 ) ) {
745
766
termios. control_chars [ mapping. 0 as usize ] = mapping. 1 ;
746
767
}
747
768
@@ -807,6 +828,124 @@ fn string_to_control_char(s: &str) -> Result<u8, ControlCharMappingError> {
807
828
}
808
829
}
809
830
831
+ // decomposes a combination argument into a vec of corresponding flags
832
+ fn combo_to_flags ( combo : & str ) -> Vec < ArgOptions > {
833
+ let mut flags = Vec :: new ( ) ;
834
+ let mut ccs = Vec :: new ( ) ;
835
+ match combo {
836
+ "lcase" | "LCASE" => {
837
+ flags = vec ! [ "xcase" , "iuclc" , "olcuc" ] ;
838
+ }
839
+ "-lcase" | "-LCASE" => {
840
+ flags = vec ! [ "-xcase" , "-iuclc" , "-olcuc" ] ;
841
+ }
842
+ "cbreak" => {
843
+ flags = vec ! [ "-icanon" ] ;
844
+ }
845
+ "-cbreak" => {
846
+ flags = vec ! [ "icanon" ] ;
847
+ }
848
+ "cooked" | "-raw" => {
849
+ flags = vec ! [
850
+ "brkint" , "ignpar" , "istrip" , "icrnl" , "ixon" , "opost" , "isig" , "icanon" ,
851
+ ] ;
852
+ ccs = vec ! [ ( S :: VEOF , "^D" ) , ( S :: VEOL , "" ) ] ;
853
+ }
854
+ "crt" => {
855
+ flags = vec ! [ "echoe" , "echoctl" , "echoke" ] ;
856
+ }
857
+ "dec" => {
858
+ flags = vec ! [ "echoe" , "echoctl" , "echoke" , "-ixany" ] ;
859
+ ccs = vec ! [ ( S :: VINTR , "^C" ) , ( S :: VERASE , "^?" ) , ( S :: VKILL , "^U" ) ] ;
860
+ }
861
+ "decctlq" => {
862
+ flags = vec ! [ "ixany" ] ;
863
+ }
864
+ "-decctlq" => {
865
+ flags = vec ! [ "-ixany" ] ;
866
+ }
867
+ "ek" => {
868
+ ccs = vec ! [ ( S :: VERASE , "^?" ) , ( S :: VKILL , "^U" ) ] ;
869
+ }
870
+ "evenp" | "parity" => {
871
+ flags = vec ! [ "parenb" , "-parodd" , "cs7" ] ;
872
+ }
873
+ "-evenp" | "-parity" => {
874
+ flags = vec ! [ "-parenb" , "cs8" ] ;
875
+ }
876
+ "litout" => {
877
+ flags = vec ! [ "-parenb" , "-istrip" , "-opost" , "-cs8" ] ;
878
+ }
879
+ "-litout" => {
880
+ flags = vec ! [ "parenb" , "istrip" , "opost" , "cs7" ] ;
881
+ }
882
+ "nl" => {
883
+ flags = vec ! [ "-icrnl" , "-onlcr" ] ;
884
+ }
885
+ "-nl" => {
886
+ flags = vec ! [ "icrnl" , "-inlcr" , "-igncr" , "onlcr" , "-ocrnl" , "-onlret" ] ;
887
+ }
888
+ "oddp" => {
889
+ flags = vec ! [ "parenb" , "parodd" , "cs7" ] ;
890
+ }
891
+ "-oddp" => {
892
+ flags = vec ! [ "-parenb" , "cs8" ] ;
893
+ }
894
+ "pass8" => {
895
+ flags = vec ! [ "-parenb" , "-istrip" , "cs8" ] ;
896
+ }
897
+ "-pass8" => {
898
+ flags = vec ! [ "parenb" , "istrip" , "cs7" ] ;
899
+ }
900
+ "raw" | "-cooked" => {
901
+ flags = vec ! [
902
+ "-ignbrk" , "-brkint" , "-ignpar" , "-parmrk" , "-inpck" , "-istrip" , "-inlcr" ,
903
+ "-igncr" , "-icrnl" , "-ixon" , "-ixoff" , "-icanon" , "-opost" , "-isig" , "-iuclc" ,
904
+ "-xcase" , "-ixany" , "-imaxbel" ,
905
+ ] ;
906
+ // TODO: add 'min 1' and 'time 0' settings here after they have been implemented
907
+ }
908
+ "sane" => {
909
+ flags = vec ! [
910
+ "cread" , "-ignbrk" , "brkint" , "-inlcr" , "-igncr" , "icrnl" , "icanon" , "iexten" ,
911
+ "echo" , "echoe" , "echok" , "-echonl" , "-noflsh" , "-ixoff" , "-iutf8" , "-iuclc" ,
912
+ "-xcase" , "-ixany" , "imaxbel" , "-olcuc" , "-ocrnl" , "opost" , "-ofill" , "onlcr" ,
913
+ "-onocr" , "-onlret" , "n10" , "cr0" , "tab0" , "bs0" , "vt0" , "ff0" , "isig" , "-tostop" ,
914
+ "-ofdel" , "-echoprt" , "echoctl" , "echoke" , "-extproc" , "-flush0" ,
915
+ ] ;
916
+ ccs = vec ! [
917
+ ( S :: VINTR , "^C" ) ,
918
+ ( S :: VQUIT , "^\\ " ) ,
919
+ ( S :: VERASE , "^?" ) ,
920
+ ( S :: VKILL , "^U" ) ,
921
+ ( S :: VEOF , "^D" ) ,
922
+ ( S :: VEOL , "" ) ,
923
+ ( S :: VEOL2 , "" ) ,
924
+ #[ cfg( target_os = "linux" ) ]
925
+ ( S :: VSWTC , "" ) ,
926
+ ( S :: VSTART , "^Q" ) ,
927
+ ( S :: VSTOP , "^S" ) ,
928
+ ( S :: VSUSP , "^Z" ) ,
929
+ ( S :: VREPRINT , "^R" ) ,
930
+ ( S :: VWERASE , "^W" ) ,
931
+ ( S :: VLNEXT , "^V" ) ,
932
+ ( S :: VDISCARD , "^O" ) ,
933
+ ] ;
934
+ }
935
+ _ => unreachable ! ( "invalid combination setting: must have been caught earlier" ) ,
936
+ }
937
+ let mut flags = flags
938
+ . iter ( )
939
+ . filter_map ( |f| string_to_flag ( f) . map ( ArgOptions :: Flags ) )
940
+ . collect :: < Vec < ArgOptions > > ( ) ;
941
+ let mut ccs = ccs
942
+ . iter ( )
943
+ . map ( |cc| ArgOptions :: Mapping ( ( cc. 0 , string_to_control_char ( cc. 1 ) . unwrap ( ) ) ) )
944
+ . collect :: < Vec < ArgOptions > > ( ) ;
945
+ flags. append ( & mut ccs) ;
946
+ flags
947
+ }
948
+
810
949
pub fn uu_app ( ) -> Command {
811
950
Command :: new ( uucore:: util_name ( ) )
812
951
. version ( uucore:: crate_version!( ) )
0 commit comments