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:
parent
ed1a6f313e
commit
0daff9026d
2 changed files with 238 additions and 194 deletions
BIN
doc/simh_doc.doc
BIN
doc/simh_doc.doc
Binary file not shown.
264
scp.c
264
scp.c
|
@ -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];
|
||||
|
||||
t_stat sim_last_cmd_stat; /* Command Status */
|
||||
struct timespec cmd_time; /* */
|
||||
|
||||
static SCHTAB sim_stabr; /* Register 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"
|
||||
" %%CTIME%%, %%DATE_YYYY%%, %%DATE_YY%%, %%DATE_YC%%, %%DATE_MM%%, %%DATE_MMM%%,\n"
|
||||
" %%DATE_MONTH%%, %%DATE_DD%%, %%DATE_D%%, %%DATE_WYYYY%%, %%DATE_WW%%,\n"
|
||||
" %%TIME_HH%%, %%TIME_MM%%, %%TIME_SS%%, %%STATUS%%, %%TSTATUS%%, %%SIM_VERIFY%%,\n"
|
||||
" %%SIM_QUIET%%, %%SIM_MESSAGE%% %%SIM_MESSAGE%%\n"
|
||||
" %%TIME_HH%%, %%TIME_MM%%, %%TIME_SS%%, %%TIME_MSEC%%, %%STATUS%%, %%TSTATUS%%,\n"
|
||||
" %%SIM_VERIFY%%, %%SIM_QUIET%%, %%SIM_MESSAGE%% %%SIM_MESSAGE%%\n"
|
||||
" %%SIM_NAME%%, %%SIM_BIN_NAME%%, %%SIM_BIN_PATH%%m %%SIM_OSTYPE%%\n\n"
|
||||
"+Token %%0 expands to the command file name.\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_MM%% mm (00-59)\n"
|
||||
"++%%TIME_SS%% ss (00-59)\n"
|
||||
"++%%TIME_MSEC%% msec (000-999)\n"
|
||||
"++%%STATUS%% Status value from the last command executed\n"
|
||||
"++%%TSTATUS%% The text form of the last status value\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.
|
||||
*/
|
||||
|
||||
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;
|
||||
char rbuf[CBUFSIZE];
|
||||
int i;
|
||||
size_t instr_off = 0;
|
||||
size_t outstr_off = 0;
|
||||
time_t now;
|
||||
struct tm *tmnow;
|
||||
char tbuf[CBUFSIZE];
|
||||
|
||||
time(&now);
|
||||
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;
|
||||
ap = getenv(gbuf); /* first try using the literal name */
|
||||
if (!ap) {
|
||||
get_glyph (gbuf, tbuf, 0); /* now try using the upcased name */
|
||||
ap = getenv(tbuf);
|
||||
}
|
||||
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 */
|
||||
if (ap) /* environment variable found? */
|
||||
strlcpy (rbuf, ap, rbuf_size); /* Return the environment value */
|
||||
else { /* otherwise, check for Special Names */
|
||||
time_t now = (time_t)cmd_time.tv_sec;
|
||||
struct tm *tmnow = localtime(&now);
|
||||
|
||||
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) {
|
||||
get_glyph (ip+1, gbuf, '%'); /* now try using the upcased name */
|
||||
ap = getenv(gbuf);
|
||||
}
|
||||
ip += 1 + strlen (gbuf);
|
||||
if (*ip == '%') ++ip;
|
||||
if (!ap) {
|
||||
/* ISO 8601 format date/time info */
|
||||
if (!strcmp ("DATE", gbuf)) {
|
||||
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 */
|
||||
else if (!strcmp ("LDATE", gbuf)) {
|
||||
strftime (rbuf, sizeof(rbuf), "%x", tmnow);
|
||||
strftime (rbuf, rbuf_size, "%x", tmnow);
|
||||
ap = rbuf;
|
||||
}
|
||||
else if (!strcmp ("LTIME", gbuf)) {
|
||||
#if defined(HAVE_C99_STRFTIME)
|
||||
strftime (rbuf, sizeof(rbuf), "%r", tmnow);
|
||||
strftime (rbuf, rbuf_size, "%r", tmnow);
|
||||
#else
|
||||
strftime (rbuf, sizeof(rbuf), "%p", tmnow);
|
||||
strftime (rbuf, rbuf_size, "%p", tmnow);
|
||||
if (rbuf[0])
|
||||
strftime (rbuf, sizeof(rbuf), "%I:%M:%S %p", tmnow);
|
||||
strftime (rbuf, rbuf_size, "%I:%M:%S %p", tmnow);
|
||||
else
|
||||
strftime (rbuf, sizeof(rbuf), "%H:%M:%S", tmnow);
|
||||
strftime (rbuf, rbuf_size, "%H:%M:%S", tmnow);
|
||||
#endif
|
||||
ap = rbuf;
|
||||
}
|
||||
else if (!strcmp ("CTIME", gbuf)) {
|
||||
#if defined(HAVE_C99_STRFTIME)
|
||||
strftime (rbuf, sizeof(rbuf), "%c", tmnow);
|
||||
strftime (rbuf, rbuf_size, "%c", tmnow);
|
||||
#else
|
||||
strcpy (rbuf, ctime(&now));
|
||||
rbuf[strlen (rbuf)-1] = '\0'; /* remove trailing \n */
|
||||
|
@ -3766,6 +3686,10 @@ for (; *ip && (op < oend); ) {
|
|||
strftime (rbuf, sizeof(rbuf), "%S", tmnow);
|
||||
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)) {
|
||||
sprintf (rbuf, "%08X", sim_last_cmd_stat);
|
||||
ap = rbuf;
|
||||
|
@ -3791,6 +3715,100 @@ for (; *ip && (op < oend); ) {
|
|||
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? */
|
||||
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)
|
||||
{
|
||||
int32 i;
|
||||
DEVICE *dptr;
|
||||
int32 i, j;
|
||||
DEVICE *dptr, **devs, **dptrptr[] = {sim_devices, sim_internal_devices, NULL};
|
||||
REG *rptr, *srptr = NULL;
|
||||
|
||||
if (stat)
|
||||
*stat = SCPE_OK;
|
||||
*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 */
|
||||
continue;
|
||||
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 */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stat && (*stat != SCPE_OK)) {
|
||||
if (sim_show_message)
|
||||
sim_printf ("\n");
|
||||
|
@ -13609,7 +13629,7 @@ static const char BinaryDigits[] = "01";
|
|||
while (isspace (*cptr))
|
||||
++cptr;
|
||||
if (isalpha (*cptr)) {
|
||||
while (isalnum (*cptr))
|
||||
while (isalnum (*cptr) || (*cptr == '.') || (*cptr == '_'))
|
||||
*buf++ = *cptr++;
|
||||
*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)
|
||||
{
|
||||
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) {
|
||||
*svalue = (t_svalue)get_rval (rptr, 0);
|
||||
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));
|
||||
return TRUE;
|
||||
}
|
||||
gptr = getenv (data);
|
||||
data = (gptr ? gptr : "");
|
||||
gptr = _sim_get_env_special (data, string + 1, string_size - 2);
|
||||
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);
|
||||
snprintf (string, string_size - 1, "\"%s\"", data);
|
||||
|
|
Loading…
Add table
Reference in a new issue