UNIX: added support for TTY / PTY attributes (`tdgetattr()` & `tcsetattr()`) jv
authorJan Vrany <jan.vrany@fit.cvut.cz>
Fri, 26 May 2017 21:24:42 +0100
branchjv
changeset 21784 d58698c455c1
parent 21783 3cd0c0e8284f
child 21785 f129a3fcd113
UNIX: added support for TTY / PTY attributes (`tdgetattr()` & `tcsetattr()`) that can be used to set up PTY stream in a desired way.
AbstractOperatingSystem.st
Make.spec
NonPositionableExternalStream.st
OSErrorHolder.st
Stream.st
TTYAttributes.st
TTYConstants.st
UnixOperatingSystem.st
Win32OperatingSystem.st
libInit.cc
stx_libbasic.st
--- a/AbstractOperatingSystem.st	Tue May 30 07:24:23 2017 +0200
+++ b/AbstractOperatingSystem.st	Fri May 26 21:24:42 2017 +0100
@@ -5130,6 +5130,15 @@
     "Modified: / 14.12.1999 / 19:40:32 / cg"
 !
 
+supportsTTYs
+    "Return true if OS supports PTYs / TTYs. UNIX do, other 
+     OSes usually don't"
+
+    ^ false
+
+    "Created: / 31-05-2017 / 10:37:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 supportsVolumes
     "return true, if the OS supports disk volumes.
      False is returned for UNIX, true for MSDOS, VMS and OSX (which treats /Volumes as such)"
--- a/Make.spec	Tue May 30 07:24:23 2017 +0200
+++ b/Make.spec	Fri May 26 21:24:42 2017 +0100
@@ -392,6 +392,8 @@
 	LongIntegerArray \
 	MissingClassInLiteralArrayErrorSignal \
 	NoByteCodeError \
+	TTYConstants \
+	TTYAttributes \
 	NonPositionableExternalStream \
 	NumberFormatError \
 	PTYOpenError \
@@ -783,6 +785,8 @@
     $(OUTDIR_SLASH)LongIntegerArray.$(O) \
     $(OUTDIR_SLASH)MissingClassInLiteralArrayErrorSignal.$(O) \
     $(OUTDIR_SLASH)NoByteCodeError.$(O) \
+    $(OUTDIR_SLASH)TTYConstants.$(O) \
+    $(OUTDIR_SLASH)TTYAttributes.$(O) \
     $(OUTDIR_SLASH)NonPositionableExternalStream.$(O) \
     $(OUTDIR_SLASH)NumberFormatError.$(O) \
     $(OUTDIR_SLASH)PTYOpenError.$(O) \
@@ -810,7 +814,7 @@
     $(OUTDIR_SLASH)UnderflowError.$(O) \
     $(OUTDIR_SLASH)ZeroDivide.$(O) \
     $(OUTDIR_SLASH)BadRomanNumberFormatError.$(O) \
-
+    
 WIN32_OBJS= \
     $(OUTDIR_SLASH)PCFilename.$(O) \
     $(OUTDIR_SLASH)Win32Constants.$(O) \
@@ -824,6 +828,7 @@
     $(OUTDIR_SLASH)UnixOperatingSystem.$(O) \
     $(OUTDIR_SLASH)OSXOperatingSystem.$(O) \
 
+
 VMS_OBJS= \
     $(OUTDIR_SLASH)OpenVMSFileHandle.$(O) \
     $(OUTDIR_SLASH)OpenVMSFilename.$(O) \
--- a/NonPositionableExternalStream.st	Tue May 30 07:24:23 2017 +0200
+++ b/NonPositionableExternalStream.st	Fri May 26 21:24:42 2017 +0100
@@ -16,7 +16,7 @@
 ExternalStream subclass:#NonPositionableExternalStream
 	instanceVariableNames:''
 	classVariableNames:'StdInStream StdOutStream StdErrorStream'
-	poolDictionaries:''
+	poolDictionaries:'TTYConstants'
 	category:'Streams-External'
 !
 
@@ -268,6 +268,40 @@
     aBoolean ifFalse:[
 	super buffered:false.
     ].
