SCP: Change command argument processing of %% and \% to be consistent.
%% now inserts a bare % and \\ only means something when parsing a quoted string argument (used by EXPECT and SEND commands). Additionally, EXPECT and BREAK commands have action steps which will now expand arguments as each of the actions are executed rather than when the EXPECT or BREAK command is defined.
This commit is contained in:
parent
d02de5156f
commit
c8a420ad48
3 changed files with 47 additions and 17 deletions
|
@ -319,8 +319,8 @@ Built In variables %DATE%, %TIME%, %DATETIME%, %LDATE%, %LTIME%, %CTIME%, %DATE_
|
||||||
Token %n (n being a single digit) expands to the n'th argument
|
Token %n (n being a single digit) expands to the n'th argument
|
||||||
Token %* expands to the whole set of arguments (%1 ... %9)
|
Token %* expands to the whole set of arguments (%1 ... %9)
|
||||||
|
|
||||||
The input sequence "\%" represents a literal "%", and "\\" represents a
|
The input sequence "%%" represents a literal "%". All other
|
||||||
literal "\". All other character combinations are rendered literally.
|
character combinations are rendered literally.
|
||||||
|
|
||||||
Omitted parameters result in null-string substitutions.
|
Omitted parameters result in null-string substitutions.
|
||||||
|
|
||||||
|
|
BIN
doc/simh_doc.doc
BIN
doc/simh_doc.doc
Binary file not shown.
60
scp.c
60
scp.c
|
@ -557,6 +557,10 @@ int32 sim_brk_lnt = 0;
|
||||||
int32 sim_brk_ins = 0;
|
int32 sim_brk_ins = 0;
|
||||||
int32 sim_quiet = 0;
|
int32 sim_quiet = 0;
|
||||||
int32 sim_step = 0;
|
int32 sim_step = 0;
|
||||||
|
char *sim_sub_instr = NULL;
|
||||||
|
char *sim_sub_instr_buf = NULL;
|
||||||
|
size_t sim_sub_instr_size = 0;
|
||||||
|
size_t *sim_sub_instr_off = NULL;
|
||||||
static double sim_time;
|
static double sim_time;
|
||||||
static uint32 sim_rtime;
|
static uint32 sim_rtime;
|
||||||
static int32 noqueue_time;
|
static int32 noqueue_time;
|
||||||
|
@ -1371,8 +1375,8 @@ static const char simh_help[] =
|
||||||
"+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"
|
||||||
"+Token %%* expands to the whole set of arguments (%%1 ... %%9)\n\n"
|
"+Token %%* expands to the whole set of arguments (%%1 ... %%9)\n\n"
|
||||||
"+The input sequence \"%%%%\" represents a literal \"%%\", and \"\\\\\" represents a\n"
|
"+The input sequence \"%%%%\" represents a literal \"%%\". All other\n"
|
||||||
"+literal \"\\\". All other character combinations are rendered literally.\n\n"
|
"+character combinations are rendered literally.\n\n"
|
||||||
"+Omitted parameters result in null-string substitutions.\n\n"
|
"+Omitted parameters result in null-string substitutions.\n\n"
|
||||||
"+Tokens preceeded and followed by %% characters are expanded as environment\n"
|
"+Tokens preceeded and followed by %% characters are expanded as environment\n"
|
||||||
"+variables, and if an environment variable isn't found then it can be one of\n"
|
"+variables, and if an environment variable isn't found then it can be one of\n"
|
||||||
|
@ -3193,8 +3197,8 @@ return stat | SCPE_NOMESSAGE; /* suppress message sinc
|
||||||
Token %n (n being a single digit) expands to the n'th argument
|
Token %n (n being a single digit) expands to the n'th argument
|
||||||
Tonen %* expands to the whole set of arguments (%1 ... %9)
|
Tonen %* expands to the whole set of arguments (%1 ... %9)
|
||||||
|
|
||||||
The input sequence "\%" represents a literal "%", and "\\" represents a
|
The input sequence "%%" represents a literal "%". All other
|
||||||
literal "\". All other character combinations are rendered literally.
|
character combinations are rendered literally.
|
||||||
|
|
||||||
Omitted parameters result in null-string substitutions.
|
Omitted parameters result in null-string substitutions.
|
||||||
|
|
||||||
|
@ -3231,6 +3235,8 @@ char *ip = instr, *op, *oend, *istart, *tmpbuf;
|
||||||
const char *ap;
|
const char *ap;
|
||||||
char rbuf[CBUFSIZE];
|
char rbuf[CBUFSIZE];
|
||||||
int i;
|
int i;
|
||||||
|
size_t instr_off = 0;
|
||||||
|
size_t outstr_off = 0;
|
||||||
time_t now;
|
time_t now;
|
||||||
struct tm *tmnow;
|
struct tm *tmnow;
|
||||||
|
|
||||||
|
@ -3239,14 +3245,23 @@ tmnow = localtime(&now);
|
||||||
tmpbuf = (char *)malloc(instr_size);
|
tmpbuf = (char *)malloc(instr_size);
|
||||||
op = tmpbuf;
|
op = tmpbuf;
|
||||||
oend = tmpbuf + instr_size - 2;
|
oend = tmpbuf + instr_size - 2;
|
||||||
while (sim_isspace (*ip)) /* skip leading spaces */
|
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++;
|
*op++ = *ip++;
|
||||||
|
}
|
||||||
istart = ip;
|
istart = ip;
|
||||||
for (; *ip && (op < oend); ) {
|
for (; *ip && (op < oend); ) {
|
||||||
if ((ip [0] == '\\') && /* literal escape? */
|
if ((ip [0] == '%') && (ip [1] == '%')) { /* literal % insert? */
|
||||||
((ip [1] == '%') || (ip [1] == '\\'))) { /* and followed by '%' or '\'? */
|
sim_sub_instr_off[outstr_off++] = ip - instr;
|
||||||
ip++; /* skip '\' */
|
ip++; /* skip one */
|
||||||
*op++ = *ip++; /* copy escaped char */
|
*op++ = *ip++; /* copy insert % */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if ((*ip == '%') &&
|
if ((*ip == '%') &&
|
||||||
|
@ -3449,26 +3464,34 @@ for (; *ip && (op < oend); ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ap) { /* non-null arg? */
|
if (ap) { /* non-null arg? */
|
||||||
while (*ap && (op < oend)) /* copy the argument */
|
while (*ap && (op < oend)) { /* copy the argument */
|
||||||
|
sim_sub_instr_off[outstr_off++] = ip - instr;
|
||||||
*op++ = *ap++;
|
*op++ = *ap++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
if (ip == istart) { /* at beginning of input? */
|
if (ip == istart) { /* at beginning of input? */
|
||||||
get_glyph (istart, gbuf, 0); /* substitute initial token */
|
get_glyph (istart, gbuf, 0); /* substitute initial token */
|
||||||
ap = getenv(gbuf); /* if it is an environment variable name */
|
ap = getenv(gbuf); /* if it is an environment variable name */
|
||||||
if (!ap) { /* nope? */
|
if (!ap) { /* nope? */
|
||||||
|
sim_sub_instr_off[outstr_off++] = ip - instr;
|
||||||
*op++ = *ip++; /* press on with literal character */
|
*op++ = *ip++; /* press on with literal character */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
while (*ap && (op < oend)) /* copy the translation */
|
while (*ap && (op < oend)) { /* copy the translation */
|
||||||
|
sim_sub_instr_off[outstr_off++] = ip - instr;
|
||||||
*op++ = *ap++;
|
*op++ = *ap++;
|
||||||
|
}
|
||||||
ip += strlen(gbuf);
|
ip += strlen(gbuf);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
|
sim_sub_instr_off[outstr_off++] = ip - instr;
|
||||||
*op++ = *ip++; /* literal character */
|
*op++ = *ip++; /* literal character */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
*op = 0; /* term buffer */
|
*op = 0; /* term buffer */
|
||||||
|
sim_sub_instr_off[outstr_off] = 0;
|
||||||
strcpy (instr, tmpbuf);
|
strcpy (instr, tmpbuf);
|
||||||
free (tmpbuf);
|
free (tmpbuf);
|
||||||
return;
|
return;
|
||||||
|
@ -5582,12 +5605,15 @@ if (uptr == NULL)
|
||||||
max = uptr->capac - 1;
|
max = uptr->capac - 1;
|
||||||
abuf[sizeof(abuf)-1] = '\0';
|
abuf[sizeof(abuf)-1] = '\0';
|
||||||
strncpy (abuf, cptr, sizeof(abuf)-1);
|
strncpy (abuf, cptr, sizeof(abuf)-1);
|
||||||
cptr = abuf;
|
|
||||||
if ((aptr = strchr (abuf, ';'))) { /* ;action? */
|
if ((aptr = strchr (abuf, ';'))) { /* ;action? */
|
||||||
|
cptr += aptr - abuf + 1;
|
||||||
if (flg != SSH_ST) /* only on SET */
|
if (flg != SSH_ST) /* only on SET */
|
||||||
return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", aptr);
|
return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", cptr);
|
||||||
*aptr++ = 0; /* separate strings */
|
*aptr++ = 0; /* separate strings */
|
||||||
|
if ((cptr > sim_sub_instr_buf) && ((size_t)(cptr - sim_sub_instr_buf) < sim_sub_instr_size))
|
||||||
|
aptr = &sim_sub_instr[sim_sub_instr_off[cptr - sim_sub_instr_buf]]; /* get un-substituted string */
|
||||||
}
|
}
|
||||||
|
cptr = abuf;
|
||||||
if (*cptr == 0) { /* no argument? */
|
if (*cptr == 0) { /* no argument? */
|
||||||
lo = (t_addr) get_rval (sim_PC, 0); /* use PC */
|
lo = (t_addr) get_rval (sim_PC, 0); /* use PC */
|
||||||
return ssh_break_one (st, flg, lo, 0, aptr);
|
return ssh_break_one (st, flg, lo, 0, aptr);
|
||||||
|
@ -10608,7 +10634,11 @@ if (ep->act) { /* replace old action? *
|
||||||
if (act)
|
if (act)
|
||||||
while (sim_isspace(*act)) ++act; /* skip leading spaces in action string */
|
while (sim_isspace(*act)) ++act; /* skip leading spaces in action string */
|
||||||
if ((act != NULL) && (*act != 0)) { /* new action? */
|
if ((act != NULL) && (*act != 0)) { /* new action? */
|
||||||
char *newp = (char *) calloc (strlen (act)+1, sizeof (*act)); /* alloc buf */
|
char *newp;
|
||||||
|
|
||||||
|
if ((act > sim_sub_instr_buf) && ((size_t)(act - sim_sub_instr_buf) < sim_sub_instr_size))
|
||||||
|
act = &sim_sub_instr[sim_sub_instr_off[act - sim_sub_instr_buf]]; /* get un-substituted string */
|
||||||
|
newp = (char *) calloc (strlen (act)+1, sizeof (*act)); /* alloc buf */
|
||||||
if (newp == NULL) /* mem err? */
|
if (newp == NULL) /* mem err? */
|
||||||
return SCPE_MEM;
|
return SCPE_MEM;
|
||||||
strcpy (newp, act); /* copy action */
|
strcpy (newp, act); /* copy action */
|
||||||
|
|
Loading…
Add table
Reference in a new issue