This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Re: [PATCH] eof() coredumps when ARGV is aliased to another filehandle
[perl5.git] / doio.c
diff --git a/doio.c b/doio.c
index ea5ab29..0520992 100644 (file)
--- a/doio.c
+++ b/doio.c
@@ -1,6 +1,6 @@
 /*    doio.c
  *
- *    Copyright (c) 1991-2000, Larry Wall
+ *    Copyright (c) 1991-2002, Larry Wall
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
 #include <signal.h>
 #endif
 
-/* XXX If this causes problems, set i_unistd=undef in the hint file.  */
-#ifdef I_UNISTD
-#  include <unistd.h>
-#endif
-
-#if defined(HAS_SOCKET) && !defined(VMS) /* VMS handles sockets via vmsish.h */
-# include <sys/socket.h>
-# if defined(USE_SOCKS) && defined(I_SOCKS)
-#   include <socks.h>
-# endif 
-# ifdef I_NETBSD
-#  include <netdb.h>
-# endif
-# ifndef ENOTSOCK
-#  ifdef I_NET_ERRNO
-#   include <net/errno.h>
-#  endif
-# endif
-#endif
-
 bool
 Perl_do_open(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
             int rawmode, int rawperm, PerlIO *supplied_fp)
 {
-    return do_open9(gv, name, len, as_raw, rawmode, rawperm,
-                   supplied_fp, Nullsv, 0);
+    return do_openn(gv, name, len, as_raw, rawmode, rawperm,
+                   supplied_fp, (SV **) NULL, 0);
 }
 
 bool
