Make vmsify support files with no directory component.
authorCraig A. Berry <craigberry@mac.com>
Wed, 6 Feb 2013 01:04:23 +0000 (19:04 -0600)
committerCraig A. Berry <craigberry@mac.com>
Wed, 6 Feb 2013 01:04:23 +0000 (19:04 -0600)
We've been assuming there is always a directory portion to a path
being converted to VMS format, and it's true that translating
directory delimiters and such is the most noticeable aspect of
such conversions.  But we also depend on the conversion to add
caret escapes to characters in the path that are only valid when
using Extended Filename Syntax (EFS), but weren't doing that
for paths with no directory component.

I.e., this was working:

/disk/dir/foo%bar --> disk:[dir]foo^%bar

but this was not (until now):

foo%bar --> foo^%bar

Since we're now working on a pointer that has not necessarily
been incremented while adding directory syntax, we also add
a number of guards to make sure we don't peek beyond the
beginning of the result string.

N.B.  There will be a separate commit following shortly that
prevents paths with no directory component from being passed
through as-is -- here we just provide the infrastructure to
make that possible.

vms/vms.c

index b92b7da..c5ad229 100644 (file)
--- a/vms/vms.c
+++ b/vms/vms.c
@@ -8499,7 +8499,7 @@ static char *int_tovmsspec
     }
     PerlMem_free(trndev);
   }
-  else {
+  else if (hasdir) {
     *(cp1++) = '[';
     if (*cp2 == '.') {
       if (*(cp2+1) == '/' || *(cp2+1) == '\0') {
@@ -8524,18 +8524,21 @@ static char *int_tovmsspec
     }
     else *(cp1++) = '.';
   }
+  else {
+    *(cp1++) = *cp2;
+  }
   for (; cp2 < dirend; cp2++) {
     if (*cp2 == '/') {
       if (*(cp2-1) == '/') continue;
-      if (*(cp1-1) != '.') *(cp1++) = '.';
+      if (cp1 > rslt && *(cp1-1) != '.') *(cp1++) = '.';
       infront = 0;
     }
     else if (!infront && *cp2 == '.') {
       if (cp2+1 == dirend || *(cp2+1) == '\0') { cp2++; break; }
       else if (*(cp2+1) == '/') cp2++;   /* skip over "./" - it's redundant */
       else if (*(cp2+1) == '.' && (*(cp2+2) == '/' || *(cp2+2) == '\0')) {
-        if (*(cp1-1) == '-' || *(cp1-1) == '[') *(cp1++) = '-'; /* handle "../" */
-        else if (*(cp1-2) == '[') *(cp1-1) = '-';
+        if (cp1 > rslt && (*(cp1-1) == '-' || *(cp1-1) == '[')) *(cp1++) = '-'; /* handle "../" */
+        else if (cp1 > rslt + 1 && *(cp1-2) == '[') *(cp1-1) = '-';
         else {
           *(cp1++) = '-';
         }
@@ -8544,7 +8547,7 @@ static char *int_tovmsspec
       }
       else if ( *(cp2+1) == '.' && *(cp2+2) == '.' &&
                 (*(cp2+3) == '/' || *(cp2+3) == '\0') ) {
-        if (*(cp1-1) != '.') *(cp1++) = '.'; /* May already have 1 from '/' */
+        if (cp1 > rslt && *(cp1-1) != '.') *(cp1++) = '.'; /* May already have 1 from '/' */
         *(cp1++) = '.'; *(cp1++) = '.'; /* ".../" --> "..." */
         if (!*(cp2+3)) { 
           *(cp1++) = '.';  /* Simulate trailing '/' */
@@ -8554,7 +8557,7 @@ static char *int_tovmsspec
       }
       else {
         if (decc_efs_charset == 0) {
-         if (*(cp1-1) == '^')
+         if (cp1 > rslt && *(cp1-1) == '^')
            cp1--;         /* remove the escape, if any */
          *(cp1++) = '_';  /* fix up syntax - '.' in name not allowed */
        }
@@ -8564,10 +8567,10 @@ static char *int_tovmsspec
       }
     }
     else {
-      if (!infront && *(cp1-1) == '-')  *(cp1++) = '.';
+      if (!infront && cp1 > rslt && *(cp1-1) == '-')  *(cp1++) = '.';
       if (*cp2 == '.') {
         if (decc_efs_charset == 0) {
-         if (*(cp1-1) == '^')
+         if (cp1 > rslt && *(cp1-1) == '^')
            cp1--;         /* remove the escape, if any */
          *(cp1++) = '_';
        }
@@ -8579,7 +8582,7 @@ static char *int_tovmsspec
       infront = 1;
     }
   }
-  if (*(cp1-1) == '.') cp1--; /* Unix spec ending in '/' ==> trailing '.' */
+  if (cp1 > rslt && *(cp1-1) == '.') cp1--; /* Unix spec ending in '/' ==> trailing '.' */
   if (hasdir) *(cp1++) = ']';
   if (*cp2) cp2++;  /* check in case we ended with trailing '..' */
   /* fixme for ODS5 */