Problems with calling script from enabledExpanion environmnt

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
carlsomo
Posts: 91
Joined: 02 Oct 2012 17:21

Problems with calling script from enabledExpanion environmnt

#1 Post by carlsomo » 05 Jul 2013 21:35

A previous topic related to masking input chars with '*' when collecting a password and was addressed with an 'Xcopy' solution that was pretty clever:

Code: Select all

 
  Set "key="
  For /F "delims=" %%# In (
     'Xcopy /L /W "%~f0" "%~f0" 2^>Nul'
  ) Do If Not Defined Key Set "Key=%%#"
  Set "Key=%Key:~-1%"
  SetLocal EnableDelayedExpansion


The string is built as long as 'Key' is defined by using:

Code: Select all

   For /F delims^=^ eol^= %%# In ("!Line!") Do (
     EndLocal&Set "Line=%%#%Key%"
  )


Once key is undefined (after enter is pressed) the routine returns the result:

Code: Select all

     For /F delims^=^ eol^= %%# In ("!Line!") Do (
        EndLocal&EndLocal&(
           Set "%~1=%%#"
           exit/b %length%
        )
     )

OK so this works great as long as the routine is called from the command line or called from another script when delayed expansion is disabled. However if you call the routine from an enabled expansion environment, i.e. from another script then you run into problems handling ^'s and !'s when returning the final string.

It seems that one must determine the calling environment conditionally as has successfully been done by jeb and dbenham by setting a flag:

setlocal
set "NotDelayedFlag=!"

So if this flag is defined the routine was called from a 'DisableDelayedExapnsion' environment or the command line.
Conversly if the flag is not defined then the script has to deal with returning ^'s and !'s.

Here is the full routine:

Code: Select all

:GetVar
:: SYNTAX: GetVar ^<EnVar^> [="User Prompt: "] [length] [/m]
::
:: Assigns User input to the Environment variable passed as 1st argument
:: Allows unbalance quotes and 'poison' characters mixed with quotes
:: The only editing key available to the User is 'backspace'
:: The user string entered is set in the Environment variable, 'Envar'
:: If no arguments are passed the routine quits, stand alone version displays this help
:: The fisrt argument is mandatory, the rest are optional
:: To display a variable with Poison chars and quotes use: Eco.bat
:: To mask input with '*'s place /m at the very end of the argument list
:: This routine has flaws if called from a Delayed Expansion environment
::
:: Example:
::
:: GetVar.bat Pa$$word="Enter your 'Poison Password' string: " len /m
:: Eco.bat "Your Poison Password is: '" Pa$$word "' with length: " len
:::
::: Dependencies - None           Author: Carl with ideas borrowed from Dostips.com
:::
  if "%~1"=="" goto :EndGetVar
  SetLocal DisableDelayedExpansion
  set "NotDelayedFlag=!"
  set "Masked="
  echo(%*|find " /m">nul
  if %errorlevel% equ 0 set "Masked=*"
  For /F %%# In ('"Prompt;$H&For %%# in (1) Do Rem"') Do Set "BS=%%#"
  Set "Line="
  if /i "%~2" neq "/m" <Nul set/p=".%BS% %BS%%~2"

  :Char_Loop_
  Set "Key="
  For /F "delims=" %%# In (
     'Xcopy /L /W "%~f0" "%~f0" 2^>Nul'
  ) Do If Not Defined Key Set "Key=%%#"
  Set "Key=%Key:~-1%"
  SetLocal EnableDelayedExpansion
  If Not Defined Key ( Rem Enter pressed
     echo(
     If not Defined Line EndLocal&EndLocal&(
        If Defined %~1 Set "%~1="
        If Defined %~3 Set/a "%~3=0
     )&exit/b 0
     For /F delims^=^ eol^= %%# In ("!Line!") Do (
        EndLocal&EndLocal&(
           If not "%~3"=="" Set/a "%~3=%length%"
           If Not "%~1"=="" (Set "%~1=%%#")
           exit/b %length%
        )
     )
  )
  If %BS%==^%Key% (
     Set "Key="
     If Defined Line set/a length-=1& Set "Line=!Line:~0,-1!"& Set /P "=%BS% %BS%" <Nul
  ) Else (
     If defined Masked (Set "Display=*") Else (Set "Display=!Key!")
     set/a length+=1& Set /p=".%BS%!Display!" <Nul
  )
  If Not Defined Line (
     EndLocal& Set/a length=1& Set "Line=%Key%"
  ) Else For /F delims^=^ eol^= %%# In ("!Line!") Do (
     EndLocal& Set/a length=%length%& Set "Line=%%#%Key%"
  )
  Goto :Char_Loop_
:EndGetVar
exit/b

:Eco "Here is a char: " char " and a string: " EnvarString /n "This is line two."
::
:: Echo's strings mixed with environment variables with or without CR/LF or embed CR/LF inside
:: Environment variables must be passed by name (not reference) and may contain poison chars
:: Quoted strings are echo'd as is and may have leading or trailing spaces do not quote Env vars
:: To place a newline (CF/LF) use '/n' unquoted
:::
::: Dependencies - None          Author: Carl with ideas borrowed from Dostips.com
:::
  SetLocal DisableDelayedExpansion
  For /F %%# In ('"Prompt;$H&For %%# in (1) Do Rem"') Do Set "BS=%%#"
  SetLocal EnableDelayedExpansion
  :Start_Eco
  if "%~1"=="" EndLocal&EndLocal&exit/b
  if /i "/n" equ "%~1" (
    echo(
  ) else if not defined %1 (
    set "string=.%BS%%~1"
    for /f delims^=^ eol^= %%# in ("!string!") do EndLocal& set/p="%%#" <nul
    SetLocal EnableDelayedExpansion
  ) else ( <nul set/p=".%BS%!%~1!")
  shift&goto :Start_Eco
:End_Eco


To make a long story short, the question is:
How to modify the routine so it returns any and all characters entered regardless if called from another routine with delayed expansion enabled?

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

Re: Problems with calling script from enabledExpanion enviro

#2 Post by jeb » 06 Jul 2013 02:27

Hi carlsomo,

carlsomo wrote:To make a long story short, the question is:
How to modify the routine so it returns any and all characters entered regardless if called from another routine with delayed expansion enabled?


I discussed this problem with Dave at Return ANY string across ENDLOCAL boundry

There is a general solution, a bit overkill for your problem, as we solved also the return value for linefeeds and carriage returns.

jeb

carlsomo
Posts: 91
Joined: 02 Oct 2012 17:21

Re: Problems with calling script from enabledExpanion enviro

#3 Post by carlsomo » 24 Jul 2013 22:18

thanks

Post Reply