[patch@35055] vms.c unixify refactor

[email protected] ("John E. Malmberg")
Newsgroups perl.perl5.porters,perl.vmsperl
Message-ID <[email protected]>
This patch makes a version of unixify available for calling with out an 
implicit context, which is needed for threaded perl as several routines 
do not have a thread context.

This is the second of a multi-part conversion to remove access 
violations when internal perl warning and error routines, and memory 
allocation routines are called with a null pointer for the implicit context.

By removing the implicit context from these routines, it will cause a 
compile time error on threaded perl should one of the affected routines 
sneak back into this code.

Patches to do:

* Refactor tounixpath, (unixpath)

* Refactor fileify_dirspec (fileify)

* Refactor tovmsspec, (vmsify)

* Refactor rmsexpand

* Refactor all cases where a implicit context is not needed
   and fix cases where a null context is present not to call
   internal perl routines that will access violate.

* fgetname needs a wrapper, it is not returning the correct
   names when DECC$FILENAME_UNIX_REPORT is enabled.

This is all needed for me to proceed with the testing of VMS perl in a 
UNIX compatible mode.  Currently most of the tests are passing.

-John
[email protected]
Personal Opinion Only
vms_c_unixify.gdiff (text/plain, 19.1 KB)
--- /ref3_root/perl/vms/vms.c	Sun Dec  7 09:19:05 2008
+++ vms/vms.c	Sun Dec  7 09:35:46 2008
@@ -296,6 +296,8 @@
 static char *mp_do_tounixspec(pTHX_ const char *, char *, int, int *);
 static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int *);
 
+static char * int_tounixspec(const char *spec, char *buf, int * utf8_fl);
+
 /* see system service docs for $TRNLNM -- NOT the same as LNM$_MAX_INDEX */
 #define PERL_LNM_MAX_ALLOWED_INDEX 127
 
@@ -6733,300 +6735,367 @@
 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 */
