1 /* sim_console.c: simulator console I/O library
3 Copyright (c) 1993-2006, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 30-Sep-06 RMS Fixed non-printable characters in KSR mode
27 22-Jun-06 RMS Implemented SET/SHOW PCHAR
28 31-May-06 JDB Fixed bug if SET CONSOLE DEBUG with no argument
29 22-Nov-05 RMS Added central input/output conversion support
30 05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy
31 28-Oct-04 JDB Fixed SET CONSOLE to allow comma-separated parameters
32 20-Aug-04 RMS Added OS/2 EMX fixes (from Holger Veit)
33 14-Jul-04 RMS Revised Windows console code (from Dave Bryan)
34 28-May-04 RMS Added SET/SHOW CONSOLE
35 RMS Added break, delete character maps
36 02-Jan-04 RMS Removed timer routines, added Telnet console routines
37 RMS Moved console logging to OS-independent code
38 25-Apr-03 RMS Added long seek support from Mark Pizzolato
39 Added Unix priority control from Mark Pizzolato
40 24-Sep-02 RMS Removed VT support, added Telnet console support
41 Added CGI support (from Brian Knittel)
42 Added MacOS sleep (from Peter Schorn)
43 14-Jul-02 RMS Added Windows priority control from Mark Pizzolato
44 20-May-02 RMS Added Windows VT support from Fischer Franz
45 01-Feb-02 RMS Added VAX fix from Robert Alan Byer
46 19-Sep-01 RMS More Mac changes
47 31-Aug-01 RMS Changed int64 to t_int64 for Windoze
48 20-Jul-01 RMS Added Macintosh support (from Louis Chretien, Peter Schorn,
50 15-May-01 RMS Added logging support
51 05-Mar-01 RMS Added clock calibration support
52 08-Dec-00 BKR Added OS/2 support (from Bruce Ray)
53 18-Aug-98 RMS Added BeOS support
54 13-Oct-97 RMS Added NetBSD terminal support
55 25-Jan-97 RMS Added POSIX terminal I/O support
56 02-Jan-97 RMS Fixed bug in sim_poll_kbd
58 This module implements the following routines to support terminal I/O:
60 sim_poll_kbd - poll for keyboard input
61 sim_putchar - output character to console
62 sim_putchar_s - output character to console, stall if congested
63 sim_set_console - set console parameters
64 sim_show_console - show console parameters
65 sim_tt_inpcvt - convert input character per mode
66 sim_tt_outcvt - convert output character per mode
68 sim_ttinit - called once to get initial terminal state
69 sim_ttrun - called to put terminal into run state
70 sim_ttcmd - called to return terminal to command state
71 sim_ttclose - called once before the simulator exits
72 sim_os_poll_kbd - poll for keyboard input
73 sim_os_putchar - output character to console
75 The first group is OS-independent; the second group is OS-dependent.
77 The following routines are exposed but deprecated:
79 sim_set_telnet - set console to Telnet port
80 sim_set_notelnet - close console Telnet port
81 sim_show_telnet - show console status
92 #define KMAP_MASK 0377
95 int32 sim_int_char
= 005; /* interrupt character */
96 int32 sim_brk_char
= 000; /* break character */
97 int32 sim_tt_pchar
= 0x00002780;
98 #if defined (_WIN32) || defined (__OS2__) || (defined (__MWERKS__) && defined (macintosh))
99 int32 sim_del_char
= '\b'; /* delete character */
101 int32 sim_del_char
= 0177;
103 TMLN sim_con_ldsc
= { 0 }; /* console line descr */
104 TMXR sim_con_tmxr
= { 1, 0, 0, &sim_con_ldsc
}; /* console line mux */
106 extern volatile int32 stop_cpu
;
107 extern int32 sim_quiet
, sim_deb_close
;
108 extern FILE *sim_log
, *sim_deb
;
109 extern DEVICE
*sim_devices
[];
111 /* Set/show data structures */
113 static CTAB set_con_tab
[] = {
114 { "WRU", &sim_set_kmap
, KMAP_WRU
| KMAP_NZ
},
115 { "BRK", &sim_set_kmap
, KMAP_BRK
},
116 { "DEL", &sim_set_kmap
, KMAP_DEL
|KMAP_NZ
},
117 { "PCHAR", &sim_set_pchar
, 0 },
118 { "TELNET", &sim_set_telnet
, 0 },
119 { "NOTELNET", &sim_set_notelnet
, 0 },
120 { "LOG", &sim_set_logon
, 0 },
121 { "NOLOG", &sim_set_logoff
, 0 },
122 { "DEBUG", &sim_set_debon
, 0 },
123 { "NODEBUG", &sim_set_deboff
, 0 },
127 static SHTAB show_con_tab
[] = {
128 { "WRU", &sim_show_kmap
, KMAP_WRU
},
129 { "BRK", &sim_show_kmap
, KMAP_BRK
},
130 { "DEL", &sim_show_kmap
, KMAP_DEL
},
131 { "PCHAR", &sim_show_pchar
, 0 },
132 { "LOG", &sim_show_log
, 0 },
133 { "TELNET", &sim_show_telnet
, 0 },
134 { "DEBUG", &sim_show_debug
, 0 },
138 static int32
*cons_kmap
[] = {
144 /* Console I/O package.
146 The console terminal can be attached to the controlling window
147 or to a Telnet connection. If attached to a Telnet connection,
148 the console is described by internal terminal multiplexor
149 sim_con_tmxr and internal terminal line description sim_con_ldsc.
152 /* SET CONSOLE command */
154 t_stat
sim_set_console (int32 flag
, char *cptr
)
156 char *cvptr
, gbuf
[CBUFSIZE
];
160 if ((cptr
== NULL
) || (*cptr
== 0)) return SCPE_2FARG
;
161 while (*cptr
!= 0) { /* do all mods */
162 cptr
= get_glyph_nc (cptr
, gbuf
, ','); /* get modifier */
163 if (cvptr
= strchr (gbuf
, '=')) *cvptr
++ = 0; /* = value? */
164 get_glyph (gbuf
, gbuf
, 0); /* modifier to UC */
165 if (ctptr
= find_ctab (set_con_tab
, gbuf
)) { /* match? */
166 r
= ctptr
->action (ctptr
->arg
, cvptr
); /* do the rest */
167 if (r
!= SCPE_OK
) return r
;
169 else return SCPE_NOPARAM
;
174 /* SHOW CONSOLE command */
176 t_stat
sim_show_console (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
182 if (*cptr
== 0) { /* show all */
183 for (i
= 0; show_con_tab
[i
].name
; i
++)
184 show_con_tab
[i
].action (st
, dptr
, uptr
, show_con_tab
[i
].arg
, cptr
);
188 cptr
= get_glyph (cptr
, gbuf
, ','); /* get modifier */
189 if (shptr
= find_shtab (show_con_tab
, gbuf
))
190 shptr
->action (st
, dptr
, uptr
, shptr
->arg
, cptr
);
191 else return SCPE_NOPARAM
;
196 /* Set keyboard map */
198 t_stat
sim_set_kmap (int32 flag
, char *cptr
)
200 DEVICE
*dptr
= sim_devices
[0];
204 if ((cptr
== NULL
) || (*cptr
== 0)) return SCPE_2FARG
;
205 if (dptr
->dradix
== 16) rdx
= 16;
207 val
= (int32
) get_uint (cptr
, rdx
, 0177, &r
);
208 if ((r
!= SCPE_OK
) ||
209 ((val
== 0) && (flag
& KMAP_NZ
))) return SCPE_ARG
;
210 *(cons_kmap
[flag
& KMAP_MASK
]) = val
;
214 /* Show keyboard map */
216 t_stat
sim_show_kmap (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
218 if (sim_devices
[0]->dradix
== 16)
219 fprintf (st
, "%s = %X\n", show_con_tab
[flag
].name
, *(cons_kmap
[flag
& KMAP_MASK
]));
220 else fprintf (st
, "%s = %o\n", show_con_tab
[flag
].name
, *(cons_kmap
[flag
& KMAP_MASK
]));
224 /* Set printable characters */
226 t_stat
sim_set_pchar (int32 flag
, char *cptr
)
228 DEVICE
*dptr
= sim_devices
[0];
232 if ((cptr
== NULL
) || (*cptr
== 0)) return SCPE_2FARG
;
233 if (dptr
->dradix
== 16) rdx
= 16;
235 val
= (uint32
) get_uint (cptr
, rdx
, 0xFFFFFFFF, &r
);
236 if ((r
!= SCPE_OK
) ||
237 ((val
& 0x00002400) == 0)) return SCPE_ARG
;
242 /* Show printable characters */
244 t_stat
sim_show_pchar (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
246 if (sim_devices
[0]->dradix
== 16)
247 fprintf (st
, "pchar mask = %X\n", sim_tt_pchar
);
248 else fprintf (st
, "pchar mask = %o\n", sim_tt_pchar
);
252 /* Set log routine */
254 t_stat
sim_set_logon (int32 flag
, char *cptr
)
258 if ((cptr
== NULL
) || (*cptr
== 0)) return SCPE_2FARG
; /* need arg */
259 cptr
= get_glyph_nc (cptr
, gbuf
, 0); /* get file name */
260 if (*cptr
!= 0) return SCPE_2MARG
; /* now eol? */
261 sim_set_logoff (0, NULL
); /* close cur log */
262 sim_log
= sim_fopen (gbuf
, "a"); /* open log */
263 if (sim_log
== NULL
) return SCPE_OPENERR
; /* error? */
264 if (!sim_quiet
) printf ("Logging to file \"%s\"\n", gbuf
);
265 fprintf (sim_log
, "Logging to file \"%s\"\n", gbuf
); /* start of log */
269 /* Set nolog routine */
271 t_stat
sim_set_logoff (int32 flag
, char *cptr
)
273 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
; /* now eol? */
274 if (sim_log
== NULL
) return SCPE_OK
; /* no log? */
275 if (!sim_quiet
) printf ("Log file closed\n");
276 fprintf (sim_log
, "Log file closed\n"); /* close log */
282 /* Show log status */
284 t_stat
sim_show_log (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
286 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
;
287 if (sim_log
) fputs ("Logging enabled\n", st
);
288 else fputs ("Logging disabled\n", st
);
292 /* Set debug routine */
294 t_stat
sim_set_debon (int32 flag
, char *cptr
)
296 char *tptr
, gbuf
[CBUFSIZE
];
298 if ((cptr
== NULL
) || (*cptr
== 0)) return SCPE_2FARG
; /* too few arguments? */
299 tptr
= get_glyph (cptr
, gbuf
, 0); /* get file name */
300 if (*tptr
!= 0) return SCPE_2MARG
; /* now eol? */
301 sim_set_deboff (0, NULL
); /* close cur debug */
302 if (strcmp (gbuf
, "LOG") == 0) { /* debug to log? */
303 if (sim_log
== NULL
) return SCPE_ARG
; /* any log? */
306 else if (strcmp (gbuf
, "STDOUT") == 0) sim_deb
= stdout
; /* debug to stdout? */
307 else if (strcmp (gbuf
, "STDERR") == 0) sim_deb
= stderr
; /* debug to stderr? */
309 cptr
= get_glyph_nc (cptr
, gbuf
, 0); /* reparse */
310 sim_deb
= sim_fopen (gbuf
, "a"); /* open debug */
311 if (sim_deb
== NULL
) return SCPE_OPENERR
; /* error? */
312 sim_deb_close
= 1; /* need close */
314 if (!sim_quiet
) printf ("Debug output to \"%s\"\n", gbuf
);
315 if (sim_log
) fprintf (sim_log
, "Debug output to \"%s\"\n", gbuf
);
319 /* Set nodebug routine */
321 t_stat
sim_set_deboff (int32 flag
, char *cptr
)
323 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
; /* now eol? */
324 if (sim_deb
== NULL
) return SCPE_OK
; /* no log? */
325 if (!sim_quiet
) printf ("Debug output disabled\n");
326 if (sim_log
) fprintf (sim_log
, "Debug output disabled\n");
327 if (sim_deb_close
) fclose (sim_deb
); /* close if needed */
333 /* Show debug routine */
335 t_stat
sim_show_debug (FILE *st
, DEVICE
*dptr
, UNIT
*uptr
, int32 flag
, char *cptr
)
337 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
;
338 if (sim_deb
) fputs ("Debug output enabled\n", st
);
339 else fputs ("Debug output disabled\n", st
);
343 /* Set console to Telnet port */
345 t_stat
sim_set_telnet (int32 flg
, char *cptr
)
347 if ((cptr
== NULL
) || (*cptr
== 0)) return SCPE_2FARG
; /* too few arguments? */
348 if (sim_con_tmxr
.master
) return SCPE_ALATT
; /* already open? */
349 return tmxr_open_master (&sim_con_tmxr
, cptr
); /* open master socket */
352 /* Close console Telnet port */
354 t_stat
sim_set_notelnet (int32 flag
, char *cptr
)
356 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
; /* too many arguments? */
357 if (sim_con_tmxr
.master
== 0) return SCPE_OK
; /* ignore if already closed */
358 return tmxr_close_master (&sim_con_tmxr
); /* close master socket */
361 /* Show console Telnet status */
363 t_stat
sim_show_telnet (FILE *st
, DEVICE
*dunused
, UNIT
*uunused
, int32 flag
, char *cptr
)
365 if (cptr
&& (*cptr
!= 0)) return SCPE_2MARG
;
366 if (sim_con_tmxr
.master
== 0)
367 fprintf (st
, "Connected to console window\n");
368 else if (sim_con_ldsc
.conn
== 0)
369 fprintf (st
, "Listening on port %d\n", sim_con_tmxr
.port
);
371 fprintf (st
, "Listening on port %d, connected to socket %d\n",
372 sim_con_tmxr
.port
, sim_con_ldsc
.conn
);
373 tmxr_fconns (st
, &sim_con_ldsc
, -1);
374 tmxr_fstats (st
, &sim_con_ldsc
, -1);
379 /* Check connection before executing */
381 t_stat
sim_check_console (int32 sec
)
385 if (sim_con_tmxr
.master
== 0) return SCPE_OK
; /* not Telnet? done */
386 if (sim_con_ldsc
.conn
) { /* connected? */
387 tmxr_poll_rx (&sim_con_tmxr
); /* poll (check disconn) */
388 if (sim_con_ldsc
.conn
) return SCPE_OK
; /* still connected? */
390 for (i
= 0; i
< sec
; i
++) { /* loop */
391 if (tmxr_poll_conn (&sim_con_tmxr
) >= 0) { /* poll connect */
392 sim_con_ldsc
.rcve
= 1; /* rcv enabled */
393 if (i
) { /* if delayed */
394 printf ("Running\n"); /* print transition */
397 return SCPE_OK
; /* ready to proceed */
399 c
= sim_os_poll_kbd (); /* check for stop char */
400 if ((c
== SCPE_STOP
) || stop_cpu
) return SCPE_STOP
;
401 if ((i
% 10) == 0) { /* Status every 10 sec */
402 printf ("Waiting for console Telnet connection\n");
405 sim_os_sleep (1); /* wait 1 second */
407 return SCPE_TTMO
; /* timed out */
410 /* Poll for character */
412 t_stat
sim_poll_kbd (void)
416 c
= sim_os_poll_kbd (); /* get character */
417 if ((c
== SCPE_STOP
) || (sim_con_tmxr
.master
== 0)) /* ^E or not Telnet? */
418 return c
; /* in-window */
419 if (sim_con_ldsc
.conn
== 0) return SCPE_LOST
; /* no Telnet conn? */
420 tmxr_poll_rx (&sim_con_tmxr
); /* poll for input */
421 if (c
= tmxr_getc_ln (&sim_con_ldsc
)) /* any char? */
422 return (c
& (SCPE_BREAK
| 0377)) | SCPE_KFLAG
;
426 /* Output character */
428 t_stat
sim_putchar (int32 c
)
430 if (sim_log
) fputc (c
, sim_log
); /* log file? */
431 if (sim_con_tmxr
.master
== 0) /* not Telnet? */
432 return sim_os_putchar (c
); /* in-window version */
433 if (sim_con_ldsc
.conn
== 0) return SCPE_LOST
; /* no Telnet conn? */
434 tmxr_putc_ln (&sim_con_ldsc
, c
); /* output char */
435 tmxr_poll_tx (&sim_con_tmxr
); /* poll xmt */
439 t_stat
sim_putchar_s (int32 c
)
443 if (sim_log
) fputc (c
, sim_log
); /* log file? */
444 if (sim_con_tmxr
.master
== 0) /* not Telnet? */
445 return sim_os_putchar (c
); /* in-window version */
446 if (sim_con_ldsc
.conn
== 0) return SCPE_LOST
; /* no Telnet conn? */
447 if (sim_con_ldsc
.xmte
== 0) r
= SCPE_STALL
; /* xmt disabled? */
448 else r
= tmxr_putc_ln (&sim_con_ldsc
, c
); /* no, Telnet output */
449 tmxr_poll_tx (&sim_con_tmxr
); /* poll xmt */
450 return r
; /* return status */
453 /* Input character processing */
455 int32
sim_tt_inpcvt (int32 c
, uint32 mode
)
457 uint32 md
= mode
& TTUF_M_MODE
;
459 if (md
!= TTUF_MODE_8B
) {
461 if (md
== TTUF_MODE_UC
) {
462 if (islower (c
)) c
= toupper (c
);
463 if (mode
& TTUF_KSR
) c
= c
| 0200;
470 /* Output character processing */
472 int32
sim_tt_outcvt (int32 c
, uint32 mode
)
474 uint32 md
= mode
& TTUF_M_MODE
;
476 if (md
!= TTUF_MODE_8B
) {
478 if (md
== TTUF_MODE_UC
) {
479 if (islower (c
)) c
= toupper (c
);
480 if ((mode
& TTUF_KSR
) && (c
>= 0140))
483 if (((md
== TTUF_MODE_UC
) || (md
== TTUF_MODE_7P
)) &&
485 ((c
< 040) && !((sim_tt_pchar
>> c
) & 1))))
492 /* VMS routines, from Ben Thomas, with fixes from Robert Alan Byer */
497 #define sys$assign SYS$ASSIGN
498 #define sys$qiow SYS$QIOW
513 unsigned short sense_count
;
514 unsigned char sense_first_char
;
515 unsigned char sense_reserved
;
517 unsigned int stat2
; } SENSE_BUF
;
520 unsigned short status
;
521 unsigned short count
;
522 unsigned int dev_status
; } IOSB
;
524 SENSE_BUF cmd_mode
= { 0 };
525 SENSE_BUF run_mode
= { 0 };
527 t_stat
sim_ttinit (void)
531 $
DESCRIPTOR (terminal_device
, "tt");
533 status
= sys$
assign (&terminal_device
, &tty_chan
, 0, 0);
534 if (status
!= SS$_NORMAL
) return SCPE_TTIERR
;
535 status
= sys$
qiow (EFN
, tty_chan
, IO$_SENSEMODE
, &iosb
, 0, 0,
536 &cmd_mode
, sizeof (cmd_mode
), 0, 0, 0, 0);
537 if ((status
!= SS$_NORMAL
) || (iosb
.status
!= SS$_NORMAL
)) return SCPE_TTIERR
;
539 run_mode
.stat
= cmd_mode
.stat
| TT$M_NOECHO
& ~(TT$M_HOSTSYNC
| TT$M_TTSYNC
);
540 run_mode
.stat2
= cmd_mode
.stat2
| TT2$M_PASTHRU
;
544 t_stat
sim_ttrun (void)
549 status
= sys$
qiow (EFN
, tty_chan
, IO$_SETMODE
, &iosb
, 0, 0,
550 &run_mode
, sizeof (run_mode
), 0, 0, 0, 0);
551 if ((status
!= SS$_NORMAL
) || (iosb
.status
!= SS$_NORMAL
)) return SCPE_TTIERR
;
555 t_stat
sim_ttcmd (void)
560 status
= sys$
qiow (EFN
, tty_chan
, IO$_SETMODE
, &iosb
, 0, 0,
561 &cmd_mode
, sizeof (cmd_mode
), 0, 0, 0, 0);
562 if ((status
!= SS$_NORMAL
) || (iosb
.status
!= SS$_NORMAL
)) return SCPE_TTIERR
;
566 t_stat
sim_ttclose (void)
571 t_stat
sim_os_poll_kbd (void)
573 unsigned int status
, term
[2];
574 unsigned char buf
[4];
578 term
[0] = 0; term
[1] = 0;
579 status
= sys$
qiow (EFN
, tty_chan
, IO$_SENSEMODE
| IO$M_TYPEAHDCNT
, &iosb
,
580 0, 0, &sense
, 8, 0, term
, 0, 0);
581 if ((status
!= SS$_NORMAL
) || (iosb
.status
!= SS$_NORMAL
)) return SCPE_TTIERR
;
582 if (sense
.sense_count
== 0) return SCPE_OK
;
583 term
[0] = 0; term
[1] = 0;
584 status
= sys$
qiow (EFN
, tty_chan
,
585 IO$_READLBLK
| IO$M_NOECHO
| IO$M_NOFILTR
| IO$M_TIMED
| IO$M_TRMNOECHO
,
586 &iosb
, 0, 0, buf
, 1, 0, term
, 0, 0);
587 if ((status
!= SS$_NORMAL
) || (iosb
.status
!= SS$_NORMAL
)) return SCPE_OK
;
588 if (buf
[0] == sim_int_char
) return SCPE_STOP
;
589 if (sim_brk_char
&& (buf
[0] == sim_brk_char
)) return SCPE_BREAK
;
590 return (buf
[0] | SCPE_KFLAG
);
593 t_stat
sim_os_putchar (int32 out
)
600 status
= sys$
qiow (EFN
, tty_chan
, IO$_WRITELBLK
| IO$M_NOFORMAT
,
601 &iosb
, 0, 0, &c
, 1, 0, 0, 0, 0);
602 if ((status
!= SS$_NORMAL
) || (iosb
.status
!= SS$_NORMAL
)) return SCPE_TTOERR
;
608 #elif defined (_WIN32)
615 static HANDLE std_input
;
616 static DWORD saved_mode
;
618 t_stat
sim_ttinit (void)
620 std_input
= GetStdHandle (STD_INPUT_HANDLE
);
621 if ((std_input
== INVALID_HANDLE_VALUE
) ||
622 !GetConsoleMode (std_input
, &saved_mode
)) return SCPE_TTYERR
;
626 t_stat
sim_ttrun (void)
628 if (!GetConsoleMode(std_input
, &saved_mode
) ||
629 !SetConsoleMode(std_input
, RAW_MODE
)) return SCPE_TTYERR
;
632 _setmode (_fileno (sim_log
), _O_BINARY
);
634 SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL
);
638 t_stat
sim_ttcmd (void)
642 _setmode (_fileno (sim_log
), _O_TEXT
);
644 SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL
);
645 if (!SetConsoleMode(std_input
, saved_mode
)) return SCPE_TTYERR
;
649 t_stat
sim_ttclose (void)
654 t_stat
sim_os_poll_kbd (void)
658 if (!_kbhit ()) return SCPE_OK
;
660 if ((c
& 0177) == sim_del_char
) c
= 0177;
661 if ((c
& 0177) == sim_int_char
) return SCPE_STOP
;
662 if (sim_brk_char
&& ((c
& 0177) == sim_brk_char
)) return SCPE_BREAK
;
663 return c
| SCPE_KFLAG
;
666 t_stat
sim_os_putchar (int32 c
)
668 if (c
!= 0177) _putch (c
);
672 /* OS/2 routines, from Bruce Ray and Holger Veit */
674 #elif defined (__OS2__)
678 t_stat
sim_ttinit (void)
683 t_stat
sim_ttrun (void)
688 t_stat
sim_ttcmd (void)
693 t_stat
sim_ttclose (void)
698 t_stat
sim_os_poll_kbd (void)
702 #if defined (__EMX__)
703 switch (c
= _read_kbd(0,0,0)) { /* EMX has _read_kbd */
705 case -1: /* no char*/
708 case 0: /* char pending */
709 c
= _read_kbd(0,1,0);
712 default: /* got char */
716 if (!kbhit ()) return SCPE_OK
;
719 if ((c
& 0177) == sim_del_char
) c
= 0177;
720 if ((c
& 0177) == sim_int_char
) return SCPE_STOP
;
721 if (sim_brk_char
&& ((c
& 0177) == sim_brk_char
)) return SCPE_BREAK
;
722 return c
| SCPE_KFLAG
;
725 t_stat
sim_os_putchar (int32 c
)
728 #if defined (__EMX__)
738 /* Metrowerks CodeWarrior Macintosh routines, from Louis Chretien and
741 #elif defined (__MWERKS__) && defined (macintosh)
744 #include <Mactypes.h>
748 #include <siouxglobals.h>
752 /* function prototypes */
754 Boolean
SIOUXIsAppWindow(WindowPtr window
);
755 void SIOUXDoMenuChoice(long menuValue
);
756 void SIOUXUpdateMenuItems(void);
757 void SIOUXUpdateScrollbar(void);
761 extern char sim_name
[];
762 extern pSIOUXWin SIOUXTextWindow
;
763 static CursHandle iBeamCursorH
= NULL
; /* contains the iBeamCursor */
765 static void updateCursor(void) {
767 window
= FrontWindow();
768 if (SIOUXIsAppWindow(window
)) {
773 #if TARGET_API_MAC_CARBON
774 GetGlobalMouse(&localMouse
);
776 localMouse
= LMGetMouseLocation();
778 GlobalToLocal(&localMouse
);
779 if (PtInRect(localMouse
, &(*SIOUXTextWindow
->edit
)->viewRect
) && iBeamCursorH
) {
780 SetCursor(*iBeamCursorH
);
783 SetCursor(&qd
.arrow
);
785 TEIdle(SIOUXTextWindow
->edit
);
789 SetCursor(&qd
.arrow
);
790 TEIdle(SIOUXTextWindow
->edit
);
799 SIOUXUpdateScrollbar();
800 while (GetNextEvent(updateMask
| osMask
| mDownMask
| mUpMask
| activMask
|
801 highLevelEventMask
| diskEvt
, &event
)) {
802 SIOUXHandleOneEvent(&event
);
807 if (EventAvail(keyDownMask
,&event
)) {
808 c
= event
.message
&charCodeMask
;
809 if ((event
.modifiers
& cmdKey
) && (c
> 0x20)) {
810 GetNextEvent(keyDownMask
, &event
);
811 SIOUXHandleOneEvent(&event
);
829 while(!GetNextEvent(keyDownMask
,&event
)) {
830 if (GetNextEvent(updateMask
| osMask
| mDownMask
| mUpMask
| activMask
|
831 highLevelEventMask
| diskEvt
, &event
)) {
832 SIOUXUpdateScrollbar();
833 SIOUXHandleOneEvent(&event
);
839 c
= event
.message
&charCodeMask
;
840 if ((event
.modifiers
& cmdKey
) && (c
> 0x20)) {
841 SIOUXUpdateMenuItems();
842 SIOUXDoMenuChoice(MenuKey(c
));
850 /* Note that this only works if the call to sim_ttinit comes before any output to the console */
852 t_stat
sim_ttinit (void) {
854 /* this blank will later be replaced by the number of characters */
855 char title
[50] = " ";
856 unsigned char ptitle
[50];
857 SIOUXSettings
.autocloseonquit
= TRUE
;
858 SIOUXSettings
.asktosaveonclose
= FALSE
;
859 SIOUXSettings
.showstatusline
= FALSE
;
860 SIOUXSettings
.columns
= 80;
861 SIOUXSettings
.rows
= 40;
862 SIOUXSettings
.toppixel
= 42;
863 SIOUXSettings
.leftpixel
= 6;
864 iBeamCursorH
= GetCursor(iBeamCursor
);
865 strcat(title
, sim_name
);
866 strcat(title
, " Simulator");
867 title
[0] = strlen(title
) - 1; /* Pascal string done */
868 for (i
= 0; i
<= title
[0]; i
++) { /* copy to unsigned char */
869 ptitle
[i
] = title
[i
];
871 SIOUXSetTitle(ptitle
);
875 t_stat
sim_ttrun (void)
880 t_stat
sim_ttcmd (void)
885 t_stat
sim_ttclose (void)
890 t_stat
sim_os_poll_kbd (void)
894 if (!ps_kbhit ()) return SCPE_OK
;
896 if ((c
& 0177) == sim_del_char
) c
= 0177;
897 if ((c
& 0177) == sim_int_char
) return SCPE_STOP
;
898 if (sim_brk_char
&& ((c
& 0177) == sim_brk_char
)) return SCPE_BREAK
;
899 return c
| SCPE_KFLAG
;
902 t_stat
sim_os_putchar (int32 c
)
911 /* BSD UNIX routines */
913 #elif defined (BSDTTY)
919 struct sgttyb cmdtty
,runtty
; /* V6/V7 stty data */
920 struct tchars cmdtchars
,runtchars
; /* V7 editing */
921 struct ltchars cmdltchars
,runltchars
; /* 4.2 BSD editing */
922 int cmdfl
,runfl
; /* TTY flags */
924 t_stat
sim_ttinit (void)
926 cmdfl
= fcntl (0, F_GETFL
, 0); /* get old flags and status */
927 runfl
= cmdfl
| FNDELAY
;
928 if (ioctl (0, TIOCGETP
, &cmdtty
) < 0) return SCPE_TTIERR
;
929 if (ioctl (0, TIOCGETC
, &cmdtchars
) < 0) return SCPE_TTIERR
;
930 if (ioctl (0, TIOCGLTC
, &cmdltchars
) < 0) return SCPE_TTIERR
;
931 runtty
= cmdtty
; /* initial run state */
932 runtty
.sg_flags
= cmdtty
.sg_flags
& ~(ECHO
|CRMOD
) | CBREAK
;
933 runtchars
.t_intrc
= sim_int_char
; /* interrupt */
934 runtchars
.t_quitc
= 0xFF; /* no quit */
935 runtchars
.t_startc
= 0xFF; /* no host sync */
936 runtchars
.t_stopc
= 0xFF;
937 runtchars
.t_eofc
= 0xFF;
938 runtchars
.t_brkc
= 0xFF;
939 runltchars
.t_suspc
= 0xFF; /* no specials of any kind */
940 runltchars
.t_dsuspc
= 0xFF;
941 runltchars
.t_rprntc
= 0xFF;
942 runltchars
.t_flushc
= 0xFF;
943 runltchars
.t_werasc
= 0xFF;
944 runltchars
.t_lnextc
= 0xFF;
945 return SCPE_OK
; /* return success */
948 t_stat
sim_ttrun (void)
950 runtchars
.t_intrc
= sim_int_char
; /* in case changed */
951 fcntl (0, F_SETFL
, runfl
); /* non-block mode */
952 if (ioctl (0, TIOCSETP
, &runtty
) < 0) return SCPE_TTIERR
;
953 if (ioctl (0, TIOCSETC
, &runtchars
) < 0) return SCPE_TTIERR
;
954 if (ioctl (0, TIOCSLTC
, &runltchars
) < 0) return SCPE_TTIERR
;
955 nice (10); /* lower priority */
959 t_stat
sim_ttcmd (void)
961 nice (-10); /* restore priority */
962 fcntl (0, F_SETFL
, cmdfl
); /* block mode */
963 if (ioctl (0, TIOCSETP
, &cmdtty
) < 0) return SCPE_TTIERR
;
964 if (ioctl (0, TIOCSETC
, &cmdtchars
) < 0) return SCPE_TTIERR
;
965 if (ioctl (0, TIOCSLTC
, &cmdltchars
) < 0) return SCPE_TTIERR
;
969 t_stat
sim_ttclose (void)
974 t_stat
sim_os_poll_kbd (void)
977 unsigned char buf
[1];
979 status
= read (0, buf
, 1);
980 if (status
!= 1) return SCPE_OK
;
981 if (sim_brk_char
&& (buf
[0] == sim_brk_char
)) return SCPE_BREAK
;
982 else return (buf
[0] | SCPE_KFLAG
);
985 t_stat
sim_os_putchar (int32 out
)
994 /* POSIX UNIX routines, from Leendert Van Doorn */
1001 struct termios cmdtty
, runtty
;
1002 static int prior_norm
= 1;
1004 t_stat
sim_ttinit (void)
1006 if (!isatty (fileno (stdin
))) return SCPE_OK
; /* skip if !tty */
1007 if (tcgetattr (0, &cmdtty
) < 0) return SCPE_TTIERR
; /* get old flags */
1009 runtty
.c_lflag
= runtty
.c_lflag
& ~(ECHO
| ICANON
); /* no echo or edit */
1010 runtty
.c_oflag
= runtty
.c_oflag
& ~OPOST
; /* no output edit */
1011 runtty
.c_iflag
= runtty
.c_iflag
& ~ICRNL
; /* no cr conversion */
1012 runtty
.c_cc
[VINTR
] = sim_int_char
; /* interrupt */
1013 runtty
.c_cc
[VQUIT
] = 0; /* no quit */
1014 runtty
.c_cc
[VERASE
] = 0;
1015 runtty
.c_cc
[VKILL
] = 0;
1016 runtty
.c_cc
[VEOF
] = 0;
1017 runtty
.c_cc
[VEOL
] = 0;
1018 runtty
.c_cc
[VSTART
] = 0; /* no host sync */
1019 runtty
.c_cc
[VSUSP
] = 0;
1020 runtty
.c_cc
[VSTOP
] = 0;
1021 #if defined (VREPRINT)
1022 runtty
.c_cc
[VREPRINT
] = 0; /* no specials */
1024 #if defined (VDISCARD)
1025 runtty
.c_cc
[VDISCARD
] = 0;
1027 #if defined (VWERASE)
1028 runtty
.c_cc
[VWERASE
] = 0;
1030 #if defined (VLNEXT)
1031 runtty
.c_cc
[VLNEXT
] = 0;
1033 runtty
.c_cc
[VMIN
] = 0; /* no waiting */
1034 runtty
.c_cc
[VTIME
] = 0;
1035 #if defined (VDSUSP)
1036 runtty
.c_cc
[VDSUSP
] = 0;
1038 #if defined (VSTATUS)
1039 runtty
.c_cc
[VSTATUS
] = 0;
1044 t_stat
sim_ttrun (void)
1046 if (!isatty (fileno (stdin
))) return SCPE_OK
; /* skip if !tty */
1047 runtty
.c_cc
[VINTR
] = sim_int_char
; /* in case changed */
1048 if (tcsetattr (0, TCSAFLUSH
, &runtty
) < 0) return SCPE_TTIERR
;
1049 if (prior_norm
) { /* at normal pri? */
1051 nice (10); /* try to lower pri */
1052 prior_norm
= errno
; /* if no error, done */
1057 t_stat
sim_ttcmd (void)
1059 if (!isatty (fileno (stdin
))) return SCPE_OK
; /* skip if !tty */
1060 if (!prior_norm
) { /* priority down? */
1062 nice (-10); /* try to raise pri */
1063 prior_norm
= (errno
== 0); /* if no error, done */
1065 if (tcsetattr (0, TCSAFLUSH
, &cmdtty
) < 0) return SCPE_TTIERR
;
1069 t_stat
sim_ttclose (void)
1071 return sim_ttcmd ();
1074 t_stat
sim_os_poll_kbd (void)
1077 unsigned char buf
[1];
1079 status
= read (0, buf
, 1);
1080 if (status
!= 1) return SCPE_OK
;
1081 if (sim_brk_char
&& (buf
[0] == sim_brk_char
)) return SCPE_BREAK
;
1082 else return (buf
[0] | SCPE_KFLAG
);
1085 t_stat
sim_os_putchar (int32 out
)