From: Gurusamy Sarathy Date: Mon, 10 Jan 2000 18:30:24 +0000 (+0000) Subject: add workaround for textmode read() bug in MSVCRT; make chdir() do X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=f7aeb604c5566ea382e11775c0d364a41af8fbb9;p=p5sagit%2Fp5-mst-13.2.git add workaround for textmode read() bug in MSVCRT; make chdir() do a real SetCurrentDirectory() in toplevel host p4raw-id: //depot/perl@4789 --- diff --git a/README.win32 b/README.win32 index 37df1d4..1623acf 100644 --- a/README.win32 +++ b/README.win32 @@ -250,10 +250,6 @@ default path. You will need to copy the DLLs reported by the messages from where Borland chose to install it, into the Windows system directory (usually somewhere like C:\WINNT\SYSTEM32), and rerun the test. -The Visual C runtime apparently has a bug that causes posix.t to fail -test#2. This usually happens only if you extracted the files in text -mode. Enable the USE_PERLCRT option in the Makefile to fix this bug. - Please report any other failures as described under L. =head2 Installation diff --git a/win32/Makefile b/win32/Makefile index 4d7f333..c100d45 100644 --- a/win32/Makefile +++ b/win32/Makefile @@ -99,6 +99,8 @@ INST_ARCH = \$(ARCHNAME) # Get it from CPAN at http://www.perl.com/CPAN/authors/id/D/DO/DOUGL/ # and follow the directions in the package to install. # +# Not recommended if you have VC 6.x and you're not running Windows 9x. +# #USE_PERLCRT = define #BUILD_FOR_WIN95 = define @@ -236,6 +238,10 @@ USE_ITHREADS = undef USE_IMP_SYS = undef !ENDIF +!IF "$(USE_PERLCRT)" == "" +USE_PERLCRT = undef +!ENDIF + !IF "$(USE_MULTI)$(USE_5005THREADS)$(USE_OBJECT)" != "undefundefundef" BUILDOPT = $(BUILDOPT) -DPERL_IMPLICIT_CONTEXT !ENDIF @@ -318,7 +324,7 @@ LOCDEFS = -DPERLDLL -DPERL_CORE SUBSYS = console CXX_FLAG = -TP -GX -!IF "$(USE_PERLCRT)" == "" +!IF "$(USE_PERLCRT)" != "define" ! IF "$(CFG)" == "Debug" PERLCRTLIBC = msvcrtd.lib ! ELSE @@ -364,10 +370,14 @@ OPTIMIZE = $(OPTIMIZE) $(CXX_FLAG) BUILDOPT = $(BUILDOPT) -DPERL_OBJECT !ENDIF +!IF "$(USE_PERLCRT)" != "define" +BUILDOPT = $(BUILDOPT) -DPERL_MSVCRT_READFIX +!ENDIF + LIBBASEFILES = $(DELAYLOAD) $(CRYPT_LIB) \ - oldnames.lib kernel32.lib user32.lib gdi32.lib \ - winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib \ - oleaut32.lib netapi32.lib uuid.lib wsock32.lib mpr.lib winmm.lib \ + oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib \ + comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib \ + netapi32.lib uuid.lib wsock32.lib mpr.lib winmm.lib \ version.lib odbc32.lib odbccp32.lib # we add LIBC here, since we may be using PerlCRT.dll diff --git a/win32/makefile.mk b/win32/makefile.mk index 84df807..e6ed176 100644 --- a/win32/makefile.mk +++ b/win32/makefile.mk @@ -118,6 +118,8 @@ CCTYPE *= BORLAND # Get it from CPAN at http://www.perl.com/CPAN/authors/id/D/DO/DOUGL/ # and follow the directions in the package to install. # +# Not recommended if you have VC 6.x and you're not running Windows 9x. +# #USE_PERLCRT *= define # @@ -245,6 +247,7 @@ USE_MULTI *= undef USE_OBJECT *= undef USE_ITHREADS *= undef USE_IMP_SYS *= undef +USE_PERLCRT *= undef .IF "$(USE_MULTI)$(USE_5005THREADS)$(USE_OBJECT)" != "undefundefundef" BUILDOPT += -DPERL_IMPLICIT_CONTEXT @@ -408,7 +411,7 @@ LOCDEFS = -DPERLDLL -DPERL_CORE SUBSYS = console CXX_FLAG = -TP -GX -.IF "$(USE_PERLCRT)" == "" +.IF "$(USE_PERLCRT)" != "define" .IF "$(CFG)" == "Debug" PERLCRTLIBC = msvcrtd.lib .ELSE @@ -450,10 +453,10 @@ LINK_DBG = -release .ENDIF LIBBASEFILES = $(DELAYLOAD) $(CRYPT_LIB) \ - oldnames.lib kernel32.lib user32.lib gdi32.lib \ - winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib \ - oleaut32.lib netapi32.lib uuid.lib wsock32.lib mpr.lib \ - winmm.lib version.lib odbc32.lib odbccp32.lib + oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib \ + comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib \ + netapi32.lib uuid.lib wsock32.lib mpr.lib winmm.lib \ + version.lib odbc32.lib odbccp32.lib # we add LIBC here, since we may be using PerlCRT.dll LIBFILES = $(LIBBASEFILES) $(LIBC) @@ -467,6 +470,10 @@ OBJOUT_FLAG = -Fo EXEOUT_FLAG = -Fe LIBOUT_FLAG = /out: +.IF "$(USE_PERLCRT)" != "define" +BUILDOPT += -DPERL_MSVCRT_READFIX +.ENDIF + .ENDIF .IF "$(USE_OBJECT)" == "define" @@ -576,7 +583,7 @@ PERLIMPLIB = ..\libperl$(a) CFGSH_TMPL = config.vc CFGH_TMPL = config_H.vc -.IF "$(USE_PERLCRT)" == "" +.IF "$(USE_PERLCRT)" != "define" PERL95EXE = ..\perl95.exe .ENDIF @@ -1097,7 +1104,7 @@ $(PERLEXE): $(PERLDLL) $(CONFIGPM) $(PERLEXE_OBJ) $(PERLEXE_RES) .IF "$(CCTYPE)" != "BORLAND" .IF "$(CCTYPE)" != "GCC" -.IF "$(USE_PERLCRT)" == "" +.IF "$(USE_PERLCRT)" != "define" perl95.c : runperl.c copy runperl.c perl95.c diff --git a/win32/perlhost.h b/win32/perlhost.h index 15f03c6..031c2b5 100644 --- a/win32/perlhost.h +++ b/win32/perlhost.h @@ -1890,7 +1890,7 @@ CPerlHost::CPerlHost(struct IPerlMem** ppMem, struct IPerlMem** ppMemShared, struct IPerlDir** ppDir, struct IPerlSock** ppSock, struct IPerlProc** ppProc) { - m_pvDir = new VDir(); + m_pvDir = new VDir(0); m_pVMem = new VMem(); m_pVMemShared = new VMem(); m_pVMemParse = new VMem(); @@ -1929,7 +1929,7 @@ CPerlHost::CPerlHost(CPerlHost& host) m_pVMemParse = host.GetMemParse(); /* duplicate directory info */ - m_pvDir = new VDir(); + m_pvDir = new VDir(0); m_pvDir->Init(host.GetDir(), m_pVMem); CopyMemory(&m_hostperlMem, &perlMem, sizeof(perlMem)); diff --git a/win32/vdir.h b/win32/vdir.h index a8a34e4..50822a7 100644 --- a/win32/vdir.h +++ b/win32/vdir.h @@ -15,7 +15,7 @@ const int driveCount = 30; class VDir { public: - VDir(); + VDir(int bManageDir = 1); ~VDir() {}; void Init(VDir* pDir, VMem *pMem); @@ -91,7 +91,7 @@ protected: }; VMem *pMem; - int nDefault; + int nDefault, bManageDirectory; char *dirTableA[driveCount]; char szLocalBufferA[MAX_PATH+1]; WCHAR *dirTableW[driveCount]; @@ -99,9 +99,10 @@ protected: }; -VDir::VDir() +VDir::VDir(int bManageDir /* = 1 */) { nDefault = 0; + bManageDirectory = bManageDir; memset(dirTableA, 0, sizeof(dirTableA)); memset(dirTableW, 0, sizeof(dirTableW)); } @@ -110,6 +111,7 @@ void VDir::Init(VDir* pDir, VMem *p) { int index; DWORD driveBits; + int nSave; char szBuffer[MAX_PATH*driveCount]; pMem = p; @@ -120,6 +122,8 @@ void VDir::Init(VDir* pDir, VMem *p) nDefault = pDir->GetDefault(); } else { + nSave = bManageDirectory; + bManageDirectory = 0; driveBits = GetLogicalDrives(); if (GetLogicalDriveStrings(sizeof(szBuffer), szBuffer)) { char* pEnv = GetEnvironmentStrings(); @@ -133,6 +137,7 @@ void VDir::Init(VDir* pDir, VMem *p) FreeEnvironmentStrings(pEnv); } SetDefaultA("."); + bManageDirectory = nSave; } } @@ -163,6 +168,10 @@ int VDir::SetDirA(char const *pPath, int index) } } } + + if(bManageDirectory) + ::SetCurrentDirectoryA(pPath); + return length; } @@ -217,6 +226,10 @@ int VDir::SetDirW(WCHAR const *pPath, int index) } } } + + if(bManageDirectory) + ::SetCurrentDirectoryW(pPath); + return length; } diff --git a/win32/win32.c b/win32/win32.c index 43e9b5e..78955fc 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -2595,10 +2595,240 @@ win32_dup2(int fd1,int fd2) return dup2(fd1,fd2); } +#ifdef PERL_MSVCRT_READFIX + +#define LF 10 /* line feed */ +#define CR 13 /* carriage return */ +#define CTRLZ 26 /* ctrl-z means eof for text */ +#define FOPEN 0x01 /* file handle open */ +#define FEOFLAG 0x02 /* end of file has been encountered */ +#define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */ +#define FPIPE 0x08 /* file handle refers to a pipe */ +#define FAPPEND 0x20 /* file handle opened O_APPEND */ +#define FDEV 0x40 /* file handle refers to device */ +#define FTEXT 0x80 /* file handle is in text mode */ +#define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */ + +/* + * Control structure for lowio file handles + */ +typedef struct { + long osfhnd; /* underlying OS file HANDLE */ + char osfile; /* attributes of file (e.g., open in text mode?) */ + char pipech; /* one char buffer for handles opened on pipes */ + int lockinitflag; + CRITICAL_SECTION lock; +} ioinfo; + + +/* + * Array of arrays of control structures for lowio files. + */ +EXTERN_C _CRTIMP ioinfo* __pioinfo[]; + +/* + * Definition of IOINFO_L2E, the log base 2 of the number of elements in each + * array of ioinfo structs. + */ +#define IOINFO_L2E 5 + +/* + * Definition of IOINFO_ARRAY_ELTS, the number of elements in ioinfo array + */ +#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) + +/* + * Access macros for getting at an ioinfo struct and its fields from a + * file handle + */ +#define _pioinfo(i) (__pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - 1))) +#define _osfhnd(i) (_pioinfo(i)->osfhnd) +#define _osfile(i) (_pioinfo(i)->osfile) +#define _pipech(i) (_pioinfo(i)->pipech) + +int __cdecl _fixed_read(int fh, void *buf, unsigned cnt) +{ + int bytes_read; /* number of bytes read */ + char *buffer; /* buffer to read to */ + int os_read; /* bytes read on OS call */ + char *p, *q; /* pointers into buffer */ + char peekchr; /* peek-ahead character */ + ULONG filepos; /* file position after seek */ + ULONG dosretval; /* o.s. return value */ + + /* validate handle */ + if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) || + !(_osfile(fh) & FOPEN)) + { + /* out of range -- return error */ + errno = EBADF; + _doserrno = 0; /* not o.s. error */ + return -1; + } + + EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */ + + bytes_read = 0; /* nothing read yet */ + buffer = (char*)buf; + + if (cnt == 0 || (_osfile(fh) & FEOFLAG)) { + /* nothing to read or at EOF, so return 0 read */ + goto functionexit; + } + + if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) { + /* a pipe/device and pipe lookahead non-empty: read the lookahead + * char */ + *buffer++ = _pipech(fh); + ++bytes_read; + --cnt; + _pipech(fh) = LF; /* mark as empty */ + } + + /* read the data */ + + if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL)) + { + /* ReadFile has reported an error. recognize two special cases. + * + * 1. map ERROR_ACCESS_DENIED to EBADF + * + * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it + * means the handle is a read-handle on a pipe for which + * all write-handles have been closed and all data has been + * read. */ + + if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) { + /* wrong read/write mode should return EBADF, not EACCES */ + errno = EBADF; + _doserrno = dosretval; + bytes_read = -1; + goto functionexit; + } + else if (dosretval == ERROR_BROKEN_PIPE) { + bytes_read = 0; + goto functionexit; + } + else { + bytes_read = -1; + goto functionexit; + } + } + + bytes_read += os_read; /* update bytes read */ + + if (_osfile(fh) & FTEXT) { + /* now must translate CR-LFs to LFs in the buffer */ + + /* set CRLF flag to indicate LF at beginning of buffer */ + /* if ((os_read != 0) && (*(char *)buf == LF)) */ + /* _osfile(fh) |= FCRLF; */ + /* else */ + /* _osfile(fh) &= ~FCRLF; */ + + _osfile(fh) &= ~FCRLF; + + /* convert chars in the buffer: p is src, q is dest */ + p = q = (char*)buf; + while (p < (char *)buf + bytes_read) { + if (*p == CTRLZ) { + /* if fh is not a device, set ctrl-z flag */ + if (!(_osfile(fh) & FDEV)) + _osfile(fh) |= FEOFLAG; + break; /* stop translating */ + } + else if (*p != CR) + *q++ = *p++; + else { + /* *p is CR, so must check next char for LF */ + if (p < (char *)buf + bytes_read - 1) { + if (*(p+1) == LF) { + p += 2; + *q++ = LF; /* convert CR-LF to LF */ + } + else + *q++ = *p++; /* store char normally */ + } + else { + /* This is the hard part. We found a CR at end of + buffer. We must peek ahead to see if next char + is an LF. */ + ++p; + + dosretval = 0; + if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1, + (LPDWORD)&os_read, NULL)) + dosretval = GetLastError(); + + if (dosretval != 0 || os_read == 0) { + /* couldn't read ahead, store CR */ + *q++ = CR; + } + else { + /* peekchr now has the extra character -- we now + have several possibilities: + 1. disk file and char is not LF; just seek back + and copy CR + 2. disk file and char is LF; store LF, don't seek back + 3. pipe/device and char is LF; store LF. + 4. pipe/device and char isn't LF, store CR and + put char in pipe lookahead buffer. */ + if (_osfile(fh) & (FDEV|FPIPE)) { + /* non-seekable device */ + if (peekchr == LF) + *q++ = LF; + else { + *q++ = CR; + _pipech(fh) = peekchr; + } + } + else { + /* disk file */ + if (peekchr == LF) { + /* nothing read yet; must make some + progress */ + *q++ = LF; + /* turn on this flag for tell routine */ + _osfile(fh) |= FCRLF; + } + else { + HANDLE osHandle; /* o.s. handle value */ + /* seek back */ + if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1) + { + if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1) + dosretval = GetLastError(); + } + if (peekchr != LF) + *q++ = CR; + } + } + } + } + } + } + + /* we now change bytes_read to reflect the true number of chars + in the buffer */ + bytes_read = q - (char *)buf; + } + +functionexit: + LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */ + + return bytes_read; +} + +#endif /* PERL_MSVCRT_READFIX */ + DllExport int win32_read(int fd, void *buf, unsigned int cnt) { +#ifdef PERL_MSVCRT_READFIX + return _fixed_read(fd, buf, cnt); +#else return read(fd, buf, cnt); +#endif } DllExport int