SCP: Add parsing of file specs in environment variables and DO command args.
This commit is contained in:
parent
9a716a7689
commit
568a80dfb8
3 changed files with 235 additions and 43 deletions
139
scp.c
139
scp.c
|
@ -1567,6 +1567,31 @@ static const char simh_help[] =
|
||||||
"+would extract the last 10 characters of the XYZ variable.\n\n"
|
"+would extract the last 10 characters of the XYZ variable.\n\n"
|
||||||
"++%%XYZ:~0,-2%%\n\n"
|
"++%%XYZ:~0,-2%%\n\n"
|
||||||
"+would extract all but the last 2 characters of the XYZ variable.\n"
|
"+would extract all but the last 2 characters of the XYZ variable.\n"
|
||||||
|
"4Parameter and Environment Variable File Parsing\n"
|
||||||
|
" The value of environment variables can be parsed as filenames\n"
|
||||||
|
" and have their values be expanded to full paths and/or into pieces.\n"
|
||||||
|
" Parsing and expansion of file names.\n\n"
|
||||||
|
"++%%~I%% - expands the value of %%I%% removing any surrounding quotes (\")\n"
|
||||||
|
"++%%~fI%% - expands the value of %%I%% to a fully qualified path name\n"
|
||||||
|
"++%%~pI%% - expands the value of %%I%% to a path only\n"
|
||||||
|
"++%%~nI%% - expands the value of %%I%% to a file name only\n"
|
||||||
|
"++%%~xI%% - expands the value of %%I%% to a file extension only\n\n"
|
||||||
|
" The modifiers can be combined to get compound results:\n\n"
|
||||||
|
"++%%~pnI%% - expands the value of %%I%% to a path and name only\n"
|
||||||
|
"++%%~nxI%% - expands the value of %%I%% to a file name and extension only\n\n"
|
||||||
|
" In the above example above %%I%% can be replaced by other\n"
|
||||||
|
" environment variables or numeric parameters to a DO command\n"
|
||||||
|
" invokation.\n"
|
||||||
|
" Examples:\n\n"
|
||||||
|
"++sim> set env FNAME='xyzzy.ini'\n"
|
||||||
|
"++sim> echo ~FNAME=%%~FNAME%%\n"
|
||||||
|
"++xyzzy.ini\n"
|
||||||
|
"++sim> echo ~fFNAME=%%~fFNAME%%\n"
|
||||||
|
"++~fFNAME=/home/user/xyzzy.ini\n"
|
||||||
|
"++sim> echo ~nxFNAME=%%~nxFNAME%%\n"
|
||||||
|
"++~nxFNAME=xyzzy.ini\n"
|
||||||
|
"++sim> echo ~fFNAME=%%~pnFNAME%%\n"
|
||||||
|
"++~pnFNAME=/home/user/xyzzy\n\n"
|
||||||
#define HLP_GOTO "*Commands Executing_Command_Files GOTO"
|
#define HLP_GOTO "*Commands Executing_Command_Files GOTO"
|
||||||
"3GOTO\n"
|
"3GOTO\n"
|
||||||
" Commands in a command file execute in sequence until either an error\n"
|
" Commands in a command file execute in sequence until either an error\n"
|
||||||
|
@ -4057,54 +4082,76 @@ for (; *ip && (op < oend); ) {
|
||||||
ip++; /* skip one */
|
ip++; /* skip one */
|
||||||
*op++ = *ip++; /* copy insert % */
|
*op++ = *ip++; /* copy insert % */
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
if ((*ip == '%') &&
|
t_bool expand_it = FALSE;
|
||||||
(sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {/* sub? */
|
char parts[32];
|
||||||
if ((ip[1] >= '0') && (ip[1] <= ('9'))) { /* %n = sub */
|
|
||||||
ap = do_arg[ip[1] - '0'];
|
if (*ip == '%') {
|
||||||
for (i=0; i<ip[1] - '0'; ++i) /* make sure we're not past the list end */
|
ap = NULL;
|
||||||
|
++ip;
|
||||||
|
if (*ip == '~') {
|
||||||
|
expand_it = TRUE;
|
||||||
|
++ip;
|
||||||
|
for (i=0; (i < (sizeof (parts) - 1)) && (strchr ("fpnx", *ip)); i++, ip++) {
|
||||||
|
parts[i] = *ip;
|
||||||
|
parts[i + 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((*ip >= '0') && (*ip <= ('9'))) { /* %n = sub */
|
||||||
|
ap = do_arg[*ip - '0'];
|
||||||
|
for (i=0; i<*ip - '0'; ++i) /* make sure we're not past the list end */
|
||||||
if (do_arg[i] == NULL) {
|
if (do_arg[i] == NULL) {
|
||||||
ap = NULL;
|
ap = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ip = ip + 2;
|
++ip;
|
||||||
}
|
}
|
||||||
else if (ip[1] == '*') { /* %1 ... %9 = sub */
|
else {
|
||||||
memset (rbuf, '\0', sizeof(rbuf));
|
if (*ip == '*') { /* %1 ... %9 = sub */
|
||||||
ap = rbuf;
|
memset (rbuf, '\0', sizeof(rbuf));
|
||||||
for (i=1; i<=9; ++i)
|
ap = rbuf;
|
||||||
if (do_arg[i] == NULL)
|
for (i=1; i<=9; ++i) {
|
||||||
break;
|
if (do_arg[i] == NULL)
|
||||||
else
|
break;
|
||||||
if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
|
else
|
||||||
if (strchr(do_arg[i], ' ')) { /* need to surround this argument with quotes */
|
if ((sizeof(rbuf)-strlen(rbuf)) < (2 + strlen(do_arg[i]))) {
|
||||||
char quote = '"';
|
if (strchr(do_arg[i], ' ')) { /* need to surround this argument with quotes */
|
||||||
if (strchr(do_arg[i], quote))
|
char quote = '"';
|
||||||
quote = '\'';
|
if (strchr(do_arg[i], quote))
|
||||||
sprintf(&rbuf[strlen(rbuf)], "%s%c%s%c\"", (i != 1) ? " " : "", quote, 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
|
else
|
||||||
sprintf(&rbuf[strlen(rbuf)], "%s%s", (i != 1) ? " " : "", do_arg[i]);
|
break;
|
||||||
}
|
}
|
||||||
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;
|
++ip;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
get_glyph_nc (ip, gbuf, '%'); /* get the literal name */
|
||||||
|
ap = _sim_get_env_special (gbuf, rbuf, sizeof (rbuf));
|
||||||
|
ip += strlen (gbuf);
|
||||||
|
if (*ip == '%')
|
||||||
|
++ip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ap) { /* non-null arg? */
|
if (ap) { /* non-null arg? */
|
||||||
|
char *expanded = NULL;
|
||||||
|
|
||||||
|
if (expand_it) {
|
||||||
|
expanded = sim_filepath_parts (ap, parts);
|
||||||
|
ap = expanded;
|
||||||
|
}
|
||||||
while (*ap && (op < oend)) { /* copy the argument */
|
while (*ap && (op < oend)) { /* copy the argument */
|
||||||
sim_sub_instr_off[outstr_off++] = ip - instr;
|
sim_sub_instr_off[outstr_off++] = ip - instr;
|
||||||
*op++ = *ap++;
|
*op++ = *ap++;
|
||||||
}
|
}
|
||||||
|
free (expanded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 */
|
||||||
|
@ -4123,6 +4170,8 @@ for (; *ip && (op < oend); ) {
|
||||||
sim_sub_instr_off[outstr_off++] = ip - instr;
|
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;
|
sim_sub_instr_off[outstr_off] = 0;
|
||||||
|
@ -4344,6 +4393,17 @@ if (Exist || (*gbuf == '"') || (*gbuf == '\'')) { /* quoted string compari
|
||||||
else {
|
else {
|
||||||
FILE *f = fopen (gbuf, "r");
|
FILE *f = fopen (gbuf, "r");
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
if (((gbuf[0] == '"') || (gbuf[0] == '\'')) && /* quoted? */
|
||||||
|
(gbuf[0] == gbuf[strlen (gbuf) - 1])) {
|
||||||
|
char *without_quotes = sim_filepath_parts (gbuf, "f");
|
||||||
|
|
||||||
|
if (without_quotes) {
|
||||||
|
f = fopen (without_quotes, "r");
|
||||||
|
free (without_quotes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (f)
|
if (f)
|
||||||
fclose (f);
|
fclose (f);
|
||||||
result = (f != NULL);
|
result = (f != NULL);
|
||||||
|
@ -6092,7 +6152,8 @@ return SCPE_OK;
|
||||||
t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
|
t_stat show_default (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char buffer[PATH_MAX];
|
||||||
char *wd = getcwd(buffer, PATH_MAX);
|
char *wd = sim_getcwd(buffer, PATH_MAX);
|
||||||
|
|
||||||
fprintf (st, "%s\n", wd);
|
fprintf (st, "%s\n", wd);
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
@ -6189,11 +6250,7 @@ strlcpy (WildName, cptr, sizeof(WildName));
|
||||||
cptr = WildName;
|
cptr = WildName;
|
||||||
sim_trim_endspc (WildName);
|
sim_trim_endspc (WildName);
|
||||||
if ((*cptr != '/') || (0 == memcmp (cptr, "./", 2)) || (0 == memcmp (cptr, "../", 3))) {
|
if ((*cptr != '/') || (0 == memcmp (cptr, "./", 2)) || (0 == memcmp (cptr, "../", 3))) {
|
||||||
#if defined (VMS)
|
sim_getcwd (WholeName, sizeof (WholeName)-1);
|
||||||
getcwd (WholeName, sizeof (WholeName)-1, 0);
|
|
||||||
#else
|
|
||||||
getcwd (WholeName, sizeof (WholeName)-1);
|
|
||||||
#endif
|
|
||||||
strlcat (WholeName, "/", sizeof (WholeName));
|
strlcat (WholeName, "/", sizeof (WholeName));
|
||||||
strlcat (WholeName, cptr, sizeof (WholeName));
|
strlcat (WholeName, cptr, sizeof (WholeName));
|
||||||
sim_trim_endspc (WholeName);
|
sim_trim_endspc (WholeName);
|
||||||
|
@ -6219,11 +6276,7 @@ if (c) {
|
||||||
DirName[1+c-WholeName] = '\0';
|
DirName[1+c-WholeName] = '\0';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if defined (VMS)
|
sim_getcwd (WholeName, sizeof (WholeName)-1);
|
||||||
getcwd (WholeName, sizeof (WholeName)-1, 0);
|
|
||||||
#else
|
|
||||||
getcwd (WholeName, sizeof (WholeName)-1);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
cptr = WholeName;
|
cptr = WholeName;
|
||||||
#if defined (HAVE_GLOB)
|
#if defined (HAVE_GLOB)
|
||||||
|
|
136
sim_fio.c
136
sim_fio.c
|
@ -404,6 +404,7 @@ return sim_messagef (SCPE_ARG, "Error Copying '%s' to '%s': %s\n", source_file,
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#include <direct.h>
|
||||||
int sim_set_fsize (FILE *fptr, t_addr size)
|
int sim_set_fsize (FILE *fptr, t_addr size)
|
||||||
{
|
{
|
||||||
return _chsize(_fileno(fptr), (long)size);
|
return _chsize(_fileno(fptr), (long)size);
|
||||||
|
@ -723,3 +724,138 @@ va_end (arglist);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
char *sim_getcwd (char *buf, size_t buf_size)
|
||||||
|
{
|
||||||
|
#if defined (VMS)
|
||||||
|
return getcwd (buf, buf_size, 0);
|
||||||
|
#else
|
||||||
|
return getcwd (buf, buf_size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parsing and expansion of file names.
|
||||||
|
*
|
||||||
|
* %~I% - expands the value of %I% removing any surrounding quotes (")
|
||||||
|
* %~fI% - expands the value of %I% to a fully qualified path name
|
||||||
|
* %~pI% - expands the value of %I% to a path only
|
||||||
|
* %~nI% - expands the value of %I% to a file name only
|
||||||
|
* %~xI% - expands the value of %I% to a file extension only
|
||||||
|
*
|
||||||
|
* The modifiers can be combined to get compound results:
|
||||||
|
*
|
||||||
|
* %~pnI% - expands the value of %I% to a path and name only
|
||||||
|
* %~nxI% - expands the value of %I% to a file name and extension only
|
||||||
|
*
|
||||||
|
* In the above example above %I% can be replaced by other
|
||||||
|
* environment variables or numeric parameters to a DO command
|
||||||
|
* invokation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char *sim_filepath_parts (const char *filepath, const char *parts)
|
||||||
|
{
|
||||||
|
size_t tot_len = 0, tot_size = 0;
|
||||||
|
char *tempfilepath = NULL;
|
||||||
|
char *fullpath = NULL, *result = NULL;
|
||||||
|
char *c, *name, *ext;
|
||||||
|
char chr;
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
if (((*filepath == '\'') || (*filepath == '"')) &&
|
||||||
|
(filepath[strlen (filepath) - 1] == *filepath)) {
|
||||||
|
tempfilepath = malloc (1 + strlen (filepath));
|
||||||
|
if (tempfilepath == NULL)
|
||||||
|
return NULL;
|
||||||
|
strlcpy (tempfilepath, 1 + filepath, 1 + strlen (filepath));
|
||||||
|
tempfilepath[strlen (tempfilepath) - 1] = '\0';
|
||||||
|
filepath = tempfilepath;
|
||||||
|
}
|
||||||
|
if ((filepath[1] == ':') ||
|
||||||
|
(filepath[0] == '/') ||
|
||||||
|
(filepath[0] == '\\')){
|
||||||
|
tot_len = 1 + strlen (filepath);
|
||||||
|
fullpath = malloc (tot_len);
|
||||||
|
if (fullpath == NULL)
|
||||||
|
return NULL;
|
||||||
|
strcpy (fullpath, filepath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char dir[PATH_MAX+1] = "";
|
||||||
|
char *wd = sim_getcwd(dir, sizeof (dir));
|
||||||
|
|
||||||
|
if (wd == NULL)
|
||||||
|
return NULL;
|
||||||
|
tot_len = 1 + strlen (filepath) + 1 + strlen (dir);
|
||||||
|
fullpath = malloc (tot_len);
|
||||||
|
if (fullpath == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
strlcpy (fullpath, dir, tot_len);
|
||||||
|
strlcat (fullpath, "/", tot_len);
|
||||||
|
strlcat (fullpath, filepath, tot_len);
|
||||||
|
}
|
||||||
|
while ((c = strchr (fullpath, '\\'))) /* standardize on / directory separator */
|
||||||
|
*c = '/';
|
||||||
|
while ((c = strstr (fullpath, "//"))) /* strip out redundant / characters */
|
||||||
|
memmove (c, c + 1, 1 + strlen (c + 1));
|
||||||
|
while ((c = strstr (fullpath, "/./"))) /* strip out irrelevant /./ sequences */
|
||||||
|
memmove (c, c + 2, 1 + strlen (c + 2));
|
||||||
|
while ((c = strstr (fullpath, "/../"))) { /* process up directory climbing */
|
||||||
|
char *cl = c -1;
|
||||||
|
|
||||||
|
while ((*cl != '/') && (cl > fullpath))
|
||||||
|
--cl;
|
||||||
|
if (*cl == '/')
|
||||||
|
memmove (cl, c + 3, 1 + strlen (c + 3));
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
name = 1 + strrchr (fullpath, '/');
|
||||||
|
ext = strrchr (name, '.');
|
||||||
|
if (ext == NULL)
|
||||||
|
ext = name + strlen (name);
|
||||||
|
for (p = parts, tot_size = 0; *p; p++) {
|
||||||
|
switch (*p) {
|
||||||
|
case 'f':
|
||||||
|
tot_size += strlen (fullpath);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
tot_size += name - fullpath;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
tot_size += ext - name;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
tot_size += strlen (ext);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = malloc (1 + tot_size);
|
||||||
|
*result = '\0';
|
||||||
|
for (p = parts; *p; p++) {
|
||||||
|
switch (*p) {
|
||||||
|
case 'f':
|
||||||
|
strlcat (result, fullpath, 1 + tot_size);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
chr = *name;
|
||||||
|
*name = '\0';
|
||||||
|
strlcat (result, fullpath, 1 + tot_size);
|
||||||
|
*name = chr;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
chr = *ext;
|
||||||
|
*ext = '\0';
|
||||||
|
strlcat (result, name, 1 + tot_size);
|
||||||
|
*ext = chr;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
strlcat (result, ext, 1 + tot_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free (fullpath);
|
||||||
|
free (tempfilepath);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -70,6 +70,9 @@ t_offset sim_ftell (FILE *st);
|
||||||
t_offset sim_fsize_ex (FILE *fptr);
|
t_offset sim_fsize_ex (FILE *fptr);
|
||||||
t_offset sim_fsize_name_ex (const char *fname);
|
t_offset sim_fsize_name_ex (const char *fname);
|
||||||
t_stat sim_copyfile (const char *source_file, const char *dest_file, t_bool overwrite_existing);
|
t_stat sim_copyfile (const char *source_file, const char *dest_file, t_bool overwrite_existing);
|
||||||
|
char *sim_filepath_parts (const char *pathname, const char *parts);
|
||||||
|
char *sim_getcwd (char *buf, size_t buf_size);
|
||||||
|
|
||||||
void sim_buf_swap_data (void *bptr, size_t size, size_t count);
|
void sim_buf_swap_data (void *bptr, size_t size, size_t count);
|
||||||
void sim_buf_copy_swapped (void *dptr, const void *bptr, size_t size, size_t count);
|
void sim_buf_copy_swapped (void *dptr, const void *bptr, size_t size, size_t count);
|
||||||
const char *sim_get_os_error_text (int error);
|
const char *sim_get_os_error_text (int error);
|
||||||
|
|
Loading…
Add table
Reference in a new issue