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 vintr vquit verase vkill veof vstart vstop vsusp vreprint vwerase vlnext vdiscard veol vswtc vswtc
7
8
8
9
mod flags;
9
10
@@ -38,6 +39,22 @@ use flags::{CONTROL_CHARS, CONTROL_FLAGS, INPUT_FLAGS, LOCAL_FLAGS, OUTPUT_FLAGS
38
39
39
40
const ASCII_DEL : u8 = 127 ;
40
41
42
+ // Sane defaults for control characters.
43
+ const SANE_CONTROL_CHARS : [ ( SpecialCharacterIndices , u8 ) ; 12 ] = [
44
+ ( SpecialCharacterIndices :: VINTR , 3 ) , // ^C
45
+ ( SpecialCharacterIndices :: VQUIT , 28 ) , // ^\
46
+ ( SpecialCharacterIndices :: VERASE , 127 ) , // DEL
47
+ ( SpecialCharacterIndices :: VKILL , 21 ) , // ^U
48
+ ( SpecialCharacterIndices :: VEOF , 4 ) , // ^D
49
+ ( SpecialCharacterIndices :: VSTART , 17 ) , // ^Q
50
+ ( SpecialCharacterIndices :: VSTOP , 19 ) , // ^S
51
+ ( SpecialCharacterIndices :: VSUSP , 26 ) , // ^Z
52
+ ( SpecialCharacterIndices :: VREPRINT , 18 ) , // ^R
53
+ ( SpecialCharacterIndices :: VWERASE , 23 ) , // ^W
54
+ ( SpecialCharacterIndices :: VLNEXT , 22 ) , // ^V
55
+ ( SpecialCharacterIndices :: VDISCARD , 15 ) , // ^O
56
+ ] ;
57
+
41
58
#[ derive( Clone , Copy , Debug ) ]
42
59
pub struct Flag < T > {
43
60
name : & ' static str ,
@@ -112,6 +129,7 @@ enum ControlCharMappingError {
112
129
enum SpecialSetting {
113
130
Rows ( u16 ) ,
114
131
Cols ( u16 ) ,
132
+ Sane ,
115
133
}
116
134
117
135
enum PrintSetting {
@@ -367,6 +385,8 @@ fn stty(opts: &Options) -> UResult<()> {
367
385
}
368
386
} else if * arg == "size" {
369
387
valid_args. push ( ArgOptions :: Print ( PrintSetting :: Size ) ) ;
388
+ } else if * arg == "sane" {
389
+ valid_args. push ( ArgOptions :: Special ( SpecialSetting :: Sane ) ) ;
370
390
// not a valid option
371
391
} else {
372
392
return Err ( USimpleError :: new (
@@ -388,7 +408,7 @@ fn stty(opts: &Options) -> UResult<()> {
388
408
ArgOptions :: Mapping ( mapping) => apply_char_mapping ( & mut termios, mapping) ,
389
409
ArgOptions :: Flags ( flag) => apply_setting ( & mut termios, flag) ,
390
410
ArgOptions :: Special ( setting) => {
391
- apply_special_setting ( setting, opts. file . as_raw_fd ( ) ) ?;
411
+ apply_special_setting ( setting, opts. file . as_raw_fd ( ) , & mut termios ) ?;
392
412
}
393
413
ArgOptions :: Print ( setting) => {
394
414
print_special_setting ( setting, opts. file . as_raw_fd ( ) ) ?;
@@ -605,7 +625,21 @@ fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result<String> {
605
625
606
626
fn print_control_chars ( termios : & Termios , opts : & Options ) -> nix:: Result < ( ) > {
607
627
if !opts. all {
608
- // TODO: this branch should print values that differ from defaults
628
+ // Print only control chars that differ from sane defaults
629
+ let mut printed = false ;
630
+ for ( text, cc_index) in CONTROL_CHARS {
631
+ let current_val = termios. control_chars [ * cc_index as usize ] ;
632
+ let sane_val = get_sane_control_char ( * cc_index) ;
633
+
634
+ if current_val != sane_val {
635
+ print ! ( "{text} = {}; " , control_char_to_string( current_val) ?) ;
636
+ printed = true ;
637
+ }
638
+ }
639
+
640
+ if printed {
641
+ println ! ( ) ;
642
+ }
609
643
return Ok ( ( ) ) ;
610
644
}
611
645
@@ -745,14 +779,28 @@ fn apply_char_mapping(termios: &mut Termios, mapping: &(SpecialCharacterIndices,
745
779
termios. control_chars [ mapping. 0 as usize ] = mapping. 1 ;
746
780
}
747
781
748
- fn apply_special_setting ( setting : & SpecialSetting , fd : i32 ) -> nix:: Result < ( ) > {
749
- let mut size = TermSize :: default ( ) ;
750
- unsafe { tiocgwinsz ( fd, & raw mut size) ? } ;
782
+ fn apply_special_setting (
783
+ setting : & SpecialSetting ,
784
+ fd : i32 ,
785
+ termios : & mut Termios ,
786
+ ) -> nix:: Result < ( ) > {
751
787
match setting {
752
- SpecialSetting :: Rows ( n) => size. rows = * n,
753
- SpecialSetting :: Cols ( n) => size. columns = * n,
788
+ SpecialSetting :: Rows ( n) => {
789
+ let mut size = TermSize :: default ( ) ;
790
+ unsafe { tiocgwinsz ( fd, & raw mut size) ? } ;
791
+ size. rows = * n;
792
+ unsafe { tiocswinsz ( fd, & raw mut size) ? } ;
793
+ }
794
+ SpecialSetting :: Cols ( n) => {
795
+ let mut size = TermSize :: default ( ) ;
796
+ unsafe { tiocgwinsz ( fd, & raw mut size) ? } ;
797
+ size. columns = * n;
798
+ unsafe { tiocswinsz ( fd, & raw mut size) ? } ;
799
+ }
800
+ SpecialSetting :: Sane => {
801
+ apply_sane_settings ( termios) ;
802
+ }
754
803
}
755
- unsafe { tiocswinsz ( fd, & raw mut size) ? } ;
756
804
Ok ( ( ) )
757
805
}
758
806
@@ -807,6 +855,61 @@ fn string_to_control_char(s: &str) -> Result<u8, ControlCharMappingError> {
807
855
}
808
856
}
809
857
858
+ fn get_sane_control_char ( cc_index : SpecialCharacterIndices ) -> u8 {
859
+ for ( sane_index, sane_val) in SANE_CONTROL_CHARS {
860
+ if sane_index == cc_index {
861
+ return sane_val;
862
+ }
863
+ }
864
+ // Default values for control chars not in the sane list
865
+ match cc_index {
866
+ SpecialCharacterIndices :: VEOL => 0 ,
867
+ SpecialCharacterIndices :: VEOL2 => 0 ,
868
+ SpecialCharacterIndices :: VMIN => 1 ,
869
+ SpecialCharacterIndices :: VTIME => 0 ,
870
+ #[ cfg( target_os = "linux" ) ]
871
+ SpecialCharacterIndices :: VSWTC => 0 ,
872
+ _ => 0 ,
873
+ }
874
+ }
875
+
876
+ fn apply_sane_settings ( termios : & mut Termios ) {
877
+ // Set sane control characters
878
+ for ( cc_index, sane_val) in SANE_CONTROL_CHARS {
879
+ termios. control_chars [ cc_index as usize ] = sane_val;
880
+ }
881
+
882
+ // Set other sane control character defaults
883
+ termios. control_chars [ SpecialCharacterIndices :: VEOL as usize ] = 0 ;
884
+ termios. control_chars [ SpecialCharacterIndices :: VEOL2 as usize ] = 0 ;
885
+ termios. control_chars [ SpecialCharacterIndices :: VMIN as usize ] = 1 ;
886
+ termios. control_chars [ SpecialCharacterIndices :: VTIME as usize ] = 0 ;
887
+ #[ cfg( target_os = "linux" ) ]
888
+ {
889
+ termios. control_chars [ SpecialCharacterIndices :: VSWTC as usize ] = 0 ;
890
+ }
891
+
892
+ // Apply sane flags
893
+ use flags:: { CONTROL_FLAGS , INPUT_FLAGS , LOCAL_FLAGS , OUTPUT_FLAGS } ;
894
+
895
+ macro_rules! apply_sane_flags {
896
+ ( $flags: ident) => {
897
+ for flag in $flags {
898
+ if flag. sane {
899
+ flag. flag. apply( termios, true ) ;
900
+ } else {
901
+ flag. flag. apply( termios, false ) ;
902
+ }
903
+ }
904
+ } ;
905
+ }
906
+
907
+ apply_sane_flags ! ( CONTROL_FLAGS ) ;
908
+ apply_sane_flags ! ( INPUT_FLAGS ) ;
909
+ apply_sane_flags ! ( OUTPUT_FLAGS ) ;
910
+ apply_sane_flags ! ( LOCAL_FLAGS ) ;
911
+ }
912
+
810
913
pub fn uu_app ( ) -> Command {
811
914
Command :: new ( uucore:: util_name ( ) )
812
915
. version ( uucore:: crate_version!( ) )
0 commit comments