[solved] Merged input & output parameter in function ?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
MvGulik
Posts: 7
Joined: 08 Jun 2011 06:18

[solved] Merged input & output parameter in function ?

#1 Post by MvGulik » 08 Jun 2011 07:45

Hi

First post ... So big thanks to DosTips site for being there. Live saver when is comes to win/cmd/dos scripting.

Wondering about something. Is it possible to use a single var-name for both data-input and -output ?
I did see its possible when you use [set /A ..], but that's for numbers. But for string data all my attempts failed so far.
Looked closely at the general Functions help page at the DosTips website, but did not see anything in that direction either.

For example I have the following function.

Code: Select all

:NormalizeFilespec - <var:Output> <"path":input> -- "normalize + strip posible trailing (path) backslash."
:: returns (additional) error(1) if filespec(file/path) is not existing.
IF "%~1" EQU ""  ECHO Err(:NormalizeFilespec): missing first parameter.&EXIT 96001
IF "%~2" EQU ""  ECHO Err(:NormalizeFilespec): missing second parameter.&EXIT 96002
SETLOCAL
set "path=%~f2"
if "%path:~-1%" equ "\"   set "path=%path:~0,-1%"
if not exist "%path%" (set "err=123") else (set "err=0")
ENDLOCAL & set "%~1=%path%" & EXIT /b %err%

Could this also be done with just one function parameter ?

Code: Select all

:NormalizeFilespec - <var:Input/Output> -- "..."
:: how to get the data in variable X, which name is in $1 ?
Last edited by MvGulik on 08 Jun 2011 11:28, edited 1 time in total.

allal
Posts: 34
Joined: 04 Jun 2011 05:49

Re: Merged input & output parameter in function ?

#2 Post by allal » 08 Jun 2011 08:48

one var for input and output

Code: Select all

set var=c:\windows\
call :NormalizeFilespec var %var%
echo %var%
pause
:NormalizeFilespec - <var:Output> <"path":input> -- "normalize + strip posible trailing (path) backslash."
:: returns (additional) error(1) if filespec(file/path) is not existing.
IF "%~1" EQU ""  ECHO Err(:NormalizeFilespec): missing first parameter.&EXIT 96001
IF "%~2" EQU ""  ECHO Err(:NormalizeFilespec): missing second parameter.&EXIT 96002
SETLOCAL
set "path=%~f2"
if "%path:~-1%" equ "\"   set "path=%path:~0,-1%"
if not exist "%path%" (set "err=123") else (set "err=0")
ENDLOCAL & set "%~1=%path%" & EXIT /b %err%





one parameter as var



Code: Select all

set var=c:\windows\
call :NormalizeFilespec var
echo %var%

:NormalizeFilespec - <var:Input/Output> -- "..."
:: how to get the data in variable X, which name is in $1 ?
REM IF "%~1" EQU ""  ECHO Err(:NormalizeFilespec): missing first parameter.&EXIT 96001
REM IF "%~2" EQU ""  ECHO Err(:NormalizeFilespec): missing second parameter.&EXIT 96002
SETLOCAL
call set "path=%%%~1%%"
if "%path:~-1%" equ "\"   set "path=%path:~0,-1%"
call echo %path%
if not exist "%path%" (set "err=123") else (set "err=0")
ENDLOCAL & set "%~1=%path%" & EXIT /b %err%




hope this help

MvGulik
Posts: 7
Joined: 08 Jun 2011 06:18

Re: Merged input & output parameter in function ?

#3 Post by MvGulik » 08 Jun 2011 11:28

Yes it did.

"Call set ..." was someting that I ever seen or used before. But it also made clear why my attempts failed (after some more experimenting of course).
Relative new to using ENABLEDELAYEDEXPANSION ... which I forgot about in my attempts.

Ergo:

Code: Select all

:NormalizeFilespec2 - <var:Input/Output> -- "..."
SETLOCAL ENABLEDELAYEDEXPANSION
set path=!%~f1!
if "%path:~-1%" equ "\"   set "path=%path:~0,-1%"
if not exist "%path%" (set "err=123") else (set "err=0")
ENDLOCAL & set "%~1=%path%" & EXIT /b %err%


Thanks.
[edit: added missing 'f' parameter in "set [set path=!%~1!] part.] (Erm, yea, needed 3 edits for that.)
Last edited by MvGulik on 09 Jun 2011 08:52, edited 3 times in total.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: [solved] Merged input & output parameter in function ?

#4 Post by dbenham » 08 Jun 2011 13:44

The suggested new versions lose significant functionality compared to the original. They don't expand wildcards, nor do they normalize the path into a fully qualified path. They only make sure it doesn't end in \.

For example, given a path of test.txt The original might come back with something like C:\myDirectory\test.txt. The new versions just come back with test.txt

I have a solution that preserves the original functionality. But first some suggestions to improve the original:

1) Send the missing argument error messages to stderr instead of stdout.

2) The original exits the cmd shell if it is missing an argument. It is probably better just to exit the batch script.

