re-use %* without corrupting it?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
Sponge Belly
Posts: 231
Joined: 01 Oct 2012 13:32
Location: Ireland
Contact:

re-use %* without corrupting it?

#1 Post by Sponge Belly » 12 May 2015 14:13

Hello All! :)

I want to make sure a script I’m writing runs in ANSI mode. The usual procedure is to check for a command line switch and call the script again if not present. The relevant line is:

Code: Select all

cmd /d /a /c call "%~dpnx0" /ansi %*


Trouble is, when I run it with echo on, I notice that unquoted carets are halved and quoted carets are doubled. Is there a way around this?

And before I’m swept away by a tsunami of terse replies consisting entirely of links to past DosTips topics, all I’ll say in my defence is that it’s impossible to search for the string: %* :?

- SB

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: re-use %* without corrupting it?

#2 Post by jeb » 12 May 2015 14:35

Interesting question with more than one problem.

I suppose you need to modify the %* content.

So at first you have to get the content of %* with the FOR/REM technic.

Then you should escape simply all characters with carets (or at least all special characters like ^<>&" )
And then you need to double the percent signs.

After all you can start your new cmd instance but as you are using the CALL you should use here an embedded double percent variable, something like

Code: Select all

@echo off
FOR block with REM to get %* into paramAll
foreach character prefix it with ^
set "paramAll=!paramAll:%%=%%%%!"
cmd /d /a /c call "%~dpnx0" /ansi %%paramAll%%

carlos
Expert
Posts: 503
Joined: 20 Aug 2010 13:57
Location: Chile
Contact:

Re: re-use %* without corrupting it?

#3 Post by carlos » 12 May 2015 15:07

you have a full example ?

Sponge Belly
Posts: 231
Joined: 01 Oct 2012 13:32
Location: Ireland
Contact:

Re: re-use %* without corrupting it?

#4 Post by Sponge Belly » 15 May 2015 16:21

Hi Jeb,

I was afraid you’d say something like that. :(

But it’s even worse than I originally thought. If the program is executed from the command line using cmd like so:

Code: Select all

cmd /c prog.cmd "quoted ^ carets" unquoted ^^^^ carets


The carets must be escaped a second time for the command line cmd. So the quoted carets are doubled and the unquoted ones are quartered in this case. :cry:

Btw, please post a link to an explanation of the technique for using rem in a plain for loop to capture the contents of %*.

Here’s my code so far, Carlos:

Code: Select all

@echo off & setlocal enableextensions disabledelayedexpansion
echo on
rem # %* #
@echo off
set "arg1=%~1"
if defined arg1 (set arg1 | findstr /ilvx arg1=/ansi >nul && (
set "arg1="
cmd /d /a /c call "%~dpnx0" /ansi %* && goto end || goto die
)) else (>&2 echo(filename(s^) expected & goto die)
shift /1
(call;)
echo(prog in ansi mode
goto end

:die
(call)
>&2 echo(program ended unexpectedly
:end
endlocal & goto :eof


But I think if I go down this road any farther, it will lead only to madness. There are too many edge cases for a watertight solution. A much simpler alternative is to redirect a newline into a file and if the file size isn’t 2, then we’re not in ANSI anymore, Toto… :lol:

- SB

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: re-use %* without corrupting it?

#5 Post by jeb » 16 May 2015 10:58

Sponge Belly wrote:But it’s even worse than I originally thought. If the program is executed from the command line using cmd like so:

Code:
cmd /c prog.cmd "quoted ^ carets" unquoted ^^^^ carets

But here you should use better a variable with "late" expansion inside the call, then the most problems will disappear.

A small sample

Code: Select all

@echo off
setlocal DisableDelayedExpansion

setlocal
for %%a in (1) do (
    set "prompt="
    echo on
    for %%b in (1) do rem * #%*#
    @echo off
) > param.txt
endlocal

for /F "delims=" %%L in (param.txt) do (
  set "paramAll=%%L"
)
SETLOCAL EnableDelayedExpansion
set "paramAll=!paramAll:*#=!"
set "paramAll=!paramAll:~0,-2!"
echo %%* is '!paramAll!' in %0

set "paramAll=!paramAll:^=^^!"
set "paramAll=!paramAll:"=^^"!"
set "paramAll=!paramAll:&=^&!"
set "paramAll=!paramAll:<=^<!"
set "paramAll=!paramAll:>=^>!"
set "paramAll=!paramAll:|=^|!"

set "p1=%%paramAll%%"
cmd /d /a /c call "param2.bat" %%p1%%

Sponge Belly
Posts: 231
Joined: 01 Oct 2012 13:32
Location: Ireland
Contact:

Re: re-use %* without corrupting it?

#6 Post by Sponge Belly » 29 Jun 2015 15:35

Hi Guys! :)

Sorry for the delay in replying. Here’s what I (eventually) came up with:

Code: Select all

@echo off & setlocal enableextensions disabledelayedexpansion
(call;)
set "crlf=%tmp%\crlf.tmp"
>"%crlf%" echo(
for %%A in ("%crlf%") do set "crlfSize=%%~zA"
if %crlfSize% neq 2 (
>&2 echo(program must be run from shell in ANSI mode (cmd /a^)
goto die)

set "pFile=%tmp%\param.tmp" & set "argc=1"
:params
for %%A in (%%A) do (
setlocal disableextensions
set prompt=@
echo on
for %%B in (%%B) do (
@goto break1
rem # %1 #
)
:break1
@echo off
endlocal
) >"%pFile%"

for /f %%A in ('find /c /v "" ^<"%pFile%"') do if %%A neq 5 (
>&2 echo(multiline parameters not supported & goto die)
for /f usebackq^ skip^=3^ delims^=^ eol^= %%A in ("%pFile%") do (
set "param=%%A"
(for /f delims^=^ eol^= %%B in (
'cmd /v:on /c "echo(^!param:~7,-3^!"'
) do set "arg%argc%=%%B") ||set "arg%argc%="
goto break2)
:break2
if defined arg%argc% (set /a argc+=1 & shift /1 & goto params
) else set /a argc-=1

setlocal enabledelayedexpansion
for /l %%I in (1 1 %argc%) do echo(arg%%I: [!arg%%I!]
echo(argc: %argc%
endlocal
goto end

:die
(call)
:end
for %%T in ("%crlf%" "%pFile%") do if exist %%T del %%T
endlocal & goto :eof


And here’s an example of its usage:

Code: Select all

>listargs  good  morning,  ""  world!  ^
More? "how are you today?
arg1: [good]
arg2: [morning]
arg3: [""]
arg4: [world!]
arg5: ["how are you today?]
argc: 5


For sanity reasons, the program must be run from a shell in ANSI mode and multiline parameters are not supported. Thanks to Jeb for his SO Answer on how to pass a multiline string as a parameter to a Batch file.

- SB

Post Reply