summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authornaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-12-22 07:00:55 +0000
committernaruse <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-12-22 07:00:55 +0000
commite39b6aaac254ca32849d3718f64d3f8f868b0c98 (patch)
tree2abb0979dd67326cab2fdbcb19c54bc81e4fb8cf /win32
parent9e5632ab14a10adc375bc6a57c30640652e0cd85 (diff)
parent9881a183bde20d1c174d33d8a2f637e9c092a08b (diff)
Release branch of Ruby 2.1
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_1@44340 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'win32')
-rw-r--r--win32/Makefile.sub98
-rw-r--r--win32/README.win328
-rwxr-xr-xwin32/configure.bat55
-rw-r--r--win32/file.c256
-rwxr-xr-xwin32/ifchange.bat24
-rwxr-xr-xwin32/rm.bat4
-rw-r--r--win32/rtname.cmd18
-rw-r--r--win32/setup.mak99
-rw-r--r--win32/win32.c896
9 files changed, 976 insertions, 482 deletions
diff --git a/win32/Makefile.sub b/win32/Makefile.sub
index 3f62197cfb..216fb9dcf3 100644
--- a/win32/Makefile.sub
+++ b/win32/Makefile.sub
@@ -7,6 +7,7 @@ MKFILES = Makefile
NULL = nul
CHDIR = cd
PATH_SEPARATOR = ;
+TZ = # skip timezone tests
!ifndef MFLAGS
MFLAGS=-l
@@ -227,10 +228,17 @@ EXTLIBS =
EXTSOLIBS =
!endif
!if !defined(LIBS)
-LIBS = oldnames.lib user32.lib advapi32.lib shell32.lib ws2_32.lib imagehlp.lib shlwapi.lib $(EXTLIBS)
+LIBS = oldnames.lib user32.lib advapi32.lib shell32.lib ws2_32.lib
+!if $(MSC_VER) >= 1400
+LIBS = $(LIBS) iphlpapi.lib
+!endif
+LIBS = $(LIBS) imagehlp.lib shlwapi.lib $(EXTLIBS)
!endif
!if !defined(MISSING)
-MISSING = acosh.obj cbrt.obj crypt.obj erf.obj ffs.obj langinfo.obj lgamma_r.obj strlcat.obj strlcpy.obj tgamma.obj win32/win32.obj win32/file.obj setproctitle.obj
+MISSING = crypt.obj ffs.obj langinfo.obj lgamma_r.obj strlcat.obj strlcpy.obj win32/win32.obj win32/file.obj setproctitle.obj
+!if $(RT_VER) < 120
+MISSING = $(MISSING) acosh.obj cbrt.obj erf.obj tgamma.obj
+!endif
!endif
DLNOBJ = dln.obj
@@ -249,7 +257,7 @@ LDSHARED_2 = @if exist $(@).manifest @$(RM) $(@:/=\).manifest
CPPFLAGS = $(DEFS) $(ARCHDEFS) $(CPPFLAGS)
DLDFLAGS = $(LDFLAGS) -dll
-SOLIBS =
+SOLIBS =
RCFILES = $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(RUBY_SO_NAME).rc
!ifndef RCFLAGS
!if $(MSC_VER) >= 1600
@@ -287,11 +295,7 @@ BTESTRUBY = $(MINIRUBY)
!ifndef RUBY
RUBY = ruby
!endif
-!if "$(USE_RUBYGEMS)" == "NO"
-DEFAULT_PRELUDES = $(NO_GEM_PRELUDE)
-!else
-DEFAULT_PRELUDES = $(YES_GEM_PRELUDE)
-!endif
+DEFAULT_PRELUDES = $(GEM_PRELUDE)
DTRACE_EXT = dmyh
@@ -324,7 +328,7 @@ PREP = miniruby$(EXEEXT)
!endif
!if !defined(EXTSTATIC)
-EXTSTATIC =
+EXTSTATIC =
!endif
OBJEXT = obj
@@ -355,6 +359,11 @@ COMMON_MACROS = WIN32_LEAN_AND_MEAN WIN32
COMMON_HEADERS = winsock2.h ws2tcpip.h windows.h
!endif
+!if "$(EXTSTATIC)" == "static"
+ENCOBJS = enc/encinit.$(OBJEXT) enc/libenc.lib enc/libtrans.lib
+EXTOBJS = ext/extinit.$(OBJEXT)
+!endif
+
arch_hdrdir = $(EXTOUT)/include/$(arch)
hdrdir = $(srcdir)/include
VPATH = $(arch_hdrdir)/ruby;$(hdrdir)/ruby;$(srcdir);$(srcdir)/enc;$(srcdir)/missing;$(win_srcdir)
@@ -373,8 +382,11 @@ ruby_pc = $(RUBY_BASE_NAME)-$(MAJOR).$(MINOR).pc
MESSAGE_BEGIN = @for %I in (
MESSAGE_END = ) do @echo.%~I
+ECHO_BEGIN = @echo.
+ECHO_END =
all: $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub $(srcdir)/common.mk
+prog: config
ruby: $(PROGRAM)
rubyw: $(WPROGRAM)
@@ -448,8 +460,8 @@ test-rubyspec-precheck:
$(MKFILES): $(win_srcdir)/Makefile.sub $(win_srcdir)/configure.bat $(win_srcdir)/setup.mak $(win_srcdir)/enc-setup.mak $(srcdir)/common.mk $(srcdir)/enc/Makefile.in
$(COMSPEC) /C $(win_srcdir:/=\)\configure.bat $(configure_args)
- @echo $(MKFILES) should be updated, re-run $(MAKE).
- @exit 1
+ @fc Makefile Makefile.old > nul && echo Makefile unchanged || \
+ (echo $(MKFILES) was updated, re-run $(MAKE). & exit 1)
RUBY_CONFIG_H = $(arch_hdrdir)/ruby/config.h
CONFIG_H = ./.config.h.time
@@ -474,7 +486,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
!if !exist("$(arch_hdrdir)/ruby")
@md $(arch_hdrdir:/=\)\ruby
!endif
- @$(IFCHANGE) $(RUBY_CONFIG_H:/=\) <<
+ @$(IFCHANGE) "--timestamp=$(@:/=\)" $(RUBY_CONFIG_H:/=\) <<
#ifndef $(guard)
#define $(guard) 1
#if _MSC_VER != $(MSC_VER)
@@ -514,6 +526,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
!endif
#define SIZEOF_FLOAT 4
#define SIZEOF_DOUBLE 8
+#define SIGNEDNESS_OF_TIME_T -1
!if $(RT_VER) >= 80
#define SIZEOF_TIME_T 8
#define TIMET2NUM(v) LL2NUM(v)
@@ -523,6 +536,9 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define TIMET2NUM(v) LONG2NUM(v)
#define NUM2TIMET(v) NUM2LONG(v)
!endif
+#define CLOCKID2NUM(v) INT2NUM(v)
+#define NUM2CLOCKID(v) NUM2INT(v)
+#define SIZEOF_CLOCK_T 4
#define SIZEOF_RLIM_T 0
!if "$(ARCH)" == "x64" || "$(ARCH)" == "ia64"
#define SIZEOF_SIZE_T 8
@@ -551,17 +567,22 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define FUNC_STDCALL(x) __stdcall x
#define FUNC_CDECL(x) __cdecl x
#define FUNC_FASTCALL(x) __fastcall x
+!if $(MSC_VER) >= 1500
+#define RUBY_FUNCTION_NAME_STRING __FUNCTION__
+!endif
#define RUBY_EXTERN extern __declspec(dllimport)
#define HAVE_DECL_SYS_NERR 1
#define HAVE_LIMITS_H 1
#define HAVE_FCNTL_H 1
#define HAVE_SYS_UTIME_H 1
#define HAVE_FLOAT_H 1
+#define HAVE_TIME_H 1
#define rb_pid_t int
#define rb_gid_t int
#define rb_uid_t int
#define HAVE_STRUCT_STAT_ST_RDEV 1
#define HAVE_ST_RDEV 1
+#define HAVE_STRUCT_TIMEVAL 1
!if $(MSC_VER) >= 1600
#define HAVE_STDINT_H 1
!else
@@ -615,11 +636,26 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define GETGROUPS_T int
#define RETSIGTYPE void
#define TYPEOF_TIMEVAL_TV_SEC long
+!if $(RT_VER) >= 120
+#define HAVE_ACOSH 1
+#define HAVE_ASINH 1
+#define HAVE_ATANH 1
+#define HAVE_CBRT 1
+#define HAVE_LOG2 1
+#define log2(x) log2(x)
+#define HAVE_ERF 1
+#define HAVE_ERFC 1
+#define HAVE_ROUND 1
+#define HAVE_TGAMMA 1
+!endif
#define HAVE_ALLOCA 1
#define HAVE_DUP2 1
#define HAVE_MEMCMP 1
#define HAVE_MEMMOVE 1
#define HAVE_MKDIR 1
+#define HAVE_CLOCK_GETTIME 1
+#define HAVE_CLOCK_GETRES 1
+#define HAVE_SPAWNV 1
#define HAVE_STRCASECMP 1
#define HAVE_STRNCASECMP 1
#define HAVE_STRERROR 1
@@ -642,7 +678,6 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define HAVE_TRUNCATE 1
#define HAVE_FTRUNCATE 1
#define HAVE_FSEEKO 1
-#define HAVE_FTELLO 1
#define HAVE_TIMES 1
#define HAVE_FCNTL 1
#define HAVE_LINK 1
@@ -657,6 +692,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define HAVE_TZNAME 1
#define HAVE_DAYLIGHT 1
#define HAVE_GMTIME_R 1
+#define HAVE_TYPE_NET_LUID 1
#define SETPGRP_VOID 1
#define RSHIFT(x,y) ((x)>>(int)y)
#define HAVE_RB_FD_INIT 1
@@ -675,9 +711,14 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
!endif
#define LOAD_RELATIVE 1
#define DLEXT ".so"
+!if "$(EXTSTATIC)" == "static"
+#define EXTSTATIC 1
+!endif
#define EXECUTABLE_EXTS $(EXECUTABLE_EXTS)
#define RUBY_COREDLL "$(RT)"
#define LIBRUBY_SO "$(LIBRUBY_SO)"
+#define RUBY_PLATFORM "$(arch)"
+#define RUBY_SITEARCH "$(sitearch)"
#if 0
$(BANG)if "$(RUBY_SO_NAME)"!="$$(RUBY_SO_NAME)" || "$(ARCH)-$(PLATFORM)"!="$$(ARCH)-$$(PLATFORM)"
config.h: nul
@@ -685,14 +726,6 @@ $(BANG)endif
#endif
#endif /* $(guard) */
<<
- @echo Creating verconf.h
- @$(IFCHANGE) verconf.h <<
-#define RUBY_LIB_VERSION_STYLE 3 /* full */
-#define RUBY_LIB_PREFIX "/lib/$(RUBY_BASE_NAME)"
-#define RUBY_PLATFORM "$(arch)"
-#define RUBY_SITEARCH "$(sitearch)"
-<<
- @exit > $(@:/=\)
#!if exist($(RUBY_CONFIG_H))
#! if exist(config_h.bak)
@@ -773,6 +806,7 @@ s,@RM@,$$(COMSPEC) /C $$(top_srcdir:/=\)\win32\rm.bat,;t t
s,@RMDIR@,$$(COMSPEC) /C $$(top_srcdir:/=\)\win32\rmdirs.bat,:t t
s,@RMDIRS@,$$(COMSPEC) /C $$(top_srcdir:/=\)\win32\rmdirs.bat,;t t
s,@RMALL@,$$(COMSPEC) /C rmdir /s /q,;t t
+s,@MAKEDIRS@,$$(COMSPEC) /E:ON /C $$(top_srcdir:/=\)\win32\makedirs.bat,;t t
s,@LIBOBJS@,$(LIBOBJS),;t t
s,@ALLOCA@,$(ALLOCA),;t t
s,@DEFAULT_KCODE@,$(DEFAULT_KCODE),;t t
@@ -839,15 +873,30 @@ s,@COMMON_HEADERS@,$(COMMON_HEADERS),;t t
s,@cleanobjs@,$$*.exp $$*.lib $$*.pdb,;t t
s,@DISTCLEANFILES@,vc*.pdb,;t t
s,@EXPORT_PREFIX@, ,;t t
+s,@archlibdir@,$${libdir}/$${arch},;t t
+s,@sitearchlibdir@,$${libdir}/$${sitearch},;t t
+s,@archincludedir@,$${includedir}/$${arch},;t t
+s,@sitearchincludedir@,$${includedir}/$${sitearch},;t t
s,@arch@,$(ARCH)-$(PLATFORM),;t t
s,@sitearch@,$(ARCH)-$(RT),;t t
s,@ruby_version@,$(ruby_version),;t t
s,@rubylibprefix@,$${prefix}/lib/$${RUBY_BASE_NAME},;t t
+s,@rubyarchdir@,$${rubylibdir}/$${arch},;t t
+s,@rubylibdir@,$${rubylibprefix}/$${ruby_version},;t t
s,@sitedir@,$${rubylibprefix}/site_ruby,;t t
+s,@sitearchdir@,$${sitelibdir}/$${sitearch},;t t
+s,@sitelibdir@,$${sitedir}/$${ruby_version},;t t
s,@vendordir@,$${rubylibprefix}/vendor_ruby,;t t
+s,@vendorarchdir@,$${vendorlibdir}/$${sitearch},;t t
+s,@vendorlibdir@,$${vendordir}/$${ruby_version},;t t
s,@rubyhdrdir@,$$(includedir)/$${RUBY_BASE_NAME}-$$(ruby_version),;t t
s,@sitehdrdir@,$$(rubyhdrdir)/site_ruby,;t t
s,@vendorhdrdir@,$$(rubyhdrdir)/vendor_ruby,;t t
+s,@rubyarchhdrdir@,$$(rubyhdrdir)/$${arch},;t t
+s,@sitearchhdrdir@,$$(sitehdrdir)/$${sitearch},;t t
+s,@vendorarchhdrdir@,$$(vendorhdrdir)/$${sitearch},;t t
+s,@PLATFORM_DIR@,$(PLATFORM_DIR),;t t
+s,@THREAD_MODEL@,$(THREAD_MODEL),;t t
s,@configure_args@,--with-make-prog=nmake --enable-shared $(configure_args),;t t
s,@configure_input@,$$configure_input,;t t
s,@srcdir@,$(srcdir),;t t
@@ -920,6 +969,7 @@ $(LIBRUBY_SO): $(LIBRUBY_A) $(DLDOBJS) $(RUBYDEF) $(RUBY_SO_NAME).res
$(Q) $(LDSHARED_0)
$(Q) $(LDSHARED_1)
$(Q) $(LDSHARED_2)
+# | findstr -v -c:LNK4049 -c:LNK4217
$(RUBYDEF): $(LIBRUBY_A) $(PREP)
$(ECHO) generating $(@:\=/)
@@ -1077,7 +1127,6 @@ probes.h: {$(VPATH)}probes.dmyh
$(Q) $(CP) $(srcdir:/=\)\probes.dmyh $(OS_DEST_FILE)\
)
-
INSNS = opt_sc.inc optinsn.inc optunifs.inc insns.inc insns_info.inc \
vmtc.inc vm.inc
@@ -1096,3 +1145,8 @@ INSNS = opt_sc.inc optinsn.inc optunifs.inc insns.inc insns_info.inc \
! if [del insns_rules.mk > nul]
! endif
!endif
+
+loadpath: verconf.h
+ @$(CPP) $(XCFLAGS) $(CPPFLAGS) $(srcdir)/loadpath.c | \
+ sed -e '1,/^const char ruby_initial_load_paths/d;/;/,$$d' \
+ -e '/^^ /!d;s/ *"\\\\0"$$//;s/" *"//g'
diff --git a/win32/README.win32 b/win32/README.win32
index 78959ad310..314feb39cc 100644
--- a/win32/README.win32
+++ b/win32/README.win32
@@ -40,7 +40,7 @@
The default ((|<PLATFORM>|)) is `(({i386-mswin32}))'.
(2) Change ((|RUBY_INSTALL_NAME|)) and ((|RUBY_SO_NAME|)) in (({Makefile}))
- if you want to change the name of the executable files.
+ if you want to change the name of the executable files.
And add ((|RUBYW_INSTALL_NAME|)) to change the name of the
executable without console window if also you want.
@@ -60,8 +60,8 @@ to their base names.
$(RUBYW_INSTALL_NAME).ico or rubyw.ico --> $(RUBYW_INSTALL_NAME).exe
the others --> $(RUBY_SO_NAME).dll
-Although no icons are distributed with the ruby source or in the official
-site, you can use anything you like. For example, followings are written
+Although no icons are distributed with the ruby source or in the official
+site, you can use anything you like. For example, followings are written
in Japanese, but you can download at least.
* ((<URL:http://homepage1.nifty.com/a_nakata/ruby/>)) or
@@ -129,7 +129,7 @@ in Japanese, but you can download at least.
== Bugs
-You can ((*NOT*)) use a path name contains any white space characters as
+You can ((*NOT*)) use a path name that contains any white space characters as
the ruby source directory, this restriction comes from the behavior of
(({!INCLUDE})) directives of (({NMAKE})).
((- you may call it a bug. -))
diff --git a/win32/configure.bat b/win32/configure.bat
index 98695ed646..6910f561dd 100755
--- a/win32/configure.bat
+++ b/win32/configure.bat
@@ -1,5 +1,6 @@
@echo off
@setlocal disabledelayedexpansion
+set witharg=
echo> ~tmp~.mak ####
echo>> ~tmp~.mak conf = %0
@@ -9,6 +10,7 @@ echo>> ~tmp~.mak @-$(MAKE) -l$(MAKEFLAGS) -f $(@D)/setup.mak \
if exist pathlist.tmp del pathlist.tmp
echo>confargs.tmp #define CONFIGURE_ARGS \
:loop
+set opt=%1
if "%1" == "" goto :end
if "%1" == "--prefix" goto :prefix
if "%1" == "--srcdir" goto :srcdir
@@ -31,23 +33,20 @@ if "%1" == "--extout" goto :extout
if "%1" == "--path" goto :path
if "%1" == "--with-baseruby" goto :baseruby
if "%1" == "--with-ntver" goto :ntver
-echo %1| findstr "^--with-.*-dir$" > nul
-if not errorlevel 1 goto :witharg
-echo %1| findstr "^--with-.*-include$" > nul
-if not errorlevel 1 goto :witharg
-echo %1| findstr "^--with-.*-lib$" > nul
-if not errorlevel 1 goto :witharg
-echo %1| findstr "^--with-ext$" > nul
-if not errorlevel 1 goto :witharg
-echo %1| findstr "^--with-extensions$" > nul
-if not errorlevel 1 goto :witharg
-echo %1| findstr "^--without-ext$" > nul
-if not errorlevel 1 goto :witharg
-echo %1| findstr "^--without-extensions$" > nul
-if not errorlevel 1 goto :witharg
+if "%1" == "--without-ext" goto :witharg
+if "%1" == "--without-extensions" goto :witharg
+if "%opt:~0,10%" == "--without-" goto :withoutarg
+if "%opt:~0,7%" == "--with-" goto :witharg
if "%1" == "-h" goto :help
if "%1" == "--help" goto :help
- echo>>confargs.tmp %1 \
+ if "%opt:~0,1%" == "-" (
+ echo>>confargs.tmp %1 \
+ set witharg=
+ ) else if "%witharg" == "" (
+ echo>>confargs.tmp %1 \
+ ) else (
+ echo>>confargs.tmp ,%1\
+ )
shift
goto :loop
:srcdir
@@ -58,31 +57,31 @@ goto :loop
goto :loop
:prefix
echo>> ~tmp~.mak "prefix=%~2" \
- echo>>confargs.tmp %1=%2 \
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:pprefix
echo>> ~tmp~.mak "PROGRAM_PREFIX=%~2" \
- echo>>confargs.tmp %1=%2 \
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:suffix
echo>> ~tmp~.mak "PROGRAM_SUFFIX=%~2" \
- echo>>confargs.tmp %1=%2 \
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:installname
echo>> ~tmp~.mak "RUBY_INSTALL_NAME=%~2" \
- echo>>confargs.tmp %1=%2 \
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:soname
echo>> ~tmp~.mak "RUBY_SO_NAME=%~2" \
- echo>>confargs.tmp %1=%2 \
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
@@ -134,31 +133,36 @@ goto :loop
goto :loop
:ntver
echo>> ~tmp~.mak "NTVER=%~2" \
- echo>>confargs.tmp %1=%2 \
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:extout
echo>> ~tmp~.mak "EXTOUT=%~2" \
- echo>>confargs.tmp %1=%2 \
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:path
echo>>pathlist.tmp %~2;\
- echo>>confargs.tmp %1=%2 \
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:baseruby
echo>> ~tmp~.mak "BASERUBY=%~2" \
- echo>>confargs.tmp %1=%2 \
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:witharg
- echo>>confargs.tmp %1=%2 \
+ echo>>confargs.tmp %1=%2\
+ set witharg=1
+ shift
shift
+goto :loop
+:withoutarg
+ echo>>confargs.tmp %1 \
shift
goto :loop
:help
@@ -175,7 +179,6 @@ goto :loop
echo --with-ext="a,b,..." use extensions a, b, ...
echo --without-ext="a,b,..." ignore extensions a, b, ...
echo --disable-install-doc do not install rdoc indexes during install
- echo --disable-win95 disable win95 support
echo --with-ntver=0xXXXX target NT version (shouldn't use with old SDK)
del *.tmp
del ~tmp~.mak
diff --git a/win32/file.c b/win32/file.c
index dfe122480f..0c5fda9611 100644
--- a/win32/file.c
+++ b/win32/file.c
@@ -1,5 +1,6 @@
#include "ruby/ruby.h"
#include "ruby/encoding.h"
+#include "internal.h"
#include <winbase.h>
#include <wchar.h>
#include <shlwapi.h>
@@ -9,7 +10,10 @@
#endif
/* cache 'encoding name' => 'code page' into a hash */
-static VALUE rb_code_page;
+static struct code_page_table {
+ USHORT *table;
+ unsigned int count;
+} rb_code_page;
#define IS_DIR_SEPARATOR_P(c) (c == L'\\' || c == L'/')
#define IS_DIR_UNC_P(c) (IS_DIR_SEPARATOR_P(c[0]) && IS_DIR_SEPARATOR_P(c[1]))
@@ -32,19 +36,14 @@ replace_wchar(wchar_t *s, int find, int replace)
/* Convert str from multibyte char to wchar with specified code page */
static inline void
-convert_mb_to_wchar(VALUE str, wchar_t **wstr, wchar_t **wstr_pos, size_t *wstr_len, UINT code_page)
+convert_mb_to_wchar(const char *str, wchar_t **wstr, size_t *wstr_len, UINT code_page)
{
size_t len;
- if (NIL_P(str))
- return;
-
- len = MultiByteToWideChar(code_page, 0, RSTRING_PTR(str), -1, NULL, 0) + 1;
+ len = MultiByteToWideChar(code_page, 0, str, -1, NULL, 0) + 1;
*wstr = (wchar_t *)xmalloc(len * sizeof(wchar_t));
- if (wstr_pos)
- *wstr_pos = *wstr;
- MultiByteToWideChar(code_page, 0, RSTRING_PTR(str), -1, *wstr, len);
+ MultiByteToWideChar(code_page, 0, str, -1, *wstr, len);
*wstr_len = len - 2;
}
@@ -172,6 +171,30 @@ system_code_page(void)
return AreFileApisANSI() ? CP_ACP : CP_OEMCP;
}
+void rb_enc_foreach_name(int (*func)(st_data_t name, st_data_t idx, st_data_t arg), st_data_t arg);
+
+static int
+code_page_i(st_data_t name, st_data_t idx, st_data_t arg)
+{
+ const char *n = (const char *)name;
+ if (strncmp("CP", n, 2) == 0) {
+ int code_page = atoi(n + 2);
+ if (code_page != 0) {
+ struct code_page_table *cp = (struct code_page_table *)arg;
+ unsigned int count = cp->count;
+ USHORT *table = cp->table;
+ if (count <= idx) {
+ unsigned int i = count;
+ cp->count = count = ((idx + 4) & ~31 | 28);
+ cp->table = table = realloc(table, count * sizeof(*table));
+ while (i < count) table[i++] = INVALID_CODE_PAGE;
+ }
+ table[idx] = (USHORT)code_page;
+ }
+ }
+ return ST_CONTINUE;
+}
+
/*
Return code page number of the encoding.
Cache code page into a hash for performance since finding the code page in
@@ -180,72 +203,25 @@ system_code_page(void)
static UINT
code_page(rb_encoding *enc)
{
- VALUE code_page_value, name_key;
- VALUE encoding, names_ary = Qundef, name;
- char *enc_name;
- struct RString fake_str;
- ID names;
- long i;
+ int enc_idx;
if (!enc)
return system_code_page();
- enc_name = (char *)rb_enc_name(enc);
-
- fake_str.basic.flags = T_STRING|RSTRING_NOEMBED;
- fake_str.basic.klass = rb_cString;
- fake_str.as.heap.len = strlen(enc_name);
- fake_str.as.heap.ptr = enc_name;
- fake_str.as.heap.aux.capa = fake_str.as.heap.len;
- name_key = (VALUE)&fake_str;
- ENCODING_CODERANGE_SET(name_key, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
+ enc_idx = rb_enc_to_index(enc);
- code_page_value = rb_hash_lookup(rb_code_page, name_key);
- if (code_page_value != Qnil)
- return (UINT)FIX2INT(code_page_value);
-
- name_key = rb_usascii_str_new2(enc_name);
-
- encoding = rb_enc_from_encoding(enc);
- if (!NIL_P(encoding)) {
- CONST_ID(names, "names");
- names_ary = rb_funcall(encoding, names, 0);
+ /* map US-ASCII and ASCII-8bit as code page 1252 (us-ascii) */
+ if (enc_idx == rb_usascii_encindex() || enc_idx == rb_ascii8bit_encindex()) {
+ return 1252;
}
- /* map US-ASCII and ASCII-8bit as code page 20127 (us-ascii) */
- if (enc == rb_usascii_encoding() || enc == rb_ascii8bit_encoding()) {
- UINT code_page = 20127;
- rb_hash_aset(rb_code_page, name_key, INT2FIX(code_page));
- return code_page;
- }
+ if (0 <= enc_idx && (unsigned int)enc_idx < rb_code_page.count)
+ return rb_code_page.table[enc_idx];
- if (names_ary != Qundef) {
- for (i = 0; i < RARRAY_LEN(names_ary); i++) {
- name = RARRAY_PTR(names_ary)[i];
- if (strncmp("CP", RSTRING_PTR(name), 2) == 0) {
- int code_page = atoi(RSTRING_PTR(name) + 2);
- if (code_page != 0) {
- rb_hash_aset(rb_code_page, name_key, INT2FIX(code_page));
- return (UINT)code_page;
- }
- }
- }
- }
-
- rb_hash_aset(rb_code_page, name_key, INT2FIX(INVALID_CODE_PAGE));
return INVALID_CODE_PAGE;
}
-static inline VALUE
-fix_string_encoding(VALUE str, rb_encoding *encoding)
-{
- VALUE result, tmp;
-
- tmp = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), encoding);
- result = rb_str_encode(tmp, rb_enc_from_encoding(rb_utf8_encoding()), 0, Qnil);
-
- return result;
-}
+#define fix_string_encoding(str, encoding) rb_str_conv_enc((str), (encoding), rb_utf8_encoding())
/*
Replace the last part of the path to long name.
@@ -317,13 +293,45 @@ replace_to_long_name(wchar_t **wfullpath, size_t size, int heap)
return size;
}
+static inline VALUE
+get_user_from_path(wchar_t **wpath, int offset, UINT cp, UINT path_cp, rb_encoding *path_encoding)
+{
+ VALUE result, tmp;
+ wchar_t *wuser = *wpath + offset;
+ wchar_t *pos = wuser;
+ char *user;
+ size_t size;
+
+ while (!IS_DIR_SEPARATOR_P(*pos) && *pos != '\0')
+ pos++;
+
+ *pos = '\0';
+ convert_wchar_to_mb(wuser, &user, &size, cp);
+
+ /* convert to VALUE and set the path encoding */
+ if (path_cp == INVALID_CODE_PAGE) {
+ tmp = rb_enc_str_new(user, size, rb_utf8_encoding());
+ result = rb_str_encode(tmp, rb_enc_from_encoding(path_encoding), 0, Qnil);
+ rb_str_resize(tmp, 0);
+ }
+ else {
+ result = rb_enc_str_new(user, size, path_encoding);
+ }
+
+ if (user)
+ xfree(user);
+
+ return result;
+}
+
VALUE
rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_name, VALUE result)
{
size_t size = 0, wpath_len = 0, wdir_len = 0, whome_len = 0;
size_t buffer_len = 0;
char *fullpath = NULL;
- wchar_t *wfullpath = NULL, *wpath = NULL, *wpath_pos = NULL, *wdir = NULL;
+ wchar_t *wfullpath = NULL, *wpath = NULL, *wpath_pos = NULL;
+ wchar_t *wdir = NULL, *wdir_pos = NULL;
wchar_t *whome = NULL, *buffer = NULL, *buffer_pos = NULL;
UINT path_cp, cp;
VALUE path = fname, dir = dname;
@@ -355,7 +363,10 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
/* convert char * to wchar_t */
- convert_mb_to_wchar(path, &wpath, &wpath_pos, &wpath_len, cp);
+ if (!NIL_P(path)) {
+ convert_mb_to_wchar(RSTRING_PTR(path), &wpath, &wpath_len, cp);
+ wpath_pos = wpath;
+ }
/* determine if we need the user's home directory */
/* expand '~' only if NOT rb_file_absolute_path() where `abs_mode` is 1 */
@@ -373,14 +384,17 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
if (PathIsRelativeW(whome) && !(whome_len >= 2 && IS_DIR_UNC_P(whome))) {
xfree(wpath);
+ xfree(whome);
rb_raise(rb_eArgError, "non-absolute home");
}
- /* use filesystem encoding if expanding home dir */
- path_encoding = rb_filesystem_encoding();
- cp = path_cp = system_code_page();
+ if (path_cp == INVALID_CODE_PAGE || rb_enc_str_asciionly_p(path)) {
+ /* use filesystem encoding if expanding home dir */
+ path_encoding = rb_filesystem_encoding();
+ cp = path_cp = system_code_page();
+ }
- /* ignores dir since we are expading home */
+ /* ignores dir since we are expanding home */
ignore_dir = 1;
/* exclude ~ from the result */
@@ -404,32 +418,10 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
}
else if (abs_mode == 0 && wpath_len >= 2 && wpath_pos[0] == L'~') {
- wchar_t *wuser = wpath_pos + 1;
- wchar_t *pos = wuser;
- char *user;
-
- /* tainted if expanding '~' */
- tainted = 1;
-
- while (!IS_DIR_SEPARATOR_P(*pos) && *pos != '\0')
- pos++;
-
- *pos = '\0';
- convert_wchar_to_mb(wuser, &user, &size, cp);
+ result = get_user_from_path(&wpath_pos, 1, cp, path_cp, path_encoding);
- /* convert to VALUE and set the path encoding */
- if (path_cp == INVALID_CODE_PAGE) {
- VALUE tmp = rb_enc_str_new(user, size, rb_utf8_encoding());
- result = rb_str_encode(tmp, rb_enc_from_encoding(path_encoding), 0, Qnil);
- rb_str_resize(tmp, 0);
- }
- else {
- result = rb_enc_str_new(user, size, path_encoding);
- }
-
- xfree(wpath);
- if (user)
- xfree(user);
+ if (wpath)
+ xfree(wpath);
rb_raise(rb_eArgError, "can't find user %s", StringValuePtr(result));
}
@@ -442,9 +434,42 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
/* convert char * to wchar_t */
- convert_mb_to_wchar(dir, &wdir, NULL, &wdir_len, cp);
+ if (!NIL_P(dir)) {
+ convert_mb_to_wchar(RSTRING_PTR(dir), &wdir, &wdir_len, cp);
+ wdir_pos = wdir;
+ }
+
+ if (abs_mode == 0 && wdir_len > 0 && wdir_pos[0] == L'~' &&
+ (wdir_len == 1 || IS_DIR_SEPARATOR_P(wdir_pos[1]))) {
+ /* tainted if expanding '~' */
+ tainted = 1;
+
+ whome = home_dir();
+ if (whome == NULL) {
+ xfree(wpath);
+ xfree(wdir);
+ rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
+ }
+ whome_len = wcslen(whome);
+
+ if (PathIsRelativeW(whome) && !(whome_len >= 2 && IS_DIR_UNC_P(whome))) {
+ xfree(wpath);
+ xfree(wdir);
+ xfree(whome);
+ rb_raise(rb_eArgError, "non-absolute home");
+ }
+
+ /* exclude ~ from the result */
+ wdir_pos++;
+ wdir_len--;
- if (wdir_len >= 2 && wdir[1] == L':') {
+ /* exclude separator if present */
+ if (wdir_len && IS_DIR_SEPARATOR_P(wdir_pos[0])) {
+ wdir_pos++;
+ wdir_len--;
+ }
+ }
+ else if (wdir_len >= 2 && wdir[1] == L':') {
dir_drive = wdir[0];
if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) {
wdir_len = 2;
@@ -466,6 +491,16 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
wdir_len = pos - 1;
}
}
+ else if (abs_mode == 0 && wdir_len >= 2 && wdir_pos[0] == L'~') {
+ result = get_user_from_path(&wdir_pos, 1, cp, path_cp, path_encoding);
+ if (wpath)
+ xfree(wpath);
+
+ if (wdir)
+ xfree(wdir);
+
+ rb_raise(rb_eArgError, "can't find user %s", StringValuePtr(result));
+ }
}
/* determine if we ignore dir or not */
@@ -515,7 +550,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
if (!tainted && OBJ_TAINTED(dir))
tainted = 1;
- wcsncpy(buffer_pos, wdir, wdir_len);
+ wcsncpy(buffer_pos, wdir_pos, wdir_len);
buffer_pos += wdir_len;
}
@@ -636,16 +671,22 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
int
rb_file_load_ok(const char *path)
{
+ DWORD attr;
int ret = 1;
- DWORD attr = GetFileAttributes(path);
+ size_t len;
+ wchar_t* wpath;
+
+ convert_mb_to_wchar(path, &wpath, &len, CP_UTF8);
+
+ attr = GetFileAttributesW(wpath);
if (attr == INVALID_FILE_ATTRIBUTES ||
- attr & FILE_ATTRIBUTE_DIRECTORY) {
+ (attr & FILE_ATTRIBUTE_DIRECTORY)) {
ret = 0;
}
else {
- HANDLE h = CreateFile(path, GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ HANDLE h = CreateFileW(wpath, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h != INVALID_HANDLE_VALUE) {
CloseHandle(h);
}
@@ -653,14 +694,13 @@ rb_file_load_ok(const char *path)
ret = 0;
}
}
+ xfree(wpath);
return ret;
}
void
-rb_w32_init_file(void)
+Init_w32_codepage(void)
{
- rb_code_page = rb_hash_new();
-
- /* prevent GC removing rb_code_page */
- rb_gc_register_mark_object(rb_code_page);
+ if (rb_code_page.count) return;
+ rb_enc_foreach_name(code_page_i, (st_data_t)&rb_code_page);
}
diff --git a/win32/ifchange.bat b/win32/ifchange.bat
index 24e4987c55..ed10914953 100755
--- a/win32/ifchange.bat
+++ b/win32/ifchange.bat
@@ -2,6 +2,8 @@
:: usage: ifchange target temporary
set timestamp=
+set keepsuffix=
+set empty=
:optloop
for %%I in (%1) do set opt=%%~I
if "%opt%" == "--timestamp" (
@@ -12,6 +14,18 @@ if "%opt%" == "--timestamp" (
set timestamp=%opt:~12%
shift
goto :optloop
+) else if "%opt%" == "--keep" (
+ set keepsuffix=.old
+ shift
+ goto :optloop
+) else if "%opt:~0,7%" == "--keep=" (
+ set keepsuffix=%opt:~7%
+ shift
+ goto :optloop
+) else if "%opt%" == "--empty" (
+ set empty=yes
+ shift
+ goto :optloop
)
if "%opt%" == "" goto :end
@@ -51,20 +65,24 @@ echo assuming %1 should be changed.
echo %1 updated.
:: if exist %1 del %1
dir /b %2
+if "%keepsuffix%" != "" %1 %1%keepsuffix%
copy %2 %1
del %2
goto :end
:nt
-if not exist %src% goto :end
if exist %dest% (
+ if not exist %src% goto :nt_unchanged1
+ if "%empty%" == "" for %%I in (%src%) do if %%~zI == 0 goto :nt_unchanged
fc.exe %dest% %src% > nul && (
- echo %1 unchanged.
+ :nt_unchanged
del %src%
+ :nt_unchanged1
+ for %%I in (%1) do echo %%~I unchanged
goto :nt_end
)
)
-echo %1 updated.
+for %%I in (%1) do echo %%~I updated
copy %src% %dest% > nul
del %src%
diff --git a/win32/rm.bat b/win32/rm.bat
index 5b4f632d63..949644111b 100755
--- a/win32/rm.bat
+++ b/win32/rm.bat
@@ -1,12 +1,12 @@
@echo off
:optloop
if "%1" == "-f" shift
-if "%1" == "-r" (set recursive=1 & goto :optloop)
+if "%1" == "-r" (shift & set recursive=1 & goto :optloop)
if "%recursive%" == "1" goto :recursive
:begin
if "%1" == "" goto :end
set p=%1
-if exist "%p:/=\%" del "%p:/=\%"
+if exist "%p:/=\%" for %%I in ("%p:/=\%") do @del "%%I"
shift
goto :begin
:recursive
diff --git a/win32/rtname.cmd b/win32/rtname.cmd
new file mode 100644
index 0000000000..1f410a02db
--- /dev/null
+++ b/win32/rtname.cmd
@@ -0,0 +1,18 @@
+@echo off
+set rt=
+set rtver=
+set osver=
+for /f "usebackq" %%I in (`dumpbin -dependents %1 ^| findstr -r -i "\<msvcr.*\.dll$"`) do set rt=%%~nI
+if "%rt%" == "" (
+ (echo %0: %1 is not linked to msvcrt) 1>&2
+ exit 1
+)
+for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do @call set rt=%%rt:%%i=%%i%%
+if "%rt%" == "msvcrt" (
+ call set rtver=60
+) else (
+ call set rtver=%%rt:msvcr=%%
+ call set rt=msvcr%%rtver%%
+ call set osver=_%%rtver%%
+)
+for %%I in ("PLATFORM = $(TARGET_OS)%osver%" "RT = %rt%" "RT_VER = %rtver%") do @echo %%~I
diff --git a/win32/setup.mak b/win32/setup.mak
index d986a64349..458212bb7b 100644
--- a/win32/setup.mak
+++ b/win32/setup.mak
@@ -70,89 +70,44 @@ USE_RUBYGEMS = $(USE_RUBYGEMS)
@echo !endif>> $(MAKEFILE)
!endif
--system-vars-: -runtime-
+-system-vars-: -osname- -runtime- -headers-
--system-vars32-: -osname32- -runtime-
+-system-vars32-: -osname32- -runtime- -headers-
--system-vars64-: -osname64- -runtime-
+-system-vars64-: -osname64- -runtime- -headers-
-osname32-: nul
- @echo TARGET_OS = mswin32 >>$(MAKEFILE)
+ @echo TARGET_OS = mswin32>>$(MAKEFILE)
-osname64-: nul
- @echo TARGET_OS = mswin64 >>$(MAKEFILE)
+ @echo TARGET_OS = mswin64>>$(MAKEFILE)
--runtime-: nul
- @$(CC) -MD <<rtname.c user32.lib -link > nul
-#include <windows.h>
-#include <memory.h>
-#include <string.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef MAXPATHLEN
-# define MAXPATHLEN 1024
+-osname-: nul
+ @echo !ifndef TARGET_OS>>$(MAKEFILE)
+ @($(CC) -c <<conftest.c > nul && (echo TARGET_OS = mswin32) || (echo TARGET_OS = mswin64)) >>$(MAKEFILE)
+#ifdef _WIN64
+#error
#endif
+<<
+ @echo !endif>>$(MAKEFILE)
+ @$(WIN32DIR:/=\)\rm.bat conftest.*
-int
-runtime_name()
-{
- char libpath[MAXPATHLEN+1];
- char *p, *base = NULL, *ver = NULL;
- HMODULE msvcrt = NULL;
- MEMORY_BASIC_INFORMATION m;
-
- memset(&m, 0, sizeof(m));
- if (VirtualQuery(stdin, &m, sizeof(m)) && m.State == MEM_COMMIT)
- msvcrt = (HMODULE)m.AllocationBase;
- GetModuleFileName(msvcrt, libpath, sizeof libpath);
+-runtime-: nul
+ @$(CC) -MD <<conftest.c user32.lib -link > nul
+#include <stdio.h>
+int main(void) {FILE *volatile f = stdin; return 0;}
+<<
+ @$(WIN32DIR:/=\)\rtname conftest.exe >>$(MAKEFILE)
+ @$(WIN32DIR:/=\)\rm.bat conftest.*
- libpath[sizeof(libpath) - 1] = '\0';
- for (p = libpath; *p; p = CharNext(p)) {
- if (*p == '\\') {
- base = ++p;
- }
- }
- if (!base) return 0;
- if (p = strchr(base, '.')) *p = '\0';
- for (p = base; *p; p = CharNext(p)) {
- if (!isascii(*p)) continue;
- if (isupper(*p)) {
- *p = tolower(*p);
- }
- if (!isdigit(*p)) {
- ver = NULL;
- } else if (!ver) {
- ver = p;
- }
- }
- printf("!ifndef TARGET_OS\n");
-#ifdef _WIN64
- printf("TARGET_OS = mswin64\n");
-#else
- printf("TARGET_OS = mswin32\n");
-#endif
- printf("!endif\n");
- if (ver) {
- printf("PLATFORM = $$(TARGET_OS)_%s\n", ver);
- }
- else {
- printf("PLATFORM = $$(TARGET_OS)\n");
- ver = "60";
- }
- printf("RT = %s\n", base);
- printf("RT_VER = %s\n", ver);
- return 1;
-}
+-headers-: nul
-int main(int argc, char **argv)
-{
- if (!runtime_name()) return EXIT_FAILURE;
- return EXIT_SUCCESS;
-}
+check-psapi.h: nul
+ ($(CC) -MD <<conftest.c psapi.lib -link && echo>>$(MAKEFILE) HAVE_PSAPI_H=1) & $(WIN32DIR:/=\)\rm.bat conftest.*
+#include <windows.h>
+#include <psapi.h>
+int main(void) {return (EnumProcesses(NULL,0,NULL) ? 0 : 1);}
<<
- @.\rtname >>$(MAKEFILE)
- @del rtname.*
-version-: nul
@$(APPEND)
@@ -247,7 +202,7 @@ $(CPU) = $(PROCESSOR_LEVEL)
# CPPFLAGS = -I. -I$$(srcdir) -I$$(srcdir)/missing -DLIBRUBY_SO=\"$$(LIBRUBY_SO)\"
# STACK = 0x2000000
# LDFLAGS = $$(CFLAGS) -Fm
-# XLDFLAGS =
+# XLDFLAGS =
# RFLAGS = -r
# EXTLIBS =
diff --git a/win32/win32.c b/win32/win32.c
index 3b827662a7..9cbd07f669 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -19,9 +19,10 @@
Copyright (C) 2000 Information-technology Promotion Agency, Japan
*/
+#undef __STRICT_ANSI__
+
#include "ruby/ruby.h"
#include "ruby/encoding.h"
-#include "dln.h"
#include <fcntl.h>
#include <process.h>
#include <sys/stat.h>
@@ -38,6 +39,7 @@
#include <share.h>
#include <shlobj.h>
#include <mbstring.h>
+#include <shlwapi.h>
#if _MSC_VER >= 1400
#include <crtdbg.h>
#include <rtcapi.h>
@@ -47,12 +49,37 @@
#endif
#include "ruby/win32.h"
#include "win32/dir.h"
+#include "internal.h"
#define isdirsep(x) ((x) == '/' || (x) == '\\')
+#if defined _MSC_VER && _MSC_VER <= 1200
+# define CharNextExA(cp, p, flags) CharNextExA((WORD)(cp), (p), (flags))
+#endif
+
+static int w32_stati64(const char *path, struct stati64 *st, UINT cp);
+static char *w32_getenv(const char *name, UINT cp);
+
+#undef getenv
+#define DLN_FIND_EXTRA_ARG_DECL ,UINT cp
+#define DLN_FIND_EXTRA_ARG ,cp
+#define rb_w32_stati64(path, st) w32_stati64(path, st, cp)
+#define getenv(name) w32_getenv(name, cp)
+#define dln_find_exe_r rb_w32_udln_find_exe_r
+#define dln_find_file_r rb_w32_udln_find_file_r
+#include "dln.h"
+#include "dln_find.c"
+#undef MAXPATHLEN
+#undef rb_w32_stati64
+#undef dln_find_exe_r
+#undef dln_find_file_r
+#define dln_find_exe_r(fname, path, buf, size) rb_w32_udln_find_exe_r(fname, path, buf, size, cp)
+#define dln_find_file_r(fname, path, buf, size) rb_w32_udln_find_file_r(fname, path, buf, size, cp)
+
#undef stat
#undef fclose
#undef close
#undef setsockopt
+#undef dup2
#if defined __BORLANDC__
# define _filbuf _fgetc
@@ -73,7 +100,7 @@
#define TO_SOCKET(x) _get_osfhandle(x)
static struct ChildRecord *CreateChild(const WCHAR *, const WCHAR *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE, DWORD);
-static int has_redirection(const char *);
+static int has_redirection(const char *, UINT);
int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout);
static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags);
static int wstati64(const WCHAR *path, struct stati64 *st);
@@ -353,12 +380,12 @@ translate_wchar(WCHAR *p, int from, int to)
/* License: Ruby's */
static inline char *
-translate_char(char *p, int from, int to)
+translate_char(char *p, int from, int to, UINT cp)
{
while (*p) {
if ((unsigned char)*p == from)
*p = to;
- p = CharNext(p);
+ p = CharNextExA(cp, p, 0);
}
return p;
}
@@ -442,8 +469,6 @@ get_system_directory(WCHAR *path, UINT len)
return GetWindowsDirectoryW(path, len);
}
-#define numberof(array) (sizeof(array) / sizeof(*array))
-
/* License: Ruby's */
VALUE
rb_w32_special_folder(int type)
@@ -467,9 +492,9 @@ rb_w32_system_tmpdir(WCHAR *path, UINT len)
}
p = translate_wchar(path, L'\\', L'/');
if (*(p - 1) != L'/') *p++ = L'/';
- if (p - path + numberof(temp) >= len) return 0;
+ if ((UINT)(p - path + numberof(temp)) >= len) return 0;
memcpy(p, temp, sizeof(temp));
- return p - path + numberof(temp) - 1;
+ return (UINT)(p - path + numberof(temp) - 1);
}
/* License: Ruby's */
@@ -482,8 +507,8 @@ init_env(void)
BOOL f;
#define env wk.val
#define set_env_val(vname) do { \
- typedef char namesizecheck[numberof(wk.name) < numberof(vname) - 1 ? -1 : 1]; \
- WCHAR *const buf = wk.name + numberof(wk.name) - numberof(vname) + 1; \
+ typedef char wk_name_offset[(numberof(wk.name) - (numberof(vname) - 1)) * 2 + 1]; \
+ WCHAR *const buf = wk.name + sizeof(wk_name_offset) / 2; \
MEMCPY(buf, vname, WCHAR, numberof(vname) - 1); \
_wputenv(buf); \
} while (0)
@@ -581,6 +606,7 @@ static CRITICAL_SECTION select_mutex;
static int NtSocketsInitialized = 0;
static st_table *socklist = NULL;
static st_table *conlist = NULL;
+#define conlist_disabled ((st_table *)-1)
static char *envarea;
static char *uenvarea;
@@ -606,7 +632,7 @@ free_conlist(st_data_t key, st_data_t val, st_data_t arg)
static void
constat_delete(HANDLE h)
{
- if (conlist) {
+ if (conlist && conlist != conlist_disabled) {
st_data_t key = (st_data_t)h, val;
st_delete(conlist, &key, &val);
xfree((struct constat *)val);
@@ -626,7 +652,7 @@ exit_handler(void)
DeleteCriticalSection(&select_mutex);
NtSocketsInitialized = 0;
}
- if (conlist) {
+ if (conlist && conlist != conlist_disabled) {
st_foreach(conlist, free_conlist, 0);
st_free_table(conlist);
conlist = NULL;
@@ -649,7 +675,7 @@ StartSockets(void)
WSADATA retdata;
//
- // initalize the winsock interface and insure that it's
+ // initialize the winsock interface and insure that it's
// cleaned up at exit.
//
version = MAKEWORD(2, 0);
@@ -962,7 +988,7 @@ rb_w32_get_osfhandle(int fh)
/* License: Ruby's */
static int
-join_argv(char *cmd, char *const *argv, BOOL escape)
+join_argv(char *cmd, char *const *argv, BOOL escape, UINT cp, int backslash)
{
const char *p, *s;
char *q, *const *t;
@@ -1008,7 +1034,7 @@ join_argv(char *cmd, char *const *argv, BOOL escape)
}
default:
bs = 0;
- p = CharNext(p) - 1;
+ p = CharNextExA(cp, p, 0) - 1;
break;
}
}
@@ -1016,6 +1042,11 @@ join_argv(char *cmd, char *const *argv, BOOL escape)
if (quote) len++;
if (q) {
memcpy(q, s, n);
+ if (backslash > 0) {
+ --backslash;
+ q[n] = 0;
+ translate_char(q, '/', '\\', cp);
+ }
q += n;
if (quote) *q++ = '"';
*q++ = ' ';
@@ -1176,16 +1207,19 @@ static char *wstr_to_mbstr(UINT, const WCHAR *, int, long *);
#define wstr_to_utf8(str, plen) wstr_to_mbstr(CP_UTF8, str, -1, plen)
/* License: Artistic or GPL */
-rb_pid_t
-rb_w32_spawn(int mode, const char *cmd, const char *prog)
+static rb_pid_t
+w32_spawn(int mode, const char *cmd, const char *prog, UINT cp)
{
char fbuf[MAXPATHLEN];
char *p = NULL;
const char *shell = NULL;
- WCHAR *wcmd, *wshell;
- rb_pid_t ret;
+ WCHAR *wcmd = NULL, *wshell = NULL;
+ int e = 0;
+ rb_pid_t ret = -1;
VALUE v = 0;
VALUE v2 = 0;
+ int sep = 0;
+ char *cmd_sep = NULL;
if (check_spawn_mode(mode)) return -1;
@@ -1195,21 +1229,24 @@ rb_w32_spawn(int mode, const char *cmd, const char *prog)
}
else {
shell = p;
- translate_char(p, '/', '\\');
+ translate_char(p, '/', '\\', cp);
}
}
else {
int redir = -1;
int nt;
while (ISSPACE(*cmd)) cmd++;
- if ((shell = getenv("RUBYSHELL")) && (redir = has_redirection(cmd))) {
- char *tmp = ALLOCV(v, strlen(shell) + strlen(cmd) + sizeof(" -c ") + 2);
- sprintf(tmp, "%s -c \"%s\"", shell, cmd);
+ if ((shell = getenv("RUBYSHELL")) && (redir = has_redirection(cmd, cp))) {
+ size_t shell_len = strlen(shell);
+ char *tmp = ALLOCV(v, shell_len + strlen(cmd) + sizeof(" -c ") + 2);
+ memcpy(tmp, shell, shell_len + 1);
+ translate_char(tmp, '/', '\\', cp);
+ sprintf(tmp + shell_len, " -c \"%s\"", cmd);
cmd = tmp;
}
else if ((shell = getenv("COMSPEC")) &&
(nt = !is_command_com(shell),
- (redir < 0 ? has_redirection(cmd) : redir) ||
+ (redir < 0 ? has_redirection(cmd, cp) : redir) ||
is_internal_cmd(cmd, nt))) {
char *tmp = ALLOCV(v, strlen(shell) + strlen(cmd) + sizeof(" /c ") + (nt ? 2 : 0));
sprintf(tmp, nt ? "%s /c \"%s\"" : "%s /c %s", shell, cmd);
@@ -1217,9 +1254,15 @@ rb_w32_spawn(int mode, const char *cmd, const char *prog)
}
else {
int len = 0, quote = (*cmd == '"') ? '"' : (*cmd == '\'') ? '\'' : 0;
- for (prog = cmd + !!quote;; prog = CharNext(prog)) {
+ int slash = 0;
+ for (prog = cmd + !!quote;; prog = CharNextExA(cp, prog, 0)) {
+ if (*prog == '/') slash = 1;
if (!*prog) {
len = prog - cmd;
+ if (slash) {
+ STRNDUPV(p, v2, cmd, len);
+ cmd = p;
+ }
shell = cmd;
break;
}
@@ -1232,12 +1275,18 @@ rb_w32_spawn(int mode, const char *cmd, const char *prog)
if (quote) continue;
if (ISSPACE(*prog) || strchr("<>|*?\"", *prog)) {
len = prog - cmd;
- STRNDUPV(p, v2, cmd, len);
+ STRNDUPV(p, v2, cmd, len + (slash ? strlen(prog) : 0));
+ if (slash) {
+ cmd = p;
+ sep = *(cmd_sep = &p[len]);
+ *cmd_sep = '\0';
+ }
shell = p;
break;
}
}
shell = dln_find_exe_r(shell, NULL, fbuf, sizeof(fbuf));
+ if (p && slash) translate_char(p, '/', '\\', cp);
if (!shell) {
shell = p ? p : cmd;
}
@@ -1251,7 +1300,7 @@ rb_w32_spawn(int mode, const char *cmd, const char *prog)
STRNDUPV(p, v2, shell, len);
shell = p;
}
- if (p) translate_char(p, '/', '\\');
+ if (p) translate_char(p, '/', '\\', cp);
if (is_batch(shell)) {
int alen = strlen(prog);
cmd = p = ALLOCV(v, len + alen + (quote ? 2 : 0) + 1);
@@ -1266,29 +1315,48 @@ rb_w32_spawn(int mode, const char *cmd, const char *prog)
}
}
- /* assume ACP */
- wcmd = cmd ? acp_to_wstr(cmd, NULL) : NULL;
- if (v) ALLOCV_END(v);
- wshell = shell ? acp_to_wstr(shell, NULL) : NULL;
+ if (!e && shell && !(wshell = mbstr_to_wstr(cp, shell, -1, NULL))) e = E2BIG;
if (v2) ALLOCV_END(v2);
+ if (cmd_sep) *cmd_sep = sep;
+ if (!e && cmd && !(wcmd = mbstr_to_wstr(cp, cmd, -1, NULL))) e = E2BIG;
+ if (v) ALLOCV_END(v);
- ret = child_result(CreateChild(wcmd, wshell, NULL, NULL, NULL, NULL, 0), mode);
+ if (!e) {
+ ret = child_result(CreateChild(wcmd, wshell, NULL, NULL, NULL, NULL, 0), mode);
+ }
free(wshell);
free(wcmd);
+ if (e) errno = e;
return ret;
}
-/* License: Artistic or GPL */
+/* License: Ruby's */
rb_pid_t
-rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
+rb_w32_spawn(int mode, const char *cmd, const char *prog)
+{
+ /* assume ACP */
+ return w32_spawn(mode, cmd, prog, filecp());
+}
+
+/* License: Ruby's */
+rb_pid_t
+rb_w32_uspawn(int mode, const char *cmd, const char *prog)
+{
+ return w32_spawn(mode, cmd, prog, CP_UTF8);
+}
+
+/* License: Artistic or GPL */
+static rb_pid_t
+w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags, UINT cp)
{
int c_switch = 0;
size_t len;
BOOL ntcmd = FALSE, tmpnt;
const char *shell;
char *cmd, fbuf[MAXPATHLEN];
- WCHAR *wcmd, *wprog;
- rb_pid_t ret;
+ WCHAR *wcmd = NULL, *wprog = NULL;
+ int e = 0;
+ rb_pid_t ret = -1;
VALUE v = 0;
if (check_spawn_mode(mode)) return -1;
@@ -1302,7 +1370,7 @@ rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
}
else if ((cmd = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
if (cmd == prog) strlcpy(cmd = fbuf, prog, sizeof(fbuf));
- translate_char(cmd, '/', '\\');
+ translate_char(cmd, '/', '\\', cp);
prog = cmd;
}
else if (strchr(prog, '/')) {
@@ -1311,46 +1379,71 @@ rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
strlcpy(cmd = fbuf, prog, sizeof(fbuf));
else
STRNDUPV(cmd, v, prog, len);
- translate_char(cmd, '/', '\\');
+ translate_char(cmd, '/', '\\', cp);
prog = cmd;
}
if (c_switch || is_batch(prog)) {
char *progs[2];
progs[0] = (char *)prog;
progs[1] = NULL;
- len = join_argv(NULL, progs, ntcmd);
+ len = join_argv(NULL, progs, ntcmd, cp, 1);
if (c_switch) len += 3;
else ++argv;
- if (argv[0]) len += join_argv(NULL, argv, ntcmd);
+ if (argv[0]) len += join_argv(NULL, argv, ntcmd, cp, 0);
cmd = ALLOCV(v, len);
- join_argv(cmd, progs, ntcmd);
+ join_argv(cmd, progs, ntcmd, cp, 1);
if (c_switch) strlcat(cmd, " /c", len);
- if (argv[0]) join_argv(cmd + strlcat(cmd, " ", len), argv, ntcmd);
+ if (argv[0]) join_argv(cmd + strlcat(cmd, " ", len), argv, ntcmd, cp, 0);
prog = c_switch ? shell : 0;
}
else {
- len = join_argv(NULL, argv, FALSE);
+ len = join_argv(NULL, argv, FALSE, cp, 1);
cmd = ALLOCV(v, len);
- join_argv(cmd, argv, FALSE);
+ join_argv(cmd, argv, FALSE, cp, 1);
}
- /* assume ACP */
- wcmd = cmd ? acp_to_wstr(cmd, NULL) : NULL;
+ if (!e && cmd && !(wcmd = mbstr_to_wstr(cp, cmd, -1, NULL))) e = E2BIG;
if (v) ALLOCV_END(v);
- wprog = prog ? acp_to_wstr(prog, NULL) : NULL;
+ if (!e && prog && !(wprog = mbstr_to_wstr(cp, prog, -1, NULL))) e = E2BIG;
- ret = child_result(CreateChild(wcmd, wprog, NULL, NULL, NULL, NULL, flags), mode);
+ if (!e) {
+ ret = child_result(CreateChild(wcmd, wprog, NULL, NULL, NULL, NULL, flags), mode);
+ }
free(wprog);
free(wcmd);
+ if (e) errno = e;
return ret;
}
+/* License: Ruby's */
+rb_pid_t
+rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
+{
+ /* assume ACP */
+ return w32_aspawn_flags(mode, prog, argv, flags, filecp());
+}
+
+/* License: Ruby's */
+rb_pid_t
+rb_w32_uaspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
+{
+ return w32_aspawn_flags(mode, prog, argv, flags, CP_UTF8);
+}
+
+/* License: Ruby's */
rb_pid_t
rb_w32_aspawn(int mode, const char *prog, char *const *argv)
{
return rb_w32_aspawn_flags(mode, prog, argv, 0);
}
+/* License: Ruby's */
+rb_pid_t
+rb_w32_uaspawn(int mode, const char *prog, char *const *argv)
+{
+ return rb_w32_uaspawn_flags(mode, prog, argv, 0);
+}
+
/* License: Artistic or GPL */
typedef struct _NtCmdLineElement {
struct _NtCmdLineElement *next;
@@ -1422,7 +1515,7 @@ cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail)
/* License: Artistic or GPL */
static int
-has_redirection(const char *cmd)
+has_redirection(const char *cmd, UINT cp)
{
char quote = '\0';
const char *ptr;
@@ -1462,7 +1555,7 @@ has_redirection(const char *cmd)
case '\\':
ptr++;
default:
- ptr = CharNext(ptr);
+ ptr = CharNextExA(cp, ptr, 0);
break;
}
}
@@ -1509,8 +1602,8 @@ rb_w32_cmdvector(const char *cmd, char ***vec)
// When we've finished, and it's an input command (meaning that it's
// the processes argv), we'll do globing and then build the argument
// vector.
- // The outer loop does one interation for each element seen.
- // The inner loop does one interation for each character in the element.
+ // The outer loop does one iteration for each element seen.
+ // The inner loop does one iteration for each character in the element.
//
while (*(ptr = skipspace(ptr))) {
@@ -1561,7 +1654,7 @@ rb_w32_cmdvector(const char *cmd, char ***vec)
//
// if we're already in a string, see if this is the
// terminating close-quote. If it is, we're finished with
- // the string, but not neccessarily with the element.
+ // the string, but not necessarily with the element.
// If we're not already in a string, start one.
//
@@ -1717,8 +1810,6 @@ rb_w32_cmdvector(const char *cmd, char ***vec)
// UNIX compatible directory access functions for NT
//
-#define PATHLEN 1024
-
//
// The idea here is to read all the directory names into a string table
// (separated by nulls) and when one of the other dir functions is called
@@ -1865,10 +1956,14 @@ static char *
wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen)
{
char *ptr;
- int len = WideCharToMultiByte(cp, 0, wstr, clen, NULL, 0, NULL, NULL) - 1;
- if (!(ptr = malloc(len + 1))) return 0;
- WideCharToMultiByte(cp, 0, wstr, clen, ptr, len + 1, NULL, NULL);
- if (plen) *plen = len;
+ int len = WideCharToMultiByte(cp, 0, wstr, clen, NULL, 0, NULL, NULL);
+ if (!(ptr = malloc(len))) return 0;
+ WideCharToMultiByte(cp, 0, wstr, clen, ptr, len, NULL, NULL);
+ if (plen) {
+ /* exclude NUL only if NUL-terminated string */
+ if (clen == -1) --len;
+ *plen = len;
+ }
return ptr;
}
@@ -1877,10 +1972,14 @@ static WCHAR *
mbstr_to_wstr(UINT cp, const char *str, int clen, long *plen)
{
WCHAR *ptr;
- int len = MultiByteToWideChar(cp, 0, str, clen, NULL, 0) - 1;
- if (!(ptr = malloc(sizeof(WCHAR) * (len + 1)))) return 0;
- MultiByteToWideChar(cp, 0, str, clen, ptr, len + 1);
- if (plen) *plen = len;
+ int len = MultiByteToWideChar(cp, 0, str, clen, NULL, 0);
+ if (!(ptr = malloc(sizeof(WCHAR) * len))) return 0;
+ MultiByteToWideChar(cp, 0, str, clen, ptr, len);
+ if (plen) {
+ /* exclude NUL only if NUL-terminated string */
+ if (clen == -1) --len;
+ *plen = len;
+ }
return ptr;
}
@@ -1944,20 +2043,31 @@ win32_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *dummy)
VALUE
rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
{
- static rb_encoding *utf16 = (rb_encoding *)-1;
VALUE src;
+ long len = lstrlenW(wstr);
+ int encindex = ENC_TO_ENCINDEX(enc);
- if (utf16 == (rb_encoding *)-1) {
- utf16 = rb_enc_find("UTF-16LE");
- if (utf16 == rb_ascii8bit_encoding())
- utf16 = NULL;
+ if (encindex == ENCINDEX_UTF_16LE) {
+ return rb_enc_str_new((char *)wstr, len * sizeof(WCHAR), enc);
}
- if (!utf16)
- /* maybe miniruby */
- return Qnil;
-
- src = rb_enc_str_new((char *)wstr, lstrlenW(wstr) * sizeof(WCHAR), utf16);
- return rb_str_encode(src, rb_enc_from_encoding(enc), ECONV_UNDEF_REPLACE, Qnil);
+ else {
+#if SIZEOF_INT < SIZEOF_LONG
+# error long should equal to int on Windows
+#endif
+ int clen = rb_long2int(len);
+ len = WideCharToMultiByte(CP_UTF8, 0, wstr, clen, NULL, 0, NULL, NULL);
+ src = rb_enc_str_new(0, len, rb_enc_from_index(ENCINDEX_UTF_8));
+ WideCharToMultiByte(CP_UTF8, 0, wstr, clen, RSTRING_PTR(src), len, NULL, NULL);
+ }
+ switch (encindex) {
+ case ENCINDEX_ASCII:
+ case ENCINDEX_US_ASCII:
+ /* assume UTF-8 */
+ case ENCINDEX_UTF_8:
+ /* do nothing */
+ return src;
+ }
+ return rb_str_conv_enc_opts(src, NULL, enc, ECONV_UNDEF_REPLACE, Qnil);
}
/* License: Ruby's */
@@ -2581,7 +2691,7 @@ is_not_socket(SOCKET sock)
/* License: Ruby's */
static int
-is_pipe(SOCKET sock) /* DONT call this for SOCKET! it clains it is PIPE. */
+is_pipe(SOCKET sock) /* DONT call this for SOCKET! it claims it is PIPE. */
{
int ret;
@@ -2659,7 +2769,7 @@ is_invalid_handle(SOCKET sock)
/* License: Artistic or GPL */
static int
do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
- struct timeval *timeout)
+ struct timeval *timeout)
{
int r = 0;
@@ -2803,10 +2913,8 @@ rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
{
struct timeval rest;
- struct timeval wait;
- struct timeval zero;
- wait.tv_sec = 0; wait.tv_usec = 10 * 1000; // 10ms
- zero.tv_sec = 0; zero.tv_usec = 0; // 0ms
+ const struct timeval wait = {0, 10 * 1000}; // 10ms
+ struct timeval zero = {0, 0}; // 0ms
for (;;) {
if (th && rb_w32_check_interrupt(th) != WAIT_TIMEOUT) {
r = -1;
@@ -2829,7 +2937,7 @@ rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
break;
}
else {
- struct timeval *dowait = &wait;
+ const struct timeval *dowait = &wait;
fd_set orig_rd;
fd_set orig_wr;
@@ -2855,7 +2963,7 @@ rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
if (!rb_w32_time_subtract(&rest, &now)) break;
if (compare(&rest, &wait) < 0) dowait = &rest;
}
- Sleep(dowait->tv_sec * 1000 + dowait->tv_usec / 1000);
+ Sleep(dowait->tv_sec * 1000 + (dowait->tv_usec + 999) / 1000);
}
}
}
@@ -3706,7 +3814,7 @@ socketpair_internal(int af, int type, int protocol, SOCKET *sv)
/* License: Ruby's */
int
-rb_w32_socketpair(int af, int type, int protocol, int *sv)
+socketpair(int af, int type, int protocol, int *sv)
{
SOCKET pair[2];
@@ -3730,6 +3838,152 @@ rb_w32_socketpair(int af, int type, int protocol, int *sv)
return 0;
}
+#if !defined(_MSC_VER) || _MSC_VER >= 1400
+/* License: Ruby's */
+static void
+str2guid(const char *str, GUID *guid)
+{
+#define hex2byte(str) \
+ ((isdigit(*(str)) ? *(str) - '0' : toupper(*(str)) - 'A' + 10) << 4 | (isdigit(*((str) + 1)) ? *((str) + 1) - '0' : toupper(*((str) + 1)) - 'A' + 10))
+ char *end;
+ int i;
+ if (*str == '{') str++;
+ guid->Data1 = (long)strtoul(str, &end, 16);
+ str += 9;
+ guid->Data2 = (unsigned short)strtoul(str, &end, 16);
+ str += 5;
+ guid->Data3 = (unsigned short)strtoul(str, &end, 16);
+ str += 5;
+ guid->Data4[0] = hex2byte(str);
+ str += 2;
+ guid->Data4[1] = hex2byte(str);
+ str += 3;
+ for (i = 0; i < 6; i++) {
+ guid->Data4[i + 2] = hex2byte(str);
+ str += 2;
+ }
+}
+
+/* License: Ruby's */
+#ifndef HAVE_TYPE_NET_LUID
+ typedef struct {
+ uint64_t Value;
+ struct {
+ uint64_t Reserved :24;
+ uint64_t NetLuidIndex :24;
+ uint64_t IfType :16;
+ } Info;
+ } NET_LUID;
+#endif
+typedef DWORD (WINAPI *cigl_t)(const GUID *, NET_LUID *);
+typedef DWORD (WINAPI *cilnA_t)(const NET_LUID *, char *, size_t);
+static cigl_t pConvertInterfaceGuidToLuid = NULL;
+static cilnA_t pConvertInterfaceLuidToNameA = NULL;
+
+int
+getifaddrs(struct ifaddrs **ifap)
+{
+ ULONG size = 0;
+ ULONG ret;
+ IP_ADAPTER_ADDRESSES *root, *addr;
+ struct ifaddrs *prev;
+
+ ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
+ if (ret != ERROR_BUFFER_OVERFLOW) {
+ errno = map_errno(ret);
+ return -1;
+ }
+ root = ruby_xmalloc(size);
+ ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, root, &size);
+ if (ret != ERROR_SUCCESS) {
+ errno = map_errno(ret);
+ ruby_xfree(root);
+ return -1;
+ }
+
+ if (!pConvertInterfaceGuidToLuid)
+ pConvertInterfaceGuidToLuid =
+ (cigl_t)get_proc_address("iphlpapi.dll",
+ "ConvertInterfaceGuidToLuid", NULL);
+ if (!pConvertInterfaceLuidToNameA)
+ pConvertInterfaceLuidToNameA =
+ (cilnA_t)get_proc_address("iphlpapi.dll",
+ "ConvertInterfaceLuidToNameA", NULL);
+
+ for (prev = NULL, addr = root; addr; addr = addr->Next) {
+ struct ifaddrs *ifa = ruby_xcalloc(1, sizeof(*ifa));
+ char name[IFNAMSIZ];
+ GUID guid;
+ NET_LUID luid;
+
+ if (prev)
+ prev->ifa_next = ifa;
+ else
+ *ifap = ifa;
+
+ str2guid(addr->AdapterName, &guid);
+ if (pConvertInterfaceGuidToLuid && pConvertInterfaceLuidToNameA &&
+ pConvertInterfaceGuidToLuid(&guid, &luid) == NO_ERROR &&
+ pConvertInterfaceLuidToNameA(&luid, name, sizeof(name)) == NO_ERROR) {
+ ifa->ifa_name = ruby_xmalloc(lstrlen(name) + 1);
+ lstrcpy(ifa->ifa_name, name);
+ }
+ else {
+ ifa->ifa_name = ruby_xmalloc(lstrlen(addr->AdapterName) + 1);
+ lstrcpy(ifa->ifa_name, addr->AdapterName);
+ }
+
+ if (addr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
+ ifa->ifa_flags |= IFF_LOOPBACK;
+ if (addr->OperStatus == IfOperStatusUp) {
+ ifa->ifa_flags |= IFF_UP;
+
+ if (addr->FirstUnicastAddress) {
+ IP_ADAPTER_UNICAST_ADDRESS *cur;
+ int added = 0;
+ for (cur = addr->FirstUnicastAddress; cur; cur = cur->Next) {
+ if (cur->Flags & IP_ADAPTER_ADDRESS_TRANSIENT ||
+ cur->DadState == IpDadStateDeprecated) {
+ continue;
+ }
+ if (added) {
+ prev = ifa;
+ ifa = ruby_xcalloc(1, sizeof(*ifa));
+ prev->ifa_next = ifa;
+ ifa->ifa_name =
+ ruby_xmalloc(lstrlen(prev->ifa_name) + 1);
+ lstrcpy(ifa->ifa_name, prev->ifa_name);
+ ifa->ifa_flags = prev->ifa_flags;
+ }
+ ifa->ifa_addr = ruby_xmalloc(cur->Address.iSockaddrLength);
+ memcpy(ifa->ifa_addr, cur->Address.lpSockaddr,
+ cur->Address.iSockaddrLength);
+ added = 1;
+ }
+ }
+ }
+
+ prev = ifa;
+ }
+
+ ruby_xfree(root);
+ return 0;
+}
+
+/* License: Ruby's */
+void
+freeifaddrs(struct ifaddrs *ifp)
+{
+ while (ifp) {
+ struct ifaddrs *next = ifp->ifa_next;
+ if (ifp->ifa_addr) ruby_xfree(ifp->ifa_addr);
+ if (ifp->ifa_name) ruby_xfree(ifp->ifa_name);
+ ruby_xfree(ifp);
+ ifp = next;
+ }
+}
+#endif
+
//
// Networking stubs
//
@@ -3878,16 +4132,19 @@ poll_child_status(struct ChildRecord *child, int *stat_loc)
DWORD err;
if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
- /* If an error occured, return immediatly. */
+ /* If an error occurred, return immediately. */
error_exit:
err = GetLastError();
- if (err == ERROR_INVALID_PARAMETER)
+ switch (err) {
+ case ERROR_INVALID_PARAMETER:
errno = ECHILD;
- else {
- if (GetLastError() == ERROR_INVALID_HANDLE)
- errno = EINVAL;
- else
- errno = map_errno(GetLastError());
+ break;
+ case ERROR_INVALID_HANDLE:
+ errno = EINVAL;
+ break;
+ default:
+ errno = map_errno(err);
+ break;
}
CloseChildHandle(child);
return -1;
@@ -3900,7 +4157,43 @@ poll_child_status(struct ChildRecord *child, int *stat_loc)
}
pid = child->pid;
CloseChildHandle(child);
- if (stat_loc) *stat_loc = exitcode << 8;
+ if (stat_loc) {
+ *stat_loc = exitcode << 8;
+ if (exitcode & 0xC0000000) {
+ static const struct {
+ DWORD status;
+ int sig;
+ } table[] = {
+ {STATUS_ACCESS_VIOLATION, SIGSEGV},
+ {STATUS_ILLEGAL_INSTRUCTION, SIGILL},
+ {STATUS_PRIVILEGED_INSTRUCTION, SIGILL},
+ {STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE},
+ {STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE},
+ {STATUS_FLOAT_INEXACT_RESULT, SIGFPE},
+ {STATUS_FLOAT_INVALID_OPERATION, SIGFPE},
+ {STATUS_FLOAT_OVERFLOW, SIGFPE},
+ {STATUS_FLOAT_STACK_CHECK, SIGFPE},
+ {STATUS_FLOAT_UNDERFLOW, SIGFPE},
+#ifdef STATUS_FLOAT_MULTIPLE_FAULTS
+ {STATUS_FLOAT_MULTIPLE_FAULTS, SIGFPE},
+#endif
+#ifdef STATUS_FLOAT_MULTIPLE_TRAPS
+ {STATUS_FLOAT_MULTIPLE_TRAPS, SIGFPE},
+#endif
+ {STATUS_CONTROL_C_EXIT, SIGINT},
+ };
+ int i;
+ for (i = 0; i < (int)numberof(table); i++) {
+ if (table[i].status == exitcode) {
+ *stat_loc |= table[i].sig;
+ break;
+ }
+ }
+ // if unknown status, assume SEGV
+ if (i >= (int)numberof(table))
+ *stat_loc |= SIGSEGV;
+ }
+ }
return pid;
}
return 0;
@@ -3956,6 +4249,7 @@ waitpid(rb_pid_t pid, int *stat_loc, int options)
}
else {
struct ChildRecord* child = FindChildSlot(pid);
+ int retried = 0;
if (!child) {
errno = ECHILD;
return -1;
@@ -3965,10 +4259,14 @@ waitpid(rb_pid_t pid, int *stat_loc, int options)
/* wait... */
if (rb_w32_wait_events_blocking(&child->hProcess, 1, timeout) != WAIT_OBJECT_0) {
/* still active */
- pid = 0;
- break;
+ if (options & WNOHANG) {
+ pid = 0;
+ break;
+ }
+ ++retried;
}
}
+ if (pid == -1 && retried) pid = 0;
}
return pid;
@@ -4001,7 +4299,7 @@ filetime_to_timeval(const FILETIME* ft, struct timeval *tv)
}
/* License: Ruby's */
-int _cdecl
+int __cdecl
gettimeofday(struct timeval *tv, struct timezone *tz)
{
FILETIME ft;
@@ -4013,6 +4311,72 @@ gettimeofday(struct timeval *tv, struct timezone *tz)
}
/* License: Ruby's */
+int
+clock_gettime(clockid_t clock_id, struct timespec *sp)
+{
+ switch (clock_id) {
+ case CLOCK_REALTIME:
+ {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ sp->tv_sec = tv.tv_sec;
+ sp->tv_nsec = tv.tv_usec * 1000;
+ return 0;
+ }
+ case CLOCK_MONOTONIC:
+ {
+ LARGE_INTEGER freq;
+ LARGE_INTEGER count;
+ if (!QueryPerformanceFrequency(&freq)) {
+ errno = map_errno(GetLastError());
+ return -1;
+ }
+ if (!QueryPerformanceCounter(&count)) {
+ errno = map_errno(GetLastError());
+ return -1;
+ }
+ sp->tv_sec = count.QuadPart / freq.QuadPart;
+ if (freq.QuadPart < 1000000000)
+ sp->tv_nsec = (count.QuadPart % freq.QuadPart) * 1000000000 / freq.QuadPart;
+ else
+ sp->tv_nsec = (long)((count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart));
+ return 0;
+ }
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/* License: Ruby's */
+int
+clock_getres(clockid_t clock_id, struct timespec *sp)
+{
+ switch (clock_id) {
+ case CLOCK_REALTIME:
+ {
+ sp->tv_sec = 0;
+ sp->tv_nsec = 1000;
+ return 0;
+ }
+ case CLOCK_MONOTONIC:
+ {
+ LARGE_INTEGER freq;
+ if (!QueryPerformanceFrequency(&freq)) {
+ errno = map_errno(GetLastError());
+ return -1;
+ }
+ sp->tv_sec = 0;
+ sp->tv_nsec = (long)(1000000000.0 / freq.QuadPart);
+ return 0;
+ }
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/* License: Ruby's */
char *
rb_w32_getcwd(char *buffer, int size)
{
@@ -4047,7 +4411,7 @@ rb_w32_getcwd(char *buffer, int size)
return NULL;
}
- translate_char(p, '\\', '/');
+ translate_char(p, '\\', '/', filecp());
return p;
}
@@ -4250,8 +4614,8 @@ wait(int *status)
}
/* License: Ruby's */
-char *
-rb_w32_ugetenv(const char *name)
+static char *
+w32_getenv(const char *name, UINT cp)
{
WCHAR *wenvarea, *wenv;
int len = strlen(name);
@@ -4275,7 +4639,7 @@ rb_w32_ugetenv(const char *name)
}
for (wenv = wenvarea, wlen = 1; *wenv; wenv += lstrlenW(wenv) + 1)
wlen += lstrlenW(wenv) + 1;
- uenvarea = wstr_to_mbstr(CP_UTF8, wenvarea, wlen, NULL);
+ uenvarea = wstr_to_mbstr(cp, wenvarea, wlen, NULL);
FreeEnvironmentStringsW(wenvarea);
if (!uenvarea)
return NULL;
@@ -4289,31 +4653,16 @@ rb_w32_ugetenv(const char *name)
/* License: Ruby's */
char *
-rb_w32_getenv(const char *name)
+rb_w32_ugetenv(const char *name)
{
- int len = strlen(name);
- char *env;
-
- if (len == 0) return NULL;
- if (uenvarea) {
- free(uenvarea);
- uenvarea = NULL;
- }
- if (envarea) {
- FreeEnvironmentStrings(envarea);
- envarea = NULL;
- }
- envarea = GetEnvironmentStrings();
- if (!envarea) {
- map_errno(GetLastError());
- return NULL;
- }
-
- for (env = envarea; *env; env += strlen(env) + 1)
- if (strncasecmp(env, name, len) == 0 && *(env + len) == '=')
- return env + len + 1;
+ return w32_getenv(name, CP_UTF8);
+}
- return NULL;
+/* License: Ruby's */
+char *
+rb_w32_getenv(const char *name)
+{
+ return w32_getenv(name, CP_ACP);
}
/* License: Artistic or GPL */
@@ -4336,18 +4685,9 @@ wrename(const WCHAR *oldpath, const WCHAR *newpath)
if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY)
SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
- if (!MoveFileW(oldpath, newpath))
+ if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
res = -1;
- if (res) {
- switch (GetLastError()) {
- case ERROR_ALREADY_EXISTS:
- case ERROR_FILE_EXISTS:
- if (MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
- res = 0;
- }
- }
-
if (res)
errno = map_errno(GetLastError());
else
@@ -4705,24 +5045,24 @@ wstati64(const WCHAR *path, struct stati64 *st)
int
rb_w32_ustati64(const char *path, struct stati64 *st)
{
- WCHAR *wpath;
- int ret;
-
- if (!(wpath = utf8_to_wstr(path, NULL)))
- return -1;
- ret = wstati64(wpath, st);
- free(wpath);
- return ret;
+ return w32_stati64(path, st, CP_UTF8);
}
/* License: Ruby's */
int
rb_w32_stati64(const char *path, struct stati64 *st)
{
+ return w32_stati64(path, st, filecp());
+}
+
+/* License: Ruby's */
+static int
+w32_stati64(const char *path, struct stati64 *st, UINT cp)
+{
WCHAR *wpath;
int ret;
- if (!(wpath = filecp_to_wstr(path, NULL)))
+ if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL)))
return -1;
ret = wstati64(wpath, st);
free(wpath);
@@ -4854,38 +5194,6 @@ _lseeki64(int fd, off_t offset, int whence)
#endif
/* License: Ruby's */
-int
-fseeko(FILE *stream, off_t offset, int whence)
-{
- off_t pos;
- switch (whence) {
- case SEEK_CUR:
- if (fgetpos(stream, (fpos_t *)&pos))
- return -1;
- pos += offset;
- break;
- case SEEK_END:
- if ((pos = _filelengthi64(fileno(stream))) == (off_t)-1)
- return -1;
- pos += offset;
- break;
- default:
- pos = offset;
- break;
- }
- return fsetpos(stream, (fpos_t *)&pos);
-}
-
-/* License: Ruby's */
-off_t
-rb_w32_ftello(FILE *stream)
-{
- off_t pos;
- if (fgetpos(stream, (fpos_t *)&pos)) return (off_t)-1;
- return pos;
-}
-
-/* License: Ruby's */
static long
filetime_to_clock(FILETIME *ft)
{
@@ -5158,6 +5466,28 @@ rb_w32_getppid(void)
return ppid;
}
+STATIC_ASSERT(std_handle, (STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)==(STD_ERROR_HANDLE-STD_OUTPUT_HANDLE));
+
+/* License: Ruby's */
+#define set_new_std_handle(newfd, handle) do { \
+ if ((unsigned)(newfd) > 2) break; \
+ SetStdHandle(STD_INPUT_HANDLE+(STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)*(newfd), \
+ (handle)); \
+ } while (0)
+#define set_new_std_fd(newfd) set_new_std_handle(newfd, (HANDLE)rb_w32_get_osfhandle(newfd))
+
+/* License: Ruby's */
+int
+rb_w32_dup2(int oldfd, int newfd)
+{
+ int ret;
+
+ if (oldfd == newfd) return newfd;
+ ret = dup2(oldfd, newfd);
+ set_new_std_fd(newfd);
+ return ret;
+}
+
/* License: Ruby's */
int
rb_w32_uopen(const char *file, int oflag, ...)
@@ -5431,8 +5761,14 @@ int
rb_w32_pipe(int fds[2])
{
static DWORD serial = 0;
- char name[] = "\\\\.\\pipe\\ruby0000000000000000-0000000000000000";
- char *p;
+ static const char prefix[] = "\\\\.\\pipe\\ruby";
+ enum {
+ width_of_prefix = (int)sizeof(prefix) - 1,
+ width_of_pid = (int)sizeof(rb_pid_t) * 2,
+ width_of_serial = (int)sizeof(serial) * 2,
+ width_of_ids = width_of_pid + 1 + width_of_serial + 1
+ };
+ char name[sizeof(prefix) + width_of_ids];
SECURITY_ATTRIBUTES sec;
HANDLE hRead, hWrite, h;
int fdRead, fdWrite;
@@ -5442,8 +5778,9 @@ rb_w32_pipe(int fds[2])
if (!cancel_io)
return _pipe(fds, 65536L, _O_NOINHERIT);
- p = strchr(name, '0');
- snprintf(p, strlen(p) + 1, "%"PRI_PIDT_PREFIX"x-%lx", rb_w32_getpid(), serial++);
+ memcpy(name, prefix, width_of_prefix);
+ snprintf(name + width_of_prefix, width_of_ids, "%.*"PRI_PIDT_PREFIX"x-%.*lx",
+ width_of_pid, rb_w32_getpid(), width_of_serial, serial++);
sec.nLength = sizeof(sec);
sec.lpSecurityDescriptor = NULL;
@@ -5520,14 +5857,42 @@ rb_w32_pipe(int fds[2])
}
/* License: Ruby's */
+static int
+console_emulator_p(void)
+{
+#ifdef _WIN32_WCE
+ return FALSE;
+#else
+ const void *const func = WriteConsoleW;
+ HMODULE k;
+ MEMORY_BASIC_INFORMATION m;
+
+ memset(&m, 0, sizeof(m));
+ if (!VirtualQuery(func, &m, sizeof(m))) {
+ return FALSE;
+ }
+ k = GetModuleHandle("kernel32.dll");
+ if (!k) return FALSE;
+ return (HMODULE)m.AllocationBase != k;
+#endif
+}
+
+/* License: Ruby's */
static struct constat *
constat_handle(HANDLE h)
{
st_data_t data;
struct constat *p;
if (!conlist) {
+ if (console_emulator_p()) {
+ conlist = conlist_disabled;
+ return NULL;
+ }
conlist = st_init_numtable();
}
+ else if (conlist == conlist_disabled) {
+ return NULL;
+ }
if (st_lookup(conlist, (st_data_t)h, &data)) {
p = (struct constat *)data;
}
@@ -5558,12 +5923,12 @@ constat_reset(HANDLE h)
}
/* License: Ruby's */
-static DWORD
-constat_attr(int count, const int *seq, DWORD attr, DWORD default_attr)
+static WORD
+constat_attr(int count, const int *seq, WORD attr, WORD default_attr)
{
#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
- DWORD bold = attr & (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
+ WORD bold = attr & (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
int rev = 0;
if (!count) return attr;
@@ -5621,6 +5986,7 @@ constat_attr(int count, const int *seq, DWORD attr, DWORD default_attr)
case 40:
attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
+ break;
case 41:
attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN) | BACKGROUND_RED;
break;
@@ -5787,9 +6153,19 @@ constat_parse(HANDLE h, struct constat *s, const WCHAR **ptrp, long *lenp)
WCHAR wc = *ptr++;
if (wc == 0x1b) {
rest = *lenp - len - 1;
+ if (s->vt100.state == constat_esc) {
+ rest++; /* reuse this ESC */
+ }
+ s->vt100.state = constat_init;
+ if (len > 0 && *ptr != L'[') continue;
s->vt100.state = constat_esc;
}
- else if (s->vt100.state == constat_esc && wc == L'[') {
+ else if (s->vt100.state == constat_esc) {
+ if (wc != L'[') {
+ /* TODO: supply dropped ESC at beginning */
+ s->vt100.state = constat_init;
+ continue;
+ }
rest = *lenp - len - 1;
if (rest > 0) --rest;
s->vt100.state = constat_seq;
@@ -5858,6 +6234,49 @@ rb_w32_close(int fd)
return 0;
}
+static int
+setup_overlapped(OVERLAPPED *ol, int fd)
+{
+ memset(ol, 0, sizeof(*ol));
+ if (!(_osfile(fd) & (FDEV | FPIPE))) {
+ LONG high = 0;
+ DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT;
+ DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+ if (low == INVALID_SET_FILE_POINTER) {
+ DWORD err = GetLastError();
+ if (err != NO_ERROR) {
+ errno = map_errno(err);
+ return -1;
+ }
+ }
+ ol->Offset = low;
+ ol->OffsetHigh = high;
+ }
+ ol->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (!ol->hEvent) {
+ errno = map_errno(GetLastError());
+ return -1;
+ }
+ return 0;
+}
+
+static void
+finish_overlapped(OVERLAPPED *ol, int fd, DWORD size)
+{
+ CloseHandle(ol->hEvent);
+
+ if (!(_osfile(fd) & (FDEV | FPIPE))) {
+ LONG high = ol->OffsetHigh;
+ DWORD low = ol->Offset + size;
+ if (low < ol->Offset)
+ ++high;
+ SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
+ }
+}
+
#undef read
/* License: Ruby's */
ssize_t
@@ -5918,25 +6337,7 @@ rb_w32_read(int fd, void *buf, size_t size)
/* if have cancel_io, use Overlapped I/O */
if (cancel_io) {
- memset(&ol, 0, sizeof(ol));
- if (!(_osfile(fd) & (FDEV | FPIPE))) {
- LONG high = 0;
- DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high,
- FILE_CURRENT);
-#ifndef INVALID_SET_FILE_POINTER
-#define INVALID_SET_FILE_POINTER ((DWORD)-1)
-#endif
- if (low == INVALID_SET_FILE_POINTER) {
- errno = map_errno(GetLastError());
- MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
- return -1;
- }
- ol.Offset = low;
- ol.OffsetHigh = high;
- }
- ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
- if (!ol.hEvent) {
- errno = map_errno(GetLastError());
+ if (setup_overlapped(&ol, fd)) {
MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
return -1;
}
@@ -5994,15 +6395,7 @@ rb_w32_read(int fd, void *buf, size_t size)
}
if (pol) {
- CloseHandle(ol.hEvent);
-
- if (!(_osfile(fd) & (FDEV | FPIPE))) {
- LONG high = ol.OffsetHigh;
- DWORD low = ol.Offset + read;
- if (low < ol.Offset)
- ++high;
- SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
- }
+ finish_overlapped(&ol, fd, read);
}
ret += read;
@@ -6062,25 +6455,7 @@ rb_w32_write(int fd, const void *buf, size_t size)
/* if have cancel_io, use Overlapped I/O */
if (cancel_io) {
- memset(&ol, 0, sizeof(ol));
- if (!(_osfile(fd) & (FDEV | FPIPE))) {
- LONG high = 0;
- DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT;
- DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
-#ifndef INVALID_SET_FILE_POINTER
-#define INVALID_SET_FILE_POINTER ((DWORD)-1)
-#endif
- if (low == INVALID_SET_FILE_POINTER) {
- errno = map_errno(GetLastError());
- MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
- return -1;
- }
- ol.Offset = low;
- ol.OffsetHigh = high;
- }
- ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
- if (!ol.hEvent) {
- errno = map_errno(GetLastError());
+ if (setup_overlapped(&ol, fd)) {
MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
return -1;
}
@@ -6126,15 +6501,7 @@ rb_w32_write(int fd, const void *buf, size_t size)
}
if (pol) {
- CloseHandle(ol.hEvent);
-
- if (!(_osfile(fd) & (FDEV | FPIPE))) {
- LONG high = ol.OffsetHigh;
- DWORD low = ol.Offset + written;
- if (low < ol.Offset)
- ++high;
- SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
- }
+ finish_overlapped(&ol, fd, written);
}
ret += written;
@@ -6157,34 +6524,53 @@ rb_w32_write_console(uintptr_t strarg, int fd)
HANDLE handle;
DWORD dwMode, reslen;
VALUE str = strarg;
- rb_encoding *utf16 = rb_enc_find("UTF-16LE");
+ int encindex;
+ WCHAR *wbuffer = 0;
const WCHAR *ptr, *next;
struct constat *s;
long len;
if (disable) return -1L;
handle = (HANDLE)_osfhnd(fd);
- if (!GetConsoleMode(handle, &dwMode) ||
- !rb_econv_has_convpath_p(rb_enc_name(rb_enc_get(str)), "UTF-16LE"))
+ if (!GetConsoleMode(handle, &dwMode))
return -1L;
- str = rb_str_encode(str, rb_enc_from_encoding(utf16),
- ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil);
- ptr = (const WCHAR *)RSTRING_PTR(str);
- len = RSTRING_LEN(str) / sizeof(WCHAR);
s = constat_handle(handle);
+ if (!s) return -1L;
+ encindex = ENCODING_GET(str);
+ switch (encindex) {
+ default:
+ if (!rb_econv_has_convpath_p(rb_enc_name(rb_enc_from_index(encindex)), "UTF-8"))
+ return -1L;
+ str = rb_str_conv_enc_opts(str, NULL, rb_enc_from_index(ENCINDEX_UTF_8),
+ ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil);
+ /* fall through */
+ case ENCINDEX_US_ASCII:
+ case ENCINDEX_ASCII:
+ /* assume UTF-8 */
+ case ENCINDEX_UTF_8:
+ ptr = wbuffer = mbstr_to_wstr(CP_UTF8, RSTRING_PTR(str), RSTRING_LEN(str), &len);
+ if (!ptr) return -1L;
+ break;
+ case ENCINDEX_UTF_16LE:
+ ptr = (const WCHAR *)RSTRING_PTR(str);
+ len = RSTRING_LEN(str) / sizeof(WCHAR);
+ break;
+ }
while (len > 0) {
long curlen = constat_parse(handle, s, (next = ptr, &next), &len);
if (curlen > 0) {
if (!WriteConsoleW(handle, ptr, curlen, &reslen, NULL)) {
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
disable = TRUE;
- return -1L;
+ reslen = (DWORD)-1L;
+ break;
}
}
ptr = next;
}
RB_GC_GUARD(str);
+ if (wbuffer) free(wbuffer);
return (long)reslen;
}
@@ -6574,7 +6960,8 @@ rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
/* License: Ruby's */
char
-rb_w32_fd_is_text(int fd) {
+rb_w32_fd_is_text(int fd)
+{
return _osfile(fd) & FTEXT;
}
@@ -6734,3 +7121,22 @@ rb_w32_unwrap_io_handle(int fd)
}
return _close(fd);
}
+
+#if !defined(__MINGW64__) && defined(__MINGW64_VERSION_MAJOR)
+/*
+ * Set floating point precision for pow() of mingw-w64 x86.
+ * With default precision the result is not proper on WinXP.
+ */
+double
+rb_w32_pow(double x, double y)
+{
+#undef pow
+ double r;
+ unsigned int default_control = _controlfp(0, 0);
+ _controlfp(_PC_64, _MCW_PC);
+ r = pow(x, y);
+ /* Restore setting */
+ _controlfp(default_control, _MCW_PC);
+ return r;
+}
+#endif