Page 1 of 1

Bug in function :Format

Posted: 26 Oct 2012 07:22
by jfl
Hello,

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.

Re: Bug in function :Format

Posted: 27 Oct 2012 11:57
by Ed Dyreen
'
Hi Jean,

If I were admin, I would like to know about any bugs, did you send a pm ? Maybe u should..

Code: Select all

set ;=true
set ;
echo.%;%
Set won't print, but echo will, that's pretty neat :)

Re: Bug in function :Format

Posted: 30 Oct 2012 08:58
by timbertuck
Ed Dyreen wrote:'
Hi Jean,

Code: Select all

set ;=true
set ;
echo.%;%
Set won't print, but echo will, that's pretty neat :)


i wondered how to get to those hidden SET params, glad to have an answer to that.
so now i can do this
echo %=c:%
which gets me the current directory. maybe nothing, maybe something...

also echo %=exitcode%