UrForth: added some words for the address register manipulation; TYPE and others...
[urasm.git] / src / liburforth / urforth_tty.c
blob6f8d5f668a8f26d938cb44bd6c0e9a6149329cba
1 // and now for something completely different...
2 // UrAsm built-in Forth Engine!
3 // GPLv3 ONLY
4 #ifndef WIN32
5 #include <errno.h>
6 #include <termios.h>
7 #include <sys/select.h>
8 #include <sys/types.h>
9 #include <sys/ioctl.h>
10 #include <sys/time.h>
11 #endif
14 static int ufoTermIsRaw = 0; /* for atexit() function to check if restore is needed */
15 #ifndef WIN32
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 //==========================================================================
28 // ufoGetTTYSize
30 //==========================================================================
31 static void ufoGetTTYSize (int *w, int *h) {
32 struct winsize ws;
33 if (ioctl(1, TIOCGWINSZ, &ws) == 0) {
34 *w = (int)ws.ws_col;
35 *h = (int)ws.ws_row;
36 if (*w == 0) *w = 80;
37 if (*h == 0) *h = 24;
38 } else {
39 *w = 80; *h = 24;
44 //==========================================================================
46 // ufoEnableRaw
48 //==========================================================================
49 static int ufoEnableRaw (void) {
50 struct termios raw;
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 */
61 raw.c_cflag |= (CS8);
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; }
71 ufoTermIsRaw = 1;
72 return 0;
73 fatal:
74 return -1;
78 //==========================================================================
80 // ufoDisableRaw
82 //==========================================================================
83 static void ufoDisableRaw (void) {
84 if (ufoTermIsRaw && tcsetattr(STDIN_FILENO, TCSAFLUSH, &ufoOrigTIOS) != -1) {
85 ufoTermIsRaw = 0;
90 //==========================================================================
92 // ufoAtExitCB
94 // at exit we'll try to fix the terminal to the initial conditions
96 //==========================================================================
97 static void ufoAtExitCB (void) {
98 ufoDisableRaw();
100 #endif
103 // TTY:TTY?
104 // ( -- bool )
105 // check if input and output are valid TTY(s).
106 UFWORD(TTY_TTYQ) {
107 uint32_t res = 0;
108 #ifndef WIN32
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
112 struct winsize ws;
113 if (ioctl(1, TIOCGWINSZ, &ws) == 0) {
114 if (ws.ws_col >= 40 && ws.ws_row >= 24) {
115 res = 1;
119 #endif
120 ufoPushBool(res);
123 // TTY:RAW?
124 // ( -- bool )
125 // check if current TTY mode is raw.
126 UFWORD(TTY_RAWQ) {
127 ufoPushBool(ufoTermIsRaw);
130 // TTY:SIZE
131 // ( -- width height )
132 // get TTY size. for non-TTYs retur default 80x24.
133 UFWORD(TTY_SIZE) {
134 int w, h;
135 #ifndef WIN32
136 ufoGetTTYSize(&w, &h);
137 #else
138 w = 80; h = 24;
139 #endif
140 ufoPush(w);
141 ufoPush(h);
144 // TTY:SET-RAW
145 // ( -- success-bool )
146 // switch TTY to raw mode.
147 UFWORD(TTY_SET_RAW) {
148 #ifndef WIN32
149 ufoPushBool(ufoEnableRaw() == 0);
150 #else
151 ufoPushBool(0);
152 #endif
155 // TTY:SET-COOKED
156 // ( -- success-bool )
157 // switch TTY to cooked mode.
158 UFWORD(TTY_SET_COOKED) {
159 #ifndef WIN32
160 ufoDisableRaw();
161 ufoPushBool(ufoTermIsRaw == 0);
162 #else
163 ufoPushBool(0);
164 #endif
168 //==========================================================================
170 // ufoTTYRawFlush
172 //==========================================================================
173 static void ufoTTYRawFlush (void) {
174 if (ufoOutBufferUsed != 0) {
175 (void)write(STDOUT_FILENO, ufoOutBuffer, ufoOutBufferUsed);
176 ufoOutBufferUsed = 0;
181 //==========================================================================
183 // ufoTTYRawEmit
185 //==========================================================================
186 static void ufoTTYRawEmit (uint8_t ch) {
187 if (ufoOutBufferUsed == UFO_TTY_OUT_BUFFER_SIZE) ufoTTYRawFlush();
188 ufoOutBuffer[ufoOutBufferUsed] = ch; ufoOutBufferUsed += 1;
189 #if 0
190 if (ch == '\n') ufoTTYRawFlush();
191 #endif
195 // TTY:RAW-EMIT
196 // ( n -- )
197 UFWORD(TTY_RAW_EMIT) {
198 #ifndef WIN32
199 ufoTTYRawEmit((uint8_t)ufoPop());
200 #else
201 ufoDrop();
202 #endif
205 // TTY:RAW-TYPE
206 // ( addr count -- )
207 UFWORD(TTY_RAW_TYPE) {
208 #ifndef WIN32
209 int32_t count = (int32_t)ufoPop();
210 uint32_t addr = ufoPop();
211 while (count > 0) {
212 const uint8_t ch = ufoImgGetU8Ext(addr);
213 ufoTTYRawEmit(ch);
214 addr += 1; count -= 1;
216 #else
217 ufoDrop(); ufoDrop();
218 #endif
221 // TTY:RAW-FLUSH
222 // ( -- )
223 UFWORD(TTY_RAW_FLUSH) {
224 #ifndef WIN32
225 ufoTTYRawFlush();
226 #endif
229 // TTY:RAW-READCH
230 // ( -- ch / -1 )
231 // -1 returned on error, or on EOF.
232 UFWORD(TTY_RAW_READCH) {
233 uint32_t res = ~(uint32_t)0; // -1
234 #ifndef WIN32
235 if (ufoTermIsRaw) {
236 uint8_t ch;
237 const ssize_t nread = read(STDIN_FILENO, &ch, 1);
238 if (nread == 1) res = ch;
240 #endif
241 ufoPush(res);
244 // TTY:RAW-READY?
245 // ( -- bool )
246 // check if raw TTY has some data to read.
247 UFWORD(TTY_RAW_READYQ) {
248 #ifndef WIN32
249 if (ufoTermIsRaw) {
250 for (;;) {
251 fd_set rd;
252 FD_ZERO(&rd);
253 FD_SET(STDIN_FILENO, &rd);
254 struct timeval to;
255 to.tv_sec = 0; to.tv_usec = 0;
256 const int res = select(STDIN_FILENO + 1, &rd, NULL, NULL, &to);
257 if (res == -1) {
258 if (errno == EINTR) continue;
260 ufoPushBool(res == 1);
261 return;
264 #endif
265 ufoPushBool(0);