+static char *
+int_tounixspec(const char *spec, char *buf, 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 __tounixspec_retbuf[VMS_MAXRSS];
-  char *dirend, *rslt, *cp1, *cp3, *tmp;
-  const char *cp2;
-  int devlen, dirlen, retlen = VMS_MAXRSS;
-  int expand = 1; /* guarantee room for leading and trailing slashes */
-  unsigned short int trnlnm_iter_count;
-  int cmp_rslt;
-  if (utf8_fl != NULL)
-    *utf8_fl = 0;
-
-  if (spec == NULL) return NULL;
-  if (strlen(spec) > (VMS_MAXRSS-1)) return NULL;
-  if (buf) rslt = buf;
-  else if (ts) {
-    Newx(rslt, VMS_MAXRSS, char);
-  }
-  else rslt = __tounixspec_retbuf;
+    char *dirend, *cp1, *cp3, *tmp;
+    const char *cp2;
+    int devlen, dirlen, retlen = VMS_MAXRSS;
+    int expand = 1; /* guarantee room for leading and trailing slashes */
+    unsigned short int trnlnm_iter_count;
+    int cmp_rslt;
+    if (utf8_fl != NULL)
+        *utf8_fl = 0;
 
-  /* New VMS specific format needs translation
-   * glob passes filenames with trailing '\n' and expects this preserved.
-   */
-  if (decc_posix_compliant_pathnames) {
-    if (strncmp(spec, "\"^UP^", 5) == 0) {
-      char * uspec;
-      char *tunix;
-      int tunix_len;
-      int nl_flag;
-
-      tunix = PerlMem_malloc(VMS_MAXRSS);
-      if (tunix == NULL) _ckvmssts(SS$_INSFMEM);
-      strcpy(tunix, spec);
-      tunix_len = strlen(tunix);
-      nl_flag = 0;
-      if (tunix[tunix_len - 1] == '\n') {
-	tunix[tunix_len - 1] = '\"';
-	tunix[tunix_len] = '\0';
-	tunix_len--;
-	nl_flag = 1;
-      }
-      uspec = decc$translate_vms(tunix);
-      PerlMem_free(tunix);
-      if ((int)uspec > 0) {
-	strcpy(rslt,uspec);
-	if (nl_flag) {
-	  strcat(rslt,"\n");
-	}
-	else {
-	  /* If we can not translate it, makemaker wants as-is */
-	  strcpy(rslt, spec);
-	}
-	return rslt;
-      }
+    if (vms_debug_fileify) {
+        if (spec == NULL)
+            fprintf(stderr, "int_tounixspec: spec = NULL\n");
+        else
+            fprintf(stderr, "int_tounixspec: spec = %s\n", spec);
+    }
+
+    if (spec == NULL) {
+        set_errno(EINVAL);
+        set_vaxc_errno(SS$_BADPARAM);
+        return NULL;
+    }
+    if (strlen(spec) > (VMS_MAXRSS-1)) {
+        set_errno(E2BIG);
+        set_vaxc_errno(SS$_BUFFEROVF);
+        return NULL;
     }
-  }
 
-  cmp_rslt = 0; /* Presume VMS */
-  cp1 = strchr(spec, '/');
-  if (cp1 == NULL)
-    cmp_rslt = 0;
+    /* New VMS specific format needs translation
+     * glob passes filenames with trailing '\n' and expects this preserved.
+     */
+    if (decc_posix_compliant_pathnames) {
+        if (strncmp(spec, "\"^UP^", 5) == 0) {
+            char * uspec;
+            char *tunix;
+            int tunix_len;
+            int nl_flag;
+
+            tunix = PerlMem_malloc(VMS_MAXRSS);
+            if (tunix == NULL)
+                _ckvmssts_noperl(SS$_INSFMEM);
+            strcpy(tunix, spec);
+            tunix_len = strlen(tunix);
+            nl_flag = 0;
+            if (tunix[tunix_len - 1] == '\n') {
+                tunix[tunix_len - 1] = '\"';
+                tunix[tunix_len] = '\0';
+                tunix_len--;
+                nl_flag = 1;
+            }
+            uspec = decc$translate_vms(tunix);
+            PerlMem_free(tunix);
+            if ((int)uspec > 0) {
+                strcpy(buf, uspec);
+                if (nl_flag) {
+                    strcat(buf, "\n");
+                } else {
+                    /* If we can not translate it, makemaker wants as-is */
+                    strcpy(buf, spec);
+                }
+                if (vms_debug_fileify) {
+                    fprintf(stderr, "int_tounixspec: buf = %s\n", buf);
+                }
+                return buf;
+            }
+        }
+    }
+
+    cmp_rslt = 0; /* Presume VMS */
+    cp1 = strchr(spec, '/');
+    if (cp1 == NULL)
+        cmp_rslt = 0;
 
     /* Look for EFS ^/ */
     if (decc_efs_charset) {
-      while (cp1 != NULL) {
-	cp2 = cp1 - 1;
-	if (*cp2 != '^') {
-	  /* Found illegal VMS, assume UNIX */
-	  cmp_rslt = 1;
-	  break;
-	}
-      cp1++;
-      cp1 = strchr(cp1, '/');
+        while (cp1 != NULL) {
+            cp2 = cp1 - 1;
+            if (*cp2 != '^') {
+                /* Found illegal VMS, assume UNIX */
+                cmp_rslt = 1;
+                break;
+            }
+            cp1++;
+            cp1 = strchr(cp1, '/');
+        }
     }
-  }
 
-  /* Look for "." and ".." */
-  if (decc_filename_unix_report) {
-    if (spec[0] == '.') {
-      if ((spec[1] == '\0') || (spec[1] == '\n')) {
-	cmp_rslt = 1;
-      }
-      else {
-	if ((spec[1] == '.') && ((spec[2] == '\0') || (spec[2] == '\n'))) {
-	  cmp_rslt = 1;
-	}
-      }
+    /* Look for "." and ".." */
+    if (decc_filename_unix_report) {
+        if (spec[0] == '.') {
+            if ((spec[1] == '\0') || (spec[1] == '\n')) {
+                cmp_rslt = 1;
+            } else {
+                if ((spec[1] == '.') &&
+                    ((spec[2] == '\0') || (spec[2] == '\n'))) {
+                    cmp_rslt = 1;
+                }
+            }
+        }
+    }
+    /* This is already UNIX or at least nothing VMS understands */
+    if (cmp_rslt) {
+        strcpy(buf, spec);
+        if (vms_debug_fileify) {
+            fprintf(stderr, "int_tounixspec: buf = %s\n", buf);
+        }
+        return buf;
     }
-  }
-  /* This is already UNIX or at least nothing VMS understands */
-  if (cmp_rslt) {
-    strcpy(rslt,spec);
-    return rslt;
-  }
 
-  cp1 = rslt;
-  cp2 = spec;
-  dirend = strrchr(spec,']');
-  if (dirend == NULL) dirend = strrchr(spec,'>');
-  if (dirend == NULL) dirend = strchr(spec,':');
-  if (dirend == NULL) {
-    strcpy(rslt,spec);
-    return rslt;
-  }
+    cp1 = buf;
+    cp2 = spec;
+    dirend = strrchr(spec,']');
+    if (dirend == NULL)
+        dirend = strrchr(spec,'>');
+    if (dirend == NULL)
+        dirend = strchr(spec,':');
+    if (dirend == NULL) {
+        strcpy(buf,spec);
+        if (vms_debug_fileify) {
+            fprintf(stderr, "int_tounixspec: buf = %s\n", buf);
+        }
+        return buf;
+    }
 
-  /* Special case 1 - sys$posix_root = / */
+    /* Special case 1 - sys$posix_root = / */
 #if __CRTL_VER >= 70000000
-  if (!decc_disable_posix_root) {
-    if (strncasecmp(spec, "SYS$POSIX_ROOT:", 15) == 0) {
-      *cp1 = '/';
-      cp1++;
-      cp2 = cp2 + 15;
-      }
-  }
+    if (!decc_disable_posix_root) {
+        if (strncasecmp(spec, "SYS$POSIX_ROOT:", 15) == 0) {
+            *cp1 = '/';
+            cp1++;
+            cp2 = cp2 + 15;
+        }
+    }
 #endif
 
-  /* Special case 2 - Convert NLA0: to /dev/null */
+    /* Special case 2 - Convert NLA0: to /dev/null */
 #if __CRTL_VER < 70000000
-  cmp_rslt = strncmp(spec,"NLA0:", 5);
-  if (cmp_rslt != 0)
-     cmp_rslt = strncmp(spec,"nla0:", 5);
+    cmp_rslt = strncmp(spec,"NLA0:", 5);
+    if (cmp_rslt != 0)
+        cmp_rslt = strncmp(spec,"nla0:", 5);
 #else
-  cmp_rslt = strncasecmp(spec,"NLA0:", 5);
+        cmp_rslt = strncasecmp(spec,"NLA0:", 5);
 #endif
-  if (cmp_rslt == 0) {
-    strcpy(rslt, "/dev/null");
-    cp1 = cp1 + 9;
-    cp2 = cp2 + 5;
-    if (spec[6] != '\0') {
-      cp1[9] == '/';
-      cp1++;
-      cp2++;
+    if (cmp_rslt == 0) {
+        strcpy(buf, "/dev/null");
+        cp1 = cp1 + 9;
+        cp2 = cp2 + 5;
+        if (spec[6] != '\0') {
+            cp1[9] == '/';
+            cp1++;
+            cp2++;
+        }
     }
-  }
 
-   /* Also handle special case "SYS$SCRATCH:" */
+    /* Also handle special case "SYS$SCRATCH:" */
 #if __CRTL_VER < 70000000
-  cmp_rslt = strncmp(spec,"SYS$SCRATCH:", 12);
-  if (cmp_rslt != 0)
-     cmp_rslt = strncmp(spec,"sys$scratch:", 12);
+    cmp_rslt = strncmp(spec,"SYS$SCRATCH:", 12);
+    if (cmp_rslt != 0)
+        cmp_rslt = strncmp(spec,"sys$scratch:", 12);
 #else
-  cmp_rslt = strncasecmp(spec,"SYS$SCRATCH:", 12);
+    cmp_rslt = strncasecmp(spec,"SYS$SCRATCH:", 12);
 #endif
-  tmp = PerlMem_malloc(VMS_MAXRSS);
-  if (tmp == NULL) _ckvmssts(SS$_INSFMEM);
-  if (cmp_rslt == 0) {
-  int islnm;
-
-    islnm = my_trnlnm(tmp, "TMP", 0);
-    if (!islnm) {
-      strcpy(rslt, "/tmp");
-      cp1 = cp1 + 4;
-      cp2 = cp2 + 12;
-      if (spec[12] != '\0') {
-	cp1[4] == '/';
-	cp1++;
-	cp2++;
-      }
+    tmp = PerlMem_malloc(VMS_MAXRSS);
+    if (tmp == NULL)
+        _ckvmssts_noperl(SS$_INSFMEM);
+    if (cmp_rslt == 0) {
+        int islnm;
+
+        islnm = simple_trnlnm(tmp, "TMP", VMS_MAXRSS);
+        if (!islnm) {
+            strcpy(buf, "/tmp");
+            cp1 = cp1 + 4;
+            cp2 = cp2 + 12;
+            if (spec[12] != '\0') {
+                cp1[4] == '/';
+                cp1++;
+                cp2++;
+            }
+        }
     }
-  }
 
-  if (*cp2 != '[' && *cp2 != '<') {
-    *(cp1++) = '/';
-  }
-  else {  /* the VMS spec begins with directories */
-    cp2++;
-    if (*cp2 == ']' || *cp2 == '>') {
-      *(cp1++) = '.'; *(cp1++) = '/'; *(cp1++) = '\0';
-      PerlMem_free(tmp);
-      return rslt;
-    }
-    else if ( *cp2 != '^' && *cp2 != '.' && *cp2 != '-') { /* add the implied device */
-      if (getcwd(tmp, VMS_MAXRSS-1 ,1) == NULL) {
-        if (ts) Safefree(rslt);
-	PerlMem_free(tmp);
-        return NULL;
-      }
-      trnlnm_iter_count = 0;
-      do {
-        cp3 = tmp;
-        while (*cp3 != ':' && *cp3) cp3++;
-        *(cp3++) = '\0';
-        if (strchr(cp3,']') != NULL) break;
-        trnlnm_iter_count++; 
-        if (trnlnm_iter_count >= PERL_LNM_MAX_ITER+1) break;
-      } while (vmstrnenv(tmp,tmp,0,fildev,0));
-      if (ts && !buf &&
-          ((devlen = strlen(tmp)) + (dirlen = strlen(cp2)) + 1 > retlen)) {
-        retlen = devlen + dirlen;
-        Renew(rslt,retlen+1+2*expand,char);
-        cp1 = rslt;
-      }
-      cp3 = tmp;
-      *(cp1++) = '/';
-      while (*cp3) {
-        *(cp1++) = *(cp3++);
-        if (cp1 - rslt > (VMS_MAXRSS - 1) && !ts && !buf) {
-	    PerlMem_free(tmp);
-	    return NULL; /* No room */
-	}
-      }
-      *(cp1++) = '/';
-    }
-    if ((*cp2 == '^')) {
-	/* EFS file escape, pass the next character as is */
-	/* Fix me: HEX encoding for Unicode not implemented */
-	cp2++;
-    }
-    else if ( *cp2 == '.') {
-      if (*(cp2+1) == '.' && *(cp2+2) == '.') {
-        *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '/';
-        cp2 += 3;
-      }
-      else cp2++;
+    if (*cp2 != '[' && *cp2 != '<') {
+        *(cp1++) = '/';
+    } else {  /* the VMS spec begins with directories */
+        cp2++;
+        if (*cp2 == ']' || *cp2 == '>') {
+            *(cp1++) = '.';
+        } else if ( *cp2 != '^' && *cp2 != '.' && *cp2 != '-') {
+            /* add the implied device */
+            if (getcwd(tmp, VMS_MAXRSS-1 ,1) == NULL) {
+                PerlMem_free(tmp);
+                if (vms_debug_fileify) {
+                    fprintf(stderr, "int_tounixspec: buf = NULL\n");
+                }
+                return NULL;
+            }
+            trnlnm_iter_count = 0;
+            do {
+                cp3 = tmp;
+                while (*cp3 != ':' && *cp3)
+                    cp3++;
+                *(cp3++) = '\0';
+                if (strchr(cp3,']') != NULL)
+                    break;
+                trnlnm_iter_count++; 
+                if (trnlnm_iter_count >= PERL_LNM_MAX_ITER+1)
+                    break;
+            } while (vmstrnenv(tmp,tmp,0,fildev,0));
+            cp1 = buf;
+            cp3 = tmp;
+            *(cp1++) = '/';
+            while (*cp3) {
+                *(cp1++) = *(cp3++);
+                if (cp1 - buf > (VMS_MAXRSS - 1)) {
+                    PerlMem_free(tmp);
+                    set_errno(ENAMETOOLONG);
+                    set_vaxc_errno(SS$_BUFFEROVF);
+                    if (vms_debug_fileify) {
+                        fprintf(stderr, "int_tounixspec: buf = NULL\n");
+                    }
+                    return NULL; /* No room */
+                }
+            }
+            *(cp1++) = '/';
+        }
+        if ((*cp2 == '^')) {
+            /* EFS file escape, pass the next character as is */
+            /* Fix me: HEX encoding for Unicode not implemented */
+            cp2++;
+        } else if ( *cp2 == '.') {
+            if (*(cp2+1) == '.' && *(cp2+2) == '.') {
+                *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '/';
+                cp2 += 3;
+            } else {
+                cp2++;
+            }
+        }
     }
-  }
-  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++;
-    }
-    if (*cp2 == ':') {
-      *(cp1++) = '/';
-      if (*(cp2+1) == '[') cp2++;
-    }
-    else if (*cp2 == ']' || *cp2 == '>') {
-      if (*(cp1-1) != '/') *(cp1++) = '/'; /* Don't double after ellipsis */
-    }
-    else if ((*cp2 == '.') && (*cp2-1 != '^')) {
-      *(cp1++) = '/';
-      if (*(cp2+1) == ']' || *(cp2+1) == '>') {
-        while (*(cp2+1) == ']' || *(cp2+1) == '>' ||
-               *(cp2+1) == '[' || *(cp2+1) == '<') cp2++;
-        if (!strncmp(cp2,"[000000",7) && (*(cp2+7) == ']' ||
-            *(cp2+7) == '>' || *(cp2+7) == '.')) cp2 += 7;
-      }
-      else if ( *(cp2+1) == '.' && *(cp2+2) == '.') {
-        *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) ='/';
-        cp2 += 2;
-      }
-    }
-    else if (*cp2 == '-') {
-      if (*(cp2-1) == '[' || *(cp2-1) == '<' || *(cp2-1) == '.') {
-        while (*cp2 == '-') {
-          cp2++;
-          *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '/';
-        }
-        if (*cp2 != '.' && *cp2 != ']' && *cp2 != '>') { /* we don't allow */
-          if (ts) Safefree(rslt);                        /* filespecs like */
-          set_errno(EINVAL); set_vaxc_errno(RMS$_SYN);   /* [fred.--foo.bar] */
-          return NULL;
+    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++;
+        }
+        if (*cp2 == ':') {
+            *(cp1++) = '/';
+            if (*(cp2+1) == '[')
+               cp2++;
+        } else if (*cp2 == ']' || *cp2 == '>') {
+            if (*(cp1-1) != '/') {
+                /* Don't double after ellipsis */
+                *(cp1++) = '/';
+            }
+        } else if ((*cp2 == '.') && (*cp2-1 != '^')) {
+            *(cp1++) = '/';
+            if (*(cp2+1) == ']' || *(cp2+1) == '>') {
+                while (*(cp2+1) == ']' || *(cp2+1) == '>' ||
+                       *(cp2+1) == '[' || *(cp2+1) == '<')
+                    cp2++;
+                if (!strncmp(cp2,"[000000",7) && (*(cp2+7) == ']' ||
+                    *(cp2+7) == '>' || *(cp2+7) == '.'))
+                    cp2 += 7;
+            } else if ( *(cp2+1) == '.' && *(cp2+2) == '.') {
+                *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) ='/';
+                cp2 += 2;
+            }
+        } else if (*cp2 == '-') {
+            if (*(cp2-1) == '[' || *(cp2-1) == '<' || *(cp2-1) == '.') {
+                while (*cp2 == '-') {
+                    cp2++;
+                    *(cp1++) = '.'; *(cp1++) = '.'; *(cp1++) = '/';
+                }
+                if (*cp2 != '.' && *cp2 != ']' && *cp2 != '>') {
+                    /* we don't allow filespecs like [fred.--foo.bar] */
+                    set_errno(EINVAL);
+                    set_vaxc_errno(RMS$_SYN);
+                    if (vms_debug_fileify) {
+                        fprintf(stderr, "int_tounixspec: buf = NULL\n");
+                    }
+                    return NULL;
+                }
+            } else {
+                *(cp1++) = *cp2;
+            }
+        } else {
+            *(cp1++) = *cp2;
         }
-      }
-      else *(cp1++) = *cp2;
     }
-    else *(cp1++) = *cp2;
-  }
-  while (*cp2) {
-    if ((*cp2 == '^') && (*(cp2+1) == '.')) cp2++;  /* '^.' --> '.' */
-    *(cp1++) = *(cp2++);
-  }
-  *cp1 = '\0';
+    while (*cp2) {
+        if ((*cp2 == '^') && (*(cp2+1) == '.')) cp2++;  /* '^.' --> '.' */
+        *(cp1++) = *(cp2++);
+    }
+    *cp1 = '\0';
 
-  /* This still leaves /000000/ when working with a
-   * VMS device root or concealed root.
-   */
-  {
-  int ulen;
-  char * zeros;
+    /* This still leaves /000000/ when working with a
+     * VMS device root or concealed root.
+     */
+    {
+    int ulen;
+    char * zeros;
 
-      ulen = strlen(rslt);
+        ulen = strlen(buf);
 
-      /* Get rid of "000000/ in rooted filespecs */
-      if (ulen > 7) {
-	zeros = strstr(rslt, "/000000/");
-	if (zeros != NULL) {
-	  int mlen;
-	  mlen = ulen - (zeros - rslt) - 7;
-	  memmove(zeros, &zeros[7], mlen);
-	  ulen = ulen - 7;
-	  rslt[ulen] = '\0';
-	}
-      }
-  }
+        /* Get rid of "000000/ in rooted filespecs */
+        if (ulen > 7) {
+            zeros = strstr(buf, "/000000/");
+            if (zeros != NULL) {
+                int mlen;
+                mlen = ulen - (zeros - buf) - 7;
+                memmove(zeros, &zeros[7], mlen);
+                ulen = ulen - 7;
+                buf[ulen] = '\0';
+            }
+        }
+    }
+
+    if (vms_debug_fileify) {
+        fprintf(stderr, "int_tounixspec: buf = %s\n", buf);
+    }
+    return buf;
+}
+
+
+/*{{{ 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 __tounixspec_retbuf[VMS_MAXRSS];
+    char * unixspec, *ret_spec, *ret_buf;
+
+    unixspec = NULL;
+    ret_buf = buf;
+    if (ret_buf == NULL) {
+        if (ts) {
+            Newx(unixspec, VMS_MAXRSS, char);
+            if (unixspec == NULL)
+                _ckvmssts(SS$_INSFMEM);
+            ret_buf = unixspec;
+        } else {
+            ret_buf = __tounixspec_retbuf;
+        }
+    }
+
+    ret_spec = int_tounixspec(spec, ret_buf, utf8_fl);
+
+    if (ret_spec == NULL) {
+       /* Cleanup on isle 5, if this is thread specific we need to deallocate */
+       if (unixspec)
+           Safefree(unixspec);
+    }
+
+    return ret_spec;
 
-  return rslt;
 
 }  /* end of do_tounixspec() */
+
 /*}}}*/
 /* External entry points */
 char *Perl_tounixspec(pTHX_ const char *spec, char *buf)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.