Better escaping of dots in tovmsspec.
authorCraig A. Berry <craigberry@mac.com>
Sun, 2 Dec 2012 21:17:55 +0000 (15:17 -0600)
committerCraig A. Berry <craigberry@mac.com>
Sun, 2 Dec 2012 21:17:55 +0000 (15:17 -0600)
When converting a filename with multiple dots to native VMS syntax,
it's necessary to escape all but the last dot with a caret ('^').
We've been doing this for some time, but have been doing it blindly
such that multiple trips through the converter resulted in a
stuttering caret problem (e.g., foo^^^.bar.pl when foo^.bar.pl was
intended).

So create a convenience macro that does the escaping and make it
only escape unescaped instances and also make it check that the
escape doesn't push us off the end of the buffer we are working
on.

Use the new macro in the three most obvious places that it's
applicable.  There may be other places that also should use it.

vms/vms.c

index 38c4ff1..43496ef 100644 (file)
--- a/vms/vms.c
+++ b/vms/vms.c
@@ -8248,7 +8248,20 @@ int utf8_flag;
    return result;
 }
 
-
+/* A convenience macro for escaping dots that haven't already been
+ * escaped, with guards to avoid checking before the start of the
+ * buffer or advancing beyond the end of it (allowing room for the
+ * NUL terminator).
+ */
+#define VMSEFS_ESCAPE_DOT(vmsefsdot,vmsefsbuf,vmsefsbufsiz) STMT_START { \
+    if ( ((vmsefsdot) > (vmsefsbuf) && *((vmsefsdot) - 1) != '^' \
+          || ((vmsefsdot) == (vmsefsbuf))) \
+         && (vmsefsdot) < (vmsefsbuf) + (vmsefsbufsiz) - 2 \
+       ) { \
+        *((vmsefsdot)++) = '^'; \
+        *((vmsefsdot)++) = '.'; \
+    } \
+} STMT_END
 
 /*{{{ char *tovmsspec[_ts](char *path, char *buf, int * utf8_flag)*/
 static char *int_tovmsspec
@@ -8536,8 +8549,7 @@ static char *int_tovmsspec
         if (decc_efs_charset == 0)
          *(cp1++) = '_';  /* fix up syntax - '.' in name not allowed */
        else {
-         *(cp1++) = '^';  /* fix up syntax - '.' in name is allowed */
-         *(cp1++) = '.';
+         VMSEFS_ESCAPE_DOT(cp1, rslt, VMS_MAXRSS);
        }
       }
     }
@@ -8547,8 +8559,7 @@ static char *int_tovmsspec
         if (decc_efs_charset == 0)
          *(cp1++) = '_';
        else {
-         *(cp1++) = '^';
-         *(cp1++) = '.';
+         VMSEFS_ESCAPE_DOT(cp1, rslt, VMS_MAXRSS);
        }
       }
       else                  *(cp1++) =  *cp2;
@@ -8578,8 +8589,7 @@ static char *int_tovmsspec
     case '.':
        if (((cp2 < lastdot) || (cp2[1] == '\0')) &&
            decc_readdir_dropdotnotype) {
-         *(cp1)++ = '^';
-         *(cp1)++ = '.';
+         VMSEFS_ESCAPE_DOT(cp1, rslt, VMS_MAXRSS);
          cp2++;
 
          /* trailing dot ==> '^..' on VMS */