From fa9e63ada9c5e3ede4cf7eca15de5b5967247df7 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 3 Feb 2026 15:07:48 +0900 Subject: [PATCH 01/10] [DOC] Run make for rdoc-coverage and generating html --- .github/workflows/check_misc.yml | 16 ++++++++++++---- common.mk | 9 +++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml index 35bad2724e9004..ac74ae1daaa9db 100644 --- a/.github/workflows/check_misc.yml +++ b/.github/workflows/check_misc.yml @@ -28,6 +28,15 @@ jobs: # Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN checkout: '' # false (ref: https://github.com/actions/runner/issues/2238) + - name: Re-generate Makefiles + run: | + # config.status needs to run as a shell script + { echo ':&&exit'; cat tool/prereq.status; } > config.status + : # same as actions/setup/directories/action.yml + for mk in Makefile GNUmakefile; do + sed -f tool/prereq.status template/$mk.in > $mk + done + - name: Check for code styles run: | set -x @@ -74,7 +83,6 @@ jobs: run: | set -- $(sed 's/#.*//;/^rdoc /!d' gems/bundled_gems) { echo version=$2; echo ref=$4; } >> $GITHUB_OUTPUT - echo RDOC='ruby -W0 --disable-gems tool/rdoc-srcdir -q' >> $GITHUB_ENV - name: Checkout rdoc uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -84,7 +92,7 @@ jobs: path: .bundle/gems/rdoc-${{ steps.rdoc.outputs.version }} if: ${{ steps.rdoc.outputs.ref != '' }} - - name: Generate rdoc + - name: Generate rdoc scripts run: | set -x gempath=$(ruby -e 'print Gem.user_dir, "/bin"') @@ -98,12 +106,12 @@ jobs: - name: Core docs coverage run: | - $RDOC -C -x ^ext -x ^lib . + make XRUBY=ruby RDOC_DEPENDS= RBCONFIG=update-rbconfig rdoc-coverage - name: Generate docs id: docs run: | - $RDOC --op html . + make XRUBY=ruby RDOC_DEPENDS= RBCONFIG=update-rbconfig html echo htmlout=ruby-html-${GITHUB_SHA:0:10} >> $GITHUB_OUTPUT # Generate only when document commit/PR if: >- diff --git a/common.mk b/common.mk index 5623b50b853cd9..d0393e1b621350 100644 --- a/common.mk +++ b/common.mk @@ -608,11 +608,12 @@ post-install-dbg:: srcs-doc: prepare-gems -rdoc: PHONY main srcs-doc +RDOC_DEPENDS = main srcs-doc +rdoc: PHONY $(RDOC_DEPENDS) $(RBCONFIG) @echo Generating RDoc documentation $(Q) $(RDOC) --ri --op "$(RDOCOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) . -html: PHONY main srcs-doc +html: PHONY $(RDOC_DEPENDS) $(RBCONFIG) @echo Generating RDoc HTML files $(Q) $(RDOC) --op "$(HTMLOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) . @@ -620,11 +621,11 @@ RDOC_COVERAGE_EXCLUDES = -x ^ext/json -x ^ext/openssl -x ^ext/psych \ -x ^lib/bundler -x ^lib/rubygems \ -x ^lib/did_you_mean -x ^lib/error_highlight -x ^lib/syntax_suggest -rdoc-coverage: PHONY main srcs-doc +rdoc-coverage: PHONY $(RDOC_DEPENDS) $(RBCONFIG) @echo Generating RDoc coverage report $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) $(RDOC_COVERAGE_EXCLUDES) . -undocumented: PHONY main srcs-doc +undocumented: PHONY $(RDOC_DEPENDS) $(RBCONFIG) $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) $(RDOC_COVERAGE_EXCLUDES) . | \ sed -n \ -e '/^ *# in file /{' -e 's///;N;s/\n/: /p' -e '}' \ From 2d054ef64de31a3306fa9cbaea68cbb5aa0faf21 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 6 Feb 2026 16:12:32 +0900 Subject: [PATCH 02/10] [ruby/rubygems] Cleaned up bundler .gem and .gemspec files in ensure block. https://github.com/ruby/rubygems/commit/dce4ef87bb --- spec/bundler/commands/clean_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb index 793aacf5c2b5cd..48a5dba4aa9db8 100644 --- a/spec/bundler/commands/clean_spec.rb +++ b/spec/bundler/commands/clean_spec.rb @@ -934,5 +934,11 @@ def should_not_have_gems(*gems) bundle :clean should_have_gems "bundler-#{version}" + ensure + ["bundler-#{version}.gem", "bundler-#{version}.gemspec"].each do |filename| + Pathname(vendored_gems(filename)).tap do |path| + FileUtils.rm_rf(path.basename) + end + end end end From f841f9fc9459d033fa7fb18caaa6e1eb3ac7195d Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 6 Feb 2026 16:54:19 +0900 Subject: [PATCH 03/10] [ruby/rubygems] Print message when signing in with an existing API key https://github.com/ruby/rubygems/commit/b4a8adbb4d --- lib/rubygems/gemcutter_utilities.rb | 7 ++++--- test/rubygems/test_gem_gemcutter_utilities.rb | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb index afe7957f43064f..9c22c14fad5b35 100644 --- a/lib/rubygems/gemcutter_utilities.rb +++ b/lib/rubygems/gemcutter_utilities.rb @@ -154,10 +154,11 @@ def update_scope(scope) def sign_in(sign_in_host = nil, scope: nil) sign_in_host ||= host - return if api_key - pretty_host = pretty_host(sign_in_host) - + if api_key + say "You are already signed in on #{pretty_host}." + return + end say "Enter your #{pretty_host} credentials." say "Don't have an account yet? " \ "Create one at #{sign_in_host}/sign_up" diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb index 9204dc5f20ec6f..ca34c8d03dc73a 100644 --- a/test/rubygems/test_gem_gemcutter_utilities.rb +++ b/test/rubygems/test_gem_gemcutter_utilities.rb @@ -150,7 +150,7 @@ def test_sign_in_skips_with_existing_credentials util_sign_in - assert_equal "", @sign_in_ui.output + assert_match(/You are already signed in/, @sign_in_ui.output) end def test_sign_in_skips_with_key_override @@ -158,7 +158,7 @@ def test_sign_in_skips_with_key_override @cmd.options[:key] = :KEY util_sign_in - assert_equal "", @sign_in_ui.output + assert_match(/You are already signed in/, @sign_in_ui.output) end def test_sign_in_with_other_credentials_doesnt_overwrite_other_keys From 17caec3cab53f16ab4e338858560519082e5dd48 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Fri, 6 Feb 2026 09:33:07 +0100 Subject: [PATCH 04/10] [ruby/json] Cleanup function delecarations https://github.com/ruby/json/commit/7ddf3499d0 --- ext/json/json.h | 4 ++++ ext/json/parser/parser.c | 24 +++++++----------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/ext/json/json.h b/ext/json/json.h index 9379d7ae7fa97a..087a2eae66e317 100644 --- a/ext/json/json.h +++ b/ext/json/json.h @@ -55,8 +55,12 @@ typedef unsigned char _Bool; #endif #ifndef NORETURN +#if defined(__has_attribute) && __has_attribute(noreturn) +#define NORETURN(x) __attribute__((noreturn)) x +#else #define NORETURN(x) x #endif +#endif #ifndef NOINLINE #if defined(__has_attribute) && __has_attribute(noinline) diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index f1ea1b6abbfdc3..93e3b021f19a67 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -400,10 +400,7 @@ static void emit_parse_warning(const char *message, JSON_ParserState *state) #define PARSE_ERROR_FRAGMENT_LEN 32 -#ifdef RBIMPL_ATTR_NORETURN -RBIMPL_ATTR_NORETURN() -#endif -static void raise_parse_error(const char *format, JSON_ParserState *state) +NORETURN(static) void raise_parse_error(const char *format, JSON_ParserState *state) { unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3]; long line, column; @@ -449,10 +446,7 @@ static void raise_parse_error(const char *format, JSON_ParserState *state) rb_exc_raise(exc); } -#ifdef RBIMPL_ATTR_NORETURN -RBIMPL_ATTR_NORETURN() -#endif -static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at) +NORETURN(static) void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at) { state->cursor = at; raise_parse_error(format, state); @@ -777,7 +771,7 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser #define MAX_FAST_INTEGER_SIZE 18 -static VALUE json_decode_large_integer(const char *start, long len) +NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len) { VALUE buffer_v; char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1); @@ -788,8 +782,7 @@ static VALUE json_decode_large_integer(const char *start, long len) return number; } -static inline VALUE -json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end) +static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end) { if (RB_LIKELY(mantissa_digits < MAX_FAST_INTEGER_SIZE)) { if (negative) { @@ -801,7 +794,7 @@ json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const return json_decode_large_integer(start, end - start); } -static VALUE json_decode_large_float(const char *start, long len) +NOINLINE(static) VALUE json_decode_large_float(const char *start, long len) { if (RB_LIKELY(len < 64)) { char buffer[64]; @@ -868,7 +861,7 @@ static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs) return Qfalse; } -static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key) +NOINLINE(static) void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key) { VALUE message = rb_sprintf( "detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`", @@ -879,10 +872,7 @@ static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_ RB_GC_GUARD(message); } -#ifdef RBIMPL_ATTR_NORETURN -RBIMPL_ATTR_NORETURN() -#endif -static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key) +NORETURN(static) void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key) { VALUE message = rb_sprintf( "duplicate key %"PRIsVALUE, From 6e18331074f188ef79241e3f5155f225da4bd440 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Fri, 6 Feb 2026 10:03:12 +0100 Subject: [PATCH 05/10] [ruby/json] Stop using RB_ALLOCV While it's a very nice API, if the buffer is too big for the stack (> 1024B) the buffer object will be mark like a stack region which is slow and overkill for a char buffer. https://github.com/ruby/json/commit/4dcbcb84a2 --- ext/json/parser/parser.c | 54 +++++++++++++++++++++-------------- test/json/json_parser_test.rb | 4 +++ 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index 93e3b021f19a67..e4b619b42fddca 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -770,16 +770,36 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser } #define MAX_FAST_INTEGER_SIZE 18 +#define MAX_NUMBER_STACK_BUFFER 128 + +typedef VALUE (*json_number_decode_func_t)(const char *ptr); + +static inline VALUE json_decode_large_number(const char *start, long len, json_number_decode_func_t func) +{ + if (RB_LIKELY(len < MAX_NUMBER_STACK_BUFFER)) { + char buffer[MAX_NUMBER_STACK_BUFFER]; + MEMCPY(buffer, start, char, len); + buffer[len] = '\0'; + return func(buffer); + } else { + VALUE buffer_v = rb_str_tmp_new(len); + char *buffer = RSTRING_PTR(buffer_v); + MEMCPY(buffer, start, char, len); + buffer[len] = '\0'; + VALUE number = func(buffer); + RB_GC_GUARD(buffer_v); + return number; + } +} + +static VALUE json_decode_inum(const char *buffer) +{ + return rb_cstr2inum(buffer, 10); +} NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len) { - VALUE buffer_v; - char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1); - MEMCPY(buffer, start, char, len); - buffer[len] = '\0'; - VALUE number = rb_cstr2inum(buffer, 10); - RB_ALLOCV_END(buffer_v); - return number; + return json_decode_large_number(start, len, json_decode_inum); } static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end) @@ -794,22 +814,14 @@ static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, return json_decode_large_integer(start, end - start); } -NOINLINE(static) VALUE json_decode_large_float(const char *start, long len) +static VALUE json_decode_dnum(const char *buffer) { - if (RB_LIKELY(len < 64)) { - char buffer[64]; - MEMCPY(buffer, start, char, len); - buffer[len] = '\0'; - return DBL2NUM(rb_cstr_to_dbl(buffer, 1)); - } + return DBL2NUM(rb_cstr_to_dbl(buffer, 1)); +} - VALUE buffer_v; - char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1); - MEMCPY(buffer, start, char, len); - buffer[len] = '\0'; - VALUE number = DBL2NUM(rb_cstr_to_dbl(buffer, 1)); - RB_ALLOCV_END(buffer_v); - return number; +NOINLINE(static) VALUE json_decode_large_float(const char *start, long len) +{ + return json_decode_large_number(start, len, json_decode_dnum); } /* Ruby JSON optimized float decoder using vendored Ryu algorithm diff --git a/test/json/json_parser_test.rb b/test/json/json_parser_test.rb index ac53ba9f0c872f..1b875422a1adc5 100644 --- a/test/json/json_parser_test.rb +++ b/test/json/json_parser_test.rb @@ -135,6 +135,10 @@ def test_parse_bignum bignum = Integer('1234567890' * 10) assert_equal(bignum, JSON.parse(bignum.to_s)) assert_equal(bignum.to_f, JSON.parse(bignum.to_s + ".0")) + + bignum = Integer('1234567890' * 50) + assert_equal(bignum, JSON.parse(bignum.to_s)) + assert_equal(bignum.to_f, JSON.parse(bignum.to_s + ".0")) end def test_parse_bigdecimals From d9674b155253a3510c1141601a5c557a72fd1f51 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 5 Feb 2026 08:31:50 +0100 Subject: [PATCH 06/10] [DOC] Fix -r CLI example > :139:in 'Kernel#require': cannot load such file -- CSV (LoadError) Maybe it currently works on a case-insensitive file system --- doc/language/options.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/language/options.md b/doc/language/options.md index 5f56ef0dd46db7..a1f29bfd03c41f 100644 --- a/doc/language/options.md +++ b/doc/language/options.md @@ -391,7 +391,7 @@ the option may be given more than once: $ ruby -e 'p defined?(JSON); p defined?(CSV)' nil nil -$ ruby -r CSV -r JSON -e 'p defined?(JSON); p defined?(CSV)' +$ ruby -r csv -r json -e 'p defined?(JSON); p defined?(CSV)' "constant" "constant" ``` @@ -685,4 +685,3 @@ and disables input from `$stdin`. ### `--version`: Print Ruby Version Option `--version` prints the version of the Ruby interpreter, then exits. - From 49d2d3a28e405ec5a3050374b07ec580f8402492 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 6 Feb 2026 19:56:39 +0900 Subject: [PATCH 07/10] Fix up GH-13520 The `-C` option takes precedence over the `-r` option. This means that the options `-r./$(arch)-fake -C $(srcdir)` try to load the file in the source directory rather than the build directory. [ci skip] because all CIs use `test-bundler-parallel` instead of this. --- common.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common.mk b/common.mk index d0393e1b621350..f7061f8975ef28 100644 --- a/common.mk +++ b/common.mk @@ -1644,7 +1644,8 @@ test-bundler: $(TEST_RUNNABLE)-test-bundler yes-test-bundler: $(PREPARE_BUNDLER) $(gnumake_recursive)$(XRUBY) \ -r./$(arch)-fake \ - -C $(srcdir) -Ispec/bundler -Ispec/lib spec/bin/rspec \ + -I$(srcdir)/spec/bundler -I$(srcdir)/spec/lib \ + -e 'Dir.chdir(ARGV.shift); load("spec/bin/rspec")' $(srcdir) \ -r spec_helper $(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS) no-test-bundler: From d858bed94ed801e788d128fad5e9eb20b6c9f975 Mon Sep 17 00:00:00 2001 From: YO4 Date: Wed, 4 Feb 2026 23:08:27 +0900 Subject: [PATCH 08/10] mswin: fix configure.bat Avoid being affected by the existing environment variable `target` Ensure `call set` works correctly even if the external command `set` exists Make `--disable-install-doc` work again Prevent `--with-static-linked-ext` from consuming subsequent arguments Make `--with-opt-dir` work correctly when specifying an existing directory --- win32/configure.bat | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/win32/configure.bat b/win32/configure.bat index 68ce7fb53f3cb4..7a196a3baea7e8 100755 --- a/win32/configure.bat +++ b/win32/configure.bat @@ -1,7 +1,13 @@ @echo off @setlocal EnableExtensions DisableDelayedExpansion || exit /b -1 set PROMPT=$E[94m+$E[m$S +goto :main +:set +set %* +exit /b + +:main if "%~dp0" == "%CD%\" ( echo don't run in win32 directory. exit /b 999 @@ -14,11 +20,12 @@ if "%~dp0" == "%CD%\" ( ) set "WIN32DIR=%WIN32DIR:\=/%:/:" -call set "WIN32DIR=%%WIN32DIR:%~x0:/:=:/:%%" -call set "WIN32DIR=%%WIN32DIR:/%~n0:/:=:/:%%" +call :set "WIN32DIR=%%WIN32DIR:%~x0:/:=:/:%%" +call :set "WIN32DIR=%%WIN32DIR:/%~n0:/:=:/:%%" set "WIN32DIR=%WIN32DIR:~0,-3%" set configure=%~0 +set target= set optdirs= set pathlist= set config_make=confargs~%RANDOM%.mak @@ -88,7 +95,6 @@ goto :loop ; echo>>%confargs% "--target=%arg:$=$$%" \ goto :loop ; :program_name - if "%eq%" == "" (set "arg=%~1" & shift) for /f "delims=- tokens=1,*" %I in ("%opt%") do set "var=%%J" if "%var%" == "prefix" (set "var=PROGRAM_PREFIX" & goto :name) if "%var%" == "suffix" (set "var=PROGRAM_SUFFIX" & goto :name) @@ -109,7 +115,7 @@ goto :loopend ; :enable echo>>%confargs% "%opt%" \ if %enable% == yes (set "opt=%opt:~9%") else (set "opt=%opt:~10%") - if "%opt%" == "rdoc" ( + if "%opt%" == "install-doc" ( echo>> %config_make% RDOCTARGET = %enable:yes=r%doc ) if "%opt%" == "install-static-library" ( @@ -155,9 +161,9 @@ goto :loop ; if "%eq%" == "" (set "NTVER=%~1" & shift) else (set "NTVER=%arg%") if /i not "%NTVER:~0,2%" == "0x" if /i not "%NTVER:~0,13%" == "_WIN32_WINNT_" ( 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 NTVER=%%NTVER:%%i=%%i%% + call :set NTVER=%%NTVER:%%i=%%i%% ) - call set NTVER=_WIN32_WINNT_%%NTVER%% + call :set NTVER=_WIN32_WINNT_%%NTVER%% ) echo>> %config_make% NTVER = %NTVER% goto :loopend ; @@ -170,7 +176,7 @@ goto :loopend ; set "pathlist=%pathlist%%arg:\=/%;" goto :loopend ; :extstatic - if "%eq%" == "" (set "arg=static" & shift) + if "%eq%" == "" (set "arg=static") echo>> %config_make% EXTSTATIC = %arg% goto :loopend ; :baseruby @@ -205,7 +211,7 @@ goto :loop ; :optdir-loop for /f "delims=; tokens=1,*" %%I in ("%arg%") do (set "d=%%I" & set "arg=%%J") pushd %d:/=\% 2> nul && ( - set "optdirs=%optdirs%;%CD:\=/%" + call :set "optdirs=%optdirs%;%%CD:\=/%%" popd ) || ( set "optdirs=%optdirs%;%d:\=/%" @@ -241,7 +247,7 @@ goto :EOF exit /b 1 :end if "%debug_configure%" == "yes" (type %confargs%) -if defined optdirs (for %%I in ("%optdirs:~1%") do echo>>%config_make% optdirs = %%~I) +if defined optdirs (echo>>%config_make% optdirs = %optdirs:~1%) ( echo. echo configure_args = \ From cda16da6e163c592b7150d2360c7a47f568ef873 Mon Sep 17 00:00:00 2001 From: YO4 Date: Wed, 4 Feb 2026 22:38:06 +0900 Subject: [PATCH 09/10] mswin: improve configure.bat syntax Introduce shellsplit.cmd command line parsing subroutine. Dealing with the limitations of cmd.exe's command-line parsing forces users to use workarounds, and corner cases still remain. By implementing our own command line splitting, we conceal the complexity and ensure maintainability. Makefile macro definition and opt-dir list now free from quoting. now can use like ``` configure.bat --with-opt-dir=c:/src/zlib;c:/src/libffi CC="cl -std:c11" DEFS=-DOPT_THREADED_CODE=2 ``` --- win32/configure.bat | 74 +++++++++++++++++-------- win32/shellsplit.cmd | 114 ++++++++++++++++++++++++++++++++++++++ win32/test_shellsplit.cmd | 28 ++++++++++ 3 files changed, 193 insertions(+), 23 deletions(-) mode change 100755 => 100644 win32/configure.bat create mode 100644 win32/shellsplit.cmd create mode 100644 win32/test_shellsplit.cmd diff --git a/win32/configure.bat b/win32/configure.bat old mode 100755 new mode 100644 index 7a196a3baea7e8..844dafd8498b4b --- a/win32/configure.bat +++ b/win32/configure.bat @@ -7,6 +7,19 @@ goto :main set %* exit /b +:shift +call %~dp0shellsplit.cmd +set "argv1=%argv2%" +set "argv2=%argv%" +if not defined argv1 if defined argv2 goto :shift +exit /b + +:take_arg +if defined arg exit /b +if not defined argv2 exit /b +if not "%argv2:~0,1%"=="-" (set "arg=%argv2%" & call :shift) +exit /b + :main if "%~dp0" == "%CD%\" ( echo don't run in win32 directory. @@ -25,6 +38,7 @@ call :set "WIN32DIR=%%WIN32DIR:/%~n0:/:=:/:%%" set "WIN32DIR=%WIN32DIR:~0,-3%" set configure=%~0 +set args=%* set target= set optdirs= set pathlist= @@ -34,12 +48,21 @@ set debug_configure= echo>%config_make% # CONFIGURE type nul > %confargs% :loop -if [%1] == [] goto :end ; -if "%~1" == "" (shift & goto :loop) -for /f "delims== tokens=1,*" %%I in ("%~1") do ((set "opt=%%I") && (set "arg=%%J")) - set "eq==" - if "%arg%" == "" if not "%~1" == "%opt%=%arg%" (set "eq=") - shift +call :shift +if not defined argv1 goto :end +for /f "delims== tokens=1,*" %%I in (" %argv1% ") do ((set "opt=%%I") && (set "arg=%%J")) + set "opt=%opt:~1%" + if defined arg ( + set "eq==" + set "arg=%arg:~0,-1%" + ) else ( + set "eq=" + set "opt=%opt:~0,-1%" + ) + if "%opt%"=="" ( + echo 1>&2 %configure%: assignment for empty variable name %argv1% + exit /b 1 + ) if "%opt%" == "--debug-configure" ( echo on set "debug_configure=yes" @@ -85,7 +108,7 @@ for /f "delims== tokens=1,*" %%I in ("%~1") do ((set "opt=%%I") && (set "arg=%%J ) goto :loop ; :target - if "%eq%" == "" (set "arg=%~1" & shift) + if "%eq%" == "" call :take_arg if "%arg%" == "" ( echo 1>&2 %configure%: missing argument for %opt% exit /b 1 @@ -105,32 +128,37 @@ goto :loop ; ) goto :unknown_opt :name - if "%eq%" == "" (set "arg=%~1" & shift) + if "%eq%" == "" call :take_arg echo>> %config_make% %var% = %arg% goto :loopend ; :dir - if "%eq%" == "" (set "arg=%~1" & shift) + if "%eq%" == "" call :take_arg echo>> %config_make% %opt:~2% = %arg:\=/% goto :loopend ; :enable - echo>>%confargs% "%opt%" \ - if %enable% == yes (set "opt=%opt:~9%") else (set "opt=%opt:~10%") - if "%opt%" == "install-doc" ( + if %enable% == yes ( + if "%eq%" == "" call :take_arg + set "feature=%opt:~9%" + ) else ( + set "feature=%opt:~10%" + ) + if %enable% == yes if defined arg (set "enable=%arg%") + if "%feature%" == "install-doc" ( echo>> %config_make% RDOCTARGET = %enable:yes=r%doc ) - if "%opt%" == "install-static-library" ( + if "%feature%" == "install-static-library" ( echo>> %config_make% INSTALL_STATIC_LIBRARY = %enable% ) - if "%opt%" == "debug-env" ( + if "%feature%" == "debug-env" ( echo>> %config_make% ENABLE_DEBUG_ENV = %enable% ) - if "%opt%" == "devel" ( + if "%feature%" == "devel" ( echo>> %config_make% RUBY_DEVEL = %enable% ) - if "%opt%" == "rubygems" ( - echo>> %config_make% USE_RUBYGEMS = %enable% + if "%feature%" == "rubygems" ( + echo>> %config_make% USE_RUBYGEMS = %enable% ) -goto :loop ; +goto :loopend ; :withoutarg echo>>%confargs% "%opt%" \ if "%opt%" == "--without-baseruby" goto :nobaseruby @@ -140,7 +168,7 @@ goto :loop ; goto :loop ; :witharg if "%opt%" == "--with-static-linked-ext" goto :extstatic - if "%eq%" == "" (set "arg=%~1" & shift) + if "%eq%" == "" call :take_arg if not "%arg%" == "" ( echo>>%confargs% "%opt%=%arg:$=$$%" \ ) else ( @@ -158,7 +186,7 @@ goto :loop ; :ntver ::- For version constants, see ::- https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt#remarks - if "%eq%" == "" (set "NTVER=%~1" & shift) else (set "NTVER=%arg%") + if "%eq%" == "" (set "NTVER=%~1" & call :shift) else (set "NTVER=%arg%") if /i not "%NTVER:~0,2%" == "0x" if /i not "%NTVER:~0,13%" == "_WIN32_WINNT_" ( 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 NTVER=%%NTVER:%%i=%%i%% @@ -168,11 +196,11 @@ goto :loop ; echo>> %config_make% NTVER = %NTVER% goto :loopend ; :extout - if "%eq%" == "" (set "arg=%~1" & shift) + if "%eq%" == "" call :take_arg if not "%arg%" == ".ext" (echo>> %config_make% EXTOUT = %arg%) goto :loopend ; :path - if "%eq%" == "" (set "arg=%~1" & shift) + if "%eq%" == "" call :take_arg set "pathlist=%pathlist%%arg:\=/%;" goto :loopend ; :extstatic @@ -236,7 +264,7 @@ goto :loop ; echo --with-ntver=0xXXXX target NT version (shouldn't use with old SDK) echo --with-ntver=_WIN32_WINNT_XXXX echo --with-ntver=XXXX same as --with-ntver=_WIN32_WINNT_XXXX - echo Note that '=,;' need to be enclosed within double quotes in batch file command line. + echo Note that parameters containing spaces must be enclosed within double quotes. del %confargs% %config_make% goto :EOF :unknown_opt diff --git a/win32/shellsplit.cmd b/win32/shellsplit.cmd new file mode 100644 index 00000000000000..0594f22df1143e --- /dev/null +++ b/win32/shellsplit.cmd @@ -0,0 +1,114 @@ +setlocal EnableExtensions DisableDelayedExpansion +if not defined V set V=0 +if not defined args ( + goto :return_arg +) +set INPUT=%args% +set OUTBUF= +set UNQ= +set QTD= + +set INPUT=%INPUT:#=#35% +set INPUT=%INPUT:@=#64% +set "PENDING=%INPUT:"=@sep%" &:: escape double quotes and split consecutive marks + +::#### split into unquoted part, quoted part, remains +:loop + +for /F "tokens=1,2* delims=@" %%I in (" %PENDING%") do ( + set "UNQ=%%I" + set "QTD=%%J" + set "PENDING=%%K" +) +set "UNQ=%UNQ:~1%" + +if %V%==1 ( + echo unquoted: + (echo UNQ :"%UNQ%")&(echo QTD :"%QTD%")&(echo REST:"%PENDING%")&(if defined OUTBUF echo OUTBUF:"%OUTBUF%") +) + +if defined QTD (set "QTD=%QTD:~3%") +if defined PENDING (set "PENDING=%PENDING:~3%") + +if %V%==1 ( + (echo QTD :"%QTD%")&(echo REST:"%PENDING%") +) + +if not defined UNQ if defined OUTBUF ( + set concat_next=true + goto :process_unquote +) + +set concat_prev= +set concat_check= +if defined UNQ (set "concat_check=%UNQ:~0,1%") +if not "%concat_check%"==" " (set concat_prev=true) + +set concat_next= +set concat_check= +if defined UNQ (set "concat_check=%UNQ:~-1%") +if not "%concat_check%"==" " (set concat_next=true) + +if not defined concat_prev if defined OUTBUF ( + goto :return_arg +) + +::#### process unquoted part +:process_unquote + +if defined UNQ if "%UNQ: =%"=="" (set UNQ=) +if not defined UNQ goto :process_quoted + +for /F "tokens=1* eol=" %%I in ("%UNQ%") do ( + set "token=%%I" + set "UNQ=%%J" +) + +if %V%==1 ( + (echo unq :"%token%")&(echo UNQ :"%UNQ%") +) + +set "OUTBUF=%OUTBUF%%token%" +if defined UNQ ( + goto :return_arg +) else ( + if not defined concat_next ( + goto :return_arg + ) +) + +::#### process quoted part +:process_quoted + +if %V%==1 ( + echo quoted: + (echo UNQ :"%UNQ%")&(echo QTD :"%QTD%")&(echo REST:"%PENDING%")&(if defined OUTBUF echo OUTBUF:"%OUTBUF%") +) + +set "OUTBUF=%OUTBUF%%QTD%" +set QTD= + +if not defined PENDING ( + goto :return_arg +) +goto :loop + +::#### return splitted argv +:return_arg + +set "argv=%OUTBUF%" +if defined argv (set "argv=%argv:#64=@%") +if defined argv (set "argv=%argv:#35=#%") + +if defined QTD (set QTD="%QTD%") + +:: special handling is required because they may contain double quotes + +if defined PENDING set PENDING=%PENDING:@sep="% +set args=%UNQ%%QTD%%PENDING% +if defined args set args=%args:#64=@% +if defined args set args=%args:#35=#% + +endlocal & set "argv=%argv%" & set args=%args% + +exit /b diff --git a/win32/test_shellsplit.cmd b/win32/test_shellsplit.cmd new file mode 100644 index 00000000000000..8a2e8ec8f45961 --- /dev/null +++ b/win32/test_shellsplit.cmd @@ -0,0 +1,28 @@ +@echo off & if not [%1]==[] goto :process + +echo. +echo This script demonstrates how shellsplit.cmd works. +echo usage: %0 arg1 arg2... +echo. +echo Prints separated arguments as (arg1)(arg2)... +echo - splits commandline with spaces/tabs. cmd.exe standard rule is ignored. +echo - you can use double quotes to contain spaces/tabs into an argument. +echo - you can not escape double quote. +echo - solitary "" is ignored since cmd.exe variables cannot represent empty value. +exit /b 0 + +:process +setlocal +set V=0 + +:: %* can contain meta character inside quote. do not use set "args=%*" here. +set args=%* + +:loop +call %~dp0\shellsplit.cmd +if not defined argv goto :end +set /p "tmp=(%argv%)" Date: Tue, 3 Feb 2026 11:06:09 +0900 Subject: [PATCH 10/10] [DOC] Exclude `require` in RubyGems not to override the original Fix ruby/rdoc#1592. --- common.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/common.mk b/common.mk index f7061f8975ef28..9506869b72a313 100644 --- a/common.mk +++ b/common.mk @@ -75,6 +75,7 @@ HTMLOUT = $(EXTOUT)/html CAPIOUT = doc/capi INSTALL_DOC_OPTS = --rdoc-output="$(RDOCOUT)" --html-output="$(HTMLOUT)" RDOC_GEN_OPTS = --no-force-update \ + --exclude '^lib/rubygems/core_ext/kernel_require\.rb$$' \ $(empty) INITOBJS = dmyext.$(OBJEXT) dmyenc.$(OBJEXT)