Skip to content

Commit 82873fc

Browse files
authored
Implement simple termios functions (#1899)
1 parent e3272b9 commit 82873fc

File tree

2 files changed

+94
-9
lines changed

2 files changed

+94
-9
lines changed

src/core/IronPython.Modules/fcntl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ public static object ioctl(CodeContext context, int fd, int cmd, [NotNone] IBuff
222222

223223
#region Helper Methods
224224

225-
private static int GetFileDescriptor(CodeContext context, object? obj) {
225+
internal static int GetFileDescriptor(CodeContext context, object? obj) {
226226
if (!PythonOps.TryGetBoundAttr(context, obj, "fileno", out object? filenoMeth)) {
227227
throw PythonOps.TypeError("argument must be an int, or have a fileno() method.");
228228
}

src/core/IronPython.Modules/termios.cs

Lines changed: 93 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
using Microsoft.Scripting.Runtime;
1515

1616
using IronPython.Runtime;
17+
using IronPython.Runtime.Exceptions;
1718
using IronPython.Runtime.Operations;
19+
using IronPython.Runtime.Types;
1820

1921
using static IronPython.Modules.PythonIOModule;
2022

@@ -323,8 +325,81 @@ public static void PerformModuleReload(PythonContext context, PythonDictionary d
323325
public static int B230400 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 230400 : 0x1003;
324326
// higher baud rates are not defined on macOS
325327

328+
#endregion
329+
330+
331+
#region Public Functions
332+
333+
[DllImport("libc", SetLastError = true, EntryPoint = "tcsendbreak")]
334+
private static extern int _tcsendbreak(int fd, int duration);
335+
336+
[LightThrowing]
337+
public static object? tcsendbreak(CodeContext context, int fd, int duration) {
338+
CheckFileDescriptor(fd);
339+
if (_tcsendbreak(fd, duration) == -1) {
340+
return LightExceptions.Throw(GetLastTermiosError(context));
341+
}
342+
return null;
343+
}
344+
345+
[LightThrowing]
346+
public static object? tcsendbreak(CodeContext context, object? fd, int duration)
347+
=> tcsendbreak(context, PythonFcntl.GetFileDescriptor(context, fd), duration);
348+
349+
350+
[DllImport("libc", SetLastError = true, EntryPoint = "tcdrain")]
351+
private static extern int _tcdrain(int fd);
352+
353+
[LightThrowing]
354+
public static object? tcdrain(CodeContext context, int fd) {
355+
CheckFileDescriptor(fd);
356+
if (_tcdrain(fd) == -1) {
357+
return LightExceptions.Throw(GetLastTermiosError(context));
358+
}
359+
return null;
360+
}
361+
362+
[LightThrowing]
363+
public static object? tcdrain(CodeContext context, object? fd)
364+
=> tcdrain(context, PythonFcntl.GetFileDescriptor(context, fd));
365+
366+
367+
[DllImport("libc", SetLastError = true, EntryPoint = "tcflush")]
368+
private static extern int _tcflush(int fd, int queue);
369+
370+
[LightThrowing]
371+
public static object? tcflush(CodeContext context, int fd, int queue) {
372+
CheckFileDescriptor(fd);
373+
if (_tcflush(fd, queue) == -1) {
374+
return LightExceptions.Throw(GetLastTermiosError(context));
375+
}
376+
return null;
377+
}
378+
379+
[LightThrowing]
380+
public static object? tcflush(CodeContext context, object? fd, int queue)
381+
=> tcflush(context, PythonFcntl.GetFileDescriptor(context, fd), queue);
382+
383+
384+
[DllImport("libc", SetLastError = true, EntryPoint = "tcflow")]
385+
private static extern int _tcflow(int fd, int action);
386+
387+
[LightThrowing]
388+
public static object? tcflow(CodeContext context, int fd, int action) {
389+
CheckFileDescriptor(fd);
390+
if (_tcflow(fd, action) == -1) {
391+
return LightExceptions.Throw(GetLastTermiosError(context));
392+
}
393+
return null;
394+
}
395+
396+
[LightThrowing]
397+
public static object? tcflow(CodeContext context, object? fd, int action)
398+
=> tcflow(context, PythonFcntl.GetFileDescriptor(context, fd), action);
399+
400+
326401
public static object tcgetattr(CodeContext context, int fd) {
327-
if (fd < 0) throw PythonOps.ValueError("file descriptor cannot be a negative integer ({0})", fd);
402+
CheckFileDescriptor(fd);
328403
if (fd > 0) throw new NotImplementedException("termios support only for stdin");
329404

330405
if (context.LanguageContext.SystemStandardIn is not TextIOWrapper stdin) {
@@ -360,6 +435,7 @@ public static object tcgetattr(CodeContext context, object? file) {
360435

361436

362437
public static void tcsetattr(CodeContext context, int fd, int when, object? attributes) {
438+
CheckFileDescriptor(fd);
363439
if (fd != 0) throw new NotImplementedException();
364440

365441
if (context.LanguageContext.SystemStandardIn is not TextIOWrapper stdin) {
@@ -528,11 +604,20 @@ public RawConsole(CodeContext context) : base(context) {
528604
public override bool isatty(CodeContext context) => true;
529605
}
530606

531-
private static int ToInt(this object? o)
532-
=> o switch {
533-
int i => i,
534-
BigInteger bi => (int)bi,
535-
Extensible<BigInteger> ebi => (int)ebi.Value,
536-
_ => throw PythonOps.TypeErrorForBadInstance("an integer is required (got type {0})", o)
537-
};
607+
608+
private static void CheckFileDescriptor(int fd) {
609+
if (fd < 0) {
610+
throw PythonOps.ValueError("file descriptor cannot be a negative integer ({0})", fd);
611+
}
612+
}
613+
614+
615+
private static Exception GetLastTermiosError(CodeContext context) {
616+
int errno = Marshal.GetLastWin32Error();
617+
return PythonExceptions.CreateThrowable(termioserror(context), errno, PythonNT.strerror(errno));
618+
}
619+
620+
621+
private static PythonType termioserror(CodeContext context)
622+
=> (PythonType)context.LanguageContext.GetModuleState("termioserror");
538623
}

0 commit comments

Comments
 (0)