anchor.diff:  :#   2010-11-16     Changed.                                                  #
   :#   2012-10-08 JFL Adapted to my %FUNCTION% library.                         #
   :#   2015-11-19 JFL Adapted to new %UPVAR% mechanism.                         #
  +:#   2016-11-11 JFL Avoid copying the input string. 5% faster.		      #
  +:#                  Added routine :strlen.q. No tracing but twice as fast.    #
   :#                                                                            #
   :#----------------------------------------------------------------------------#
   
   :strlen stringVar lenVar                -- returns the length of a string
  -%FUNCTION% enabledelayedexpansion
  -set "RETVAR=%~2"
  -if "%RETVAR%"=="" set "RETVAR=RETVAL"
  -set "str=A!%~1!" &:# keep the A up front to ensure we get the length and not the upper bound
  -		  :# it also avoids trouble in case of empty string
  +%FUNCTION% EnableDelayedExpansion
  +if "%~2"=="" %RETURN% 1 &:# Missing argument
  +%UPVAR% %~2
  +set "%~2=0"
  +if defined %~1 for /l %%b in (12,-1,0) do (
  +  set /a "i=(%~2|(1<<%%b))-1"
  +  for %%i in (!i!) do if not "!%~1:~%%i!"=="" set /a "%~2=%%i+1"
  +)
  +%RETURN%
  +
  +:strlen.q stringVar lenVar                -- returns the length of a string
  +setlocal EnableDelayedExpansion
   set "len=0"
  -for /L %%A in (12,-1,0) do (
  -  set /a "len|=1<<%%A"
  -  for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"
  -)
  -set "%RETVAR%=%len%" & %UPVAR% %RETVAR% & %RETURN%
  +if defined %~1 for /l %%b in (12,-1,0) do (
  +  set /a "i=(len|(1<<%%b))-1"
  +  for %%i in (!i!) do if not "!%~1:~%%i!"=="" set /a "len=%%i+1"
  +)
  +endlocal & if "%~2" neq "" set "%~2=%len%"
  +exit /b
   
   :#----------------------------------------------------------------------------#
   :#                                                                            #
  
positive.code: set "^!=^^^^^^^!"	&:# Define a %!%DelayedExpansion%!% variable
  set "'^!=^^^!"		&:# Idem, but inside a quoted string
  set ">=^^^>"		&:# Insert a redirection character
  set "&=^^^&"		&:# Insert a command separator in a macro
  :# Idem, to be expanded twice, for use in macros within macros
  set "^!2=^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!"
  
negative.code: call :trimright "%~1" "%~2"
  %UPVAR% %~1
  %RETURN%
  
  :#----------------------------------------------------------------------------#
  :#                                                                            #
  :#  Function        ReplaceXxxx						      #
  :#                                                                            #
  :#  Description     Replace tricky characters                                 #
  :#                                                                            #
  :#  Arguments                                                                 #
  :#                                                                            #
  :#  Notes 	    '*' '=' ':' cannot be replaced by %VAR:c=repl%            #
  :#                                                                            #
  :#  History                                                                   #
  :#   2016-11-13 JFL Added routine ReplaceChars.                               #
  :#                                                                            #
  :#----------------------------------------------------------------------------#
  
  :# Replace characters
  :# Advantage: Works with CHAR '=' ':' '*' '~'
  :# Advantage: The string can contain LF and '"' characters
  :# Drawback: Does not work with '='.
  :ReplaceChars STRVAR CHAR REPLACEMENT RETVAR 
  setlocal EnableDelayedExpansion
  set "STRING=!%~1!"
  set "REPL=%~3"
  set "RESULT="
  if defined STRING (
    call :strlen.q STRING SLEN	&:# SLEN = Full string length
  :ReplaceChars.again
    set "TAIL=!STRING:*%~2=!"	&:# Split STRING into HEAD CHAR TAIL
    call :strlen.q TAIL TLEN	&:# TLEN = Tail length
    if !TLEN!==!SLEN! (	:# No more C chars
      set "RESULT=!RESULT!!TAIL!"
    ) else (		:# Reached one char
      set /a "HLEN=SLEN-TLEN-1"	&:# HLEN = Head length
      for %%h in (!HLEN!) do set "RESULT=!RESULT!!STRING:~0,%%h!!REPL!"
      if defined TAIL (	:# Then there might be more chars in the tail
        set "STRING=!TAIL!"	&:# Repeat the same operation for the tail.
        set "SLEN=!TLEN!"
        goto :ReplaceChars.again
      )
    )
  )
  endlocal & set "%~4=%RESULT%"
  exit /b 0
  
  :# Replace delimiter sets.
  :# Advantage: Simple and fast; Works with CHAR '=' ':' '*'
  :# Drawback: Multiple consecutive CHARs are replaced by a single REPL string.
  :# Drawback: Does not work on strings with LF or '!' characters.
  :ReplaceDelimSets STRVAR CHAR REPLACEMENT RETVAR
  setlocal EnableDelayedExpansion
  set "STRING=[!%~1!]"	&:# Make mure the string does not begin or end with delims
  set "REPL=%~3"
  set "RESULT="
  :ReplaceDelimSets.loop
  for /f "delims=%~2 tokens=1*" %%s in ("!STRING!") do (
    set "RESULT=!RESULT!%%s"
    set "TAIL=%%t"
    if defined TAIL (	 :# Then there might be more chars to replace in the tail
      set "RESULT=!RESULT!!REPL!"
      set "STRING=!TAIL!"	&:# Repeat the same operation for the tail.
      goto :ReplaceDelimSets.loop
    )
  )
  endlocal & set "%~4=%RESULT:~1,-1%"
  exit /b
  
  :# Replace delimiters.
  :# Inspired by npocmaka post: http://www.dostips.com/forum/viewtopic.php?p=29901#p29901
  :# Advantage: Works with CHAR '=' ':' '*'
  :# Drawback: Does not work on strings with LF or '"' characters.
  :ReplaceDelims STRVAR CHAR REPLACEMENT RETVAR
  setlocal DisableDelayedExpansion
  call set "STRING=[%%%~1%%]"	&:# Make mure the string does not begin or end with delims
  set "REPL=%~3"
  set "RESULT="
  call :strlen.q STRING SLEN	&:# SLEN = Full string length
  :ReplaceDelims.loop
  for /f "delims=%~2 tokens=1*" %%s in ("%STRING%") do (
    set "HEAD=%%s"
    set "TAIL=%%t"
  )
  set "RESULT=%RESULT%%HEAD%"
  call :strlen.q HEAD HLEN	&:# HLEN = Head length
  call :strlen.q TAIL TLEN	&:# TLEN = Tail length
  set /a "N=SLEN-HLEN-TLEN"	&:# Number of delimiters in between
  setlocal EnableDelayedExpansion
  for /l %%n in (1,1,%N%) do set "RESULT=!RESULT!!REPL!"
  endlocal & set "RESULT=%RESULT%"
  if defined TAIL (	 :# Then there might be more chars to replace in the tail
    set "STRING=%TAIL%"	&:# Repeat the same operation for the tail.
    set "SLEN=%TLEN%"
    goto :ReplaceDelims.loop
  )
  endlocal & set "%~4=%RESULT:~1,-1%"
  exit /b
  
  :#----------------------------------------------------------------------------#
  :#                                                                            #
  