SCP: Add parsing of file specs in environment variables and DO command args.

This commit is contained in:
Mark Pizzolato 2018-09-28 15:43:01 -07:00
parent 9a716a7689
commit 568a80dfb8
3 changed files with 235 additions and 43 deletions

139
scp.c
View file

@ -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
View file

@ -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;
}

View file

@ -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);