3) You don't want to strip the final \ if the path represents the root directory. For example C:\ (the root directory) has entirely different meaning than C: (the current directory for C:). Rather than strip the last \, why not add a \ if the path represents a directory and the last character is not a \? In this way you can easily tell the difference between a file path and a directory path.

4) You don't want to get in the habit of defining a local PATH variable in your functions. It doesn't cause a problem in this case, but it will prevent you from executing an external command from within the function. Worse yet, if you forget to issue SETLOCAL, you will have corrupted your PATH for the remainder of your session!

Here is a modified version implementing the above suggestions:

Code: Select all

@echo off
:NormalizeFilespec - <var:Output> <"path":input> -- "normalize + guarantee \ at end of directory path"
:: returns (additional) error(123) if filespec(file/path) is not existing.
IF "%~1" EQU "" >&2 ECHO Err(:NormalizeFilespec): missing first parameter.&EXIT /b 96001
IF "%~2" EQU "" >&2 ECHO Err(:NormalizeFilespec): missing second parameter.&EXIT /b 96002
SETLOCAL
set "fpath=%~f2"
if "%fpath:~-1%" neq "\" dir "%fpath%\." >nul 2>nul && set "fpath=%fpath%\"
if not exist "%fpath%" (set "err=123") else (set "err=0")
ENDLOCAL & set "%~1=%fpath%" & EXIT /b %err%


And here is a version that requires only one argument. I replaced the missing second parameter error with one where variable is not defined:

Code: Select all

:NormalizeFilespec - <var:Input/Output> -- "normalize + guarantee \ at end of directory path."
:: returns (additional) error(123) if filespec(file/path) is not existing.
IF "%~1" EQU "" >&2 ECHO Err(:NormalizeFilespec): missing parameter.&EXIT /b 96001
IF not defined %~1 >&2 ECHO Err(:NormalizeFilespec): variable not defined - %~1&EXIT /b 96002
SETLOCAL enableDelayedExpansion
set "fpath=!%~1!"
for /f "eol=: delims=" %%a in ("!fpath!") do set "fpath=%%~fa"
if "!fpath:~-1!" neq "\" dir "!fpath!\." >nul 2>nul && set "fpath=!fpath!\"
if not exist "!fpath!" (set "err=123") else (set "err=0")
ENDLOCAL & set "%~1=%fpath%" & EXIT /b %err%
While delayed expansion is enabled, I like to restrict variable expansion to !var! form in case the contents contain ! or ^. Both of these characters can appear in a file name and the characters will not be preserved if you use %var% expansion while delayed expansion is enabled.


In case you really prefer to strip final \ from directory paths, unless root directory:

Code: Select all

:NormalizeFilespec - <var:Input/Output> -- "normalize + strip ending \ unless root"
:: returns (additional) error(123) if filespec(file/path) is not existing.
IF "%~1" EQU "" >&2 ECHO Err(:NormalizeFilespec): missing parameter.&EXIT /b 96001
IF not defined %~1 >&2 ECHO Err(:NormalizeFilespec): variable not defined - %~1&EXIT /b 96002
SETLOCAL enableDelayedExpansion
set "fpath=!%~1!"
for /f "eol=: delims=" %%a in ("!fpath!") do set "fpath=%%~fa"
if "!fpath:~-1!" equ "\" if "!fpath:~-2,1!" neq ":" set "fpath=!fpath:~0,-1!"
if not exist "!fpath!" (set "err=123") else (set "err=0")
ENDLOCAL & set "%~1=%fpath%" & EXIT /b %err%


Dave Benham

MvGulik
Posts: 7
Joined: 08 Jun 2011 06:18

Re: [solved] Merged input & output parameter in function ?

#5 Post by MvGulik » 09 Jun 2011 09:39

dbenham wrote:The suggested new versions lose significant functionality compared to the original. They don't expand wildcards, nor do they normalize the path into a fully qualified path. They only make sure it doesn't end in \.
Correct. Fixed missing 'f'.

1) Send the missing argument error messages to stderr instead of stdout.

2) The original exits the cmd shell if it is missing an argument. It is probably better just to exit the batch script.

3) You don't want to strip the final \ if the path represents the root directory. For example C:\ (the root directory) has entirely different meaning than C: (the current directory for C:). Rather than strip the last \, why not add a \ if the path represents a directory and the last character is not a \? In this way you can easily tell the difference between a file path and a directory path.

4) You don't want to get in the habit of defining a local PATH variable in your functions. It doesn't cause a problem in this case, but it will prevent you from executing an external command from within the function. Worse yet, if you forget to issue SETLOCAL, you will have corrupted your PATH for the remainder of your session!

1) Personal habit ... But your right. Error related messages should go to stderr.
2) ...
3) Forgot about the "X:\" root case. The stripping of the trailing '\' for path is related to a other code-language I use. Both cases (strip or add trailing '\', for path's only, have there merits.)
Need to give it some more thought ...
4) so true. :)

Thanks for feedback and code examples. Giving me some additional thinking and learning to do.
[Edit: +second quote]

Post Reply