Skip to content

Commit 6c95964

Browse files
committed
mswin: use shellsplit sub batch
Introduce shellsplit.cmd to simplify configure.bat command line parsing. Makefile macro definition and opt-dir list now free from quoting. eg. now can use as ``` configure --with-opt-dir=c:/src/zlib;c:/src/libffi CC="cl -std:clatest" ```
1 parent 9715b29 commit 6c95964

4 files changed

Lines changed: 255 additions & 34 deletions

File tree

win32/configure.bat

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,56 @@ if "%~dp0" == "%CD%\" (
1414
)
1515

1616
set "WIN32DIR=%WIN32DIR:\=/%:/:"
17-
call set "WIN32DIR=%%WIN32DIR:%~x0:/:=:/:%%"
18-
call set "WIN32DIR=%%WIN32DIR:/%~n0:/:=:/:%%"
17+
call :set "WIN32DIR=%%WIN32DIR:%~x0:/:=:/:%%"
18+
call :set "WIN32DIR=%%WIN32DIR:/%~n0:/:=:/:%%"
1919
set "WIN32DIR=%WIN32DIR:~0,-3%"
2020

2121
set configure=%~0
22+
set target=
2223
set optdirs=
2324
set pathlist=
2425
set config_make=confargs~%RANDOM%.mak
2526
set confargs=%config_make:.mak=.sub%
2627
set debug_configure=
2728
echo>%config_make% # CONFIGURE
2829
type nul > %confargs%
30+
set args=%*
31+
goto :loop
32+
33+
:shift_argv
34+
call %~dp0shellsplit.cmd
35+
set "argv1=%argv2%"
36+
set "argv2=%argv%"
37+
if not defined argv1 if defined argv2 goto :shift_argv
38+
exit /b
39+
40+
:take_arg
41+
if defined arg exit /b
42+
if not defined argv2 exit /b
43+
if not "%argv2:~0,1%"=="-" (set "arg=%argv2%" & call :shift_argv)
44+
exit /b
45+
46+
:set
47+
set %1
48+
exit /b
49+
2950
:loop
30-
if [%1] == [] goto :end ;
31-
if "%~1" == "" (shift & goto :loop)
32-
for /f "delims== tokens=1,*" %%I in ("%~1") do ((set "opt=%%I") && (set "arg=%%J"))
33-
set "eq=="
34-
if "%arg%" == "" if not "%~1" == "%opt%=%arg%" (set "eq=")
35-
shift
51+
call :shift_argv
52+
if not defined argv1 goto :end
53+
54+
for /f "delims== tokens=1*" %%I in (" %argv1% ") do ((set "opt=%%I") && (set "arg=%%J"))
55+
set "opt=%opt:~1%"
56+
set "eq="
57+
if defined arg (
58+
set "eq=="
59+
set "arg=%arg:~0,-1%"
60+
) else (
61+
set "opt=%opt:~0,-1%"
62+
)
63+
if "%opt%"=="" (
64+
echo 1>&2 %configure%: assignment for empty variable name %argv1%
65+
exit /b 1
66+
)
3667
if "%opt%" == "--debug-configure" (
3768
echo on
3869
set "debug_configure=yes"
@@ -78,7 +109,7 @@ for /f "delims== tokens=1,*" %%I in ("%~1") do ((set "opt=%%I") && (set "arg=%%J
78109
)
79110
goto :loop ;
80111
:target
81-
if "%eq%" == "" (set "arg=%~1" & shift)
112+
if "%eq%" == "" call :take_arg
82113
if "%arg%" == "" (
83114
echo 1>&2 %configure%: missing argument for %opt%
84115
exit /b 1
@@ -88,7 +119,6 @@ goto :loop ;
88119
echo>>%confargs% "--target=%arg:$=$$%" \
89120
goto :loop ;
90121
:program_name
91-
if "%eq%" == "" (set "arg=%~1" & shift)
92122
for /f "delims=- tokens=1,*" %I in ("%opt%") do set "var=%%J"
93123
if "%var%" == "prefix" (set "var=PROGRAM_PREFIX" & goto :name)
94124
if "%var%" == "suffix" (set "var=PROGRAM_SUFFIX" & goto :name)
@@ -99,32 +129,37 @@ goto :loop ;
99129
)
100130
goto :unknown_opt
101131
:name
102-
if "%eq%" == "" (set "arg=%~1" & shift)
132+
if "%eq%" == "" call :take_arg
103133
echo>> %config_make% %var% = %arg%
104134
goto :loopend ;
105135
:dir
106-
if "%eq%" == "" (set "arg=%~1" & shift)
136+
if "%eq%" == "" call :take_arg
107137
echo>> %config_make% %opt:~2% = %arg:\=/%
108138
goto :loopend ;
109139
:enable
110-
echo>>%confargs% "%opt%" \
111-
if %enable% == yes (set "opt=%opt:~9%") else (set "opt=%opt:~10%")
112-
if "%opt%" == "rdoc" (
140+
if %enable% == yes (
141+
if "%eq%" == "" call :take_arg
142+
set "feature=%opt:~9%"
143+
) else (
144+
set "feature=%opt:~10%"
145+
)
146+
if %enable% == yes if defined arg set "enable=%arg%"
147+
if "%feature%" == "install-doc" (
113148
echo>> %config_make% RDOCTARGET = %enable:yes=r%doc
114149
)
115-
if "%opt%" == "install-static-library" (
150+
if "%feature%" == "install-static-library" (
116151
echo>> %config_make% INSTALL_STATIC_LIBRARY = %enable%
117152
)
118-
if "%opt%" == "debug-env" (
153+
if "%feature%" == "debug-env" (
119154
echo>> %config_make% ENABLE_DEBUG_ENV = %enable%
120155
)
121-
if "%opt%" == "devel" (
156+
if "%feature%" == "devel" (
122157
echo>> %config_make% RUBY_DEVEL = %enable%
123158
)
124-
if "%opt%" == "rubygems" (
125-
echo>> %config_make% USE_RUBYGEMS = %enable%
159+
if "%feature%" == "rubygems" (
160+
echo>> %config_make% USE_RUBYGEMS = %enable%
126161
)
127-
goto :loop ;
162+
goto :loopend ;
128163
:withoutarg
129164
echo>>%confargs% "%opt%" \
130165
if "%opt%" == "--without-baseruby" goto :nobaseruby
@@ -134,7 +169,7 @@ goto :loop ;
134169
goto :loop ;
135170
:witharg
136171
if "%opt%" == "--with-static-linked-ext" goto :extstatic
137-
if "%eq%" == "" (set "arg=%~1" & shift)
172+
if "%eq%" == "" call :take_arg
138173
if not "%arg%" == "" (
139174
echo>>%confargs% "%opt%=%arg:$=$$%" \
140175
) else (
@@ -152,25 +187,25 @@ goto :loop ;
152187
:ntver
153188
::- For version constants, see
154189
::- https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt#remarks
155-
if "%eq%" == "" (set "NTVER=%~1" & shift) else (set "NTVER=%arg%")
190+
if "%eq%" == "" (set "NTVER=%~1" & call :shift_argv) else (set "NTVER=%arg%")
156191
if /i not "%NTVER:~0,2%" == "0x" if /i not "%NTVER:~0,13%" == "_WIN32_WINNT_" (
157192
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 (
158-
call set NTVER=%%NTVER:%%i=%%i%%
193+
call :set NTVER=%%NTVER:%%i=%%i%%
159194
)
160-
call set NTVER=_WIN32_WINNT_%%NTVER%%
195+
call :set NTVER=_WIN32_WINNT_%%NTVER%%
161196
)
162197
echo>> %config_make% NTVER = %NTVER%
163198
goto :loopend ;
164199
:extout
165-
if "%eq%" == "" (set "arg=%~1" & shift)
200+
if "%eq%" == "" call :take_arg
166201
if not "%arg%" == ".ext" (echo>> %config_make% EXTOUT = %arg%)
167202
goto :loopend ;
168203
:path
169-
if "%eq%" == "" (set "arg=%~1" & shift)
204+
if "%eq%" == "" call :take_arg
170205
set "pathlist=%pathlist%%arg:\=/%;"
171206
goto :loopend ;
172207
:extstatic
173-
if "%eq%" == "" (set "arg=static" & shift)
208+
if "%eq%" == "" (set "arg=static")
174209
echo>> %config_make% EXTSTATIC = %arg%
175210
goto :loopend ;
176211
:baseruby
@@ -203,13 +238,16 @@ goto :loop ;
203238
exit /b 1
204239
)
205240
:optdir-loop
206-
for /f "delims=; tokens=1,*" %%I in ("%arg%") do (set "d=%%I" & set "arg=%%J")
207-
pushd %d:/=\% 2> nul && (
208-
set "optdirs=%optdirs%;%CD:\=/%"
241+
setlocal EnableDelayedExpansion
242+
for /f "delims=; tokens=1,*" %%I in ("%arg%") do ((set "d=%%I" & set "arg=%%J")
243+
pushd !d:/=\! 2> nul
244+
if not ERRORLEVEL 1 (
245+
call :set d=%%cd%%
209246
popd
210-
) || (
211-
set "optdirs=%optdirs%;%d:\=/%"
212247
)
248+
call :set "optdirs=%%optdirs%%;%%d:\=/%%"
249+
)
250+
endlocal & set "optdirs=%optdirs%" & set "arg=%arg%"
213251
if not "%arg%" == "" goto :optdir-loop
214252
goto :loop ;
215253
:help
@@ -241,7 +279,7 @@ goto :EOF
241279
exit /b 1
242280
:end
243281
if "%debug_configure%" == "yes" (type %confargs%)
244-
if defined optdirs (for %%I in ("%optdirs:~1%") do echo>>%config_make% optdirs = %%~I)
282+
if defined optdirs echo>>%config_make% optdirs = %optdirs:~1%
245283
(
246284
echo.
247285
echo configure_args = \

win32/shellsplit.cmd

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
rem shellsplit.cmd
2+
rem input : %args%
3+
rem output: one unquoted %argv%, remains are in %args%
4+
rem note : the empty argument "" is completely ignored.
5+
6+
setlocal EnableExtensions DisableDelayedExpansion
7+
8+
if not defined V set V=0
9+
10+
goto :main
11+
12+
:set
13+
set %*
14+
exit /b
15+
16+
:main
17+
set OUT=
18+
if not defined args (
19+
goto :return_arg
20+
)
21+
set "PENDING=%args%"
22+
set UNQ=
23+
set QTD=
24+
25+
set "HT= "
26+
:: .subst(\", `DQ`) (currently disabled)
27+
rem set "PENDING=%PENDING:\"=`??%" &
28+
:: .subst(", \tsep)
29+
call :set "PENDING=%%PENDING:"=%HT%sep%%"
30+
31+
::#### split into unquoted part, quoted part, remains
32+
:loop
33+
34+
for /F "tokens=1,2* delims=%HT%" %%I in (" %PENDING%") do (
35+
set "UNQ=%%I"
36+
call :set "UNQ=%%UNQ:~1%%"
37+
set "QTD=%%J"
38+
set "PENDING=%%K"
39+
)
40+
41+
if %V%==1 (
42+
echo unquoted:
43+
(echo UNQ :"%UNQ%")&(echo QTD :"%QTD%")&(echo REST:"%PENDING%")&(if defined OUT echo OUT:"%OUT%")
44+
)
45+
46+
if defined QTD set "QTD=%QTD:~3%" &:: remove sep
47+
if defined PENDING set "PENDING=%PENDING:~3%" &:: ditto
48+
49+
if %V%==1 (
50+
(echo QTD :"%QTD%")&(echo REST:"%PENDING%")
51+
)
52+
53+
if not defined UNQ if defined OUT (
54+
set concat_next=true
55+
goto :process_unquote
56+
)
57+
58+
set concat_prev=
59+
set concat_check=
60+
if defined UNQ set "concat_check=%UNQ:~0,1%"
61+
if not "%concat_check%"==" " set concat_prev=true
62+
63+
set concat_next=
64+
set concat_check=
65+
if defined UNQ set "concat_check=%UNQ:~-1%"
66+
if not "%concat_check%"==" " set concat_next=true
67+
68+
if not defined concat_prev if defined OUT (
69+
goto :return_arg
70+
)
71+
72+
::#### process unquoted part
73+
:process_unquote
74+
75+
if defined UNQ if "%UNQ: =%"=="" set UNQ=
76+
if not defined UNQ goto :process_quoted
77+
78+
for /F "tokens=1* eol=" %%I in ("%UNQ%") do (
79+
set "token=%%I"
80+
set "UNQ=%%J"
81+
)
82+
83+
if %V%==1 (
84+
(echo unq :"%token%")&(echo UNQ :"%UNQ%")
85+
)
86+
87+
set "OUT=%OUT%%token%"
88+
if defined UNQ (
89+
goto :return_arg
90+
) else (
91+
if not defined concat_next (
92+
goto :return_arg
93+
)
94+
)
95+
96+
::#### process quoted part
97+
:process_quoted
98+
99+
if %V%==1 (
100+
echo quoted:
101+
(echo UNQ :"%UNQ%")&(echo QTD :"%QTD%")&(echo REST:"%PENDING%")&(if defined OUT echo OUT:"%OUT%")
102+
)
103+
104+
set "OUT=%OUT%%QTD%"
105+
set QTD=
106+
107+
if not defined PENDING (
108+
goto :return_arg
109+
)
110+
goto :loop
111+
112+
::#### return splitted argv
113+
:return_arg
114+
115+
if defined PENDING call :set "PENDING=%%PENDING:%HT%sep="%%"
116+
set eq="
117+
118+
endlocal & set "argv=%OUT%" & set "args=%UNQ%%eq%%QTD%%eq%%PENDING%"
119+
120+
exit /b

win32/test_shellsplit.cmd

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
@echo off & if not [%1]==[] goto :process
2+
3+
echo This script demonstrates how shellsplit.cmd works.
4+
echo usage: %0 arg1 [arg2]...
5+
echo Prints (arg1) (arg2), shift the arguments, and loop until there are no more arguments.
6+
echo - splits commandline with spaces.
7+
echo - support quoting but only with double quotes.
8+
echo - escape character not supported.
9+
echo - standalone "" is ignored since cmd.exe variables cannot represent empty strings.
10+
exit /b 0
11+
12+
:process
13+
setlocal
14+
set V=0
15+
set argv1=
16+
set argv2=
17+
18+
set "args=%*"
19+
20+
:loop
21+
call :shift_argv
22+
if not defined argv1 if not defined argv2 goto :end
23+
echo (%argv1%) (%argv2%)
24+
25+
goto :loop
26+
27+
:shift_argv
28+
call %~dp0\shellsplit.cmd
29+
set "argv1=%argv2%"
30+
set "argv2=%argv%"
31+
if not defined argv1 if defined argv2 goto :shift_argv
32+
33+
exit /b
34+
35+
:end
36+
exit /b 0

win32/test_shellsplit2.cmd

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@echo off & if not [%1]==[] goto :process
2+
3+
echo.
4+
echo This script demonstrates how shellsplit.cmd works.
5+
echo usage: %0 arg1 arg2...
6+
echo.
7+
echo Prints separated arguments as (arg1)(arg2)...
8+
echo - splits commandline with spaces/tabs.
9+
echo - support quoting with double quotes.
10+
echo - escaping characters not supported.
11+
echo - solitary "" is ignored since cmd.exe variables cannot represent empty value.
12+
exit /b 0
13+
14+
:process
15+
setlocal
16+
set V=0
17+
18+
set "args=%*"
19+
20+
:loop
21+
call %~dp0\shellsplit.cmd
22+
if not defined argv goto :end
23+
set /p "tmp=(%argv%)"<NUL
24+
goto :loop
25+
26+
:end
27+
exit /b 0

0 commit comments

Comments
 (0)