@@ -264,6 +264,9 @@ fn stty(opts: &Options) -> UResult<()> {
264264 ) ) ;
265265 }
266266
267+ // Fetch termios for the target device once and reuse it downstream
268+ let base_termios = tcgetattr ( opts. file . as_fd ( ) ) ?;
269+
267270 let mut set_arg = SetArg :: TCSADRAIN ;
268271 let mut valid_args: Vec < ArgOptions > = Vec :: new ( ) ;
269272
@@ -274,11 +277,16 @@ fn stty(opts: &Options) -> UResult<()> {
274277
275278 if let Some ( args) = & opts. settings {
276279 if let Some ( ( first, rest) ) = args. split_first ( ) {
277- if let Ok ( termios) = parse_save_format ( first) {
278- restored_from_save = Some ( termios) ;
279- settings_iter = Box :: new ( rest. iter ( ) . copied ( ) ) ;
280- } else {
281- settings_iter = Box :: new ( args. iter ( ) . map ( |s| & * * s) ) ;
280+ match parse_save_format ( first, & base_termios) {
281+ Ok ( termios) => {
282+ restored_from_save = Some ( termios) ;
283+ settings_iter = Box :: new ( rest. iter ( ) . copied ( ) ) ;
284+ }
285+ // GNU stty は先頭が save 形式っぽいのにパースできなければ即エラーにする
286+ Err ( e) if first. contains ( ':' ) => return Err ( e) ,
287+ Err ( _) => {
288+ settings_iter = Box :: new ( args. iter ( ) . map ( |s| & * * s) ) ;
289+ }
282290 }
283291 }
284292 }
@@ -426,11 +434,7 @@ fn stty(opts: &Options) -> UResult<()> {
426434 }
427435
428436 // TODO: Figure out the right error message for when tcgetattr fails
429- let mut termios = if let Some ( restored) = restored_from_save {
430- restored
431- } else {
432- tcgetattr ( opts. file . as_fd ( ) ) ?
433- } ;
437+ let mut termios = restored_from_save. unwrap_or ( base_termios) ;
434438
435439 // iterate over valid_args, match on the arg type, do the matching apply function
436440 for arg in & valid_args {
@@ -447,9 +451,7 @@ fn stty(opts: &Options) -> UResult<()> {
447451 }
448452 tcsetattr ( opts. file . as_fd ( ) , set_arg, & termios) ?;
449453 } else {
450- // TODO: Figure out the right error message for when tcgetattr fails
451- let termios = tcgetattr ( opts. file . as_fd ( ) ) ?;
452- print_settings ( & termios, opts) ?;
454+ print_settings ( & base_termios, opts) ?;
453455 }
454456 Ok ( ( ) )
455457}
@@ -719,7 +721,7 @@ fn print_in_save_format(termios: &Termios) {
719721
720722/// GNU stty -g compatibility: restore Termios from the colon-separated hexadecimal representation
721723/// produced by print_in_save_format.
722- fn parse_save_format ( s : & str ) -> Result < Termios , Box < dyn UError > > {
724+ fn parse_save_format ( s : & str , base : & Termios ) -> Result < Termios , Box < dyn UError > > {
723725 // Expect four flag values + a variable-length sequence of cc_t values (at least one).
724726 let parts: Vec < & str > = s. split ( ':' ) . collect ( ) ;
725727 if parts. len ( ) < 5 {
@@ -747,10 +749,8 @@ fn parse_save_format(s: &str) -> Result<Termios, Box<dyn UError>> {
747749 // Remaining segments are control_chars.
748750 let cc_hex = & parts[ 4 ..] ;
749751
750- // Obtain the original termios and overwrite specific fields on top of it to preserve
751- // platform-dependent fields.
752- let mut termios = tcgetattr ( std:: io:: stdout ( ) . as_fd ( ) )
753- . map_err ( |_| USimpleError :: new ( 1 , translate ! ( "stty-error-io" ) ) ) ?;
752+ // base で渡されたデバイスの termios をコピーし、プラットフォーム依存フィールドを保持する
753+ let mut termios = base. clone ( ) ;
754754
755755 termios. input_flags = InputFlags :: from_bits_truncate ( iflags_bits) ;
756756 termios. output_flags = OutputFlags :: from_bits_truncate ( oflags_bits) ;
0 commit comments