+!
+
+getTTYAttributes
+    "Return (UNIX) TTY / PTY attributes for this stream as an instance of
+     UnixTerminalAttributes. Throw an error if terminal attributes cannot 
+     be retrieved (OS call fails, stream does  not refer to terminal or 
+     opration is not supported by this operating system. 
+
+     See tcgetattr()
+    "
+    ^ OperatingSystem getTTYAttributes: self fileDescriptor
+
+    "
+    Stdout ttyAttributes
+    "
+
+    "Created: / 30-05-2017 / 20:55:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+setTTYAttributes: aUnixTerminalAttributes
+    "Set (UNIX) TTY / PTY attributes for this stream. Throw an error if 
+     terminal attributes cannot be set (OS call fails, stream does  not 
+     refer to terminal or operation is not supported by this operating 
+     system. 
+
+     See tcsetattr()
+    "
+    ^ OperatingSystem setTTYAttributes: self fileDescriptor to: aUnixTerminalAttributes withActions: TCSANOW
+
+    "
+    Stdout ttyAttributes
+    "
+
+    "Created: / 30-05-2017 / 20:57:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !NonPositionableExternalStream methodsFor:'error handling'!
@@ -818,6 +852,16 @@
     "not reached"
 ! !
 
+!NonPositionableExternalStream methodsFor:'testing'!
+
+isTTY
+    "Return true if receiver refers to TTY / PTY, false otherwise."
+
+    ^ OperatingSystem isTTY: self fileDescriptor
+
+    "Created: / 30-05-2017 / 16:46:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !NonPositionableExternalStream methodsFor:'writing'!
 
 nextPutAll:aCollection
@@ -873,5 +917,10 @@
 
 version_CVS
     ^ '$Header$'
+!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
 ! !
 
--- a/OSErrorHolder.st	Tue May 30 07:24:23 2017 +0200
+++ b/OSErrorHolder.st	Fri May 26 21:24:42 2017 +0100
@@ -398,6 +398,8 @@
     "Report an error."
     "Delegate to the receiver's error reporter."
 
+    <resource: #skipInDebuggersWalkBack>
+
     |signal|
 
     signal := self class signalNamed:errorCategory.
@@ -409,6 +411,8 @@
     "
       (OperatingSystem errorHolderForNumber:22) reportError
     "
+
+    "Modified (format): / 30-05-2017 / 09:05:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 reportError:errorMessage
@@ -519,5 +523,10 @@
 
 version_CVS
     ^ '$Header$'
+!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
 ! !
 
--- a/Stream.st	Tue May 30 07:24:23 2017 +0200
+++ b/Stream.st	Fri May 26 21:24:42 2017 +0100
@@ -220,6 +220,7 @@
     ^ self == Stream
 ! !
 
+
 !Stream methodsFor:'Compatibility-Dolphin'!
 
 display:someObject
@@ -3804,6 +3805,14 @@
     "Modified: 15.5.1996 / 17:54:48 / cg"
 !
 
+isTTY
+    "Return true if receiver refers to TTY / PTY, false otherwise."
+
+    ^ false
+
+    "Created: / 30-05-2017 / 21:13:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 isTerminalStream
     "true, iff this is a terminal emulator stream"
 
@@ -4715,6 +4724,11 @@
 
 version_CVS
     ^ '$Header$'
+!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
 ! !
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TTYAttributes.st	Fri May 26 21:24:42 2017 +0100
@@ -0,0 +1,150 @@
+"
+Copyright (c) 2017-now Jan Vrany
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MeERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"
+"{ Package: 'stx:libbasic' }"
+
+"{ NameSpace: Smalltalk }"
+
+Object subclass:#TTYAttributes
+	instanceVariableNames:'c_iflag c_oflag c_cflag c_lflag c_cc'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'OS-Unix'
+!
+
+!TTYAttributes class methodsFor:'documentation'!
+
+copyright
+"
+Copyright (c) 2017-now Jan Vrany
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MeERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"
+! !
+
+!TTYAttributes methodsFor:'accessing'!
+
+c_cc
+    ^ c_cc
+!
+
+c_cc:something
+    c_cc := something.
+!
+
+c_cflag
+    ^ c_cflag
+!
+
+c_cflag:something
+    c_cflag := something.
+!
+
+c_iflag
+    ^ c_iflag
+!
+
+c_iflag:something
+    c_iflag := something.
+!
+
+c_lflag
+    ^ c_lflag
+!
+
+c_lflag:something
+    c_lflag := something.
+!
+
+c_oflag
+    ^ c_oflag
+!
+
+c_oflag:something
+    c_oflag := something.
+! !
+
+!TTYAttributes methodsFor:'debugging'!
+
+inspectorExtraAttributes
+    | printer |
+
+    printer := [ :flag :flags |
+        | first |
+
+        first := true.
+        String streamContents:[ :s |
+            flags do:[:each | 
+                | eachVal |
+
+                eachVal := TTYConstants classVarNamed: each.
+                (eachVal notNil and:[(flag bitAnd: eachVal) ~~ 0]) ifTrue:[ 
+                    first ifTrue:[ 
+                        first := false
+                    ] ifFalse:[ 
+                        s nextPutAll: ' | '.
+                    ].
+                    s nextPutAll: each.
+                ].
+            ].
+        ].
+    ].
+    ^ super inspectorExtraAttributes
+        at: '-c_iflag'put: [ printer value: c_iflag value: #(BRKINT ICRNL IGNBRK IGNCR IGNPAR INLCR INPCK ISTRIP IXANY IXOFF IXON PARMRK)];
+        at: '-c_oflag'put: [ printer value: c_oflag value: #(OPOST ONLCR OCRNL ONOCR ONLRET OFILL NLDLY CRDLY TABDLY BSDLY VTDLY FFDLY )];
+        at: '-c_cflag'put: [ printer value: c_cflag value: #(CSIZE CSTOPB CREAD PARENB PARODD HUPCL CLOCAL)];
+        at: '-c_lflag'put: [ printer value: c_lflag value: #(ECHO ECHOE ECHOK ECHONL ICANON IEXTEN ISIG NOFLSH TOSTOP ) ];
+        yourself
+
+    "
+    OperatingSystem getTerminalAttributes: (Stdout fileDescriptor).
+    "
+
+    "Created: / 30-05-2017 / 15:51:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 31-05-2017 / 20:28:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!TTYAttributes class methodsFor:'documentation'!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
+! !
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TTYConstants.st	Fri May 26 21:24:42 2017 +0100
@@ -0,0 +1,675 @@
+"
+Copyright (c) 2017-now Jan Vrany
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MeERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"
+"{ Package: 'stx:libbasic' }"
+
+"{ NameSpace: Smalltalk }"
+
+SharedPool subclass:#TTYConstants
+	instanceVariableNames:''
+	classVariableNames:'NCCS VINTR VQUIT VERASE VKILL VEOF VTIME VMIN VSWTC VSTART VSTOP
+		VSUSP0 VEOL VREPRINT VDISCARD VWERASE VLNEXT VEOL2 IGNBRK BRKINT
+		IGNPAR PARMRK INPCK ISTRIP INLCR IGNCR ICRNL IUCLC IXON IXANY
+		IXOFF IMAXBEL IUTF8 OPOST OLCUC ONLCR OCRNL ONOCR ONLRET OFILL
+		OFDEL NLDLY NL0 NL1 CRDLY CR0 CR1 CR2 CR3 TABDLY TAB0 TAB1 TAB2
+		TAB3 XTABS BSDLY BS0 BS1 VTDLY VT0 VT1 FFDLY FF0 FF1 CBAUD B0 B50
+		B75 B110 B134 B150 B200 B300 B600 B1200 B1800 B2400 B4800 B9600
+		B19200 B38400 EXTA B19200 EXTB B38400 CSIZE CS5 CS6 CS7 CS8
+		CSTOPB CREAD PARENB PARODD HUPCL CLOCAL CBAUDEX BOTHER B57600
+		B115200 B230400 B460800 B500000 B576000 B921600 B1000000 B1152000
+		B1500000 B2000000 B2500000 B3000000 B3500000 B4000000 CIBAUD
+		CMSPAR CRTSCTS IBSHIFT ISIG ICANON XCASE ECHO ECHOE ECHOK ECHONL
+		NOFLSH TOSTOP ECHOCTL ECHOPRT ECHOKE FLUSHO PENDIN IEXTEN EXTPROC
+		TCOOFF TCOON TCIOFF TCION TCIFLUSH TCOFLUSH TCIOFLUSH TCSANOW
+		TCSADRAIN TCSAFLUSH'
+	poolDictionaries:''
+	category:'OS-Unix'
+!
+
+!TTYConstants primitiveDefinitions!
+%{
+#ifdef UNIX
+# include <unistd.h>
+# include <termios.h>
+#endif
+%}
+! !
+
+!TTYConstants class methodsFor:'documentation'!
+
+copyright
+"
+Copyright (c) 2017-now Jan Vrany
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MeERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"
+! !
+
+!TTYConstants class methodsFor:'initialization'!
+
+initialize
+
+%{
+#   ifdef NCCS
+    @global(TTYConstants:NCCS) = __MKSMALLINT(NCCS);
+#   endif
+
+#   ifdef VINTR
+    @global(TTYConstants:VINTR) = __MKSMALLINT(VINTR);
+#   endif
+
+#   ifdef VQUIT
+    @global(TTYConstants:VQUIT) = __MKSMALLINT(VQUIT);
+#   endif
+
+#   ifdef VERASE
+    @global(TTYConstants:VERASE) = __MKSMALLINT(VERASE);
+#   endif
+
+#   ifdef VKILL
+    @global(TTYConstants:VKILL) = __MKSMALLINT(VKILL);
+#   endif
+
+#   ifdef VEOF
+    @global(TTYConstants:VEOF) = __MKSMALLINT(VEOF);
+#   endif
+
+#   ifdef VTIME
+    @global(TTYConstants:VTIME) = __MKSMALLINT(VTIME);
+#   endif
+
+#   ifdef VMIN
+    @global(TTYConstants:VMIN) = __MKSMALLINT(VMIN);
+#   endif
+
+#   ifdef VSWTC
+    @global(TTYConstants:VSWTC) = __MKSMALLINT(VSWTC);
+#   endif
+
+#   ifdef VSTART
+    @global(TTYConstants:VSTART) = __MKSMALLINT(VSTART);
+#   endif
+
+#   ifdef VSTOP
+    @global(TTYConstants:VSTOP) = __MKSMALLINT(VSTOP);
+#   endif
+
+#   ifdef VSUSP0
+    @global(TTYConstants:VSUSP0) = __MKSMALLINT(VSUSP0);
+#   endif
+
+#   ifdef VEOL
+    @global(TTYConstants:VEOL) = __MKSMALLINT(VEOL);
+#   endif
+
+#   ifdef VREPRINT
+    @global(TTYConstants:VREPRINT) = __MKSMALLINT(VREPRINT);
+#   endif
+
+#   ifdef VDISCARD
+    @global(TTYConstants:VDISCARD) = __MKSMALLINT(VDISCARD);
+#   endif
+
+#   ifdef VWERASE
+    @global(TTYConstants:VWERASE) = __MKSMALLINT(VWERASE);
+#   endif
+
+#   ifdef VLNEXT
+    @global(TTYConstants:VLNEXT) = __MKSMALLINT(VLNEXT);
+#   endif
+
+#   ifdef VEOL2
+    @global(TTYConstants:VEOL2) = __MKSMALLINT(VEOL2);
+#   endif
+
+#   ifdef IGNBRK
+    @global(TTYConstants:IGNBRK) = __MKSMALLINT(IGNBRK);
+#   endif
+
+#   ifdef BRKINT
+    @global(TTYConstants:BRKINT) = __MKSMALLINT(BRKINT);
+#   endif
+
+#   ifdef IGNPAR
+    @global(TTYConstants:IGNPAR) = __MKSMALLINT(IGNPAR);
+#   endif
+
+#   ifdef PARMRK
+    @global(TTYConstants:PARMRK) = __MKSMALLINT(PARMRK);
+#   endif
+
+#   ifdef INPCK
+    @global(TTYConstants:INPCK) = __MKSMALLINT(INPCK);
+#   endif
+
+#   ifdef ISTRIP
+    @global(TTYConstants:ISTRIP) = __MKSMALLINT(ISTRIP);
+#   endif
+
+#   ifdef INLCR
+    @global(TTYConstants:INLCR) = __MKSMALLINT(INLCR);
+#   endif
+
+#   ifdef IGNCR
+    @global(TTYConstants:IGNCR) = __MKSMALLINT(IGNCR);
+#   endif
+
+#   ifdef ICRNL
+    @global(TTYConstants:ICRNL) = __MKSMALLINT(ICRNL);
+#   endif
+
+#   ifdef IUCLC
+    @global(TTYConstants:IUCLC) = __MKSMALLINT(IUCLC);
+#   endif
+
+#   ifdef IXON
+    @global(TTYConstants:IXON) = __MKSMALLINT(IXON);
+#   endif
+
+#   ifdef IXANY
+    @global(TTYConstants:IXANY) = __MKSMALLINT(IXANY);
+#   endif
+
+#   ifdef IXOFF
+    @global(TTYConstants:IXOFF) = __MKSMALLINT(IXOFF);
+#   endif
+
+#   ifdef IMAXBEL
+    @global(TTYConstants:IMAXBEL) = __MKSMALLINT(IMAXBEL);
+#   endif
+
+#   ifdef IUTF8
+    @global(TTYConstants:IUTF8) = __MKSMALLINT(IUTF8);
+#   endif
+
+#   ifdef OPOST
+    @global(TTYConstants:OPOST) = __MKSMALLINT(OPOST);
+#   endif
+
+#   ifdef OLCUC
+    @global(TTYConstants:OLCUC) = __MKSMALLINT(OLCUC);
+#   endif
+
+#   ifdef ONLCR
+    @global(TTYConstants:ONLCR) = __MKSMALLINT(ONLCR);
+#   endif
+
+#   ifdef OCRNL
+    @global(TTYConstants:OCRNL) = __MKSMALLINT(OCRNL);
+#   endif
+
+#   ifdef ONOCR
+    @global(TTYConstants:ONOCR) = __MKSMALLINT(ONOCR);
+#   endif
+
+#   ifdef ONLRET
+    @global(TTYConstants:ONLRET) = __MKSMALLINT(ONLRET);
+#   endif
+
+#   ifdef OFILL
+    @global(TTYConstants:OFILL) = __MKSMALLINT(OFILL);
+#   endif
+
+#   ifdef OFDEL
+    @global(TTYConstants:OFDEL) = __MKSMALLINT(OFDEL);
+#   endif
+
+#   ifdef NLDLY
+    @global(TTYConstants:NLDLY) = __MKSMALLINT(NLDLY);
+#   endif
+
+#   ifdef NL0
+    @global(TTYConstants:NL0) = __MKSMALLINT(NL0);
+#   endif
+
+#   ifdef NL1
+    @global(TTYConstants:NL1) = __MKSMALLINT(NL1);
+#   endif
+
+#   ifdef CRDLY
+    @global(TTYConstants:CRDLY) = __MKSMALLINT(CRDLY);
+#   endif
+
+#   ifdef CR0
+    @global(TTYConstants:CR0) = __MKSMALLINT(CR0);
+#   endif
+
+#   ifdef CR1
+    @global(TTYConstants:CR1) = __MKSMALLINT(CR1);
+#   endif
+
+#   ifdef CR2
+    @global(TTYConstants:CR2) = __MKSMALLINT(CR2);
+#   endif
+
+#   ifdef CR3
+    @global(TTYConstants:CR3) = __MKSMALLINT(CR3);
+#   endif
+
+#   ifdef TABDLY
+    @global(TTYConstants:TABDLY) = __MKSMALLINT(TABDLY);
+#   endif
+
+#   ifdef TAB0
+    @global(TTYConstants:TAB0) = __MKSMALLINT(TAB0);
+#   endif
+
+#   ifdef TAB1
+    @global(TTYConstants:TAB1) = __MKSMALLINT(TAB1);
+#   endif
+
+#   ifdef TAB2
+    @global(TTYConstants:TAB2) = __MKSMALLINT(TAB2);
+#   endif
+
+#   ifdef TAB3
+    @global(TTYConstants:TAB3) = __MKSMALLINT(TAB3);
+#   endif
+
+#   ifdef XTABS
+    @global(TTYConstants:XTABS) = __MKSMALLINT(XTABS);
+#   endif
+
+#   ifdef BSDLY
+    @global(TTYConstants:BSDLY) = __MKSMALLINT(BSDLY);
+#   endif
+
+#   ifdef BS0
+    @global(TTYConstants:BS0) = __MKSMALLINT(BS0);
+#   endif
+
+#   ifdef BS1
+    @global(TTYConstants:BS1) = __MKSMALLINT(BS1);
+#   endif
+
+#   ifdef VTDLY
+    @global(TTYConstants:VTDLY) = __MKSMALLINT(VTDLY);
+#   endif
+
+#   ifdef VT0
+    @global(TTYConstants:VT0) = __MKSMALLINT(VT0);
+#   endif
+
+#   ifdef VT1
+    @global(TTYConstants:VT1) = __MKSMALLINT(VT1);
+#   endif
+
+#   ifdef FFDLY
+    @global(TTYConstants:FFDLY) = __MKSMALLINT(FFDLY);
+#   endif
+
+#   ifdef FF0
+    @global(TTYConstants:FF0) = __MKSMALLINT(FF0);
+#   endif
+
+#   ifdef FF1
+    @global(TTYConstants:FF1) = __MKSMALLINT(FF1);
+#   endif
+
+#   ifdef CBAUD
+    @global(TTYConstants:CBAUD) = __MKSMALLINT(CBAUD);
+#   endif
+
+#   ifdef B0
+    @global(TTYConstants:B0) = __MKSMALLINT(B0);
+#   endif
+
+#   ifdef B50
+    @global(TTYConstants:B50) = __MKSMALLINT(B50);
+#   endif
+
+#   ifdef B75
+    @global(TTYConstants:B75) = __MKSMALLINT(B75);
+#   endif
+
+#   ifdef B110
+    @global(TTYConstants:B110) = __MKSMALLINT(B110);
+#   endif
+
+#   ifdef B134
+    @global(TTYConstants:B134) = __MKSMALLINT(B134);
+#   endif
+
+#   ifdef B150
+    @global(TTYConstants:B150) = __MKSMALLINT(B150);
+#   endif
+
+#   ifdef B200
+    @global(TTYConstants:B200) = __MKSMALLINT(B200);
+#   endif
+
+#   ifdef B300
+    @global(TTYConstants:B300) = __MKSMALLINT(B300);
+#   endif
+
+#   ifdef B600
+    @global(TTYConstants:B600) = __MKSMALLINT(B600);
+#   endif
+
+#   ifdef B1200
+    @global(TTYConstants:B1200) = __MKSMALLINT(B1200);
+#   endif
+
+#   ifdef B1800
+    @global(TTYConstants:B1800) = __MKSMALLINT(B1800);
+#   endif
+
+#   ifdef B2400
+    @global(TTYConstants:B2400) = __MKSMALLINT(B2400);
+#   endif
+
+#   ifdef B4800
+    @global(TTYConstants:B4800) = __MKSMALLINT(B4800);
+#   endif
+
+#   ifdef B9600
+    @global(TTYConstants:B9600) = __MKSMALLINT(B9600);
+#   endif
+
+#   ifdef B19200
+    @global(TTYConstants:B19200) = __MKSMALLINT(B19200);
+#   endif
+
+#   ifdef B38400
+    @global(TTYConstants:B38400) = __MKSMALLINT(B38400);
+#   endif
+
+#   ifdef EXTA
+    @global(TTYConstants:EXTA) = __MKSMALLINT(EXTA);
+#   endif
+
+#   ifdef B19200
+    @global(TTYConstants:B19200) = __MKSMALLINT(B19200);
+#   endif
+
+#   ifdef EXTB
+    @global(TTYConstants:EXTB) = __MKSMALLINT(EXTB);
+#   endif
+
+#   ifdef B38400
+    @global(TTYConstants:B38400) = __MKSMALLINT(B38400);
+#   endif
+
+#   ifdef CSIZE
+    @global(TTYConstants:CSIZE) = __MKSMALLINT(CSIZE);
+#   endif
+
+#   ifdef CS5
+    @global(TTYConstants:CS5) = __MKSMALLINT(CS5);
+#   endif
+
+#   ifdef CS6
+    @global(TTYConstants:CS6) = __MKSMALLINT(CS6);
+#   endif
+
+#   ifdef CS7
+    @global(TTYConstants:CS7) = __MKSMALLINT(CS7);
+#   endif
+
+#   ifdef CS8
+    @global(TTYConstants:CS8) = __MKSMALLINT(CS8);
+#   endif
+
+#   ifdef CSTOPB
+    @global(TTYConstants:CSTOPB) = __MKSMALLINT(CSTOPB);
+#   endif
+
+#   ifdef CREAD
+    @global(TTYConstants:CREAD) = __MKSMALLINT(CREAD);
+#   endif
+
+#   ifdef PARENB
+    @global(TTYConstants:PARENB) = __MKSMALLINT(PARENB);
+#   endif
+
+#   ifdef PARODD
+    @global(TTYConstants:PARODD) = __MKSMALLINT(PARODD);
+#   endif
+
+#   ifdef HUPCL
+    @global(TTYConstants:HUPCL) = __MKSMALLINT(HUPCL);
+#   endif
+
+#   ifdef CLOCAL
+    @global(TTYConstants:CLOCAL) = __MKSMALLINT(CLOCAL);
+#   endif
+
+#   ifdef CBAUDEX
+    @global(TTYConstants:CBAUDEX) = __MKSMALLINT(CBAUDEX);
+#   endif
+
+#   ifdef BOTHER
+    @global(TTYConstants:BOTHER) = __MKSMALLINT(BOTHER);
+#   endif
+
+#   ifdef B57600
+    @global(TTYConstants:B57600) = __MKSMALLINT(B57600);
+#   endif
+
+#   ifdef B115200
+    @global(TTYConstants:B115200) = __MKSMALLINT(B115200);
+#   endif
+
+#   ifdef B230400
+    @global(TTYConstants:B230400) = __MKSMALLINT(B230400);
+#   endif
+
+#   ifdef B460800
+    @global(TTYConstants:B460800) = __MKSMALLINT(B460800);
+#   endif
+
+#   ifdef B500000
+    @global(TTYConstants:B500000) = __MKSMALLINT(B500000);
+#   endif
+
+#   ifdef B576000
+    @global(TTYConstants:B576000) = __MKSMALLINT(B576000);
+#   endif
+
+#   ifdef B921600
+    @global(TTYConstants:B921600) = __MKSMALLINT(B921600);
+#   endif
+
+#   ifdef B1000000
+    @global(TTYConstants:B1000000) = __MKSMALLINT(B1000000);
+#   endif
+
+#   ifdef B1152000
+    @global(TTYConstants:B1152000) = __MKSMALLINT(B1152000);
+#   endif
+
+#   ifdef B1500000
+    @global(TTYConstants:B1500000) = __MKSMALLINT(B1500000);
+#   endif
+
+#   ifdef B2000000
+    @global(TTYConstants:B2000000) = __MKSMALLINT(B2000000);
+#   endif
+
+#   ifdef B2500000
+    @global(TTYConstants:B2500000) = __MKSMALLINT(B2500000);
+#   endif
+
+#   ifdef B3000000
+    @global(TTYConstants:B3000000) = __MKSMALLINT(B3000000);
+#   endif
+
+#   ifdef B3500000
+    @global(TTYConstants:B3500000) = __MKSMALLINT(B3500000);
+#   endif
+
+#   ifdef B4000000
+    @global(TTYConstants:B4000000) = __MKSMALLINT(B4000000);
+#   endif
+
+#   ifdef CIBAUD
+    @global(TTYConstants:CIBAUD) = __MKSMALLINT(CIBAUD);
+#   endif
+
+#   ifdef CMSPAR
+    @global(TTYConstants:CMSPAR) = __MKSMALLINT(CMSPAR);
+#   endif
+
+#   ifdef CRTSCTS
+    @global(TTYConstants:CRTSCTS) = __MKSMALLINT(CRTSCTS);
+#   endif
+
+#   ifdef IBSHIFT
+    @global(TTYConstants:IBSHIFT) = __MKSMALLINT(IBSHIFT);
+#   endif
+
+#   ifdef ISIG
+    @global(TTYConstants:ISIG) = __MKSMALLINT(ISIG);
+#   endif
+
+#   ifdef ICANON
+    @global(TTYConstants:ICANON) = __MKSMALLINT(ICANON);
+#   endif
+
+#   ifdef XCASE
+    @global(TTYConstants:XCASE) = __MKSMALLINT(XCASE);
+#   endif
+
+#   ifdef ECHO
+    @global(TTYConstants:ECHO) = __MKSMALLINT(ECHO);
+#   endif
+
+#   ifdef ECHOE
+    @global(TTYConstants:ECHOE) = __MKSMALLINT(ECHOE);
+#   endif
+
+#   ifdef ECHOK
+    @global(TTYConstants:ECHOK) = __MKSMALLINT(ECHOK);
+#   endif
+
+#   ifdef ECHONL
+    @global(TTYConstants:ECHONL) = __MKSMALLINT(ECHONL);
+#   endif
+
+#   ifdef NOFLSH
+    @global(TTYConstants:NOFLSH) = __MKSMALLINT(NOFLSH);
+#   endif
+
+#   ifdef OSTOP
+    @global(TTYConstants:OSTOP) = __MKSMALLINT(OSTOP);
+#   endif
+
+#   ifdef ECHOCTL
+    @global(TTYConstants:ECHOCTL) = __MKSMALLINT(ECHOCTL);
+#   endif
+
+#   ifdef ECHOPRT
+    @global(TTYConstants:ECHOPRT) = __MKSMALLINT(ECHOPRT);
+#   endif
+
+#   ifdef ECHOKE
+    @global(TTYConstants:ECHOKE) = __MKSMALLINT(ECHOKE);
+#   endif
+
+#   ifdef FLUSHO
+    @global(TTYConstants:FLUSHO) = __MKSMALLINT(FLUSHO);
+#   endif
+
+#   ifdef PENDIN
+    @global(TTYConstants:PENDIN) = __MKSMALLINT(PENDIN);
+#   endif
+
+#   ifdef IEXTEN
+    @global(TTYConstants:IEXTEN) = __MKSMALLINT(IEXTEN);
+#   endif
+
+#   ifdef EXTPROC
+    @global(TTYConstants:EXTPROC) = __MKSMALLINT(EXTPROC);
+#   endif
+
+#   ifdef TCOOFF
+    @global(TTYConstants:TCOOFF) = __MKSMALLINT(TCOOFF);
+#   endif
+
+#   ifdef TCOON
+    @global(TTYConstants:TCOON) = __MKSMALLINT(TCOON);
+#   endif
+
+#   ifdef TCIOFF
+    @global(TTYConstants:TCIOFF) = __MKSMALLINT(TCIOFF);
+#   endif
+
+#   ifdef TCION
+    @global(TTYConstants:TCION) = __MKSMALLINT(TCION);
+#   endif
+
+#   ifdef TCIFLUSH
+    @global(TTYConstants:TCIFLUSH) = __MKSMALLINT(TCIFLUSH);
+#   endif
+
+#   ifdef TCOFLUSH
+    @global(TTYConstants:TCOFLUSH) = __MKSMALLINT(TCOFLUSH);
+#   endif
+
+#   ifdef TCIOFLUSH
+    @global(TTYConstants:TCIOFLUSH) = __MKSMALLINT(TCIOFLUSH);
+#   endif
+
+#   ifdef TCSANOW
+    @global(TTYConstants:TCSANOW) = __MKSMALLINT(TCSANOW);
+#   endif
+
+#   ifdef TCSADRAIN
+    @global(TTYConstants:TCSADRAIN) = __MKSMALLINT(TCSADRAIN);
+#   endif
+
+#   ifdef TCSAFLUSH
+    @global(TTYConstants:TCSAFLUSH) = __MKSMALLINT(TCSAFLUSH);
+#   endif
+
+%}
+
+    "Created: / 26-05-2017 / 21:52:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!TTYConstants class methodsFor:'documentation'!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
+! !
+
+
+TTYConstants initialize!
--- a/UnixOperatingSystem.st	Tue May 30 07:24:23 2017 +0200
+++ b/UnixOperatingSystem.st	Fri May 26 21:24:42 2017 +0100
@@ -250,6 +250,12 @@
 #   define _UNISTD_H_INCLUDED_
 #  endif
 
+#  ifndef _TERMIOS_H_INCLUDED_
+#   include <termios.h>
+#   define _TERMIOS_H_INCLUDED_
+#  endif
+
+
 #  ifndef _TIME_H_INCLUDED_
 #   include <time.h>
 #   define _TIME_H_INCLUDED_
@@ -1909,6 +1915,103 @@
     "
 ! !
 
+!UnixOperatingSystem class methodsFor:'TTY support'!
+
+getTTYAttributes: fd
+
+     | iflag oflag cflag lflag cc err |
+%{
+    if ( __isSmallInteger(fd) ) {
+        struct termios attrs;
+        if ( tcgetattr( __intVal(fd) , &attrs) == 0 ) {
+            iflag = __MKINT(attrs.c_iflag);
+            oflag = __MKINT(attrs.c_oflag);
+            cflag = __MKINT(attrs.c_cflag);
+            lflag = __MKINT(attrs.c_lflag);
+            cc    = __BYTEARRAY_NEW_INT(NCCS);
+            memcpy(__byteArrayVal(cc), attrs.c_cc, NCCS);
+        } else {
+            err = __mkSmallInteger(errno);        
+        }
+    }
+%}.
+    err notNil ifTrue:[
+    	(OperatingSystem errorHolderForNumber:err)
+             parameter:'tcgetattr() failed';
+             reportError.       
+    ].
+    ^ TTYAttributes new
+        c_iflag: iflag;
+        c_oflag: oflag;
+        c_cflag: cflag;
+        c_lflag: lflag;
+        c_cc:    cc;
+        yourself.
+
+    "Created: / 27-05-2017 / 20:16:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+isTTY: fd
+    "Return true, if given filedescriptor refers to a terminal. See isatty() 
+     for details."
+
+%{
+    if (__isSmallInteger(fd)) {
+    	if ( isatty( __intVal(fd))  ) {
+    	    RETURN(true)
+    	} else {
+            if ( errno == ENOTTY /* POSIX */ || errno == EINVAL /* Linux */ ) {
+            	RETURN(false)
+            }    		
+    	}
+    }
+%}.
+    self primitiveFailed.
+
+    "Created: / 27-05-2017 / 20:27:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+setTTYAttributes: fd to: ttyattrs withActions: actions
+     | iflag oflag cflag lflag cc err |
+
+     iflag := ttyattrs c_iflag.
+     oflag := ttyattrs c_oflag.
+     cflag := ttyattrs c_cflag.
+     lflag := ttyattrs c_lflag.
+     cc    := ttyattrs c_cc.
+%{
+    if (   __isSmallInteger(fd) 
+    	&& __isSmallInteger(iflag) 
+    	&& __isSmallInteger(oflag) 
+    	&& __isSmallInteger(cflag) 
+    	&& __isSmallInteger(lflag) 
+    	&& __isByteArray(cc)
+        && __isSmallInteger(actions)  ) {
+        struct termios attrs;
+        attrs.c_iflag = __intVal(iflag);
+        attrs.c_oflag = __intVal(oflag);
+        attrs.c_cflag = __intVal(cflag);
+        attrs.c_lflag = __intVal(lflag);
+        memcpy(attrs.c_cc, __byteArrayVal(cc), NCCS);
+
+        if ( tcsetattr( __intVal(fd) , __intVal(actions), &attrs) == 0 ) {
+            RETURN (self);
+        } else {
+            err = __mkSmallInteger(errno);        
+        }
+    }   
+%}.
+    err notNil ifTrue:[
+        (OperatingSystem errorHolderForNumber:err)
+        	parameter:'tcgetattr() failed';
+            reportError.       
+    ].
+    self primitiveFailed.
+
+ "Created: / 27-05-2017 / 20:27:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+
+! !
+
 !UnixOperatingSystem class methodsFor:'directory access'!
 
 closeDirectory:dirPointer
@@ -9378,6 +9481,15 @@
      OperatingSystem supportsSymbolicLinks
     "
 
+!
+
+supportsTTYs
+    "Return true if OS supports PTYs / TTYs. UNIX do, other 
+     OSes usually don't"
+
+    ^ true
+
+    "Created: / 31-05-2017 / 10:37:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !UnixOperatingSystem class methodsFor:'path queries'!
@@ -14486,6 +14598,11 @@
 
 version_CVS
     ^ '$Header$'
+!
+
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
 ! !
 
 
--- a/Win32OperatingSystem.st	Tue May 30 07:24:23 2017 +0200
+++ b/Win32OperatingSystem.st	Fri May 26 21:24:42 2017 +0100
@@ -1563,6 +1563,37 @@
 %}
 ! !
 
+!Win32OperatingSystem class methodsFor:'TTY support'!
+
+getTTYAttributes: fd
+	OsError raiseErrorString: 'TTYs / PTYs not supported on Windows'
+
+!	
+
+isTTY: fd                                                                                                     
+    "Return true, if given filedescriptor refers to a character device (console). See _isatty()                                  
+     for details."                                                                                            
+
+%{                                                                                                            
+    if (__isSmallInteger(fd)) {                                                                               
+        if ( _isatty( __intVal(fd) )  ) {                                                                       
+            RETURN(true)                                                                                      
+        } else {                                                                                              
+            RETURN(false);                                                                                           
+        }                                                                                                     
+    }                                                                                                         
+%}.                                                                                                           
+    self primitiveFailed.                                                                                     
+
+    "Created: / 01-06-2017 / 20:12:57 / jv"
+
+!
+
+setTTYAttributes: fd to: ttyattrs withActions: actions
+	OsError raiseErrorString: 'TTYs / PTYs not supported on Windows'
+
+! !
+
 !Win32OperatingSystem class methodsFor:'VM messages'!
 
 win32LogFile
--- a/libInit.cc	Tue May 30 07:24:23 2017 +0200
+++ b/libInit.cc	Fri May 26 21:24:42 2017 +0100
@@ -357,6 +357,8 @@
 extern void _LongIntegerArray_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _MissingClassInLiteralArrayErrorSignal_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _NoByteCodeError_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
+extern void _TTYConstants_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
+extern void _TTYAttributes_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _NonPositionableExternalStream_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _NumberFormatError_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
 extern void _PTYOpenError_Init(int pass, struct __vmData__ *__pRT__, OBJ snd);
@@ -756,6 +758,8 @@
     _LongIntegerArray_Init(pass,__pRT__,snd);
     _MissingClassInLiteralArrayErrorSignal_Init(pass,__pRT__,snd);
     _NoByteCodeError_Init(pass,__pRT__,snd);
+    _TTYConstants_Init(pass,__pRT__,snd);
+    _TTYAttributes_Init(pass,__pRT__,snd);
     _NonPositionableExternalStream_Init(pass,__pRT__,snd);
     _NumberFormatError_Init(pass,__pRT__,snd);
     _PTYOpenError_Init(pass,__pRT__,snd);
--- a/stx_libbasic.st	Tue May 30 07:24:23 2017 +0200
+++ b/stx_libbasic.st	Fri May 26 21:24:42 2017 +0100
@@ -397,7 +397,9 @@
         UninterpretedBytes
         (UnixFileDescriptorHandle unix)
         (UnixFileHandle unix)
-        (UnixOperatingSystem unix)
+        UnixTerminalAttributes
+        UnixTerminalConstants
+        UnixOperatingSystem        
         UserInformation
         UtcTimestamp
         VMInternalError