Handling of %~I problem

Nov 6, 2014
18
0
cmd supports this bit of variable expansion in a `for` loop (from the `for /?` help):

Code:
 %~I         - expands %I removing any surrounding quotes (")
tcc used to handle this construct the same way as cmd until v21. Here's a simple test script:

Code:
C:\Program Files\JPSoft>type c:\temp\test.cmd
@echo off
for /f "usebackq" %%a IN ('test') do (
    echo a is :%%a:
    echo ~a is :%%~a:
)

for /f "usebackq" %%a IN ('"test2"') do (
    echo a is :%%a:
    echo ~a is :%%~a:
)
cmd and tcc through v20 process it the same:

Code:
C:\Program Files\JPSoft>ver

Microsoft Windows [Version 10.0.17134.765]

C:\Program Files\JPSoft>c:\temp\test.cmd
a is :test:
~a is :test:
a is :"test2":
~a is :test2:

C:\Program Files\JPSoft>TCMD20\tcc c:\temp\test.cmd

TCC  20.11.46 x64   Windows 10 [Version 6.3.17134]
Copyright 2017 JP Software Inc.  All Rights Reserved
Your evaluation period expires in 30 days.
You can buy Take Command and TCC at https://jpsoft.com

a is :test:
~a is :test:
a is :"test2":
~a is :test2:
But starting with tcc v21 the `%~I` construct expands to nothing:

Code:
C:\Program Files\JPSoft>TCC_RT_21\tcc c:\temp\test.cmd

TCC-RT  21.01.63 x64   Windows 10 [Version 10.0.17134]
Copyright 2017 JP Software Inc.  All Rights Reserved
a is :test:
~a is ::
a is :"test2":
~a is ::
 

rconn

Administrator
Staff member
May 14, 2008
11,021
98
The problem is that TCC thinks that any of the characters A D F N P S T X Z following a ~ is a special CMD FOR argument. In this case, the unfortunate use of A as the FOR variable confused TCC (since ~A means "display the file attributes"). If you use some other character (i.e., B C E G etc.) it will work in both TCC and CMD.

I will try to come up with a workaround for the next version, but this particular syntax is complicated as I'm already kludging around two CMD bugs.
 
Nov 6, 2014
18
0
Thanks. I hope you can come up with a workaround - I hit this with a third party script and have no idea if the author would accept a change request based on tcc compatibility. I can make the change locally easily enough though so it's certainly not an emergency.

Now that I look a little more closely at the cmd %~ modifier syntax I can see how it would be pretty painful to parse. I imagine you already know this, but I'll post what I concluded from 5 minutes of playing with cmd.exe's ~% expansion:

It looks like when cmd sees the %~modifier syntax, it does something like:

- as long as the next character is in the set [adfnpstxz] (upper or lower case) or is the FOR variable name (must match the FOR variable's case), push it on a stack
- when you reach a character that doesn't meet the above criteria, stop pushing
- pop characters off the stack until you reach the FOR variable

Now you know which is the FOR variable, and all the other characters on the stack are modifiers (repeated modifiers are ignored).

I haven't thought about how to fit the %~$PATH:I construct into that scheme.
 
Nov 6, 2014
18
0
When updating the script, I found that the likely reason that "A" was used as the FOR variable is because it makes it a bit easier to follow what token is going where when the FOR statement parses several tokens into sequential variables:

Code:
for /f "usebackq tokens=1,2,*" %%a in ('first second third') do (
    echo 1: %%a
    echo 2: %%b
    echo 3: %%c
)
Regardless, the workaround is in place here. Thanks.