<http://www.netikka.net/tsneti/info/tscmd018.htm>
Copyright © 2003- by Prof. Timo Salmi  
Last modified Sat 10-Nov-2012 21:46:00

 
Assorted NT/2000/XP/.. CMD.EXE Script Tricks
From the html version of the tscmd.zip 1cmdfaq.txt file
To the Description and the Index
 

This page is edited from the 1cmdfaq.txt faq-file contained in my tscmd.zip command line interface (CLI) collection. That zipped file has much additional material, including a number of detached .cmd script files. It is recommended that you also get the zipped version as a companion.

Please see "The Description and the Index page" for the conditions of usage and other such information.



18} How does one build re-usable script function modules?

The best way to get started is making the simplest possible example. Let's build and test one script function for addition and one for subtraction. The arguments are passed by reference.
  @echo off
  setlocal enableextensions
  call :FuncAdd 3 5 sum_
  echo The sum is %sum_%
  call :FuncSub 3 5 diff_
  echo The difference is %diff_%
  goto :EOF

  :FuncAdd arg1_ arg2_ return_
  setlocal enableextensions
    set /a return_=%1+%2
  endlocal & set "%3=%return_%" & goto :EOF

  :FuncSub arg1_ arg2_ return_
  setlocal enableextensions
    set /a return_=%1-%2
  endlocal & set "%3=%return_%" & goto :EOF

The output:
  D:\TEST>cmdfaq
  The sum is 8
  The difference is -2
The arguments on the line :FuncAdd arg1_ arg2_ return_ are, in fact, superfluous. They are permissible, though, and make for a better documentation.

How does one return the values of more than one variable from a subroutine? See the AssignSource module below. For another example see the JDinverse module in Item #31.

