Skip to content

Commit d0c63c4

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 d0c63c4

3 files changed

Lines changed: 212 additions & 30 deletions

File tree

win32/configure.bat

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,49 @@ 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+
:set_arg
41+
set next_is_opt=
42+
if defined arg exit /b
43+
if not defined argv2 exit /b
44+
if not "%argv2:~0,1%"=="-" (set "arg=%argv2%" & call :shift_argv)
45+
exit /b
46+
2947
: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
48+
call :shift_argv
49+
if not defined argv1 if not defined argv2 goto :end
50+
REM if %argv1% == "" goto :loop
51+
52+
for /f "delims== tokens=1*" %%I in (" %argv1% ") do ((set "opt=%%I") && (set "arg=%%J"))
53+
set "opt=%opt:~1%"
54+
set "eq="
55+
if defined arg (
56+
set "eq=="
57+
set "arg=%arg:~0,-1%"
58+
) else (
59+
set "opt=%opt:~0,-1%"
60+
)
61+
if "%opt%"=="" (
62+
echo 1>&2 %configure%: assignment for empty variable name %argv1%
63+
exit /b 1
64+
)
3665
if "%opt%" == "--debug-configure" (
3766
echo on
3867
set "debug_configure=yes"
@@ -78,7 +107,7 @@ for /f "delims== tokens=1,*" %%I in ("%~1") do ((set "opt=%%I") && (set "arg=%%J
78107
)
79108
goto :loop ;
80109
:target
81-
if "%eq%" == "" (set "arg=%~1" & shift)
110+
if "%eq%" == "" call :set_arg
82111
if "%arg%" == "" (
83112
echo 1>&2 %configure%: missing argument for %opt%
84113
exit /b 1
@@ -88,7 +117,6 @@ goto :loop ;
88117
echo>>%confargs% "--target=%arg:$=$$%" \
89118
goto :loop ;
90119
:program_name
91-
if "%eq%" == "" (set "arg=%~1" & shift)
92120
for /f "delims=- tokens=1,*" %I in ("%opt%") do set "var=%%J"
93121
if "%var%" == "prefix" (set "var=PROGRAM_PREFIX" & goto :name)
94122
if "%var%" == "suffix" (set "var=PROGRAM_SUFFIX" & goto :name)
@@ -99,32 +127,37 @@ goto :loop ;
99127
)
100128
goto :unknown_opt
101129
:name
102-
if "%eq%" == "" (set "arg=%~1" & shift)
130+
if "%eq%" == "" call :set_arg
103131
echo>> %config_make% %var% = %arg%
104132
goto :loopend ;
105133
:dir
106-
if "%eq%" == "" (set "arg=%~1" & shift)
134+
if "%eq%" == "" call :set_arg
107135
echo>> %config_make% %opt:~2% = %arg:\=/%
108136
goto :loopend ;
109137
:enable
110-
echo>>%confargs% "%opt%" \
111-
if %enable% == yes (set "opt=%opt:~9%") else (set "opt=%opt:~10%")
112-
if "%opt%" == "rdoc" (
138+
if %enable% == yes (
139+
if "%eq%" == "" call :set_arg
140+
set "feature=%opt:~9%"
141+
) else (
142+
set "feature=%opt:~10%"
143+
)
144+
if %enable% == yes if defined arg set "enable=%arg%"
145+
if "%feature%" == "install-doc" (
113146
echo>> %config_make% RDOCTARGET = %enable:yes=r%doc
114147
)
115-
if "%opt%" == "install-static-library" (
148+
if "%feature%" == "install-static-library" (
116149
echo>> %config_make% INSTALL_STATIC_LIBRARY = %enable%
117150
)
118-
if "%opt%" == "debug-env" (
151+
if "%feature%" == "debug-env" (
119152
echo>> %config_make% ENABLE_DEBUG_ENV = %enable%
120153
)
121-
if "%opt%" == "devel" (
154+
if "%feature%" == "devel" (
122155
echo>> %config_make% RUBY_DEVEL = %enable%
123156
)
124-
if "%opt%" == "rubygems" (
125-
echo>> %config_make% USE_RUBYGEMS = %enable%
157+
if "%feature%" == "rubygems" (
158+
echo>> %config_make% USE_RUBYGEMS = %enable%
126159
)
127-
goto :loop ;
160+
goto :loopend ;
128161
:withoutarg
129162
echo>>%confargs% "%opt%" \
130163
if "%opt%" == "--without-baseruby" goto :nobaseruby
@@ -134,7 +167,7 @@ goto :loop ;
134167
goto :loop ;
135168
:witharg
136169
if "%opt%" == "--with-static-linked-ext" goto :extstatic
137-
if "%eq%" == "" (set "arg=%~1" & shift)
170+
if "%eq%" == "" call :set_arg
138171
if not "%arg%" == "" (
139172
echo>>%confargs% "%opt%=%arg:$=$$%" \
140173
) else (
@@ -152,7 +185,7 @@ goto :loop ;
152185
:ntver
153186
::- For version constants, see
154187
::- 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%")
188+
if "%eq%" == "" (set "NTVER=%~1" & call :shift_argv) else (set "NTVER=%arg%")
156189
if /i not "%NTVER:~0,2%" == "0x" if /i not "%NTVER:~0,13%" == "_WIN32_WINNT_" (
157190
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 (
158191
call set NTVER=%%NTVER:%%i=%%i%%
@@ -162,15 +195,15 @@ goto :loop ;
162195
echo>> %config_make% NTVER = %NTVER%
163196
goto :loopend ;
164197
:extout
165-
if "%eq%" == "" (set "arg=%~1" & shift)
198+
if "%eq%" == "" call :set_arg
166199
if not "%arg%" == ".ext" (echo>> %config_make% EXTOUT = %arg%)
167200
goto :loopend ;
168201
:path
169-
if "%eq%" == "" (set "arg=%~1" & shift)
202+
if "%eq%" == "" call :set_arg
170203
set "pathlist=%pathlist%%arg:\=/%;"
171204
goto :loopend ;
172205
:extstatic
173-
if "%eq%" == "" (set "arg=static" & shift)
206+
if "%eq%" == "" (set "arg=static")
174207
echo>> %config_make% EXTSTATIC = %arg%
175208
goto :loopend ;
176209
:baseruby
@@ -203,13 +236,16 @@ goto :loop ;
203236
exit /b 1
204237
)
205238
: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:\=/%"
239+
setlocal EnableDelayedExpansion
240+
for /f "delims=; tokens=1,*" %%I in ("%arg%") do ((set "d=%%I" & set "arg=%%J")
241+
pushd !d:/=\! 2> nul
242+
if not ERRORLEVEL 1 (
243+
call set d=%%cd%%
209244
popd
210-
) || (
211-
set "optdirs=%optdirs%;%d:\=/%"
212245
)
246+
call set "optdirs=%%optdirs%%;%%d:\=/%%"
247+
)
248+
endlocal & set "optdirs=%optdirs%" & set "arg=%arg%"
213249
if not "%arg%" == "" goto :optdir-loop
214250
goto :loop ;
215251
:help
@@ -241,7 +277,7 @@ goto :EOF
241277
exit /b 1
242278
:end
243279
if "%debug_configure%" == "yes" (type %confargs%)
244-
if defined optdirs (for %%I in ("%optdirs:~1%") do echo>>%config_make% optdirs = %%~I)
280+
if defined optdirs echo>>%config_make% optdirs = %optdirs:~1%
245281
(
246282
echo.
247283
echo configure_args = \

win32/shellsplit.cmd

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

0 commit comments

Comments
 (0)