:: For more information on the shell builtins used in this script, open a DOS :: command prompt, and type "help ": :: - cd :: - cmd :: - del :: - echo :: - endlocal :: - exit :: - findstr :: - for :: - goto :: - if :: - pause :: - prompt :: - set :: - setlocal :: - shift :: - title :: :: Some interesting Windows scripting notes that will be of help in :: understanding this launch script: :: - If you invoke echo with a variable that evaluates to the empty string, :: echo will print a status message, not an empty string itself. :: "help echo" for more info. :: - Since the equals sign is a metacharacter used in string substitutions, :: it's very difficult to replace it with something else. Also, when :: doing text processing, particularly with invocations of the set builtin, :: equals signs are interpreted as spaces; this is inexplicable but very :: much the case. We hedge against this below by replacing the equals sign :: character in arguments (e.g. "-Dx=y") with a unique token so that it may :: be restored later. :: - Although Windows scripting now allows you to perform blocks of operations :: within a conditional or loop, the command processor isn't intelligent :: about handling instances of the block metacharacters (the parenthesis :: characters, in this case) as values in dereferenced variables. This :: causes problems if you want to, say, pass an ASCII property list :: representation of a string as a value for, say, NSProjectSearchPath. :: As with the equals sign, we replace these characters with unique tokens :: so that the characters may be restored later. This token replacement :: is much simpler for these characters than it is for the equals sign :: character, though. :: - When you echo the character sequence "%%", it collapses to a single "%". :: - We need to create temporary, helper scripts, and sometimes these scripts :: echo text to another file. This is a problem when generating the helper :: script on the fly, because the act of generating the script itself :: involves echo text to a file; you run into the difficulty of having :: stdout redirected twice on the same line, which would confuse the command :: interpreter. We rely on an old DOS trick of abusing the prompt builtin to :: hack together sketchy character sequences in a subshell and harvest the :: resulting prompt and echo *that* to the script. All uses of the prompt :: builtin address this problem alone. You'll notice that the script line :: up to the "prompt" keyword is identical in every instance; for more info :: check "help cmd", "help for" and "help prompt". This is a trick :: that should be documented in various Windows scripting sites on the WWW. :: - Windows scripting doesn't treat single quotes specially. Don't use single :: quotes to quote arguments (e.g. arguments that contain spaces) to pass to :: this launch script. :: - Setting a variable like "set BLAH=" is the same semantic for undefining a :: variable. Instead of checks for whether the value of the variable is :: empty, all we have to do is check whether the variable is defined. :: Unfortunately, this sort of check doesn't work for automatic variables :: such as those used by for loops (e.g. "%%a", etc). :: - If you echo a variable where the last character of the value is a number, :: and you redirect this echo to a file, the command processor will try to :: interpret the number as a file descriptor (e.g. "1>" means stdout, "2>" :: means stderr), regardless of the number, and will effectively eat the :: number. This causes big problems if you pass arguments to the script :: like "-DNSDebugLevel=1". You need to ensure that a space always follows :: the echo invocation before the redirection. :: Turn off echo. @echo off ::@echo on :: Use the setlocal builtin to test whether we're running on a supported version :: of Windows. If not, exit. set BADWINVR=no setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION if errorlevel 1 set BADWINVR=yes if not "%BADWINVR%"=="no" ( echo This version of WebObjects is not supported on this version of Windows. Terminating. 1>&2 set BADWINVER= if not "%NOPAUSE%"=="yes" pause exit /B 1 ) endlocal set BADWINVER= :: Unfortunately, the scripting environment isn't very intelligent about what :: changes it considers "local". If setlocal is active, changes made in for :: loops have no cumulative effect (the changes are local to that iteration of :: the for loop). So we can't use setlocal for its main behavior. We will :: also unset any variables that might have been left laying around in a :: previous launch in this same shell and that aren't explicitly cleared or :: initialized before their first use. set ARGLIST= set JAVAARGS= set JVARGS= set JXARGS= set NONXARGS= set TEMPARGS= set THEARGS= :: Grab the path to the current working directory, before we change directories :: into the application wrapper. :: We need this for the benefit of applications like JavaConverter. for /F "tokens=*" %%a in ('cd') do set CURRDIR=%%~fsa set CURRDIR=%CURRDIR:\=/% :: Change directory to the location of the WebObjects application. :: The first line changes the drive letter. %~d0 cd "%~p0" :: Change the titlebar for this window. set APPNAME=%~n0 title %APPNAME%.woa :: Argument for the Windows launch script only: :: -WONoPause YES: Do not execute pauses for user input during startup set NOPAUSE=no echo %* | findstr /I /R /C:"WONoPause *true" /C:"WONoPause *YES" /C:"WONoPause=true" /C:"WONoPause=YES" > nul 2> nul if not errorlevel 1 set NOPAUSE=yes echo Configuring launch environment for %~n0 ... :: Keep track of the failure state. Try to log as many error conditions :: at once as possible. set FAILURE=no if not defined TEMP echo TEMP environment variable is not defined -- define it and relaunch! 1>&2 if not defined TEMP set FAILURE=yes :: Figure out where the launch configuration activity needs to occur. :: Scratch files will be created there. :: We prefer to use the short version of TEMP (SDRNM). for /F "tokens=*" %%a in ("%TEMP%") do set SDRNM=%%~fsa :: These are all of the scratch files used to configure and launch the app. :: NOTE: There had better be no spaces in any of these directories :: or filenames, hence the use of SDRNM. set APPID=%APPNAME%-%RANDOM% set ARGCMD1FL=%SDRNM%\%APPID%-1.CMD set ARGCMD2FL=%SDRNM%\%APPID%-2.CMD set ARGCMD3FL=%SDRNM%\%APPID%-3.CMD set ARG1FL=%SDRNM%\%APPID%-4.TXT set ARG2FL=%SDRNM%\%APPID%-5.TXT set ARG3FL=%SDRNM%\%APPID%-6.TXT set ARG4FL=%SDRNM%\%APPID%-7.TXT set ARG5FL=%SDRNM%\%APPID%-8.TXT set ARG6FL=%SDRNM%\%APPID%-9.TXT set CLSFL=CONTENTS\WINDOWS\CLSSPATH.TXT set JARGFL=%SDRNM%\%APPID%-10.TXT set JXARGFL=%SDRNM%\%APPID%-11.TXT :: These environment variables vary for each system and/or user. :: The script variables set as a result will be used to create real :: paths out of the abstractions in the classpath file. :: NOTE: There might be a relevant complaint from above about the :: lack of the TEMP environment variable. if not defined NEXT_ROOT echo NEXT_ROOT is not defined -- WORootDirectory and WOLocalRootDirectory set to empty string! 1>&2 if not defined NEXT_ROOT goto ENDROOTDEF for /F "tokens=*" %%a in ("%NEXT_ROOT%") do set WOROOT=%%~fa set WOROOT=%WOROOT:\=/% for /F "tokens=*" %%a in ("%NEXT_ROOT%\Local") do set LOCALROOT=%%~fa set LOCALROOT=%LOCALROOT:\=/% :ENDROOTDEF :: Quit if there were problems getting crucial environment variables. :: NOTE: Don't remove the scratch directory if it's somehow being reused. if not "%FAILURE%"=="no" if not "%NOPAUSE%"=="yes" pause if not "%FAILURE%"=="no" exit /B 1 :: When we run an app, we might be in the top-level directory or in the :: Contents\Windows directory. We want to be in the top-level directory, so :: if we cannot find the CLSSPATH.TXT file in Contents\Windows\CLSSPATH.TXT, :: then we change directory two levels up. if not exist %CLSFL% cd ..\.. :: These are the arguments passed to the script. set THEARGS=%* :: If there are no command-line args, skip argument processing. if not defined THEARGS goto ENDHANDLEARGS :: Several characters that might be in the argument are script metacharacters. :: If so, replace them with unique tokens for later reversion. if defined THEARGS set THEARGS=%THEARGS:(=LeftParenthesisToken% if defined THEARGS set THEARGS=%THEARGS:)=RightParenthesisToken% :: Determine which launch args we want to pass directly to the JVM (beginning :: with -D and containing an = sign) and build a string with just those args. :: This requires two steps: :: First, we need to substitute a special delimiter string for the '=' :: character because, while we can use %1, %2, ... to handle spaces in our :: arguments, those conventions handle the '=' sign in a very strange way. :: NOTE: Besides the complication of handling spaces in argument values, :: some old-style arguments start with "-D" (e.g. "-D2WSomeOption YES"). echo %THEARGS% > %ARG1FL% echo @echo off> %ARGCMD1FL% ::echo @echo on> %ARGCMD1FL% echo set ARGLIST=>> %ARGCMD1FL% echo :SUBSTEQ>> %ARGCMD1FL% echo for /F "tokens=1* delims==" %%%%i in (%ARG1FL%) do (>> %ARGCMD1FL% echo if defined ARGLIST (>> %ARGCMD1FL% echo set ARGLIST=!ARGLIST!EqualsDelimiterToken>> %ARGCMD1FL% echo )>> %ARGCMD1FL% echo set ARGLIST=!ARGLIST!%%%%i>> %ARGCMD1FL% echo if not '%%%%j'=='' (>> %ARGCMD1FL% cmd /A /X /C for /L %%v in (1,1,2) do prompt echo %%%%j $g %ARG1FL% $_| findstr /V "$g" | findstr /V /R "^$">> %ARGCMD1FL% echo goto :SUBSTEQ>> %ARGCMD1FL% echo )>> %ARGCMD1FL% echo )>> %ARGCMD1FL% cmd /A /X /C for /L %%v in (1,1,2) do prompt if defined ARGLIST echo !ARGLIST! $g %ARG2FL% $_| findstr /V "$g" | findstr /V /R "^$">> %ARGCMD1FL% cmd /V:ON /A /X /C %ARGCMD1FL% set TEMPARGS= :: NOTE: TEMPARGS now contains all of the command line args with "=" replaced :: by "EqualsDelimiterToken". if exist %ARG2FL% for /F "tokens=*" %%a in (%ARG2FL%) do set TEMPARGS=%%a :: Second, we break the args each on one line for ease of processing, :: taking advantage of one of the few shell-like behaviors of batch :: scripting -- arg processing. :: Then, we separate -X (JVM-specific) args from all others and write them to :: two different files. echo @echo off> %ARGCMD2FL% ::echo @echo on> %ARGCMD2FL% echo :PARSARGS>> %ARGCMD2FL% echo if not '%%1'=='' (>> %ARGCMD2FL% cmd /A /C for /L %%v in (1,1,2) do prompt echo %%1 $g$g %ARG3FL% $_| findstr /V "$g" | findstr /V /R "^$">> %ARGCMD2FL% echo shift>> %ARGCMD2FL% echo goto :PARSARGS>> %ARGCMD2FL% echo )>> %ARGCMD2FL% echo set JXARGS=>> %ARGCMD2FL% echo if exist %ARG3FL% for /F "tokens=*" %%%%a in ('findstr /R "\-X.*" %ARG3FL%') do (>> %ARGCMD2FL% echo if not '%%%%a'=='' (>> %ARGCMD2FL% echo set JXARGS=!JXARGS!%%%%a>> %ARGCMD2FL% echo )>> %ARGCMD2FL% echo )>> %ARGCMD2FL% cmd /A /C for /L %%v in (1,1,2) do prompt if defined JXARGS echo !JXARGS! $g$g %JXARGFL% $_| findstr /V "$g" | findstr /V /R "^$">> %ARGCMD2FL% echo set TEMPARGS=>> %ARGCMD2FL% echo if exist %ARG3FL% for /F "tokens=*" %%%%a in ('findstr /V /R "\-X.*" %ARG3FL%') do (>> %ARGCMD2FL% echo if not '%%%%a'=='' (>> %ARGCMD2FL% echo set TEMPARGS=!TEMPARGS!%%%%a>> %ARGCMD2FL% echo )>> %ARGCMD2FL% echo )>> %ARGCMD2FL% cmd /A /C for /L %%v in (1,1,2) do prompt if defined TEMPARGS echo !TEMPARGS! $g$g %ARG4FL% $_| findstr /V "$g" | findstr /V /R "^$">> %ARGCMD2FL% cmd /V:ON /A /X /C %ARGCMD2FL% %TEMPARGS% :: Third, we read back in the separated args. set TEMPARGS= :: NOTE: TEMPARGS now contains all of the command line args with "=" replaced :: by "EqualsDelimiterToken", sans any arguments that start with "-X". :: "-X" arguments end up in JXARGS. if exist %ARG4FL% for /F "tokens=*" %%a in (%ARG4FL%) do set TEMPARGS=%%a set JXARGS= if exist %JXARGFL% for /F "tokens=*" %%a in (%JXARGFL%) do set JXARGS=%%a set JXARGS=-Xrs %JXARGS% :: Fourth, we need to examine each argument to see if it meets our format :: requirement (-D*=*) and if so then include it in our Java arguments string, :: and replace the '=' delimiter string at the end. :: Lastly, read back in all non-"-X" args and repopulate THEARGS. echo @echo off> %ARGCMD3FL% ::echo @echo on> %ARGCMD3FL% echo :PARSARGS>> %ARGCMD3FL% echo if not '%%1'=='' (>> %ARGCMD3FL% cmd /A /C for /L %%v in (1,1,2) do prompt echo %%1 $g$g %ARG5FL% $_| findstr /V "$g" | findstr /V /R "^$">> %ARGCMD3FL% echo shift>> %ARGCMD3FL% echo goto :PARSARGS>> %ARGCMD3FL% echo )>> %ARGCMD3FL% echo set JVARGS=>> %ARGCMD3FL% echo for /F "tokens=*" %%%%a in ('findstr /R "\-D.*EqualsDelimiterToken.*" %ARG5FL%') do if not '%%%%a'=='' set JVARGS=!JVARGS!%%%%a>> %ARGCMD3FL% cmd /A /X /C for /L %%v in (1,1,2) do prompt if defined JVARGS echo %%JVARGS:EqualsDelimiterToken==%% $g %JARGFL% $_| findstr /V "$g" | findstr /V /R "^$">> %ARGCMD3FL% echo set NONXARGS=>> %ARGCMD3FL% echo for /F "tokens=*" %%%%a in (%ARG5FL%) do if not '%%%%a'=='' set NONXARGS=!NONXARGS!%%%%a>> %ARGCMD3FL% cmd /A /C for /L %%v in (1,1,2) do prompt if defined NONXARGS echo %%NONXARGS:EqualsDelimiterToken==%% $g$g %ARG6FL% $_| findstr /V "$g" | findstr /V /R "^$">> %ARGCMD3FL% cmd /V:ON /A /X /C %ARGCMD3FL% %TEMPARGS% :: Reset THEARGS here, because we want to prune all the -X args from the args :: given to the woapp, not just copy them to the front of the arg list. if exist %ARG6FL% for /F "tokens=*" %%a in (%ARG6FL%) do set THEARGS=%%a set JAVAARGS= if exist %JARGFL% for /F "tokens=*" %%a in (%JARGFL%) do set JAVAARGS=%%a set JAVAARGS=%JXARGS% %JAVAARGS% :: Restore script metacharacters in the arguments (see above). if defined THEARGS set THEARGS=%THEARGS:LeftParenthesisToken=(% if defined THEARGS set THEARGS=%THEARGS:RightParenthesisToken=)% if defined JAVAARGS set JAVAARGS=%JAVAARGS:LeftParenthesisToken=(% if defined JAVAARGS set JAVAARGS=%JAVAARGS:RightParenthesisToken=)% :: Delete any scratch files previously used for argument processing. del /F /Q %ARG1FL% %ARG2FL% %ARG3FL% %ARG4FL% %ARG5FL% %ARG6FL% %ARGCMD1FL% %ARGCMD2FL% %ARGCMD3FL% %JARGFL% %JXARGFL% > nul 2> nul :ENDHANDLEARGS :: Read in the configuration information from the comment "header" at the :: beginning of the classpath file. This information will be used when :: creating the scratch script that will actually invoke the JVM below. for /F "tokens=1,2,3*" %%a in (%CLSFL%) do if /I "%%b"=="ApplicationClass" set APPCLS=%%d for /F "tokens=1,2,3*" %%a in (%CLSFL%) do if /I "%%b"=="JDB" set JDB=%%d for /F "tokens=1,2,3*" %%a in (%CLSFL%) do if /I "%%b"=="JDBOptions" set JDBOPTS=%%d for /F "tokens=1,2,3*" %%a in (%CLSFL%) do if /I "%%b"=="JVM" set JVM=%%d for /F "tokens=1,2,3*" %%a in (%CLSFL%) do if /I "%%b"=="JVMOptions" set JVMOPTS=%%d :: Set certain configuration information to defaults, if not specified in the :: comment "header" at the beginning of the classpath file. if not defined APPCLS set APPCLS=Application if not defined JDB set JDB=jdb if not defined JVM set JVM=java :: Even in the case of no command-line args, we need to pass certain arguments :: used by the WebObjects runtime. set JAVAARGS=%JAVAARGS% -DWORootDirectory="%WOROOT%" -DWOLocalRootDirectory="%LOCALROOT%" -DWOUserDirectory="%CURRDIR%" if not defined CLASSPATH goto ENDENVCPDEF set JAVAARGS=%JAVAARGS% -DWOEnvClassPath="%CLASSPATH:\=/%" :ENDENVCPDEF set JAVAARGS=%JAVAARGS% -DWOApplicationClass=%APPCLS% -DWOPlatform=Windows :: Determine whether the debugger or the JVM should be invoked. set JAVAEXE=%JVM% set DEBUG=no echo %THEARGS% | findstr /C:NSPBDebug /C:NSJavaDebug > nul 2> nul if not errorlevel 1 set DEBUG=yes if "%DEBUG%"=="yes" set JAVAEXE=%JDB% if "%DEBUG%"=="yes" set JVMOPTS=%JVMOPTS% %JDBOPTS% :: Launch the application. echo Launching %~n0. echo %JAVAEXE% %JVMOPTS% %JAVAARGS% -classpath WOBootstrap.jar com.webobjects._bootstrap.WOBootstrap %THEARGS% call %JAVAEXE% %JVMOPTS% %JAVAARGS% -classpath WOBootstrap.jar com.webobjects._bootstrap.WOBootstrap %THEARGS% :: Capture the exit code returned by the JVM (important in the event :: of an error). set RETVAL=%ERRORLEVEL% :: Return the exit code provided by the terminated Java process. if not "%NOPAUSE%"=="yes" pause exit /B %RETVAL%