Thanks for all the great ideas published here! I've been happily using many in my scripts.
But when I tried using the function :Format in one of them, it gave incoherent results.
It took me quite a while to understand what was wrong. (Given its rather sophisticated implementation )
The root cause ended up to be that I was calling :Format from within a for loop, with the loop variable called %%c.
This caused references to %%const%% in the routine to yield the %%c value, then "onst", then garbage.
I suppose that there would have been similar failures if :Format had been called in a loop on %%f or %%l or %%s or %%i variables.
To avoid that, we must rename all local variables with a first character that is invalid for for %%variables.
Finding the right character is more difficult than it seems, because most printable characters are actually usable for %%variables, not just the 52 upper and lower case letters.
Here's an example that works using the ";" character, and that fixes my initial problem.
Jean-François
Code: Select all
:Format fmt str1 str2 ... -- outputs columns of strings right or left aligned
:: -- fmt [in] - format string specifying column width and alignment. Ex: "[-10] / [10] / []"
:$created 20060101 :$changed 20091130 :$categories Echo
:# Updated 20121026 JFL: Added tons of comments.
:# Fixed a bug if invoked in a loop on %%c or %%f or %%l or %%s or %%i.
:# Added an unspecified width format []. Useful for the last string.
:$source http://www.dostips.com
setlocal EnableExtensions DisableDelayedExpansion
set ";fmt=%~1" &:# Format string
set ";line=" &:# Output string. Initially empty.
set ";spac= "
set ";i=1" &:# Argument index. 1=fmt; 2=str1; ...
:# For each substring in fmt split at each "]"... (So looking like "Fixed text[SIZE]".)
for /f "tokens=1,2 delims=[" %%a in ('"echo..%;fmt:]=&echo..%"') do ( :# %%a=Fixed text before "["; %%b=size after "["
call set /a ";i=%%;i%%+1" &:# Compute the next str argument index.
call call set ";subst=%%%%~%%;i%%%;spac%%%%%~%%;i%%" &:# Append that str at both ends of the spacer
if "%%b"=="" ( :# Unspecified width. Use the string as it is.
call call set ";subst=%%%%~%%;i%%"
) else if %%b0 GEQ 0 ( :# Cut a left-aligned field at the requested size.
call set ";subst=%%;subst:~0,%%b%%"
) else ( :# Cut a right-aligned field at the requested size.
call set ";subst=%%;subst:~%%b%%"
)
call set ";const=%%a" &:# %%a=Fixed text before "[". Includes an extra dot at index 0.
call set ";line=%%;line%%%%;const:~1%%%%;subst%%" &:# Append the fixed text, and the formated string, to the output line.
)
echo.%;line%
endlocal & exit /b
PS. Why did you use "call ... %%variable%% ..." and not delayed expansion "... !variable! ..." ?
(Which would have avoided that problem altogether.)
PS2. Also it'd be nice to document in the header the limitations of the routine:
- Can format at most 8 strings.
- The format string cannot contain | < > & (The | is annoying, because it'd be very useful to display good-looking tables.)
- Each formatted field can be at most 53 characters long.