This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Remove another dead function in vms/vms.c.
[perl5.git] / vms / vms.c
index c5ad229..0364415 100644 (file)
--- a/vms/vms.c
+++ b/vms/vms.c
@@ -2,13 +2,10 @@
  *
  *    VMS-specific routines for perl5
  *
- *    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- *    2002, 2003, 2004, 2005, 2006, 2007 by Charles Bailey and others.
+ *    Copyright (C) 1993-2015 by Charles Bailey and others.
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
- *
- *    Please see Changes*.* or the Perl Repository Browser for revision history.
  */
 
 /*
@@ -267,17 +264,14 @@ static int vms_posix_exit = 0;
 
 /* bug workarounds if needed */
 int decc_bug_devnull = 1;
-int decc_dir_barename = 0;
 int vms_bug_stat_filename = 0;
 
 static int vms_debug_on_exception = 0;
 static int vms_debug_fileify = 0;
 
 /* Simple logical name translation */
-static int simple_trnlnm
-   (const char * logname,
-    char * value,
-    int value_len)
+static int
+simple_trnlnm(const char * logname, char * value, int value_len)
 {
     const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV");
     const unsigned long attr = LNM$M_CASE_BLIND;
@@ -314,10 +308,11 @@ static int simple_trnlnm
  *   changes to many other conversion routines.
  */
 
-static int is_unix_filespec(const char *path)
+static int
+is_unix_filespec(const char *path)
 {
-int ret_val;
-const char * pch1;
+    int ret_val;
+    const char * pch1;
 
     ret_val = 0;
     if (strncmp(path,"\"^UP^",5) != 0) {
@@ -339,13 +334,11 @@ const char * pch1;
 /* This routine converts a UCS-2 character to be VTF-7 encoded.
  */
 
-static void ucs2_to_vtf7
-   (char *outspec,
-    unsigned long ucs2_char,
-    int * output_cnt)
+static void
+ucs2_to_vtf7(char *outspec, unsigned long ucs2_char, int * output_cnt)
 {
-unsigned char * ucs_ptr;
-int hex;
+    unsigned char * ucs_ptr;
+    int hex;
 
     ucs_ptr = (unsigned char *)&ucs2_char;
 
@@ -386,11 +379,11 @@ int hex;
  *
  * The return value is the number of characters read from the input string
  */
-static int copy_expand_unix_filename_escape
-  (char *outspec, const char *inspec, int *output_cnt, const int * utf8_fl)
+static int
+copy_expand_unix_filename_escape(char *outspec, const char *inspec, int *output_cnt, const int * utf8_fl)
 {
-int count;
-int utf8_flag;
+    int count;
+    int utf8_flag;
 
     utf8_flag = 0;
     if (utf8_fl)
@@ -582,11 +575,11 @@ int utf8_flag;
  * The return value is the number of characters read from the input
  * string
  */
-static int copy_expand_vms_filename_escape
-  (char *outspec, const char *inspec, int *output_cnt)
+static int
+copy_expand_vms_filename_escape(char *outspec, const char *inspec, int *output_cnt)
 {
-int count;
-int scnt;
+    int count;
+    int scnt;
 
     count = 0;
     *output_cnt = 0;
@@ -673,34 +666,24 @@ int scnt;
  * string, then the passed file specification is probably a UNIX style
  * path.
  */
-static int vms_split_path
-   (const char * path,
-    char * * volume,
-    int * vol_len,
-    char * * root,
-    int * root_len,
-    char * * dir,
-    int * dir_len,
-    char * * name,
-    int * name_len,
-    char * * ext,
-    int * ext_len,
-    char * * version,
-    int * ver_len)
-{
-struct dsc$descriptor path_desc;
-int status;
-unsigned long flags;
-int ret_stat;
-struct filescan_itmlst_2 item_list[9];
-const int filespec = 0;
-const int nodespec = 1;
-const int devspec = 2;
-const int rootspec = 3;
-const int dirspec = 4;
-const int namespec = 5;
-const int typespec = 6;
-const int verspec = 7;
+static int
+vms_split_path(const char * path, char * * volume, int * vol_len, char * * root, int * root_len, 
+               char * * dir, int * dir_len, char * * name, int * name_len,
+               char * * ext, int * ext_len, char * * version, int * ver_len)
+{
+    struct dsc$descriptor path_desc;
+    int status;
+    unsigned long flags;
+    int ret_stat;
+    struct filescan_itmlst_2 item_list[9];
+    const int filespec = 0;
+    const int nodespec = 1;
+    const int devspec = 2;
+    const int rootspec = 3;
+    const int dirspec = 4;
+    const int namespec = 5;
+    const int typespec = 6;
+    const int verspec = 7;
 
     /* Assume the worst for an easy exit */
     ret_stat = -1;
@@ -821,7 +804,9 @@ const int verspec = 7;
 }
 
 /* Routine to determine if the file specification ends with .dir */
-static int is_dir_ext(char * e_spec, int e_len, char * vs_spec, int vs_len) {
+static int
+is_dir_ext(char * e_spec, int e_len, char * vs_spec, int vs_len)
+{
 
     /* e_len must be 4, and version must be <= 2 characters */
     if (e_len != 4 || vs_len > 2)
@@ -882,6 +867,25 @@ my_maxidx(const char *lnm)
 }
 /*}}}*/
 
+/* Routine to remove the 2-byte prefix from the translation of a
+ * process-permanent file (PPF).
+ */
+static inline unsigned short int
+S_remove_ppf_prefix(const char *lnm, char *eqv, unsigned short int eqvlen)
+{
+    if (*((int *)lnm) == *((int *)"SYS$")                    &&
+        eqvlen >= 4 && eqv[0] == 0x1b && eqv[1] == 0x00      &&
+        ( (lnm[4] == 'O' && !strcmp(lnm,"SYS$OUTPUT"))  ||
+          (lnm[4] == 'I' && !strcmp(lnm,"SYS$INPUT"))   ||
+          (lnm[4] == 'E' && !strcmp(lnm,"SYS$ERROR"))   ||
+          (lnm[4] == 'C' && !strcmp(lnm,"SYS$COMMAND")) )  ) {
+
+        memmove(eqv, eqv+4, eqvlen-4);
+        eqvlen -= 4;
+    }
+    return eqvlen;
+}
+
 /*{{{int vmstrnenv(const char *lnm, char *eqv, unsigned long int idx, struct dsc$descriptor_s **tabvec, unsigned long int flags) */
 int
 Perl_vmstrnenv(const char *lnm, char *eqv, unsigned long int idx,
@@ -999,39 +1003,33 @@ Perl_vmstrnenv(const char *lnm, char *eqv, unsigned long int idx,
             retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
             if (retsts == SS$_IVLOGNAM) { ivlnm = 1; break; }
             if (retsts == SS$_NOLOGNAM) break;
-            /* PPFs have a prefix */
-            if (
-#if INTSIZE == 4
-                 *((int *)uplnm) == *((int *)"SYS$")                    &&
-#endif
-                 eqvlen >= 4 && eqv[0] == 0x1b && eqv[1] == 0x00        &&
-                 ( (uplnm[4] == 'O' && !strcmp(uplnm,"SYS$OUTPUT"))  ||
-                   (uplnm[4] == 'I' && !strcmp(uplnm,"SYS$INPUT"))   ||
-                   (uplnm[4] == 'E' && !strcmp(uplnm,"SYS$ERROR"))   ||
-                   (uplnm[4] == 'C' && !strcmp(uplnm,"SYS$COMMAND")) )  ) {
-              memmove(eqv,eqv+4,eqvlen-4);
-              eqvlen -= 4;
-            }
+            eqvlen = S_remove_ppf_prefix(uplnm, eqv, eqvlen);
             cp2 += eqvlen;
             *cp2 = '\0';
           }
           if ((retsts == SS$_IVLOGNAM) ||
               (retsts == SS$_NOLOGNAM)) { continue; }
+          eqvlen = strlen(eqv);
         }
         else {
           retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
           if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
           if (retsts == SS$_NOLOGNAM) continue;
+          eqvlen = S_remove_ppf_prefix(uplnm, eqv, eqvlen);
           eqv[eqvlen] = '\0';
         }
-        eqvlen = strlen(eqv);
         break;
       }
     }
     if (retsts & 1) { eqv[eqvlen] = '\0'; return eqvlen; }
-    else if (retsts == LIB$_NOSUCHSYM || retsts == LIB$_INVSYMNAM ||
-             retsts == SS$_IVLOGNAM   || retsts == SS$_IVLOGTAB   ||
+    else if (retsts == LIB$_NOSUCHSYM ||
              retsts == SS$_NOLOGNAM) {
+     /* Unsuccessful lookup is normal -- no need to set errno */
+     return 0;
+    }
+    else if (retsts == LIB$_INVSYMNAM ||
+             retsts == SS$_IVLOGNAM   ||
+             retsts == SS$_IVLOGTAB) {
       set_errno(EINVAL);  set_vaxc_errno(retsts);
     }
     else _ckvmssts_noperl(retsts);
@@ -1041,7 +1039,8 @@ Perl_vmstrnenv(const char *lnm, char *eqv, unsigned long int idx,
 
 /*{{{ int my_trnlnm(const char *lnm, char *eqv, unsigned long int idx)*/
 /* Define as a function so we can access statics. */
-int Perl_my_trnlnm(pTHX_ const char *lnm, char *eqv, unsigned long int idx)
+int
+Perl_my_trnlnm(pTHX_ const char *lnm, char *eqv, unsigned long int idx)
 {
     int flags = 0;
 
@@ -1073,7 +1072,7 @@ Perl_my_getenv(pTHX_ const char *lnm, bool sys)
     static char *__my_getenv_eqv = NULL;
     char uplnm[LNM$C_NAMLENGTH+1], *cp2, *eqv;
     unsigned long int idx = 0;
-    int success, secure, saverr, savvmserr;
+    int success, secure;
     int midx, flags;
     SV *tmpsv;
 
@@ -1123,7 +1122,6 @@ Perl_my_getenv(pTHX_ const char *lnm, bool sys)
       if (sys) {
         /* Impose security constraints only if tainting */
         secure = PL_curinterp ? TAINTING_get : will_taint;
-        saverr = errno;  savvmserr = vaxc$errno;
       }
       else {
         secure = 0;
@@ -1155,10 +1153,6 @@ Perl_my_getenv(pTHX_ const char *lnm, bool sys)
 
       success = vmstrnenv(lnm,eqv,idx,secure ? fildev : NULL,flags);
 
-      /* Discard NOLOGNAM on internal calls since we're often looking
-       * for an optional name, and this "error" often shows up as the
-       * (bogus) exit status for a die() call later on.  */
-      if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
       return success ? eqv : NULL;
     }
 
@@ -1175,7 +1169,7 @@ Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys)
     unsigned long idx = 0;
     int midx, flags;
     static char *__my_getenv_len_eqv = NULL;
-    int secure, saverr, savvmserr;
+    int secure;
     SV *tmpsv;
     
     midx = my_maxidx(lnm) + 1;
@@ -1222,7 +1216,6 @@ Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys)
       if (sys) {
         /* Impose security constraints only if tainting */
         secure = PL_curinterp ? TAINTING_get : will_taint;
-        saverr = errno;  savvmserr = vaxc$errno;
       }
       else {
         secure = 0;
@@ -1249,7 +1242,7 @@ Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys)
 
       /* Get rid of "000000/ in rooted filespecs */
       if (*len > 7) {
-      char * zeros;
+       char * zeros;
        zeros = strstr(buf, "/000000/");
        if (zeros != NULL) {
          int mlen;
@@ -1260,10 +1253,6 @@ Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys)
        }
       }
 
-      /* Discard NOLOGNAM on internal calls since we're often looking
-       * for an optional name, and this "error" often shows up as the
-       * (bogus) exit status for a die() call later on.  */
-      if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
       return *len ? buf : NULL;
     }
 
@@ -1375,7 +1364,7 @@ prime_env_iter(void)
       my_strlcpy(cmd, "Show Logical *", sizeof(cmd));
       if (str$case_blind_compare(env_tables[i],&fildevdsc)) {
         my_strlcat(cmd," /Table=", sizeof(cmd));
-        cmddsc.dsc$w_length = my_strlcat(cmd, env_tables[i]->dsc$a_pointer, env_tables[i]->dsc$w_length + 1);
+        cmddsc.dsc$w_length = my_strlcat(cmd, env_tables[i]->dsc$a_pointer, sizeof(cmd));
       }
       else cmddsc.dsc$w_length = 14;  /* N.B. We test this below */
       flags = defflags | CLI$M_NOCLISYM;
@@ -1782,20 +1771,6 @@ static char *mp_do_rmsexpand(pTHX_ const char *, char *, int, const char *, unsi
 static char *mp_do_fileify_dirspec(pTHX_ const char *, char *, int, int *);
 static char *mp_do_tovmsspec(pTHX_ const char *, char *, int, int, int *);
 
-/* fixup barenames that are directories for internal use.
- * There have been problems with the consistent handling of UNIX
- * style directory names when routines are presented with a name that
- * has no directory delimiters at all.  So this routine will eventually
- * fix the issue.
- */
-static char * fixup_bare_dirnames(const char * name)
-{
-  if (decc_disable_to_vms_logname_translation) {
-/* fix me */
-  }
-  return NULL;
-}
-
 /* 8.3, remove() is now broken on symbolic links */
 static int rms_erase(const char * vmsname);
 
@@ -1818,7 +1793,8 @@ mp_do_kill_file(pTHX_ const char *name, int dirflag)
     char *vmsname;
     char *rslt;
     unsigned long int jpicode = JPI$_UIC, type = ACL$C_FILE;
-    unsigned long int cxt = 0, aclsts, fndsts, rmsts = -1;
+    unsigned long int cxt = 0, aclsts, fndsts;
+    int rmsts = -1;
     struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
     struct myacedef {
       unsigned char myace$b_length;
@@ -2102,16 +2078,18 @@ int
 Perl_my_chdir(pTHX_ const char *dir)
 {
   STRLEN dirlen = strlen(dir);
+  const char *dir1 = dir;
 
   /* zero length string sometimes gives ACCVIO */
-  if (dirlen == 0) return -1;
-  const char *dir1;
+  if (dirlen == 0) {
+    SETERRNO(EINVAL, SS$_BADPARAM);
+    return -1;
+  }
 
   /* Perl is passing the output of the DCL SHOW DEFAULT with leading spaces.
    * This does not work if DECC$EFS_CHARSET is active.  Hack it here
    * so that existing scripts do not need to be changed.
    */
-  dir1 = dir;
   while ((dirlen > 0) && (*dir1 == ' ')) {
     dir1++;
     dirlen--;
@@ -2436,13 +2414,14 @@ Perl_my_kill(int pid, int sig)
 #define DCL_IVVERB 0x38090
 #endif
 
-int Perl_vms_status_to_unix(int vms_status, int child_flag)
+int
+Perl_vms_status_to_unix(int vms_status, int child_flag)
 {
-int facility;
-int fac_sp;
-int msg_no;
-int msg_status;
-int unix_status;
+  int facility;
+  int fac_sp;
+  int msg_no;
+  int msg_status;
+  int unix_status;
 
   /* Assume the best or the worst */
   if (vms_status & STS$M_SUCCESS)
@@ -2618,9 +2597,10 @@ int unix_status;
  * error statuses that caused the errno value to be set.
  */
 
-int Perl_unix_status_to_vms(int unix_status)
+int
+Perl_unix_status_to_vms(int unix_status)
 {
-int test_unix_status;
+    int test_unix_status;
 
      /* Trivial cases first */
     /*---------------------*/
@@ -3653,9 +3633,8 @@ store_pipelocs(pTHX)
     PerlMem_free(unixdir);
 }
 
-static I32
-Perl_cando_by_name_int
-   (pTHX_ I32 bit, bool effective, const char *fname, int opts);
+static I32 Perl_cando_by_name_int(pTHX_ I32 bit, bool effective,
+                                  const char *fname, int opts);
 #if !defined(PERL_IMPLICIT_CONTEXT)
 #define cando_by_name_int              Perl_cando_by_name_int
 #else
@@ -3802,7 +3781,8 @@ vmspipe_tempfile(pTHX)
 }
 
 
-static int vms_is_syscommand_xterm(void)
+static int
+vms_is_syscommand_xterm(void)
 {
     const static struct dsc$descriptor_s syscommand_dsc = 
       { 11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND" };
@@ -3868,7 +3848,8 @@ static int vms_is_syscommand_xterm(void)
 }
 
 /* If we are on a DECTerm, we can pretend to fork xterms when requested */
-static PerlIO * create_forked_xterm(pTHX_ const char *cmd, const char *mode)
+static PerlIO* 
+create_forked_xterm(pTHX_ const char *cmd, const char *mode)
 {
     int status;
     int ret_stat;
@@ -4329,6 +4310,13 @@ safe_popen(pTHX_ const char *cmd, const char *in_mode, int *psts)
         
 
     } else if (*mode == 'n') {       /* separate subprocess, no Perl i/o */
+        /* Let the child inherit standard input, unless it's a directory. */
+        Stat_t st;
+        if (my_trnlnm("SYS$INPUT", in, 0)) {
+            if (flex_stat(in, &st) != 0 || S_ISDIR(st.st_mode))
+                *in = '\0';
+        }
+
         info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
         if (info->out) {
             info->out->pipe_done = &info->out_done;
@@ -4457,7 +4445,8 @@ Perl_my_popen(pTHX_ const char *cmd, const char *mode)
 
 /* Routine to close and cleanup a pipe info structure */
 
-static I32 my_pclose_pinfo(pTHX_ pInfo info) {
+static I32
+my_pclose_pinfo(pTHX_ pInfo info) {
 
     unsigned long int retsts;
     int done, n;
@@ -4764,9 +4753,10 @@ my_gconvert(double val, int ndig, int trail, char *buf)
 /*}}}*/
 
 #if defined(__VAX) || !defined(NAML$C_MAXRSS)
-static int rms_free_search_context(struct FAB * fab)
+static int
+rms_free_search_context(struct FAB * fab)
 {
-struct NAM * nam;
+    struct NAM * nam;
 
     nam = fab->fab$l_nam;
     nam->nam$b_nop |= NAM$M_SYNCHK;
@@ -4808,9 +4798,10 @@ struct NAM * nam;
 #define rms_nam_name_type_l_size(nam) \
        (nam.nam$b_name + nam.nam$b_type)
 #else
-static int rms_free_search_context(struct FAB * fab)
+static int
+rms_free_search_context(struct FAB * fab)
 {
-struct NAML * nam;
+    struct NAML * nam;
 
     nam = fab->fab$l_naml;
     nam->naml$b_nop |= NAM$M_SYNCHK;
@@ -4873,7 +4864,8 @@ struct NAML * nam;
  * however in 8.3 the unlink/remove/delete routines will only properly handle
  * them if one of the PCP modes is active.
  */
-static int rms_erase(const char * vmsname)
+static int
+rms_erase(const char * vmsname)
 {
   int status;
   struct FAB myfab = cc$rms_fab;
@@ -4906,28 +4898,28 @@ vms_rename_with_acl(pTHX_ const struct dsc$descriptor_s * vms_src_dsc,
    /* I can not find online documentation for $change_acl
     * it appears to be replaced by $set_security some time ago */
 
-const unsigned int access_mode = 0;
-$DESCRIPTOR(obj_file_dsc,"FILE");
-char *vmsname;
-char *rslt;
-unsigned long int jpicode = JPI$_UIC;
-int aclsts, fndsts, rnsts = -1;
-unsigned int ctx = 0;
-struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
-struct dsc$descriptor_s * clean_dsc;
-
-struct myacedef {
-    unsigned char myace$b_length;
-    unsigned char myace$b_type;
-    unsigned short int myace$w_flags;
-    unsigned long int myace$l_access;
-    unsigned long int myace$l_ident;
-} newace = { sizeof(struct myacedef), ACE$C_KEYID, 0,
-            ACE$M_READ | ACE$M_WRITE | ACE$M_DELETE | ACE$M_CONTROL,
-            0},
-            oldace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 0, 0};
-
-struct item_list_3
+    const unsigned int access_mode = 0;
+    $DESCRIPTOR(obj_file_dsc,"FILE");
+    char *vmsname;
+    char *rslt;
+    unsigned long int jpicode = JPI$_UIC;
+    int aclsts, fndsts, rnsts = -1;
+    unsigned int ctx = 0;
+    struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
+    struct dsc$descriptor_s * clean_dsc;
+    
+    struct myacedef {
+        unsigned char myace$b_length;
+        unsigned char myace$b_type;
+        unsigned short int myace$w_flags;
+        unsigned long int myace$l_access;
+        unsigned long int myace$l_ident;
+    } newace = { sizeof(struct myacedef), ACE$C_KEYID, 0,
+            ACE$M_READ | ACE$M_WRITE | ACE$M_DELETE | ACE$M_CONTROL,
+            0},
+            oldace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 0, 0};
+
+    struct item_list_3
        findlst[3] = {{sizeof oldace, OSS$_ACL_FIND_ENTRY, &oldace, 0},
                      {sizeof oldace, OSS$_ACL_READ_ENTRY, &oldace, 0},
                      {0,0,0,0}},
@@ -5064,12 +5056,12 @@ struct item_list_3
 int
 Perl_rename(pTHX_ const char *src, const char * dst)
 {
-int retval;
-int pre_delete = 0;
-int src_sts;
-int dst_sts;
-Stat_t src_st;
-Stat_t dst_st;
+    int retval;
+    int pre_delete = 0;
+    int src_sts;
+    int dst_sts;
+    Stat_t src_st;
+    Stat_t dst_st;
 
     /* Validate the source file */
     src_sts = flex_lstat(src, &src_st);
@@ -5832,18 +5824,31 @@ mp_do_rmsexpand
 }
 /*}}}*/
 /* External entry points */
-char *Perl_rmsexpand(pTHX_ const char *spec, char *buf, const char *def, unsigned opt)
-{ return do_rmsexpand(spec,buf,0,def,opt,NULL,NULL); }
-char *Perl_rmsexpand_ts(pTHX_ const char *spec, char *buf, const char *def, unsigned opt)
-{ return do_rmsexpand(spec,buf,1,def,opt,NULL,NULL); }
-char *Perl_rmsexpand_utf8
-  (pTHX_ const char *spec, char *buf, const char *def,
-   unsigned opt, int * fs_utf8, int * dfs_utf8)
-{ return do_rmsexpand(spec,buf,0,def,opt, fs_utf8, dfs_utf8); }
-char *Perl_rmsexpand_utf8_ts
-  (pTHX_ const char *spec, char *buf, const char *def,
-   unsigned opt, int * fs_utf8, int * dfs_utf8)
-{ return do_rmsexpand(spec,buf,1,def,opt, fs_utf8, dfs_utf8); }
+char *
+Perl_rmsexpand(pTHX_ const char *spec, char *buf, const char *def, unsigned opt)
+{
+    return do_rmsexpand(spec, buf, 0, def, opt, NULL, NULL);
+}
+
+char *
+Perl_rmsexpand_ts(pTHX_ const char *spec, char *buf, const char *def, unsigned opt)
+{
+    return do_rmsexpand(spec, buf, 1, def, opt, NULL, NULL);
+}
+
+char *
+Perl_rmsexpand_utf8(pTHX_ const char *spec, char *buf, const char *def,
+                    unsigned opt, int * fs_utf8, int * dfs_utf8)
+{
+    return do_rmsexpand(spec, buf, 0, def, opt, fs_utf8, dfs_utf8);
+}
+
+char *
+Perl_rmsexpand_utf8_ts(pTHX_ const char *spec, char *buf, const char *def,
+                       unsigned opt, int * fs_utf8, int * dfs_utf8)
+{
+    return do_rmsexpand(spec, buf, 1, def, opt, fs_utf8, dfs_utf8);
+}
 
 
 /*
@@ -5969,6 +5974,9 @@ int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl)
     vmsdir = (char *)PerlMem_malloc(VMS_MAXRSS + 1);
     if (vmsdir == NULL) _ckvmssts_noperl(SS$_INSFMEM);
     cp1 = strpbrk(trndir,"]:>");
+    if (cp1 && *(cp1+1) == ':')   /* DECNet node spec with :: */
+        cp1 = strpbrk(cp1+2,"]:>");
+
     if (hasfilename || !cp1) { /* filename present or not VMS */
 
       if (trndir[0] == '.') {
@@ -6113,9 +6121,11 @@ int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl)
       /* We've picked up everything up to the directory file name.
          Now just add the type and version, and we're set. */
       if ((!decc_efs_case_preserve) && vms_process_case_tolerant)
-          strcat(buf,".dir;1");
+          strcat(buf,".dir");
       else
-          strcat(buf,".DIR;1");
+          strcat(buf,".DIR");
+      if (!decc_filename_unix_no_version)
+          strcat(buf,";1");
       PerlMem_free(trndir);
       PerlMem_free(vmsdir);
       return buf;
@@ -6174,7 +6184,10 @@ int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl)
           rms_set_nam_fnb(dirnam, (NAM$M_EXP_TYPE | NAM$M_EXP_VER));
         }
         else { /* No; just work with potential name */
-          if (dirfab.fab$l_sts == RMS$_FNF) dirnam = savnam;
+          if (dirfab.fab$l_sts    == RMS$_FNF
+              || dirfab.fab$l_sts == RMS$_DNF
+              || dirfab.fab$l_sts == RMS$_FND)
+                dirnam = savnam;
           else { 
            int fab_sts;
            fab_sts = dirfab.fab$l_sts;
@@ -6350,12 +6363,12 @@ int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl)
           }
         }
         else {  /* This is a top-level dir.  Add the MFD to the path. */
-          cp1 = my_esa;
-          cp2 = buf;
-          while ((*cp1 != ':')  && (*cp1 != '\0')) *(cp2++) = *(cp1++);
-          strcpy(cp2,":[000000]");
-          cp1 += 2;
-          strcpy(cp2+9,cp1);
+          cp1 = strrchr(my_esa, ':');
+          assert(cp1);
+          memmove(buf, my_esa, cp1 - my_esa + 1);
+          memmove(buf + (cp1 - my_esa) + 1, "[000000]", 8);
+          memmove(buf + (cp1 - my_esa) + 9, cp1 + 2, retlen - (cp1 - my_esa + 2));
+          buf[retlen + 7] = '\0';  /* We've inserted '000000]' */
         }
       }
       sts = rms_free_search_context(&dirfab);
@@ -6377,7 +6390,8 @@ int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl)
 
 
 /*{{{ char *fileify_dirspec[_ts](char *dir, char *buf, int * utf8_fl)*/
-static char *mp_do_fileify_dirspec(pTHX_ const char *dir,char *buf,int ts, int *utf8_fl)
+static char *
+mp_do_fileify_dirspec(pTHX_ const char *dir,char *buf,int ts, int *utf8_fl)
 {
     static char __fileify_retbuf[VMS_MAXRSS];
     char * fileified, *ret_spec, *ret_buf;
@@ -6408,19 +6422,36 @@ static char *mp_do_fileify_dirspec(pTHX_ const char *dir,char *buf,int ts, int *
 /*}}}*/
 
 /* External entry points */
-char *Perl_fileify_dirspec(pTHX_ const char *dir, char *buf)
-{ return do_fileify_dirspec(dir,buf,0,NULL); }
-char *Perl_fileify_dirspec_ts(pTHX_ const char *dir, char *buf)
-{ return do_fileify_dirspec(dir,buf,1,NULL); }
-char *Perl_fileify_dirspec_utf8(pTHX_ const char *dir, char *buf, int * utf8_fl)
-{ return do_fileify_dirspec(dir,buf,0,utf8_fl); }
-char *Perl_fileify_dirspec_utf8_ts(pTHX_ const char *dir, char *buf, int * utf8_fl)
-{ return do_fileify_dirspec(dir,buf,1,utf8_fl); }
-
-static char * int_pathify_dirspec_simple(const char * dir, char * buf,
+char *
+Perl_fileify_dirspec(pTHX_ const char *dir, char *buf)
+{
+    return do_fileify_dirspec(dir, buf, 0, NULL);
+}
+
+char *
+Perl_fileify_dirspec_ts(pTHX_ const char *dir, char *buf)
+{
+    return do_fileify_dirspec(dir, buf, 1, NULL);
+}
+
+char *
+Perl_fileify_dirspec_utf8(pTHX_ const char *dir, char *buf, int * utf8_fl)
+{
+    return do_fileify_dirspec(dir, buf, 0, utf8_fl);
+}
+
+char *
+Perl_fileify_dirspec_utf8_ts(pTHX_ const char *dir, char *buf, int * utf8_fl)
+{
+    return do_fileify_dirspec(dir, buf, 1, utf8_fl);
+}
+
+static char * 
+int_pathify_dirspec_simple(const char * dir, char * buf,
     char * v_spec, int v_len, char * r_spec, int r_len,
     char * d_spec, int d_len, char * n_spec, int n_len,
-    char * e_spec, int e_len, char * vs_spec, int vs_len) {
+    char * e_spec, int e_len, char * vs_spec, int vs_len)
+{
 
     /* VMS specification - Try to do this the simple way */
     if ((v_len + r_len > 0) || (d_len > 0)) {
@@ -6510,7 +6541,8 @@ static char * int_pathify_dirspec_simple(const char * dir, char * buf,
 
 /* Internal routine to make sure or convert a directory to be in a */
 /* path specification.  No utf8 flag because it is not changed or used */
-static char *int_pathify_dirspec(const char *dir, char *buf)
+static char *
+int_pathify_dirspec(const char *dir, char *buf)
 {
     char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec;
     int sts, v_len, r_len, d_len, n_len, e_len, vs_len;
@@ -6802,7 +6834,8 @@ static char *int_pathify_dirspec(const char *dir, char *buf)
 }
 
 /*{{{ char *pathify_dirspec[_ts](char *path, char *buf)*/
-static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int * utf8_fl)
+static char *
+mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int * utf8_fl)
 {
     static char __pathify_retbuf[VMS_MAXRSS];
     char * pathified, *ret_spec, *ret_buf;
@@ -6834,24 +6867,40 @@ static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int
 
 
 /* External entry points */
-char *Perl_pathify_dirspec(pTHX_ const char *dir, char *buf)
-{ return do_pathify_dirspec(dir,buf,0,NULL); }
-char *Perl_pathify_dirspec_ts(pTHX_ const char *dir, char *buf)
-{ return do_pathify_dirspec(dir,buf,1,NULL); }
-char *Perl_pathify_dirspec_utf8(pTHX_ const char *dir, char *buf, int *utf8_fl)
-{ return do_pathify_dirspec(dir,buf,0,utf8_fl); }
-char *Perl_pathify_dirspec_utf8_ts(pTHX_ const char *dir, char *buf, int *utf8_fl)
-{ return do_pathify_dirspec(dir,buf,1,utf8_fl); }
+char *
+Perl_pathify_dirspec(pTHX_ const char *dir, char *buf)
+{
+    return do_pathify_dirspec(dir, buf, 0, NULL);
+}
+
+char *
+Perl_pathify_dirspec_ts(pTHX_ const char *dir, char *buf)
+{
+    return do_pathify_dirspec(dir, buf, 1, NULL);
+}
+
+char *
+Perl_pathify_dirspec_utf8(pTHX_ const char *dir, char *buf, int *utf8_fl)
+{
+    return do_pathify_dirspec(dir, buf, 0, utf8_fl);
+}
+
+char *
+Perl_pathify_dirspec_utf8_ts(pTHX_ const char *dir, char *buf, int *utf8_fl)
+{
+    return do_pathify_dirspec(dir, buf, 1, utf8_fl);
+}
 
 /* Internal tounixspec routine that does not use a thread context */
 /*{{{ char *int_tounixspec[_ts](char *spec, char *buf, int *)*/
-static char *int_tounixspec(const char *spec, char *rslt, int * utf8_fl)
+static char *
+int_tounixspec(const char *spec, char *rslt, int * utf8_fl)
 {
   char *dirend, *cp1, *cp3, *tmp;
   const char *cp2;
   int dirlen;
   unsigned short int trnlnm_iter_count;
-  int cmp_rslt;
+  int cmp_rslt, outchars_added;
   if (utf8_fl != NULL)
     *utf8_fl = 0;
 
@@ -6942,26 +6991,32 @@ static char *int_tounixspec(const char *spec, char *rslt, int * utf8_fl)
       }
     }
   }
-  /* This is already UNIX or at least nothing VMS understands */
+
+  cp1 = rslt;
+  cp2 = spec;
+
+  /* This is already UNIX or at least nothing VMS understands,
+   * so all we can reasonably do is unescape extended chars.
+   */
   if (cmp_rslt) {
-    my_strlcpy(rslt, spec, VMS_MAXRSS);
+    while (*cp2) {
+        cp2 += copy_expand_vms_filename_escape(cp1, cp2, &outchars_added);
+        cp1 += outchars_added;
+    }
+    *cp1 = '\0';    
     if (vms_debug_fileify) {
         fprintf(stderr, "int_tounixspec: rslt = %s\n", rslt);
     }
     return rslt;
   }
 
-  cp1 = rslt;
-  cp2 = spec;
   dirend = strrchr(spec,']');
   if (dirend == NULL) dirend = strrchr(spec,'>');
   if (dirend == NULL) dirend = strchr(spec,':');
   if (dirend == NULL) {
     while (*cp2) {
-        if (*cp2 == '^')
-            cp2++;
-        else 
-            *(cp1++) = *(cp2++);
+        cp2 += copy_expand_vms_filename_escape(cp1, cp2, &outchars_added);
+        cp1 += outchars_added;
     }
     *cp1 = '\0';    
     if (vms_debug_fileify) {
@@ -7057,9 +7112,8 @@ static char *int_tounixspec(const char *spec, char *rslt, int * utf8_fl)
       *(cp1++) = '/';
     }
     if ((*cp2 == '^')) {
-       /* EFS file escape, pass the next character as is */
-       /* Fix me: HEX encoding for Unicode not implemented */
-       cp2++;
+        cp2 += copy_expand_vms_filename_escape(cp1, cp2, &outchars_added);
+        cp1 += outchars_added;
     }
     else if ( *cp2 == '.') {
       if (*(cp2+1) == '.' && *(cp2+2) == '.') {
@@ -7072,13 +7126,11 @@ static char *int_tounixspec(const char *spec, char *rslt, int * utf8_fl)
   PerlMem_free(tmp);
   for (; cp2 <= dirend; cp2++) {
     if ((*cp2 == '^')) {
-       /* EFS file escape, pass the next character as is */
-       /* Fix me: HEX encoding for Unicode not implemented */
-       *(cp1++) = *(++cp2);
-        /* An escaped dot stays as is -- don't convert to slash */
-        if (*cp2 == '.') cp2++;
+        /* EFS file escape -- unescape it. */
+        cp2 += copy_expand_vms_filename_escape(cp1, cp2, &outchars_added) - 1;
+        cp1 += outchars_added;
     }
-    if (*cp2 == ':') {
+    else if (*cp2 == ':') {
       *(cp1++) = '/';
       if (*(cp2+1) == '[' || *(cp2+1) == '<') cp2++;
     }
@@ -7119,8 +7171,7 @@ static char *int_tounixspec(const char *spec, char *rslt, int * utf8_fl)
   }
   /* Translate the rest of the filename. */
   while (*cp2) {
-      int dot_seen;
-      dot_seen = 0;
+      int dot_seen = 0;
       switch(*cp2) {
       /* Fixme - for compatibility with the CRTL we should be removing */
       /* spaces from the file specifications, but this may show that */
@@ -7130,16 +7181,8 @@ static char *int_tounixspec(const char *spec, char *rslt, int * utf8_fl)
           *(cp1++) = '?';
           break;
       case '^':
-          /* Fix me hex expansions not implemented */
-          cp2++;  /* '^.' --> '.' and other. */
-          if (*cp2) {
-              if (*cp2 == '_') {
-                  cp2++;
-                  *(cp1++) = ' ';
-              } else {
-                  *(cp1++) = *(cp2++);
-              }
-          }
+          cp2 += copy_expand_vms_filename_escape(cp1, cp2, &outchars_added);
+          cp1 += outchars_added;
           break;
       case ';':
           if (decc_filename_unix_no_version) {
@@ -7195,8 +7238,8 @@ static char *int_tounixspec(const char *spec, char *rslt, int * utf8_fl)
    * VMS device root or concealed root.
    */
   {
-  int ulen;
-  char * zeros;
+      int ulen;
+      char * zeros;
 
       ulen = strlen(rslt);
 
@@ -7222,7 +7265,8 @@ static char *int_tounixspec(const char *spec, char *rslt, int * utf8_fl)
 
 
 /*{{{ char *tounixspec[_ts](char *spec, char *buf, int *)*/
-static char *mp_do_tounixspec(pTHX_ const char *spec, char *buf, int ts, int * utf8_fl)
+static char *
+mp_do_tounixspec(pTHX_ const char *spec, char *buf, int ts, int * utf8_fl)
 {
     static char __tounixspec_retbuf[VMS_MAXRSS];
     char * unixspec, *ret_spec, *ret_buf;
@@ -7253,14 +7297,29 @@ static char *mp_do_tounixspec(pTHX_ const char *spec, char *buf, int ts, int * u
 }  /* end of do_tounixspec() */
 /*}}}*/
 /* External entry points */
-char *Perl_tounixspec(pTHX_ const char *spec, char *buf)
-  { return do_tounixspec(spec,buf,0, NULL); }
-char *Perl_tounixspec_ts(pTHX_ const char *spec, char *buf)
-  { return do_tounixspec(spec,buf,1, NULL); }
-char *Perl_tounixspec_utf8(pTHX_ const char *spec, char *buf, int * utf8_fl)
-  { return do_tounixspec(spec,buf,0, utf8_fl); }
-char *Perl_tounixspec_utf8_ts(pTHX_ const char *spec, char *buf, int * utf8_fl)
-  { return do_tounixspec(spec,buf,1, utf8_fl); }
+char *
+Perl_tounixspec(pTHX_ const char *spec, char *buf)
+{
+    return do_tounixspec(spec, buf, 0, NULL);
+}
+
+char *
+Perl_tounixspec_ts(pTHX_ const char *spec, char *buf)
+{
+    return do_tounixspec(spec,buf,1, NULL);
+}
+
+char *
+Perl_tounixspec_utf8(pTHX_ const char *spec, char *buf, int * utf8_fl)
+{
+    return do_tounixspec(spec,buf,0, utf8_fl);
+}
+
+char *
+Perl_tounixspec_utf8_ts(pTHX_ const char *spec, char *buf, int * utf8_fl)
+{
+    return do_tounixspec(spec,buf,1, utf8_fl);
+}
 
 #if __CRTL_VER >= 70200000 && !defined(__VAX)
 
@@ -7279,26 +7338,25 @@ char *Perl_tounixspec_utf8_ts(pTHX_ const char *spec, char *buf, int * utf8_fl)
  It is used only internally by posix_to_vmsspec_hardway().
  */
 
-static int posix_root_to_vms
-  (char *vmspath, int vmspath_len,
-   const char *unixpath,
-   const int * utf8_fl)
-{
-int sts;
-struct FAB myfab = cc$rms_fab;
-rms_setup_nam(mynam);
-struct dsc$descriptor_s dvidsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
-struct dsc$descriptor_s specdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
-char * esa, * esal, * rsa, * rsal;
-int dir_flag;
-int unixlen;
-
-    dir_flag = 0;
-    vmspath[0] = '\0';
-    unixlen = strlen(unixpath);
-    if (unixlen == 0) {
-      return RMS$_FNF;
-    }
+static int
+posix_root_to_vms(char *vmspath, int vmspath_len,
+                  const char *unixpath, const int * utf8_fl)
+{
+  int sts;
+  struct FAB myfab = cc$rms_fab;
+  rms_setup_nam(mynam);
+  struct dsc$descriptor_s dvidsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
+  struct dsc$descriptor_s specdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
+  char * esa, * esal, * rsa, * rsal;
+  int dir_flag;
+  int unixlen;
+
+  dir_flag = 0;
+  vmspath[0] = '\0';
+  unixlen = strlen(unixpath);
+  if (unixlen == 0) {
+    return RMS$_FNF;
+  }
 
 #if __CRTL_VER >= 80200000
   /* If not a posix spec already, convert it */
@@ -7315,8 +7373,8 @@ int unixlen;
   else
 #endif
   {     
-  int path_len;
-  int i,j;
+     int path_len;
+     int i,j;
 
      /* Check to see if this is under the POSIX root */
      if (decc_disable_posix_root) {
@@ -7488,14 +7546,11 @@ int unixlen;
 */
 
 static int 
-slash_dev_special_to_vms
-   (const char * unixptr,
-    char * vmspath,
-    int vmspath_len)
+slash_dev_special_to_vms(const char *unixptr, char *vmspath, int vmspath_len)
 {
-char * nextslash;
-int len;
-int cmp;
+    char * nextslash;
+    int len;
+    int cmp;
 
     unixptr += 4;
     nextslash = strchr(unixptr, '/');
@@ -7523,25 +7578,24 @@ int cmp;
     through with out interpretation instead of being escaped.
 
   */
-static int posix_to_vmsspec_hardway
-  (char *vmspath, int vmspath_len,
-   const char *unixpath,
-   int dir_flag,
-   int * utf8_fl) {
-
-char *esa;
-const char *unixptr;
-const char *unixend;
-char *vmsptr;
-const char *lastslash;
-const char *lastdot;
-int unixlen;
-int vmslen;
-int dir_start;
-int dir_dot;
-int quoted;
-char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec;
-int sts, v_len, r_len, d_len, n_len, e_len, vs_len;
+static int
+posix_to_vmsspec_hardway(char *vmspath, int vmspath_len, const char *unixpath,
+                         int dir_flag, int * utf8_fl)
+{
+
+  char *esa;
+  const char *unixptr;
+  const char *unixend;
+  char *vmsptr;
+  const char *lastslash;
+  const char *lastdot;
+  int unixlen;
+  int vmslen;
+  int dir_start;
+  int dir_dot;
+  int quoted;
+  char * v_spec, * r_spec, * d_spec, * n_spec, * e_spec, * vs_spec;
+  int sts, v_len, r_len, d_len, n_len, e_len, vs_len;
 
   if (utf8_fl != NULL)
     *utf8_fl = 0;
@@ -7996,9 +8050,9 @@ int sts, v_len, r_len, d_len, n_len, e_len, vs_len;
   } /* End of relative/absolute path handling */
 
   while ((unixptr <= unixend) && (vmslen < vmspath_len)){
-  int dash_flag;
-  int in_cnt;
-  int out_cnt;
+    int dash_flag;
+    int in_cnt;
+    int out_cnt;
 
     dash_flag = 0;
 
@@ -8229,31 +8283,6 @@ int sts, v_len, r_len, d_len, n_len, e_len, vs_len;
 }
 #endif
 
- /* Eventual routine to convert a UTF-8 specification to VTF-7. */
-static char * utf8_to_vtf7(char * rslt, const char * path, int *utf8_fl)
-{
-char * result;
-int utf8_flag;
-
-   /* If a UTF8 flag is being passed, honor it */
-   utf8_flag = 0;
-   if (utf8_fl != NULL) {
-     utf8_flag = *utf8_fl;
-    *utf8_fl = 0;
-   }
-
-   if (utf8_flag) {
-     /* If there is a possibility of UTF8, then if any UTF8 characters
-        are present, then they must be converted to VTF-7
-      */
-     result = strcpy(rslt, path); /* FIX-ME */
-   }
-   else
-     result = strcpy(rslt, path);
-
-   return result;
-}
-
 /* A convenience macro for copying dots in filenames and escaping
  * them when they haven't already been escaped, with guards to
  * avoid checking before the start of the buffer or advancing
@@ -8271,8 +8300,9 @@ int utf8_flag;
 } STMT_END
 
 /*{{{ char *tovmsspec[_ts](char *path, char *buf, int * utf8_flag)*/
-static char *int_tovmsspec
-   (const char *path, char *rslt, int dir_flag, int * utf8_flag) {
+static char *
+int_tovmsspec(const char *path, char *rslt, int dir_flag, int * utf8_flag)
+{
   char *dirend;
   char *lastdot;
   char *cp1;
@@ -8388,17 +8418,20 @@ static char *int_tovmsspec
   dirend = strrchr(path,'/');
 
   if (dirend == NULL) {
-     /* If we get here with no UNIX directory delimiters, then this is
-      * not a complete file specification, such as a Unix glob
-      * specification, shell macro, make macro, or even a valid VMS
-      * filespec but with unescaped extended characters.  The safest
-      * thing in all these cases is to pass it through as-is.
+     /* If we get here with no Unix directory delimiters, then this is an
+      * ambiguous file specification, such as a Unix glob specification, a
+      * shell or make macro, or a filespec that would be valid except for
+      * unescaped extended characters.  The safest thing if it's a macro
+      * is to pass it through as-is.
       */
-      my_strlcpy(rslt, path, VMS_MAXRSS);
-      if (vms_debug_fileify) {
-          fprintf(stderr, "int_tovmsspec: rslt = %s\n", rslt);
+      if (strstr(path, "$(")) {
+          my_strlcpy(rslt, path, VMS_MAXRSS);
+          if (vms_debug_fileify) {
+              fprintf(stderr, "int_tovmsspec: rslt = %s\n", rslt);
+          }
+          return rslt;
       }
-      return rslt;
+      hasdir = 0;
   }
   else if (*(dirend+1) == '.') {  /* do we have trailing "/." or "/.." or "/..."? */
     if (!*(dirend+2)) dirend +=2;
@@ -8524,9 +8557,6 @@ static char *int_tovmsspec
     }
     else *(cp1++) = '.';
   }
-  else {
-    *(cp1++) = *cp2;
-  }
   for (; cp2 < dirend; cp2++) {
     if (*cp2 == '/') {
       if (*(cp2-1) == '/') continue;
@@ -8578,14 +8608,18 @@ static char *int_tovmsspec
          VMSEFS_DOT_WITH_ESCAPE(cp1, rslt, VMS_MAXRSS);
        }
       }
-      else                  *(cp1++) =  *cp2;
+      else {
+        int out_cnt;
+        cp2 += copy_expand_unix_filename_escape(cp1, cp2, &out_cnt, utf8_flag);
+        cp2--; /* we're in a loop that will increment this */
+        cp1 += out_cnt;
+      }
       infront = 1;
     }
   }
   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 */
+  if (*cp2 && *cp2 == '/') cp2++;  /* check in case we ended with trailing '/' */
   no_type_seen = 0;
   if (cp2 > lastdot)
     no_type_seen = 1;
@@ -8598,7 +8632,7 @@ static char *int_tovmsspec
          *(cp1++) = '?';
        cp2++;
     case ' ':
-       if (cp2 > path && *(cp2-1) != '^') /* not previously escaped */
+       if (cp2 >= path && (cp2 == path || *(cp2-1) != '^')) /* not previously escaped */
            *(cp1)++ = '^';
        *(cp1)++ = '_';
        cp2++;
@@ -8683,21 +8717,23 @@ static char *int_tovmsspec
     case '|':
     case '<':
     case '>':
-       if (cp2 > path && *(cp2-1) != '^') /* not previously escaped */
+       if (cp2 >= path && *(cp2-1) != '^') /* not previously escaped */
            *(cp1++) = '^';
        *(cp1++) = *(cp2++);
        break;
     case ';':
-       /* FIXME: This needs fixing as Perl is putting ".dir;" on UNIX filespecs
-        * which is wrong.  UNIX notation should be ".dir." unless
-        * the DECC$FILENAME_UNIX_NO_VERSION is enabled.
-        * changing this behavior could break more things at this time.
-        * efs character set effectively does not allow "." to be a version
-        * delimiter as a further complication about changing this.
-        */
-       if (decc_filename_unix_report != 0) {
+        /* If it doesn't look like the beginning of a version number,
+         * or we've been promised there are no version numbers, then
+         * escape it.
+         */
+       if (decc_filename_unix_no_version) {
          *(cp1++) = '^';
        }
+       else {
+         size_t all_nums = strspn(cp2+1, "0123456789");
+         if (all_nums > 5 || *(cp2 + all_nums + 1) != '\0')
+           *(cp1++) = '^';
+       }
        *(cp1++) = *(cp2++);
        break;
     default:
@@ -8727,9 +8763,10 @@ static char *int_tovmsspec
 
 
 /*{{{ char *tovmsspec[_ts](char *path, char *buf, int * utf8_flag)*/
-static char *mp_do_tovmsspec
-   (pTHX_ const char *path, char *buf, int ts, int dir_flag, int * utf8_flag) {
-  static char __tovmsspec_retbuf[VMS_MAXRSS];
+static char *
+mp_do_tovmsspec(pTHX_ const char *path, char *buf, int ts, int dir_flag, int * utf8_flag)
+{
+    static char __tovmsspec_retbuf[VMS_MAXRSS];
     char * vmsspec, *ret_spec, *ret_buf;
 
     vmsspec = NULL;
@@ -8758,19 +8795,35 @@ static char *mp_do_tovmsspec
 }  /* end of mp_do_tovmsspec() */
 /*}}}*/
 /* External entry points */
-char *Perl_tovmsspec(pTHX_ const char *path, char *buf)
-  { return do_tovmsspec(path,buf,0,NULL); }
-char *Perl_tovmsspec_ts(pTHX_ const char *path, char *buf)
-  { return do_tovmsspec(path,buf,1,NULL); }
-char *Perl_tovmsspec_utf8(pTHX_ const char *path, char *buf, int * utf8_fl)
-  { return do_tovmsspec(path,buf,0,utf8_fl); }
-char *Perl_tovmsspec_utf8_ts(pTHX_ const char *path, char *buf, int * utf8_fl)
-  { return do_tovmsspec(path,buf,1,utf8_fl); }
+char *
+Perl_tovmsspec(pTHX_ const char *path, char *buf)
+{
+    return do_tovmsspec(path, buf, 0, NULL);
+}
+
+char *
+Perl_tovmsspec_ts(pTHX_ const char *path, char *buf)
+{
+    return do_tovmsspec(path, buf, 1, NULL);
+}
+
+char *
+Perl_tovmsspec_utf8(pTHX_ const char *path, char *buf, int * utf8_fl)
+{
+    return do_tovmsspec(path, buf, 0, utf8_fl);
+}
+
+char *
+Perl_tovmsspec_utf8_ts(pTHX_ const char *path, char *buf, int * utf8_fl)
+{
+    return do_tovmsspec(path, buf, 1, utf8_fl);
+}
 
 /*{{{ char *int_tovmspath(char *path, char *buf, const int *)*/
 /* Internal routine for use with out an explicit context present */
-static char * int_tovmspath(const char *path, char *buf, int * utf8_fl) {
-
+static char *
+int_tovmspath(const char *path, char *buf, int * utf8_fl)
+{
     char * ret_spec, *pathified;
 
     if (path == NULL)
@@ -8795,7 +8848,9 @@ static char * int_tovmspath(const char *path, char *buf, int * utf8_fl) {
 }
 
 /*{{{ char *tovmspath[_ts](char *path, char *buf, const int *)*/
-static char *mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int * utf8_fl) {
+static char *
+mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int * utf8_fl)
+{
   static char __tovmspath_retbuf[VMS_MAXRSS];
   int vmslen;
   char *pathified, *vmsified, *cp;
@@ -8837,18 +8892,35 @@ static char *mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int * ut
 }  /* end of do_tovmspath() */
 /*}}}*/
 /* External entry points */
-char *Perl_tovmspath(pTHX_ const char *path, char *buf)
-  { return do_tovmspath(path,buf,0, NULL); }
-char *Perl_tovmspath_ts(pTHX_ const char *path, char *buf)
-  { return do_tovmspath(path,buf,1, NULL); }
-char *Perl_tovmspath_utf8(pTHX_ const char *path, char *buf, int *utf8_fl) 
-  { return do_tovmspath(path,buf,0,utf8_fl); }
-char *Perl_tovmspath_utf8_ts(pTHX_ const char *path, char *buf, int *utf8_fl)
-  { return do_tovmspath(path,buf,1,utf8_fl); }
+char *
+Perl_tovmspath(pTHX_ const char *path, char *buf)
+{
+    return do_tovmspath(path, buf, 0, NULL);
+}
+
+char *
+Perl_tovmspath_ts(pTHX_ const char *path, char *buf)
+{
+    return do_tovmspath(path, buf, 1, NULL);
+}
+
+char *
+Perl_tovmspath_utf8(pTHX_ const char *path, char *buf, int *utf8_fl)
+{
+    return do_tovmspath(path, buf, 0, utf8_fl);
+}
+
+char *
+Perl_tovmspath_utf8_ts(pTHX_ const char *path, char *buf, int *utf8_fl)
+{
+    return do_tovmspath(path, buf, 1, utf8_fl);
+}
 
 
 /*{{{ char *tounixpath[_ts](char *path, char *buf, int * utf8_fl)*/
-static char *mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int * utf8_fl) {
+static char *
+mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int * utf8_fl)
+{
   static char __tounixpath_retbuf[VMS_MAXRSS];
   int unixlen;
   char *pathified, *unixified, *cp;
@@ -8891,14 +8963,29 @@ static char *mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int * u
 }  /* end of do_tounixpath() */
 /*}}}*/
 /* External entry points */
-char *Perl_tounixpath(pTHX_ const char *path, char *buf)
-  { return do_tounixpath(path,buf,0,NULL); }
-char *Perl_tounixpath_ts(pTHX_ const char *path, char *buf)
-  { return do_tounixpath(path,buf,1,NULL); }
-char *Perl_tounixpath_utf8(pTHX_ const char *path, char *buf, int * utf8_fl)
-  { return do_tounixpath(path,buf,0,utf8_fl); }
-char *Perl_tounixpath_utf8_ts(pTHX_ const char *path, char *buf, int * utf8_fl)
-  { return do_tounixpath(path,buf,1,utf8_fl); }
+char *
+Perl_tounixpath(pTHX_ const char *path, char *buf)
+{
+    return do_tounixpath(path, buf, 0, NULL);
+}
+
+char *
+Perl_tounixpath_ts(pTHX_ const char *path, char *buf)
+{
+    return do_tounixpath(path, buf, 1, NULL);
+}
+
+char *
+Perl_tounixpath_utf8(pTHX_ const char *path, char *buf, int * utf8_fl)
+{
+    return do_tounixpath(path, buf, 0, utf8_fl);
+}
+
+char *
+Perl_tounixpath_utf8_ts(pTHX_ const char *path, char *buf, int * utf8_fl)
+{
+    return do_tounixpath(path, buf, 1, utf8_fl);
+}
 
 /*
  * @(#)argproc.c 2.2 94/08/16  Mark Pizzolato (mark AT infocomm DOT com)
@@ -9191,10 +9278,8 @@ mp_getredirection(pTHX_ int *ac, char ***av)
 }  /* end of getredirection() */
 /*}}}*/
 
-static void add_item(struct list_item **head,
-                    struct list_item **tail,
-                    char *value,
-                    int *count)
+static void
+add_item(struct list_item **head, struct list_item **tail, char *value, int *count)
 {
     if (*head == 0)
        {
@@ -9211,26 +9296,25 @@ static void add_item(struct list_item **head,
     ++(*count);
 }
 
-static void mp_expand_wild_cards(pTHX_ char *item,
-                             struct list_item **head,
-                             struct list_item **tail,
-                             int *count)
-{
-int expcount = 0;
-unsigned long int context = 0;
-int isunix = 0;
-int item_len = 0;
-char *had_version;
-char *had_device;
-int had_directory;
-char *devdir,*cp;
-char *vmsspec;
-$DESCRIPTOR(filespec, "");
-$DESCRIPTOR(defaultspec, "SYS$DISK:[]");
-$DESCRIPTOR(resultspec, "");
-unsigned long int lff_flags = 0;
-int sts;
-int rms_sts;
+static void 
+mp_expand_wild_cards(pTHX_ char *item, struct list_item **head,
+                     struct list_item **tail, int *count)
+{
+    int expcount = 0;
+    unsigned long int context = 0;
+    int isunix = 0;
+    int item_len = 0;
+    char *had_version;
+    char *had_device;
+    int had_directory;
+    char *devdir,*cp;
+    char *vmsspec;
+    $DESCRIPTOR(filespec, "");
+    $DESCRIPTOR(defaultspec, "SYS$DISK:[]");
+    $DESCRIPTOR(resultspec, "");
+    unsigned long int lff_flags = 0;
+    int sts;
+    int rms_sts;
 
 #ifdef VMS_LONGNAME_SUPPORT
     lff_flags = LIB$M_FIL_LONG_NAMES;
@@ -9336,46 +9420,6 @@ int rms_sts;
     _ckvmssts_noperl(lib$find_file_end(&context));
 }
 
-static int child_st[2];/* Event Flag set when child process completes  */
-
-static unsigned short child_chan;/* I/O Channel for Pipe Mailbox               */
-
-static unsigned long int exit_handler(void)
-{
-short iosb[4];
-
-    if (0 == child_st[0])
-       {
-#ifdef ARGPROC_DEBUG
-       PerlIO_printf(Perl_debug_log, "Waiting for Child Process to Finish . . .\n");
-#endif
-       fflush(stdout);     /* Have to flush pipe for binary data to    */
-                           /* terminate properly -- <tp@mccall.com>    */
-       sys$qiow(0, child_chan, IO$_WRITEOF, iosb, 0, 0, 0, 0, 0, 0, 0, 0);
-       sys$dassgn(child_chan);
-       fclose(stdout);
-       sys$synch(0, child_st);
-       }
-    return(1);
-}
-
-static void sig_child(int chan)
-{
-#ifdef ARGPROC_DEBUG
-    PerlIO_printf(Perl_debug_log, "Child Completion AST\n");
-#endif
-    if (child_st[0] == 0)
-       child_st[0] = 1;
-}
-
-static struct exit_control_block exit_block =
-    {
-    0,
-    exit_handler,
-    1,
-    &exit_block.exit_status,
-    0
-    };
 
 static void 
 pipe_and_fork(pTHX_ char **cmargv)
@@ -9428,18 +9472,19 @@ pipe_and_fork(pTHX_ char **cmargv)
     }
 }
 
-static int background_process(pTHX_ int argc, char **argv)
-{
-char command[MAX_DCL_SYMBOL + 1] = "$";
-$DESCRIPTOR(value, "");
-static $DESCRIPTOR(cmd, "BACKGROUND$COMMAND");
-static $DESCRIPTOR(null, "NLA0:");
-static $DESCRIPTOR(pidsymbol, "SHELL_BACKGROUND_PID");
-char pidstring[80];
-$DESCRIPTOR(pidstr, "");
-int pid;
-unsigned long int flags = 17, one = 1, retsts;
-int len;
+static int
+background_process(pTHX_ int argc, char **argv)
+{
+    char command[MAX_DCL_SYMBOL + 1] = "$";
+    $DESCRIPTOR(value, "");
+    static $DESCRIPTOR(cmd, "BACKGROUND$COMMAND");
+    static $DESCRIPTOR(null, "NLA0:");
+    static $DESCRIPTOR(pidsymbol, "SHELL_BACKGROUND_PID");
+    char pidstring[80];
+    $DESCRIPTOR(pidstr, "");
+    int pid;
+    unsigned long int flags = 17, one = 1, retsts;
+    int len;
 
     len = my_strlcat(command, argv[0], sizeof(command));
     while (--argc && (len < MAX_DCL_SYMBOL))
@@ -9589,8 +9634,8 @@ vms_image_init(int *argcp, char ***argvp)
    * directory.  This needs to be removed.
    */
   if (decc_filename_unix_report) {
-  char * zeros;
-  int ulen;
+    char * zeros;
+    int ulen;
     ulen = strlen(argvp[0][0]);
     if (ulen > 7) {
       zeros = strstr(argvp[0][0], "/000000/");
@@ -9660,11 +9705,12 @@ vms_image_init(int *argcp, char ***argvp)
     }
     tabvec[tabidx] = (struct dsc$descriptor_s *) PerlMem_malloc(sizeof(struct dsc$descriptor_s));
     if (tabvec[tabidx] == NULL) _ckvmssts_noperl(SS$_INSFMEM);
-    tabvec[tabidx]->dsc$w_length  = 0;
+    tabvec[tabidx]->dsc$w_length  = len;
     tabvec[tabidx]->dsc$b_dtype   = DSC$K_DTYPE_T;
-    tabvec[tabidx]->dsc$b_class   = DSC$K_CLASS_D;
-    tabvec[tabidx]->dsc$a_pointer = NULL;
-    _ckvmssts_noperl(lib$scopy_r_dx(&len,eqv,tabvec[tabidx]));
+    tabvec[tabidx]->dsc$b_class   = DSC$K_CLASS_S;
+    tabvec[tabidx]->dsc$a_pointer = (char *)PerlMem_malloc(len + 1);
+    if (tabvec[tabidx]->dsc$a_pointer == NULL) _ckvmssts_noperl(SS$_INSFMEM);
+    my_strlcpy(tabvec[tabidx]->dsc$a_pointer, eqv, len + 1);
   }
   if (tabidx) { tabvec[tabidx] = NULL; env_tables = tabvec; }
 
@@ -9967,7 +10013,8 @@ Perl_opendir(pTHX_ const char *name)
     /* Check access before stat; otherwise stat does not
      * accurately report whether it's a directory.
      */
-    if (!cando_by_name_int(S_IRUSR,0,dir,PERL_RMSEXPAND_M_VMS_IN)) {
+    if (!strstr(dir, "::") /* sys$check_access doesn't do remotes */
+        && !cando_by_name_int(S_IRUSR,0,dir,PERL_RMSEXPAND_M_VMS_IN)) {
       /* cando_by_name has already set errno */
       Safefree(dir);
       return NULL;
@@ -9988,12 +10035,12 @@ Perl_opendir(pTHX_ const char *name)
     dd->context = 0;
     dd->count = 0;
     dd->flags = 0;
-    /* By saying we always want the result of readdir() in unix format, we 
-     * are really saying we want all the escapes removed.  Otherwise the caller,
-     * having no way to know whether it's already in VMS format, might send it
-     * through tovmsspec again, thus double escaping.
+    /* By saying we want the result of readdir() in unix format, we are really
+     * saying we want all the escapes removed, translating characters that
+     * must be escaped in a VMS-format name to their unescaped form, which is
+     * presumably allowed in a Unix-format name.
      */
-    dd->flags = PERL_VMSDIR_M_UNIXSPECS;
+    dd->flags = decc_filename_unix_report ? PERL_VMSDIR_M_UNIXSPECS : 0;
     dd->pat.dsc$a_pointer = dd->pattern;
     dd->pat.dsc$w_length = strlen(dd->pattern);
     dd->pat.dsc$b_dtype = DSC$K_DTYPE_T;
@@ -10805,8 +10852,8 @@ setup_cmddsc(pTHX_ const char *incmd, int check_img, int *suggest_quote,
 bool
 Perl_vms_do_aexec(pTHX_ SV *really,SV **mark,SV **sp)
 {
-bool exec_sts;
-char * cmd;
+  bool exec_sts;
+  char * cmd;
 
   if (sp > mark) {
     if (vfork_called) {           /* this follows a vfork - act Unixish */
@@ -10887,9 +10934,9 @@ int do_spawn2(pTHX_ const char *, int);
 int
 Perl_do_aspawn(pTHX_ SV* really, SV** mark, SV** sp)
 {
-unsigned long int sts;
-char * cmd;
-int flags = 0;
+  unsigned long int sts;
+  char * cmd;
+  int flags = 0;
 
   if (sp > mark) {
 
@@ -10989,7 +11036,11 @@ do_spawn2(pTHX_ const char *cmd, int flags)
     fp = safe_popen(aTHX_ cmd, mode, (int *)&sts);
     if (fp != NULL)
       my_pclose(fp);
-    /* sts will be the pid in the nowait case */
+    /* sts will be the pid in the nowait case, so leave a
+     * hint saying not to do any bit shifting to it.
+     */
+    if (flags & CLI$M_NOWAIT)
+        PL_statusvalue = -1;
   }
   return sts;
 }  /* end of do_spawn2() */
@@ -11005,7 +11056,8 @@ static unsigned int *sockflags, sockflagsize;
  * likely to be opened by a name.
  */
 /*{{{ FILE *my_fdopen(int fd, const char *mode)*/
-FILE *my_fdopen(int fd, const char *mode)
+FILE *
+my_fdopen(int fd, const char *mode)
 {
   FILE *fp = fdopen(fd, mode);
 
@@ -11033,7 +11085,8 @@ FILE *my_fdopen(int fd, const char *mode)
  * via freopen().  >> Todo
  */
 /*{{{ int my_fclose(FILE *fp)*/
-int my_fclose(FILE *fp) {
+int
+my_fclose(FILE *fp) {
   if (fp) {
     unsigned int fd = fileno(fp);
     unsigned int fdoff = fd / sizeof(unsigned int);
@@ -11204,7 +11257,8 @@ static char __pw_namecache[UAI$S_IDENT+1];
 /*
  * This routine does most of the work extracting the user information.
  */
-static int fillpasswd (pTHX_ const char *name, struct passwd *pwd)
+static int
+fillpasswd (pTHX_ const char *name, struct passwd *pwd)
 {
     static struct {
         unsigned char length;
@@ -11286,7 +11340,8 @@ static int fillpasswd (pTHX_ const char *name, struct passwd *pwd)
  * Get information for a named user.
 */
 /*{{{struct passwd *getpwnam(char *name)*/
-struct passwd *Perl_my_getpwnam(pTHX_ const char *name)
+struct passwd *
+Perl_my_getpwnam(pTHX_ const char *name)
 {
     struct dsc$descriptor_s name_desc;
     union uicdef uic;
@@ -11323,7 +11378,8 @@ struct passwd *Perl_my_getpwnam(pTHX_ const char *name)
  * Called by my_getpwent with uid=-1 to list all users.
 */
 /*{{{struct passwd *my_getpwuid(Uid_t uid)*/
-struct passwd *Perl_my_getpwuid(pTHX_ Uid_t uid)
+struct passwd *
+Perl_my_getpwuid(pTHX_ Uid_t uid)
 {
     const $DESCRIPTOR(name_desc,__pw_namecache);
     unsigned short lname;
@@ -11378,7 +11434,8 @@ struct passwd *Perl_my_getpwuid(pTHX_ Uid_t uid)
  * Get information for next user.
 */
 /*{{{struct passwd *my_getpwent()*/
-struct passwd *Perl_my_getpwent(pTHX)
+struct passwd *
+Perl_my_getpwent(pTHX)
 {
     return (my_getpwuid((unsigned int) -1));
 }
@@ -11388,7 +11445,8 @@ struct passwd *Perl_my_getpwent(pTHX)
  * Finish searching rights database for users.
 */
 /*{{{void my_endpwent()*/
-void Perl_my_endpwent(pTHX)
+void
+Perl_my_endpwent(pTHX)
 {
     if (contxt) {
       _ckvmssts(sys$finish_rdb(&contxt));
@@ -11454,7 +11512,8 @@ static time_t toloc_dst(time_t utc) {
  */
 
 /*{{{time_t my_time(time_t *timep)*/
-time_t Perl_my_time(pTHX_ time_t *timep)
+time_t
+Perl_my_time(pTHX_ time_t *timep)
 {
   time_t when;
   struct tm *tm_p;
@@ -11576,7 +11635,8 @@ Perl_my_localtime(pTHX_ const time_t *timep)
 static const long int utime_baseadjust[2] = { 0x4beb4000, 0x7c9567 };
 
 /*{{{int my_utime(const char *path, const struct utimbuf *utimes)*/
-int Perl_my_utime(pTHX_ const char *file, const struct utimbuf *utimes)
+int
+Perl_my_utime(pTHX_ const char *file, const struct utimbuf *utimes)
 {
 #if __CRTL_VER >= 70300000
   struct utimbuf utc_utimes, *utc_utimesp;
@@ -11792,7 +11852,8 @@ int Perl_my_utime(pTHX_ const char *file, const struct utimbuf *utimes)
  * on the first call.
  */
 #define LOCKID_MASK 0x80000000     /* Use 0 to force device name use only */
-static mydev_t encode_dev (pTHX_ const char *dev)
+static mydev_t
+encode_dev (pTHX_ const char *dev)
 {
   int i;
   unsigned long int f;
@@ -11882,8 +11943,7 @@ Perl_flex_stat_int(pTHX_ const char *fspec, Stat_t *statbufp, int lstat_flag);
 #define flex_stat_int(a,b,c)           Perl_flex_stat_int(aTHX_ a,b,c)
 
 static I32
-Perl_cando_by_name_int
-   (pTHX_ I32 bit, bool effective, const char *fname, int opts)
+Perl_cando_by_name_int(pTHX_ I32 bit, bool effective, const char *fname, int opts)
 {
   char usrname[L_cuserid];
   struct dsc$descriptor_s usrdsc =
@@ -12067,6 +12127,7 @@ Perl_cando_by_name(pTHX_ I32 bit, bool effective, const char *fname)
 int
 Perl_flex_fstat(pTHX_ int fd, Stat_t *statbufp)
 {
+  dSAVE_ERRNO; /* fstat may set this even on success */
   if (!fstat(fd, &statbufp->crtl_stat)) {
     char *cptr;
     char *vms_filename;
@@ -12102,6 +12163,7 @@ Perl_flex_fstat(pTHX_ int fd, Stat_t *statbufp)
       statbufp->st_ctime = _toloc(statbufp->st_ctime);
     }
 #   endif
+    RESTORE_ERRNO;
     return 0;
   }
   return -1;
@@ -12941,12 +13003,12 @@ mod2fname(pTHX_ CV *cv)
   dXSARGS;
   char ultimate_name[NAM$C_MAXRSS+1], work_name[NAM$C_MAXRSS*8 + 1],
        workbuff[NAM$C_MAXRSS*1 + 1];
-  int counter, num_entries;
+  SSize_t counter, num_entries;
   /* ODS-5 ups this, but we want to be consistent, so... */
   int max_name_len = 39;
   AV *in_array = (AV *)SvRV(ST(0));
 
-  num_entries = av_len(in_array);
+  num_entries = av_tindex(in_array);
 
   /* All the names start with PL_. */
   strcpy(ultimate_name, "PL_");
@@ -13023,9 +13085,7 @@ hushexit_fromperl(pTHX_ CV *cv)
 
 
 PerlIO * 
-Perl_vms_start_glob
-   (pTHX_ SV *tmpglob,
-    IO *io)
+Perl_vms_start_glob(pTHX_ SV *tmpglob, IO *io)
 {
     PerlIO *fp;
     struct vs_str_st *rslt;
@@ -13510,12 +13570,12 @@ int vms_fid_to_name(char * outname, int outlen,
 #pragma message disable MISALGNDMEM
 #pragma member_alignment save
 #pragma nomember_alignment
-struct statbuf_t {
-    char          * st_dev;
-    unsigned short st_ino[3];
-    unsigned short old_st_mode;
-    unsigned long  padl[30];  /* plenty of room */
-} statbuf;
+    struct statbuf_t {
+        char      * st_dev;
+        unsigned short st_ino[3];
+        unsigned short old_st_mode;
+        unsigned long  padl[30];  /* plenty of room */
+    } statbuf;
 #pragma message restore
 #pragma member_alignment restore
 
@@ -13864,11 +13924,17 @@ mp_do_vms_realname(pTHX_ const char *filespec, char *outbuf,
 
 /*}}}*/
 /* External entry points */
-char *Perl_vms_realpath(pTHX_ const char *filespec, char *outbuf, int *utf8_fl)
-{ return do_vms_realpath(filespec, outbuf, utf8_fl); }
+char *
+Perl_vms_realpath(pTHX_ const char *filespec, char *outbuf, int *utf8_fl)
+{
+    return do_vms_realpath(filespec, outbuf, utf8_fl);
+}
 
-char *Perl_vms_realname(pTHX_ const char *filespec, char *outbuf, int *utf8_fl)
-{ return do_vms_realname(filespec, outbuf, utf8_fl); }
+char *
+Perl_vms_realname(pTHX_ const char *filespec, char *outbuf, int *utf8_fl)
+{
+    return do_vms_realname(filespec, outbuf, utf8_fl);
+}
 
 /* case_tolerant */
 
@@ -13876,20 +13942,22 @@ char *Perl_vms_realname(pTHX_ const char *filespec, char *outbuf, int *utf8_fl)
 /* OpenVMS provides a case sensitive implementation of ODS-5 and this is
  * controlled by a process setting.
  */
-int do_vms_case_tolerant(void)
+int
+do_vms_case_tolerant(void)
 {
     return vms_process_case_tolerant;
 }
 /*}}}*/
 /* External entry points */
+int
+Perl_vms_case_tolerant(void)
+{
 #if __CRTL_VER >= 70301000 && !defined(__VAX)
-int Perl_vms_case_tolerant(void)
-{ return do_vms_case_tolerant(); }
+    return do_vms_case_tolerant();
 #else
-int Perl_vms_case_tolerant(void)
-{ return vms_process_case_tolerant; }
+    return vms_process_case_tolerant;
 #endif
-
+}
 
  /* Start of DECC RTL Feature handling */
 
@@ -13900,6 +13968,19 @@ set_feature_default(const char *name, int value)
 {
     int status;
     int index;
+    char val_str[10];
+
+    /* If the feature has been explicitly disabled in the environment,
+     * then don't enable it here.
+     */
+    if (value > 0) {
+        status = simple_trnlnm(name, val_str, sizeof(val_str));
+        if (status) {
+            val_str[0] = _toupper(val_str[0]);
+            if (val_str[0] == 'D' || val_str[0] == '0' || val_str[0] == 'F')
+               return 0;
+        }
+    }
 
     index = decc$feature_get_index(name);
 
@@ -13947,7 +14028,7 @@ vmsperl_set_features(void)
     /* Allow an exception to bring Perl into the VMS debugger */
     vms_debug_on_exception = 0;
     status = simple_trnlnm("PERL_VMS_EXCEPTION_DEBUG", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T'))
         vms_debug_on_exception = 1;
@@ -13958,7 +14039,7 @@ vmsperl_set_features(void)
     /* Debug unix/vms file translation routines */
     vms_debug_fileify = 0;
     status = simple_trnlnm("PERL_VMS_FILEIFY_DEBUG", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
         if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T'))
            vms_debug_fileify = 1;
@@ -13978,7 +14059,7 @@ vmsperl_set_features(void)
     /* enable it so that the impact can be studied.                     */
     vms_bug_stat_filename = 0;
     status = simple_trnlnm("PERL_VMS_BUG_STAT_FILENAME", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
         if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T'))
            vms_bug_stat_filename = 1;
@@ -13990,7 +14071,7 @@ vmsperl_set_features(void)
     /* Create VTF-7 filenames from Unicode instead of UTF-8 */
     vms_vtf7_filenames = 0;
     status = simple_trnlnm("PERL_VMS_VTF7_FILENAMES", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T'))
         vms_vtf7_filenames = 1;
@@ -14000,9 +14081,8 @@ vmsperl_set_features(void)
 
     /* unlink all versions on unlink() or rename() */
     vms_unlink_all_versions = 0;
-    status = simple_trnlnm
-       ("PERL_VMS_UNLINK_ALL_VERSIONS", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    status = simple_trnlnm("PERL_VMS_UNLINK_ALL_VERSIONS", val_str, sizeof(val_str));
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T'))
         vms_unlink_all_versions = 1;
@@ -14014,19 +14094,22 @@ vmsperl_set_features(void)
     /* Detect running under GNV Bash or other UNIX like shell */
     gnv_unix_shell = 0;
     status = simple_trnlnm("GNV$UNIX_SHELL", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
         gnv_unix_shell = 1;
-        set_feature_default("DECC$EFS_CHARSET", 1);
         set_feature_default("DECC$FILENAME_UNIX_NO_VERSION", 1);
         set_feature_default("DECC$FILENAME_UNIX_REPORT", 1);
         set_feature_default("DECC$READDIR_DROPDOTNOTYPE", 1);
         set_feature_default("DECC$DISABLE_POSIX_ROOT", 0);
         vms_unlink_all_versions = 1;
         vms_posix_exit = 1;
+        /* Reverse default ordering of PERL_ENV_TABLES. */
+        defenv[0] = &crtlenvdsc;
+        defenv[1] = &fildevdsc;
     }
     /* Some reasonable defaults that are not CRTL defaults */
     set_feature_default("DECC$EFS_CASE_PRESERVE", 1);
     set_feature_default("DECC$ARGV_PARSE_STYLE", 1);     /* Requires extended parse. */
+    set_feature_default("DECC$EFS_CHARSET", 1);
 #endif
 
     /* hacks to see if known bugs are still present for testing */
@@ -14034,7 +14117,7 @@ vmsperl_set_features(void)
     /* PCP mode requires creating /dev/null special device file */
     decc_bug_devnull = 0;
     status = simple_trnlnm("DECC_BUG_DEVNULL", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T'))
           decc_bug_devnull = 1;
@@ -14042,17 +14125,6 @@ vmsperl_set_features(void)
          decc_bug_devnull = 0;
     }
 
-    /* UNIX directory names with no paths are broken in a lot of places */
-    decc_dir_barename = 1;
-    status = simple_trnlnm("DECC_DIR_BARENAME", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
-      val_str[0] = _toupper(val_str[0]);
-      if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T'))
-       decc_dir_barename = 1;
-      else
-       decc_dir_barename = 0;
-    }
-
 #if __CRTL_VER >= 70300000 && !defined(__VAX)
     s = decc$feature_get_index("DECC$DISABLE_TO_VMS_LOGNAME_TRANSLATION");
     if (s >= 0) {
@@ -14126,7 +14198,7 @@ vmsperl_set_features(void)
 #else
     status = simple_trnlnm
        ("DECC$DISABLE_TO_VMS_LOGNAME_TRANSLATION", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) {
           decc_disable_to_vms_logname_translation = 1;
@@ -14135,7 +14207,7 @@ vmsperl_set_features(void)
 
 #ifndef __VAX
     status = simple_trnlnm("DECC$EFS_CASE_PRESERVE", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) {
           decc_efs_case_preserve = 1;
@@ -14144,14 +14216,14 @@ vmsperl_set_features(void)
 #endif
 
     status = simple_trnlnm("DECC$FILENAME_UNIX_REPORT", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) {
           decc_filename_unix_report = 1;
        }
     }
     status = simple_trnlnm("DECC$FILENAME_UNIX_ONLY", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) {
           decc_filename_unix_only = 1;
@@ -14159,14 +14231,14 @@ vmsperl_set_features(void)
        }
     }
     status = simple_trnlnm("DECC$FILENAME_UNIX_NO_VERSION", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) {
           decc_filename_unix_no_version = 1;
        }
     }
     status = simple_trnlnm("DECC$READDIR_DROPDOTNOTYPE", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T')) {
           decc_readdir_dropdotnotype = 1;
@@ -14192,9 +14264,8 @@ vmsperl_set_features(void)
 
     /* USE POSIX/DCL Exit codes - Recommended, but needs to default to  */
     /* for strict backward compatibility */
-    status = simple_trnlnm
-       ("PERL_VMS_POSIX_EXIT", val_str, sizeof(val_str));
-    if ($VMS_STATUS_SUCCESS(status)) {
+    status = simple_trnlnm("PERL_VMS_POSIX_EXIT", val_str, sizeof(val_str));
+    if (status) {
        val_str[0] = _toupper(val_str[0]);
        if ((val_str[0] == 'E') || (val_str[0] == '1') || (val_str[0] == 'T'))
         vms_posix_exit = 1;