A much more complicated, modular true-life script built might serve as an example of subroutines in scripting. What this script actually does is besides the point. The point in this connection is its structure. Nevertheless, you might find Item #182 of some iterest.
  @echo off & setlocal enableextensions
 
  :: Assign a value for the temporary folder variable temp_
  call :AssignTemp temp_
 
  :: Create a four-digit random string
  call :Rand4 rand_
 
  :: Do not allow running simultaneous instances of the script
  call :CheckLock locked_
  if defined locked_ (
    if not defined cmdbox if defined PauseIfFromDesktop pause
    goto :EOF)
 
  :: Is help asked for
  if "%~1"==""   (call :programTitle & echo. & call :ProgramHelp & goto _out)
  if "%~1"=="?"  (call :programTitle & echo. & call :ProgramHelp & goto _out)
  if "%~1"=="/?" (call :programTitle & echo. & call :ProgramHelp & goto _out)
 
  :: The location of the PGP program on the PC
  :: pgp263i.zip Pretty Good Privacy RSA public key cryptography

  set pgpProg_=C:\_F\PGP\PGP.EXE
  if "%USERNAME%"=="qt" set pgpProg_=C:\_L\QT\PGP\PGP.EXE
  if not exist "%pgpProg_%" (call :NotFound "%pgpProg_%" & goto _out)
 
  :: Define the file to be decrypted and listed
  :: The module takes %~1 and it returns filename_ and filefold_
  call :AssignSource %~1 filename_ filefold_
 
  :: Check for the existence of the file to be decrypted
  if not exist "%filename_%" (call :NotFound "%filename_%" & goto _out)
 
  :: Check for wildcards, do not allow
  call :IsWild "%filename_%" wild_
  if defined wild_ goto _out
 
  :: Capture the foldername of the files' location
  if not defined filefold_ set filefold_=%~dp1
 
  :: Store the screen with PUSHSCR.EXE from tsutld25.zip
  c:\_f\tuki\pushscr %temp_%\lpgp%rand_%.scn /o
 
  :: Decrypt and list the file with PGP
  call :DecryptAndListFile "%filename_%"
 
  :: Restore the screen with POPSCR.EXE from tsutld25.zip
  c:\_f\tuki\popscr %temp_%\lpgp%rand_%.scn
  if exist "%temp_%\lpgp%rand_%.scn" del "%temp_%\lpgp%rand_%.scn" > nul
 
  :: Some concuding maitenance
  call :CleanUp
 
  :_out
  :: Release the lockfile. Pause if from GUI as per tscmd002.htm.
  for %%f in ("%temp_%\typepgpLockfile.tmp") do if exist %%f del %%f
  if not defined cmdbox if defined PauseIfFromDesktop pause
  endlocal & goto :EOF
 
  rem Start of the subroutine modules
 
  :programTitle
  echo +-----------------------------------------------------------+
  echo ^| TYPEPGP.CMD Type an encrypted file, wildcards not allowed ^|
  echo ^| Prof. Timo Salmi, Last modified Sat 3-Dec-2011            ^|
  echo +-----------------------------------------------------------+
  goto :EOF
 
  :AssignTemp
  setlocal
  set return_=%temp%
  if defined mytemp if exist "%mytemp%\" set return_=%mytemp%
  endlocal & set "%1=%return_%" & goto :EOF
 
  :Rand4
  setlocal
  set /a rand4_=%random% %% 10000
  set rand4_=0000%rand4_%
  set rand4_=%rand4_:~-4%
  endlocal & set "%1=%rand4_%" & goto :EOF
 
  :AssignSource
  setlocal
  set filename_=%~1
  set filefold_=
  if "%~1"=="/1" (
    set filename_=C:\_F\MYFOLD\MYLIST\PRIVATE.PGP
    set filefold_=C:\_F\MYFOLD\MYLIST\)
  if "%~1"=="/2" (
    set filename_=C:\_F\MYFOLD\MYLIST\QTLIST.PGP
    set filefold_=C:\_F\MYFOLD\MYLIST\)
  if "%~1"=="/3" (
    set filename_=C:\_F\MYFOLD\MYLIST\LOCALADM.PGP
    set filefold_=C:\_F\MYFOLD\MYLIST\)
  if "%~1"=="/4" (
    set filename_=C:\_D\MAIL\MYREGIS.PGP
    set filefold_=C:\_D\MAIL\)
  if not defined filefold_ set filefold_=%~dp1
  endlocal & set "%2=%filename_%" & set "%3=%filefold_%" & goto :EOF
 
  :NotFound
  call :programTitle
  echo.
  echo %1|findstr /c:"/">nul
  if %errorlevel% EQU 0 (echo %1 No such switch&echo.&call :programHelp)
  if %errorlevel% GTR 0 (echo %~1 not found)
  goto :EOF
 
  :IsWild
  set return_=
  echo %filename_%|findstr "[*?]">nul
  if %errorlevel% GTR 0 goto _endIsWild
  call :programTitle
  echo.
  echo Wildcards are not allowed in the file name
  set return_=true
  :_endIsWild
  endlocal & set "%2=%return_%" & goto :EOF
 
  :DecryptAndListFile
  setlocal
  set bn_=%~sn1
  set ext_=%~x1
  set fullname_=%filefold_%%~snx1
  if /i not "%ext_%"==".pgp" (
    call :programTitle
    echo.
    echo "%fullname_%" does not have a .PGP extension
    goto _endDecryptAndListFile)
  set path_=%path%
  set tz_=%TZ%
  set TZ=Europe/Helsinki
  SET PGPPATH=C:\_F\PGP
  if "%USERNAME%"=="qt" SET PGPPATH=C:\_L\QT\PGP
  SET PATH=%PGPPATH%;%PATH%
  @echo on
  %PGPPATH%\pgp -m "%fullname_%"
  @echo off
  set path=%path_%
  set path_=
  set TZ=%tz_%
  :_endDecryptAndListFile
  goto :EOF
 
  :CleanUp
  if /i not "%USERNAME%"=="me" goto _endCleanUp
  if exist "C:\WINDOWS\Temp\PRIVATE.$??" del /p "C:\WINDOWS\Temp\PRIVATE.$??"
  if exist "C:\WINDOWS\Temp\QTLIST.$??" del /p "C:\WINDOWS\Temp\QTLIST.$??"
  if exist "C:\WINDOWS\Temp\LOCALADM.$??" del /p "C:\WINDOWS\Temp\LOCALADM.$??"
  if exist "C:\WINDOWS\Temp\MYREGIS.$??" del /p "C:\WINDOWS\Temp\MYREGIS.$??"
  :_endCleanUp
  goto :EOF
 
  :CheckLock
  setlocal
  if exist "%temp_%\typepgpLockfile.tmp" (
    call :programTitle
    echo.
    echo An instance of TYPEPGP.CMD already is running
    echo If this is in error delete the lockfile
    echo "%temp_%\typepgpLockfile.tmp"
    if not defined cmdbox if defined PauseIfFromDesktop pause
    endlocal & set "%1=true" & goto :EOF)
  echo Lockfile "%temp_%\typepgpLockfile.tmp" for TYPEPGP.CMD>"%temp_%\typepgpLockfile.tmp"
  endlocal & set "%1=" & goto :EOF
 
  :ProgramHelp
  echo Usage: TYPEPGP [Filename^|/switch]
  echo  /1 = C:\_F\MYFOLD\MYLIST\PRIVATE.PGP
  echo  /2 = C:\_F\MYFOLD\MYLIST\QTLIST.PGP
  echo  /3 = C:\_F\MYFOLD\MYLIST\LOCALADM.PGP
  echo  /4 = C:\_D\MAIL\MYREGIS.PGP
  echo.
  echo To preset the password you can first use
  echo SET PGPPASS=YourPassword
  echo Afterwards it is prudent to erase the history e.g. with ALT-F7
  goto :EOF

There are a number of re-usable subroutines on these FAQ pages, including for example

AskQuestionWithYdefault   AssignTemp   BinToDecimal   BreakPoint   CheckDevice   checkVBS   ContinueOrNot   DecimalToBinary   DecimalToHex   DecimalToOctal   DisplayDateSizeName   EchoVbsN   FuncAdd   FuncRightJustify   GetDateTime   GetFirstChar   GetLabel   GetStrLength   GetVolSerialNr   HexToDecimal   InstrLastFN   IsAtPath   IsDeviceReady   IsFileFn   IsFolderFn   IsProgramAtPath   IsWildSub   JDdayNumber   JDweekNumber   LeadVar   OctToDecimal   ProcDelay   RemoveLeadingZeros   ShowFileinfo   ShowVarValue   SmallDelay   SubCount   TestForZeroFile   ToUpcase   TrimZeros   Uniq_id

  VBS:   FileAgeFn   GetAndShowPath   PadFn   PadLeftFn   RandomFn   ShowVolumeInfo   Slice   TraverseOneFolder   TraverseManyFolders   WeekNumJRS

Furthermore, see e.g.
  GetOneRandomChar in MAKEPASS.CMD and ToLowCase in NAMEDOWN.CMD
and
  #Item 300 of this FAQ collection.

References/Comments:
  Google Thread Jan 3 2009, 7:30 pm