1 // and now for something completely different...
2 // UrAsm built-in Forth Engine!
7 #include <sys/select.h>
14 static int ufoTermIsRaw
= 0; /* for atexit() function to check if restore is needed */
16 static struct termios ufoOrigTIOS
; /* in order to restore at exit */
17 static int ufoAtExitSet
= 0; /* register atexit just 1 time */
19 #define UFO_TTY_OUT_BUFFER_SIZE (4096)
20 static uint8_t ufoOutBuffer
[UFO_TTY_OUT_BUFFER_SIZE
];
21 static uint32_t ufoOutBufferUsed
= 0;
23 static void ufoAtExitCB (void);
26 //==========================================================================
30 //==========================================================================
31 static void ufoGetTTYSize (int *w
, int *h
) {
33 if (ioctl(1, TIOCGWINSZ
, &ws
) == 0) {
44 //==========================================================================
48 //==========================================================================
49 static int ufoEnableRaw (void) {
51 if (ufoTermIsRaw
) return 0;
52 if (!isatty(STDIN_FILENO
)) goto fatal
;
53 if (tcgetattr(STDIN_FILENO
, &ufoOrigTIOS
) == -1) goto fatal
;
54 raw
= ufoOrigTIOS
; /* modify the original mode */
55 /* input modes: no break, no CR to NL, no parity check, no strip char,
56 * no start/stop output control. */
57 raw
.c_iflag
&= ~(BRKINT
|ICRNL
|INPCK
|ISTRIP
|IXON
);
58 /* output modes - disable post processing */
59 raw
.c_oflag
&= ~(OPOST
);
60 /* control modes - set 8 bit chars */
62 /* local modes - choing off, canonical off, no extended functions,
63 * no signal chars (^Z,^C) */
64 raw
.c_lflag
&= ~(ECHO
|ICANON
|IEXTEN
|ISIG
);
65 /* control chars - set return condition: min number of bytes and timer;
66 * we want read to return every single byte, without timeout */
67 raw
.c_cc
[VMIN
] = 1; raw
.c_cc
[VTIME
] = 0; /* 1 byte, no timer */
68 /* put terminal in raw mode after flushing */
69 if (tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &raw
) < 0) goto fatal
;
70 if (!ufoAtExitSet
) { atexit(&ufoAtExitCB
); ufoAtExitSet
= 1; }
78 //==========================================================================
82 //==========================================================================
83 static void ufoDisableRaw (void) {
84 if (ufoTermIsRaw
&& tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &ufoOrigTIOS
) != -1) {
90 //==========================================================================
94 // at exit we'll try to fix the terminal to the initial conditions
96 //==========================================================================
97 static void ufoAtExitCB (void) {
105 // check if input and output are valid TTY(s).
109 if (isatty(STDIN_FILENO
) && isatty(STDOUT_FILENO
)) {
110 // this checks for pseudo-tty from my SXED, for example
111 // it doesn't have a proper size set
113 if (ioctl(1, TIOCGWINSZ
, &ws
) == 0) {
114 if (ws
.ws_col
>= 40 && ws
.ws_row
>= 24) {
125 // check if current TTY mode is raw.
127 ufoPushBool(ufoTermIsRaw
);
131 // ( -- width height )
132 // get TTY size. for non-TTYs retur default 80x24.
136 ufoGetTTYSize(&w
, &h
);
145 // ( -- success-bool )
146 // switch TTY to raw mode.
147 UFWORD(TTY_SET_RAW
) {
149 ufoPushBool(ufoEnableRaw() == 0);
156 // ( -- success-bool )
157 // switch TTY to cooked mode.
158 UFWORD(TTY_SET_COOKED
) {
161 ufoPushBool(ufoTermIsRaw
== 0);
168 //==========================================================================
172 //==========================================================================
173 static void ufoTTYRawFlush (void) {
174 if (ufoOutBufferUsed
!= 0) {
175 (void)write(STDOUT_FILENO
, ufoOutBuffer
, ufoOutBufferUsed
);
176 ufoOutBufferUsed
= 0;
181 //==========================================================================
185 //==========================================================================
186 static void ufoTTYRawEmit (uint8_t ch
) {
187 if (ufoOutBufferUsed
== UFO_TTY_OUT_BUFFER_SIZE
) ufoTTYRawFlush();
188 ufoOutBuffer
[ufoOutBufferUsed
] = ch
; ufoOutBufferUsed
+= 1;
190 if (ch
== '\n') ufoTTYRawFlush();
197 UFWORD(TTY_RAW_EMIT
) {
199 ufoTTYRawEmit((uint8_t)ufoPop());
207 UFWORD(TTY_RAW_TYPE
) {
209 int32_t count
= (int32_t)ufoPop();
210 uint32_t addr
= ufoPop();
212 const uint8_t ch
= ufoImgGetU8Ext(addr
);
214 addr
+= 1; count
-= 1;
217 ufoDrop(); ufoDrop();
223 UFWORD(TTY_RAW_FLUSH
) {
231 // -1 returned on error, or on EOF.
232 UFWORD(TTY_RAW_READCH
) {
233 uint32_t res
= ~(uint32_t)0; // -1
237 const ssize_t nread
= read(STDIN_FILENO
, &ch
, 1);
238 if (nread
== 1) res
= ch
;
246 // check if raw TTY has some data to read.
247 UFWORD(TTY_RAW_READYQ
) {
253 FD_SET(STDIN_FILENO
, &rd
);
255 to
.tv_sec
= 0; to
.tv_usec
= 0;
256 const int res
= select(STDIN_FILENO
+ 1, &rd
, NULL
, NULL
, &to
);
258 if (errno
== EINTR
) continue;
260 ufoPushBool(res
== 1);