From 568a80dfb8f7d043d5e622095965a5bfa5feca69 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 28 Sep 2018 15:43:01 -0700 Subject: [PATCH] SCP: Add parsing of file specs in environment variables and DO command args. --- scp.c | 139 +++++++++++++++++++++++++++++++++++++----------------- sim_fio.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sim_fio.h | 3 ++ 3 files changed, 235 insertions(+), 43 deletions(-) diff --git a/scp.c b/scp.c index e14a13fa..7adfa7f3 100644 --- a/scp.c +++ b/scp.c @@ -1567,6 +1567,31 @@ static const char simh_help[] = "+would extract the last 10 characters of the XYZ variable.\n\n" "++%%XYZ:~0,-2%%\n\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" "3GOTO\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 */ *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= '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) { ap = NULL; break; } - ip = ip + 2; + ++ip; } - 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 { + if (*ip == '*') { /* %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 - 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 == '%') + break; + } ++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? */ + char *expanded = NULL; + + if (expand_it) { + expanded = sim_filepath_parts (ap, parts); + ap = expanded; + } while (*ap && (op < oend)) { /* copy the argument */ sim_sub_instr_off[outstr_off++] = ip - instr; *op++ = *ap++; } + free (expanded); } } - else + else { if (ip == istart) { /* at beginning of input? */ get_glyph (istart, gbuf, 0); /* substitute initial token */ 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; *op++ = *ip++; /* literal character */ } + } + } } *op = 0; /* term buffer */ sim_sub_instr_off[outstr_off] = 0; @@ -4344,6 +4393,17 @@ if (Exist || (*gbuf == '"') || (*gbuf == '\'')) { /* quoted string compari else { 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) fclose (f); 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) { char buffer[PATH_MAX]; -char *wd = getcwd(buffer, PATH_MAX); +char *wd = sim_getcwd(buffer, PATH_MAX); + fprintf (st, "%s\n", wd); return SCPE_OK; } @@ -6189,11 +6250,7 @@ strlcpy (WildName, cptr, sizeof(WildName)); cptr = WildName; sim_trim_endspc (WildName); if ((*cptr != '/') || (0 == memcmp (cptr, "./", 2)) || (0 == memcmp (cptr, "../", 3))) { -#if defined (VMS) - getcwd (WholeName, sizeof (WholeName)-1, 0); -#else - getcwd (WholeName, sizeof (WholeName)-1); -#endif + sim_getcwd (WholeName, sizeof (WholeName)-1); strlcat (WholeName, "/", sizeof (WholeName)); strlcat (WholeName, cptr, sizeof (WholeName)); sim_trim_endspc (WholeName); @@ -6219,11 +6276,7 @@ if (c) { DirName[1+c-WholeName] = '\0'; } else { -#if defined (VMS) - getcwd (WholeName, sizeof (WholeName)-1, 0); -#else - getcwd (WholeName, sizeof (WholeName)-1); -#endif + sim_getcwd (WholeName, sizeof (WholeName)-1); } cptr = WholeName; #if defined (HAVE_GLOB) diff --git a/sim_fio.c b/sim_fio.c index 6d10a8eb..29594036 100644 --- a/sim_fio.c +++ b/sim_fio.c @@ -404,6 +404,7 @@ return sim_messagef (SCPE_ARG, "Error Copying '%s' to '%s': %s\n", source_file, } #include +#include int sim_set_fsize (FILE *fptr, t_addr size) { return _chsize(_fileno(fptr), (long)size); @@ -723,3 +724,138 @@ va_end (arglist); return 0; } #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; +} diff --git a/sim_fio.h b/sim_fio.h index 5f3b0e74..a959d137 100644 --- a/sim_fio.h +++ b/sim_fio.h @@ -70,6 +70,9 @@ t_offset sim_ftell (FILE *st); t_offset sim_fsize_ex (FILE *fptr); 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); +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_copy_swapped (void *dptr, const void *bptr, size_t size, size_t count); const char *sim_get_os_error_text (int error);