SCP: Provide an API to display alternate error message text while returning SCPE status.

This commit is contained in:
Mark Pizzolato 2014-12-31 14:32:10 -08:00
parent 813d8f6290
commit 6ec6b6ab1f
2 changed files with 117 additions and 56 deletions

172
scp.c
View file

@ -504,6 +504,7 @@ int32 sim_do_depth = 0;
static int32 sim_on_check[MAX_DO_NEST_LVL+1]; static int32 sim_on_check[MAX_DO_NEST_LVL+1];
static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1]; static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1];
static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE]; static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE];
static char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
static char *sim_do_label[MAX_DO_NEST_LVL+1]; static char *sim_do_label[MAX_DO_NEST_LVL+1];
static t_stat sim_last_cmd_stat; /* Command Status */ static t_stat sim_last_cmd_stat; /* Command Status */
@ -1980,6 +1981,8 @@ while (stat != SCPE_EXIT) { /* in case exit */
sim_sub_args (cbuf, sizeof(cbuf), argv); sim_sub_args (cbuf, sizeof(cbuf), argv);
if (sim_log) /* log cmd */ if (sim_log) /* log cmd */
fprintf (sim_log, "%s%s\n", sim_prompt, cptr); fprintf (sim_log, "%s%s\n", sim_prompt, cptr);
if (sim_deb && (sim_deb != sim_log))
fprintf (sim_deb, "%s%s\n", sim_prompt, cptr);
cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */
sim_switches = 0; /* init switches */ sim_switches = 0; /* init switches */
if ((cmdp = find_cmd (gbuf))) /* lookup command */ if ((cmdp = find_cmd (gbuf))) /* lookup command */
@ -2612,7 +2615,6 @@ int32 saved_sim_do_echo = sim_do_echo,
saved_sim_quiet = sim_quiet; saved_sim_quiet = sim_quiet;
t_bool staying; t_bool staying;
t_stat stat, stat_nomessage; t_stat stat, stat_nomessage;
char *ocptr;
stat = SCPE_OK; stat = SCPE_OK;
staying = TRUE; staying = TRUE;
@ -2694,9 +2696,9 @@ if (errabort) /* -e flag? */
set_on (1, NULL); /* equivalent to ON ERROR RETURN */ set_on (1, NULL); /* equivalent to ON ERROR RETURN */
do { do {
ocptr = cptr = sim_brk_getact (cbuf, sizeof(cbuf)); /* get bkpt action */ sim_do_ocptr[sim_do_depth] = cptr = sim_brk_getact (cbuf, sizeof(cbuf)); /* get bkpt action */
if (!ocptr) { /* no pending action? */ if (!sim_do_ocptr[sim_do_depth]) { /* no pending action? */
ocptr = cptr = read_line (cbuf, sizeof(cbuf), fpin);/* get cmd line */ sim_do_ocptr[sim_do_depth] = cptr = read_line (cbuf, sizeof(cbuf), fpin);/* get cmd line */
sim_goto_line[sim_do_depth] += 1; sim_goto_line[sim_do_depth] += 1;
} }
sim_sub_args (cbuf, sizeof(cbuf), do_arg); /* substitute args */ sim_sub_args (cbuf, sizeof(cbuf), do_arg); /* substitute args */
@ -2759,12 +2761,12 @@ do {
if (!echo && !sim_quiet && /* report if not echoing */ if (!echo && !sim_quiet && /* report if not echoing */
!stat_nomessage && /* and not suppressing messages */ !stat_nomessage && /* and not suppressing messages */
!(cmdp && cmdp->message)) { /* and not handling them specially */ !(cmdp && cmdp->message)) { /* and not handling them specially */
sim_printf("%s> %s\n", do_position(), ocptr); sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
} }
} }
if (!stat_nomessage) { /* report error if not suppressed */ if (!stat_nomessage) { /* report error if not suppressed */
if (cmdp && cmdp->message) /* special message handler */ if (cmdp && cmdp->message) /* special message handler */
cmdp->message ((!echo && !sim_quiet) ? ocptr : NULL, stat); cmdp->message ((!echo && !sim_quiet) ? sim_do_ocptr[sim_do_depth] : NULL, stat);
else else
if (stat >= SCPE_BASE) /* report error if not suppressed */ if (stat >= SCPE_BASE) /* report error if not suppressed */
sim_printf ("%s\n", sim_error_text (stat)); sim_printf ("%s\n", sim_error_text (stat));
@ -3186,10 +3188,8 @@ if (*cptr == '"') { /* quoted string compari
for (optr = compare_ops; optr->op; optr++) for (optr = compare_ops; optr->op; optr++)
if (0 == strcmp (op, optr->op)) if (0 == strcmp (op, optr->op))
break; break;
if (!optr->op) { if (!optr->op)
sim_printf ("Invalid operator: %s\n", op); return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op);
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr += strlen (op); cptr += strlen (op);
while (isspace (*cptr)) /* skip spaces */ while (isspace (*cptr)) /* skip spaces */
++cptr; ++cptr;
@ -3330,20 +3330,16 @@ else
while (*cptr) { while (*cptr) {
if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) { if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) {
delay = (uint32)get_uint (&gbuf[6], 10, 10000000, &r); delay = (uint32)get_uint (&gbuf[6], 10, 10000000, &r);
if (r != SCPE_OK) { if (r != SCPE_OK)
sim_printf ("Invalid Delay Value\n"); return sim_messagef (SCPE_ARG, "Invalid Delay Value\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = tptr; cptr = tptr;
tptr = get_glyph (cptr, gbuf, ','); tptr = get_glyph (cptr, gbuf, ',');
continue; continue;
} }
if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) { if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) {
after = (uint32)get_uint (&gbuf[6], 10, 10000000, &r); after = (uint32)get_uint (&gbuf[6], 10, 10000000, &r);
if (r != SCPE_OK) { if (r != SCPE_OK)
sim_printf ("Invalid After Value\n"); return sim_messagef (SCPE_ARG, "Invalid After Value\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = tptr; cptr = tptr;
tptr = get_glyph (cptr, gbuf, ','); tptr = get_glyph (cptr, gbuf, ',');
continue; continue;
@ -3353,18 +3349,14 @@ while (*cptr) {
return SCPE_ARG; return SCPE_ARG;
} }
if (*cptr) { if (*cptr) {
if ((*cptr != '"') && (*cptr != '\'')) { if ((*cptr != '"') && (*cptr != '\''))
sim_printf ("String must be quote delimited\n"); return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = get_glyph_quoted (cptr, gbuf, 0); cptr = get_glyph_quoted (cptr, gbuf, 0);
if (*cptr != '\0') if (*cptr != '\0')
return SCPE_2MARG; /* No more arguments */ return SCPE_2MARG; /* No more arguments */
if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize)) { if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize))
sim_printf ("Invalid String\n"); return sim_messagef (SCPE_ARG, "Invalid String\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
} }
if ((dsize == 0) && (delay == 0) && (after == 0)) if ((dsize == 0) && (delay == 0) && (after == 0))
return SCPE_2FARG; return SCPE_2FARG;
@ -4586,10 +4578,8 @@ if (sim_is_running)
if ((!cptr) || (*cptr == 0)) if ((!cptr) || (*cptr == 0))
return SCPE_2FARG; return SCPE_2FARG;
sim_trim_endspc(cptr); sim_trim_endspc(cptr);
if (chdir(cptr) != 0) { if (chdir(cptr) != 0)
sim_printf("Unable to directory change to: %s\n", cptr); return sim_messagef(SCPE_IOERR, "Unable to directory change to: %s\n", cptr);
return SCPE_IOERR & SCPE_NOMESSAGE;
}
return SCPE_OK; return SCPE_OK;
} }
@ -8739,10 +8729,8 @@ if ((cptr == NULL) || (*cptr == 0))
return SCPE_2FARG; return SCPE_2FARG;
if (*cptr == '[') { if (*cptr == '[') {
cnt = (int32) strtotv (cptr + 1, &c1ptr, 10); cnt = (int32) strtotv (cptr + 1, &c1ptr, 10);
if ((cptr == c1ptr) || (*c1ptr != ']')) { if ((cptr == c1ptr) || (*c1ptr != ']'))
sim_printf ("Invalid Repeat count specification\n"); return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = (char *)(c1ptr + 1); cptr = (char *)(c1ptr + 1);
while (isspace(*cptr)) while (isspace(*cptr))
++cptr; ++cptr;
@ -8750,16 +8738,12 @@ if (*cptr == '[') {
tptr = get_glyph (cptr, gbuf, ','); tptr = get_glyph (cptr, gbuf, ',');
if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) { if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) {
after = (uint32)get_uint (&gbuf[10], 10, 100000000, &r); after = (uint32)get_uint (&gbuf[10], 10, 100000000, &r);
if (r != SCPE_OK) { if (r != SCPE_OK)
sim_printf ("Invalid Halt After Value\n"); return sim_messagef (SCPE_ARG, "Invalid Halt After Value\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = tptr; cptr = tptr;
} }
if ((*cptr != '"') && (*cptr != '\'')) { if ((*cptr != '"') && (*cptr != '\''))
sim_printf ("String must be quote delimited\n"); return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = get_glyph_quoted (cptr, gbuf, 0); cptr = get_glyph_quoted (cptr, gbuf, 0);
return sim_exp_set (exp, gbuf, cnt, (after ? after : exp->after), sim_switches, cptr); return sim_exp_set (exp, gbuf, cnt, (after ? after : exp->after), sim_switches, cptr);
@ -8773,10 +8757,8 @@ char gbuf[CBUFSIZE];
if (!cptr || !*cptr) if (!cptr || !*cptr)
return sim_exp_clrall (exp); /* clear all rules */ return sim_exp_clrall (exp); /* clear all rules */
if ((*cptr != '"') && (*cptr != '\'')) { if ((*cptr != '"') && (*cptr != '\''))
sim_printf ("String must be quote delimited\n"); return sim_messagef (SCPE_ARG, "String must be quote delimited\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
cptr = get_glyph_quoted (cptr, gbuf, 0); cptr = get_glyph_quoted (cptr, gbuf, 0);
if (*cptr != '\0') if (*cptr != '\0')
return SCPE_2MARG; /* No more arguments */ return SCPE_2MARG; /* No more arguments */
@ -8864,8 +8846,7 @@ if (!match_buf)
if (switches & EXP_TYP_REGEX) { if (switches & EXP_TYP_REGEX) {
#if !defined (USE_REGEX) #if !defined (USE_REGEX)
free (match_buf); free (match_buf);
sim_printf ("RegEx support not available\n"); return sim_messagef (SCPE_ARG, "RegEx support not available\n");
return SCPE_ARG|SCPE_NOMESSAGE; /* RegEx not available */
} }
#else /* USE_REGEX */ #else /* USE_REGEX */
int res; int res;
@ -8880,7 +8861,7 @@ if (switches & EXP_TYP_REGEX) {
char *err_buf = calloc (err_size+1, 1); char *err_buf = calloc (err_size+1, 1);
regerror (res, &re, err_buf, err_size); regerror (res, &re, err_buf, err_size);
sim_printf ("Regular Expression Error: %s\n", err_buf); sim_messagef (SCPE_ARG, "Regular Expression Error: %s\n", err_buf);
free (err_buf); free (err_buf);
free (match_buf); free (match_buf);
return SCPE_ARG|SCPE_NOMESSAGE; return SCPE_ARG|SCPE_NOMESSAGE;
@ -8891,22 +8872,20 @@ if (switches & EXP_TYP_REGEX) {
#endif #endif
else { else {
if (switches & EXP_TYP_REGEX_I) { if (switches & EXP_TYP_REGEX_I) {
sim_printf ("Case independed matching is only valid for RegEx expect rules\n"); free (match_buf);
return SCPE_ARG|SCPE_NOMESSAGE; return sim_messagef (SCPE_ARG, "Case independed matching is only valid for RegEx expect rules\n");
} }
if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) { if (SCPE_OK != sim_decode_quoted_string (match, match_buf, &match_size)) {
free (match_buf); free (match_buf);
return SCPE_ARG; return sim_messagef (SCPE_ARG, "Invalid quoted string\n");
} }
} }
free (match_buf); free (match_buf);
ep = sim_exp_fnd (exp, match); /* present? */ ep = sim_exp_fnd (exp, match); /* present? */
if (ep) /* no, allocate */ if (ep) /* no, allocate */
sim_exp_clr_tab (exp, ep); /* clear it */ sim_exp_clr_tab (exp, ep); /* clear it */
if (after && exp->size) { if (after && exp->size)
sim_printf ("Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n"); return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n");
return SCPE_ARG|SCPE_NOMESSAGE;
}
exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1)); exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1));
ep = &exp->rules[exp->size]; ep = &exp->rules[exp->size];
exp->size += 1; exp->size += 1;
@ -9490,6 +9469,87 @@ if (buf != stackbuf)
free (buf); free (buf);
} }
/* Print command result message to stdout, sim_log (if enabled) and sim_deb (if enabled) */
t_stat sim_messagef (t_stat stat, const char* fmt, ...)
{
char stackbuf[STACKBUFSIZE];
int32 bufsize = sizeof(stackbuf);
char *buf = stackbuf;
int32 len;
va_list arglist;
t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE));
while (1) { /* format passed string, args */
va_start (arglist, fmt);
#if defined(NO_vsnprintf)
#if defined(HAS_vsprintf_void)
/* Note, this could blow beyond the buffer, and we couldn't tell */
/* That is a limitation of the C runtime library available on this platform */
vsprintf (buf, fmt, arglist);
for (len = 0; len < bufsize-1; len++)
if (buf[len] == 0) break;
#else
len = vsprintf (buf, fmt, arglist);
#endif /* HAS_vsprintf_void */
#else /* NO_vsnprintf */
#if defined(HAS_vsnprintf_void)
vsnprintf (buf, bufsize-1, fmt, arglist);
for (len = 0; len < bufsize-1; len++)
if (buf[len] == 0) break;
#else
len = vsnprintf (buf, bufsize-1, fmt, arglist);
#endif /* HAS_vsnprintf_void */
#endif /* NO_vsnprintf */
va_end (arglist);
/* If the formatted result didn't fit into the buffer, then grow the buffer and try again */
if ((len < 0) || (len >= bufsize-1)) {
if (buf != stackbuf)
free (buf);
bufsize = bufsize * 2;
buf = (char *) malloc (bufsize);
if (buf == NULL) /* out of memory */
return SCPE_MEM;
buf[bufsize-1] = '\0';
continue;
}
break;
}
if (sim_do_ocptr[sim_do_depth]) {
if (!sim_do_echo && !sim_quiet && !inhibit_message)
sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
else {
if (sim_deb) /* Always put context in debug output */
fprintf (sim_deb, "%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]);
}
}
if (sim_is_running && !inhibit_message) {
char *c, *remnant = buf;
while ((c = strchr(remnant, '\n'))) {
printf("%.*s\r\n", (int)(c-remnant), remnant);
remnant = c + 1;
}
printf("%s", remnant);
}
else {
if (!inhibit_message)
printf("%s", buf);
}
if (sim_log && (sim_log != stdout) && !inhibit_message)
fprintf (sim_log, "%s", buf);
if (sim_deb && (((sim_deb != stdout) && (sim_deb != sim_log)) || inhibit_message))/* Always display messages in debug output */
fprintf (sim_deb, "%s", buf);
if (buf != stackbuf)
free (buf);
return stat | SCPE_NOMESSAGE;
}
/* Inline debugging - will print debug message if debug file is /* Inline debugging - will print debug message if debug file is
set and the bitmask matches the current device debug options. set and the bitmask matches the current device debug options.
Extra returns are added for un*x systems, since the output Extra returns are added for un*x systems, since the output

1
scp.h
View file

@ -178,6 +178,7 @@ const char *sim_error_text (t_stat stat);
t_stat sim_string_to_stat (char *cptr, t_stat *cond); t_stat sim_string_to_stat (char *cptr, t_stat *cond);
t_stat sim_cancel_step (void); t_stat sim_cancel_step (void);
void sim_printf (const char* fmt, ...); void sim_printf (const char* fmt, ...);
t_stat sim_messagef (t_stat stat, const char* fmt, ...);
void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason); void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason);
void sim_debug_bits (uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs, void sim_debug_bits (uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
uint32 before, uint32 after, int terminate); uint32 before, uint32 after, int terminate);