The problem with file names containing one or more !
is caused by enabled delayed expansion on execution of the command line set "filepath=%%a"
. This command line is parsed a second time because of enabled delayed expansion resulting in interpreting all exclamation marks in file name assigned to the loop variable a
as beginning/end of a delayed expanded variable reference. Therefore a single exclamation mark is removed from the file name string before assigning the remaining string to the environment variable filepath
.
Here is the code rewritten to avoid this and several other possible problems.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
cls
echo(
echo Select a system to create MGL files for:
echo(
echo 1. SNES
echo 2. PSX
echo 3. Gameboy
echo 4. C64
echo(
:Console0
%SystemRoot%\System32\choice.exe /C 1234 /N /M "Please make your selection:"
goto Console%ErrorLevel%
:Console1
set "console=SNES"
set "settings=delay="2" type="f" index="0""
goto CreateFolder
:Console2
set "console=PSX"
set "settings=delay="1" type="s" index="0""
goto CreateFolder
:Console3
set "console=gameboy"
set "settings=delay="1" type="f" index="1""
goto CreateFolder
:Console4
set "console=C64"
set "settings=delay="1" type="f" index="1""
:CreateFolder
mkdir "MLG_%console%" 2>nul
if exist "MLG_%console%\" goto GetBasePathLength
for %%I in (".\MLG_%console%") do echo ERROR: Failed to create the directory: "%%~fI"
echo(
@setlocal EnableExtensions EnableDelayedExpansion & for /F "tokens=1,2" %%G in ("!CMDCMDLINE!") do @endlocal & if /I "%%~nG" == "cmd" if /I "%%~H" == "/c" pause
goto EndBatch
:GetBasePathLength
set "BasePath=_%CD%"
if not "%BasePath:~-1%" == "\" set "BasePath=%BasePath%\"
setlocal EnableDelayedExpansion
set "BasePathLength=0"
for /L %%I in (12,-1,0) do (
set /A "BasePathLength|=1<<%%I"
for %%J in (!BasePathLength!) do if "!BasePath:~%%J,1!" == "" set /A "BasePathLength&=~1<<%%I"
)
endlocal & set "BasePathLength=%BasePathLength%"
for /R %%I in (*.32x,*.a26,*.a78,*.abs,*.bin,*.bs,*.chd,*.cof,*.col,*.fds,*.gb,*.gbc,*.gba,*.gg,*.j64,*.jag,*.lnx,*.md,*.neo,*.nes,*.o,*.pce,*.rom,*.sc,*.sfc,*.sg,*.smc,*.smd,*.sms,"*.vec",*.wsc,*.ws) do (
set "FileName=%%I"
set "OutputFile=MLG_%console%\%%~nI.mgl"
setlocal EnableDelayedExpansion
set "FileName=!FileName:~%BasePathLength%!"
set "FileName=!FileName:\=/!"
(
echo ^<mistergamedescription^>
echo ^<rbf^>_console/!console!^</rbf^>
echo ^<file !settings! path="!FileName!"/^>
echo ^</mistergamedescription^>
)>"!OutputFile!"
endlocal
)
:EndBatch
endlocal
I recommend to read first:
The strange looking FOR command line with command pause
at end is for running PAUSE only if the Windows Command Processor instance processing the batch file was started with first argument being case-insensitive /C
as done on double clicking on the batch file. PAUSE is not executed if there is first opened a command prompt window and next executed the batch file from within the command prompt window and the error occurs on creation of output directory in current directory as in this case the error message can be read in the command prompt window without using pause
.
The main FOR loop assigns first the fully qualified file name to the environment variable FileName
while delayed expansion is disabled to handle correct also file names with one or more question marks in its path/name.
The output file name with path relative to current directory is assigned also to the environment variable OutputFile
while disabled delayed expansion to work also for a file name like Blitz! - Action Football (USA, Europe) (0F11CE0C).mgl
.
Next delayed expansion is enabled which causes additional actions in the background as described in this answer with all the details about the commands SETLOCAL and ENDLOCAL.
Then the base path is removed from the file name and all \
are replaced by /
using delayed expansion.
Next the output file is created and opened with writing the four lines output with ECHO using delayed expansion into the file. Finally the output file is closed and the previous execution environment is restored using the command ENDLOCAL.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
choice /?
cls /?
echo /?
endlocal /?
for /?
goto /?
if /?
mkdir /?
pause /?
set /?
setlocal /?