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