summaryrefslogtreecommitdiff
path: root/vms/vms.c
diff options
context:
space:
mode:
authorCraig A. Berry <craigberry@mac.com>2012-07-05 18:22:46 -0500
committerCraig A. Berry <craigberry@mac.com>2012-07-05 21:16:32 -0500
commit22831cc58b7641c7a2f9dfe9514021980919e264 (patch)
treea1e271af98c308753013b5e0d35a4932297effb8 /vms/vms.c
parentc2900bb8185ddf2411dcf67573ec1c2e991d6dba (diff)
downloadperl-22831cc58b7641c7a2f9dfe9514021980919e264.tar.gz
Unquote spawned command verbs on VMS.
Prior to the current change, $ foo "A" "b" "c" worked, but the following didn't: $ "foo" "A" "b" "c" %DCL-E-PARSEFAIL, error parsing DCL$PATH:"foo".* -RMS-F-FNM, error in file name even if foo was a valid command or path. It's illegal in DCL to quote the command verb even if it's often necessary to quote the parameters to it. But various things in the wild (such as Test::Harness::_filtered_inc), find it convenient or necessary to quote the command verb, so the easiest way to support that is to unquote it before DCL sees it, and that's what this change does. Also, spaces within the first quoted item are now escaped so that an image path containing spaces doesn't run afoul of subsequent tokenizing based on spaces.
Diffstat (limited to 'vms/vms.c')
-rw-r--r--vms/vms.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/vms/vms.c b/vms/vms.c
index a235a10b95..97778029eb 100644
--- a/vms/vms.c
+++ b/vms/vms.c
@@ -10467,6 +10467,68 @@ setup_cmddsc(pTHX_ const char *incmd, int check_img, int *suggest_quote,
for (cp = &vmsspec[1]; *rest && isspace(*rest); rest++,cp++) *cp = *rest;
}
else { cp = vmsspec; rest = s; }
+
+ /* If the first word is quoted, then we need to unquote it and
+ * escape spaces within it. We'll expand into the resspec buffer,
+ * then copy back into the cmd buffer, expanding the latter if
+ * necessary.
+ */
+ if (*rest == '"') {
+ char *cp2;
+ char *r = rest;
+ bool in_quote = 0;
+ int clen = cmdlen;
+ int soff = s - cmd;
+
+ for (cp2 = resspec;
+ *rest && cp2 - resspec < (VMS_MAXRSS - 1);
+ rest++) {
+
+ if (*rest == ' ') { /* Escape ' ' to '^_'. */
+ *cp2 = '^';
+ *(++cp2) = '_';
+ cp2++;
+ clen++;
+ }
+ else if (*rest == '"') {
+ clen--;
+ if (in_quote) { /* Must be closing quote. */
+ rest++;
+ break;
+ }
+ in_quote = 1;
+ }
+ else {
+ *cp2 = *rest;
+ cp2++;
+ }
+ }
+ *cp2 = '\0';
+
+ /* Expand the command buffer if necessary. */
+ if (clen > cmdlen) {
+ cmd = PerlMem_realloc(cmd, clen);
+ if (cmd == NULL)
+ _ckvmssts_noperl(SS$_INSFMEM);
+ /* Where we are may have changed, so recompute offsets */
+ r = cmd + (r - s - soff);
+ rest = cmd + (rest - s - soff);
+ s = cmd + soff;
+ }
+
+ /* Shift the non-verb portion of the command (if any) up or
+ * down as necessary.
+ */
+ if (*rest)
+ memmove(rest + clen - cmdlen, rest, s - soff + cmdlen - rest);
+
+ /* Copy the unquoted and escaped command verb into place. */
+ memcpy(r, resspec, cp2 - resspec);
+ cmd[clen] = '\0';
+ cmdlen = clen;
+ rest = r; /* Rewind for subsequent operations. */
+ }
+
if (*rest == '.' || *rest == '/') {
char *cp2;
for (cp2 = resspec;