@@ -84,9 +64,19 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
              int rawmode, int rawperm, PerlIO *supplied_fp, SV *svs,
              I32 num_svs)
 {
+    return do_openn(gv, name, len, as_raw, rawmode, rawperm,
+                   supplied_fp, &svs, 1);
+}
+
+bool
+Perl_do_openn(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
+             int rawmode, int rawperm, PerlIO *supplied_fp, SV **svp,
+             I32 num_svs)
+{
     register IO *io = GvIOn(gv);
     PerlIO *saveifp = Nullfp;
     PerlIO *saveofp = Nullfp;
+    int savefd = -1;
     char savetype = IoTYPE_CLOSED;
     int writing = 0;
     PerlIO *fp;
@@ -94,9 +84,14 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
     int result;
     bool was_fdopen = FALSE;
     bool in_raw = 0, in_crlf = 0, out_raw = 0, out_crlf = 0;
+    char *type  = NULL;
+    char mode[8];              /* stdio file mode ("r\0", "rb\0", "r+b\0" etc.) */
+    SV *namesv;
 
+    Zero(mode,sizeof(mode),char);
     PL_forkprocess = 1;                /* assume true if no fork */
 
+    /* Collect default raw/crlf info from the op */
     if (PL_op && PL_op->op_type == OP_OPEN) {
        /* set up disciplines */
        U8 flags = PL_op->op_private;
@@ -106,15 +101,20 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
        out_crlf = (flags & OPpOPEN_OUT_CRLF);
     }
 
+    /* If currently open - close before we re-open */
     if (IoIFP(io)) {
        fd = PerlIO_fileno(IoIFP(io));
-       if (IoTYPE(io) == IoTYPE_STD)
+       if (IoTYPE(io) == IoTYPE_STD) {
+           /* This is a clone of one of STD* handles */
            result = 0;
-       else if (fd <= PL_maxsysfd) {
-           saveifp = IoIFP(io);
-           saveofp = IoOFP(io);
+       }
+       else if (fd >= 0 && fd <= PL_maxsysfd) {
+           /* This is one of the original STD* handles */
+           saveifp  = IoIFP(io);
+           saveofp  = IoOFP(io);
            savetype = IoTYPE(io);
-           result = 0;
+           savefd   = fd;
+           result   = 0;
        }
        else if (IoTYPE(io) == IoTYPE_PIPE)
            result = PerlProc_pclose(IoIFP(io));
@@ -128,113 +128,125 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
        }
        else
            result = PerlIO_close(IoIFP(io));
-       if (result == EOF && fd > PL_maxsysfd)
+       if (result == EOF && fd > PL_maxsysfd) {
+           /* Why is this not Perl_warn*() call ? */
            PerlIO_printf(Perl_error_log,
                          "Warning: unable to close filehandle %s properly.\n",
                          GvENAME(gv));
+       }
        IoOFP(io) = IoIFP(io) = Nullfp;
     }
 
     if (as_raw) {
-#if defined(USE_64_BIT_RAWIO) && defined(O_LARGEFILE)
-       rawmode |= O_LARGEFILE;
+        /* sysopen style args, i.e. integer mode and permissions */
+       STRLEN ix = 0;
+       int appendtrunc =
+            0
+#ifdef O_APPEND        /* Not fully portable. */
+            |O_APPEND
 #endif
-
-#ifndef O_ACCMODE
-#define O_ACCMODE 3            /* Assume traditional implementation */
+#ifdef O_TRUNC /* Not fully portable. */
+            |O_TRUNC
 #endif
+            ;
+       int modifyingmode =
+            O_WRONLY|O_RDWR|O_CREAT|appendtrunc;
+       int ismodifying;
 
-       switch (result = rawmode & O_ACCMODE) {
-       case O_RDONLY:
-            IoTYPE(io) = IoTYPE_RDONLY;
-            break;
-       case O_WRONLY:
-            IoTYPE(io) = IoTYPE_WRONLY;
-            break;
-       case O_RDWR:
-       default:
-            IoTYPE(io) = IoTYPE_RDWR;
-            break;
+       if (num_svs != 0) {
+            Perl_croak(aTHX_ "panic: sysopen with multiple args");
        }
+       /* It's not always
 
-       writing = (result > 0);
-       fd = PerlLIO_open3(name, rawmode, rawperm);
+          O_RDONLY 0
+          O_WRONLY 1
+          O_RDWR   2
 
-       if (fd == -1)
-           fp = NULL;
-       else {
-           char fpmode[4];
-           STRLEN ix = 0;
-           if (result == O_RDONLY)
-               fpmode[ix++] = 'r';
-#ifdef O_APPEND
-           else if (rawmode & O_APPEND) {
-               fpmode[ix++] = 'a';
-               if (result != O_WRONLY)
-                   fpmode[ix++] = '+';
-           }
-#endif
-           else {
-               if (result == O_WRONLY)
-                   fpmode[ix++] = 'w';
-               else {
-                   fpmode[ix++] = 'r';
-                   fpmode[ix++] = '+';
-               }
-           }
-           if (rawmode & O_BINARY)
-               fpmode[ix++] = 'b';
-           fpmode[ix] = '\0';
-           fp = PerlIO_fdopen(fd, fpmode);
-           if (!fp)
-               PerlLIO_close(fd);
+          It might be (in OS/390 and Mac OS Classic it is)
+
+          O_WRONLY 1
+          O_RDONLY 2
+          O_RDWR   3
+
+          This means that simple & with O_RDWR would look
+          like O_RDONLY is present.  Therefore we have to
+          be more careful.
+       */
+       if ((ismodifying = (rawmode & modifyingmode))) {
+            if ((ismodifying & O_WRONLY) == O_WRONLY ||
+                (ismodifying & O_RDWR)   == O_RDWR   ||
+                (ismodifying & (O_CREAT|appendtrunc)))
+                 TAINT_PROPER("sysopen");
        }
+       mode[ix++] = '#'; /* Marker to openn to use numeric "sysopen" */
+
+#if defined(USE_64_BIT_RAWIO) && defined(O_LARGEFILE)
+       rawmode |= O_LARGEFILE; /* Transparently largefiley. */
+#endif
+
+        IoTYPE(io) = PerlIO_intmode2str(rawmode, &mode[ix], &writing);
+
+       namesv = sv_2mortal(newSVpvn(name,strlen(name)));
+       num_svs = 1;
+       svp = &namesv;
+        type = Nullch;
+       fp = PerlIO_openn(aTHX_ type, mode, -1, rawmode, rawperm, NULL, num_svs, svp);
     }
     else {
-       char *type;
+       /* Regular (non-sys) open */
        char *oname = name;
-       STRLEN tlen;
        STRLEN olen = len;
-       char mode[4];           /* stdio file mode ("r\0", "rb\0", "r+b\0" etc.) */
-       int dodup;
+       char *tend;
+       int dodup = 0;
+       PerlIO *that_fp = NULL;
 
        type = savepvn(name, len);
-       tlen = len;
+       tend = type+len;
        SAVEFREEPV(type);
+
+        /* Lose leading and trailing white space */
+        /*SUPPRESS 530*/
+        for (; isSPACE(*type); type++) ;
+        while (tend > type && isSPACE(tend[-1]))
+           *--tend = '\0';
+
        if (num_svs) {
-           STRLEN l;
-           name = SvPV(svs, l) ;
+           /* New style explict name, type is just mode and discipline/layer info */
+           STRLEN l = 0;
+           name = SvOK(*svp) ? SvPV(*svp, l) : "";
            len = (I32)l;
            name = savepvn(name, len);
            SAVEFREEPV(name);
        }
        else {
-           while (tlen && isSPACE(type[tlen-1]))
-               type[--tlen] = '\0';
            name = type;
-           len = tlen;
+           len  = tend-type;
        }
-       mode[0] = mode[1] = mode[2] = mode[3] = '\0';
        IoTYPE(io) = *type;
-       if (*type == IoTYPE_RDWR && tlen > 1 && type[tlen-1] != IoTYPE_PIPE) { /* scary */
+       if ((*type == IoTYPE_RDWR) && /* scary */
+           (*(type+1) == IoTYPE_RDONLY || *(type+1) == IoTYPE_WRONLY) &&
+           ((!num_svs || (tend > type+1 && tend[-1] != IoTYPE_PIPE)))) {
+        TAINT_PROPER("open");
            mode[1] = *type++;
-           --tlen;
            writing = 1;
        }
 
        if (*type == IoTYPE_PIPE) {
-           if (num_svs && (tlen != 2 || type[1] != IoTYPE_STD)) {
-             unknown_desr:
-               Perl_croak(aTHX_ "Unknown open() mode '%.*s'", (int)olen, oname);
+           if (num_svs) {
+               if (type[1] != IoTYPE_STD) {
+                 unknown_desr:
+                   Perl_croak(aTHX_ "Unknown open() mode '%.*s'", (int)olen, oname);
+               }
+               type++;
            }
            /*SUPPRESS 530*/
-           for (type++, tlen--; isSPACE(*type); type++, tlen--) ;
+           for (type++; isSPACE(*type); type++) ;
            if (!num_svs) {
                name = type;
-               len = tlen;
+               len = tend-type;
            }
-           if (*name == '\0') { /* command is missing 19990114 */
-               dTHR;
+           if (*name == '\0') {
+               /* command is missing 19990114 */
                if (ckWARN(WARN_PIPE))
                    Perl_warner(aTHX_ WARN_PIPE, "Missing command in piped open");
                errno = EPIPE;
@@ -243,23 +255,23 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
            if (strNE(name,"-") || num_svs)
                TAINT_ENV();
            TAINT_PROPER("piped open");
-           if (name[len-1] == '|') {
-               dTHR;
+           if (!num_svs && name[len-1] == '|') {
                name[--len] = '\0' ;
                if (ckWARN(WARN_PIPE))
                    Perl_warner(aTHX_ WARN_PIPE, "Can't open bidirectional pipe");
            }
-           {
-               char *mode;
-               if (out_raw)
-                   mode = "wb";
-               else if (out_crlf)
-                   mode = "wt";
-               else
-                   mode = "w";
+           mode[0] = 'w';
+           writing = 1;
+           if (out_raw)
+               strcat(mode, "b");
+           else if (out_crlf)
+               strcat(mode, "t");
+           if (num_svs > 1) {
+               fp = PerlProc_popen_list(mode, num_svs, svp);
+           }
+           else {
                fp = PerlProc_popen(name,mode);
            }
-           writing = 1;
        }
        else if (*type == IoTYPE_WRONLY) {
            TAINT_PROPER("open");
@@ -268,10 +280,10 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
                /* Two IoTYPE_WRONLYs in a row make for an IoTYPE_APPEND. */
                mode[0] = IoTYPE(io) = IoTYPE_APPEND;
                type++;
-               tlen--;
            }
-           else
+           else {
                mode[0] = 'w';
+           }
            writing = 1;
 
            if (out_raw)
@@ -279,54 +291,73 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
            else if (out_crlf)
                strcat(mode, "t");
 
-           if (num_svs && tlen != 1)
-               goto unknown_desr;
            if (*type == '&') {
-               name = type;
              duplicity:
-               dodup = 1;
-               name++;
-               if (*name == '=') {
+               dodup = PERLIO_DUP_FD;
+               type++;
+               if (*type == '=') {
                    dodup = 0;
-                   name++;
+                   type++;
                }
-               if (!*name && supplied_fp)
+               if (!num_svs && !*type && supplied_fp) {
+                   /* "<+&" etc. is used by typemaps */
                    fp = supplied_fp;
+               }
                else {
-                   /*SUPPRESS 530*/
-                   for (; isSPACE(*name); name++) ;
-                   if (isDIGIT(*name))
-                       fd = atoi(name);
+                   if (num_svs > 1) {
+                       Perl_croak(aTHX_ "More than one argument to '%c&' open",IoTYPE(io));
+                   }
+                   if (num_svs && SvIOK(*svp)) {
+                       fd = SvUV(*svp);
+                   }
+                   else if (isDIGIT(*type)) {
+                       /*SUPPRESS 530*/
+                       for (; isSPACE(*type); type++) ;
+                       fd = atoi(type);
+                   }
                    else {
                        IO* thatio;
-                       gv = gv_fetchpv(name,FALSE,SVt_PVIO);
-                       thatio = GvIO(gv);
+                       if (num_svs) {
+                           thatio = sv_2io(*svp);
+                       }
+                       else {
+                           GV *thatgv;
+                           /*SUPPRESS 530*/
+                           for (; isSPACE(*type); type++) ;
+                           thatgv = gv_fetchpv(type,FALSE,SVt_PVIO);
+                           thatio = GvIO(thatgv);
+                       }
                        if (!thatio) {
 #ifdef EINVAL
                            SETERRNO(EINVAL,SS$_IVCHAN);
 #endif
                            goto say_false;
                        }
-                       if (IoIFP(thatio)) {
-                           PerlIO *fp = IoIFP(thatio);
+                       if ((that_fp = IoIFP(thatio))) {
                            /* Flush stdio buffer before dup. --mjd
                             * Unfortunately SEEK_CURing 0 seems to
                             * be optimized away on most platforms;
                             * only Solaris and Linux seem to flush
                             * on that. --jhi */
-                           PerlIO_seek(fp, 0, SEEK_CUR);
+#ifdef USE_SFIO
+                           /* sfio fails to clear error on next
+                              sfwrite, contrary to documentation.
+                              -- Nick Clark */
+                           if (PerlIO_seek(that_fp, 0, SEEK_CUR) == -1)
+                               PerlIO_clearerr(that_fp);
+#endif
                            /* On the other hand, do all platforms
                             * take gracefully to flushing a read-only
                             * filehandle?  Perhaps we should do
                             * fsetpos(src)+fgetpos(dst)?  --nik */
-                           PerlIO_flush(fp);
-                           fd = PerlIO_fileno(fp);
+                           PerlIO_flush(that_fp);
+                           fd = PerlIO_fileno(that_fp);
                            /* When dup()ing STDIN, STDOUT or STDERR
                             * explicitly set appropriate access mode */
-                           if (IoIFP(thatio) == PerlIO_stdout()
-                               || IoIFP(thatio) == PerlIO_stderr())
+                           if (that_fp == PerlIO_stdout()
+                               || that_fp == PerlIO_stderr())
                                IoTYPE(io) = IoTYPE_WRONLY;
-                           else if (IoIFP(thatio) == PerlIO_stdin())
+                           else if (that_fp == PerlIO_stdin())
                                 IoTYPE(io) = IoTYPE_RDONLY;
                            /* When dup()ing a socket, say result is
                             * one as well */
@@ -336,31 +367,47 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
                        else
                            fd = -1;
                    }
-                   if (dodup)
-                       fd = PerlLIO_dup(fd);
-                   else
-                       was_fdopen = TRUE;
-                   if (!(fp = PerlIO_fdopen(fd,mode))) {
+                   if (!num_svs)
+                       type = Nullch;
+                   if (that_fp) {
+                       fp = PerlIO_fdupopen(aTHX_ that_fp, NULL, dodup);
+                   }
+                   else {
                        if (dodup)
-                           PerlLIO_close(fd);
+                           fd = PerlLIO_dup(fd);
+                       else
+                           was_fdopen = TRUE;
+                       if (!(fp = PerlIO_openn(aTHX_ type,mode,fd,0,0,NULL,num_svs,svp))) {
+                           if (dodup)
+                               PerlLIO_close(fd);
+                       }
                    }
                }
-           }
+           } /* & */
            else {
                /*SUPPRESS 530*/
                for (; isSPACE(*type); type++) ;
-               if (*type == IoTYPE_STD && !type[1]) {
+               if (*type == IoTYPE_STD && (!type[1] || isSPACE(type[1]) || type[1] == ':')) {
+                   /*SUPPRESS 530*/
+                   type++;
                    fp = PerlIO_stdout();
                    IoTYPE(io) = IoTYPE_STD;
+                   if (num_svs > 1) {
+                       Perl_croak(aTHX_ "More than one argument to '>%c' open",IoTYPE_STD);
+                   }
                }
                else  {
-                   fp = PerlIO_open((num_svs ? name : type), mode);
+                   if (!num_svs) {
+                       namesv = sv_2mortal(newSVpvn(type,strlen(type)));
+                       num_svs = 1;
+                       svp = &namesv;
+                       type = Nullch;
+                   }
+                   fp = PerlIO_openn(aTHX_ type,mode,-1,0,0,NULL,num_svs,svp);
                }
-           }
+           } /* !& */
        }
        else if (*type == IoTYPE_RDONLY) {
-           if (num_svs && tlen != 1)
-               goto unknown_desr;
            /*SUPPRESS 530*/
            for (type++; isSPACE(*type); type++) ;
            mode[0] = 'r';
@@ -370,31 +417,43 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
                strcat(mode, "t");
 
            if (*type == '&') {
-               name = type;
                goto duplicity;
            }
-           if (*type == IoTYPE_STD && !type[1]) {
+           if (*type == IoTYPE_STD && (!type[1] || isSPACE(type[1]) || type[1] == ':')) {
+               /*SUPPRESS 530*/
+               type++;
                fp = PerlIO_stdin();
                IoTYPE(io) = IoTYPE_STD;
+               if (num_svs > 1) {
+                   Perl_croak(aTHX_ "More than one argument to '<%c' open",IoTYPE_STD);
+               }
+           }
+           else {
+               if (!num_svs) {
+                   namesv = sv_2mortal(newSVpvn(type,strlen(type)));
+                   num_svs = 1;
+                   svp = &namesv;
+                   type = Nullch;
+               }
+               fp = PerlIO_openn(aTHX_ type,mode,-1,0,0,NULL,num_svs,svp);
            }
-           else
-               fp = PerlIO_open((num_svs ? name : type), mode);
        }
-       else if (tlen > 1 && type[tlen-1] == IoTYPE_PIPE) {
+       else if ((num_svs && type[0] == IoTYPE_STD && type[1] == IoTYPE_PIPE) ||
+                (!num_svs && tend > type+1 && tend[-1] == IoTYPE_PIPE)) {
            if (num_svs) {
-               if (tlen != 2 || type[0] != IoTYPE_STD)
-                   goto unknown_desr;
+               type += 2;   /* skip over '-|' */
            }
            else {
-               type[--tlen] = '\0';
-               while (tlen && isSPACE(type[tlen-1]))
-                   type[--tlen] = '\0';
+               *--tend = '\0';
+               while (tend > type && isSPACE(tend[-1]))
+                   *--tend = '\0';
                /*SUPPRESS 530*/
                for (; isSPACE(*type); type++) ;
                name = type;
+               len  = tend-type;
            }
-           if (*name == '\0') { /* command is missing 19990114 */
-               dTHR;
+           if (*name == '\0') {
+               /* command is missing 19990114 */
                if (ckWARN(WARN_PIPE))
                    Perl_warner(aTHX_ WARN_PIPE, "Missing command in piped open");
                errno = EPIPE;
@@ -403,14 +462,15 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
            if (strNE(name,"-") || num_svs)
                TAINT_ENV();
            TAINT_PROPER("piped open");
-           {
-               char *mode;
-               if (in_raw)
-                   mode = "rb";
-               else if (in_crlf)
-                   mode = "rt";
-               else
-                   mode = "r";
+           mode[0] = 'r';
+           if (in_raw)
+               strcat(mode, "b");
+           else if (in_crlf)
+               strcat(mode, "t");
+           if (num_svs > 1) {
+               fp = PerlProc_popen_list(mode,num_svs,svp);
+           }
+           else {
                fp = PerlProc_popen(name,mode);
            }
            IoTYPE(io) = IoTYPE_PIPE;
@@ -422,35 +482,57 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
            IoTYPE(io) = IoTYPE_RDONLY;
            /*SUPPRESS 530*/
            for (; isSPACE(*name); name++) ;
+           mode[0] = 'r';
+           if (in_raw)
+               strcat(mode, "b");
+           else if (in_crlf)
+               strcat(mode, "t");
            if (strEQ(name,"-")) {
                fp = PerlIO_stdin();
                IoTYPE(io) = IoTYPE_STD;
            }
            else {
-               char *mode;
-               if (in_raw)
-                   mode = "rb";
-               else if (in_crlf)
-                   mode = "rt";
-               else
-                   mode = "r";
-               fp = PerlIO_open(name,mode);
+               if (!num_svs) {
+                   namesv = sv_2mortal(newSVpvn(type,strlen(type)));
+                   num_svs = 1;
+                   svp = &namesv;
+                   type = Nullch;
+               }
+               fp = PerlIO_openn(aTHX_ type,mode,-1,0,0,NULL,num_svs,svp);
            }
        }
     }
     if (!fp) {
-       dTHR;
        if (ckWARN(WARN_NEWLINE) && IoTYPE(io) == IoTYPE_RDONLY && strchr(name, '\n'))
            Perl_warner(aTHX_ WARN_NEWLINE, PL_warn_nl, "open");
        goto say_false;
     }
-    if (IoTYPE(io) &&
-      IoTYPE(io) != IoTYPE_PIPE && IoTYPE(io) != IoTYPE_STD) {
-       dTHR;
-       if (PerlLIO_fstat(PerlIO_fileno(fp),&PL_statbuf) < 0) {
-           (void)PerlIO_close(fp);
+
+    if (ckWARN(WARN_IO)) {
+       if ((IoTYPE(io) == IoTYPE_RDONLY) &&
+           (fp == PerlIO_stdout() || fp == PerlIO_stderr())) {
+               Perl_warner(aTHX_ WARN_IO,
+                           "Filehandle STD%s opened only for input",
+                           (fp == PerlIO_stdout()) ? "OUT" : "ERR");
+       }
+       else if ((IoTYPE(io) == IoTYPE_WRONLY) && fp == PerlIO_stdin()) {
+               Perl_warner(aTHX_ WARN_IO,
+                           "Filehandle STDIN opened only for output");
+       }
+    }
+
+    fd = PerlIO_fileno(fp);
+    /* If there is no fd (e.g. PerlIO::Scalar) assume it isn't a
+     * socket - this covers PerlIO::Scalar - otherwise unless we "know" the
+     * type probe for socket-ness.
+     */
+    if (IoTYPE(io) && IoTYPE(io) != IoTYPE_PIPE && IoTYPE(io) != IoTYPE_STD && fd >= 0) {
+       if (PerlLIO_fstat(fd,&PL_statbuf) < 0) {
+           /* If PerlIO claims to have fd we had better be able to fstat() it. */
+           (void) PerlIO_close(fp);
            goto say_false;
        }
+#ifndef PERL_MICRO
        if (S_ISSOCK(PL_statbuf.st_mode))
            IoTYPE(io) = IoTYPE_SOCKET; /* in case a socket was passed in to us */
 #ifdef HAS_SOCKET
@@ -463,71 +545,84 @@ Perl_do_open9(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
            && IoTYPE(io) != IoTYPE_WRONLY  /* Dups of STD* filehandles already have */
            && IoTYPE(io) != IoTYPE_RDONLY  /* type so they aren't marked as sockets */
        ) {                                 /* on OS's that return 0 on fstat()ed pipe */
-           char tmpbuf[256];
-           Sock_size_t buflen = sizeof tmpbuf;
-           if (PerlSock_getsockname(PerlIO_fileno(fp), (struct sockaddr *)tmpbuf,
-                           &buflen) >= 0
-                 || errno != ENOTSOCK)
-               IoTYPE(io) = IoTYPE_SOCKET; /* some OS's return 0 on fstat()ed socket */
-                               /* but some return 0 for streams too, sigh */
+            char tmpbuf[256];
+            Sock_size_t buflen = sizeof tmpbuf;
+            if (PerlSock_getsockname(fd, (struct sockaddr *)tmpbuf, &buflen) >= 0
+                     || errno != ENOTSOCK)
+                   IoTYPE(io) = IoTYPE_SOCKET; /* some OS's return 0 on fstat()ed socket */
+                                               /* but some return 0 for streams too, sigh */
        }
-#endif
+#endif /* HAS_SOCKET */
+#endif /* !PERL_MICRO */
     }
+
+    /* Eeek - FIXME !!!
+     * If this is a standard handle we discard all the layer stuff
+     * and just dup the fd into whatever was on the handle before !
+     */
+
     if (saveifp) {             /* must use old fp? */
-       fd = PerlIO_fileno(saveifp);
+        /* If fd is less that PL_maxsysfd i.e. STDIN..STDERR
+           then dup the new fileno down
+         */
        if (saveofp) {
-           PerlIO_flush(saveofp);              /* emulate PerlIO_close() */
+           PerlIO_flush(saveofp);      /* emulate PerlIO_close() */
            if (saveofp != saveifp) {   /* was a socket? */
                PerlIO_close(saveofp);
-               if (fd > 2)
-                   Safefree(saveofp);
            }
        }
-       if (fd != PerlIO_fileno(fp)) {
+       if (savefd != fd) {
            Pid_t pid;
            SV *sv;
-
-           PerlLIO_dup2(PerlIO_fileno(fp), fd);
+           /* Still a small can-of-worms here if (say) PerlIO::Scalar
+              is assigned to (say) STDOUT - for now let dup2() fail
+              and provide the error
+            */
+           if (PerlLIO_dup2(fd, savefd) < 0) {
+               (void)PerlIO_close(fp);
+               goto say_false;
+           }
+#ifdef VMS
+           if (savefd != PerlIO_fileno(PerlIO_stdin())) {
+             char newname[FILENAME_MAX+1];
+             if (PerlIO_getname(fp, newname)) {
+               if (fd == PerlIO_fileno(PerlIO_stdout())) Perl_vmssetuserlnm(aTHX_ "SYS$OUTPUT", newname);
+               if (fd == PerlIO_fileno(PerlIO_stderr())) Perl_vmssetuserlnm(aTHX_ "SYS$ERROR",  newname);
+             }
+           }
+#endif
            LOCK_FDPID_MUTEX;
-           sv = *av_fetch(PL_fdpid,PerlIO_fileno(fp),TRUE);
+           sv = *av_fetch(PL_fdpid,fd,TRUE);
            (void)SvUPGRADE(sv, SVt_IV);
            pid = SvIVX(sv);
            SvIVX(sv) = 0;
-           sv = *av_fetch(PL_fdpid,fd,TRUE);
+           sv = *av_fetch(PL_fdpid,savefd,TRUE);
            UNLOCK_FDPID_MUTEX;
            (void)SvUPGRADE(sv, SVt_IV);
            SvIVX(sv) = pid;
-           if (!was_fdopen)
+           if (!was_fdopen) {
                PerlIO_close(fp);
-
+           }
        }
        fp = saveifp;
        PerlIO_clearerr(fp);
+       fd = PerlIO_fileno(fp);
     }
 #if defined(HAS_FCNTL) && defined(F_SETFD)
-    {
+    if (fd >= 0) {
        int save_errno = errno;
-       fd = PerlIO_fileno(fp);
        fcntl(fd,F_SETFD,fd > PL_maxsysfd); /* can change errno */
        errno = save_errno;
     }
 #endif
     IoIFP(io) = fp;
+
     IoFLAGS(io) &= ~IOf_NOLINE;
     if (writing) {
-       dTHR;
        if (IoTYPE(io) == IoTYPE_SOCKET
-           || (IoTYPE(io) == IoTYPE_WRONLY && S_ISCHR(PL_statbuf.st_mode)) )
-       {
-           char *mode;
-           if (out_raw)
-               mode = "wb";
-           else if (out_crlf)
-               mode = "wt";
-           else
-               mode = "w";
-
-           if (!(IoOFP(io) = PerlIO_fdopen(PerlIO_fileno(fp),mode))) {
+           || (IoTYPE(io) == IoTYPE_WRONLY && fd >= 0 && S_ISCHR(PL_statbuf.st_mode)) ) {
+           mode[0] = 'w';
+           if (!(IoOFP(io) = PerlIO_openn(aTHX_ type,mode,fd,0,0,NULL,num_svs,svp))) {
                PerlIO_close(fp);
                IoIFP(io) = Nullfp;
                goto say_false;
@@ -577,7 +672,6 @@ Perl_nextargv(pTHX_ register GV *gv)
     }
     PL_filemode = 0;
     while (av_len(GvAV(gv)) >= 0) {
-       dTHR;
        STRLEN oldlen;
        sv = av_shift(GvAV(gv));
        SAVEFREESV(sv);
@@ -623,11 +717,11 @@ Perl_nextargv(pTHX_ register GV *gv)
                        sv_catpv(sv,PL_inplace);
                    }
 #ifndef FLEXFILENAMES
-                   if (PerlLIO_stat(SvPVX(sv),&PL_statbuf) >= 0
-                     && PL_statbuf.st_dev == filedev
-                     && PL_statbuf.st_ino == fileino
+                   if ((PerlLIO_stat(SvPVX(sv),&PL_statbuf) >= 0
+                        && PL_statbuf.st_dev == filedev
+                        && PL_statbuf.st_ino == fileino)
 #ifdef DJGPP
-                      || (_djstat_fail_bits & _STFAIL_TRUENAME)!=0
+                       || ((_djstat_fail_bits & _STFAIL_TRUENAME)!=0)
 #endif
                       )
                    {
@@ -643,7 +737,7 @@ Perl_nextargv(pTHX_ register GV *gv)
 #if !defined(DOSISH) && !defined(__CYGWIN__)
                    if (PerlLIO_rename(PL_oldname,SvPVX(sv)) < 0) {
                        if (ckWARN_d(WARN_INPLACE))     
-                           Perl_warner(aTHX_ WARN_INPLACE, 
+                           Perl_warner(aTHX_ WARN_INPLACE,
                              "Can't rename %s to %s: %s, skipping file",
                              PL_oldname, SvPVX(sv), Strerror(errno) );
                        do_close(gv,FALSE);
@@ -726,7 +820,6 @@ Perl_nextargv(pTHX_ register GV *gv)
            return IoIFP(GvIOp(gv));
        }
        else {
-           dTHR;
            if (ckWARN_d(WARN_INPLACE)) {
                int eno = errno;
                if (PerlLIO_stat(PL_oldname, &PL_statbuf) >= 0
@@ -821,7 +914,6 @@ Perl_do_close(pTHX_ GV *gv, bool not_implicit)
     io = GvIO(gv);
     if (!io) {         /* never opened */
        if (not_implicit) {
-           dTHR;
            if (ckWARN(WARN_UNOPENED)) /* no check for closed here */
                report_evil_fh(gv, io, PL_op->op_type);
            SETERRNO(EBADF,SS$_IVCHAN);
@@ -877,7 +969,6 @@ Perl_io_close(pTHX_ IO *io, bool not_implicit)
 bool
 Perl_do_eof(pTHX_ GV *gv)
 {
-    dTHR;
     register IO *io;
     int ch;
 
@@ -885,24 +976,8 @@ Perl_do_eof(pTHX_ GV *gv)
 
     if (!io)
        return TRUE;
-    else if (ckWARN(WARN_IO)
-            && (IoTYPE(io) == IoTYPE_WRONLY || IoIFP(io) == PerlIO_stdout()
-                || IoIFP(io) == PerlIO_stderr()))
-    {
-       /* integrate to report_evil_fh()? */
-        char *name = NULL; 
-       if (isGV(gv)) {
-           SV* sv = sv_newmortal();
-           gv_efullname4(sv, gv, Nullch, FALSE);
-           name = SvPV_nolen(sv);
-       }
-       if (name && *name)
-           Perl_warner(aTHX_ WARN_IO,
-                       "Filehandle %s opened only for output", name);
-       else
-           Perl_warner(aTHX_ WARN_IO,
-                       "Filehandle opened only for output");
-    }
+    else if (ckWARN(WARN_IO) && (IoTYPE(io) == IoTYPE_WRONLY))
+       report_evil_fh(gv, io, OP_phoney_OUTPUT_ONLY);
 
     while (IoIFP(io)) {
 
@@ -916,12 +991,13 @@ Perl_do_eof(pTHX_ GV *gv)
            (void)PerlIO_ungetc(IoIFP(io),ch);
            return FALSE;
        }
+
         if (PerlIO_has_cntptr(IoIFP(io)) && PerlIO_canset_cnt(IoIFP(io))) {
            if (PerlIO_get_cnt(IoIFP(io)) < -1)
                PerlIO_set_cnt(IoIFP(io),-1);
        }
        if (PL_op->op_flags & OPf_SPECIAL) { /* not necessarily a real EOF yet? */
-           if (!nextargv(PL_argvgv))   /* get another fp handy */
+           if (gv != PL_argvgv || !nextargv(gv))       /* get another fp handy */
                return TRUE;
        }
        else
@@ -933,7 +1009,7 @@ Perl_do_eof(pTHX_ GV *gv)
 Off_t
 Perl_do_tell(pTHX_ GV *gv)
 {
-    register IO *io;
+    register IO *io = 0;
     register PerlIO *fp;
 
     if (gv && (io = GvIO(gv)) && (fp = IoIFP(io))) {
@@ -943,11 +1019,8 @@ Perl_do_tell(pTHX_ GV *gv)
 #endif
        return PerlIO_tell(fp);
     }
-    {
-       dTHR;
-       if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
-           report_evil_fh(gv, io, PL_op->op_type);
-    }
+    if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
+       report_evil_fh(gv, io, PL_op->op_type);
     SETERRNO(EBADF,RMS$_IFI);
     return (Off_t)-1;
 }
@@ -955,7 +1028,7 @@ Perl_do_tell(pTHX_ GV *gv)
 bool
 Perl_do_seek(pTHX_ GV *gv, Off_t pos, int whence)
 {
-    register IO *io;
+    register IO *io = 0;
     register PerlIO *fp;
 
     if (gv && (io = GvIO(gv)) && (fp = IoIFP(io))) {
@@ -965,11 +1038,8 @@ Perl_do_seek(pTHX_ GV *gv, Off_t pos, int whence)
 #endif
        return PerlIO_seek(fp, pos, whence) >= 0;
     }
-    {
-       dTHR;
-       if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
-           report_evil_fh(gv, io, PL_op->op_type);
-    }
+    if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
+       report_evil_fh(gv, io, PL_op->op_type);
     SETERRNO(EBADF,RMS$_IFI);
     return FALSE;
 }
@@ -977,16 +1047,13 @@ Perl_do_seek(pTHX_ GV *gv, Off_t pos, int whence)
 Off_t
 Perl_do_sysseek(pTHX_ GV *gv, Off_t pos, int whence)
 {
-    register IO *io;
+    register IO *io = 0;
     register PerlIO *fp;
 
     if (gv && (io = GvIO(gv)) && (fp = IoIFP(io)))
        return PerlLIO_lseek(PerlIO_fileno(fp), pos, whence);
-    {
-       dTHR;
-       if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
-           report_evil_fh(gv, io, PL_op->op_type);
-    }
+    if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
+       report_evil_fh(gv, io, PL_op->op_type);
     SETERRNO(EBADF,RMS$_IFI);
     return (Off_t)-1;
 }
@@ -1035,7 +1102,11 @@ fail_discipline:
                end = strchr(s+1, ':');
                if (!end)
                    end = s+len;
+#ifndef PERLIO_LAYERS
                Perl_croak(aTHX_ "Unknown discipline '%.*s'", end-s, s);
+#else
+               s = end;
+#endif
            }
        }
     }
@@ -1045,46 +1116,15 @@ fail_discipline:
 int
 Perl_do_binmode(pTHX_ PerlIO *fp, int iotype, int mode)
 {
-#ifdef DOSISH
-#  if defined(atarist) || defined(__MINT__)
-    if (!PerlIO_flush(fp)) {
-       if (mode & O_BINARY)
-           ((FILE*)fp)->_flag |= _IOBIN;
-       else
-           ((FILE*)fp)->_flag &= ~ _IOBIN;
-       return 1;
-    }
-    return 0;
-#  else
-    if (PerlLIO_setmode(PerlIO_fileno(fp), mode) != -1) {
-#    if defined(WIN32) && defined(__BORLANDC__)
-       /* The translation mode of the stream is maintained independent
-        * of the translation mode of the fd in the Borland RTL (heavy
-        * digging through their runtime sources reveal).  User has to
-        * set the mode explicitly for the stream (though they don't
-        * document this anywhere). GSAR 97-5-24
-        */
-       PerlIO_seek(fp,0L,0);
-       if (mode & O_BINARY)
-           ((FILE*)fp)->flags |= _F_BIN;
-       else
-           ((FILE*)fp)->flags &= ~ _F_BIN;
-#    endif
-       return 1;
-    }
-    else
-       return 0;
-#  endif
-#else
-#  if defined(USEMYBINMODE)
-    if (my_binmode(fp, iotype, mode) != FALSE)
-       return 1;
-    else
-       return 0;
-#  else
-    return 1;
-#  endif
+ /* The old body of this is now in non-LAYER part of perlio.c
+  * This is a stub for any XS code which might have been calling it.
+  */
+ char *name = ":raw";
+#ifdef PERLIO_USING_CRLF
+ if (!(mode & O_BINARY))
+     name = ":crlf";
 #endif
+ return PerlIO_binmode(aTHX_ fp, iotype, mode, name);
 }
 
 #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
@@ -1162,11 +1202,8 @@ Perl_do_print(pTHX_ register SV *sv, PerlIO *fp)
     }
     switch (SvTYPE(sv)) {
     case SVt_NULL:
-       {
-           dTHR;
-           if (ckWARN(WARN_UNINITIALIZED))
-               report_uninit();
-       }
+       if (ckWARN(WARN_UNINITIALIZED))
+           report_uninit();
        return TRUE;
     case SVt_IV:
        if (SvIOK(sv)) {
@@ -1180,6 +1217,17 @@ Perl_do_print(pTHX_ register SV *sv, PerlIO *fp)
        }
        /* FALL THROUGH */
     default:
+       if (PerlIO_isutf8(fp)) {
+           if (!SvUTF8(sv))
+               sv_utf8_upgrade(sv = sv_mortalcopy(sv));
+       }
+       else if (DO_UTF8(sv)) {
+           if (!sv_utf8_downgrade((sv = sv_mortalcopy(sv)), TRUE)
+               && ckWARN_d(WARN_UTF8))
+           {
+               Perl_warner(aTHX_ WARN_UTF8, "Wide character in print");
+           }
+       }
        tmps = SvPV(sv, len);
        break;
     }
@@ -1189,7 +1237,7 @@ Perl_do_print(pTHX_ register SV *sv, PerlIO *fp)
      * but only until the system hard limit/the filesystem limit,
      * at which we would get EPERM.  Note that when using buffered
      * io the write failure can be delayed until the flush/close. --jhi */
-    if (len && (PerlIO_write(fp,tmps,len) == 0 || PerlIO_error(fp)))
+    if (len && (PerlIO_write(fp,tmps,len) == 0))
        return FALSE;
     return !PerlIO_error(fp);
 }
@@ -1197,7 +1245,7 @@ Perl_do_print(pTHX_ register SV *sv, PerlIO *fp)
 I32
 Perl_my_stat(pTHX)
 {
-    djSP;
+    dSP;
     IO *io;
     GV* gv;
 
@@ -1250,7 +1298,7 @@ Perl_my_stat(pTHX)
 I32
 Perl_my_lstat(pTHX)
 {
-    djSP;
+    dSP;
     SV *sv;
     STRLEN n_a;
     if (PL_op->op_flags & OPf_REF) {
@@ -1260,13 +1308,22 @@ Perl_my_lstat(pTHX)
                Perl_croak(aTHX_ "The stat preceding -l _ wasn't an lstat");
            return PL_laststatval;
        }
-       Perl_croak(aTHX_ "You can't use -l on a filehandle");
+       if (ckWARN(WARN_IO)) {
+           Perl_warner(aTHX_ WARN_IO, "Use of -l on filehandle %s",
+                   GvENAME(cGVOP_gv));
+           return (PL_laststatval = -1);
+       }
     }
 
     PL_laststype = OP_LSTAT;
     PL_statgv = Nullgv;
     sv = POPs;
     PUTBACK;
+    if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVGV && ckWARN(WARN_IO)) {
+       Perl_warner(aTHX_ WARN_IO, "Use of -l on filehandle %s",
+               GvENAME((GV*) SvRV(sv)));
+       return (PL_laststatval = -1);
+    }
     sv_setpv(PL_statname,SvPV(sv, n_a));
     PL_laststatval = PerlLIO_lstat(SvPV(sv, n_a),&PL_statcache);
     if (PL_laststatval < 0 && ckWARN(WARN_NEWLINE) && strchr(SvPV(sv, n_a), '\n'))
@@ -1288,11 +1345,10 @@ Perl_do_aexec5(pTHX_ SV *really, register SV **mark, register SV **sp,
     Perl_croak(aTHX_ "exec? I'm not *that* kind of operating system");
 #else
     register char **a;
-    char *tmps;
+    char *tmps = Nullch;
     STRLEN n_a;
 
     if (sp > mark) {
-       dTHR;
        New(401,PL_Argv, sp - mark + 1, char*);
        a = PL_Argv;
        while (++mark <= sp) {
@@ -1302,15 +1358,18 @@ Perl_do_aexec5(pTHX_ SV *really, register SV **mark, register SV **sp,
                *a++ = "";
        }
        *a = Nullch;
-       if (*PL_Argv[0] != '/') /* will execvp use PATH? */
+       if (really)
+           tmps = SvPV(really, n_a);
+       if ((!really && *PL_Argv[0] != '/') ||
+           (really && *tmps != '/'))           /* will execvp use PATH? */
            TAINT_ENV();                /* testing IFS here is overkill, probably */
-       if (really && *(tmps = SvPV(really, n_a)))
-           PerlProc_execvp(tmps,PL_Argv);
+       if (really && *tmps)
+           PerlProc_execvp(tmps,EXEC_ARGV_CAST(PL_Argv));
        else
-           PerlProc_execvp(PL_Argv[0],PL_Argv);
+           PerlProc_execvp(PL_Argv[0],EXEC_ARGV_CAST(PL_Argv));
        if (ckWARN(WARN_EXEC))
-           Perl_warner(aTHX_ WARN_EXEC, "Can't exec \"%s\": %s", 
-               PL_Argv[0], Strerror(errno));
+           Perl_warner(aTHX_ WARN_EXEC, "Can't exec \"%s\": %s",
+               (really ? tmps : PL_Argv[0]), Strerror(errno));
        if (do_report) {
            int e = errno;
 
@@ -1349,7 +1408,6 @@ Perl_do_exec3(pTHX_ char *cmd, int fd, int do_report)
 {
     register char **a;
     register char *s;
-    char flags[10];
 
     while (*cmd && isSPACE(*cmd))
        cmd++;
@@ -1357,28 +1415,32 @@ Perl_do_exec3(pTHX_ char *cmd, int fd, int do_report)
     /* save an extra exec if possible */
 
 #ifdef CSH
-    if (strnEQ(cmd,PL_cshname,PL_cshlen) && strnEQ(cmd+PL_cshlen," -c",3)) {
-       strcpy(flags,"-c");
-       s = cmd+PL_cshlen+3;
-       if (*s == 'f') {
-           s++;
-           strcat(flags,"f");
-       }
-       if (*s == ' ')
-           s++;
-       if (*s++ == '\'') {
-           char *ncmd = s;
-
-           while (*s)
-               s++;
-           if (s[-1] == '\n')
-               *--s = '\0';
-           if (s[-1] == '\'') {
-               *--s = '\0';
-               PerlProc_execl(PL_cshname,"csh", flags,ncmd,(char*)0);
-               *s = '\'';
-               return FALSE;
-           }
+    {
+        char flags[10];
+       if (strnEQ(cmd,PL_cshname,PL_cshlen) &&
+           strnEQ(cmd+PL_cshlen," -c",3)) {
+         strcpy(flags,"-c");
+         s = cmd+PL_cshlen+3;
+         if (*s == 'f') {
+             s++;
+             strcat(flags,"f");
+         }
+         if (*s == ' ')
+             s++;
+         if (*s++ == '\'') {
+             char *ncmd = s;
+
+             while (*s)
+                 s++;
+             if (s[-1] == '\n')
+                 *--s = '\0';
+             if (s[-1] == '\'') {
+                 *--s = '\0';
+                 PerlProc_execl(PL_cshname,"csh", flags, ncmd, (char*)0);
+                 *s = '\'';
+                 return FALSE;
+             }
+         }
        }
     }
 #endif /* CSH */
@@ -1396,7 +1458,8 @@ Perl_do_exec3(pTHX_ char *cmd, int fd, int do_report)
        goto doshell;
 
     for (s = cmd; *s; s++) {
-       if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
+       if (*s != ' ' && !isALPHA(*s) &&
+           strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
            if (*s == '\n' && !s[1]) {
                *s = '\0';
                break;
@@ -1440,11 +1503,10 @@ Perl_do_exec3(pTHX_ char *cmd, int fd, int do_report)
            goto doshell;
        }
        {
-           dTHR;
            int e = errno;
 
            if (ckWARN(WARN_EXEC))
-               Perl_warner(aTHX_ WARN_EXEC, "Can't exec \"%s\": %s", 
+               Perl_warner(aTHX_ WARN_EXEC, "Can't exec \"%s\": %s",
                    PL_Argv[0], Strerror(errno));
            if (do_report) {
                PerlLIO_write(fd, (void*)&e, sizeof(int));
@@ -1461,7 +1523,6 @@ Perl_do_exec3(pTHX_ char *cmd, int fd, int do_report)
 I32
 Perl_apply(pTHX_ I32 type, register SV **mark, register SV **sp)
 {
-    dTHR;
     register I32 val;
     register I32 val2;
     register I32 tot = 0;
@@ -1519,7 +1580,7 @@ Perl_apply(pTHX_ I32 type, register SV **mark, register SV **sp)
        }
        break;
 #endif
-/* 
+/*
 XXX Should we make lchown() directly available from perl?
 For now, we'll let Configure test for HAS_LCHOWN, but do
 nothing in the core.
@@ -1631,20 +1692,31 @@ nothing in the core.
            } utbuf;
 #endif
 
+           SV* accessed = *++mark;
+           SV* modified = *++mark;
+           void * utbufp = &utbuf;
+
+           /* be like C, and if both times are undefined, let the C
+              library figure out what to do.  This usually means
+              "current time" */
+
+           if ( accessed == &PL_sv_undef && modified == &PL_sv_undef )
+             utbufp = NULL;
+
            Zero(&utbuf, sizeof utbuf, char);
 #ifdef BIG_TIME
-           utbuf.actime = (Time_t)SvNVx(*++mark);      /* time accessed */
-           utbuf.modtime = (Time_t)SvNVx(*++mark);     /* time modified */
+           utbuf.actime = (Time_t)SvNVx(accessed);     /* time accessed */
+           utbuf.modtime = (Time_t)SvNVx(modified);    /* time modified */
 #else
-           utbuf.actime = (Time_t)SvIVx(*++mark);      /* time accessed */
-           utbuf.modtime = (Time_t)SvIVx(*++mark);     /* time modified */
+           utbuf.actime = (Time_t)SvIVx(accessed);     /* time accessed */
+           utbuf.modtime = (Time_t)SvIVx(modified);    /* time modified */
 #endif
            APPLY_TAINT_PROPER();
            tot = sp - mark;
            while (++mark <= sp) {
                char *name = SvPVx(*mark, n_a);
                APPLY_TAINT_PROPER();
-               if (PerlLIO_utime(name, &utbuf))
+               if (PerlLIO_utime(name, utbufp))
                    tot--;
            }
        }
@@ -1746,7 +1818,6 @@ Perl_ingroup(pTHX_ Gid_t testgid, Uid_t effective)
 I32
 Perl_do_ipcget(pTHX_ I32 optype, SV **mark, SV **sp)
 {
-    dTHR;
     key_t key;
     I32 n, flags;
 
@@ -1779,7 +1850,6 @@ Perl_do_ipcget(pTHX_ I32 optype, SV **mark, SV **sp)
 I32
 Perl_do_ipcctl(pTHX_ I32 optype, SV **mark, SV **sp)
 {
-    dTHR;
     SV *astr;
     char *a;
     I32 id, n, cmd, infosize, getinfo;
@@ -1904,7 +1974,6 @@ I32
 Perl_do_msgsnd(pTHX_ SV **mark, SV **sp)
 {
 #ifdef HAS_MSG
-    dTHR;
     SV *mstr;
     char *mbuf;
     I32 id, msize, flags;
@@ -1927,7 +1996,6 @@ I32
 Perl_do_msgrcv(pTHX_ SV **mark, SV **sp)
 {
 #ifdef HAS_MSG
-    dTHR;
     SV *mstr;
     char *mbuf;
     long mtype;
@@ -1944,7 +2012,7 @@ Perl_do_msgrcv(pTHX_ SV **mark, SV **sp)
     flags = SvIVx(*++mark);
     SvPV_force(mstr, len);
     mbuf = SvGROW(mstr, sizeof(long)+msize+1);
-    
+
     SETERRNO(0,0);
     ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
     if (ret >= 0) {
@@ -1965,7 +2033,6 @@ I32
 Perl_do_semop(pTHX_ SV **mark, SV **sp)
 {
 #ifdef HAS_SEM
-    dTHR;
     SV *opstr;
     char *opbuf;
     I32 id;
@@ -1974,13 +2041,42 @@ Perl_do_semop(pTHX_ SV **mark, SV **sp)
     id = SvIVx(*++mark);
     opstr = *++mark;
     opbuf = SvPV(opstr, opsize);
-    if (opsize < sizeof(struct sembuf)
-       || (opsize % sizeof(struct sembuf)) != 0) {
+    if (opsize < 3 * SHORTSIZE
+       || (opsize % (3 * SHORTSIZE))) {
        SETERRNO(EINVAL,LIB$_INVARG);
        return -1;
     }
     SETERRNO(0,0);
-    return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
+    /* We can't assume that sizeof(struct sembuf) == 3 * sizeof(short). */
+    {
+        int nsops  = opsize / (3 * sizeof (short));
+        int i      = nsops;
+        short *ops = (short *) opbuf;
+        short *o   = ops;
+        struct sembuf *temps, *t;
+        I32 result;
+
+        New (0, temps, nsops, struct sembuf);
+        t = temps;
+        while (i--) {
+            t->sem_num = *o++;
+            t->sem_op  = *o++;
+            t->sem_flg = *o++;
+            t++;
+        }
+        result = semop(id, temps, nsops);
+        t = temps;
+        o = ops;
+        i = nsops;
+        while (i--) {
+            *o++ = t->sem_num;
+            *o++ = t->sem_op;
+            *o++ = t->sem_flg;
+            t++;
+        }
+        Safefree(temps);
+        return result;
+    }
 #else
     Perl_croak(aTHX_ "semop not implemented");
 #endif
@@ -1990,7 +2086,6 @@ I32
 Perl_do_shmio(pTHX_ I32 optype, SV **mark, SV **sp)
 {
 #ifdef HAS_SHM
-    dTHR;
     SV *mstr;
     char *mbuf, *shm;
     I32 id, mpos, msize;
@@ -2045,3 +2140,151 @@ Perl_do_shmio(pTHX_ I32 optype, SV **mark, SV **sp)
 
 #endif /* SYSV IPC */
 
+/*
+=head1 IO Functions
+
+=for apidoc start_glob
+
+Function called by C<do_readline> to spawn a glob (or do the glob inside
+perl on VMS). This code used to be inline, but now perl uses C<File::Glob>
+this glob starter is only used by miniperl during the build process.
+Moving it away shrinks pp_hot.c; shrinking pp_hot.c helps speed perl up.
+
+=cut
+*/
+
+PerlIO *
+Perl_start_glob (pTHX_ SV *tmpglob, IO *io)
+{
+    SV *tmpcmd = NEWSV(55, 0);
+    PerlIO *fp;
+    ENTER;
+    SAVEFREESV(tmpcmd);
+#ifdef VMS /* expand the wildcards right here, rather than opening a pipe, */
+           /* since spawning off a process is a real performance hit */
+    {
+#include <descrip.h>
+#include <lib$routines.h>
+#include <nam.h>
+#include <rmsdef.h>
+       char rslt[NAM$C_MAXRSS+1+sizeof(unsigned short int)] = {'\0','\0'};
+       char vmsspec[NAM$C_MAXRSS+1];
+       char *rstr = rslt + sizeof(unsigned short int), *begin, *end, *cp;
+       $DESCRIPTOR(dfltdsc,"SYS$DISK:[]*.*;");
+       PerlIO *tmpfp;
+       STRLEN i;
+       struct dsc$descriptor_s wilddsc
+           = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
+       struct dsc$descriptor_vs rsdsc
+           = {sizeof rslt, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, rslt};
+       unsigned long int cxt = 0, sts = 0, ok = 1, hasdir = 0, hasver = 0, isunix = 0;
+
+       /* We could find out if there's an explicit dev/dir or version
+          by peeking into lib$find_file's internal context at
+          ((struct NAM *)((struct FAB *)cxt)->fab$l_nam)->nam$l_fnb
+          but that's unsupported, so I don't want to do it now and
+          have it bite someone in the future. */
+       cp = SvPV(tmpglob,i);
+       for (; i; i--) {
+           if (cp[i] == ';') hasver = 1;
+           if (cp[i] == '.') {
+               if (sts) hasver = 1;
+               else sts = 1;
+           }
+           if (cp[i] == '/') {
+               hasdir = isunix = 1;
+               break;
+           }
+           if (cp[i] == ']' || cp[i] == '>' || cp[i] == ':') {
+               hasdir = 1;
+               break;
+           }
+       }
+       if ((tmpfp = PerlIO_tmpfile()) != NULL) {
+           Stat_t st;
+           if (!PerlLIO_stat(SvPVX(tmpglob),&st) && S_ISDIR(st.st_mode))
+               ok = ((wilddsc.dsc$a_pointer = tovmspath(SvPVX(tmpglob),vmsspec)) != NULL);
+           else ok = ((wilddsc.dsc$a_pointer = tovmsspec(SvPVX(tmpglob),vmsspec)) != NULL);
+           if (ok) wilddsc.dsc$w_length = (unsigned short int) strlen(wilddsc.dsc$a_pointer);
+           for (cp=wilddsc.dsc$a_pointer; ok && cp && *cp; cp++)
+               if (*cp == '?') *cp = '%';  /* VMS style single-char wildcard */
+           while (ok && ((sts = lib$find_file(&wilddsc,&rsdsc,&cxt,
+                                              &dfltdsc,NULL,NULL,NULL))&1)) {
+               end = rstr + (unsigned long int) *rslt;
+               if (!hasver) while (*end != ';') end--;
+               *(end++) = '\n';  *end = '\0';
+               for (cp = rstr; *cp; cp++) *cp = _tolower(*cp);
+               if (hasdir) {
+                   if (isunix) trim_unixpath(rstr,SvPVX(tmpglob),1);
+                   begin = rstr;
+               }
+               else {
+                   begin = end;
+                   while (*(--begin) != ']' && *begin != '>') ;
+                   ++begin;
+               }
+               ok = (PerlIO_puts(tmpfp,begin) != EOF);
+           }
+           if (cxt) (void)lib$find_file_end(&cxt);
+           if (ok && sts != RMS$_NMF &&
+               sts != RMS$_DNF && sts != RMS$_FNF) ok = 0;
+           if (!ok) {
+               if (!(sts & 1)) {
+                   SETERRNO((sts == RMS$_SYN ? EINVAL : EVMSERR),sts);
+               }
+               PerlIO_close(tmpfp);
+               fp = NULL;
+           }
+           else {
+               PerlIO_rewind(tmpfp);
+               IoTYPE(io) = IoTYPE_RDONLY;
+               IoIFP(io) = fp = tmpfp;
+               IoFLAGS(io) &= ~IOf_UNTAINT;  /* maybe redundant */
+           }
+       }
+    }
+#else /* !VMS */
+#ifdef MACOS_TRADITIONAL
+    sv_setpv(tmpcmd, "glob ");
+    sv_catsv(tmpcmd, tmpglob);
+    sv_catpv(tmpcmd, " |");
+#else
+#ifdef DOSISH
+#ifdef OS2
+    sv_setpv(tmpcmd, "for a in ");
+    sv_catsv(tmpcmd, tmpglob);
+    sv_catpv(tmpcmd, "; do echo \"$a\\0\\c\"; done |");
+#else
+#ifdef DJGPP
+    sv_setpv(tmpcmd, "/dev/dosglob/"); /* File System Extension */
+    sv_catsv(tmpcmd, tmpglob);
+#else
+    sv_setpv(tmpcmd, "perlglob ");
+    sv_catsv(tmpcmd, tmpglob);
+    sv_catpv(tmpcmd, " |");
+#endif /* !DJGPP */
+#endif /* !OS2 */
+#else /* !DOSISH */
+#if defined(CSH)
+    sv_setpvn(tmpcmd, PL_cshname, PL_cshlen);
+    sv_catpv(tmpcmd, " -cf 'set nonomatch; glob ");
+    sv_catsv(tmpcmd, tmpglob);
+    sv_catpv(tmpcmd, "' 2>/dev/null |");
+#else
+    sv_setpv(tmpcmd, "echo ");
+    sv_catsv(tmpcmd, tmpglob);
+#if 'z' - 'a' == 25
+    sv_catpv(tmpcmd, "|tr -s ' \t\f\r' '\\012\\012\\012\\012'|");
+#else
+    sv_catpv(tmpcmd, "|tr -s ' \t\f\r' '\\n\\n\\n\\n'|");
+#endif
+#endif /* !CSH */
+#endif /* !DOSISH */
+#endif /* MACOS_TRADITIONAL */
+    (void)do_open(PL_last_in_gv, SvPVX(tmpcmd), SvCUR(tmpcmd),
+                 FALSE, O_RDONLY, 0, Nullfp);
+    fp = IoIFP(io);
+#endif /* !VMS */
+    LEAVE;
+    return fp;
+}