@@ -396,6 +396,64 @@ public static void PerformModuleReload(PythonContext context, PythonDictionary d
396396 => tcflow ( context , PythonFcntl . GetFileDescriptor ( context , fd ) , action ) ;
397397
398398
399+ // Python 3.11: tcgetwinsize, tcsetwinsize
400+
401+ [ LightThrowing ]
402+ public static object tcgetwinsize ( CodeContext context , int fd ) {
403+ var ws = new ushort [ 4 ] ;
404+ var buf = new MemoryBufferProtocolWrapper < ushort > ( ws . AsMemory ( ) ) ;
405+
406+ object result = PythonFcntl . ioctl ( fd , TIOCGWINSZ , buf , mutate_flag : true ) ;
407+
408+ if ( ToTermiosError ( context , result ) is not null and var ex ) {
409+ return ex ;
410+ }
411+ return PythonTuple . MakeTuple ( ( int ) ws [ 0 ] , ( int ) ws [ 1 ] ) ;
412+ }
413+
414+ [ LightThrowing ]
415+ public static object ? tcgetwinsize ( CodeContext context , object ? fd )
416+ => tcgetwinsize ( context , PythonFcntl . GetFileDescriptor ( context , fd ) ) ;
417+
418+
419+ [ LightThrowing ]
420+ public static object ? tcsetwinsize ( CodeContext context , int fd , object ? winsize ) {
421+ CheckFileDescriptor ( fd ) ;
422+
423+ if ( winsize is not IList wsList || wsList . Count != 2 ) {
424+ throw PythonOps . TypeError ( "tcsetwinsize, arg 2: must be a two-item sequence" ) ;
425+ }
426+
427+ long winsize_0 = ( long ) PythonOps . ToIndex ( wsList [ 0 ] ) ;
428+ long winsize_1 = ( long ) PythonOps . ToIndex ( wsList [ 1 ] ) ;
429+
430+ var ws = new ushort [ 4 ] ;
431+ var buf = new MemoryBufferProtocolWrapper < ushort > ( ws . AsMemory ( ) ) ;
432+
433+ object result = PythonFcntl . ioctl ( fd , TIOCGWINSZ , buf , mutate_flag : true ) ;
434+ if ( ToTermiosError ( context , result ) is not null and var ex ) {
435+ return ex ;
436+ }
437+
438+ ws [ 0 ] = unchecked ( ( ushort ) winsize_0 ) ;
439+ ws [ 1 ] = unchecked ( ( ushort ) winsize_1 ) ;
440+ if ( ws [ 0 ] != winsize_0 || ws [ 1 ] != winsize_1 ) {
441+ throw PythonOps . OverflowError ( "winsize value(s) out of range" ) ;
442+ }
443+
444+ result = PythonFcntl . ioctl ( fd , TIOCSWINSZ , buf ) ;
445+ if ( ToTermiosError ( context , result ) is not null and var ex2 ) {
446+ return ex2 ;
447+ }
448+
449+ return null ;
450+ }
451+
452+ [ LightThrowing ]
453+ public static object ? tcsetwinsize ( CodeContext context , object ? fd , object ? winsize )
454+ => tcsetwinsize ( context , PythonFcntl . GetFileDescriptor ( context , fd ) , winsize ) ;
455+
456+
399457 public static object tcgetattr ( CodeContext context , int fd ) {
400458 CheckFileDescriptor ( fd ) ;
401459 if ( fd > 0 ) throw new NotImplementedException ( "termios support only for stdin" ) ;
@@ -609,13 +667,28 @@ private static void CheckFileDescriptor(int fd) {
609667 }
610668 }
611669
670+ private static object ? ToTermiosError ( CodeContext context , object ? error ) {
671+ if ( LightExceptions . GetLightException ( error ) is Exception ex ) {
672+ var pex = ex . GetPythonException ( ) ;
673+ if ( pex is PythonExceptions . _OSError oserr ) {
674+ return LightExceptions . Throw ( GetTermiosError ( context , oserr . errno , oserr . strerror ) ) ;
675+ } else {
676+ return error ;
677+ }
678+ }
679+ return null ;
680+ }
612681
613682 private static Exception GetLastTermiosError ( CodeContext context ) {
614683 int errno = Marshal . GetLastWin32Error ( ) ;
615- return PythonExceptions . CreateThrowable ( termioserror ( context ) , errno , PythonNT . strerror ( errno ) ) ;
684+ return GetTermiosError ( context , errno , PythonNT . strerror ( errno ) ) ;
616685 }
617686
618687
688+ private static Exception GetTermiosError ( CodeContext context , object errno , object message )
689+ => PythonExceptions . CreateThrowable ( termioserror ( context ) , errno , message ) ;
690+
691+
619692 private static PythonType termioserror ( CodeContext context )
620693 => ( PythonType ) context . LanguageContext . GetModuleState ( "termioserror" ) ;
621694}
0 commit comments