Commit | Line | Data |
---|---|---|
196ba1fc PH |
1 | /* sim_console.c: simulator console I/O library\r |
2 | \r | |
3 | Copyright (c) 1993-2006, Robert M Supnik\r | |
4 | \r | |
5 | Permission is hereby granted, free of charge, to any person obtaining a\r | |
6 | copy of this software and associated documentation files (the "Software"),\r | |
7 | to deal in the Software without restriction, including without limitation\r | |
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,\r | |
9 | and/or sell copies of the Software, and to permit persons to whom the\r | |
10 | Software is furnished to do so, subject to the following conditions:\r | |
11 | \r | |
12 | The above copyright notice and this permission notice shall be included in\r | |
13 | all copies or substantial portions of the Software.\r | |
14 | \r | |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r | |
18 | ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r | |
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r | |
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r | |
21 | \r | |
22 | Except as contained in this notice, the name of Robert M Supnik shall not be\r | |
23 | used in advertising or otherwise to promote the sale, use or other dealings\r | |
24 | in this Software without prior written authorization from Robert M Supnik.\r | |
25 | \r | |
26 | 30-Sep-06 RMS Fixed non-printable characters in KSR mode\r | |
27 | 22-Jun-06 RMS Implemented SET/SHOW PCHAR\r | |
28 | 31-May-06 JDB Fixed bug if SET CONSOLE DEBUG with no argument\r | |
29 | 22-Nov-05 RMS Added central input/output conversion support\r | |
30 | 05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy\r | |
31 | 28-Oct-04 JDB Fixed SET CONSOLE to allow comma-separated parameters\r | |
32 | 20-Aug-04 RMS Added OS/2 EMX fixes (from Holger Veit)\r | |
33 | 14-Jul-04 RMS Revised Windows console code (from Dave Bryan)\r | |
34 | 28-May-04 RMS Added SET/SHOW CONSOLE\r | |
35 | RMS Added break, delete character maps\r | |
36 | 02-Jan-04 RMS Removed timer routines, added Telnet console routines\r | |
37 | RMS Moved console logging to OS-independent code\r | |
38 | 25-Apr-03 RMS Added long seek support from Mark Pizzolato\r | |
39 | Added Unix priority control from Mark Pizzolato\r | |
40 | 24-Sep-02 RMS Removed VT support, added Telnet console support\r | |
41 | Added CGI support (from Brian Knittel)\r | |
42 | Added MacOS sleep (from Peter Schorn)\r | |
43 | 14-Jul-02 RMS Added Windows priority control from Mark Pizzolato\r | |
44 | 20-May-02 RMS Added Windows VT support from Fischer Franz\r | |
45 | 01-Feb-02 RMS Added VAX fix from Robert Alan Byer\r | |
46 | 19-Sep-01 RMS More Mac changes\r | |
47 | 31-Aug-01 RMS Changed int64 to t_int64 for Windoze\r | |
48 | 20-Jul-01 RMS Added Macintosh support (from Louis Chretien, Peter Schorn,\r | |
49 | and Ben Supnik)\r | |
50 | 15-May-01 RMS Added logging support\r | |
51 | 05-Mar-01 RMS Added clock calibration support\r | |
52 | 08-Dec-00 BKR Added OS/2 support (from Bruce Ray)\r | |
53 | 18-Aug-98 RMS Added BeOS support\r | |
54 | 13-Oct-97 RMS Added NetBSD terminal support\r | |
55 | 25-Jan-97 RMS Added POSIX terminal I/O support\r | |
56 | 02-Jan-97 RMS Fixed bug in sim_poll_kbd\r | |
57 | \r | |
58 | This module implements the following routines to support terminal I/O:\r | |
59 | \r | |
60 | sim_poll_kbd - poll for keyboard input\r | |
61 | sim_putchar - output character to console\r | |
62 | sim_putchar_s - output character to console, stall if congested\r | |
63 | sim_set_console - set console parameters\r | |
64 | sim_show_console - show console parameters\r | |
65 | sim_tt_inpcvt - convert input character per mode\r | |
66 | sim_tt_outcvt - convert output character per mode\r | |
67 | \r | |
68 | sim_ttinit - called once to get initial terminal state\r | |
69 | sim_ttrun - called to put terminal into run state\r | |
70 | sim_ttcmd - called to return terminal to command state\r | |
71 | sim_ttclose - called once before the simulator exits\r | |
72 | sim_os_poll_kbd - poll for keyboard input\r | |
73 | sim_os_putchar - output character to console\r | |
74 | \r | |
75 | The first group is OS-independent; the second group is OS-dependent.\r | |
76 | \r | |
77 | The following routines are exposed but deprecated:\r | |
78 | \r | |
79 | sim_set_telnet - set console to Telnet port\r | |
80 | sim_set_notelnet - close console Telnet port\r | |
81 | sim_show_telnet - show console status\r | |
82 | */\r | |
83 | \r | |
84 | #include "sim_defs.h"\r | |
85 | #include "sim_sock.h"\r | |
86 | #include "sim_tmxr.h"\r | |
87 | #include <ctype.h>\r | |
88 | \r | |
89 | #define KMAP_WRU 0\r | |
90 | #define KMAP_BRK 1\r | |
91 | #define KMAP_DEL 2\r | |
92 | #define KMAP_MASK 0377\r | |
93 | #define KMAP_NZ 0400\r | |
94 | \r | |
95 | int32 sim_int_char = 005; /* interrupt character */\r | |
96 | int32 sim_brk_char = 000; /* break character */\r | |
97 | int32 sim_tt_pchar = 0x00002780;\r | |
98 | #if defined (_WIN32) || defined (__OS2__) || (defined (__MWERKS__) && defined (macintosh))\r | |
99 | int32 sim_del_char = '\b'; /* delete character */\r | |
100 | #else\r | |
101 | int32 sim_del_char = 0177;\r | |
102 | #endif\r | |
103 | TMLN sim_con_ldsc = { 0 }; /* console line descr */\r | |
104 | TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc }; /* console line mux */\r | |
105 | \r | |
106 | extern volatile int32 stop_cpu;\r | |
107 | extern int32 sim_quiet, sim_deb_close;\r | |
108 | extern FILE *sim_log, *sim_deb;\r | |
109 | extern DEVICE *sim_devices[];\r | |
110 | \r | |
111 | /* Set/show data structures */\r | |
112 | \r | |
113 | static CTAB set_con_tab[] = {\r | |
114 | { "WRU", &sim_set_kmap, KMAP_WRU | KMAP_NZ },\r | |
115 | { "BRK", &sim_set_kmap, KMAP_BRK },\r | |
116 | { "DEL", &sim_set_kmap, KMAP_DEL |KMAP_NZ },\r | |
117 | { "PCHAR", &sim_set_pchar, 0 },\r | |
118 | { "TELNET", &sim_set_telnet, 0 },\r | |
119 | { "NOTELNET", &sim_set_notelnet, 0 },\r | |
120 | { "LOG", &sim_set_logon, 0 },\r | |
121 | { "NOLOG", &sim_set_logoff, 0 },\r | |
122 | { "DEBUG", &sim_set_debon, 0 },\r | |
123 | { "NODEBUG", &sim_set_deboff, 0 },\r | |
124 | { NULL, NULL, 0 }\r | |
125 | };\r | |
126 | \r | |
127 | static SHTAB show_con_tab[] = {\r | |
128 | { "WRU", &sim_show_kmap, KMAP_WRU },\r | |
129 | { "BRK", &sim_show_kmap, KMAP_BRK },\r | |
130 | { "DEL", &sim_show_kmap, KMAP_DEL },\r | |
131 | { "PCHAR", &sim_show_pchar, 0 },\r | |
132 | { "LOG", &sim_show_log, 0 },\r | |
133 | { "TELNET", &sim_show_telnet, 0 },\r | |
134 | { "DEBUG", &sim_show_debug, 0 },\r | |
135 | { NULL, NULL, 0 }\r | |
136 | };\r | |
137 | \r | |
138 | static int32 *cons_kmap[] = {\r | |
139 | &sim_int_char,\r | |
140 | &sim_brk_char,\r | |
141 | &sim_del_char\r | |
142 | };\r | |
143 | \r | |
144 | /* Console I/O package.\r | |
145 | \r | |
146 | The console terminal can be attached to the controlling window\r | |
147 | or to a Telnet connection. If attached to a Telnet connection,\r | |
148 | the console is described by internal terminal multiplexor\r | |
149 | sim_con_tmxr and internal terminal line description sim_con_ldsc.\r | |
150 | */\r | |
151 | \r | |
152 | /* SET CONSOLE command */\r | |
153 | \r | |
154 | t_stat sim_set_console (int32 flag, char *cptr)\r | |
155 | {\r | |
156 | char *cvptr, gbuf[CBUFSIZE];\r | |
157 | CTAB *ctptr;\r | |
158 | t_stat r;\r | |
159 | \r | |
160 | if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG;\r | |
161 | while (*cptr != 0) { /* do all mods */\r | |
162 | cptr = get_glyph_nc (cptr, gbuf, ','); /* get modifier */\r | |
163 | if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */\r | |
164 | get_glyph (gbuf, gbuf, 0); /* modifier to UC */\r | |
165 | if (ctptr = find_ctab (set_con_tab, gbuf)) { /* match? */\r | |
166 | r = ctptr->action (ctptr->arg, cvptr); /* do the rest */\r | |
167 | if (r != SCPE_OK) return r;\r | |
168 | }\r | |
169 | else return SCPE_NOPARAM;\r | |
170 | }\r | |
171 | return SCPE_OK;\r | |
172 | }\r | |
173 | \r | |
174 | /* SHOW CONSOLE command */\r | |
175 | \r | |
176 | t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r | |
177 | {\r | |
178 | char gbuf[CBUFSIZE];\r | |
179 | SHTAB *shptr;\r | |
180 | int32 i;\r | |
181 | \r | |
182 | if (*cptr == 0) { /* show all */\r | |
183 | for (i = 0; show_con_tab[i].name; i++)\r | |
184 | show_con_tab[i].action (st, dptr, uptr, show_con_tab[i].arg, cptr);\r | |
185 | return SCPE_OK;\r | |
186 | }\r | |
187 | while (*cptr != 0) {\r | |
188 | cptr = get_glyph (cptr, gbuf, ','); /* get modifier */\r | |
189 | if (shptr = find_shtab (show_con_tab, gbuf))\r | |
190 | shptr->action (st, dptr, uptr, shptr->arg, cptr);\r | |
191 | else return SCPE_NOPARAM;\r | |
192 | }\r | |
193 | return SCPE_OK;\r | |
194 | }\r | |
195 | \r | |
196 | /* Set keyboard map */\r | |
197 | \r | |
198 | t_stat sim_set_kmap (int32 flag, char *cptr)\r | |
199 | {\r | |
200 | DEVICE *dptr = sim_devices[0];\r | |
201 | int32 val, rdx;\r | |
202 | t_stat r;\r | |
203 | \r | |
204 | if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG;\r | |
205 | if (dptr->dradix == 16) rdx = 16;\r | |
206 | else rdx = 8;\r | |
207 | val = (int32) get_uint (cptr, rdx, 0177, &r);\r | |
208 | if ((r != SCPE_OK) ||\r | |
209 | ((val == 0) && (flag & KMAP_NZ))) return SCPE_ARG;\r | |
210 | *(cons_kmap[flag & KMAP_MASK]) = val;\r | |
211 | return SCPE_OK;\r | |
212 | }\r | |
213 | \r | |
214 | /* Show keyboard map */\r | |
215 | \r | |
216 | t_stat sim_show_kmap (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r | |
217 | {\r | |
218 | if (sim_devices[0]->dradix == 16)\r | |
219 | fprintf (st, "%s = %X\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK]));\r | |
220 | else fprintf (st, "%s = %o\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK]));\r | |
221 | return SCPE_OK;\r | |
222 | }\r | |
223 | \r | |
224 | /* Set printable characters */\r | |
225 | \r | |
226 | t_stat sim_set_pchar (int32 flag, char *cptr)\r | |
227 | {\r | |
228 | DEVICE *dptr = sim_devices[0];\r | |
229 | uint32 val, rdx;\r | |
230 | t_stat r;\r | |
231 | \r | |
232 | if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG;\r | |
233 | if (dptr->dradix == 16) rdx = 16;\r | |
234 | else rdx = 8;\r | |
235 | val = (uint32) get_uint (cptr, rdx, 0xFFFFFFFF, &r);\r | |
236 | if ((r != SCPE_OK) ||\r | |
237 | ((val & 0x00002400) == 0)) return SCPE_ARG;\r | |
238 | sim_tt_pchar = val;\r | |
239 | return SCPE_OK;\r | |
240 | }\r | |
241 | \r | |
242 | /* Show printable characters */\r | |
243 | \r | |
244 | t_stat sim_show_pchar (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r | |
245 | {\r | |
246 | if (sim_devices[0]->dradix == 16)\r | |
247 | fprintf (st, "pchar mask = %X\n", sim_tt_pchar);\r | |
248 | else fprintf (st, "pchar mask = %o\n", sim_tt_pchar);\r | |
249 | return SCPE_OK;\r | |
250 | }\r | |
251 | \r | |
252 | /* Set log routine */\r | |
253 | \r | |
254 | t_stat sim_set_logon (int32 flag, char *cptr)\r | |
255 | {\r | |
256 | char gbuf[CBUFSIZE];\r | |
257 | \r | |
258 | if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; /* need arg */\r | |
259 | cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */\r | |
260 | if (*cptr != 0) return SCPE_2MARG; /* now eol? */\r | |
261 | sim_set_logoff (0, NULL); /* close cur log */\r | |
262 | sim_log = sim_fopen (gbuf, "a"); /* open log */\r | |
263 | if (sim_log == NULL) return SCPE_OPENERR; /* error? */\r | |
264 | if (!sim_quiet) printf ("Logging to file \"%s\"\n", gbuf);\r | |
265 | fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); /* start of log */\r | |
266 | return SCPE_OK;\r | |
267 | }\r | |
268 | \r | |
269 | /* Set nolog routine */\r | |
270 | \r | |
271 | t_stat sim_set_logoff (int32 flag, char *cptr)\r | |
272 | {\r | |
273 | if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */\r | |
274 | if (sim_log == NULL) return SCPE_OK; /* no log? */\r | |
275 | if (!sim_quiet) printf ("Log file closed\n");\r | |
276 | fprintf (sim_log, "Log file closed\n"); /* close log */\r | |
277 | fclose (sim_log);\r | |
278 | sim_log = NULL;\r | |
279 | return SCPE_OK;\r | |
280 | }\r | |
281 | \r | |
282 | /* Show log status */\r | |
283 | \r | |
284 | t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r | |
285 | {\r | |
286 | if (cptr && (*cptr != 0)) return SCPE_2MARG;\r | |
287 | if (sim_log) fputs ("Logging enabled\n", st);\r | |
288 | else fputs ("Logging disabled\n", st);\r | |
289 | return SCPE_OK;\r | |
290 | }\r | |
291 | \r | |
292 | /* Set debug routine */\r | |
293 | \r | |
294 | t_stat sim_set_debon (int32 flag, char *cptr)\r | |
295 | {\r | |
296 | char *tptr, gbuf[CBUFSIZE];\r | |
297 | \r | |
298 | if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; /* too few arguments? */\r | |
299 | tptr = get_glyph (cptr, gbuf, 0); /* get file name */\r | |
300 | if (*tptr != 0) return SCPE_2MARG; /* now eol? */\r | |
301 | sim_set_deboff (0, NULL); /* close cur debug */\r | |
302 | if (strcmp (gbuf, "LOG") == 0) { /* debug to log? */\r | |
303 | if (sim_log == NULL) return SCPE_ARG; /* any log? */\r | |
304 | sim_deb = sim_log;\r | |
305 | }\r | |
306 | else if (strcmp (gbuf, "STDOUT") == 0) sim_deb = stdout; /* debug to stdout? */\r | |
307 | else if (strcmp (gbuf, "STDERR") == 0) sim_deb = stderr; /* debug to stderr? */\r | |
308 | else {\r | |
309 | cptr = get_glyph_nc (cptr, gbuf, 0); /* reparse */\r | |
310 | sim_deb = sim_fopen (gbuf, "a"); /* open debug */\r | |
311 | if (sim_deb == NULL) return SCPE_OPENERR; /* error? */\r | |
312 | sim_deb_close = 1; /* need close */\r | |
313 | }\r | |
314 | if (!sim_quiet) printf ("Debug output to \"%s\"\n", gbuf);\r | |
315 | if (sim_log) fprintf (sim_log, "Debug output to \"%s\"\n", gbuf);\r | |
316 | return SCPE_OK;\r | |
317 | }\r | |
318 | \r | |
319 | /* Set nodebug routine */\r | |
320 | \r | |
321 | t_stat sim_set_deboff (int32 flag, char *cptr)\r | |
322 | {\r | |
323 | if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */\r | |
324 | if (sim_deb == NULL) return SCPE_OK; /* no log? */\r | |
325 | if (!sim_quiet) printf ("Debug output disabled\n");\r | |
326 | if (sim_log) fprintf (sim_log, "Debug output disabled\n");\r | |
327 | if (sim_deb_close) fclose (sim_deb); /* close if needed */\r | |
328 | sim_deb_close = 0;\r | |
329 | sim_deb = NULL;\r | |
330 | return SCPE_OK;\r | |
331 | }\r | |
332 | \r | |
333 | /* Show debug routine */\r | |
334 | \r | |
335 | t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)\r | |
336 | {\r | |
337 | if (cptr && (*cptr != 0)) return SCPE_2MARG;\r | |
338 | if (sim_deb) fputs ("Debug output enabled\n", st);\r | |
339 | else fputs ("Debug output disabled\n", st);\r | |
340 | return SCPE_OK;\r | |
341 | }\r | |
342 | \r | |
343 | /* Set console to Telnet port */\r | |
344 | \r | |
345 | t_stat sim_set_telnet (int32 flg, char *cptr)\r | |
346 | {\r | |
347 | if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; /* too few arguments? */\r | |
348 | if (sim_con_tmxr.master) return SCPE_ALATT; /* already open? */\r | |
349 | return tmxr_open_master (&sim_con_tmxr, cptr); /* open master socket */\r | |
350 | }\r | |
351 | \r | |
352 | /* Close console Telnet port */\r | |
353 | \r | |
354 | t_stat sim_set_notelnet (int32 flag, char *cptr)\r | |
355 | {\r | |
356 | if (cptr && (*cptr != 0)) return SCPE_2MARG; /* too many arguments? */\r | |
357 | if (sim_con_tmxr.master == 0) return SCPE_OK; /* ignore if already closed */\r | |
358 | return tmxr_close_master (&sim_con_tmxr); /* close master socket */\r | |
359 | }\r | |
360 | \r | |
361 | /* Show console Telnet status */\r | |
362 | \r | |
363 | t_stat sim_show_telnet (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, char *cptr)\r | |
364 | {\r | |
365 | if (cptr && (*cptr != 0)) return SCPE_2MARG;\r | |
366 | if (sim_con_tmxr.master == 0)\r | |
367 | fprintf (st, "Connected to console window\n");\r | |
368 | else if (sim_con_ldsc.conn == 0)\r | |
369 | fprintf (st, "Listening on port %d\n", sim_con_tmxr.port);\r | |
370 | else {\r | |
371 | fprintf (st, "Listening on port %d, connected to socket %d\n",\r | |
372 | sim_con_tmxr.port, sim_con_ldsc.conn);\r | |
373 | tmxr_fconns (st, &sim_con_ldsc, -1);\r | |
374 | tmxr_fstats (st, &sim_con_ldsc, -1);\r | |
375 | }\r | |
376 | return SCPE_OK;\r | |
377 | }\r | |
378 | \r | |
379 | /* Check connection before executing */\r | |
380 | \r | |
381 | t_stat sim_check_console (int32 sec)\r | |
382 | {\r | |
383 | int32 c, i;\r | |
384 | \r | |
385 | if (sim_con_tmxr.master == 0) return SCPE_OK; /* not Telnet? done */\r | |
386 | if (sim_con_ldsc.conn) { /* connected? */\r | |
387 | tmxr_poll_rx (&sim_con_tmxr); /* poll (check disconn) */\r | |
388 | if (sim_con_ldsc.conn) return SCPE_OK; /* still connected? */\r | |
389 | }\r | |
390 | for (i = 0; i < sec; i++) { /* loop */\r | |
391 | if (tmxr_poll_conn (&sim_con_tmxr) >= 0) { /* poll connect */\r | |
392 | sim_con_ldsc.rcve = 1; /* rcv enabled */\r | |
393 | if (i) { /* if delayed */\r | |
394 | printf ("Running\n"); /* print transition */\r | |
395 | fflush (stdout);\r | |
396 | }\r | |
397 | return SCPE_OK; /* ready to proceed */\r | |
398 | }\r | |
399 | c = sim_os_poll_kbd (); /* check for stop char */\r | |
400 | if ((c == SCPE_STOP) || stop_cpu) return SCPE_STOP;\r | |
401 | if ((i % 10) == 0) { /* Status every 10 sec */\r | |
402 | printf ("Waiting for console Telnet connection\n");\r | |
403 | fflush (stdout);\r | |
404 | }\r | |
405 | sim_os_sleep (1); /* wait 1 second */\r | |
406 | }\r | |
407 | return SCPE_TTMO; /* timed out */\r | |
408 | }\r | |
409 | \r | |
410 | /* Poll for character */\r | |
411 | \r | |
412 | t_stat sim_poll_kbd (void)\r | |
413 | {\r | |
414 | int32 c;\r | |
415 | \r | |
416 | c = sim_os_poll_kbd (); /* get character */\r | |
417 | if ((c == SCPE_STOP) || (sim_con_tmxr.master == 0)) /* ^E or not Telnet? */\r | |
418 | return c; /* in-window */\r | |
419 | if (sim_con_ldsc.conn == 0) return SCPE_LOST; /* no Telnet conn? */\r | |
420 | tmxr_poll_rx (&sim_con_tmxr); /* poll for input */\r | |
421 | if (c = tmxr_getc_ln (&sim_con_ldsc)) /* any char? */ \r | |
422 | return (c & (SCPE_BREAK | 0377)) | SCPE_KFLAG;\r | |
423 | return SCPE_OK;\r | |
424 | }\r | |
425 | \r | |
426 | /* Output character */\r | |
427 | \r | |
428 | t_stat sim_putchar (int32 c)\r | |
429 | {\r | |
430 | if (sim_log) fputc (c, sim_log); /* log file? */\r | |
431 | if (sim_con_tmxr.master == 0) /* not Telnet? */\r | |
432 | return sim_os_putchar (c); /* in-window version */\r | |
433 | if (sim_con_ldsc.conn == 0) return SCPE_LOST; /* no Telnet conn? */\r | |
434 | tmxr_putc_ln (&sim_con_ldsc, c); /* output char */\r | |
435 | tmxr_poll_tx (&sim_con_tmxr); /* poll xmt */\r | |
436 | return SCPE_OK;\r | |
437 | }\r | |
438 | \r | |
439 | t_stat sim_putchar_s (int32 c)\r | |
440 | {\r | |
441 | t_stat r;\r | |
442 | \r | |
443 | if (sim_log) fputc (c, sim_log); /* log file? */\r | |
444 | if (sim_con_tmxr.master == 0) /* not Telnet? */\r | |
445 | return sim_os_putchar (c); /* in-window version */\r | |
446 | if (sim_con_ldsc.conn == 0) return SCPE_LOST; /* no Telnet conn? */\r | |
447 | if (sim_con_ldsc.xmte == 0) r = SCPE_STALL; /* xmt disabled? */\r | |
448 | else r = tmxr_putc_ln (&sim_con_ldsc, c); /* no, Telnet output */\r | |
449 | tmxr_poll_tx (&sim_con_tmxr); /* poll xmt */\r | |
450 | return r; /* return status */\r | |
451 | }\r | |
452 | \r | |
453 | /* Input character processing */\r | |
454 | \r | |
455 | int32 sim_tt_inpcvt (int32 c, uint32 mode)\r | |
456 | {\r | |
457 | uint32 md = mode & TTUF_M_MODE;\r | |
458 | \r | |
459 | if (md != TTUF_MODE_8B) {\r | |
460 | c = c & 0177;\r | |
461 | if (md == TTUF_MODE_UC) {\r | |
462 | if (islower (c)) c = toupper (c);\r | |
463 | if (mode & TTUF_KSR) c = c | 0200;\r | |
464 | }\r | |
465 | }\r | |
466 | else c = c & 0377;\r | |
467 | return c;\r | |
468 | }\r | |
469 | \r | |
470 | /* Output character processing */\r | |
471 | \r | |
472 | int32 sim_tt_outcvt (int32 c, uint32 mode)\r | |
473 | {\r | |
474 | uint32 md = mode & TTUF_M_MODE;\r | |
475 | \r | |
476 | if (md != TTUF_MODE_8B) {\r | |
477 | c = c & 0177;\r | |
478 | if (md == TTUF_MODE_UC) {\r | |
479 | if (islower (c)) c = toupper (c);\r | |
480 | if ((mode & TTUF_KSR) && (c >= 0140))\r | |
481 | return -1;\r | |
482 | }\r | |
483 | if (((md == TTUF_MODE_UC) || (md == TTUF_MODE_7P)) &&\r | |
484 | ((c == 0177) ||\r | |
485 | ((c < 040) && !((sim_tt_pchar >> c) & 1))))\r | |
486 | return -1;\r | |
487 | }\r | |
488 | else c = c & 0377;\r | |
489 | return c;\r | |
490 | }\r | |
491 | \r | |
492 | /* VMS routines, from Ben Thomas, with fixes from Robert Alan Byer */\r | |
493 | \r | |
494 | #if defined (VMS)\r | |
495 | \r | |
496 | #if defined(__VAX)\r | |
497 | #define sys$assign SYS$ASSIGN\r | |
498 | #define sys$qiow SYS$QIOW\r | |
499 | #endif\r | |
500 | \r | |
501 | #include <descrip.h>\r | |
502 | #include <ttdef.h>\r | |
503 | #include <tt2def.h>\r | |
504 | #include <iodef.h>\r | |
505 | #include <ssdef.h>\r | |
506 | #include <starlet.h>\r | |
507 | #include <unistd.h>\r | |
508 | \r | |
509 | #define EFN 0\r | |
510 | uint32 tty_chan = 0;\r | |
511 | \r | |
512 | typedef struct {\r | |
513 | unsigned short sense_count;\r | |
514 | unsigned char sense_first_char;\r | |
515 | unsigned char sense_reserved;\r | |
516 | unsigned int stat;\r | |
517 | unsigned int stat2; } SENSE_BUF;\r | |
518 | \r | |
519 | typedef struct {\r | |
520 | unsigned short status;\r | |
521 | unsigned short count;\r | |
522 | unsigned int dev_status; } IOSB;\r | |
523 | \r | |
524 | SENSE_BUF cmd_mode = { 0 };\r | |
525 | SENSE_BUF run_mode = { 0 };\r | |
526 | \r | |
527 | t_stat sim_ttinit (void)\r | |
528 | {\r | |
529 | unsigned int status;\r | |
530 | IOSB iosb;\r | |
531 | $DESCRIPTOR (terminal_device, "tt");\r | |
532 | \r | |
533 | status = sys$assign (&terminal_device, &tty_chan, 0, 0);\r | |
534 | if (status != SS$_NORMAL) return SCPE_TTIERR;\r | |
535 | status = sys$qiow (EFN, tty_chan, IO$_SENSEMODE, &iosb, 0, 0,\r | |
536 | &cmd_mode, sizeof (cmd_mode), 0, 0, 0, 0);\r | |
537 | if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR;\r | |
538 | run_mode = cmd_mode;\r | |
539 | run_mode.stat = cmd_mode.stat | TT$M_NOECHO & ~(TT$M_HOSTSYNC | TT$M_TTSYNC);\r | |
540 | run_mode.stat2 = cmd_mode.stat2 | TT2$M_PASTHRU;\r | |
541 | return SCPE_OK;\r | |
542 | }\r | |
543 | \r | |
544 | t_stat sim_ttrun (void)\r | |
545 | {\r | |
546 | unsigned int status;\r | |
547 | IOSB iosb;\r | |
548 | \r | |
549 | status = sys$qiow (EFN, tty_chan, IO$_SETMODE, &iosb, 0, 0,\r | |
550 | &run_mode, sizeof (run_mode), 0, 0, 0, 0);\r | |
551 | if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR;\r | |
552 | return SCPE_OK;\r | |
553 | }\r | |
554 | \r | |
555 | t_stat sim_ttcmd (void)\r | |
556 | {\r | |
557 | unsigned int status;\r | |
558 | IOSB iosb;\r | |
559 | \r | |
560 | status = sys$qiow (EFN, tty_chan, IO$_SETMODE, &iosb, 0, 0,\r | |
561 | &cmd_mode, sizeof (cmd_mode), 0, 0, 0, 0);\r | |
562 | if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR;\r | |
563 | return SCPE_OK;\r | |
564 | }\r | |
565 | \r | |
566 | t_stat sim_ttclose (void)\r | |
567 | {\r | |
568 | return sim_ttcmd ();\r | |
569 | }\r | |
570 | \r | |
571 | t_stat sim_os_poll_kbd (void)\r | |
572 | {\r | |
573 | unsigned int status, term[2];\r | |
574 | unsigned char buf[4];\r | |
575 | IOSB iosb;\r | |
576 | SENSE_BUF sense;\r | |
577 | \r | |
578 | term[0] = 0; term[1] = 0;\r | |
579 | status = sys$qiow (EFN, tty_chan, IO$_SENSEMODE | IO$M_TYPEAHDCNT, &iosb,\r | |
580 | 0, 0, &sense, 8, 0, term, 0, 0);\r | |
581 | if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR;\r | |
582 | if (sense.sense_count == 0) return SCPE_OK;\r | |
583 | term[0] = 0; term[1] = 0;\r | |
584 | status = sys$qiow (EFN, tty_chan,\r | |
585 | IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO,\r | |
586 | &iosb, 0, 0, buf, 1, 0, term, 0, 0);\r | |
587 | if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_OK;\r | |
588 | if (buf[0] == sim_int_char) return SCPE_STOP;\r | |
589 | if (sim_brk_char && (buf[0] == sim_brk_char)) return SCPE_BREAK;\r | |
590 | return (buf[0] | SCPE_KFLAG);\r | |
591 | }\r | |
592 | \r | |
593 | t_stat sim_os_putchar (int32 out)\r | |
594 | {\r | |
595 | unsigned int status;\r | |
596 | char c;\r | |
597 | IOSB iosb;\r | |
598 | \r | |
599 | c = out;\r | |
600 | status = sys$qiow (EFN, tty_chan, IO$_WRITELBLK | IO$M_NOFORMAT,\r | |
601 | &iosb, 0, 0, &c, 1, 0, 0, 0, 0);\r | |
602 | if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTOERR;\r | |
603 | return SCPE_OK;\r | |
604 | }\r | |
605 | \r | |
606 | /* Win32 routines */\r | |
607 | \r | |
608 | #elif defined (_WIN32)\r | |
609 | \r | |
610 | #include <conio.h>\r | |
611 | #include <fcntl.h>\r | |
612 | #include <io.h>\r | |
613 | #include <windows.h>\r | |
614 | #define RAW_MODE 0\r | |
615 | static HANDLE std_input;\r | |
616 | static DWORD saved_mode;\r | |
617 | \r | |
618 | t_stat sim_ttinit (void)\r | |
619 | {\r | |
620 | std_input = GetStdHandle (STD_INPUT_HANDLE);\r | |
621 | if ((std_input == INVALID_HANDLE_VALUE) ||\r | |
622 | !GetConsoleMode (std_input, &saved_mode)) return SCPE_TTYERR;\r | |
623 | return SCPE_OK;\r | |
624 | }\r | |
625 | \r | |
626 | t_stat sim_ttrun (void)\r | |
627 | {\r | |
628 | if (!GetConsoleMode(std_input, &saved_mode) ||\r | |
629 | !SetConsoleMode(std_input, RAW_MODE)) return SCPE_TTYERR;\r | |
630 | if (sim_log) {\r | |
631 | fflush (sim_log);\r | |
632 | _setmode (_fileno (sim_log), _O_BINARY);\r | |
633 | }\r | |
634 | SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);\r | |
635 | return SCPE_OK;\r | |
636 | }\r | |
637 | \r | |
638 | t_stat sim_ttcmd (void)\r | |
639 | {\r | |
640 | if (sim_log) {\r | |
641 | fflush (sim_log);\r | |
642 | _setmode (_fileno (sim_log), _O_TEXT);\r | |
643 | }\r | |
644 | SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL);\r | |
645 | if (!SetConsoleMode(std_input, saved_mode)) return SCPE_TTYERR;\r | |
646 | return SCPE_OK;\r | |
647 | }\r | |
648 | \r | |
649 | t_stat sim_ttclose (void)\r | |
650 | {\r | |
651 | return SCPE_OK;\r | |
652 | }\r | |
653 | \r | |
654 | t_stat sim_os_poll_kbd (void)\r | |
655 | {\r | |
656 | int c;\r | |
657 | \r | |
658 | if (!_kbhit ()) return SCPE_OK;\r | |
659 | c = _getch ();\r | |
660 | if ((c & 0177) == sim_del_char) c = 0177;\r | |
661 | if ((c & 0177) == sim_int_char) return SCPE_STOP;\r | |
662 | if (sim_brk_char && ((c & 0177) == sim_brk_char)) return SCPE_BREAK;\r | |
663 | return c | SCPE_KFLAG;\r | |
664 | }\r | |
665 | \r | |
666 | t_stat sim_os_putchar (int32 c)\r | |
667 | {\r | |
668 | if (c != 0177) _putch (c);\r | |
669 | return SCPE_OK;\r | |
670 | }\r | |
671 | \r | |
672 | /* OS/2 routines, from Bruce Ray and Holger Veit */\r | |
673 | \r | |
674 | #elif defined (__OS2__)\r | |
675 | \r | |
676 | #include <conio.h>\r | |
677 | \r | |
678 | t_stat sim_ttinit (void)\r | |
679 | {\r | |
680 | return SCPE_OK;\r | |
681 | }\r | |
682 | \r | |
683 | t_stat sim_ttrun (void)\r | |
684 | {\r | |
685 | return SCPE_OK;\r | |
686 | }\r | |
687 | \r | |
688 | t_stat sim_ttcmd (void)\r | |
689 | {\r | |
690 | return SCPE_OK;\r | |
691 | }\r | |
692 | \r | |
693 | t_stat sim_ttclose (void)\r | |
694 | {\r | |
695 | return SCPE_OK;\r | |
696 | }\r | |
697 | \r | |
698 | t_stat sim_os_poll_kbd (void)\r | |
699 | {\r | |
700 | int c;\r | |
701 | \r | |
702 | #if defined (__EMX__)\r | |
703 | switch (c = _read_kbd(0,0,0)) { /* EMX has _read_kbd */\r | |
704 | \r | |
705 | case -1: /* no char*/\r | |
706 | return SCPE_OK;\r | |
707 | \r | |
708 | case 0: /* char pending */\r | |
709 | c = _read_kbd(0,1,0);\r | |
710 | break;\r | |
711 | \r | |
712 | default: /* got char */\r | |
713 | break;\r | |
714 | }\r | |
715 | #else\r | |
716 | if (!kbhit ()) return SCPE_OK;\r | |
717 | c = getch();\r | |
718 | #endif\r | |
719 | if ((c & 0177) == sim_del_char) c = 0177;\r | |
720 | if ((c & 0177) == sim_int_char) return SCPE_STOP;\r | |
721 | if (sim_brk_char && ((c & 0177) == sim_brk_char)) return SCPE_BREAK;\r | |
722 | return c | SCPE_KFLAG;\r | |
723 | }\r | |
724 | \r | |
725 | t_stat sim_os_putchar (int32 c)\r | |
726 | {\r | |
727 | if (c != 0177) {\r | |
728 | #if defined (__EMX__)\r | |
729 | putchar (c);\r | |
730 | #else\r | |
731 | putch (c);\r | |
732 | #endif\r | |
733 | fflush (stdout);\r | |
734 | }\r | |
735 | return SCPE_OK;\r | |
736 | }\r | |
737 | \r | |
738 | /* Metrowerks CodeWarrior Macintosh routines, from Louis Chretien and\r | |
739 | Peter Schorn */\r | |
740 | \r | |
741 | #elif defined (__MWERKS__) && defined (macintosh)\r | |
742 | \r | |
743 | #include <console.h>\r | |
744 | #include <Mactypes.h>\r | |
745 | #include <string.h>\r | |
746 | #include <sioux.h>\r | |
747 | #include <unistd.h>\r | |
748 | #include <siouxglobals.h>\r | |
749 | #include <Traps.h>\r | |
750 | #include <LowMem.h>\r | |
751 | \r | |
752 | /* function prototypes */\r | |
753 | \r | |
754 | Boolean SIOUXIsAppWindow(WindowPtr window);\r | |
755 | void SIOUXDoMenuChoice(long menuValue);\r | |
756 | void SIOUXUpdateMenuItems(void);\r | |
757 | void SIOUXUpdateScrollbar(void);\r | |
758 | int ps_kbhit(void);\r | |
759 | int ps_getch(void);\r | |
760 | \r | |
761 | extern char sim_name[];\r | |
762 | extern pSIOUXWin SIOUXTextWindow;\r | |
763 | static CursHandle iBeamCursorH = NULL; /* contains the iBeamCursor */\r | |
764 | \r | |
765 | static void updateCursor(void) {\r | |
766 | WindowPtr window;\r | |
767 | window = FrontWindow();\r | |
768 | if (SIOUXIsAppWindow(window)) {\r | |
769 | GrafPtr savePort;\r | |
770 | Point localMouse;\r | |
771 | GetPort(&savePort);\r | |
772 | SetPort(window);\r | |
773 | #if TARGET_API_MAC_CARBON\r | |
774 | GetGlobalMouse(&localMouse);\r | |
775 | #else\r | |
776 | localMouse = LMGetMouseLocation();\r | |
777 | #endif\r | |
778 | GlobalToLocal(&localMouse);\r | |
779 | if (PtInRect(localMouse, &(*SIOUXTextWindow->edit)->viewRect) && iBeamCursorH) {\r | |
780 | SetCursor(*iBeamCursorH);\r | |
781 | }\r | |
782 | else {\r | |
783 | SetCursor(&qd.arrow);\r | |
784 | }\r | |
785 | TEIdle(SIOUXTextWindow->edit);\r | |
786 | SetPort(savePort);\r | |
787 | }\r | |
788 | else {\r | |
789 | SetCursor(&qd.arrow);\r | |
790 | TEIdle(SIOUXTextWindow->edit);\r | |
791 | }\r | |
792 | return;\r | |
793 | }\r | |
794 | \r | |
795 | int ps_kbhit(void) {\r | |
796 | EventRecord event;\r | |
797 | int c;\r | |
798 | updateCursor();\r | |
799 | SIOUXUpdateScrollbar();\r | |
800 | while (GetNextEvent(updateMask | osMask | mDownMask | mUpMask | activMask |\r | |
801 | highLevelEventMask | diskEvt, &event)) {\r | |
802 | SIOUXHandleOneEvent(&event);\r | |
803 | }\r | |
804 | if (SIOUXQuitting) {\r | |
805 | exit(1);\r | |
806 | }\r | |
807 | if (EventAvail(keyDownMask,&event)) {\r | |
808 | c = event.message&charCodeMask;\r | |
809 | if ((event.modifiers & cmdKey) && (c > 0x20)) {\r | |
810 | GetNextEvent(keyDownMask, &event);\r | |
811 | SIOUXHandleOneEvent(&event);\r | |
812 | if (SIOUXQuitting) {\r | |
813 | exit(1);\r | |
814 | }\r | |
815 | return false;\r | |
816 | }\r | |
817 | return true;\r | |
818 | }\r | |
819 | else {\r | |
820 | return false;\r | |
821 | }\r | |
822 | }\r | |
823 | \r | |
824 | int ps_getch(void) {\r | |
825 | int c;\r | |
826 | EventRecord event;\r | |
827 | fflush(stdout);\r | |
828 | updateCursor();\r | |
829 | while(!GetNextEvent(keyDownMask,&event)) {\r | |
830 | if (GetNextEvent(updateMask | osMask | mDownMask | mUpMask | activMask |\r | |
831 | highLevelEventMask | diskEvt, &event)) {\r | |
832 | SIOUXUpdateScrollbar();\r | |
833 | SIOUXHandleOneEvent(&event);\r | |
834 | }\r | |
835 | }\r | |
836 | if (SIOUXQuitting) {\r | |
837 | exit(1);\r | |
838 | }\r | |
839 | c = event.message&charCodeMask;\r | |
840 | if ((event.modifiers & cmdKey) && (c > 0x20)) {\r | |
841 | SIOUXUpdateMenuItems();\r | |
842 | SIOUXDoMenuChoice(MenuKey(c));\r | |
843 | }\r | |
844 | if (SIOUXQuitting) {\r | |
845 | exit(1);\r | |
846 | }\r | |
847 | return c;\r | |
848 | }\r | |
849 | \r | |
850 | /* Note that this only works if the call to sim_ttinit comes before any output to the console */\r | |
851 | \r | |
852 | t_stat sim_ttinit (void) {\r | |
853 | int i;\r | |
854 | /* this blank will later be replaced by the number of characters */\r | |
855 | char title[50] = " ";\r | |
856 | unsigned char ptitle[50];\r | |
857 | SIOUXSettings.autocloseonquit = TRUE;\r | |
858 | SIOUXSettings.asktosaveonclose = FALSE;\r | |
859 | SIOUXSettings.showstatusline = FALSE;\r | |
860 | SIOUXSettings.columns = 80;\r | |
861 | SIOUXSettings.rows = 40;\r | |
862 | SIOUXSettings.toppixel = 42;\r | |
863 | SIOUXSettings.leftpixel = 6;\r | |
864 | iBeamCursorH = GetCursor(iBeamCursor);\r | |
865 | strcat(title, sim_name);\r | |
866 | strcat(title, " Simulator");\r | |
867 | title[0] = strlen(title) - 1; /* Pascal string done */\r | |
868 | for (i = 0; i <= title[0]; i++) { /* copy to unsigned char */\r | |
869 | ptitle[i] = title[i];\r | |
870 | }\r | |
871 | SIOUXSetTitle(ptitle);\r | |
872 | return SCPE_OK;\r | |
873 | }\r | |
874 | \r | |
875 | t_stat sim_ttrun (void)\r | |
876 | {\r | |
877 | return SCPE_OK;\r | |
878 | }\r | |
879 | \r | |
880 | t_stat sim_ttcmd (void)\r | |
881 | {\r | |
882 | return SCPE_OK;\r | |
883 | }\r | |
884 | \r | |
885 | t_stat sim_ttclose (void)\r | |
886 | {\r | |
887 | return SCPE_OK;\r | |
888 | }\r | |
889 | \r | |
890 | t_stat sim_os_poll_kbd (void)\r | |
891 | {\r | |
892 | int c;\r | |
893 | \r | |
894 | if (!ps_kbhit ()) return SCPE_OK;\r | |
895 | c = ps_getch();\r | |
896 | if ((c & 0177) == sim_del_char) c = 0177;\r | |
897 | if ((c & 0177) == sim_int_char) return SCPE_STOP;\r | |
898 | if (sim_brk_char && ((c & 0177) == sim_brk_char)) return SCPE_BREAK;\r | |
899 | return c | SCPE_KFLAG;\r | |
900 | }\r | |
901 | \r | |
902 | t_stat sim_os_putchar (int32 c)\r | |
903 | {\r | |
904 | if (c != 0177) {\r | |
905 | putchar (c);\r | |
906 | fflush (stdout);\r | |
907 | }\r | |
908 | return SCPE_OK;\r | |
909 | }\r | |
910 | \r | |
911 | /* BSD UNIX routines */\r | |
912 | \r | |
913 | #elif defined (BSDTTY)\r | |
914 | \r | |
915 | #include <sgtty.h>\r | |
916 | #include <fcntl.h>\r | |
917 | #include <unistd.h>\r | |
918 | \r | |
919 | struct sgttyb cmdtty,runtty; /* V6/V7 stty data */\r | |
920 | struct tchars cmdtchars,runtchars; /* V7 editing */\r | |
921 | struct ltchars cmdltchars,runltchars; /* 4.2 BSD editing */\r | |
922 | int cmdfl,runfl; /* TTY flags */\r | |
923 | \r | |
924 | t_stat sim_ttinit (void)\r | |
925 | {\r | |
926 | cmdfl = fcntl (0, F_GETFL, 0); /* get old flags and status */\r | |
927 | runfl = cmdfl | FNDELAY;\r | |
928 | if (ioctl (0, TIOCGETP, &cmdtty) < 0) return SCPE_TTIERR;\r | |
929 | if (ioctl (0, TIOCGETC, &cmdtchars) < 0) return SCPE_TTIERR;\r | |
930 | if (ioctl (0, TIOCGLTC, &cmdltchars) < 0) return SCPE_TTIERR;\r | |
931 | runtty = cmdtty; /* initial run state */\r | |
932 | runtty.sg_flags = cmdtty.sg_flags & ~(ECHO|CRMOD) | CBREAK;\r | |
933 | runtchars.t_intrc = sim_int_char; /* interrupt */\r | |
934 | runtchars.t_quitc = 0xFF; /* no quit */\r | |
935 | runtchars.t_startc = 0xFF; /* no host sync */\r | |
936 | runtchars.t_stopc = 0xFF;\r | |
937 | runtchars.t_eofc = 0xFF;\r | |
938 | runtchars.t_brkc = 0xFF;\r | |
939 | runltchars.t_suspc = 0xFF; /* no specials of any kind */\r | |
940 | runltchars.t_dsuspc = 0xFF;\r | |
941 | runltchars.t_rprntc = 0xFF;\r | |
942 | runltchars.t_flushc = 0xFF;\r | |
943 | runltchars.t_werasc = 0xFF;\r | |
944 | runltchars.t_lnextc = 0xFF;\r | |
945 | return SCPE_OK; /* return success */\r | |
946 | }\r | |
947 | \r | |
948 | t_stat sim_ttrun (void)\r | |
949 | {\r | |
950 | runtchars.t_intrc = sim_int_char; /* in case changed */\r | |
951 | fcntl (0, F_SETFL, runfl); /* non-block mode */\r | |
952 | if (ioctl (0, TIOCSETP, &runtty) < 0) return SCPE_TTIERR;\r | |
953 | if (ioctl (0, TIOCSETC, &runtchars) < 0) return SCPE_TTIERR;\r | |
954 | if (ioctl (0, TIOCSLTC, &runltchars) < 0) return SCPE_TTIERR;\r | |
955 | nice (10); /* lower priority */\r | |
956 | return SCPE_OK;\r | |
957 | }\r | |
958 | \r | |
959 | t_stat sim_ttcmd (void)\r | |
960 | {\r | |
961 | nice (-10); /* restore priority */\r | |
962 | fcntl (0, F_SETFL, cmdfl); /* block mode */\r | |
963 | if (ioctl (0, TIOCSETP, &cmdtty) < 0) return SCPE_TTIERR;\r | |
964 | if (ioctl (0, TIOCSETC, &cmdtchars) < 0) return SCPE_TTIERR;\r | |
965 | if (ioctl (0, TIOCSLTC, &cmdltchars) < 0) return SCPE_TTIERR;\r | |
966 | return SCPE_OK;\r | |
967 | }\r | |
968 | \r | |
969 | t_stat sim_ttclose (void)\r | |
970 | {\r | |
971 | return sim_ttcmd ();\r | |
972 | }\r | |
973 | \r | |
974 | t_stat sim_os_poll_kbd (void)\r | |
975 | {\r | |
976 | int status;\r | |
977 | unsigned char buf[1];\r | |
978 | \r | |
979 | status = read (0, buf, 1);\r | |
980 | if (status != 1) return SCPE_OK;\r | |
981 | if (sim_brk_char && (buf[0] == sim_brk_char)) return SCPE_BREAK;\r | |
982 | else return (buf[0] | SCPE_KFLAG);\r | |
983 | }\r | |
984 | \r | |
985 | t_stat sim_os_putchar (int32 out)\r | |
986 | {\r | |
987 | char c;\r | |
988 | \r | |
989 | c = out;\r | |
990 | write (1, &c, 1);\r | |
991 | return SCPE_OK;\r | |
992 | }\r | |
993 | \r | |
994 | /* POSIX UNIX routines, from Leendert Van Doorn */\r | |
995 | \r | |
996 | #else\r | |
997 | \r | |
998 | #include <termios.h>\r | |
999 | #include <unistd.h>\r | |
1000 | \r | |
1001 | struct termios cmdtty, runtty;\r | |
1002 | static int prior_norm = 1;\r | |
1003 | \r | |
1004 | t_stat sim_ttinit (void)\r | |
1005 | {\r | |
1006 | if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */\r | |
1007 | if (tcgetattr (0, &cmdtty) < 0) return SCPE_TTIERR; /* get old flags */\r | |
1008 | runtty = cmdtty;\r | |
1009 | runtty.c_lflag = runtty.c_lflag & ~(ECHO | ICANON); /* no echo or edit */\r | |
1010 | runtty.c_oflag = runtty.c_oflag & ~OPOST; /* no output edit */\r | |
1011 | runtty.c_iflag = runtty.c_iflag & ~ICRNL; /* no cr conversion */\r | |
1012 | runtty.c_cc[VINTR] = sim_int_char; /* interrupt */\r | |
1013 | runtty.c_cc[VQUIT] = 0; /* no quit */\r | |
1014 | runtty.c_cc[VERASE] = 0;\r | |
1015 | runtty.c_cc[VKILL] = 0;\r | |
1016 | runtty.c_cc[VEOF] = 0;\r | |
1017 | runtty.c_cc[VEOL] = 0;\r | |
1018 | runtty.c_cc[VSTART] = 0; /* no host sync */\r | |
1019 | runtty.c_cc[VSUSP] = 0;\r | |
1020 | runtty.c_cc[VSTOP] = 0;\r | |
1021 | #if defined (VREPRINT)\r | |
1022 | runtty.c_cc[VREPRINT] = 0; /* no specials */\r | |
1023 | #endif\r | |
1024 | #if defined (VDISCARD)\r | |
1025 | runtty.c_cc[VDISCARD] = 0;\r | |
1026 | #endif\r | |
1027 | #if defined (VWERASE)\r | |
1028 | runtty.c_cc[VWERASE] = 0;\r | |
1029 | #endif\r | |
1030 | #if defined (VLNEXT)\r | |
1031 | runtty.c_cc[VLNEXT] = 0;\r | |
1032 | #endif\r | |
1033 | runtty.c_cc[VMIN] = 0; /* no waiting */\r | |
1034 | runtty.c_cc[VTIME] = 0;\r | |
1035 | #if defined (VDSUSP)\r | |
1036 | runtty.c_cc[VDSUSP] = 0;\r | |
1037 | #endif\r | |
1038 | #if defined (VSTATUS)\r | |
1039 | runtty.c_cc[VSTATUS] = 0;\r | |
1040 | #endif\r | |
1041 | return SCPE_OK;\r | |
1042 | }\r | |
1043 | \r | |
1044 | t_stat sim_ttrun (void)\r | |
1045 | {\r | |
1046 | if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */\r | |
1047 | runtty.c_cc[VINTR] = sim_int_char; /* in case changed */\r | |
1048 | if (tcsetattr (0, TCSAFLUSH, &runtty) < 0) return SCPE_TTIERR;\r | |
1049 | if (prior_norm) { /* at normal pri? */\r | |
1050 | errno = 0;\r | |
1051 | nice (10); /* try to lower pri */\r | |
1052 | prior_norm = errno; /* if no error, done */\r | |
1053 | }\r | |
1054 | return SCPE_OK;\r | |
1055 | }\r | |
1056 | \r | |
1057 | t_stat sim_ttcmd (void)\r | |
1058 | {\r | |
1059 | if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */\r | |
1060 | if (!prior_norm) { /* priority down? */\r | |
1061 | errno = 0;\r | |
1062 | nice (-10); /* try to raise pri */\r | |
1063 | prior_norm = (errno == 0); /* if no error, done */\r | |
1064 | }\r | |
1065 | if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0) return SCPE_TTIERR;\r | |
1066 | return SCPE_OK;\r | |
1067 | }\r | |
1068 | \r | |
1069 | t_stat sim_ttclose (void)\r | |
1070 | {\r | |
1071 | return sim_ttcmd ();\r | |
1072 | }\r | |
1073 | \r | |
1074 | t_stat sim_os_poll_kbd (void)\r | |
1075 | {\r | |
1076 | int status;\r | |
1077 | unsigned char buf[1];\r | |
1078 | \r | |
1079 | status = read (0, buf, 1);\r | |
1080 | if (status != 1) return SCPE_OK;\r | |
1081 | if (sim_brk_char && (buf[0] == sim_brk_char)) return SCPE_BREAK;\r | |
1082 | else return (buf[0] | SCPE_KFLAG);\r | |
1083 | }\r | |
1084 | \r | |
1085 | t_stat sim_os_putchar (int32 out)\r | |
1086 | {\r | |
1087 | char c;\r | |
1088 | \r | |
1089 | c = out;\r | |
1090 | write (1, &c, 1);\r | |
1091 | return SCPE_OK;\r | |
1092 | }\r | |
1093 | \r | |
1094 | #endif\r |