Merge branch 'BufferedConsole' into simhv3.8-2.rc2
Conflicts: scp.c sim_console.c sim_tmxr.c
This commit is contained in:
commit
87157dc737
6 changed files with 483 additions and 124 deletions
4
scp.c
4
scp.c
|
@ -395,10 +395,10 @@ static uint32 sim_rtime;
|
||||||
static int32 noqueue_time;
|
static int32 noqueue_time;
|
||||||
volatile int32 stop_cpu = 0;
|
volatile int32 stop_cpu = 0;
|
||||||
t_value *sim_eval = NULL;
|
t_value *sim_eval = NULL;
|
||||||
int32 sim_deb_close = 0; /* 1 = close debug */
|
|
||||||
FILE *sim_log = NULL; /* log file */
|
FILE *sim_log = NULL; /* log file */
|
||||||
|
FILEREF *sim_log_ref = NULL; /* log file file reference */
|
||||||
FILE *sim_deb = NULL; /* debug file */
|
FILE *sim_deb = NULL; /* debug file */
|
||||||
|
FILEREF *sim_deb_ref = NULL; /* debug file file reference */
|
||||||
static FILE *sim_gotofile;
|
static FILE *sim_gotofile;
|
||||||
static int32 sim_do_depth = 0;
|
static int32 sim_do_depth = 0;
|
||||||
|
|
||||||
|
|
337
sim_console.c
337
sim_console.c
|
@ -23,7 +23,27 @@
|
||||||
used in advertising or otherwise to promote the sale, use or other dealings
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
in this Software without prior written authorization from Robert M Supnik.
|
in this Software without prior written authorization from Robert M Supnik.
|
||||||
|
|
||||||
20-Jan-11 MP Added support for BREAK key on Windows
|
20-Jan-11 MP Fixed support for BREAK key on Windows to account
|
||||||
|
for/ignore other keyboard Meta characters.
|
||||||
|
18-Jan-11 MP Added log file reference count support
|
||||||
|
17-Jan-11 MP Added support for a "Buffered" behaviors which include:
|
||||||
|
- If Buffering is enabled and Telnet is enabled, a
|
||||||
|
telnet connection is not required for simulator
|
||||||
|
operation (instruction execution).
|
||||||
|
- If Buffering is enabled, all console output is
|
||||||
|
written to the buffer at all times (deleting the
|
||||||
|
oldest buffer contents on overflow).
|
||||||
|
- when a connection is established on the console
|
||||||
|
telnet port, the whole contents of the Buffer is
|
||||||
|
presented on the telnet session and connection
|
||||||
|
will then proceed as if the connection had always
|
||||||
|
been there.
|
||||||
|
This concept allows a simulator to run in the background
|
||||||
|
and when needed a console session to be established.
|
||||||
|
The "when needed" case usually will be interested in
|
||||||
|
what already happened before looking to address what
|
||||||
|
to do, hence the buffer contents being presented.
|
||||||
|
28-Dec-10 MP Added support for BREAK key on Windows
|
||||||
30-Sep-06 RMS Fixed non-printable characters in KSR mode
|
30-Sep-06 RMS Fixed non-printable characters in KSR mode
|
||||||
22-Jun-06 RMS Implemented SET/SHOW PCHAR
|
22-Jun-06 RMS Implemented SET/SHOW PCHAR
|
||||||
31-May-06 JDB Fixed bug if SET CONSOLE DEBUG with no argument
|
31-May-06 JDB Fixed bug if SET CONSOLE DEBUG with no argument
|
||||||
|
@ -63,6 +83,12 @@
|
||||||
sim_putchar_s - output character to console, stall if congested
|
sim_putchar_s - output character to console, stall if congested
|
||||||
sim_set_console - set console parameters
|
sim_set_console - set console parameters
|
||||||
sim_show_console - show console parameters
|
sim_show_console - show console parameters
|
||||||
|
sim_set_cons_buff - set console buffered
|
||||||
|
sim_set_cons_unbuff -set console unbuffered
|
||||||
|
sim_set_cons_log - set console log
|
||||||
|
sim_set_cons_nolog - set console nolog
|
||||||
|
sim_show_cons_buff - show console buffered
|
||||||
|
sim_show_cons_log - show console log
|
||||||
sim_tt_inpcvt - convert input character per mode
|
sim_tt_inpcvt - convert input character per mode
|
||||||
sim_tt_outcvt - convert output character per mode
|
sim_tt_outcvt - convert output character per mode
|
||||||
|
|
||||||
|
@ -105,8 +131,9 @@ TMLN sim_con_ldsc = { 0 }; /* console line descr */
|
||||||
TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc }; /* console line mux */
|
TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc }; /* console line mux */
|
||||||
|
|
||||||
extern volatile int32 stop_cpu;
|
extern volatile int32 stop_cpu;
|
||||||
extern int32 sim_quiet, sim_deb_close;
|
extern int32 sim_quiet;
|
||||||
extern FILE *sim_log, *sim_deb;
|
extern FILE *sim_log, *sim_deb;
|
||||||
|
extern FILEREF *sim_log_ref, *sim_deb_ref;
|
||||||
extern DEVICE *sim_devices[];
|
extern DEVICE *sim_devices[];
|
||||||
|
|
||||||
/* Set/show data structures */
|
/* Set/show data structures */
|
||||||
|
@ -130,9 +157,19 @@ static SHTAB show_con_tab[] = {
|
||||||
{ "BRK", &sim_show_kmap, KMAP_BRK },
|
{ "BRK", &sim_show_kmap, KMAP_BRK },
|
||||||
{ "DEL", &sim_show_kmap, KMAP_DEL },
|
{ "DEL", &sim_show_kmap, KMAP_DEL },
|
||||||
{ "PCHAR", &sim_show_pchar, 0 },
|
{ "PCHAR", &sim_show_pchar, 0 },
|
||||||
{ "LOG", &sim_show_log, 0 },
|
{ "LOG", &sim_show_cons_log, 0 },
|
||||||
{ "TELNET", &sim_show_telnet, 0 },
|
{ "TELNET", &sim_show_telnet, 0 },
|
||||||
{ "DEBUG", &sim_show_debug, 0 },
|
{ "DEBUG", &sim_show_debug, 0 },
|
||||||
|
{ "BUFFERED", &sim_show_cons_buff, 0 },
|
||||||
|
{ NULL, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static CTAB set_con_telnet_tab[] = {
|
||||||
|
{ "LOG", &sim_set_cons_log, 0 },
|
||||||
|
{ "NOLOG", &sim_set_cons_nolog, 0 },
|
||||||
|
{ "BUFFERED", &sim_set_cons_buff, 0 },
|
||||||
|
{ "NOBUFFERED", &sim_set_cons_unbuff, 0 },
|
||||||
|
{ "UNBUFFERED", &sim_set_cons_unbuff, 0 },
|
||||||
{ NULL, NULL, 0 }
|
{ NULL, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -262,6 +299,7 @@ return SCPE_OK;
|
||||||
t_stat sim_set_logon (int32 flag, char *cptr)
|
t_stat sim_set_logon (int32 flag, char *cptr)
|
||||||
{
|
{
|
||||||
char gbuf[CBUFSIZE];
|
char gbuf[CBUFSIZE];
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
if ((cptr == NULL) || (*cptr == 0)) /* need arg */
|
if ((cptr == NULL) || (*cptr == 0)) /* need arg */
|
||||||
return SCPE_2FARG;
|
return SCPE_2FARG;
|
||||||
|
@ -269,12 +307,14 @@ cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */
|
||||||
if (*cptr != 0) /* now eol? */
|
if (*cptr != 0) /* now eol? */
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
sim_set_logoff (0, NULL); /* close cur log */
|
sim_set_logoff (0, NULL); /* close cur log */
|
||||||
sim_log = sim_fopen (gbuf, "a"); /* open log */
|
r = sim_open_logfile (gbuf, FALSE, &sim_log, &sim_log_ref); /* open log */
|
||||||
if (sim_log == NULL) /* error? */
|
if (r != SCPE_OK) /* error? */
|
||||||
return SCPE_OPENERR;
|
return r;
|
||||||
if (!sim_quiet)
|
if (!sim_quiet)
|
||||||
printf ("Logging to file \"%s\"\n", gbuf);
|
printf ("Logging to file \"%s\"\n",
|
||||||
fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); /* start of log */
|
sim_logfile_name (sim_log, sim_log_ref));
|
||||||
|
fprintf (sim_log, "Logging to file \"%s\"\n",
|
||||||
|
sim_logfile_name (sim_log, sim_log_ref)); /* start of log */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,8 +328,8 @@ if (sim_log == NULL) /* no log? */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
if (!sim_quiet)
|
if (!sim_quiet)
|
||||||
printf ("Log file closed\n");
|
printf ("Log file closed\n");
|
||||||
fprintf (sim_log, "Log file closed\n"); /* close log */
|
fprintf (sim_log, "Log file closed\n");
|
||||||
fclose (sim_log);
|
sim_close_logfile (&sim_log_ref); /* close log */
|
||||||
sim_log = NULL;
|
sim_log = NULL;
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
@ -301,8 +341,8 @@ t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr)
|
||||||
if (cptr && (*cptr != 0))
|
if (cptr && (*cptr != 0))
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
if (sim_log)
|
if (sim_log)
|
||||||
fputs ("Logging enabled\n", st);
|
fprintf (st, "Logging enabled to %s\n", sim_logfile_name (sim_log, sim_log_ref));
|
||||||
else fputs ("Logging disabled\n", st);
|
else fprintf (st, "Logging disabled\n");
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,34 +350,24 @@ return SCPE_OK;
|
||||||
|
|
||||||
t_stat sim_set_debon (int32 flag, char *cptr)
|
t_stat sim_set_debon (int32 flag, char *cptr)
|
||||||
{
|
{
|
||||||
char *tptr, gbuf[CBUFSIZE];
|
char gbuf[CBUFSIZE];
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
if ((cptr == NULL) || (*cptr == 0)) /* too few arguments? */
|
if ((cptr == NULL) || (*cptr == 0)) /* need arg */
|
||||||
return SCPE_2FARG;
|
return SCPE_2FARG;
|
||||||
tptr = get_glyph (cptr, gbuf, 0); /* get file name */
|
cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */
|
||||||
if (*tptr != 0) /* now eol? */
|
if (*cptr != 0) /* now eol? */
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
sim_set_deboff (0, NULL); /* close cur debug */
|
r = sim_open_logfile (gbuf, FALSE, &sim_deb, &sim_deb_ref);
|
||||||
if (strcmp (gbuf, "LOG") == 0) { /* debug to log? */
|
|
||||||
if (sim_log == NULL) /* any log? */
|
if (r != SCPE_OK)
|
||||||
return SCPE_ARG;
|
return r;
|
||||||
sim_deb = sim_log;
|
|
||||||
}
|
|
||||||
else if (strcmp (gbuf, "STDOUT") == 0) /* debug to stdout? */
|
|
||||||
sim_deb = stdout;
|
|
||||||
else if (strcmp (gbuf, "STDERR") == 0) /* debug to stderr? */
|
|
||||||
sim_deb = stderr;
|
|
||||||
else {
|
|
||||||
cptr = get_glyph_nc (cptr, gbuf, 0); /* reparse */
|
|
||||||
sim_deb = sim_fopen (gbuf, "a"); /* open debug */
|
|
||||||
if (sim_deb == NULL) /* error? */
|
|
||||||
return SCPE_OPENERR;
|
|
||||||
sim_deb_close = 1; /* need close */
|
|
||||||
}
|
|
||||||
if (!sim_quiet)
|
if (!sim_quiet)
|
||||||
printf ("Debug output to \"%s\"\n", gbuf);
|
printf ("Debug output to \"%s\"\n",
|
||||||
|
sim_logfile_name (sim_deb, sim_deb_ref));
|
||||||
if (sim_log)
|
if (sim_log)
|
||||||
fprintf (sim_log, "Debug output to \"%s\"\n", gbuf);
|
fprintf (sim_log, "Debug output to \"%s\"\n",
|
||||||
|
sim_logfile_name (sim_deb, sim_deb_ref));
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,18 +375,18 @@ return SCPE_OK;
|
||||||
|
|
||||||
t_stat sim_set_deboff (int32 flag, char *cptr)
|
t_stat sim_set_deboff (int32 flag, char *cptr)
|
||||||
{
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
if (cptr && (*cptr != 0)) /* now eol? */
|
if (cptr && (*cptr != 0)) /* now eol? */
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
if (sim_deb == NULL) /* no log? */
|
if (sim_deb == NULL) /* no log? */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
r = sim_close_logfile (&sim_deb_ref);
|
||||||
|
sim_deb = NULL;
|
||||||
if (!sim_quiet)
|
if (!sim_quiet)
|
||||||
printf ("Debug output disabled\n");
|
printf ("Debug output disabled\n");
|
||||||
if (sim_log)
|
if (sim_log)
|
||||||
fprintf (sim_log, "Debug output disabled\n");
|
fprintf (sim_log, "Debug output disabled\n");
|
||||||
if (sim_deb_close) /* close if needed */
|
|
||||||
fclose (sim_deb);
|
|
||||||
sim_deb_close = 0;
|
|
||||||
sim_deb = NULL;
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,20 +397,41 @@ t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cpt
|
||||||
if (cptr && (*cptr != 0))
|
if (cptr && (*cptr != 0))
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
if (sim_deb)
|
if (sim_deb)
|
||||||
fputs ("Debug output enabled\n", st);
|
fprintf (st, "Debug output enabled\n", sim_logfile_name (sim_deb, sim_deb_ref));
|
||||||
else fputs ("Debug output disabled\n", st);
|
else fprintf (st, "Debug output disabled\n");
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set console to Telnet port */
|
/* SET CONSOLE command */
|
||||||
|
|
||||||
t_stat sim_set_telnet (int32 flg, char *cptr)
|
/* Set console to Telnet port (and parameters) */
|
||||||
|
|
||||||
|
t_stat sim_set_telnet (int32 flag, char *cptr)
|
||||||
{
|
{
|
||||||
if ((cptr == NULL) || (*cptr == 0)) /* too few arguments? */
|
char *cvptr, gbuf[CBUFSIZE];
|
||||||
|
CTAB *ctptr;
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if ((cptr == NULL) || (*cptr == 0))
|
||||||
return SCPE_2FARG;
|
return SCPE_2FARG;
|
||||||
if (sim_con_tmxr.master) /* already open? */
|
while (*cptr != 0) { /* do all mods */
|
||||||
return SCPE_ALATT;
|
cptr = get_glyph_nc (cptr, gbuf, ','); /* get modifier */
|
||||||
return tmxr_open_master (&sim_con_tmxr, cptr); /* open master socket */
|
if (cvptr = strchr (gbuf, '=')) /* = value? */
|
||||||
|
*cvptr++ = 0;
|
||||||
|
get_glyph (gbuf, gbuf, 0); /* modifier to UC */
|
||||||
|
if (isdigit (*gbuf)) {
|
||||||
|
if (sim_con_tmxr.master) return SCPE_ALATT; /* already open? */
|
||||||
|
return tmxr_open_master (&sim_con_tmxr, gbuf); /* open master socket */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (ctptr = find_ctab (set_con_telnet_tab, gbuf)) { /* match? */
|
||||||
|
r = ctptr->action (ctptr->arg, cvptr); /* do the rest */
|
||||||
|
if (r != SCPE_OK)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else return SCPE_NOPARAM;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close console Telnet port */
|
/* Close console Telnet port */
|
||||||
|
@ -402,17 +453,167 @@ if (cptr && (*cptr != 0))
|
||||||
return SCPE_2MARG;
|
return SCPE_2MARG;
|
||||||
if (sim_con_tmxr.master == 0)
|
if (sim_con_tmxr.master == 0)
|
||||||
fprintf (st, "Connected to console window\n");
|
fprintf (st, "Connected to console window\n");
|
||||||
else if (sim_con_ldsc.conn == 0)
|
else {
|
||||||
|
if (sim_con_ldsc.conn == 0)
|
||||||
fprintf (st, "Listening on port %d\n", sim_con_tmxr.port);
|
fprintf (st, "Listening on port %d\n", sim_con_tmxr.port);
|
||||||
else {
|
else {
|
||||||
fprintf (st, "Listening on port %d, connected to socket %d\n",
|
fprintf (st, "Listening on port %d, connected to socket %d\n",
|
||||||
sim_con_tmxr.port, sim_con_ldsc.conn);
|
sim_con_tmxr.port, sim_con_ldsc.conn);
|
||||||
tmxr_fconns (st, &sim_con_ldsc, -1);
|
tmxr_fconns (st, &sim_con_ldsc, -1);
|
||||||
|
}
|
||||||
tmxr_fstats (st, &sim_con_ldsc, -1);
|
tmxr_fstats (st, &sim_con_ldsc, -1);
|
||||||
}
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set console to Buffering */
|
||||||
|
|
||||||
|
t_stat sim_set_cons_buff (int32 flg, char *cptr)
|
||||||
|
{
|
||||||
|
char cmdbuf[CBUFSIZE];
|
||||||
|
|
||||||
|
sprintf(cmdbuf, "BUFFERED%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
|
||||||
|
return tmxr_open_master (&sim_con_tmxr, cmdbuf); /* open master socket */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set console to NoBuffering */
|
||||||
|
|
||||||
|
t_stat sim_set_cons_unbuff (int32 flg, char *cptr)
|
||||||
|
{
|
||||||
|
char cmdbuf[CBUFSIZE];
|
||||||
|
|
||||||
|
sprintf(cmdbuf, "UNBUFFERED%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
|
||||||
|
return tmxr_open_master (&sim_con_tmxr, cmdbuf); /* open master socket */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set console to Logging */
|
||||||
|
|
||||||
|
t_stat sim_set_cons_log (int32 flg, char *cptr)
|
||||||
|
{
|
||||||
|
char cmdbuf[CBUFSIZE];
|
||||||
|
|
||||||
|
sprintf(cmdbuf, "LOG%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
|
||||||
|
return tmxr_open_master (&sim_con_tmxr, cmdbuf); /* open master socket */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set console to NoLogging */
|
||||||
|
|
||||||
|
t_stat sim_set_cons_nolog (int32 flg, char *cptr)
|
||||||
|
{
|
||||||
|
char cmdbuf[CBUFSIZE];
|
||||||
|
|
||||||
|
sprintf(cmdbuf, "NOLOG%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
|
||||||
|
return tmxr_open_master (&sim_con_tmxr, cmdbuf); /* open master socket */
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat sim_show_cons_log (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, char *cptr)
|
||||||
|
{
|
||||||
|
if (cptr && (*cptr != 0))
|
||||||
|
return SCPE_2MARG;
|
||||||
|
if (sim_con_tmxr.ldsc->txlog)
|
||||||
|
fprintf (st, "Log File being written to %s\n", sim_con_tmxr.ldsc->txlogname);
|
||||||
|
else
|
||||||
|
fprintf (st, "No Logging\n");
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat sim_show_cons_buff (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, char *cptr)
|
||||||
|
{
|
||||||
|
if (cptr && (*cptr != 0))
|
||||||
|
return SCPE_2MARG;
|
||||||
|
if (!sim_con_tmxr.buffered)
|
||||||
|
fprintf (st, "Unbuffered\n");
|
||||||
|
else
|
||||||
|
fprintf (st, "Buffer Size = %d\n", sim_con_tmxr.buffered);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Log File Open/Close/Show Support */
|
||||||
|
|
||||||
|
/* Open log file */
|
||||||
|
|
||||||
|
t_stat sim_open_logfile (char *filename, t_bool binary, FILE **pf, FILEREF **pref)
|
||||||
|
{
|
||||||
|
char *tptr, gbuf[CBUFSIZE];
|
||||||
|
|
||||||
|
*pref = NULL;
|
||||||
|
if ((filename == NULL) || (*filename == 0)) /* too few arguments? */
|
||||||
|
return SCPE_2FARG;
|
||||||
|
tptr = get_glyph (filename, gbuf, 0);
|
||||||
|
if (*tptr != 0) /* now eol? */
|
||||||
|
return SCPE_2MARG;
|
||||||
|
sim_close_logfile (pref);
|
||||||
|
*pf = NULL;
|
||||||
|
if (strcmp (gbuf, "LOG") == 0) { /* output to log? */
|
||||||
|
if (sim_log == NULL) /* any log? */
|
||||||
|
return SCPE_ARG;
|
||||||
|
*pf = sim_log;
|
||||||
|
*pref = sim_log_ref;
|
||||||
|
if (*pref)
|
||||||
|
++(*pref)->refcount;
|
||||||
|
}
|
||||||
|
else if (strcmp (gbuf, "DEBUG") == 0) { /* output to debug? */
|
||||||
|
if (sim_debug == NULL) /* any debug? */
|
||||||
|
return SCPE_ARG;
|
||||||
|
*pf = sim_deb;
|
||||||
|
*pref = sim_deb_ref;
|
||||||
|
if (*pref)
|
||||||
|
++(*pref)->refcount;
|
||||||
|
}
|
||||||
|
else if (strcmp (gbuf, "STDOUT") == 0) /* output to stdout? */
|
||||||
|
*pf = stdout;
|
||||||
|
else if (strcmp (gbuf, "STDERR") == 0) /* output to stderr? */
|
||||||
|
*pf = stderr;
|
||||||
|
else {
|
||||||
|
*pref = calloc (1, sizeof(**pref));
|
||||||
|
if (!*pref)
|
||||||
|
return SCPE_MEM;
|
||||||
|
get_glyph_nc (filename, gbuf, 0); /* reparse */
|
||||||
|
strncpy ((*pref)->name, gbuf, sizeof((*pref)->name)-1);
|
||||||
|
*pf = sim_fopen (gbuf, (binary ? "ab" : "a")); /* open file */
|
||||||
|
if (*pf == NULL) { /* error? */
|
||||||
|
free (*pref);
|
||||||
|
*pref = NULL;
|
||||||
|
return SCPE_OPENERR;
|
||||||
|
}
|
||||||
|
(*pref)->file = *pf;
|
||||||
|
(*pref)->refcount = 1; /* need close */
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close log file */
|
||||||
|
|
||||||
|
t_stat sim_close_logfile (FILEREF **pref)
|
||||||
|
{
|
||||||
|
if (NULL == *pref)
|
||||||
|
return SCPE_OK;
|
||||||
|
(*pref)->refcount = (*pref)->refcount - 1;
|
||||||
|
if ((*pref)->refcount > 0)
|
||||||
|
return SCPE_OK;
|
||||||
|
fclose ((*pref)->file);
|
||||||
|
free (*pref);
|
||||||
|
*pref = NULL;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show logfile support routine */
|
||||||
|
|
||||||
|
const char *sim_logfile_name (FILE *st, FILEREF *ref)
|
||||||
|
{
|
||||||
|
if (!st)
|
||||||
|
return "";
|
||||||
|
if (st == stdout)
|
||||||
|
return "STDOUT";
|
||||||
|
if (st == stderr)
|
||||||
|
return "STDERR";
|
||||||
|
if (!ref)
|
||||||
|
return "";
|
||||||
|
return ref->name;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check connection before executing */
|
/* Check connection before executing */
|
||||||
|
|
||||||
t_stat sim_check_console (int32 sec)
|
t_stat sim_check_console (int32 sec)
|
||||||
|
@ -421,11 +622,16 @@ int32 c, i;
|
||||||
|
|
||||||
if (sim_con_tmxr.master == 0) /* not Telnet? done */
|
if (sim_con_tmxr.master == 0) /* not Telnet? done */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
if (sim_con_ldsc.conn) { /* connected? */
|
if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) { /* connected or buffered ? */
|
||||||
tmxr_poll_rx (&sim_con_tmxr); /* poll (check disconn) */
|
tmxr_poll_rx (&sim_con_tmxr); /* poll (check disconn) */
|
||||||
if (sim_con_ldsc.conn) /* still connected? */
|
if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) { /* still connected? */
|
||||||
|
if (!sim_con_ldsc.conn) {
|
||||||
|
printf ("Running with Buffered Console\n"); /* print transition */
|
||||||
|
fflush (stdout);
|
||||||
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for (i = 0; i < sec; i++) { /* loop */
|
for (i = 0; i < sec; i++) { /* loop */
|
||||||
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) { /* poll connect */
|
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) { /* poll connect */
|
||||||
sim_con_ldsc.rcve = 1; /* rcv enabled */
|
sim_con_ldsc.rcve = 1; /* rcv enabled */
|
||||||
|
@ -456,8 +662,14 @@ int32 c;
|
||||||
c = sim_os_poll_kbd (); /* get character */
|
c = sim_os_poll_kbd (); /* get character */
|
||||||
if ((c == SCPE_STOP) || (sim_con_tmxr.master == 0)) /* ^E or not Telnet? */
|
if ((c == SCPE_STOP) || (sim_con_tmxr.master == 0)) /* ^E or not Telnet? */
|
||||||
return c; /* in-window */
|
return c; /* in-window */
|
||||||
if (sim_con_ldsc.conn == 0) /* no Telnet conn? */
|
if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */
|
||||||
return SCPE_LOST;
|
if (!sim_con_ldsc.txbfd) /* unbuffered? */
|
||||||
|
return SCPE_LOST; /* connection lost */
|
||||||
|
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
|
||||||
|
sim_con_ldsc.rcve = 1; /* rcv enabled */
|
||||||
|
else /* fall through to poll reception */
|
||||||
|
return SCPE_OK; /* unconnected and buffered - nothing to receive */
|
||||||
|
}
|
||||||
tmxr_poll_rx (&sim_con_tmxr); /* poll for input */
|
tmxr_poll_rx (&sim_con_tmxr); /* poll for input */
|
||||||
if (c = tmxr_getc_ln (&sim_con_ldsc)) /* any char? */
|
if (c = tmxr_getc_ln (&sim_con_ldsc)) /* any char? */
|
||||||
return (c & (SCPE_BREAK | 0377)) | SCPE_KFLAG;
|
return (c & (SCPE_BREAK | 0377)) | SCPE_KFLAG;
|
||||||
|
@ -468,12 +680,19 @@ return SCPE_OK;
|
||||||
|
|
||||||
t_stat sim_putchar (int32 c)
|
t_stat sim_putchar (int32 c)
|
||||||
{
|
{
|
||||||
|
if (sim_con_tmxr.master == 0) { /* not Telnet? */
|
||||||
if (sim_log) /* log file? */
|
if (sim_log) /* log file? */
|
||||||
fputc (c, sim_log);
|
fputc (c, sim_log);
|
||||||
if (sim_con_tmxr.master == 0) /* not Telnet? */
|
|
||||||
return sim_os_putchar (c); /* in-window version */
|
return sim_os_putchar (c); /* in-window version */
|
||||||
if (sim_con_ldsc.conn == 0) /* no Telnet conn? */
|
}
|
||||||
return SCPE_LOST;
|
if (sim_log && !sim_con_ldsc.txlog) /* log file, but no line log? */
|
||||||
|
fputc (c, sim_log);
|
||||||
|
if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */
|
||||||
|
if (!sim_con_ldsc.txbfd) /* unbuffered? */
|
||||||
|
return SCPE_LOST; /* connection lost */
|
||||||
|
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
|
||||||
|
sim_con_ldsc.rcve = 1; /* rcv enabled */
|
||||||
|
}
|
||||||
tmxr_putc_ln (&sim_con_ldsc, c); /* output char */
|
tmxr_putc_ln (&sim_con_ldsc, c); /* output char */
|
||||||
tmxr_poll_tx (&sim_con_tmxr); /* poll xmt */
|
tmxr_poll_tx (&sim_con_tmxr); /* poll xmt */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -486,8 +705,12 @@ t_stat r;
|
||||||
if (sim_log) fputc (c, sim_log); /* log file? */
|
if (sim_log) fputc (c, sim_log); /* log file? */
|
||||||
if (sim_con_tmxr.master == 0) /* not Telnet? */
|
if (sim_con_tmxr.master == 0) /* not Telnet? */
|
||||||
return sim_os_putchar (c); /* in-window version */
|
return sim_os_putchar (c); /* in-window version */
|
||||||
if (sim_con_ldsc.conn == 0) /* no Telnet conn? */
|
if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */
|
||||||
return SCPE_LOST;
|
if (!sim_con_ldsc.txbfd) /* non-buffered Telnet conn? */
|
||||||
|
return SCPE_LOST; /* lost */
|
||||||
|
if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */
|
||||||
|
sim_con_ldsc.rcve = 1; /* rcv enabled */
|
||||||
|
}
|
||||||
if (sim_con_ldsc.xmte == 0) /* xmt disabled? */
|
if (sim_con_ldsc.xmte == 0) /* xmt disabled? */
|
||||||
r = SCPE_STALL;
|
r = SCPE_STALL;
|
||||||
else r = tmxr_putc_ln (&sim_con_ldsc, c); /* no, Telnet output */
|
else r = tmxr_putc_ln (&sim_con_ldsc, c); /* no, Telnet output */
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
used in advertising or otherwise to promote the sale, use or other dealings
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
in this Software without prior written authorization from Robert M Supnik.
|
in this Software without prior written authorization from Robert M Supnik.
|
||||||
|
|
||||||
|
17-Jan-11 MP Added buffered line capabilities
|
||||||
22-Jun-06 RMS Implemented SET/SHOW PCHAR
|
22-Jun-06 RMS Implemented SET/SHOW PCHAR
|
||||||
22-Nov-05 RMS Added central input/output conversion support
|
22-Nov-05 RMS Added central input/output conversion support
|
||||||
05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy
|
05-Nov-04 RMS Moved SET/SHOW DEBUG under CONSOLE hierarchy
|
||||||
|
@ -57,6 +58,10 @@ t_stat sim_set_notelnet (int32 flag, char *cptr);
|
||||||
t_stat sim_set_logon (int32 flag, char *cptr);
|
t_stat sim_set_logon (int32 flag, char *cptr);
|
||||||
t_stat sim_set_logoff (int32 flag, char *cptr);
|
t_stat sim_set_logoff (int32 flag, char *cptr);
|
||||||
t_stat sim_set_debon (int32 flag, char *cptr);
|
t_stat sim_set_debon (int32 flag, char *cptr);
|
||||||
|
t_stat sim_set_cons_buff (int32 flg, char *cptr);
|
||||||
|
t_stat sim_set_cons_unbuff (int32 flg, char *cptr);
|
||||||
|
t_stat sim_set_cons_log (int32 flg, char *cptr);
|
||||||
|
t_stat sim_set_cons_nolog (int32 flg, char *cptr);
|
||||||
t_stat sim_set_deboff (int32 flag, char *cptr);
|
t_stat sim_set_deboff (int32 flag, char *cptr);
|
||||||
t_stat sim_set_pchar (int32 flag, char *cptr);
|
t_stat sim_set_pchar (int32 flag, char *cptr);
|
||||||
t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||||
|
@ -65,7 +70,12 @@ t_stat sim_show_telnet (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cp
|
||||||
t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||||
t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||||
t_stat sim_show_pchar (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
t_stat sim_show_pchar (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||||
|
t_stat sim_show_cons_buff (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||||
|
t_stat sim_show_cons_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr);
|
||||||
t_stat sim_check_console (int32 sec);
|
t_stat sim_check_console (int32 sec);
|
||||||
|
t_stat sim_open_logfile (char *filename, t_bool binary, FILE **pf, FILEREF **pref);
|
||||||
|
t_stat sim_close_logfile (FILEREF **pref);
|
||||||
|
const char *sim_logfile_name (FILE *st, FILEREF *ref);
|
||||||
t_stat sim_poll_kbd (void);
|
t_stat sim_poll_kbd (void);
|
||||||
t_stat sim_putchar (int32 c);
|
t_stat sim_putchar (int32 c);
|
||||||
t_stat sim_putchar_s (int32 c);
|
t_stat sim_putchar_s (int32 c);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
used in advertising or otherwise to promote the sale, use or other dealings
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
in this Software without prior written authorization from Robert M Supnik.
|
in this Software without prior written authorization from Robert M Supnik.
|
||||||
|
|
||||||
|
18-Jan-11 MP Added log file reference count support
|
||||||
21-Jul-08 RMS Removed inlining support
|
21-Jul-08 RMS Removed inlining support
|
||||||
28-May-08 RMS Added inlining support
|
28-May-08 RMS Added inlining support
|
||||||
28-Jun-07 RMS Added IA64 VMS support (from Norm Lastovica)
|
28-Jun-07 RMS Added IA64 VMS support (from Norm Lastovica)
|
||||||
|
@ -486,6 +487,13 @@ struct sim_debtab {
|
||||||
#define DEBUG_PRI(d,m) (sim_deb && (d.dctrl & (m)))
|
#define DEBUG_PRI(d,m) (sim_deb && (d.dctrl & (m)))
|
||||||
#define DEBUG_PRJ(d,m) (sim_deb && (d->dctrl & (m)))
|
#define DEBUG_PRJ(d,m) (sim_deb && (d->dctrl & (m)))
|
||||||
|
|
||||||
|
/* File Reference */
|
||||||
|
struct sim_fileref {
|
||||||
|
char name[CBUFSIZE]; /* file name */
|
||||||
|
FILE *file; /* file handle */
|
||||||
|
int32 refcount; /* reference count */
|
||||||
|
};
|
||||||
|
|
||||||
/* The following macros define structure contents */
|
/* The following macros define structure contents */
|
||||||
|
|
||||||
#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),(cap),0,0
|
#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),(cap),0,0
|
||||||
|
@ -522,6 +530,7 @@ typedef struct sim_mtab MTAB;
|
||||||
typedef struct sim_schtab SCHTAB;
|
typedef struct sim_schtab SCHTAB;
|
||||||
typedef struct sim_brktab BRKTAB;
|
typedef struct sim_brktab BRKTAB;
|
||||||
typedef struct sim_debtab DEBTAB;
|
typedef struct sim_debtab DEBTAB;
|
||||||
|
typedef struct sim_fileref FILEREF;
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
|
|
||||||
|
|
220
sim_tmxr.c
220
sim_tmxr.c
|
@ -26,6 +26,7 @@
|
||||||
Based on the original DZ11 simulator by Thord Nilson, as updated by
|
Based on the original DZ11 simulator by Thord Nilson, as updated by
|
||||||
Arthur Krewat.
|
Arthur Krewat.
|
||||||
|
|
||||||
|
17-Jan-11 MP Added Buffered line capabilities
|
||||||
16-Jan-11 MP Made option negotiation more reliable
|
16-Jan-11 MP Made option negotiation more reliable
|
||||||
20-Nov-08 RMS Added three new standardized SHOW routines
|
20-Nov-08 RMS Added three new standardized SHOW routines
|
||||||
30-Sep-08 JDB Reverted tmxr_find_ldsc to original implementation
|
30-Sep-08 JDB Reverted tmxr_find_ldsc to original implementation
|
||||||
|
@ -154,9 +155,12 @@ int32 tmxr_poll_conn (TMXR *mp)
|
||||||
SOCKET newsock;
|
SOCKET newsock;
|
||||||
TMLN *lp;
|
TMLN *lp;
|
||||||
int32 *op;
|
int32 *op;
|
||||||
int32 i, j;
|
int32 i, j, psave;
|
||||||
uint32 ipaddr;
|
uint32 ipaddr;
|
||||||
|
char cmsg[80];
|
||||||
|
char dmsg[80] = "";
|
||||||
|
char lmsg[80] = "";
|
||||||
|
char msgbuf[256];
|
||||||
static char mantra[] = {
|
static char mantra[] = {
|
||||||
TN_IAC, TN_WILL, TN_LINE,
|
TN_IAC, TN_WILL, TN_LINE,
|
||||||
TN_IAC, TN_WILL, TN_SGA,
|
TN_IAC, TN_WILL, TN_SGA,
|
||||||
|
@ -189,34 +193,38 @@ if (newsock != INVALID_SOCKET) { /* got a live one? */
|
||||||
lp = mp->ldsc + i; /* get line desc */
|
lp = mp->ldsc + i; /* get line desc */
|
||||||
lp->conn = newsock; /* record connection */
|
lp->conn = newsock; /* record connection */
|
||||||
lp->ipad = ipaddr; /* ip address */
|
lp->ipad = ipaddr; /* ip address */
|
||||||
|
sim_write_sock (newsock, mantra, sizeof(mantra));
|
||||||
|
sprintf (cmsg, "\n\r\nConnected to the %s simulator ", sim_name);
|
||||||
|
|
||||||
|
if (mp->dptr) { /* device defined? */
|
||||||
|
sprintf (dmsg, "%s device", /* report device name */
|
||||||
|
sim_dname (mp->dptr));
|
||||||
|
|
||||||
|
if (mp->lines > 1) /* more than one line? */
|
||||||
|
sprintf (lmsg, ", line %d", i); /* report the line number */
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf (msgbuf, "%s%s%s\r\n\n", cmsg, dmsg, lmsg);
|
||||||
lp->cnms = sim_os_msec (); /* time of conn */
|
lp->cnms = sim_os_msec (); /* time of conn */
|
||||||
lp->rxbpr = lp->rxbpi = 0; /* init buf pointers */
|
if (!mp->buffered) {
|
||||||
lp->txbpr = lp->txbpi = 0;
|
lp->txbpi = 0; /* init buf pointers */
|
||||||
lp->rxcnt = lp->txcnt = 0; /* init counters */
|
lp->txbpr = lp->txbsz - strlen (msgbuf);
|
||||||
|
lp->rxcnt = lp->txcnt = lp->txdrp = 0; /* init counters */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (lp->txcnt > lp->txbsz)
|
||||||
|
lp->txbpr = (lp->txbpi + 1) % lp->txbsz;
|
||||||
|
else
|
||||||
|
lp->txbpr = lp->txbsz - strlen (msgbuf);
|
||||||
lp->tsta = 0; /* init telnet state */
|
lp->tsta = 0; /* init telnet state */
|
||||||
lp->xmte = 1; /* enable transmit */
|
lp->xmte = 1; /* enable transmit */
|
||||||
lp->dstb = 0; /* default bin mode */
|
lp->dstb = 0; /* default bin mode */
|
||||||
sim_write_sock (newsock, mantra, sizeof (mantra));
|
psave = lp->txbpi; /* save insertion pointer */
|
||||||
tmxr_linemsg (lp, "\n\r\nConnected to the ");
|
lp->txbpi = lp->txbpr; /* insert connection message */
|
||||||
tmxr_linemsg (lp, sim_name);
|
tmxr_linemsg (lp, msgbuf); /* beginning of buffer */
|
||||||
tmxr_linemsg (lp, " simulator ");
|
lp->txbpi = psave; /* restore insertion pointer */
|
||||||
|
|
||||||
if (mp->dptr) { /* device defined? */
|
|
||||||
tmxr_linemsg (lp, sim_dname (mp->dptr)); /* report device name */
|
|
||||||
tmxr_linemsg (lp, " device");
|
|
||||||
|
|
||||||
if (mp->lines > 1) { /* more than one line? */
|
|
||||||
char line[20];
|
|
||||||
|
|
||||||
tmxr_linemsg (lp, ", line "); /* report the line number */
|
|
||||||
sprintf (line, "%i", i);
|
|
||||||
tmxr_linemsg (lp, line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmxr_linemsg (lp, "\r\n\n");
|
|
||||||
|
|
||||||
tmxr_poll_tx (mp); /* flush output */
|
tmxr_poll_tx (mp); /* flush output */
|
||||||
|
lp->txcnt -= strlen (msgbuf); /* adjust statistics */
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
} /* end if newsock */
|
} /* end if newsock */
|
||||||
|
@ -233,6 +241,7 @@ tmxr_send_buffered_data (lp); /* send buffered data */
|
||||||
sim_close_sock (lp->conn, 0); /* reset conn */
|
sim_close_sock (lp->conn, 0); /* reset conn */
|
||||||
lp->conn = lp->tsta = 0; /* reset state */
|
lp->conn = lp->tsta = 0; /* reset state */
|
||||||
lp->rxbpr = lp->rxbpi = 0;
|
lp->rxbpr = lp->rxbpi = 0;
|
||||||
|
if (!lp->txbfd)
|
||||||
lp->txbpr = lp->txbpi = 0;
|
lp->txbpr = lp->txbpi = 0;
|
||||||
lp->xmte = 1;
|
lp->xmte = 1;
|
||||||
lp->dstb = 0;
|
lp->dstb = 0;
|
||||||
|
@ -419,7 +428,7 @@ return;
|
||||||
|
|
||||||
int32 tmxr_rqln (TMLN *lp)
|
int32 tmxr_rqln (TMLN *lp)
|
||||||
{
|
{
|
||||||
return (lp->rxbpi - lp->rxbpr);
|
return (lp->rxbpi - lp->rxbpr + ((lp->rxbpi < lp->rxbpr)? TMXR_MAXBUF: 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove character p (and matching status) from line l input buffer */
|
/* Remove character p (and matching status) from line l input buffer */
|
||||||
|
@ -447,24 +456,29 @@ t_stat tmxr_putc_ln (TMLN *lp, int32 chr)
|
||||||
{
|
{
|
||||||
if (lp->txlog) /* log if available */
|
if (lp->txlog) /* log if available */
|
||||||
fputc (chr, lp->txlog);
|
fputc (chr, lp->txlog);
|
||||||
if (lp->conn == 0) /* no conn? lost */
|
if ((lp->conn == 0) && (!lp->txbfd)) /* no conn & not buffered? */
|
||||||
|
if (lp->txlog) /* if it was logged, we got it */
|
||||||
|
return SCPE_OK;
|
||||||
|
else {
|
||||||
|
++lp->txdrp; /* lost */
|
||||||
return SCPE_LOST;
|
return SCPE_LOST;
|
||||||
if (tmxr_tqln (lp) < (TMXR_MAXBUF - 1)) { /* room for char (+ IAC)? */
|
|
||||||
lp->txb[lp->txbpi] = (char) chr; /* buffer char */
|
|
||||||
lp->txbpi = lp->txbpi + 1; /* adv pointer */
|
|
||||||
if (lp->txbpi >= TMXR_MAXBUF) /* wrap? */
|
|
||||||
lp->txbpi = 0;
|
|
||||||
if ((char) chr == TN_IAC) { /* IAC? */
|
|
||||||
lp->txb[lp->txbpi] = (char) chr; /* IAC + IAC */
|
|
||||||
lp->txbpi = lp->txbpi + 1; /* adv pointer */
|
|
||||||
if (lp->txbpi >= TMXR_MAXBUF) /* wrap? */
|
|
||||||
lp->txbpi = 0;
|
|
||||||
}
|
}
|
||||||
if (tmxr_tqln (lp) > (TMXR_MAXBUF - TMXR_GUARD)) /* near full? */
|
#define TXBUF_AVAIL(lp) (lp->txbsz - tmxr_tqln (lp))
|
||||||
|
#define TXBUF_CHAR(lp, c) { \
|
||||||
|
lp->txb[lp->txbpi++] = (char)(c); \
|
||||||
|
lp->txbpi %= lp->txbsz; \
|
||||||
|
if (lp->txbpi == lp->txbpr) \
|
||||||
|
lp->txbpr = (1+lp->txbpr)%lp->txbsz, ++lp->txdrp; \
|
||||||
|
}
|
||||||
|
if ((lp->txbfd) || (TXBUF_AVAIL(lp) > 1)) { /* room for char (+ IAC)? */
|
||||||
|
if (TN_IAC == (char) chr) /* char == IAC ? */
|
||||||
|
TXBUF_CHAR (lp, TN_IAC); /* stuff extra IAC char */
|
||||||
|
TXBUF_CHAR (lp, chr); /* buffer char & adv pointer */
|
||||||
|
if ((!lp->txbfd) && (TXBUF_AVAIL (lp) <= TMXR_GUARD))/* near full? */
|
||||||
lp->xmte = 0; /* disable line */
|
lp->xmte = 0; /* disable line */
|
||||||
return SCPE_OK; /* char sent */
|
return SCPE_OK; /* char sent */
|
||||||
}
|
}
|
||||||
lp->xmte = 0; /* no room, dsbl line */
|
++lp->txdrp; lp->xmte = 0; /* no room, dsbl line */
|
||||||
return SCPE_STALL; /* char not sent */
|
return SCPE_STALL; /* char not sent */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,10 +524,10 @@ if (nbytes) { /* >0? write */
|
||||||
sbytes = sim_write_sock (lp->conn, /* write all data */
|
sbytes = sim_write_sock (lp->conn, /* write all data */
|
||||||
&(lp->txb[lp->txbpr]), nbytes);
|
&(lp->txb[lp->txbpr]), nbytes);
|
||||||
else sbytes = sim_write_sock (lp->conn, /* write to end buf */
|
else sbytes = sim_write_sock (lp->conn, /* write to end buf */
|
||||||
&(lp->txb[lp->txbpr]), TMXR_MAXBUF - lp->txbpr);
|
&(lp->txb[lp->txbpr]), lp->txbsz - lp->txbpr);
|
||||||
if (sbytes != SOCKET_ERROR) { /* ok? */
|
if (sbytes != SOCKET_ERROR) { /* ok? */
|
||||||
lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */
|
lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */
|
||||||
if (lp->txbpr >= TMXR_MAXBUF) /* wrap? */
|
if (lp->txbpr >= lp->txbsz) /* wrap? */
|
||||||
lp->txbpr = 0;
|
lp->txbpr = 0;
|
||||||
lp->txcnt = lp->txcnt + sbytes; /* update counts */
|
lp->txcnt = lp->txcnt + sbytes; /* update counts */
|
||||||
nbytes = nbytes - sbytes;
|
nbytes = nbytes - sbytes;
|
||||||
|
@ -522,7 +536,7 @@ if (nbytes) { /* >0? write */
|
||||||
sbytes = sim_write_sock (lp->conn, lp->txb, nbytes);
|
sbytes = sim_write_sock (lp->conn, lp->txb, nbytes);
|
||||||
if (sbytes != SOCKET_ERROR) { /* ok */
|
if (sbytes != SOCKET_ERROR) { /* ok */
|
||||||
lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */
|
lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */
|
||||||
if (lp->txbpr >= TMXR_MAXBUF) /* wrap? */
|
if (lp->txbpr >= lp->txbsz) /* wrap? */
|
||||||
lp->txbpr = 0;
|
lp->txbpr = 0;
|
||||||
lp->txcnt = lp->txcnt + sbytes; /* update counts */
|
lp->txcnt = lp->txcnt + sbytes; /* update counts */
|
||||||
nbytes = nbytes - sbytes;
|
nbytes = nbytes - sbytes;
|
||||||
|
@ -536,7 +550,7 @@ return nbytes;
|
||||||
|
|
||||||
int32 tmxr_tqln (TMLN *lp)
|
int32 tmxr_tqln (TMLN *lp)
|
||||||
{
|
{
|
||||||
return (lp->txbpi - lp->txbpr + ((lp->txbpi < lp->txbpr)? TMXR_MAXBUF: 0));
|
return (lp->txbpi - lp->txbpr + ((lp->txbpi < lp->txbpr)? lp->txbsz: 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open master socket */
|
/* Open master socket */
|
||||||
|
@ -548,6 +562,81 @@ SOCKET sock;
|
||||||
TMLN *lp;
|
TMLN *lp;
|
||||||
t_stat r;
|
t_stat r;
|
||||||
|
|
||||||
|
if (!isdigit(*cptr)) {
|
||||||
|
char gbuf[CBUFSIZE];
|
||||||
|
cptr = get_glyph (cptr, gbuf, '=');
|
||||||
|
if (0 == MATCH_CMD (gbuf, "LOG")) {
|
||||||
|
if ((NULL == cptr) || ('\0' == *cptr))
|
||||||
|
return SCPE_2FARG;
|
||||||
|
strncpy(mp->logfiletmpl, cptr, sizeof(mp->logfiletmpl)-1);
|
||||||
|
for (i = 0; i < mp->lines; i++) {
|
||||||
|
lp = mp->ldsc + i;
|
||||||
|
sim_close_logfile (&lp->txlogref);
|
||||||
|
lp->txlog = NULL;
|
||||||
|
lp->txlogname = realloc(lp->txlogname, CBUFSIZE);
|
||||||
|
if (mp->lines > 1)
|
||||||
|
sprintf(lp->txlogname, "%s_%d", mp->logfiletmpl, i);
|
||||||
|
else
|
||||||
|
strcpy(lp->txlogname, mp->logfiletmpl);
|
||||||
|
r = sim_open_logfile (lp->txlogname, TRUE, &lp->txlog, &lp->txlogref);
|
||||||
|
if (r == SCPE_OK)
|
||||||
|
setvbuf(lp->txlog, NULL, _IOFBF, 65536);
|
||||||
|
else {
|
||||||
|
free (lp->txlogname);
|
||||||
|
lp->txlogname = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if ((0 == MATCH_CMD (gbuf, "NOBUFFERED")) ||
|
||||||
|
(0 == MATCH_CMD (gbuf, "UNBUFFERED"))) {
|
||||||
|
if (mp->buffered) {
|
||||||
|
mp->buffered = 0;
|
||||||
|
for (i = 0; i < mp->lines; i++) { /* default line buffers */
|
||||||
|
lp = mp->ldsc + i;
|
||||||
|
lp->txbsz = TMXR_MAXBUF;
|
||||||
|
lp->txb = (char *)realloc(lp->txb, lp->txbsz);
|
||||||
|
lp->txbfd = lp->txbpi = lp->txbpr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (0 == MATCH_CMD (gbuf, "BUFFERED")) {
|
||||||
|
if ((NULL == cptr) || ('\0' == *cptr))
|
||||||
|
mp->buffered = 32768;
|
||||||
|
else {
|
||||||
|
i = (int32) get_uint (cptr, 10, 1024*1024, &r);
|
||||||
|
if ((r != SCPE_OK) || (i == 0))
|
||||||
|
return SCPE_ARG;
|
||||||
|
mp->buffered = i;
|
||||||
|
}
|
||||||
|
for (i = 0; i < mp->lines; i++) { /* initialize line buffers */
|
||||||
|
lp = mp->ldsc + i;
|
||||||
|
lp->txbsz = mp->buffered;
|
||||||
|
lp->txbfd = 1;
|
||||||
|
lp->txb = (char *)realloc(lp->txb, lp->txbsz);
|
||||||
|
lp->txbpi = lp->txbpr = 0;
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
if (0 == MATCH_CMD (gbuf, "NOLOG")) {
|
||||||
|
if ((NULL != cptr) && ('\0' != *cptr))
|
||||||
|
return SCPE_2MARG;
|
||||||
|
mp->logfiletmpl[0] = '\0';
|
||||||
|
for (i = 0; i < mp->lines; i++) { /* close line logs */
|
||||||
|
lp = mp->ldsc + i;
|
||||||
|
free(lp->txlogname);
|
||||||
|
lp->txlogname = NULL;
|
||||||
|
if (lp->txlog) {
|
||||||
|
sim_close_logfile (&lp->txlogref);
|
||||||
|
lp->txlog = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
return SCPE_ARG;
|
||||||
|
}
|
||||||
port = (int32) get_uint (cptr, 10, 65535, &r); /* get port */
|
port = (int32) get_uint (cptr, 10, 65535, &r); /* get port */
|
||||||
if ((r != SCPE_OK) || (port == 0))
|
if ((r != SCPE_OK) || (port == 0))
|
||||||
return SCPE_ARG;
|
return SCPE_ARG;
|
||||||
|
@ -564,7 +653,12 @@ for (i = 0; i < mp->lines; i++) { /* initialize lines */
|
||||||
lp->conn = lp->tsta = 0;
|
lp->conn = lp->tsta = 0;
|
||||||
lp->rxbpi = lp->rxbpr = 0;
|
lp->rxbpi = lp->rxbpr = 0;
|
||||||
lp->txbpi = lp->txbpr = 0;
|
lp->txbpi = lp->txbpr = 0;
|
||||||
lp->rxcnt = lp->txcnt = 0;
|
if (!mp->buffered) {
|
||||||
|
lp->txbfd = lp->txbpi = lp->txbpr = 0;
|
||||||
|
lp->txbsz = TMXR_MAXBUF;
|
||||||
|
lp->txb = (char *)realloc(lp->txb, lp->txbsz);
|
||||||
|
}
|
||||||
|
lp->rxcnt = lp->txcnt = lp->txdrp = 0;
|
||||||
lp->xmte = 1;
|
lp->xmte = 1;
|
||||||
lp->dstb = 0;
|
lp->dstb = 0;
|
||||||
}
|
}
|
||||||
|
@ -577,8 +671,11 @@ t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr)
|
||||||
{
|
{
|
||||||
char* tptr;
|
char* tptr;
|
||||||
t_stat r;
|
t_stat r;
|
||||||
|
char pmsg[20], bmsg[32] = "", lmsg[64+PATH_MAX] = "";
|
||||||
|
|
||||||
tptr = (char *) malloc (strlen (cptr) + 1); /* get string buf */
|
tptr = (char *) malloc (strlen (cptr) + /* get string buf */
|
||||||
|
sizeof(pmsg) +
|
||||||
|
sizeof(bmsg) + sizeof(lmsg));
|
||||||
if (tptr == NULL) /* no more mem? */
|
if (tptr == NULL) /* no more mem? */
|
||||||
return SCPE_MEM;
|
return SCPE_MEM;
|
||||||
r = tmxr_open_master (mp, cptr); /* open master socket */
|
r = tmxr_open_master (mp, cptr); /* open master socket */
|
||||||
|
@ -586,7 +683,12 @@ if (r != SCPE_OK) { /* error? */
|
||||||
free (tptr); /* release buf */
|
free (tptr); /* release buf */
|
||||||
return SCPE_OPENERR;
|
return SCPE_OPENERR;
|
||||||
}
|
}
|
||||||
strcpy (tptr, cptr); /* copy port */
|
sprintf (pmsg, "%d", mp->port); /* copy port */
|
||||||
|
if (mp->buffered)
|
||||||
|
sprintf (bmsg, ", buffered=%d", mp->buffered); /* buffer info */
|
||||||
|
if (mp->logfiletmpl[0])
|
||||||
|
sprintf (lmsg, ", log=%s", mp->logfiletmpl); /* logfile info */
|
||||||
|
sprintf (tptr, "%s%s%s", pmsg, bmsg, lmsg); /* assemble all */
|
||||||
uptr->filename = tptr; /* save */
|
uptr->filename = tptr; /* save */
|
||||||
uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */
|
uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */
|
||||||
|
|
||||||
|
@ -696,16 +798,24 @@ static const char *enab = "on";
|
||||||
static const char *dsab = "off";
|
static const char *dsab = "off";
|
||||||
|
|
||||||
if (ln >= 0)
|
if (ln >= 0)
|
||||||
fprintf (st, "line %d: ", ln);
|
fprintf (st, "line %d:\b", ln);
|
||||||
if (lp->conn) {
|
if (!lp->conn)
|
||||||
fprintf (st, "input (%s) queued/total = %d/%d, ",
|
fprintf (st, "line disconnected\n");
|
||||||
|
if (lp->rxcnt)
|
||||||
|
fprintf (st, " input (%s) queued/total = %d/%d\n",
|
||||||
(lp->rcve? enab: dsab),
|
(lp->rcve? enab: dsab),
|
||||||
lp->rxbpi - lp->rxbpr, lp->rxcnt);
|
tmxr_rqln (lp), lp->rxcnt);
|
||||||
|
if (lp->txcnt || lp->txbpi)
|
||||||
fprintf (st, " output (%s) queued/total = %d/%d\n",
|
fprintf (st, " output (%s) queued/total = %d/%d\n",
|
||||||
(lp->xmte? enab: dsab),
|
(lp->xmte? enab: dsab),
|
||||||
lp->txbpi - lp->txbpr, lp->txcnt);
|
tmxr_tqln (lp), lp->txcnt);
|
||||||
}
|
if (lp->txbfd)
|
||||||
else fprintf (st, "line disconnected\n");
|
fprintf (st, " output buffer size = %d\n", lp->txbsz);
|
||||||
|
if (lp->txcnt || lp->txbpi)
|
||||||
|
fprintf (st, " bytes in buffer = %d\n",
|
||||||
|
((lp->txcnt > 0) && (lp->txcnt > lp->txbsz)) ? lp->txbsz : lp->txbpi);
|
||||||
|
if (lp->txdrp)
|
||||||
|
fprintf (st, " dropped = %d\n", lp->txdrp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,7 +868,7 @@ lp->txlogname = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc namebuf */
|
||||||
if (lp->txlogname == NULL) /* can't? */
|
if (lp->txlogname == NULL) /* can't? */
|
||||||
return SCPE_MEM;
|
return SCPE_MEM;
|
||||||
strncpy (lp->txlogname, cptr, CBUFSIZE); /* save file name */
|
strncpy (lp->txlogname, cptr, CBUFSIZE); /* save file name */
|
||||||
lp->txlog = fopen (cptr, "ab"); /* open log */
|
sim_open_logfile (cptr, TRUE, &lp->txlog, &lp->txlogref);/* open log */
|
||||||
if (lp->txlog == NULL) { /* error? */
|
if (lp->txlog == NULL) { /* error? */
|
||||||
free (lp->txlogname); /* free buffer */
|
free (lp->txlogname); /* free buffer */
|
||||||
return SCPE_OPENERR;
|
return SCPE_OPENERR;
|
||||||
|
@ -779,7 +889,7 @@ lp = tmxr_find_ldsc (uptr, val, mp); /* find line desc */
|
||||||
if (lp == NULL)
|
if (lp == NULL)
|
||||||
return SCPE_IERR;
|
return SCPE_IERR;
|
||||||
if (lp->txlog) { /* logging? */
|
if (lp->txlog) { /* logging? */
|
||||||
fclose (lp->txlog); /* close log */
|
sim_close_logfile (&lp->txlogref); /* close log */
|
||||||
free (lp->txlogname); /* free namebuf */
|
free (lp->txlogname); /* free namebuf */
|
||||||
lp->txlog = NULL;
|
lp->txlog = NULL;
|
||||||
lp->txlogname = NULL;
|
lp->txlogname = NULL;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
Based on the original DZ11 simulator by Thord Nilson, as updated by
|
Based on the original DZ11 simulator by Thord Nilson, as updated by
|
||||||
Arthur Krewat.
|
Arthur Krewat.
|
||||||
|
|
||||||
|
17-Jan-11 MP Added buffered line capabilities
|
||||||
20-Nov-08 RMS Added three new standardized SHOW routines
|
20-Nov-08 RMS Added three new standardized SHOW routines
|
||||||
27-May-08 JDB Added lnorder to TMXR structure,
|
27-May-08 JDB Added lnorder to TMXR structure,
|
||||||
added tmxr_set_lnorder and tmxr_set_lnorder
|
added tmxr_set_lnorder and tmxr_set_lnorder
|
||||||
|
@ -62,11 +63,15 @@ struct tmln {
|
||||||
int32 txbpr; /* xmt buf remove */
|
int32 txbpr; /* xmt buf remove */
|
||||||
int32 txbpi; /* xmt buf insert */
|
int32 txbpi; /* xmt buf insert */
|
||||||
int32 txcnt; /* xmt count */
|
int32 txcnt; /* xmt count */
|
||||||
|
int32 txdrp; /* xmt drop count */
|
||||||
|
int32 txbsz; /* xmt buffer size */
|
||||||
|
int32 txbfd; /* xmt buffered flag */
|
||||||
FILE *txlog; /* xmt log file */
|
FILE *txlog; /* xmt log file */
|
||||||
|
FILEREF *txlogref; /* xmt log file reference */
|
||||||
char *txlogname; /* xmt log file name */
|
char *txlogname; /* xmt log file name */
|
||||||
char rxb[TMXR_MAXBUF]; /* rcv buffer */
|
char rxb[TMXR_MAXBUF]; /* rcv buffer */
|
||||||
char rbr[TMXR_MAXBUF]; /* rcv break */
|
char rbr[TMXR_MAXBUF]; /* rcv break */
|
||||||
char txb[TMXR_MAXBUF]; /* xmt buffer */
|
char *txb; /* xmt buffer */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct tmln TMLN;
|
typedef struct tmln TMLN;
|
||||||
|
@ -78,6 +83,8 @@ struct tmxr {
|
||||||
TMLN *ldsc; /* line descriptors */
|
TMLN *ldsc; /* line descriptors */
|
||||||
int32 *lnorder; /* line connection order */
|
int32 *lnorder; /* line connection order */
|
||||||
DEVICE *dptr; /* multiplexer device */
|
DEVICE *dptr; /* multiplexer device */
|
||||||
|
char logfiletmpl[FILENAME_MAX]; /* template logfile name */
|
||||||
|
int32 buffered; /* Buffered Line Behavior and Buffer Size Flag */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct tmxr TMXR;
|
typedef struct tmxr TMXR;
|
||||||
|
|
Loading…
Add table
Reference in a new issue