@@ -108,9 +108,20 @@ enum ControlCharMappingError {
108
108
MultipleChars ,
109
109
}
110
110
111
+ enum SpecialSetting {
112
+ Rows ( u16 ) ,
113
+ Cols ( u16 ) ,
114
+ }
115
+
116
+ enum PrintSetting {
117
+ Size ,
118
+ }
119
+
111
120
enum ArgOptions < ' a > {
112
121
Flags ( AllFlags < ' a > ) ,
113
122
Mapping ( ( SpecialCharacterIndices , u8 ) ) ,
123
+ Special ( SpecialSetting ) ,
124
+ Print ( PrintSetting ) ,
114
125
}
115
126
116
127
impl < ' a > From < AllFlags < ' a > > for ArgOptions < ' a > {
@@ -280,7 +291,35 @@ fn stty(opts: &Options) -> UResult<()> {
280
291
return Err ( USimpleError :: new ( 1 , format ! ( "invalid argument '{arg}'" ) ) ) ;
281
292
}
282
293
valid_args. push ( flag. into ( ) ) ;
283
- // not a valid control char or flag
294
+ } else if * arg == "rows" {
295
+ if let Some ( rows) = args_iter. next ( ) {
296
+ if let Some ( n) = parse_rows_cols ( rows) {
297
+ valid_args. push ( ArgOptions :: Special ( SpecialSetting :: Rows ( n) ) ) ;
298
+ } else {
299
+ return Err ( USimpleError :: new (
300
+ 1 ,
301
+ format ! ( "invalid integer argument: '{rows}'" ) ,
302
+ ) ) ;
303
+ }
304
+ } else {
305
+ return Err ( USimpleError :: new ( 1 , format ! ( "missing argument to '{arg}'" ) ) ) ;
306
+ }
307
+ } else if * arg == "columns" || * arg == "cols" {
308
+ if let Some ( cols) = args_iter. next ( ) {
309
+ if let Some ( n) = parse_rows_cols ( cols) {
310
+ valid_args. push ( ArgOptions :: Special ( SpecialSetting :: Cols ( n) ) ) ;
311
+ } else {
312
+ return Err ( USimpleError :: new (
313
+ 1 ,
314
+ format ! ( "invalid integer argument: '{cols}'" ) ,
315
+ ) ) ;
316
+ }
317
+ } else {
318
+ return Err ( USimpleError :: new ( 1 , format ! ( "missing argument to '{arg}'" ) ) ) ;
319
+ }
320
+ } else if * arg == "size" {
321
+ valid_args. push ( ArgOptions :: Print ( PrintSetting :: Size ) ) ;
322
+ // not a valid option
284
323
} else {
285
324
return Err ( USimpleError :: new ( 1 , format ! ( "invalid argument '{arg}'" ) ) ) ;
286
325
}
@@ -294,6 +333,12 @@ fn stty(opts: &Options) -> UResult<()> {
294
333
match arg {
295
334
ArgOptions :: Mapping ( mapping) => apply_char_mapping ( & mut termios, mapping) ,
296
335
ArgOptions :: Flags ( flag) => apply_setting ( & mut termios, flag) ,
336
+ ArgOptions :: Special ( setting) => {
337
+ apply_special_setting ( setting, opts. file . as_raw_fd ( ) ) ?;
338
+ }
339
+ ArgOptions :: Print ( setting) => {
340
+ print_special_setting ( setting, opts. file . as_raw_fd ( ) ) ?;
341
+ }
297
342
}
298
343
}
299
344
tcsetattr (
@@ -310,10 +355,30 @@ fn stty(opts: &Options) -> UResult<()> {
310
355
Ok ( ( ) )
311
356
}
312
357
358
+ // GNU uses an unsigned 32 bit integer for row/col sizes, but then wraps around 16 bits
359
+ // this function returns Some(n), where n is a u16 row/col size, or None if the string arg cannot be parsed as a u32
360
+ fn parse_rows_cols ( arg : & str ) -> Option < u16 > {
361
+ if let Ok ( n) = arg. parse :: < u32 > ( ) {
362
+ return Some ( ( n % ( u16:: MAX as u32 + 1 ) ) as u16 ) ;
363
+ }
364
+ None
365
+ }
366
+
313
367
fn check_flag_group < T > ( flag : & Flag < T > , remove : bool ) -> bool {
314
368
remove && flag. group . is_some ( )
315
369
}
316
370
371
+ fn print_special_setting ( setting : & PrintSetting , fd : i32 ) -> nix:: Result < ( ) > {
372
+ match setting {
373
+ PrintSetting :: Size => {
374
+ let mut size = TermSize :: default ( ) ;
375
+ unsafe { tiocgwinsz ( fd, & raw mut size) ? } ;
376
+ println ! ( "{} {}" , size. rows, size. columns) ;
377
+ }
378
+ }
379
+ Ok ( ( ) )
380
+ }
381
+
317
382
fn print_terminal_size ( termios : & Termios , opts : & Options ) -> nix:: Result < ( ) > {
318
383
let speed = cfgetospeed ( termios) ;
319
384
@@ -588,6 +653,17 @@ fn apply_char_mapping(termios: &mut Termios, mapping: &(SpecialCharacterIndices,
588
653
termios. control_chars [ mapping. 0 as usize ] = mapping. 1 ;
589
654
}
590
655
656
+ fn apply_special_setting ( setting : & SpecialSetting , fd : i32 ) -> nix:: Result < ( ) > {
657
+ let mut size = TermSize :: default ( ) ;
658
+ unsafe { tiocgwinsz ( fd, & raw mut size) ? } ;
659
+ match setting {
660
+ SpecialSetting :: Rows ( n) => size. rows = * n,
661
+ SpecialSetting :: Cols ( n) => size. columns = * n,
662
+ }
663
+ unsafe { tiocswinsz ( fd, & raw mut size) ? } ;
664
+ Ok ( ( ) )
665
+ }
666
+
591
667
// GNU stty defines some valid values for the control character mappings
592
668
// 1. Standard character, can be a a single char (ie 'C') or hat notation (ie '^C')
593
669
// 2. Integer
0 commit comments