forked from IronLanguages/ironpython3
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtermios.cs
More file actions
807 lines (620 loc) · 31.9 KB
/
termios.cs
File metadata and controls
807 lines (620 loc) · 31.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Microsoft.Scripting.Runtime;
using IronPython.Runtime;
using IronPython.Runtime.Exceptions;
using IronPython.Runtime.Operations;
using IronPython.Runtime.Types;
using static IronPython.Modules.PythonIOModule;
[assembly: PythonModule("termios", typeof(IronPython.Modules.PythonTermios), PlatformsAttribute.PlatformFamily.Unix)]
namespace IronPython.Modules;
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public static class PythonTermios {
public const string __doc__ = """
This module provides an interface to the Posix calls for tty I/O control.
For a complete description of these calls, see the Posix or Unix manual
pages. It is only available for those Unix versions that support Posix
termios style tty I/O control.
All functions in this module take a file descriptor fd as their first
argument. This can be an integer file descriptor, such as returned by
sys.stdin.fileno(), or a file object, such as sys.stdin itself.
""";
[SpecialName]
public static void PerformModuleReload(PythonContext context, PythonDictionary dict)
=> context.EnsureModuleException("termioserror", dict, "error", "termios");
#region Generated TIOC Commands
// *** BEGIN GENERATED CODE ***
// generated by function: generate_TIOC_commands from: generate_os_codes.py
public static long TIOCCONS => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x80047462 : 0x541d;
public static int TIOCEXCL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x2000740d : 0x540c;
public static int TIOCGETD => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x4004741a : 0x5424;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCGICOUNT => 0x545d;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCGLCKTRMIOS => 0x5456;
public static int TIOCGPGRP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x40047477 : 0x540f;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCGSERIAL => 0x541e;
[PythonHidden(PlatformID.Unix)]
[SupportedOSPlatform("macos")]
public static int TIOCGSIZE => 0x40087468;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCGSOFTCAR => 0x5419;
public static int TIOCGWINSZ => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x40087468 : 0x5413;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCINQ => 0x541b;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCLINUX => 0x541c;
public static long TIOCMBIC => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x8004746b : 0x5417;
public static long TIOCMBIS => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x8004746c : 0x5416;
public static int TIOCMGET => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x4004746a : 0x5415;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCMIWAIT => 0x545c;
public static long TIOCMSET => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x8004746d : 0x5418;
public static int TIOCM_CAR => 0x40;
public static int TIOCM_CD => 0x40;
public static int TIOCM_CTS => 0x20;
public static int TIOCM_DSR => 0x100;
public static int TIOCM_DTR => 0x2;
public static int TIOCM_LE => 0x1;
public static int TIOCM_RI => 0x80;
public static int TIOCM_RNG => 0x80;
public static int TIOCM_RTS => 0x4;
public static int TIOCM_SR => 0x10;
public static int TIOCM_ST => 0x8;
public static int TIOCNOTTY => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x20007471 : 0x5422;
public static int TIOCNXCL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x2000740e : 0x540d;
public static int TIOCOUTQ => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x40047473 : 0x5411;
public static long TIOCPKT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x80047470 : 0x5420;
public static int TIOCPKT_DATA => 0x0;
public static int TIOCPKT_DOSTOP => 0x20;
public static int TIOCPKT_FLUSHREAD => 0x1;
public static int TIOCPKT_FLUSHWRITE => 0x2;
public static int TIOCPKT_NOSTOP => 0x10;
public static int TIOCPKT_START => 0x8;
public static int TIOCPKT_STOP => 0x4;
public static int TIOCSCTTY => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x20007461 : 0x540e;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSERCONFIG => 0x5453;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSERGETLSR => 0x5459;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSERGETMULTI => 0x545a;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSERGSTRUCT => 0x5458;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSERGWILD => 0x5454;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSERSETMULTI => 0x545b;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSERSWILD => 0x5455;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSER_TEMT => 0x1;
public static long TIOCSETD => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x8004741b : 0x5423;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSLCKTRMIOS => 0x5457;
public static long TIOCSPGRP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x80047476 : 0x5410;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSSERIAL => 0x541f;
[PythonHidden(PlatformID.Unix)]
[SupportedOSPlatform("macos")]
public static long TIOCSSIZE => 0x80087467;
[PythonHidden(PlatformID.MacOSX)]
[SupportedOSPlatform("linux")]
public static int TIOCSSOFTCAR => 0x541a;
public static long TIOCSTI => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x80017472 : 0x5412;
public static long TIOCSWINSZ => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x80087467 : 0x5414;
// *** END GENERATED CODE ***
#endregion
#region Other Public Constants
// Linux: glibc/bits/termios.h (/usr/include/{x86_64,aarch64}-linux-gnu/)
// macOS: usr/include/sys/termios.h (/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk)
// iflag
public const int IGNBRK = 0x0001; // ignore break condition
public const int BRKINT = 0x0002; // signal interrupt on break
public const int IGNPAR = 0x0004; // ignore characters with parity errors
public const int PARMRK = 0x0008; // mark parity and framing errors
public const int INPCK = 0x0010; // enable input parity check
public const int ISTRIP = 0x0020; // mask off 8th bit
public const int INLCR = 0x0040; // map NL into CR on input
public const int IGNCR = 0x0080; // ignore CR
public const int ICRNL = 0x0100; // map CR to NL on input
public static int IXON => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ?
0x0200 : 0x0400; // enable start output control
public static int IXOFF => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ?
0x0400 : 0x1000; // enable stop output control
public const int IXANY = 0x0800; // any char will restart after stop
public const int IMAXBEL = 0x2000; // ring bell on input queue full
public const int IUTF8 = 0x4000; // maintain state for UTF-8 VERASE
// oflag
public const int OPOST = 0x0001; // enable output processing
public static int ONLCR => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ?
0x0002 : 0x0004; // map NL to CR-NL
// cflag
public static int CSIZE => CS5 | CS6 | CS7 | CS8; // number of bits per character
public static int CS5 => 0x0000; // 5 bits per character
public static int CS6 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0100 : 0x0010; // 6 bits per character
public static int CS7 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0200 : 0x0020; // 7 bits per character
public static int CS8 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0300 : 0x0030; // 8 bits per character
public static int CREAD => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0800 : 0x0080; // enable receiver
public static int PARENB => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x1000 : 0x0100; // parity enable
public static int HUPCL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x4000 : 0x0400; // hang up on last close
[PythonHidden(PlatformID.MacOSX)]
public static int CBAUD => 0x100f; // mask for baud rate
[PythonHidden(PlatformID.MacOSX)]
public static int CBAUDEX => 0x1000; // extra baud speed mask
// lflag
public static uint ECHOKE => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0001u : 0x0800u; // visual erase for line kill
public static uint ECHOE => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0002u : 0x0010u; // visually erase chars
public static uint ECHOK => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0004u : 0x0020u; // echo NL after line kill
public static uint ECHO => 0x0008u; // enable echoing of input characters
public static uint ECHONL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0010u : 0x0040u; // echo NL even if ECHO is off
public static uint ECHOPRT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0020u : 0x0400u; // visual erase mode for hardcopy
public static uint ECHOCTL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0040u : 0x0200u; // echo control characters as ^(Char)
public static uint ISIG => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0080u : 0x0001u; // enable signals
public static uint ICANON => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0100u : 0x0002u; // canonical mode
public static uint IEXTEN => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0400u : 0x8000u; // enable extended input character processing
public static uint TOSTOP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0040_0000u : 0x0100u; // stop background jobs from output
public static uint FLUSHO => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x0080_0000u : 0x1000u; // output being flushed
public static uint PENDIN => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x2000_0000u : 0x4000u; // retype pending input
public static uint NOFLSH => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0x8000_0000u : 0x0080u; // don't flush after interrupt
// when the changes take effect:
public const int TCSANOW = 0; // change immediately
public const int TCSADRAIN = 1; // flush output, then change
public const int TCSAFLUSH = 2; // discard input, flush output, then change
// control characters - indices into c_cc array
public static int VEOF => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0 : 4;
public static int VEOL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 1 : 11;
public static int VEOL2 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 2 : 16;
public static int VERASE => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 3 : 2;
public static int VWERASE => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 4 : 14;
public static int VKILL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 5 : 3;
public static int VREPRINT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 6 : 12;
public static int VINTR => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 8 : 0;
public static int VQUIT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 9 : 1;
public static int VSUSP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 10 : 10;
public static int VSTART => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 12 : 8;
public static int VSTOP => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 13 : 9;
public static int VLNEXT => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 14 : 15;
public static int VDISCARD => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 15 : 13;
public static int VMIN => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 16 : 6;
public static int VTIME => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 17 : 5;
[PythonHidden(PlatformID.MacOSX)]
public static int VSWTC => 7;
public static int NCCS => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 20 : 32;
// control characters - character values
public static int CINTR = 0x03; // ^C
public static int CEOF = 0x04; // ^D
public static int CEOT = 0x04; // ^D
public static int CFLUSH = 0x0f; // ^O
public static int CSTART = 0x11; // ^Q
public static int CSTOP = 0x13; // ^S
public static int CKILL = 0x15; // ^U
public static int CLNEXT = 0x16; // ^V
public static int CWERASE = 0x17; // ^W
public static int CDSUSP = 0x19; // ^Y
public static int CSUSP = 0x1a; // ^Z
public static int CQUIT = 0x1c; // ^\
public static int CERASE = 0x7f; // DEL
public static int CEOL => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 0xff : 0x00;
// tcflush() uses these
public static int TCIFLUSH => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 1 : 0; // flush input
public static int TCOFLUSH => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 2 : 1; // flush output
public static int TCIOFLUSH => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 3 : 2; // flush both
// tcflow() uses these
public static int TCOOFF => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 1 : 0; // suspend output
public static int TCOON => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 2 : 1; // restart output
public static int TCIOFF => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 3 : 2; // transmit STOP character
public static int TCION => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 4 : 3; // transmit START character
// baud rates
public static int B0 => 0;
public static int B50 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 50 : 1;
public static int B75 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 75 : 2;
public static int B110 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 110 : 3;
public static int B134 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 134 : 4;
public static int B150 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 150 : 5;
public static int B200 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 200 : 6;
public static int B300 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 300 : 7;
public static int B600 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 600 : 8;
public static int B1200 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 1200 : 9;
public static int B1800 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 1800 : 10;
public static int B2400 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 2400 : 11;
public static int B4800 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 4800 : 12;
public static int B9600 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 9600 : 13;
public static int B19200 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 19200 : 14;
public static int B38400 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 38400 : 15;
public static int B57600 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 57600 : 0x1001;
public static int B115200 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 115200 : 0x1002;
public static int B230400 => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? 230400 : 0x1003;
// higher baud rates are not defined on macOS
#endregion
#region Public Functions
[SupportedOSPlatform("macos")]
[DllImport("libc", SetLastError = true, EntryPoint = "tcgetattr")]
private static extern int _tcgetattr_darwin(int fd, out darwin__termios termios);
[SupportedOSPlatform("linux")]
[DllImport("libc", SetLastError = true, EntryPoint = "tcgetattr")]
private static extern int _tcgetattr_linux(int fd, out linux__termios termios);
[LightThrowing]
public static object tcgetattr(CodeContext context, int fd) {
CheckFileDescriptor(fd);
var cc = new PythonList(NCCS);
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
var termios = new darwin__termios();
if (_tcgetattr_darwin(fd, out termios) == -1) {
return LightExceptions.Throw(PythonNT.GetLastUnixError());
}
for (int i = 0; i < NCCS; i++) {
unsafe { cc.Add(Bytes.FromByte(termios.c_cc[i])); }
}
return PythonList.FromArrayNoCopy([
ToPythonInt(termios.c_iflag),
ToPythonInt(termios.c_oflag),
ToPythonInt(termios.c_cflag),
ToPythonInt(termios.c_lflag),
ToPythonInt(termios.c_ispeed),
ToPythonInt(termios.c_ospeed),
cc
]);
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
unsafe { Console.WriteLine($"termios_size: {sizeof(linux__termios)}"); }
var termios = new linux__termios();
if (_tcgetattr_linux(fd, out termios) == -1) {
return LightExceptions.Throw(PythonNT.GetLastUnixError());
}
for (int i = 0; i < NCCS; i++) {
unsafe { cc.Add(Bytes.FromByte(termios.c_cc[i])); }
}
return PythonList.FromArrayNoCopy([
ToPythonInt(termios.c_iflag),
ToPythonInt(termios.c_oflag),
ToPythonInt(termios.c_cflag),
ToPythonInt(termios.c_lflag),
ToPythonInt(termios.c_ispeed),
ToPythonInt(termios.c_ospeed),
cc
]);
} else {
throw new PlatformNotSupportedException();
}
}
public static object tcgetattr(CodeContext context, object? file)
=> tcgetattr(context, PythonFcntl.GetFileDescriptor(context, file));
[SupportedOSPlatform("macos")]
[DllImport("libc", SetLastError = true, EntryPoint = "tcsetattr")]
private static extern int _tcsetattr_darwin(int fd, int when, in darwin__termios termios);
[SupportedOSPlatform("linux")]
[DllImport("libc", SetLastError = true, EntryPoint = "tcsetattr")]
private static extern int _tcsetattr_linux(int fd, int when, in linux__termios termios);
[LightThrowing]
public static object? tcsetattr(CodeContext context, int fd, int when, object? attributes) {
CheckFileDescriptor(fd);
if (attributes is not IList attrs || attrs.Count != 7) {
throw PythonOps.TypeError("tcsetattr, arg 3: must be 7 element list");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
var termios = new darwin__termios {
c_iflag = ToUInt64(attrs[InputFlagIdx]),
c_oflag = ToUInt64(attrs[OutputFlagIdx]),
c_cflag = ToUInt64(attrs[ControlFlagIdx]),
c_lflag = ToUInt64(attrs[LocalFlagIdx]),
c_ispeed = ToUInt64(attrs[InputSpeedIdx]),
c_ospeed = ToUInt64(attrs[OutputSpeedIdx])
};
IList chars = GetControlCharList(attrs);
for (int i = 0; i < NCCS; i++) {
unsafe { termios.c_cc[i] = GetControlChar(chars[i]); }
}
if (_tcsetattr_darwin(fd, when, in termios) == -1) {
return LightExceptions.Throw(GetLastTermiosError(context));
}
} else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
var termios = new linux__termios {
c_iflag = (uint)ToUInt64(attrs[InputFlagIdx]),
c_oflag = (uint)ToUInt64(attrs[OutputFlagIdx]),
c_cflag = (uint)ToUInt64(attrs[ControlFlagIdx]),
c_lflag = (uint)ToUInt64(attrs[LocalFlagIdx]),
c_ispeed = (uint)ToUInt64(attrs[InputSpeedIdx]),
c_ospeed = (uint)ToUInt64(attrs[OutputSpeedIdx])
};
IList chars = GetControlCharList(attrs);
for (int i = 0; i < NCCS; i++) {
unsafe { termios.c_cc[i] = GetControlChar(chars[i]); }
}
if (_tcsetattr_linux(fd, when, in termios) == -1) {
return LightExceptions.Throw(GetLastTermiosError(context));
}
} else {
throw new PlatformNotSupportedException();
}
#if NETCOREAPP
// TODO: remove .NET workaround
if (fd == 0
&& context.LanguageContext.SystemStandardIn is TextIOWrapper stdin
&& !stdin.closed
&& stdin.isatty(context)
&& stdin.fileno(context) == 0
&& !Console.IsInputRedirected) {
if (when != TCSANOW) {
stdin.flush(context);
}
ulong newLflag = ToUInt64(attrs[LocalFlagIdx]);
if ((newLflag & (ECHO | ICANON | IEXTEN | ISIG)) == 0) {
setraw(context, stdin);
} else {
setcbreak(context, stdin);
}
}
#endif
return null;
// Local functions ------------------------------------------------
static IList GetControlCharList(IList attrs) {
if (attrs[ControlCharsIdx] is not IList chars || chars.Count != NCCS) {
throw PythonOps.TypeError("tcsetattr, atributes[{0}] must be {1} element list", ControlCharsIdx, NCCS);
}
return chars;
}
static byte GetControlChar(object? o) {
if (o is Bytes b && b.Count == 1) {
return (byte)b[0];
}
if (Converter.TryConvertToInt32(o, out int i)) {
return (byte)i;
}
throw PythonOps.TypeError("tcsetattr: elements of attributes must be characters or integers");
}
static ulong ToUInt64(object? o)
=> PythonOps.TryToInt(o, out BigInteger index)
? (ulong)index
: throw PythonOps.TypeErrorForBadInstance("tcsetattr: an integer is required (got type {0})", o);
}
[LightThrowing]
public static object? tcsetattr(CodeContext context, object? file, int when, [NotNone] object attributes)
=> tcsetattr(context, PythonFcntl.GetFileDescriptor(context, file), when, attributes);
[DllImport("libc", SetLastError = true, EntryPoint = "tcsendbreak")]
private static extern int _tcsendbreak(int fd, int duration);
[LightThrowing]
public static object? tcsendbreak(CodeContext context, int fd, int duration) {
CheckFileDescriptor(fd);
if (_tcsendbreak(fd, duration) == -1) {
return LightExceptions.Throw(GetLastTermiosError(context));
}
return null;
}
[LightThrowing]
public static object? tcsendbreak(CodeContext context, object? fd, int duration)
=> tcsendbreak(context, PythonFcntl.GetFileDescriptor(context, fd), duration);
[DllImport("libc", SetLastError = true, EntryPoint = "tcdrain")]
private static extern int _tcdrain(int fd);
[LightThrowing]
public static object? tcdrain(CodeContext context, int fd) {
CheckFileDescriptor(fd);
if (_tcdrain(fd) == -1) {
return LightExceptions.Throw(GetLastTermiosError(context));
}
return null;
}
[LightThrowing]
public static object? tcdrain(CodeContext context, object? fd)
=> tcdrain(context, PythonFcntl.GetFileDescriptor(context, fd));
[DllImport("libc", SetLastError = true, EntryPoint = "tcflush")]
private static extern int _tcflush(int fd, int queue);
[LightThrowing]
public static object? tcflush(CodeContext context, int fd, int queue) {
CheckFileDescriptor(fd);
if (_tcflush(fd, queue) == -1) {
return LightExceptions.Throw(GetLastTermiosError(context));
}
return null;
}
[LightThrowing]
public static object? tcflush(CodeContext context, object? fd, int queue)
=> tcflush(context, PythonFcntl.GetFileDescriptor(context, fd), queue);
[DllImport("libc", SetLastError = true, EntryPoint = "tcflow")]
private static extern int _tcflow(int fd, int action);
[LightThrowing]
public static object? tcflow(CodeContext context, int fd, int action) {
CheckFileDescriptor(fd);
if (_tcflow(fd, action) == -1) {
return LightExceptions.Throw(GetLastTermiosError(context));
}
return null;
}
[LightThrowing]
public static object? tcflow(CodeContext context, object? fd, int action)
=> tcflow(context, PythonFcntl.GetFileDescriptor(context, fd), action);
// Python 3.11: tcgetwinsize, tcsetwinsize
[LightThrowing]
public static object tcgetwinsize(CodeContext context, int fd) {
var ws = new ushort[4];
var buf = new MemoryBufferProtocolWrapper<ushort>(ws.AsMemory());
object result = PythonFcntl.ioctl(fd, TIOCGWINSZ, buf, mutate_flag: true);
if (ToTermiosError(context, result) is not null and var ex) {
return ex;
}
return PythonTuple.MakeTuple((int)ws[0], (int)ws[1]);
}
[LightThrowing]
public static object? tcgetwinsize(CodeContext context, object? fd)
=> tcgetwinsize(context, PythonFcntl.GetFileDescriptor(context, fd));
[LightThrowing]
public static object? tcsetwinsize(CodeContext context, int fd, object? winsize) {
CheckFileDescriptor(fd);
if (winsize is not IList wsList || wsList.Count != 2) {
throw PythonOps.TypeError("tcsetwinsize, arg 2: must be a two-item sequence");
}
long winsize_0 = (long)PythonOps.ToIndex(wsList[0]);
long winsize_1 = (long)PythonOps.ToIndex(wsList[1]);
var ws = new ushort[4];
var buf = new MemoryBufferProtocolWrapper<ushort>(ws.AsMemory());
object result = PythonFcntl.ioctl(fd, TIOCGWINSZ, buf, mutate_flag: true);
if (ToTermiosError(context, result) is not null and var ex) {
return ex;
}
ws[0] = unchecked((ushort)winsize_0);
ws[1] = unchecked((ushort)winsize_1);
if (ws[0] != winsize_0 || ws[1] != winsize_1) {
throw PythonOps.OverflowError("winsize value(s) out of range");
}
result = PythonFcntl.ioctl(fd, TIOCSWINSZ, buf);
if (ToTermiosError(context, result) is not null and var ex2) {
return ex2;
}
return null;
}
[LightThrowing]
public static object? tcsetwinsize(CodeContext context, object? fd, object? winsize)
=> tcsetwinsize(context, PythonFcntl.GetFileDescriptor(context, fd), winsize);
#endregion
#region Termios struct
/*
Linux: termios-struct.h
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
#define NCCS 32
struct termios
{
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_line;
cc_t c_cc[NCCS];
speed_t c_ispeed;
speed_t c_ospeed;
};
*/
[SupportedOSPlatform("linux")]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct linux__termios {
public uint c_iflag;
public uint c_oflag;
public uint c_cflag;
public uint c_lflag;
public byte c_line;
public fixed byte c_cc[32];
public uint c_ispeed;
public uint c_ospeed;
}
/*
Darwin: termios.h
typedef unsigned long tcflag_t;
typedef unsigned char cc_t;
typedef unsigned long speed_t;
#define NCCS 20
struct termios {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_cc[NCCS];
speed_t c_ispeed;
speed_t c_ospeed;
};
*/
[SupportedOSPlatform("macos")]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct darwin__termios {
public ulong c_iflag;
public ulong c_oflag;
public ulong c_cflag;
public ulong c_lflag;
public fixed byte c_cc[20];
public ulong c_ispeed;
public ulong c_ospeed;
}
// Python termios attributes
private const int InputFlagIdx = 0;
private const int OutputFlagIdx = 1;
private const int ControlFlagIdx = 2;
private const int LocalFlagIdx = 3;
private const int InputSpeedIdx = 4;
private const int OutputSpeedIdx = 5;
private const int ControlCharsIdx = 6;
#endregion
#region Private Helpers
#if NETCOREAPP
// .NET workaround for stdin raw mode
private static object? _savedRawStdin;
private static void setraw(CodeContext context, TextIOWrapper stdin) {
if (_savedRawStdin is null && stdin.buffer is BufferedReader reader) {
_savedRawStdin = reader.raw;
reader.raw = new RawConsole(context);
}
}
private static void setcbreak(CodeContext context, TextIOWrapper stdin) {
if (_savedRawStdin is not null
&& stdin.buffer is BufferedReader reader
&& reader.raw is RawConsole) {
reader.raw = _savedRawStdin;
_savedRawStdin = null;
}
}
private class RawConsole : _RawIOBase {
public RawConsole(CodeContext context) : base(context) {
}
public override object? read(CodeContext context, object? size=null) {
BigInteger intSize = PythonOps.ToIndex(size);
if (intSize == 0) return null;
ConsoleKeyInfo info = Console.ReadKey(intercept: true);
return Bytes.FromByte(unchecked((byte)info.KeyChar));
}
public override int fileno(CodeContext context) => 0;
public override bool isatty(CodeContext context) => true;
}
#endif
private static void CheckFileDescriptor(int fd) {
if (fd < 0) {
throw PythonOps.ValueError("file descriptor cannot be a negative integer ({0})", fd);
}
}
private static object ToPythonInt(this ulong value)
=> value is <= int.MaxValue ? (int)value : (BigInteger)value;
private static object? ToTermiosError(CodeContext context, object? error) {
if (LightExceptions.GetLightException(error) is Exception ex) {
var pex = ex.GetPythonException();
if (pex is PythonExceptions._OSError oserr) {
return LightExceptions.Throw(GetTermiosError(context, oserr.errno, oserr.strerror));
} else {
return error;
}
}
return null;
}
private static Exception GetLastTermiosError(CodeContext context) {
int errno = Marshal.GetLastWin32Error();
return GetTermiosError(context, errno, PythonNT.strerror(errno));
}
private static Exception GetTermiosError(CodeContext context, object errno, object message)
=> PythonExceptions.CreateThrowable(termioserror(context), errno, message);
private static PythonType termioserror(CodeContext context)
=> (PythonType)context.LanguageContext.GetModuleState("termioserror");
#endregion
}