From: Gurusamy Sarathy Date: Fri, 28 May 1999 21:22:23 +0000 (+0000) Subject: add wide versions of win32 system calls (first step in X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=7fac1903b890dcf899cc0c18a1b5f9e0198b58ab;p=p5sagit%2Fp5-mst-13.2.git add wide versions of win32 system calls (first step in globalization); delayload winsock for performance if compiling with VC 6.0 p4raw-id: //depot/perl@3501 --- diff --git a/win32/Makefile b/win32/Makefile index 086da4c..3d8570e 100644 --- a/win32/Makefile +++ b/win32/Makefile @@ -42,9 +42,11 @@ INST_VER = \5.00557 #USE_MULTI = define # -# uncomment next line if you are using Visual C++ 2.x +# uncomment one of the following lines if you are using either +# Visual C++ 2.x or Visual C++ 6.x (aka Visual Studio 98) # #CCTYPE = MSVC20 +#CCTYPE = MSVC60 # # uncomment next line if you want to use the perl object @@ -58,15 +60,6 @@ INST_VER = \5.00557 #CFG = Debug # -# uncomment next option if you want to use the VC++ compiler optimization. -# Warning: This is known to produce incorrect code for compiler versions -# earlier than VC++ 98 (Visual Studio 6.0). VC++ 98 generates code that -# successfully passes the Perl regression test suite. It hasn't yet been -# widely tested with real applications though. -# -#CFG = Optimize - -# # uncomment to enable use of PerlCRT.DLL when using the Visual C compiler. # Highly recommended. It has patches that fix known bugs in MSVCRT.DLL. # This currently requires VC 5.0 with Service Pack 3. @@ -187,6 +180,20 @@ ARCHNAME = MSWin32-$(PROCESSOR_ARCHITECTURE) !ENDIF !ENDIF +# Visual Studio 98 specific +!IF "$(CCTYPE)" == "MSVC60" + +# VC 6.0 can load the socket dll on demand. Makes the test suite +# run in about 10% less time. +DELAYLOAD = -DELAYLOAD:wsock32.dll delayimp.lib + +# VC 6.0 seems capable of compiling perl correctly with optimizations +# enabled. Anything earlier fails tests. +!IF "$(CFG)" == "" +CFG = Optimize +!ENDIF +!ENDIF + ARCHDIR = ..\lib\$(ARCHNAME) COREDIR = ..\lib\CORE AUTODIR = ..\lib\auto @@ -251,7 +258,8 @@ LINK_DBG = -release OPTIMIZE = $(OPTIMIZE) $(CXX_FLAG) !ENDIF -LIBBASEFILES = $(CRYPT_LIB) oldnames.lib kernel32.lib user32.lib gdi32.lib \ +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 diff --git a/win32/dl_win32.xs b/win32/dl_win32.xs index 3473520..8a91973 100644 --- a/win32/dl_win32.xs +++ b/win32/dl_win32.xs @@ -102,9 +102,17 @@ dl_load_file(filename,flags=0) int flags PREINIT: CODE: + WCHAR wfilename[MAX_PATH]; DLDEBUG(1,PerlIO_printf(PerlIO_stderr(),"dl_load_file(%s):\n", filename)); - if (dl_static_linked(filename) == 0) - RETVAL = (void*) LoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH ) ; + if (dl_static_linked(filename) == 0) { + if (USING_WIDE()) { + A2WHELPER(filename, wfilename, sizeof(wfilename), GETINTERPMODE()); + RETVAL = (void*) LoadLibraryExW(wfilename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + } + else { + RETVAL = (void*) LoadLibraryExA(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + } + } else RETVAL = (void*) GetModuleHandle(NULL); DLDEBUG(2,PerlIO_printf(PerlIO_stderr()," libref=%x\n", RETVAL)); diff --git a/win32/makefile.mk b/win32/makefile.mk index d50408a..c6605ec 100644 --- a/win32/makefile.mk +++ b/win32/makefile.mk @@ -46,11 +46,17 @@ INST_VER *= \5.00557 #USE_MULTI *= define # -# uncomment one -# +# uncomment exactly one of the following +# +# Visual C++ 2.x #CCTYPE *= MSVC20 +# Visual C++ > 2.x and < 6.x #CCTYPE *= MSVC +# Visual C++ >= 6.x +#CCTYPE *= MSVC60 +# Borland 5.02 or later CCTYPE *= BORLAND +# mingw32/egcs or mingw32/gcc #CCTYPE *= GCC # @@ -62,25 +68,15 @@ CCTYPE *= BORLAND # # uncomment next line if you want debug version of perl (big,slow) +# If not enabled, we automatically try to use maximum optimization +# with all compilers that are known to have a working optimizer. # #CFG *= Debug # -# uncomment next option if you want to use the VC++ compiler optimization. -# This option is only relevant for the Microsoft compiler; we automatically -# use maximum optimization with the other compilers (unless you specify a -# DEBUGGING build). -# Warning: This is known to produce incorrect code for compiler versions -# earlier than VC++ 98 (Visual Studio 6.0). VC++ 98 generates code that -# successfully passes the Perl regression test suite. It hasn't yet been -# widely tested with real applications though. -# -#CFG *= Optimize - -# # uncomment to enable use of PerlCRT.DLL when using the Visual C compiler. # Highly recommended. It has patches that fix known bugs in MSVCRT.DLL. -# This currently requires VC 5.0 with Service Pack 3. +# This currently requires VC 5.0 with Service Pack 3 or later. # Get it from CPAN at http://www.perl.com/CPAN/authors/id/D/DO/DOUGL/ # and follow the directions in the package to install. # @@ -196,6 +192,18 @@ ARCHNAME = MSWin32-$(PROCESSOR_ARCHITECTURE)-thread ARCHNAME = MSWin32-$(PROCESSOR_ARCHITECTURE) .ENDIF +# Visual Studio 98 specific +.IF "$(CCTYPE)" == "MSVC60" + +# VC 6.0 can load the socket dll on demand. Makes the test suite +# run in about 10% less time. +DELAYLOAD *= -DELAYLOAD:wsock32.dll delayimp.lib + +# VC 6.0 seems capable of compiling perl correctly with optimizations +# enabled. Anything earlier fails tests. +CFG *= Optimize +.ENDIF + ARCHDIR = ..\lib\$(ARCHNAME) COREDIR = ..\lib\CORE AUTODIR = ..\lib\auto @@ -334,7 +342,8 @@ OPTIMIZE = -Od $(RUNTIME) -DNDEBUG LINK_DBG = -release .ENDIF -LIBBASEFILES = $(CRYPT_LIB) oldnames.lib kernel32.lib user32.lib gdi32.lib \ +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 diff --git a/win32/win32.c b/win32/win32.c index 9361191..20aa4ee 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -669,8 +669,12 @@ win32_opendir(char *filename) long idx; char scanname[MAX_PATH+3]; struct stat sbuf; - WIN32_FIND_DATA FindData; + WIN32_FIND_DATAA aFindData; + WIN32_FIND_DATAW wFindData; HANDLE fh; + char buffer[MAX_PATH*2]; + WCHAR wbuffer[MAX_PATH]; + char* ptr; len = strlen(filename); if (len > MAX_PATH) @@ -700,7 +704,13 @@ win32_opendir(char *filename) scanname[len] = '\0'; /* do the FindFirstFile call */ - fh = FindFirstFile(scanname, &FindData); + if (USING_WIDE()) { + A2WHELPER(scanname, wbuffer, sizeof(wbuffer), GETINTERPMODE()); + fh = FindFirstFileW(wbuffer, &wFindData); + } + else { + fh = FindFirstFileA(scanname, &aFindData); + } if (fh == INVALID_HANDLE_VALUE) { /* FindFirstFile() fails on empty drives! */ if (GetLastError() == ERROR_FILE_NOT_FOUND) @@ -712,11 +722,18 @@ win32_opendir(char *filename) /* now allocate the first part of the string table for * the filenames that we find. */ - idx = strlen(FindData.cFileName)+1; + if (USING_WIDE()) { + W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer), GETINTERPMODE()); + ptr = buffer; + } + else { + ptr = aFindData.cFileName; + } + idx = strlen(ptr)+1; New(1304, p->start, idx, char); if (p->start == NULL) croak("opendir: malloc failed!\n"); - strcpy(p->start, FindData.cFileName); + strcpy(p->start, ptr); p->nfiles++; /* loop finding all the files that match the wildcard @@ -724,15 +741,21 @@ win32_opendir(char *filename) * the variable idx should point one past the null terminator * of the previous string found. */ - while (FindNextFile(fh, &FindData)) { - len = strlen(FindData.cFileName); + while (USING_WIDE() + ? FindNextFileW(fh, &wFindData) + : FindNextFileA(fh, &aFindData)) { + if (USING_WIDE()) { + W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer), GETINTERPMODE()); + } + /* ptr is set above to the correct area */ + len = strlen(ptr); /* bump the string table size by enough for the * new name and it's null terminator */ Renew(p->start, idx+len+1, char); if (p->start == NULL) croak("opendir: malloc failed!\n"); - strcpy(&p->start[idx], FindData.cFileName); + strcpy(&p->start[idx], ptr); p->nfiles++; idx += len+1; } @@ -930,6 +953,7 @@ win32_stat(const char *path, struct stat *buffer) char t[MAX_PATH+1]; int l = strlen(path); int res; + WCHAR wbuffer[MAX_PATH]; if (l > 1) { switch(path[l - 1]) { @@ -951,13 +975,25 @@ win32_stat(const char *path, struct stat *buffer) break; } } - res = stat(path,buffer); + if (USING_WIDE()) { + A2WHELPER(path, wbuffer, sizeof(wbuffer), GETINTERPMODE()); + res = _wstat(wbuffer, (struct _stat *)buffer); + } + else { + res = stat(path, buffer); + } if (res < 0) { /* CRT is buggy on sharenames, so make sure it really isn't. * XXX using GetFileAttributesEx() will enable us to set * buffer->st_*time (but note that's not available on the * Windows of 1995) */ - DWORD r = GetFileAttributes(path); + DWORD r; + if (USING_WIDE()) { + r = GetFileAttributesW(wbuffer); + } + else { + r = GetFileAttributesA(path); + } if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) { /* buffer may still contain old garbage since stat() failed */ Zero(buffer, 1, struct stat); @@ -973,7 +1009,9 @@ win32_stat(const char *path, struct stat *buffer) && (path[2] == '\\' || path[2] == '/')) { /* The drive can be inaccessible, some _stat()s are buggy */ - if (!GetVolumeInformation(path,NULL,0,NULL,NULL,NULL,NULL,0)) { + if (USING_WIDE() + ? !GetVolumeInformationW(wbuffer,NULL,0,NULL,NULL,NULL,NULL,0) + : !GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) { errno = ENOENT; return -1; } @@ -1083,19 +1121,46 @@ DllExport char * win32_getenv(const char *name) { static char *curitem = Nullch; /* XXX threadead */ - static DWORD curlen = 0; /* XXX threadead */ + static WCHAR *wCuritem = (WCHAR*)Nullch; /* XXX threadead */ + static DWORD curlen = 0, wCurlen = 0;/* XXX threadead */ + WCHAR wBuffer[MAX_PATH]; DWORD needlen; + if (USING_WIDE()) { + if (!wCuritem) { + wCurlen = 512; + New(1306,wCuritem,wCurlen,WCHAR); + } + } if (!curitem) { curlen = 512; New(1305,curitem,curlen,char); } - needlen = GetEnvironmentVariable(name,curitem,curlen); + if (USING_WIDE()) { + A2WHELPER(name, wBuffer, sizeof(wBuffer), GETINTERPMODE()); + needlen = GetEnvironmentVariableW(wBuffer,wCuritem,wCurlen); + } + else + needlen = GetEnvironmentVariableA(name,curitem,curlen); if (needlen != 0) { - while (needlen > curlen) { - Renew(curitem,needlen,char); - curlen = needlen; - needlen = GetEnvironmentVariable(name,curitem,curlen); + if (USING_WIDE()) { + while (needlen > wCurlen) { + Renew(wCuritem,needlen,WCHAR); + wCurlen = needlen; + needlen = GetEnvironmentVariableW(wBuffer,wCuritem,wCurlen); + } + if (needlen > curlen) { + Renew(curitem,needlen,char); + curlen = needlen; + } + W2AHELPER(wCuritem, curitem, curlen, GETINTERPMODE()); + } + else { + while (needlen > curlen) { + Renew(curitem,needlen,char); + curlen = needlen; + needlen = GetEnvironmentVariableA(name,curitem,curlen); + } } } else { @@ -1124,31 +1189,47 @@ win32_putenv(const char *name) { char* curitem; char* val; - int relval = -1; + WCHAR* wCuritem; + WCHAR* wVal; + int length, relval = -1; if(name) { - New(1309,curitem,strlen(name)+1,char); - strcpy(curitem, name); - val = strchr(curitem, '='); - if(val) { - /* The sane way to deal with the environment. - * Has these advantages over putenv() & co.: - * * enables us to store a truly empty value in the - * environment (like in UNIX). - * * we don't have to deal with RTL globals, bugs and leaks. - * * Much faster. - * Why you may want to enable USE_WIN32_RTL_ENV: - * * environ[] and RTL functions will not reflect changes, - * which might be an issue if extensions want to access - * the env. via RTL. This cuts both ways, since RTL will - * not see changes made by extensions that call the Win32 - * functions directly, either. - * GSAR 97-06-07 - */ - *val++ = '\0'; - if(SetEnvironmentVariable(curitem, *val ? val : NULL)) - relval = 0; + if (USING_WIDE()) { + length = strlen(name)+1; + New(1309,wCuritem,length,WCHAR); + A2WHELPER(name, wCuritem, length*2, GETINTERPMODE()); + wVal = wcschr(wCuritem, '='); + if(wVal) { + *wVal++ = '\0'; + if(SetEnvironmentVariableW(wCuritem, *wVal ? wVal : NULL)) + relval = 0; + } + Safefree(wCuritem); + } + else { + New(1309,curitem,strlen(name)+1,char); + strcpy(curitem, name); + val = strchr(curitem, '='); + if(val) { + /* The sane way to deal with the environment. + * Has these advantages over putenv() & co.: + * * enables us to store a truly empty value in the + * environment (like in UNIX). + * * we don't have to deal with RTL globals, bugs and leaks. + * * Much faster. + * Why you may want to enable USE_WIN32_RTL_ENV: + * * environ[] and RTL functions will not reflect changes, + * which might be an issue if extensions want to access + * the env. via RTL. This cuts both ways, since RTL will + * not see changes made by extensions that call the Win32 + * functions directly, either. + * GSAR 97-06-07 + */ + *val++ = '\0'; + if(SetEnvironmentVariableA(curitem, *val ? val : NULL)) + relval = 0; + } + Safefree(curitem); } - Safefree(curitem); } return relval; } @@ -1220,8 +1301,16 @@ win32_utime(const char *filename, struct utimbuf *times) FILETIME ftAccess; FILETIME ftWrite; struct utimbuf TimeBuffer; + WCHAR wbuffer[MAX_PATH]; - int rc = utime(filename,times); + int rc; + if (USING_WIDE()) { + A2WHELPER(filename, wbuffer, sizeof(wbuffer), GETINTERPMODE()); + rc = _wutime(wbuffer, (struct _utimbuf*)times); + } + else { + rc = utime(filename, times); + } /* EACCES: path specifies directory or readonly file */ if (rc == 0 || errno != EACCES /* || !IsWinNT() */) return rc; @@ -1233,9 +1322,16 @@ win32_utime(const char *filename, struct utimbuf *times) } /* This will (and should) still fail on readonly files */ - handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (USING_WIDE()) { + handle = CreateFileW(wbuffer, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + } + else { + handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + } if (handle == INVALID_HANDLE_VALUE) return rc; @@ -1770,11 +1866,20 @@ win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp) return fwrite(buf, size, count, fp); } +#define MODE_SIZE 10 + DllExport FILE * win32_fopen(const char *filename, const char *mode) { + WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH]; if (stricmp(filename, "/dev/null")==0) - return fopen("NUL", mode); + filename = "NUL"; + + if (USING_WIDE()) { + A2WHELPER(mode, wMode, sizeof(wMode), GETINTERPMODE()); + A2WHELPER(filename, wBuffer, sizeof(wBuffer), GETINTERPMODE()); + return _wfopen(wBuffer, wMode); + } return fopen(filename, mode); } @@ -1784,16 +1889,28 @@ win32_fopen(const char *filename, const char *mode) #endif DllExport FILE * -win32_fdopen( int handle, const char *mode) +win32_fdopen(int handle, const char *mode) { + WCHAR wMode[MODE_SIZE]; + if (USING_WIDE()) { + A2WHELPER(mode, wMode, sizeof(wMode), GETINTERPMODE()); + return _wfdopen(handle, wMode); + } return fdopen(handle, (char *) mode); } DllExport FILE * -win32_freopen( const char *path, const char *mode, FILE *stream) +win32_freopen(const char *path, const char *mode, FILE *stream) { + WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH]; if (stricmp(path, "/dev/null")==0) - return freopen("NUL", mode, stream); + path = "NUL"; + + if (USING_WIDE()) { + A2WHELPER(mode, wMode, sizeof(wMode), GETINTERPMODE()); + A2WHELPER(path, wBuffer, sizeof(wBuffer), GETINTERPMODE()); + return _wfreopen(wBuffer, wMode, stream); + } return freopen(path, mode, stream); } @@ -2026,12 +2143,24 @@ win32_pclose(FILE *pf) DllExport int win32_rename(const char *oname, const char *newname) { + WCHAR wOldName[MAX_PATH]; + WCHAR wNewName[MAX_PATH]; + BOOL bResult; /* XXX despite what the documentation says about MoveFileEx(), * it doesn't work under Windows95! */ if (IsWinNT()) { - if (!MoveFileEx(oname,newname, - MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING)) { + if (USING_WIDE()) { + A2WHELPER(oname, wOldName, sizeof(wOldName), GETINTERPMODE()); + A2WHELPER(newname, wNewName, sizeof(wNewName), GETINTERPMODE()); + bResult = MoveFileExW(wOldName,wNewName, + MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING); + } + else { + bResult = MoveFileExA(oname,newname, + MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING); + } + if (!bResult) { DWORD err = GetLastError(); switch (err) { case ERROR_BAD_NET_NAME: @@ -2152,8 +2281,14 @@ win32_open(const char *path, int flag, ...) pmode = va_arg(ap, int); va_end(ap); + WCHAR wBuffer[MAX_PATH]; if (stricmp(path, "/dev/null")==0) - return open("NUL", flag, pmode); + path = "NUL"; + + if (USING_WIDE()) { + A2WHELPER(path, wBuffer, sizeof(wBuffer), GETINTERPMODE()); + return _wopen(wBuffer, flag, pmode); + } return open(path,flag,pmode); } diff --git a/win32/win32.h b/win32/win32.h index bfca44a..a539a16 100644 --- a/win32/win32.h +++ b/win32/win32.h @@ -392,5 +392,19 @@ struct thread_intern { # endif /* !USE_DECLSPEC_THREAD */ #endif /* USE_THREADS */ +/* UNICODE<>ANSI translation helpers */ +/* Use CP_ACP when mode is ANSI */ +/* Use CP_UTF8 when mode is UTF8 */ + +#define A2WHELPER(lpa, lpw, nChars, acp)\ + lpw[0] = 0, MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars) + +#define W2AHELPER(lpw, lpa, nChars, acp)\ + lpa[0] = '\0', WideCharToMultiByte(acp, 0, lpw, -1, lpa, nChars, NULL, NULL) + +/* place holders for now */ +#define USING_WIDE() 0 +#define GETINTERPMODE() CP_ACP + #endif /* _INC_WIN32_PERL5 */