SCP: Add TIME_MSEC predefined variable to provide time to milliseconds

- Assure that Internal variables are referencable during expression evaluation
- Add DEVNAME.REGNAME format for referencing non unique registers in
  expression evaluation.
- Extend global register search to also search known internal device list
  registers
- Allow expression variable names to have _ as a character within in the name
This commit is contained in:
Mark Pizzolato 2018-05-24 01:46:24 -07:00
parent ed1a6f313e
commit 0daff9026d
2 changed files with 238 additions and 194 deletions

Binary file not shown.

264
scp.c
View file

@ -591,6 +591,7 @@ static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1];
static const char *sim_do_label[MAX_DO_NEST_LVL+1]; static const char *sim_do_label[MAX_DO_NEST_LVL+1];
t_stat sim_last_cmd_stat; /* Command Status */ t_stat sim_last_cmd_stat; /* Command Status */
struct timespec cmd_time; /* */
static SCHTAB sim_stabr; /* Register search specifier */ static SCHTAB sim_stabr; /* Register search specifier */
static SCHTAB sim_staba; /* Memory search specifier */ static SCHTAB sim_staba; /* Memory search specifier */
@ -1455,8 +1456,8 @@ static const char simh_help[] =
" Built In variables %%DATE%%, %%TIME%%, %%DATETIME%%, %%LDATE%%, %%LTIME%%,\n" " Built In variables %%DATE%%, %%TIME%%, %%DATETIME%%, %%LDATE%%, %%LTIME%%,\n"
" %%CTIME%%, %%DATE_YYYY%%, %%DATE_YY%%, %%DATE_YC%%, %%DATE_MM%%, %%DATE_MMM%%,\n" " %%CTIME%%, %%DATE_YYYY%%, %%DATE_YY%%, %%DATE_YC%%, %%DATE_MM%%, %%DATE_MMM%%,\n"
" %%DATE_MONTH%%, %%DATE_DD%%, %%DATE_D%%, %%DATE_WYYYY%%, %%DATE_WW%%,\n" " %%DATE_MONTH%%, %%DATE_DD%%, %%DATE_D%%, %%DATE_WYYYY%%, %%DATE_WW%%,\n"
" %%TIME_HH%%, %%TIME_MM%%, %%TIME_SS%%, %%STATUS%%, %%TSTATUS%%, %%SIM_VERIFY%%,\n" " %%TIME_HH%%, %%TIME_MM%%, %%TIME_SS%%, %%TIME_MSEC%%, %%STATUS%%, %%TSTATUS%%,\n"
" %%SIM_QUIET%%, %%SIM_MESSAGE%% %%SIM_MESSAGE%%\n" " %%SIM_VERIFY%%, %%SIM_QUIET%%, %%SIM_MESSAGE%% %%SIM_MESSAGE%%\n"
" %%SIM_NAME%%, %%SIM_BIN_NAME%%, %%SIM_BIN_PATH%%m %%SIM_OSTYPE%%\n\n" " %%SIM_NAME%%, %%SIM_BIN_NAME%%, %%SIM_BIN_PATH%%m %%SIM_OSTYPE%%\n\n"
"+Token %%0 expands to the command file name.\n" "+Token %%0 expands to the command file name.\n"
"+Token %%n (n being a single digit) expands to the n'th argument\n" "+Token %%n (n being a single digit) expands to the n'th argument\n"
@ -1491,6 +1492,7 @@ static const char simh_help[] =
"++%%TIME_HH%% hh (00-23)\n" "++%%TIME_HH%% hh (00-23)\n"
"++%%TIME_MM%% mm (00-59)\n" "++%%TIME_MM%% mm (00-59)\n"
"++%%TIME_SS%% ss (00-59)\n" "++%%TIME_SS%% ss (00-59)\n"
"++%%TIME_MSEC%% msec (000-999)\n"
"++%%STATUS%% Status value from the last command executed\n" "++%%STATUS%% Status value from the last command executed\n"
"++%%TSTATUS%% The text form of the last status value\n" "++%%TSTATUS%% The text form of the last status value\n"
"++%%SIM_VERIFY%% The Verify/Verbose mode of the current Do command file\n" "++%%SIM_VERIFY%% The Verify/Verbose mode of the current Do command file\n"
@ -3537,105 +3539,23 @@ return stat | SCPE_NOMESSAGE; /* suppress message sinc
untouched. untouched.
*/ */
void sim_sub_args (char *instr, size_t instr_size, char *do_arg[]) static const char *
_sim_get_env_special (const char *gbuf, char *rbuf, size_t rbuf_size)
{ {
char gbuf[CBUFSIZE];
char *ip = instr, *op, *oend, *istart, *tmpbuf;
const char *ap; const char *ap;
char rbuf[CBUFSIZE]; char tbuf[CBUFSIZE];
int i;
size_t instr_off = 0;
size_t outstr_off = 0;
time_t now;
struct tm *tmnow;
time(&now); ap = getenv(gbuf); /* first try using the literal name */
tmnow = localtime(&now);
tmpbuf = (char *)malloc(instr_size);
op = tmpbuf;
oend = tmpbuf + instr_size - 2;
if (instr_size > sim_sub_instr_size) {
sim_sub_instr = (char *)realloc (sim_sub_instr, instr_size*sizeof(*sim_sub_instr));
sim_sub_instr_off = (size_t *)realloc (sim_sub_instr_off, instr_size*sizeof(*sim_sub_instr_off));
sim_sub_instr_size = instr_size;
}
sim_sub_instr_buf = instr;
strlcpy (sim_sub_instr, instr, instr_size*sizeof(*sim_sub_instr));
while (sim_isspace (*ip)) { /* skip leading spaces */
sim_sub_instr_off[outstr_off++] = ip - instr;
*op++ = *ip++;
}
/* If entire string is within quotes, strip the quotes */
if ((*ip == '"') || (*ip == '\'')) { /* start with a quote character? */
const char *cptr = ip;
char *tp = op; /* use remainder of output buffer as temp buffer */
cptr = get_glyph_quoted (cptr, tp, 0); /* get quoted string */
while (sim_isspace (*cptr))
++cptr; /* skip over trailing spaces */
if (*cptr == '\0') { /* full string was quoted? */
uint32 dsize;
if (SCPE_OK == sim_decode_quoted_string (tp, (uint8 *)tp, &dsize)) {
tp[dsize] = '\0';
while (sim_isspace (*tp))
memmove (tp, tp + 1, strlen (tp));
strlcpy (ip, tp, instr_size - (ip - instr));/* copy quoted contents to input buffer */
strlcpy (sim_sub_instr + (ip - instr), tp, instr_size - (ip - instr));
}
}
}
istart = ip;
for (; *ip && (op < oend); ) {
if ((ip [0] == '%') && (ip [1] == '%')) { /* literal % insert? */
sim_sub_instr_off[outstr_off++] = ip - instr;
ip++; /* skip one */
*op++ = *ip++; /* copy insert % */
}
else
if ((*ip == '%') &&
(sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {/* sub? */
if ((ip[1] >= '0') && (ip[1] <= ('9'))) { /* %n = sub */
ap = do_arg[ip[1] - '0'];
for (i=0; i<ip[1] - '0'; ++i) /* make sure we're not past the list end */
if (do_arg[i] == NULL) {
ap = NULL;
break;
}
ip = ip + 2;
}
else if (ip[1] == '*') { /* %1 ... %9 = sub */
memset (rbuf, '\0', sizeof(rbuf));
ap = rbuf;
for (i=1; i<=9; ++i)
if (do_arg[i] == NULL)
break;
else
if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
if (strchr(do_arg[i], ' ')) { /* need to surround this argument with quotes */
char quote = '"';
if (strchr(do_arg[i], quote))
quote = '\'';
sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"", (i != 1) ? " " : "", quote, do_arg[i], quote);
}
else
sprintf(&rbuf[strlen(rbuf)], "%s%s", (i != 1) ? " " : "", do_arg[i]);
}
else
break;
ip = ip + 2;
}
else { /* environment variable */
ap = NULL;
get_glyph_nc (ip+1, gbuf, '%'); /* first try using the literal name */
ap = getenv(gbuf);
if (!ap) { if (!ap) {
get_glyph (ip+1, gbuf, '%'); /* now try using the upcased name */ get_glyph (gbuf, tbuf, 0); /* now try using the upcased name */
ap = getenv(gbuf); ap = getenv(tbuf);
} }
ip += 1 + strlen (gbuf); if (ap) /* environment variable found? */
if (*ip == '%') ++ip; strlcpy (rbuf, ap, rbuf_size); /* Return the environment value */
if (!ap) { else { /* otherwise, check for Special Names */
time_t now = (time_t)cmd_time.tv_sec;
struct tm *tmnow = localtime(&now);
/* ISO 8601 format date/time info */ /* ISO 8601 format date/time info */
if (!strcmp ("DATE", gbuf)) { if (!strcmp ("DATE", gbuf)) {
sprintf (rbuf, "%4d-%02d-%02d", tmnow->tm_year+1900, tmnow->tm_mon+1, tmnow->tm_mday); sprintf (rbuf, "%4d-%02d-%02d", tmnow->tm_year+1900, tmnow->tm_mon+1, tmnow->tm_mday);
@ -3651,24 +3571,24 @@ for (; *ip && (op < oend); ) {
} }
/* Locale oriented formatted date/time info */ /* Locale oriented formatted date/time info */
else if (!strcmp ("LDATE", gbuf)) { else if (!strcmp ("LDATE", gbuf)) {
strftime (rbuf, sizeof(rbuf), "%x", tmnow); strftime (rbuf, rbuf_size, "%x", tmnow);
ap = rbuf; ap = rbuf;
} }
else if (!strcmp ("LTIME", gbuf)) { else if (!strcmp ("LTIME", gbuf)) {
#if defined(HAVE_C99_STRFTIME) #if defined(HAVE_C99_STRFTIME)
strftime (rbuf, sizeof(rbuf), "%r", tmnow); strftime (rbuf, rbuf_size, "%r", tmnow);
#else #else
strftime (rbuf, sizeof(rbuf), "%p", tmnow); strftime (rbuf, rbuf_size, "%p", tmnow);
if (rbuf[0]) if (rbuf[0])
strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow); strftime (rbuf, rbuf_size, "%I:%M:%S %p", tmnow);
else else
strftime (rbuf, sizeof(rbuf), "%H:%M:%S", tmnow); strftime (rbuf, rbuf_size, "%H:%M:%S", tmnow);
#endif #endif
ap = rbuf; ap = rbuf;
} }
else if (!strcmp ("CTIME", gbuf)) { else if (!strcmp ("CTIME", gbuf)) {
#if defined(HAVE_C99_STRFTIME) #if defined(HAVE_C99_STRFTIME)
strftime (rbuf, sizeof(rbuf), "%c", tmnow); strftime (rbuf, rbuf_size, "%c", tmnow);
#else #else
strcpy (rbuf, ctime(&now)); strcpy (rbuf, ctime(&now));
rbuf[strlen (rbuf)-1] = '\0'; /* remove trailing \n */ rbuf[strlen (rbuf)-1] = '\0'; /* remove trailing \n */
@ -3766,6 +3686,10 @@ for (; *ip && (op < oend); ) {
strftime (rbuf, sizeof(rbuf), "%S", tmnow); strftime (rbuf, sizeof(rbuf), "%S", tmnow);
ap = rbuf; ap = rbuf;
} }
else if (!strcmp ("TIME_MSEC", gbuf)) {/* Milliseconds of Second (000-999) */
sprintf (rbuf, "%03d", (int)(cmd_time.tv_nsec / 1000000));
ap = rbuf;
}
else if (!strcmp ("STATUS", gbuf)) { else if (!strcmp ("STATUS", gbuf)) {
sprintf (rbuf, "%08X", sim_last_cmd_stat); sprintf (rbuf, "%08X", sim_last_cmd_stat);
ap = rbuf; ap = rbuf;
@ -3791,6 +3715,100 @@ for (; *ip && (op < oend); ) {
ap = rbuf; ap = rbuf;
} }
} }
return ap;
}
void sim_sub_args (char *instr, size_t instr_size, char *do_arg[])
{
char gbuf[CBUFSIZE];
char *ip = instr, *op, *oend, *istart, *tmpbuf;
const char *ap;
char rbuf[CBUFSIZE];
int i;
size_t instr_off = 0;
size_t outstr_off = 0;
clock_gettime(CLOCK_REALTIME, &cmd_time);
tmpbuf = (char *)malloc(instr_size);
op = tmpbuf;
oend = tmpbuf + instr_size - 2;
if (instr_size > sim_sub_instr_size) {
sim_sub_instr = (char *)realloc (sim_sub_instr, instr_size*sizeof(*sim_sub_instr));
sim_sub_instr_off = (size_t *)realloc (sim_sub_instr_off, instr_size*sizeof(*sim_sub_instr_off));
sim_sub_instr_size = instr_size;
}
sim_sub_instr_buf = instr;
strlcpy (sim_sub_instr, instr, instr_size*sizeof(*sim_sub_instr));
while (sim_isspace (*ip)) { /* skip leading spaces */
sim_sub_instr_off[outstr_off++] = ip - instr;
*op++ = *ip++;
}
/* If entire string is within quotes, strip the quotes */
if ((*ip == '"') || (*ip == '\'')) { /* start with a quote character? */
const char *cptr = ip;
char *tp = op; /* use remainder of output buffer as temp buffer */
cptr = get_glyph_quoted (cptr, tp, 0); /* get quoted string */
while (sim_isspace (*cptr))
++cptr; /* skip over trailing spaces */
if (*cptr == '\0') { /* full string was quoted? */
uint32 dsize;
if (SCPE_OK == sim_decode_quoted_string (tp, (uint8 *)tp, &dsize)) {
tp[dsize] = '\0';
while (sim_isspace (*tp))
memmove (tp, tp + 1, strlen (tp));
strlcpy (ip, tp, instr_size - (ip - instr));/* copy quoted contents to input buffer */
strlcpy (sim_sub_instr + (ip - instr), tp, instr_size - (ip - instr));
}
}
}
istart = ip;
for (; *ip && (op < oend); ) {
if ((ip [0] == '%') && (ip [1] == '%')) { /* literal % insert? */
sim_sub_instr_off[outstr_off++] = ip - instr;
ip++; /* skip one */
*op++ = *ip++; /* copy insert % */
}
else
if ((*ip == '%') &&
(sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {/* sub? */
if ((ip[1] >= '0') && (ip[1] <= ('9'))) { /* %n = sub */
ap = do_arg[ip[1] - '0'];
for (i=0; i<ip[1] - '0'; ++i) /* make sure we're not past the list end */
if (do_arg[i] == NULL) {
ap = NULL;
break;
}
ip = ip + 2;
}
else if (ip[1] == '*') { /* %1 ... %9 = sub */
memset (rbuf, '\0', sizeof(rbuf));
ap = rbuf;
for (i=1; i<=9; ++i)
if (do_arg[i] == NULL)
break;
else
if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
if (strchr(do_arg[i], ' ')) { /* need to surround this argument with quotes */
char quote = '"';
if (strchr(do_arg[i], quote))
quote = '\'';
sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"", (i != 1) ? " " : "", quote, do_arg[i], quote);
}
else
sprintf(&rbuf[strlen(rbuf)], "%s%s", (i != 1) ? " " : "", do_arg[i]);
}
else
break;
ip = ip + 2;
}
else { /* check environment variable or special variables */
get_glyph_nc (ip+1, gbuf, '%'); /* get the literal name */
ap = _sim_get_env_special (gbuf, rbuf, sizeof (rbuf));
ip += 1 + strlen (gbuf);
if (*ip == '%')
++ip;
} }
if (ap) { /* non-null arg? */ if (ap) { /* non-null arg? */
while (*ap && (op < oend)) { /* copy the argument */ while (*ap && (op < oend)) { /* copy the argument */
@ -9368,14 +9386,15 @@ return (dptr->flags & DEV_DIS? TRUE: FALSE);
REG *find_reg_glob_reason (CONST char *cptr, CONST char **optr, DEVICE **gdptr, t_stat *stat) REG *find_reg_glob_reason (CONST char *cptr, CONST char **optr, DEVICE **gdptr, t_stat *stat)
{ {
int32 i; int32 i, j;
DEVICE *dptr; DEVICE *dptr, **devs, **dptrptr[] = {sim_devices, sim_internal_devices, NULL};
REG *rptr, *srptr = NULL; REG *rptr, *srptr = NULL;
if (stat) if (stat)
*stat = SCPE_OK; *stat = SCPE_OK;
*gdptr = NULL; *gdptr = NULL;
for (i = 0; (dptr = sim_devices[i]) != 0; i++) { /* all dev */ for (j = 0; (devs = dptrptr[j]) != NULL; j++) {
for (i = 0; (dptr = devs[i]) != NULL; i++) { /* all dev */
if (dptr->flags & DEV_DIS) /* skip disabled */ if (dptr->flags & DEV_DIS) /* skip disabled */
continue; continue;
if ((rptr = find_reg (cptr, optr, dptr))) { /* found? */ if ((rptr = find_reg (cptr, optr, dptr))) { /* found? */
@ -9396,6 +9415,7 @@ for (i = 0; (dptr = sim_devices[i]) != 0; i++) { /* all dev */
*gdptr = dptr; /* save unit */ *gdptr = dptr; /* save unit */
} }
} }
}
if (stat && (*stat != SCPE_OK)) { if (stat && (*stat != SCPE_OK)) {
if (sim_show_message) if (sim_show_message)
sim_printf ("\n"); sim_printf ("\n");
@ -13609,7 +13629,7 @@ static const char BinaryDigits[] = "01";
while (isspace (*cptr)) while (isspace (*cptr))
++cptr; ++cptr;
if (isalpha (*cptr)) { if (isalpha (*cptr)) {
while (isalnum (*cptr)) while (isalnum (*cptr) || (*cptr == '.') || (*cptr == '_'))
*buf++ = *cptr++; *buf++ = *cptr++;
*buf = '\0'; *buf = '\0';
} }
@ -13784,9 +13804,26 @@ return cptr; /* return any unprocessed input */
static t_bool _value_of (const char *data, t_svalue *svalue, char *string, size_t string_size) static t_bool _value_of (const char *data, t_svalue *svalue, char *string, size_t string_size)
{ {
CONST char *gptr; CONST char *gptr;
if (isalpha (*data)) {
REG *rptr = find_reg (data, &gptr, sim_dfdev);
if (isalpha (*data)) {
REG *rptr;
DEVICE *dptr = sim_dfdev;
const char *dot;
dot = strchr (data, '.');
if (dot) {
char devnam[CBUFSIZE];
memcpy (devnam, data, dot - data);
devnam[dot - data] = '\0';
if (find_dev (devnam)) {
dptr = find_dev (devnam);
data = dot + 1;
rptr = find_reg (data, &gptr, dptr);
}
}
else
rptr = find_reg_glob (data, &gptr, &dptr);
if (rptr) { if (rptr) {
*svalue = (t_svalue)get_rval (rptr, 0); *svalue = (t_svalue)get_rval (rptr, 0);
sprint_val (string + 1, *svalue, 10, string_size - 2, PV_LEFTSIGN); sprint_val (string + 1, *svalue, 10, string_size - 2, PV_LEFTSIGN);
@ -13794,8 +13831,15 @@ if (isalpha (*data)) {
strlcpy (&string[strlen (string)], "\"", string_size - strlen (string)); strlcpy (&string[strlen (string)], "\"", string_size - strlen (string));
return TRUE; return TRUE;
} }
gptr = getenv (data); gptr = _sim_get_env_special (data, string + 1, string_size - 2);
data = (gptr ? gptr : ""); if (gptr) {
*svalue = strtotsv(string + 1, &gptr, 0);
*string = '"';
strlcpy (&string[strlen (string)], "\"", string_size - strlen (string));
return (*gptr == '\0');
}
else
data = "";
} }
*svalue = strtotsv(data, &gptr, 0); *svalue = strtotsv(data, &gptr, 0);
snprintf (string, string_size - 1, "\"%s\"", data); snprintf (string, string_size - 1, "\"%s\"", data);