Hello, I don't know where else to post this But I made a bunch of batch file function that relate to launching jscript from batch files efficiently I would have posted it on the dostip forum, but they have been down for months Code: @if (@X)==(@Y) @end /* batch+jscript hybrid header @echo off :: ============================================================================ :: BATCH+JSCRIPT HYBRID — HOW-TO :: ============================================================================ :: :: This block documents how to use the Dispatch function (defined further down :: in this file) to call JScript functions from a plain batch script. :: :: It is organized so you can stop reading after the Quick Start and have :: everything you need. The rest is reference material for less common cases. :: :: 1. Quick Start <- read this, you can stop here :: 2. The minimum hybrid file :: 3. How to call a JScript function :: 4. How the hybrid trick works (one minute) :: 5. Other call modes (reference) :: 6. Common gotchas :: 7. Dispatch reference (env vars, modes, return codes) :: :: ============================================================================ :: 1. QUICK START :: ============================================================================ :: :: To call a JScript function from a batch script, your .bat file needs :: exactly five things: :: :: 1. First line of the file: :: @if (@X)==(@Y) @end / * batch+jscript hybrid header :: :: 2. Last line of the file: :: batch+jscript hybrid trailer * / :: :: 3. One launcher line, anywhere in a JS island: :: * / WScript.Quit(Dispatch()); / * :: :: 4. The Dispatch function, in a JS island. :: :: 5. Your target JScript function(s), each in a JS island. :: :: That is all. You can stop reading here and use the framework. :: :: A "JS island" is any line (or block) bracketed by * / and / *. The brackets :: temporarily expose JScript to the interpreter; everything outside them is :: hidden from JScript inside one big comment that wraps the file. Section 4 :: explains why this works. :: :: To call your JScript function from the batch section of the file: :: :: cscript //E:JScript //nologo "%~d0\:FunctionName:\..\%~pnx0" [args...] :: :: Replace FunctionName with whatever your JScript function is called. :: Arguments after the path are passed through to the function normally. :: :: ============================================================================ :: 2. THE MINIMUM HYBRID FILE :: ============================================================================ :: :: Here is a complete, working hybrid file that prints "hello world": :: :: @if (@X)==(@Y) @end / * batch+jscript hybrid header :: @echo off :: cscript //E:JScript //nologo "%~d0\:Greet:\..\%~pnx0" "world" :: goto :EOF :: :: * / WScript.Quit(Dispatch()); / * :: :: * / function Greet(who) { :: WScript.Echo("hello " + who); :: return 0; :: } / * :: :: * / function Dispatch() { / * ...the Dispatch body goes here... * / } / * :: :: batch+jscript hybrid trailer * / :: :: Save as anything.bat and run. Output: hello world :: :: Add as many target functions as you want; each gets its own JS island. :: The order of islands does not matter — JScript hoists function declarations. :: :: ============================================================================ :: 3. CALLING A JSCRIPT FUNCTION FROM BATCH :: ============================================================================ :: :: The canonical call form is: :: :: cscript //E:JScript //nologo "%~d0\:FunctionName:\..\%~pnx0" [args...] :: :: %~d0 drive letter of this batch file (e.g. C:) :: %~pnx0 path + name + extension of this batch file :: :Name: the JScript function name to call, wrapped in colons :: \..\ cancels the synthetic :Name: segment for path resolution :: :: Examples: :: :: cscript //E:JScript //nologo "%~d0\:Greet:\..\%~pnx0" :: cscript //E:JScript //nologo "%~d0\:Greet:\..\%~pnx0" "world" :: cscript //E:JScript //nologo "%~d0\:Compute:\..\%~pnx0" "42" "rounding=on" :: :: If you'd rather not type the full path every time, the optional :: :SelfCallJs helper (also in this file) lets you write: :: :: set "SelfCallJs=Greet" & call :SelfCallJs "world" :: :: ============================================================================ :: 4. HOW THE HYBRID TRICK WORKS (one minute) :: ============================================================================ :: :: A hybrid file is one .bat file that two different interpreters read: :: - cmd.exe sees it as batch. :: - cscript.exe (with //E:JScript) sees it as JScript. :: :: Each language has to be hidden from the other one. The mechanism is :: comments. :: :: JScript uses / * ... * / for multi-line comments (like C). :: Batch uses :: (or REM) for line comments. :: :: The hybrid file's default state is "batch with JScript hidden": :: :: - The HEADER line ends in / * which opens a JScript multi-line comment. :: - The TRAILER line begins with * / which closes it. :: - Everything between is one giant comment from JScript's point of view. :: :: So when JScript reads the file, it sees nothing but one big comment — :: unless you "punch out" of that comment. A line like: :: :: * / function Greet(who) { WScript.Echo("hello " + who); return 0; } / * :: :: ...closes the comment with * / , defines a JScript function, then reopens :: the comment with / *. That exposed region is what we call a "JS island". :: :: cmd.exe never sees JS island lines as executable batch — control flow :: never reaches them (they sit below the goto :EOF in your batch section, :: or are simply skipped over). :: :: When cscript runs the file, the LAUNCHER line: :: :: * / WScript.Quit(Dispatch()); / * :: :: ...is the one top-level statement that actually executes. Every other :: island is just a function declaration. JScript hoists function declarations :: to the top of the script, so the launcher can appear before or after the :: Dispatch declaration in source order — both work. :: :: The synthetic path "%~d0\:Greet:\..\%~pnx0" is how the function name :: travels from batch into JScript: :: :: - Windows path normalization treats \..\ as "go up one directory", :: which cancels out the synthetic :Greet: segment. The path resolves :: to the real file, so cscript opens it correctly. :: :: - But the original, un-normalized command line lives on in the cscript :: process's record. Dispatch reads it back via WMI and extracts the :: "Greet" name. :: :: - Dispatch then looks up the function by that name and calls it. :: :: That is the entire mechanism. :: :: ============================================================================ :: 5. OTHER CALL MODES (reference) :: ============================================================================ :: :: Beyond named functions, Dispatch supports several other modes. Reach for :: them when you need dynamic code, generated code, or want to avoid defining :: a permanent function. These modes use plain cscript on "%~f0" with no :: path-injection — Dispatch picks a mode by inspecting environment variables. :: :: They also run faster than named dispatch (no WMI lookup needed). :: :: --- Direct code in an environment variable --------------------------------- :: :: set "dispatch=WScript.Echo('hello');" & cscript //E:JScript //nologo "%~f0" :: set "dispatch=" :: :: --- Code in another env var (indirect) ------------------------------------- :: :: set "mycode=WScript.Echo('hello');" :: set "dispatch.codevar=mycode" :: cscript //E:JScript //nologo "%~f0" :: set "dispatch.codevar=" & set "mycode=" :: :: --- Multi-line code in a pseudoarray --------------------------------------- :: :: set "lines[0]=function f(a) {" :: set "lines[1]= WScript.Echo('arg=' + a);" :: set "lines[2]= return 0; }" :: set "lines[3]=WScript.Quit(f(WScript.Arguments(0)));" :: set "lines.ubound=3" :: set "dispatch.codearray=lines" :: cscript //E:JScript //nologo "%~f0" "hello" :: set "dispatch.codearray=" & set "lines.ubound=" :: for /l %%N in (0,1,3) do set "lines[%%N]=" :: :: --- Code from a labeled range in a file ------------------------------------ :: :: :: place this elsewhere in the file: :: :: :MyJs_start :: :: function f() { WScript.Echo('from a range'); return 0; } f(); :: :: :MyJs_end :: :: set "dispatch.file=%~f0" :: set "dispatch.range=MyJs_start MyJs_end" :: cscript //E:JScript //nologo "%~f0" :: set "dispatch.file=" & set "dispatch.range=" :: :: --- Code as command-line arguments (argv-code) ----------------------------- :: :: With no dispatch env source set, args before "--" are treated as lines of :: code. Args after "--" become the global DispatchArgs array. :: :: cscript //E:JScript //nologo "%~f0" "WScript.Echo('hello');" :: :: cscript //E:JScript //nologo "%~f0" ^ :: "function f(a,b) { WScript.Echo(a+' '+b); return 0; }" ^ :: "WScript.Quit(f(DispatchArgs[0], DispatchArgs[1]));" ^ :: -- "hello" "world" :: :: --- Function with one array argument --------------------------------------- :: :: For functions shaped like "function f(args) { ... }": :: :: set "dispatch.argtype=array" :: cscript //E:JScript //nologo "%~d0\:MyArrayFn:\..\%~pnx0" "a" "b" "c" :: set "dispatch.argtype=" :: :: ============================================================================ :: 6. COMMON GOTCHAS :: ============================================================================ :: :: - The launcher MUST be a top-level statement. Don't wrap :: WScript.Quit(Dispatch()) inside a function — if you do, nothing runs :: when cscript starts the file. :: :: - Only function DECLARATIONS are hoisted. Use: :: function Dispatch() { ... } :: not: :: var Dispatch = function() { ... } :: ...or the launcher will fail with "Dispatch is undefined" because the :: var assignment happens at runtime in source order, after the launcher. :: :: - "The system cannot find the path specified" from a hybrid call almost :: always means the synthetic path is malformed. The exact form is: :: "%~d0\:Name:\..\%~pnx0" :: Two colons around the name, two backslashes (the inner one and the :: one before "..\"), all forward slashes are wrong. :: :: - Always use cscript with //E:JScript, never wscript. wscript pops a GUI :: dialog for every WScript.Echo, which is not what you want from a batch. :: :: - The header MUST be the first line of the file. The trailer MUST be the :: last line. Anything before/after will break one or both interpreters. :: No blank line before the header. No trailing blank line after the :: trailer (or at least nothing that disturbs the closing * / ). :: :: - Inside a JS island, you can use / * ... * / comments normally, even :: though the outer hybrid framing also uses them. JScript's parser :: handles the nesting correctly: * / closes the nearest open / *. Don't :: try to nest / * / * ... * / * / — that won't work. :: :: - If your batch calls a JScript function inside a parenthesized block :: (like a FOR loop body), %errorlevel% won't update mid-block due to :: batch's expansion timing. Use "call set" or delayed expansion to :: capture the exit code reliably. :: :: ============================================================================ :: 7. DISPATCH REFERENCE :: ============================================================================ :: :: Dispatch resolves what to run by checking sources in this priority order: :: :: 1. Path-injected function name :: Recovered from the cscript command line via WMI when the script was :: launched with "%~d0\:Name:\..\%~pnx0". :: :: 2. dispatch :: Direct JScript code in this environment variable. :: :: 3. dispatch.codevar :: Name of another env var that holds the JScript code. :: :: 4. dispatch.codearray :: Name of a pseudoarray of code lines. Lines are joined with \r\n. :: Uses <name>[0] through <name>.ubound (inclusive). :: :: 5. dispatch.range / dispatch.start / dispatch.end :: Labeled code range read from a file. :: dispatch.range can carry both labels separated by whitespace. :: dispatch.start and dispatch.end can be used instead, individually. :: dispatch.file selects the file (default: WScript.ScriptFullName). :: :: 6. argv-code :: With no env source set, cscript args become JScript code. :: Args before "--" are joined as code; args after "--" become :: DispatchArgs. :: :: 7. no-op :: No target found. Returns 0 silently. :: :: Environment variables consulted: :: :: dispatch direct JScript code :: dispatch.codevar name of env var containing code :: dispatch.codearray name of pseudoarray of code lines :: dispatch.range "<startLabel> <endLabel>" :: dispatch.start start label (alternative to dispatch.range) :: dispatch.end end label :: dispatch.file file to read for range (default: this script) :: dispatch.args explicit arg string for DispatchArgs :: dispatch.args.sep separator for dispatch.args (default: |) :: dispatch.argsarray name of pseudoarray of args (alternative form) :: dispatch.argtype "array" -> call function with one array argument :: :: Globals available inside evaluated dynamic code: :: :: DispatchArgs clean argument array managed by Dispatch :: dispatchArgs same array, lowercase alias :: :: Return codes: :: :: function returns undefined -> 0 :: function returns a number -> that number :: function throws -> Dispatch prints error, returns 1 :: function returns non-number -> 1 :: no dispatch target found -> 0 (silent no-op) :: :: Performance, for context (typical Windows 10, hot cache): :: :: named path-injection ~70 ms per call (WMI lookup) :: env-driven dispatch modes ~35 ms per call (no WMI) :: batch-only path-injection ~30 ms per call :: :: For tight loops that call JScript many times, prefer an env-driven mode :: with a switch inside the JScript, rather than path-injection per call. :: :: Security note: all dynamic-code modes execute their input as JScript. :: Don't pass untrusted input into dispatch, dispatch.codevar, codearray, :: range files you don't control, or argv-code. :: :: ============================================================================ :: ====================================================================================================================== :: Batch + JScript Hybrid Dispatch Library Documentation :: ====================================================================================================================== :: :: Purpose :: ------- :: This library lets one .bat file contain both batch labels and JScript functions. :: It provides a dispatch layer so batch code can call batch labels, JScript functions, dynamic JScript snippets, :: JScript code ranges, generated temporary .js files, and no-path Dispatch code sources. :: :: The library is useful when a single hybrid file should behave like a small multi-language function library. :: :: ====================================================================================================================== :: Requirements :: ====================================================================================================================== :: :: Required Windows components: :: :: cmd.exe :: cscript.exe / Windows Script Host :: JScript engine :: WMI Win32_Process :: findstr :: Scripting.FileSystemObject :: :: Dispatch uses WMI to inspect the current cscript command line and recover the path-injected JScript function name. :: WriteFileFromLabels uses findstr. :: EvalRange and no-path dispatch.range use Scripting.FileSystemObject. :: :: ====================================================================================================================== :: Main Capabilities :: ====================================================================================================================== :: :: Batch execution: :: :: direct internal batch labels :: plain direct batch path-injection :: SelfCallBatch, same-file batch path-injection helper :: CallBatch, explicit-file batch path-injection helper :: :: JScript execution: :: :: plain direct JScript path-injection :: SelfCallJs, same-file JScript function helper :: CallJs, explicit-file JScript function helper :: positional JScript arguments :: JScript built-in arguments object :: WScript.Arguments :: dispatch.argtype=array for one-array-argument functions :: :: Dynamic JScript execution: :: :: EvalArg, code from first argument :: EvalEnv, code from dispatch.code :: EvalRange, code from labeled file range :: TempJs, temporary .js file generated from labels :: no-path Dispatch from env vars, ranges, pseudoarrays, or argv-code :: :: ====================================================================================================================== :: Hybrid File Layout :: ====================================================================================================================== :: :: A typical file starts as batch and hides JScript inside comment islands. :: :: @if (@X)==(@Y) @end /* batch+jscript hybrid header :: @echo off :: :: :setup :: for /f "delims=: tokens=3" %%L in ("%~0") do goto :%%L :: :: :main :: rem normal batch entry point :: goto :EOF :: :: :setupjs :: :mainjs :: / WScript.Quit(Dispatch()); / js islanded instruction :: :endjs :: :: rem batch helpers and batch labels can continue here :: :: / :: // JS island comment :: / :: :: / function Dispatch() { :: rem JScript implementation here :: } / js island instruction :: :: batch+jscript hybrid trailer / :: :: The important batch entry point is :setup. :: The important JScript entry point is WScript.Quit(Dispatch()). :: :: ====================================================================================================================== :: Path Injection :: ====================================================================================================================== :: :: A normal internal batch call: :: :: call :DemoBatch "arg one" "arg two" :: :: A path-injected batch call: :: :: call "%~d0:DemoBatch:..%~pnx0" "arg one" "arg two" :: :: A path-injected JScript call: :: :: cscript //E:JScript //nologo "%~d0:DemoJs:..%~pnx0" "arg one" "arg two" :: :: The injected target name is the path segment between the synthetic colons: :: :: :DemoJs:.. :: :: Batch path-injection is handled by :setup. :: JScript path-injection is handled by Dispatch(). :: :: ====================================================================================================================== :: :setup :: ====================================================================================================================== :: :: Purpose: :: :: Batch setup and path-injection dispatcher. :: Normal execution falls through to :main. :: Path-injected calls jump directly to the injected batch label. :: :: Usage: :: :: call "%~d0:DemoBatch:..%~pnx0" [args...] :: :: Returns: :: :: selected label result, or falls through to :main :: :: Requires: :: :: path-injected label name in token 3 of %~0 :: :: Implementation: :: :: :setup :: for /f "delims=: tokens=3" %%L in ("%~0") do goto :%%L :: :: ====================================================================================================================== :: Batch Helper API :: ====================================================================================================================== :: :: ---------------------------------------------------------------------------------------------------------------------- :: :SelfCallBatch :: ---------------------------------------------------------------------------------------------------------------------- :: :: Purpose: :: :: Calls a batch label in this same hybrid file by path injection. :: :: Usage: :: :: ref hot-path form: :: set "SelfCallBatch=<label>" & call :SelfCallBatch [args...] :: :: positional form: :: call :SelfCallBatch <label> [args...] :: :: Notes: :: :: ref hot-path form forwards % directly. :: positional form forwards %2 through %8. :: SelfCallBatch is caller-owned and is not cleared by the helper. :: :: Returns: :: :: called batch label exit code :: :: Requires: :: :: :setup path-injection dispatcher :: :: Examples: :: :: set "SelfCallBatch=DemoBatch_star" & call :SelfCallBatch "arg one" "arg two" :: call :SelfCallBatch DemoBatch_star "arg one" "arg two" :: :: ---------------------------------------------------------------------------------------------------------------------- :: :SelfCallJs :: ---------------------------------------------------------------------------------------------------------------------- :: :: Purpose: :: :: Calls a JScript function in this same hybrid file by path injection. :: :: Usage: :: :: ref hot-path form: :: set "SelfCallJs=<function>" & call :SelfCallJs [args...] :: :: positional form: :: call :SelfCallJs <function> [args...] :: :: Notes: :: :: ref hot-path form forwards %* directly. :: positional form forwards %2 through %8. :: SelfCallJs is cleared after ref hot-path dispatch. :: :: Returns: :: :: cscript exit code :: :: Requires: :: :: Dispatch :: Windows Script Host :: :: Examples: :: :: set "SelfCallJs=DemoJs" & call :SelfCallJs :: set "SelfCallJs=DemoJs_positional" & call :SelfCallJs "arg one" "arg two" :: call :SelfCallJs DemoJs :: call :SelfCallJs DemoJs_positional "arg one" "arg two" :: :: ---------------------------------------------------------------------------------------------------------------------- :: :CallBatch :: ---------------------------------------------------------------------------------------------------------------------- :: :: Purpose: :: :: Calls a batch label in an explicit hybrid file by path injection. :: :: Usage: :: :: ref hot-path form: :: set "CallBatchFile=<file>" & set "CallBatch=<label>" & call :CallBatch [args...] :: :: positional form: :: call :CallBatch <file> <label> [args...] :: :: Notes: :: :: ref hot-path form forwards %* directly. :: positional form forwards %3 through %9. :: CallBatchFile and CallBatch are caller-owned and are not cleared by the helper. :: :: Returns: :: :: called batch label exit code :: :: Requires: :: :: target file :setup path-injection dispatcher :: :: Examples: :: :: set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch_star" & call :CallBatch "arg one" "arg two" :: call :CallBatch "%~f0" DemoBatch_star "arg one" "arg two" :: :: ---------------------------------------------------------------------------------------------------------------------- :: :CallJs :: ---------------------------------------------------------------------------------------------------------------------- :: :: Purpose: :: :: Calls a JScript function in an explicit hybrid file by path injection. :: :: Usage: :: :: ref hot-path form: :: set "CallJsFile=<file>" & set "CallJs=<function>" & call :CallJs [args...] :: :: positional form: :: call :CallJs <file> <function> [args...] :: :: Notes: :: :: ref hot-path form forwards %* directly. :: positional form forwards %3 through %9. :: CallJsFile and CallJs are caller-owned and are not cleared by the helper. :: :: Returns: :: :: cscript exit code :: :: Requires: :: :: target file Dispatch :: Windows Script Host :: :: Examples: :: :: set "CallJsFile=%~f0" & set "CallJs=DemoJs_positional" & call :CallJs "arg one" "arg two" :: call :CallJs "%~f0" DemoJs_positional "arg one" "arg two" :: :: ====================================================================================================================== :: JScript Dispatch API :: ====================================================================================================================== :: :: Dispatch has two major modes: :: :: 1. Path-injected function mode :: cscript //E:JScript //nologo "%~d0:DemoJs:..%~pnx0" [args...] :: :: 2. No-path dynamic-code mode :: cscript //E:JScript //nologo "%~f0" :: with code supplied through env vars, ranges, pseudoarrays, or argv-code :: :: ---------------------------------------------------------------------------------------------------------------------- :: Path-injected function mode :: ---------------------------------------------------------------------------------------------------------------------- :: :: When Dispatch finds a function name in the synthetic path, it calls that JScript function. :: :: Default call style: :: :: fn.apply(null, args) :: :: This supports these normal JScript styles: :: :: function DemoJs() { } :: function DemoJs_positional(first, second) { } :: function DemoJs_arguments() { arguments[0]; } :: function DemoJs_wscriptarguments() { WScript.Arguments(0); } :: :: One-array-argument mode: :: :: set "dispatch.argtype=array" :: set "SelfCallJs=DemoJs_array" & call :SelfCallJs "arg one" "arg two" :: set "dispatch.argtype=" :: :: This calls: :: :: fn(args) :: :: That supports: :: :: function DemoJs_array(args) { } :: :: ---------------------------------------------------------------------------------------------------------------------- :: No-path dynamic-code mode :: ---------------------------------------------------------------------------------------------------------------------- :: :: When no path-injected JScript function exists, Dispatch checks dynamic code sources in this order: :: :: 1. dispatch :: 2. dispatch.codevar :: 3. dispatch.codearray :: 4. dispatch.range, dispatch.start, dispatch.end :: 5. argv-code :: 6. no-op return 0 :: :: No-op is success: :: :: cscript //E:JScript //nologo "%~f0" :: :: If no path-injected function and no dynamic code source exists, Dispatch prints nothing and returns 0. :: :: ====================================================================================================================== :: Dispatch Environment Variables :: ====================================================================================================================== :: :: dispatch :: :: Direct JScript code. :: :: dispatch.codevar :: :: Name of another environment variable containing JScript code. :: :: dispatch.codearray :: :: Name of a pseudoarray containing JScript code lines. :: Uses <name>[0] through <name>.ubound. :: :: dispatch.range :: :: Two labels: <startLabel> <endLabel>. :: :: dispatch.start :: dispatch.end :: :: Alternative to dispatch.range. :: :: dispatch.file :: :: File to read for dispatch.range, dispatch.start, and dispatch.end. :: Defaults to WScript.ScriptFullName when omitted. :: :: dispatch.args :: :: Explicit argument string for DispatchArgs. :: :: dispatch.args.sep :: :: Separator for dispatch.args. :: Defaults to vertical bar. :: :: dispatch.argsarray :: :: Name of a pseudoarray containing arguments. :: Uses <name>[0] through <name>.ubound. :: :: dispatch.argtype :: :: Used in path-injected function mode. :: dispatch.argtype=array calls the selected JScript function with one array argument. :: :: ====================================================================================================================== :: Dispatch Runtime Globals :: ====================================================================================================================== :: :: Evaluated no-path code can use these global arrays: :: :: DispatchArgs :: dispatchArgs :: :: These contain the clean argument array managed by Dispatch. :: :: WScript.Arguments cannot be rewritten. When clean dynamic args are needed, use DispatchArgs. :: :: ====================================================================================================================== :: No-Path Dispatch Examples :: ====================================================================================================================== :: :: ---------------------------------------------------------------------------------------------------------------------- :: Direct code from dispatch :: ---------------------------------------------------------------------------------------------------------------------- :: :: Bare command: :: :: set "dispatch=WScript.Echo('JS DemoJs no-args acknowledgement');" :: cscript //E:JScript //nologo "%~f0" :: set "dispatch=" :: :: Function plus call: :: :: set "dispatch=function DemoJs() { WScript.Echo('JS DemoJs no-args acknowledgement'); return 0; } WScript.Quit(DemoJs());" :: cscript //E:JScript //nologo "%~f0" :: set "dispatch=" :: :: With normal WScript.Arguments: :: :: set "dispatch=function DemoJs_positional(first, second) { WScript.Echo('first=' + first); WScript.Echo('second=' + second); return 0; } WScript.Quit(DemoJs_positional(WScript.Arguments(0), WScript.Arguments(1)));" :: cscript //E:JScript //nologo "%~f0" "arg one" "arg two" :: set "dispatch=" :: :: ---------------------------------------------------------------------------------------------------------------------- :: Indirect code from dispatch.codevar :: ---------------------------------------------------------------------------------------------------------------------- :: :: set "mycodevar=WScript.Echo('JS DemoJs no-args acknowledgement');" :: set "dispatch.codevar=mycodevar" :: cscript //E:JScript //nologo "%~f0" :: set "dispatch.codevar=" & set "mycodevar=" :: :: ---------------------------------------------------------------------------------------------------------------------- :: Multiline code from dispatch.codearray :: ---------------------------------------------------------------------------------------------------------------------- :: :: set "dispatch.codearray=myarray" :: set "myarray[0]=function DemoJs_positional(first, second) {" :: set "myarray[1]= WScript.Echo('JS DemoJs_positional acknowledgement');" :: set "myarray[2]= WScript.Echo('first=' + first);" :: set "myarray[3]= WScript.Echo('second=' + second);" :: set "myarray[4]= return 0; }" :: set "myarray[5]=WScript.Quit(DemoJs_positional(WScript.Arguments(0), WScript.Arguments(1)));" :: set "myarray.ubound=5" :: cscript //E:JScript //nologo "%~f0" "arg one" "arg two" :: set "dispatch.codearray=" :: for /l %%N in (0,1,5) do set "myarray[%%N]=" :: set "myarray.ubound=" :: :: ---------------------------------------------------------------------------------------------------------------------- :: Explicit args from dispatch.args :: ---------------------------------------------------------------------------------------------------------------------- :: :: set "dispatch=function DemoJs_positional(first, second) { WScript.Echo('first=' + first); WScript.Echo('second=' + second); return 0; } WScript.Quit(DemoJs_positional(DispatchArgs[0], DispatchArgs[1]));" :: set "dispatch.args=arg one|arg two" :: cscript //E:JScript //nologo "%~f0" :: set "dispatch=" & set "dispatch.args=" :: :: Custom separator: :: :: set "dispatch.args=arg one,arg two" :: set "dispatch.args.sep=," :: :: ---------------------------------------------------------------------------------------------------------------------- :: Code from labeled range :: ---------------------------------------------------------------------------------------------------------------------- :: :: Range: :: :: :DemoJs_range_start :: function DemoJs() { WScript.Echo("JS DemoJs no-args acknowledgement"); return 0; } DemoJs(); :: :DemoJs_range_end :: :: Call with dispatch.range: :: :: set "dispatch.file=%~f0" :: set "dispatch.range=DemoJs_range_start DemoJs_range_end" :: cscript //E:JScript //nologo "%~f0" :: set "dispatch.file=" & set "dispatch.range=" :: :: Call with dispatch.start and dispatch.end: :: :: set "dispatch.file=%~f0" :: set "dispatch.start=DemoJs_range_start" :: set "dispatch.end=DemoJs_range_end" :: cscript //E:JScript //nologo "%~f0" :: set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" :: :: ---------------------------------------------------------------------------------------------------------------------- :: Argv-code fallback :: ---------------------------------------------------------------------------------------------------------------------- :: :: If no dispatch env source exists, command-line arguments before -- become JScript code lines. :: :: One line: :: :: cscript //E:JScript //nologo "%~f0" "WScript.Echo('JS DemoJs no-args acknowledgement');" :: :: Multiple lines: :: :: cscript //E:JScript //nologo "%~f0" "WScript.Echo('JS DemoJs no-args acknowledgement');" "WScript.Echo('JS second argv-code line');" :: :: Code before -- and clean user args after --: :: :: cscript //E:JScript //nologo "%~f0" "function DemoJs_positional(first, second) {" "WScript.Echo('first=' + first);" "WScript.Echo('second=' + second);" "return 0; }" "WScript.Quit(DemoJs_positional(DispatchArgs[0], DispatchArgs[1]));" -- "arg one" "arg two" :: :: ====================================================================================================================== :: Eval Helper API :: ====================================================================================================================== :: :: ---------------------------------------------------------------------------------------------------------------------- :: EvalCode :: ---------------------------------------------------------------------------------------------------------------------- :: :: Purpose: :: :: Evaluates a JScript code string and normalizes the return code. :: :: Usage: :: :: EvalCode("WScript.Echo('hello');") :: :: Return behavior: :: :: undefined eval result -> 0 :: numeric result -> that number :: non-numeric result -> 1 :: exception -> handled by Dispatch wrapper, returns 1 :: :: ---------------------------------------------------------------------------------------------------------------------- :: EvalArg :: ---------------------------------------------------------------------------------------------------------------------- :: :: Purpose: :: :: Evaluates JScript code passed as the first WScript argument. :: :: Usage: :: :: set "SelfCallJs=EvalArg" & call :SelfCallJs "WScript.Echo('hello');" :: :: Best for: :: :: tiny one-line snippets :: :: Limitation: :: :: WScript.Arguments(0) is occupied by the code itself. :: This is not ideal for snippets that need clean WScript.Arguments. :: :: ---------------------------------------------------------------------------------------------------------------------- :: EvalEnv :: ---------------------------------------------------------------------------------------------------------------------- :: :: Purpose: :: :: Evaluates JScript code stored in dispatch.code. :: :: Usage: :: :: set "dispatch.code=WScript.Echo('hello');" :: set "SelfCallJs=EvalEnv" & call :SelfCallJs :: set "dispatch.code=" :: :: Best for: :: :: generated snippets while preserving normal command-line args :: :: ---------------------------------------------------------------------------------------------------------------------- :: EvalRange :: ---------------------------------------------------------------------------------------------------------------------- :: :: Purpose: :: :: Evaluates JScript code between start and end labels in a file. :: :: Positional metadata form: :: :: set "SelfCallJs=EvalRange" & call :SelfCallJs "%~f0" DemoJs_start DemoJs_end :: :: Environment metadata form: :: :: set "dispatch.file=%~f0" :: set "dispatch.start=DemoJs_start" :: set "dispatch.end=DemoJs_end" :: set "SelfCallJs=EvalRange" & call :SelfCallJs :: set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" :: :: Environment metadata keeps WScript.Arguments clean for user args. :: :: ====================================================================================================================== :: Temporary .js File Method :: ====================================================================================================================== :: :: Purpose: :: :: Extract pure JScript from labels, write it to a temporary .js file, and run it with cscript. :: :: This method does not need Dispatch or path injection once the temp file exists. :: It is closest to running a normal standalone .js script. :: :: Example: :: :: set "TempJs=%TEMP%\hybrid_demo_%RANDOM%%RANDOM%.js" :: call :WriteFileFromLabels "%~f0" "%TempJs%" TempJs_DemoJs_start TempJs_DemoJs_end :: if errorlevel 1 ( :: echo WriteFileFromLabels failed :: ) else ( :: cscript //E:JScript //nologo "%TempJs%" :: ) :: del "%TempJs%" >nul 2>nul :: :: Example range: :: :: :TempJs_DemoJs_start :: function DemoJs() { WScript.Echo("JS DemoJs no-args acknowledgement"); return 0; } :: WScript.Quit(DemoJs()); :: :TempJs_DemoJs_end :: :: ====================================================================================================================== :: :WriteFileFromLabels :: ====================================================================================================================== :: :: Purpose: :: :: Writes the lines between two labels from a source file to an output file. :: Boundary labels are not written. :: :: Usage: :: :: call :WriteFileFromLabels <sourceFile> <outputFile> <startLabel> <endLabel> :: :: Returns: :: :: 0 = written :: 1 = label not found, bad order, or output not created :: 2 = invalid arguments/source missing :: :: Requires: :: :: findstr :: :: Important implementation note: :: :: Do not parse findstr /N output with delims=: when leading colons must be preserved. :: :: A source line: :: :: :TempJs_bare_start :: :: becomes: :: :: 123::TempJs_bare_start :: :: A FOR /F parse using tokens=1,* delims=: returns token 2 without the leading colon. :: The robust approach reads the whole numbered line and removes only the first number: prefix. :: :: ====================================================================================================================== :: JScript Function Styles :: ====================================================================================================================== :: :: ---------------------------------------------------------------------------------------------------------------------- :: No arguments :: ---------------------------------------------------------------------------------------------------------------------- :: :: Function: :: :: function DemoJs() { :: WScript.Echo("JS DemoJs no-args acknowledgement"); :: return 0; :: } :: :: Call: :: :: set "SelfCallJs=DemoJs" & call :SelfCallJs :: :: ---------------------------------------------------------------------------------------------------------------------- :: Positional arguments :: ---------------------------------------------------------------------------------------------------------------------- :: :: Function: :: :: function DemoJs_positional(first, second) { :: WScript.Echo("first=" + first); :: WScript.Echo("second=" + second); :: return 0; :: } :: :: Call: :: :: set "SelfCallJs=DemoJs_positional" & call :SelfCallJs "arg one" "arg two" :: :: ---------------------------------------------------------------------------------------------------------------------- :: Built-in arguments object :: ---------------------------------------------------------------------------------------------------------------------- :: :: Function: :: :: function DemoJs_arguments() { :: WScript.Echo("JS arguments.length=" + arguments.length); :: for (var i = 0; i < arguments.length; i++) WScript.Echo("JS arguments[" + i + "]=" + arguments[i]); :: return 0; :: } :: :: Call: :: :: set "SelfCallJs=DemoJs_arguments" & call :SelfCallJs "arg one" "arg two" :: :: ---------------------------------------------------------------------------------------------------------------------- :: WScript.Arguments :: ---------------------------------------------------------------------------------------------------------------------- :: :: Function: :: :: function DemoJs_wscriptarguments() { :: WScript.Echo("JS WScript.Arguments.length=" + WScript.Arguments.length); :: for (var i = 0; i < WScript.Arguments.length; i++) WScript.Echo("JS WScript.Arguments[" + i + "]=" + WScript.Arguments(i)); :: return 0; :: } :: :: Call: :: :: set "SelfCallJs=DemoJs_wscriptarguments" & call :SelfCallJs "arg one" "arg two" :: :: ---------------------------------------------------------------------------------------------------------------------- :: One array argument :: ---------------------------------------------------------------------------------------------------------------------- :: :: Function: :: :: function DemoJs_array(args) { :: WScript.Echo("JS args.length=" + args.length); :: for (var i = 0; i < args.length; i++) WScript.Echo("JS args[" + i + "]=" + args[i]); :: return 0; :: } :: :: Call: :: :: set "dispatch.argtype=array" :: set "SelfCallJs=DemoJs_array" & call :SelfCallJs "arg one" "arg two" :: set "dispatch.argtype=" :: :: ====================================================================================================================== :: Batch Function Styles :: ====================================================================================================================== :: :: No arguments: :: :: :DemoBatch :: echo BATCH :DemoBatch acknowledgement :: exit /b 0 :: :: Positional arguments: :: :: :DemoBatch_positional :: echo BATCH first=%~1 :: echo BATCH second=%~2 :: exit /b 0 :: :: All arguments with %: :: :: :DemoBatch_star :: echo BATCH args=% :: exit /b 0 :: :: SHIFT loop: :: :: :DemoBatch_shift :: set "dbs_n=0" :: :DemoBatch_shift_loop :: if "%~1"=="" exit /b 0 :: echo BATCH arg[%dbs_n%]=%~1 :: set /a dbs_n+=1 :: shift :: goto :DemoBatch_shift_loop :: :: ====================================================================================================================== :: Return Codes :: ====================================================================================================================== :: :: All dispatch methods are intended to preserve return codes. :: :: Validated return-code paths: :: :: direct batch label :: SelfCallBatch :: JScript named dispatch :: EvalArg :: no-path dispatch :: EvalRange :: TempJs :: :: JScript return rules: :: :: function returns undefined -> exit code 0 :: function returns number -> that number :: function throws -> Dispatch prints an error and returns 1 :: function returns non-number -> 1 :: :: Batch return rule: :: :: exit /b <code> :: :: JScript process return: :: :: WScript.Quit(Dispatch()); :: :: ====================================================================================================================== :: Expected Failure Behavior :: ====================================================================================================================== :: :: Failures after a dispatch target or dynamic dispatch mode is selected print an error and return 1. :: :: Expected failure examples: :: :: missing JScript function :: invalid eval code :: missing dispatch.range labels :: invalid dispatch.codearray ubound :: :: Typical error: :: :: JS dispatch error while running NoSuchFunction: invalid or missing function: NoSuchFunction :: :: No-op is not an error: :: :: cscript //E:JScript //nologo "%~f0" :: :: With no path-injected function and no code source, Dispatch returns 0 silently. :: :: ====================================================================================================================== :: Source Priority in No-Path Dispatch :: ====================================================================================================================== :: :: Priority order: :: :: dispatch :: dispatch.codevar :: dispatch.codearray :: dispatch.range / dispatch.start / dispatch.end :: argv-code :: no-op :: :: If dispatch is defined, argv-code does not run. :: :: Example: :: :: set "dispatch=WScript.Echo('JS dispatch env source wins');" :: cscript //E:JScript //nologo "%~f0" "WScript.Echo('JS argv-code should not run');" :: set "dispatch=" :: :: Expected output: :: :: JS dispatch env source wins :: :: ====================================================================================================================== :: Quoting and Argument Notes :: ====================================================================================================================== :: :: Validated argument content: :: :: spaces :: parentheses :: commas :: semicolons :: apostrophes :: :: Example: :: :: set "SelfCallJs=DemoJs_positional" & call :SelfCallJs "arg one (paren), semicolon; ok" "O'Brien second arg" :: :: Shell metacharacters need careful escaping: :: :: & :: | :: < :: > :: ^ :: ! :: % :: " :: :: EvalArg is most fragile because code is passed on the command line. :: EvalEnv, dispatch.codevar, dispatch.codearray, and EvalRange are easier for larger snippets. :: TempJs is best when normal standalone .js behavior is desired. :: :: ====================================================================================================================== :: Security Note :: ====================================================================================================================== :: :: Dynamic-code features execute code. :: :: This includes: :: :: EvalArg :: EvalEnv :: EvalRange :: dispatch :: dispatch.codevar :: dispatch.codearray :: dispatch.range :: argv-code :: TempJs generated from labels :: :: Only run trusted code. :: Do not pass untrusted input into these mechanisms without validation. :: :: ====================================================================================================================== :: Method Selection Guide :: ====================================================================================================================== :: :: Direct batch call: :: :: Best for normal local batch labels. :: :: SelfCallBatch: :: :: Best for batch path-injection in the same file. :: :: CallBatch: :: :: Best for calling a batch label in an explicit hybrid file. :: :: SelfCallJs: :: :: Best for calling a named JScript function in the same file. :: :: CallJs: :: :: Best for calling a named JScript function in another hybrid file. :: :: EvalArg: :: :: Best for tiny one-line JScript snippets. :: :: EvalEnv: :: :: Best for generated snippets while keeping user args clean. :: :: EvalRange: :: :: Best for readable embedded snippets inside a labeled range. :: :: TempJs: :: :: Best for extracting embedded code into a normal standalone .js file. :: :: No-path Dispatch: :: :: Best when running plain cscript "%~f0" and selecting behavior by env vars, ranges, or argv-code. :: :: ====================================================================================================================== :: Cleanup Recommendations :: ====================================================================================================================== :: :: Clear temporary control variables after special calls. :: :: Common cleanup: :: :: set "SelfCallBatch=" & set "SelfCallJs=" :: set "CallBatchFile=" & set "CallBatch=" :: set "CallJsFile=" & set "CallJs=" :: set "dispatch=" & set "dispatch.argtype=" :: set "dispatch.code=" & set "dispatch.codevar=" & set "dispatch.codearray=" :: set "dispatch.range=" & set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" :: set "dispatch.args=" & set "dispatch.args.sep=" & set "dispatch.argsarray=" :: :: Pseudoarray cleanup: :: :: for /l %%N in (0,1,5) do set "myarray[%%N]=" :: set "myarray.ubound=" :: :: ====================================================================================================================== :: Troubleshooting :: ====================================================================================================================== :: :: Problem: :: :: Positional helper call passes the selector as an argument. :: :: Symptom: :: :: BATCH args=DemoBatch_star "arg one" "arg two" :: :: Cause: :: :: A ref hot-path variable such as SelfCallBatch or CallBatch is still defined. :: :: Fix: :: :: set "SelfCallBatch=" & set "SelfCallJs=" :: set "CallBatchFile=" & set "CallBatch=" :: set "CallJsFile=" & set "CallJs=" :: :: ---------------------------------------------------------------------------------------------------------------------- :: :: Problem: :: :: TempJs label extraction fails. :: :: Symptom: :: :: WriteFileFromLabels failed :: :: Likely causes: :: :: start/end labels missing :: label names misspelled :: old WriteFileFromLabels stripped leading colon from labels :: end label appears before start label :: :: Diagnostic: :: :: findstr /I /N /B /L /C:":TempJs_bare_start" "%~f0" :: findstr /I /N /B /L /C:":TempJs_bare_end" "%~f0" :: :: ---------------------------------------------------------------------------------------------------------------------- :: :: Problem: :: :: Missing dispatch.codearray ubound does not fail. :: :: Cause: :: :: Number("") is 0 in JScript. :: :: Fix: :: :: Validate ubound text with a digits-only regex before converting it to Number. :: :: ---------------------------------------------------------------------------------------------------------------------- :: :: Problem: :: :: TempJs return code is captured as 0. :: :: Cause: :: :: %errorlevel% expanded too early inside a parenthesized block. :: :: Fix: :: :: cscript //E:JScript //nologo "%TempJs%" :: call set "TestRc=%%errorlevel%%" :: :: ====================================================================================================================== :: Validated Coverage :: ====================================================================================================================== :: :: The demonstrator validates: :: :: direct batch labels :: batch positional args :: batch %* :: batch SHIFT loop :: plain direct batch path-injection :: SelfCallBatch ref and positional forms :: CallBatch ref and positional forms :: :: plain direct JScript path-injection :: SelfCallJs ref and positional forms :: CallJs ref and positional forms :: :: JScript no-args functions :: JScript positional args :: JScript arguments object :: JScript WScript.Arguments :: JScript array argument mode :: :: EvalArg bare command :: EvalArg function plus call :: EvalEnv bare command :: EvalEnv function plus call :: EvalRange bare command :: EvalRange function plus call :: :: TempJs generated from labels :: TempJs no-args, positional, arguments, WScript.Arguments, array style :: :: no-path Dispatch no-op :: no-path dispatch direct code :: no-path dispatch.codevar :: no-path dispatch.codearray :: no-path dispatch.args :: no-path dispatch.range :: no-path dispatch.file :: no-path argv-code fallback :: no-path source priority :: :: expected failures :: argument stress tests :: return-code preservation :: :: Final expected success line: :: :: Demonstrator complete. Final test exit code=0 :: :: ====================================================================================================================== :setup :: ============================================================ :: :setup :: Batch setup and path-injection dispatcher. :: Normal execution falls through to :main. :: Path-injected calls jump directly to the injected label. :: Usage: :: call "%~d0\:DemoBatch:\..\%~pnx0" [args...] :: Returns: selected label result, or falls through to :main :: Requires: path-injected label name in token 3 of %~0 :: ============================================================ for /f "delims=: tokens=3" %%L in ("%~0") do goto :%%L :main set "LastRc=%errorlevel%" echo. echo ============================================================================ echo Hybrid batch/JScript dispatch demonstrator echo ============================================================================ echo This run starts with simple direct batch calls, then batch path-injection, echo then direct JScript dispatch, then dynamic JScript eval from arg/env/range. echo Previous test exit code is tracked as LastRc so cleanup SET commands do not echo hide the real result of the previous test. echo ============================================================================ echo. echo ---------------------------------------------------------------------------- echo SECTION 1: Direct batch label calls echo ---------------------------------------------------------------------------- echo These are ordinary internal batch calls. No path-injection and no cscript. echo Use this style when the caller and target label are in the same batch context. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST DemoBatch direct no-args& call :DemoBatch set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST DemoBatch_positional direct %%1/%%2 args& call :DemoBatch_positional "arg one" "arg two" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST DemoBatch_star direct %%* args& call :DemoBatch_star "arg one" "arg two" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST DemoBatch_shift direct SHIFT loop& call :DemoBatch_shift "arg one" "arg two" set "LastRc=%errorlevel%" echo. echo ---------------------------------------------------------------------------- echo SECTION 2: Batch path-injection helpers echo ---------------------------------------------------------------------------- echo These call batch labels through the synthetic path form. echo Use SelfCallBatch for this same hybrid file. echo Use CallBatch when the target hybrid file is explicit. echo Example: set "SelfCallBatch=DemoBatch_star" ^& call :SelfCallBatch "arg one" "arg two" echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST DemoBatch_star via SelfCallBatch& set "SelfCallBatch=DemoBatch_star" & call :SelfCallBatch "arg one" "arg two" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST DemoBatch_star via CallBatch explicit file& set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch_star" & call :CallBatch "arg one" "arg two" set "LastRc=%errorlevel%" echo. echo ---------------------------------------------------------------------------- echo SECTION 3: Direct JScript function dispatch echo ---------------------------------------------------------------------------- echo These call named JScript functions already defined in this hybrid file. echo Dispatch discovers the function name from the path-injected cscript command. echo Default mode passes normal positional args. dispatch.argtype=array passes echo one array argument for functions shaped like function DemoJs_array(args). echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST DemoJs direct JScript dispatch no-args& set "SelfCallJs=DemoJs" & call :SelfCallJs set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST DemoJs_positional direct JScript dispatch& set "SelfCallJs=DemoJs_positional" & call :SelfCallJs "arg one" "arg two" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST DemoJs_arguments direct JScript dispatch& set "SelfCallJs=DemoJs_arguments" & call :SelfCallJs "arg one" "arg two" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST DemoJs_wscriptarguments direct JScript dispatch& set "SelfCallJs=DemoJs_wscriptarguments" & call :SelfCallJs "arg one" "arg two" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST DemoJs_array direct JScript dispatch with dispatch.argtype=array& set "dispatch.argtype=array" & set "SelfCallJs=DemoJs_array" & call :SelfCallJs "arg one" "arg two" set "LastRc=%errorlevel%" & set "dispatch.argtype=" echo Previous test exit code=%LastRc%&echo.&echo TEST plain direct batch path-injection& call "%~d0\:DemoBatch_star:\..\%~pnx0" "arg one" "arg two" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST plain direct JScript path-injection& cscript //E:JScript //nologo "%~d0\:DemoJs_positional:\..\%~pnx0" "arg one" "arg two" set "LastRc=%errorlevel%" set "SelfCallBatch=" & set "SelfCallJs=" & set "CallBatchFile=" & set "CallBatch=" & set "CallJsFile=" & set "CallJs=" echo Previous test exit code=%LastRc%&echo.&echo TEST SelfCallBatch positional form& call :SelfCallBatch DemoBatch_star "arg one" "arg two" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST SelfCallJs positional form& call :SelfCallJs DemoJs_positional "arg one" "arg two" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST CallBatch positional form& call :CallBatch "%~f0" DemoBatch_star "arg one" "arg two" set "LastRc=%errorlevel%" set "SelfCallBatch=" & set "SelfCallJs=" & set "CallBatchFile=" & set "CallBatch=" & set "CallJsFile=" & set "CallJs=" echo Previous test exit code=%LastRc%&echo.&echo TEST CallJs ref hot-path form& set "CallJsFile=%~f0" & set "CallJs=DemoJs_positional" & call :CallJs "arg one" "arg two" set "LastRc=%errorlevel%" set "CallJsFile=" & set "CallJs=" echo Previous test exit code=%LastRc%&echo.&echo TEST CallJs positional form& call :CallJs "%~f0" DemoJs_positional "arg one" "arg two" set "LastRc=%errorlevel%" echo. echo ---------------------------------------------------------------------------- echo SECTION 4: Small dynamic JScript snippets echo ---------------------------------------------------------------------------- echo These do not call pre-existing demo functions. They evaluate code supplied echo from three sources: first argument, environment variable, and labeled range. echo Use EvalArg for tiny one-liners, EvalEnv for generated snippets, and echo EvalRange for readable embedded multiline or range-based snippets. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST EvalArg bare command from command-line argument& set "SelfCallJs=EvalArg" & call :SelfCallJs "WScript.Echo('JS DemoJs no-args acknowledgement');" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalArg function plus call from command-line argument& set "SelfCallJs=EvalArg" & call :SelfCallJs "function DemoJs() { WScript.Echo('JS DemoJs no-args acknowledgement'); return 0; } DemoJs();" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalEnv bare command from dispatch.code& set "dispatch.code=WScript.Echo('JS DemoJs no-args acknowledgement');" & set "SelfCallJs=EvalEnv" & call :SelfCallJs set "LastRc=%errorlevel%" & set "dispatch.code=" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalEnv function plus call from dispatch.code& set "dispatch.code=function DemoJs() { WScript.Echo('JS DemoJs no-args acknowledgement'); return 0; } DemoJs();" & set "SelfCallJs=EvalEnv" & call :SelfCallJs set "LastRc=%errorlevel%" & set "dispatch.code=" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalRange bare command from DemoJs_start..DemoJs_end& set "SelfCallJs=EvalRange" & call :SelfCallJs "%~f0" DemoJs_start DemoJs_end set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalRange function plus call from DemoJs_function_start..DemoJs_function_end& set "SelfCallJs=EvalRange" & call :SelfCallJs "%~f0" DemoJs_function_start DemoJs_function_end set "LastRc=%errorlevel%" echo. echo ---------------------------------------------------------------------------- echo SECTION 5: Prepare reusable JScript snippets for EvalArg and EvalEnv echo ---------------------------------------------------------------------------- echo These variables hold full JScript snippets. Each snippet defines a function echo and then calls it. EvalArg receives the snippet as argv[0]. EvalEnv receives echo the snippet through dispatch.code, leaving WScript.Arguments cleaner. echo ---------------------------------------------------------------------------- set "JS_DemoJs=function DemoJs() { WScript.Echo('JS DemoJs no-args acknowledgement'); return 0; } DemoJs();" set "JS_DemoJs_positional=function DemoJs_positional(first, second) { WScript.Echo('JS DemoJs_positional acknowledgement'); WScript.Echo('first=' + first); WScript.Echo('second=' + second); return 0; } DemoJs_positional('arg one', 'arg two');" set "JS_DemoJs_arguments=function DemoJs_arguments() { WScript.Echo('JS DemoJs_arguments acknowledgement'); WScript.Echo('JS arguments.length=' + arguments.length); for (var i = 0; i < arguments.length; i++) WScript.Echo('JS arguments[' + i + ']=' + arguments[i]); return 0; } DemoJs_arguments('arg one', 'arg two');" set "JS_DemoJs_wscriptarguments=function DemoJs_wscriptarguments() { WScript.Echo('JS DemoJs_wscriptarguments acknowledgement'); WScript.Echo('JS WScript.Arguments.length=' + WScript.Arguments.length); for (var i = 0; i < WScript.Arguments.length; i++) WScript.Echo('JS WScript.Arguments[' + i + ']=' + WScript.Arguments(i)); return 0; } DemoJs_wscriptarguments();" set "JS_DemoJs_array=function DemoJs_array(args) { WScript.Echo('JS DemoJs_array acknowledgement'); WScript.Echo('JS args.length=' + args.length); for (var i = 0; i < args.length; i++) WScript.Echo('JS args[' + i + ']=' + args[i]); return 0; } DemoJs_array(['arg one', 'arg two']);" echo. echo ---------------------------------------------------------------------------- echo SECTION 6: EvalArg full demo snippets echo ---------------------------------------------------------------------------- echo EvalArg evaluates the first WScript argument as code. echo This is compact, but not ideal for WScript.Arguments demos because argv[0] echo is occupied by the code string itself. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST EvalArg DemoJs& set "SelfCallJs=EvalArg" & call :SelfCallJs "%JS_DemoJs%" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalArg DemoJs_positional& set "SelfCallJs=EvalArg" & call :SelfCallJs "%JS_DemoJs_positional%" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalArg DemoJs_arguments& set "SelfCallJs=EvalArg" & call :SelfCallJs "%JS_DemoJs_arguments%" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalArg DemoJs_array& set "SelfCallJs=EvalArg" & call :SelfCallJs "%JS_DemoJs_array%" set "LastRc=%errorlevel%" echo. echo ---------------------------------------------------------------------------- echo SECTION 7: EvalEnv full demo snippets echo ---------------------------------------------------------------------------- echo EvalEnv evaluates dispatch.code. This lets the code arrive through the echo environment while normal command-line args remain available to the snippet. echo This is why DemoJs_wscriptarguments is clean here. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST EvalEnv DemoJs& set "dispatch.code=%JS_DemoJs%" & set "SelfCallJs=EvalEnv" & call :SelfCallJs set "LastRc=%errorlevel%" & set "dispatch.code=" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalEnv DemoJs_positional& set "dispatch.code=%JS_DemoJs_positional%" & set "SelfCallJs=EvalEnv" & call :SelfCallJs set "LastRc=%errorlevel%" & set "dispatch.code=" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalEnv DemoJs_arguments& set "dispatch.code=%JS_DemoJs_arguments%" & set "SelfCallJs=EvalEnv" & call :SelfCallJs set "LastRc=%errorlevel%" & set "dispatch.code=" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalEnv DemoJs_wscriptarguments with clean user args& set "dispatch.code=%JS_DemoJs_wscriptarguments%" & set "SelfCallJs=EvalEnv" & call :SelfCallJs "arg one" "arg two" set "LastRc=%errorlevel%" & set "dispatch.code=" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalEnv DemoJs_array& set "dispatch.code=%JS_DemoJs_array%" & set "SelfCallJs=EvalEnv" & call :SelfCallJs set "LastRc=%errorlevel%" & set "dispatch.code=" echo. echo ---------------------------------------------------------------------------- echo SECTION 8: EvalRange full demo snippets echo ---------------------------------------------------------------------------- echo EvalRange reads code from labels inside a file. Here the file is this script. echo The range metadata is passed through dispatch.file/start/end so normal echo command-line args can still be passed cleanly to WScript.Arguments. echo This is the most readable embedded-code method. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST EvalRange DemoJs& set "dispatch.file=%~f0" & set "dispatch.start=DemoJs_range_start" & set "dispatch.end=DemoJs_range_end" & set "SelfCallJs=EvalRange" & call :SelfCallJs set "LastRc=%errorlevel%" & set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalRange DemoJs_positional& set "dispatch.file=%~f0" & set "dispatch.start=DemoJs_positional_range_start" & set "dispatch.end=DemoJs_positional_range_end" & set "SelfCallJs=EvalRange" & call :SelfCallJs set "LastRc=%errorlevel%" & set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalRange DemoJs_arguments& set "dispatch.file=%~f0" & set "dispatch.start=DemoJs_arguments_range_start" & set "dispatch.end=DemoJs_arguments_range_end" & set "SelfCallJs=EvalRange" & call :SelfCallJs set "LastRc=%errorlevel%" & set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalRange DemoJs_wscriptarguments with clean user args& set "dispatch.file=%~f0" & set "dispatch.start=DemoJs_wscriptarguments_range_start" & set "dispatch.end=DemoJs_wscriptarguments_range_end" & set "SelfCallJs=EvalRange" & call :SelfCallJs "arg one" "arg two" set "LastRc=%errorlevel%" & set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" echo Previous test exit code=%LastRc%&echo.&echo TEST EvalRange DemoJs_array& set "dispatch.file=%~f0" & set "dispatch.start=DemoJs_array_range_start" & set "dispatch.end=DemoJs_array_range_end" & set "SelfCallJs=EvalRange" & call :SelfCallJs set "LastRc=%errorlevel%" & set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" echo. echo ---------------------------------------------------------------------------- echo SECTION 9: Temporary .js files generated from labeled ranges echo ---------------------------------------------------------------------------- echo This extracts pure JScript from labels into a temporary .js file, then runs echo that file with cscript. This does not need Dispatch or path-injection. echo It is closest to running a normal standalone .js script. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST TempJs bare command from labels set "TempJs=%TEMP%\hybrid_demo_%RANDOM%%RANDOM%.js" call :WriteFileFromLabels "%~f0" "%TempJs%" TempJs_bare_start TempJs_bare_end if errorlevel 1 (set "LastRc=%errorlevel%" & echo WriteFileFromLabels failed) else cscript //E:JScript //nologo "%TempJs%" set "LastRc=%errorlevel%" & del "%TempJs%" >nul 2>nul echo Previous test exit code=%LastRc%&echo.&echo TEST TempJs DemoJs no-args set "TempJs=%TEMP%\hybrid_demo_%RANDOM%%RANDOM%.js" call :WriteFileFromLabels "%~f0" "%TempJs%" TempJs_DemoJs_start TempJs_DemoJs_end if errorlevel 1 (set "LastRc=%errorlevel%" & echo WriteFileFromLabels failed) else cscript //E:JScript //nologo "%TempJs%" set "LastRc=%errorlevel%" & del "%TempJs%" >nul 2>nul echo Previous test exit code=%LastRc%&echo.&echo TEST TempJs DemoJs_positional with cscript args set "TempJs=%TEMP%\hybrid_demo_%RANDOM%%RANDOM%.js" call :WriteFileFromLabels "%~f0" "%TempJs%" TempJs_DemoJs_positional_start TempJs_DemoJs_positional_end if errorlevel 1 (set "LastRc=%errorlevel%" & echo WriteFileFromLabels failed) else cscript //E:JScript //nologo "%TempJs%" "arg one" "arg two" set "LastRc=%errorlevel%" & del "%TempJs%" >nul 2>nul echo Previous test exit code=%LastRc%&echo.&echo TEST TempJs DemoJs_arguments with cscript args set "TempJs=%TEMP%\hybrid_demo_%RANDOM%%RANDOM%.js" call :WriteFileFromLabels "%~f0" "%TempJs%" TempJs_DemoJs_arguments_start TempJs_DemoJs_arguments_end if errorlevel 1 (set "LastRc=%errorlevel%" & echo WriteFileFromLabels failed) else cscript //E:JScript //nologo "%TempJs%" "arg one" "arg two" set "LastRc=%errorlevel%" & del "%TempJs%" >nul 2>nul echo Previous test exit code=%LastRc%&echo.&echo TEST TempJs DemoJs_wscriptarguments with cscript args set "TempJs=%TEMP%\hybrid_demo_%RANDOM%%RANDOM%.js" call :WriteFileFromLabels "%~f0" "%TempJs%" TempJs_DemoJs_wscriptarguments_start TempJs_DemoJs_wscriptarguments_end if errorlevel 1 (set "LastRc=%errorlevel%" & echo WriteFileFromLabels failed) else cscript //E:JScript //nologo "%TempJs%" "arg one" "arg two" set "LastRc=%errorlevel%" & del "%TempJs%" >nul 2>nul echo Previous test exit code=%LastRc%&echo.&echo TEST TempJs DemoJs_array with cscript args converted to array set "TempJs=%TEMP%\hybrid_demo_%RANDOM%%RANDOM%.js" call :WriteFileFromLabels "%~f0" "%TempJs%" TempJs_DemoJs_array_start TempJs_DemoJs_array_end if errorlevel 1 (set "LastRc=%errorlevel%" & echo WriteFileFromLabels failed) else cscript //E:JScript //nologo "%TempJs%" "arg one" "arg two" set "LastRc=%errorlevel%" & del "%TempJs%" >nul 2>nul echo. echo ---------------------------------------------------------------------------- echo SECTION 10: No-path Dispatch no-op fallback echo ---------------------------------------------------------------------------- echo This runs cscript on the hybrid file without path-injection and without any echo dispatch code source. Dispatch should find nothing to run, print nothing from echo JScript, and return 0. echo ---------------------------------------------------------------------------- set "dispatch=" & set "dispatch.codevar=" & set "dispatch.codearray=" set "dispatch.range=" & set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" set "dispatch.args=" & set "dispatch.args.sep=" & set "dispatch.argsarray=" echo Previous test exit code=%LastRc%&echo.&echo TEST no-path Dispatch no-op fallback& cscript //E:JScript //nologo "%~f0" set "LastRc=%errorlevel%" echo. echo ---------------------------------------------------------------------------- echo SECTION 11: No-path Dispatch direct code from dispatch echo ---------------------------------------------------------------------------- echo This sets dispatch directly to JScript code, then runs this hybrid file with echo plain cscript. There is no path-injected function name in the script path. echo Use this when one environment variable is enough to hold the generated code. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch direct code bare command& set "dispatch=WScript.Echo('JS DemoJs no-args acknowledgement');" & cscript //E:JScript //nologo "%~f0" set "LastRc=%errorlevel%" & set "dispatch=" echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch direct code function plus call& set "dispatch=function DemoJs() { WScript.Echo('JS DemoJs no-args acknowledgement'); return 0; } WScript.Quit(DemoJs());" & cscript //E:JScript //nologo "%~f0" set "LastRc=%errorlevel%" & set "dispatch=" echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch direct code using normal WScript.Arguments& set "dispatch=function DemoJs_positional(first, second) { WScript.Echo('JS DemoJs_positional acknowledgement'); WScript.Echo('first=' + first); WScript.Echo('second=' + second); return 0; } WScript.Quit(DemoJs_positional(WScript.Arguments(0), WScript.Arguments(1)));" & cscript //E:JScript //nologo "%~f0" "arg one" "arg two" set "LastRc=%errorlevel%" & set "dispatch=" echo. echo ---------------------------------------------------------------------------- echo SECTION 12: No-path Dispatch indirect code from dispatch.codevar echo ---------------------------------------------------------------------------- echo dispatch.codevar contains the name of another environment variable. echo Dispatch reads that named variable to get the JScript code. echo Use this when the control variable should point to a reusable named snippet. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch.codevar bare command& set "mycodevar=WScript.Echo('JS DemoJs no-args acknowledgement');" & set "dispatch.codevar=mycodevar" & cscript //E:JScript //nologo "%~f0" set "LastRc=%errorlevel%" & set "dispatch.codevar=" & set "mycodevar=" echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch.codevar function plus call& set "mycodevar=function DemoJs() { WScript.Echo('JS DemoJs no-args acknowledgement'); return 0; } WScript.Quit(DemoJs());" & set "dispatch.codevar=mycodevar" & cscript //E:JScript //nologo "%~f0" set "LastRc=%errorlevel%" & set "dispatch.codevar=" & set "mycodevar=" echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch.codevar with WScript.Arguments& set "mycodevar=function DemoJs_positional(first, second) { WScript.Echo('JS DemoJs_positional acknowledgement'); WScript.Echo('first=' + first); WScript.Echo('second=' + second); return 0; } WScript.Quit(DemoJs_positional(WScript.Arguments(0), WScript.Arguments(1)));" & set "dispatch.codevar=mycodevar" & cscript //E:JScript //nologo "%~f0" "arg one" "arg two" set "LastRc=%errorlevel%" & set "dispatch.codevar=" & set "mycodevar=" echo. echo ---------------------------------------------------------------------------- echo SECTION 13: No-path Dispatch multiline code from dispatch.codearray echo ---------------------------------------------------------------------------- echo dispatch.codearray names a pseudoarray of code lines. echo Dispatch assembles arrayName[0] through arrayName.ubound into one script. echo Use this for multiline generated code without writing a temporary .js file. echo ---------------------------------------------------------------------------- set "myarray[0]=function DemoJs_positional(first, second) {" set "myarray[1]= WScript.Echo('JS DemoJs_positional acknowledgement');" set "myarray[2]= WScript.Echo('first=' + first);" set "myarray[3]= WScript.Echo('second=' + second);" set "myarray[4]= return 0; }" set "myarray[5]=WScript.Quit(DemoJs_positional(WScript.Arguments(0), WScript.Arguments(1)));" set "myarray.ubound=5" echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch.codearray with WScript.Arguments& set "dispatch.codearray=myarray" & cscript //E:JScript //nologo "%~f0" "arg one" "arg two" set "LastRc=%errorlevel%" & set "dispatch.codearray=" for /l %%N in (0,1,5) do set "myarray[%%N]=" set "myarray.ubound=" set "myarray[0]=function DemoJs_array(args) {" set "myarray[1]= WScript.Echo('JS DemoJs_array acknowledgement');" set "myarray[2]= WScript.Echo('JS args.length=' + args.length);" set "myarray[3]= for (var i = 0; i < args.length; i++) WScript.Echo('JS args[' + i + ']=' + args[i]);" set "myarray[4]= return 0; }" set "myarray[5]=WScript.Quit(DemoJs_array(DispatchArgs));" set "myarray.ubound=5" echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch.codearray using DispatchArgs from normal cscript args& set "dispatch.codearray=myarray" & cscript //E:JScript //nologo "%~f0" "arg one" "arg two" set "LastRc=%errorlevel%" & set "dispatch.codearray=" for /l %%N in (0,1,5) do set "myarray[%%N]=" set "myarray.ubound=" echo. echo ---------------------------------------------------------------------------- echo SECTION 14: No-path Dispatch explicit dispatch.args echo ---------------------------------------------------------------------------- echo dispatch.args supplies clean arguments to evaluated code through DispatchArgs. echo By default the separator is ^|. dispatch.args.sep can change the separator. echo WScript.Arguments is not rewritten; use DispatchArgs for these explicit args. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch.args default separator with direct dispatch code& set "dispatch=function DemoJs_positional(first, second) { WScript.Echo('JS DemoJs_positional acknowledgement'); WScript.Echo('first=' + first); WScript.Echo('second=' + second); return 0; } WScript.Quit(DemoJs_positional(DispatchArgs[0], DispatchArgs[1]));" & set "dispatch.args=arg one|arg two" & cscript //E:JScript //nologo "%~f0" set "LastRc=%errorlevel%" & set "dispatch=" & set "dispatch.args=" echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch.args custom separator with direct dispatch code& set "dispatch=function DemoJs_positional(first, second) { WScript.Echo('JS DemoJs_positional acknowledgement'); WScript.Echo('first=' + first); WScript.Echo('second=' + second); return 0; } WScript.Quit(DemoJs_positional(DispatchArgs[0], DispatchArgs[1]));" & set "dispatch.args=arg one,arg two" & set "dispatch.args.sep=," & cscript //E:JScript //nologo "%~f0" set "LastRc=%errorlevel%" & set "dispatch=" & set "dispatch.args=" & set "dispatch.args.sep=" echo. echo ---------------------------------------------------------------------------- echo SECTION 15: No-path Dispatch range loading with dispatch.range and dispatch.file echo ---------------------------------------------------------------------------- echo dispatch.range names start/end labels containing JScript code. echo dispatch.file points to the file to read. Here it points to this hybrid file. echo Since metadata is in env vars, normal cscript args remain clean. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch.range DemoJs_range_start..DemoJs_range_end& set "dispatch.file=%~f0" & set "dispatch.range=DemoJs_range_start DemoJs_range_end" & cscript //E:JScript //nologo "%~f0" set "LastRc=%errorlevel%" & set "dispatch.file=" & set "dispatch.range=" echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch.range DemoJs_wscriptarguments with clean cscript args& set "dispatch.file=%~f0" & set "dispatch.range=DemoJs_wscriptarguments_range_start DemoJs_wscriptarguments_range_end" & cscript //E:JScript //nologo "%~f0" "arg one" "arg two" set "LastRc=%errorlevel%" & set "dispatch.file=" & set "dispatch.range=" echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch.start and dispatch.end equivalent to dispatch.range& set "dispatch.file=%~f0" & set "dispatch.start=DemoJs_array_range_start" & set "dispatch.end=DemoJs_array_range_end" & cscript //E:JScript //nologo "%~f0" set "LastRc=%errorlevel%" & set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" echo. echo ---------------------------------------------------------------------------- echo SECTION 16: No-path Dispatch argv-code fallback echo ---------------------------------------------------------------------------- echo If no dispatch env source exists, Dispatch treats command-line args before echo -- as JScript code lines. Args after -- become DispatchArgs. echo Use DispatchArgs for clean user args in this mode. echo ---------------------------------------------------------------------------- set "dispatch=" & set "dispatch.codevar=" & set "dispatch.codearray=" set "dispatch.range=" & set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" set "dispatch.args=" & set "dispatch.args.sep=" & set "dispatch.argsarray=" echo Previous test exit code=%LastRc%&echo.&echo TEST argv-code bare command one line& cscript //E:JScript //nologo "%~f0" "WScript.Echo('JS DemoJs no-args acknowledgement');" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST argv-code two code lines before --& cscript //E:JScript //nologo "%~f0" "WScript.Echo('JS DemoJs no-args acknowledgement');" "WScript.Echo('JS second argv-code line');" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST argv-code function using DispatchArgs after --& cscript //E:JScript //nologo "%~f0" "function DemoJs_positional(first, second) {" "WScript.Echo('JS DemoJs_positional acknowledgement');" "WScript.Echo('first=' + first);" "WScript.Echo('second=' + second);" "return 0; }" "WScript.Quit(DemoJs_positional(DispatchArgs[0], DispatchArgs[1]));" -- "arg one" "arg two" set "LastRc=%errorlevel%" echo. echo ---------------------------------------------------------------------------- echo SECTION 17: No-path Dispatch source priority check echo ---------------------------------------------------------------------------- echo This verifies that env sources win before argv-code. echo dispatch should run, and the argv-code line should not run. echo Expected output: JS dispatch env source wins echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST dispatch env source wins over argv-code& set "dispatch=WScript.Echo('JS dispatch env source wins');" & cscript //E:JScript //nologo "%~f0" "WScript.Echo('JS argv-code should not run');" set "LastRc=%errorlevel%" & set "dispatch=" echo. echo ============================================================================ echo No-path Dispatch feature tests complete. Final test exit code=%LastRc% echo ============================================================================ echo. echo. echo ---------------------------------------------------------------------------- echo SECTION 18: Expected failure behavior echo ---------------------------------------------------------------------------- echo These tests are supposed to fail. The demonstrator treats a nonzero result echo as PASS for this section. This proves bad dispatch targets, bad eval code, echo missing ranges, and bad codearrays fail cleanly. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST expected failure missing JScript function& set "SelfCallJs=NoSuchFunction" & call :SelfCallJs set "TestRc=%errorlevel%" if "%TestRc%"=="0" (echo EXPECTED FAILURE DID NOT FAIL&set "LastRc=1") else (echo Expected failure returned %TestRc%&set "LastRc=0") echo Previous test exit code=%LastRc%&echo.&echo TEST expected failure invalid EvalArg code& set "SelfCallJs=EvalArg" & call :SelfCallJs "function {" set "TestRc=%errorlevel%" if "%TestRc%"=="0" (echo EXPECTED FAILURE DID NOT FAIL&set "LastRc=1") else (echo Expected failure returned %TestRc%&set "LastRc=0") echo Previous test exit code=%LastRc%&echo.&echo TEST expected failure missing no-path dispatch.range& set "dispatch.file=%~f0" & set "dispatch.range=NoSuchStart NoSuchEnd" & cscript //E:JScript //nologo "%~f0" set "TestRc=%errorlevel%" & set "dispatch.file=" & set "dispatch.range=" if "%TestRc%"=="0" (echo EXPECTED FAILURE DID NOT FAIL&set "LastRc=1") else (echo Expected failure returned %TestRc%&set "LastRc=0") echo Previous test exit code=%LastRc%&echo.&echo TEST expected failure bad dispatch.codearray ubound& set "dispatch.codearray=badarray" & cscript //E:JScript //nologo "%~f0" set "TestRc=%errorlevel%" & set "dispatch.codearray=" if "%TestRc%"=="0" (echo EXPECTED FAILURE DID NOT FAIL&set "LastRc=1") else (echo Expected failure returned %TestRc%&set "LastRc=0") echo. echo ---------------------------------------------------------------------------- echo SECTION 19: Argument stress tests echo ---------------------------------------------------------------------------- echo These tests pass arguments containing spaces, parentheses, commas, echo semicolons, and apostrophes. They avoid command separators like ^&, ^|, ^<, ^> echo because those require a separate escaping-focused section. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST JScript positional args with spaces punctuation and apostrophe& set "SelfCallJs=DemoJs_positional" & call :SelfCallJs "arg one (paren), semicolon; ok" "O'Brien second arg" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST JScript arguments object with spaces punctuation and apostrophe& set "SelfCallJs=DemoJs_arguments" & call :SelfCallJs "arg one (paren), semicolon; ok" "O'Brien second arg" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST JScript WScript.Arguments with spaces punctuation and apostrophe& set "SelfCallJs=DemoJs_wscriptarguments" & call :SelfCallJs "arg one (paren), semicolon; ok" "O'Brien second arg" set "LastRc=%errorlevel%" echo Previous test exit code=%LastRc%&echo.&echo TEST no-path dispatch.args with custom separator and punctuation& set "dispatch=function DemoJs_positional(first, second) { WScript.Echo('JS DemoJs_positional acknowledgement'); WScript.Echo('first=' + first); WScript.Echo('second=' + second); return 0; } WScript.Quit(DemoJs_positional(DispatchArgs[0], DispatchArgs[1]));" & set "dispatch.args=arg one (paren), semicolon; ok~O'Brien second arg" & set "dispatch.args.sep=~" & cscript //E:JScript //nologo "%~f0" set "LastRc=%errorlevel%" & set "dispatch=" & set "dispatch.args=" & set "dispatch.args.sep=" echo Previous test exit code=%LastRc%&echo.&echo TEST argv-code DispatchArgs with punctuation after --& cscript //E:JScript //nologo "%~f0" "function DemoJs_positional(first, second) {" "WScript.Echo('JS DemoJs_positional acknowledgement');" "WScript.Echo('first=' + first);" "WScript.Echo('second=' + second);" "return 0; }" "WScript.Quit(DemoJs_positional(DispatchArgs[0], DispatchArgs[1]));" -- "arg one (paren), semicolon; ok" "O'Brien second arg" set "LastRc=%errorlevel%" echo. echo ---------------------------------------------------------------------------- echo SECTION 20: Return-code preservation echo ---------------------------------------------------------------------------- echo These tests intentionally return 7. The section treats actual exit code 7 echo as PASS and sets LastRc back to 0. Any other code is a failure. echo ---------------------------------------------------------------------------- echo Previous test exit code=%LastRc%&echo.&echo TEST batch direct return code 7& call :DemoBatch_return7 set "TestRc=%errorlevel%" if "%TestRc%"=="7" (echo Return-code PASS actual=%TestRc%&set "LastRc=0") else (echo Return-code FAIL actual=%TestRc% expected=7&set "LastRc=1") echo Previous test exit code=%LastRc%&echo.&echo TEST SelfCallBatch return code 7& set "SelfCallBatch=DemoBatch_return7" & call :SelfCallBatch set "TestRc=%errorlevel%" & set "SelfCallBatch=" if "%TestRc%"=="7" (echo Return-code PASS actual=%TestRc%&set "LastRc=0") else (echo Return-code FAIL actual=%TestRc% expected=7&set "LastRc=1") echo Previous test exit code=%LastRc%&echo.&echo TEST JScript named dispatch return code 7& set "SelfCallJs=DemoJs_return7" & call :SelfCallJs set "TestRc=%errorlevel%" if "%TestRc%"=="7" (echo Return-code PASS actual=%TestRc%&set "LastRc=0") else (echo Return-code FAIL actual=%TestRc% expected=7&set "LastRc=1") echo Previous test exit code=%LastRc%&echo.&echo TEST EvalArg return code 7& set "SelfCallJs=EvalArg" & call :SelfCallJs "function Ret7() { WScript.Echo('JS EvalArg return 7 acknowledgement'); return 7; } Ret7();" set "TestRc=%errorlevel%" if "%TestRc%"=="7" (echo Return-code PASS actual=%TestRc%&set "LastRc=0") else (echo Return-code FAIL actual=%TestRc% expected=7&set "LastRc=1") echo Previous test exit code=%LastRc%&echo.&echo TEST no-path dispatch direct code return code 7& set "dispatch=function Ret7() { WScript.Echo('JS no-path dispatch return 7 acknowledgement'); return 7; } Ret7();" & cscript //E:JScript //nologo "%~f0" set "TestRc=%errorlevel%" & set "dispatch=" if "%TestRc%"=="7" (echo Return-code PASS actual=%TestRc%&set "LastRc=0") else (echo Return-code FAIL actual=%TestRc% expected=7&set "LastRc=1") echo Previous test exit code=%LastRc%&echo.&echo TEST EvalRange return code 7& set "SelfCallJs=EvalRange" & call :SelfCallJs "%~f0" Return7_range_start Return7_range_end set "TestRc=%errorlevel%" if "%TestRc%"=="7" (echo Return-code PASS actual=%TestRc%&set "LastRc=0") else (echo Return-code FAIL actual=%TestRc% expected=7&set "LastRc=1") echo Previous test exit code=%LastRc%&echo.&echo TEST TempJs return code 7 from labels set "TempJs=%TEMP%\hybrid_demo_%RANDOM%%RANDOM%.js" call :WriteFileFromLabels "%~f0" "%TempJs%" TempJs_Return7_start TempJs_Return7_end set "TestRc=%errorlevel%" if not "%TestRc%"=="0" ( echo WriteFileFromLabels failed ) else ( cscript //E:JScript //nologo "%TempJs%" call set "TestRc=%%errorlevel%%" ) del "%TempJs%" >nul 2>nul if "%TestRc%"=="7" (echo Return-code PASS actual=%TestRc%&set "LastRc=0") else (echo Return-code FAIL actual=%TestRc% expected=7&set "LastRc=1") echo. echo ============================================================================ echo SECTION 21: Performance benchmark echo ============================================================================ echo Each method invokes a WScript.Echo (or batch echo) PERF_N times with output echo redirected to nul. Timing is %%TIME%% centiseconds (10ms granularity). Avg echo is total/PERF_N. cscript-based methods include process startup + WMI cost. echo ============================================================================ set "PERF_N=10" echo. echo --- Batch-only methods --- call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do call :PerfBatch >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "direct batch label" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "SelfCallBatch=PerfBatch" & call :SelfCallBatch) >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "SelfCallBatch ref form" set "SelfCallBatch=" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do call :SelfCallBatch PerfBatch >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "SelfCallBatch positional" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do call "%~d0\:PerfBatch:\..\%~pnx0" >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "direct batch path-injection" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "CallBatchFile=%~f0" & set "CallBatch=PerfBatch" & call :CallBatch) >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "CallBatch ref form" set "CallBatchFile=" & set "CallBatch=" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do call :CallBatch "%~f0" PerfBatch >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "CallBatch positional" echo. echo --- JScript named dispatch (each spawns cscript) --- call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do cscript //E:JScript //nologo "%~d0\:PerfJs:\..\%~pnx0" >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "direct JS path-injection" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "SelfCallJs=PerfJs" & call :SelfCallJs) >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "SelfCallJs ref form" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do call :SelfCallJs PerfJs >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "SelfCallJs positional" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "CallJsFile=%~f0" & set "CallJs=PerfJs" & call :CallJs) >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "CallJs ref form" set "CallJsFile=" & set "CallJs=" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do call :CallJs "%~f0" PerfJs >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "CallJs positional" echo. echo --- Dynamic eval --- call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "SelfCallJs=EvalArg" & call :SelfCallJs "WScript.Echo('PERF evalarg');") >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "EvalArg" set "dispatch.code=WScript.Echo('PERF evalenv');" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "SelfCallJs=EvalEnv" & call :SelfCallJs) >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "EvalEnv" set "dispatch.code=" set "dispatch.file=%~f0" & set "dispatch.start=PerfJs_range_start" & set "dispatch.end=PerfJs_range_end" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "SelfCallJs=EvalRange" & call :SelfCallJs) >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "EvalRange" set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" echo. echo --- TempJs (extract once, run N times) --- set "PerfTempJs=%TEMP%\hybrid_perf_%RANDOM%%RANDOM%.js" call :TimeNow & set /a "BenchT0=Ret" call :WriteFileFromLabels "%~f0" "%PerfTempJs%" TempJs_Perf_start TempJs_Perf_end call :TimeNow & set /a "BenchT1=Ret" set /a "BenchD=BenchT1-BenchT0" if %BenchD% LSS 0 set /a "BenchD+=8640000" set /a "BenchExtractMs=BenchD*10" echo TempJs extract (one-time): %BenchExtractMs% ms call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do cscript //E:JScript //nologo "%PerfTempJs%" >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "TempJs run (post-extract)" del "%PerfTempJs%" >nul 2>nul set "PerfTempJs=" echo. echo --- No-path Dispatch (each spawns cscript with %%~f0 directly) --- call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "dispatch=WScript.Echo('PERF nopath');" & cscript //E:JScript //nologo "%~f0") >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "no-path dispatch (env)" set "dispatch=" set "perfcv=WScript.Echo('PERF codevar');" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "dispatch.codevar=perfcv" & cscript //E:JScript //nologo "%~f0") >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "no-path dispatch.codevar" set "dispatch.codevar=" & set "perfcv=" set "perfca[0]=WScript.Echo('PERF codearray');" set "perfca.ubound=0" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "dispatch.codearray=perfca" & cscript //E:JScript //nologo "%~f0") >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "no-path dispatch.codearray" set "dispatch.codearray=" & set "perfca[0]=" & set "perfca.ubound=" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do (set "dispatch.file=%~f0" & set "dispatch.range=PerfJs_range_start PerfJs_range_end" & cscript //E:JScript //nologo "%~f0") >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "no-path dispatch.range" set "dispatch.file=" & set "dispatch.range=" call :TimeNow & set /a "BenchT0=Ret" for /l %%I in (1,1,%PERF_N%) do cscript //E:JScript //nologo "%~f0" "WScript.Echo('PERF argv');" >nul call :TimeNow & set /a "BenchT1=Ret" & call :BenchReport "no-path argv-code" echo. echo ============================================================================ echo Performance benchmark complete. echo ============================================================================ echo ============================================================================ echo Demonstrator complete. Final test exit code=%LastRc% echo ============================================================================ :end for %%P in (SelfCall Call dispatch JS_ LastRc TestRc TempJs Bench Perf T BenchT BenchD wffl_ Ret myarray badarray mycodevar) do for /f "tokens=1 delims==" %%v in ('set %%P 2^>nul') do set "%%v=" goto :EOF
Code: :setupjs :mainjs */ WScript.Quit(Dispatch()); /* js islanded instruction :endjs */ // JS island comment /* :: This function is disabled, by removing the uncomment tags, star slash and slash start, known as a js island function Dispatch() { var name = "", fn, rc, rows, args = []; try { var sh = new ActiveXObject("WScript.Shell"), svc = GetObject("winmgmts:root\\cimv2"); rows = new Enumerator(svc.ExecQuery("select ParentProcessId from Win32_Process where ProcessId=" + sh.Exec('"' + sh.ExpandEnvironmentStrings("%ComSpec%") + '" /d /q /c ping -n 2 127.0.0.1 >nul').ProcessID)); rows = new Enumerator(svc.ExecQuery("select CommandLine from Win32_Process where ProcessId=" + rows.item().ParentProcessId)); name = (String(rows.item().CommandLine || "").match(/[A-Za-z]:\\:([^:\\\/"]+):\\\.\.\\/) || [])[1] || ""; if (!name) return 0; if (!/^[A-Za-z_$][\w$]*$/.test(name) || typeof (fn = this[name]) != "function") throw new Error("invalid or missing function: " + name); for (var i = 0; i < WScript.Arguments.length; i++) args[i] = WScript.Arguments(i); rc = sh.ExpandEnvironmentStrings("%dispatch.argtype%").toLowerCase() == "array" ? fn(args) : fn.apply(null, args); return typeof rc == "undefined" ? 0 : isNaN(rc = Number(rc)) ? 1 : rc; } catch (e) { if (!name) return 0; WScript.Echo("JS dispatch error while running " + name + ": " + e.message); return 1; } } js island instruction :: ============================================================ :: Dispatch :: Dispatches a path-injected JScript function name. :: Usage: :: JS entry point: :: WScript.Quit(Dispatch()); :: JS internal helper call: :: var rc = Dispatch(); :: :: Argument modes: :: default: :: Calls the selected function with normal positional args. :: Supports function DemoJs(a, b), function DemoJs(), :: function DemoJs(){ arguments[...] }, and WScript.Arguments. :: :: dispatch.argtype=array: :: Calls the selected function with one array argument. :: Supports function DemoJs(args). :: :: Returns: :: selected function exit code :: 0 if no path-injected JScript function was selected :: 1 on dispatch error after a function was selected :: Requires: Windows Script Host, WMI Win32_Process :: ============================================================ :DispatchJs */ function Dispatch() { var sh = new ActiveXObject("WScript.Shell"), env = sh.Environment("Process"), Env = function (n) { return String(env(n) || ""); }, Exit = function (x) { return typeof x == "undefined" ? 0 : isNaN(x = Number(x)) ? 1 : x; }, PA = function (n) { var ub = Env(n + ".ubound"), a = [], i; if (!/^\d+$/.test(ub)) throw new Error("missing or invalid " + n + ".ubound"); for (i = 0; i <= Number(ub); i++) a[i] = Env(n + "[" + i + "]"); return a; }, args = [], i, name = "", mode = "", code = "", fn; for (i = 0; i < WScript.Arguments.length; i++) args[i] = WScript.Arguments(i); try {if (Env("dispatch")) { mode = "dispatch"; code = Env("dispatch"); } else if (Env("dispatch.codevar")) { mode = "dispatch.codevar"; code = Env(Env("dispatch.codevar")); } else if (Env("dispatch.codearray")) { mode = "dispatch.codearray"; code = PA(Env("dispatch.codearray")).join("\r\n"); } else if (Env("dispatch.range") || Env("dispatch.start")) { mode = "dispatch.range"; var file = Env("dispatch.file") || WScript.ScriptFullName, rr = Env("dispatch.range").replace(/^\s+|\s+$/g, "").split(/\s+/), s = ":" + (Env("dispatch.start") || rr[0] || "").replace(/^:/, ""), e = ":" + (Env("dispatch.end") || rr[1] || "").replace(/^:/, ""), lines = new ActiveXObject("Scripting.FileSystemObject").OpenTextFile(file, 1).ReadAll().split(/\r?\n/), si = -1, ei = -1; for (i = 0; i < lines.length; i++) { if (si < 0 && lines[i] == s) si = i; else if (si >= 0 && lines[i] == e) { ei = i; break; } } if (si < 0 || ei < 0) throw new Error("range not found or bad order: " + s + " .. " + e); code = lines.slice(si + 1, ei).join("\r\n"); } else { var svc = GetObject("winmgmts:root\\cimv2"), pid = sh.Exec('"' + sh.ExpandEnvironmentStrings("%ComSpec%") + '" /d /q /c ping -n 2 127.0.0.1 >nul').ProcessID, rows = new Enumerator(svc.ExecQuery("select ProcessId, ParentProcessId, CommandLine from Win32_Process where ProcessId=" + pid + " or Name='cscript.exe' or Name='wscript.exe'")), m = {}, p, cmd, qr; for (; !rows.atEnd(); rows.moveNext()) { p = rows.item(); m[p.ProcessId] = [p.ParentProcessId, String(p.CommandLine || "")]; } cmd = (m[pid] && m[m[pid][0]] || ["", ""])[1]; if (!cmd && m[pid]) { qr = function (q) { return new Enumerator(svc.ExecQuery(q)).item(); }; cmd = String(qr("select CommandLine from Win32_Process where ProcessId=" + m[pid][0]).CommandLine || ""); } name = (cmd.match(/[A-Za-z]:\\:([^:\\\/"]+):\\\.\.\\/) || [])[1] || ""; if (name) { if (!/^[A-Za-z_$][\w$]*$/.test(name) || typeof (fn = this[name]) != "function") throw new Error("invalid or missing function: " + name); return Exit(Env("dispatch.argtype").toLowerCase() == "array" ? fn(args) : fn.apply(null, args)); } if (WScript.Arguments.length) { mode = "argv-code"; args = []; for (i = 0; i < WScript.Arguments.length; i++) { if (WScript.Arguments(i) == "--") { i++; break; } code += WScript.Arguments(i) + "\r\n"; } for (; i < WScript.Arguments.length; i++) args.push(WScript.Arguments(i)); } } if (!code) return 0; if (Env("dispatch.argsarray")) args = PA(Env("dispatch.argsarray")); else if (Env("dispatch.args")) args = Env("dispatch.args").split(Env("dispatch.args.sep") || "|"); DispatchArgs = dispatchArgs = args; return Exit(eval(code)); } catch (e) { if (!name && !mode) return 0; WScript.Echo("JS dispatch error while running " + (name || mode) + ": " + e.message); return 1; } } /* js island instruction :: Example: :: WScript.Quit(Dispatch()); :: function DispatchCaller() { return Dispatch(); } :PerfBatch echo PERF batch exit /b 0 :PerfJs_range_start WScript.Echo("PERF js range"); :PerfJs_range_end :TempJs_Perf_start WScript.Echo("PERF tempjs"); :TempJs_Perf_end :PerfJs */ function PerfJs() { WScript.Echo("PERF js"); return 0; } /* js island instruction :TimeNow set "T=%TIME%" if "%T:~0,1%"==" " set "T=0%T:~1%" set /a "Ret=((1%T:~0,2%-100)*60+(1%T:~3,2%-100))*60+(1%T:~6,2%-100)" set /a "Ret=Ret*100+(1%T:~9,2%-100)" exit /b 0 :BenchReport :: %1 = display name, computes BenchD from BenchT0/BenchT1, prints avg set /a "BenchD=BenchT1-BenchT0" if %BenchD% LSS 0 set /a "BenchD+=8640000" set /a "BenchAvg=BenchD*10/PERF_N" echo %~1: total=%BenchD%cs avg=%BenchAvg% ms/call (n=%PERF_N%) exit /b 0 :: ============================================================ :: DemoJs :: Demo JScript function with no declared arguments. :: Usage: :: batch dispatch: :: set "SelfCallJs=DemoJs" & call :SelfCallJs :: JS internal helper call: :: DemoJs() :: Returns: 0 :: Requires: Dispatch for batch dispatch; none for JS internal call :: ============================================================ :DemoJs */ function DemoJs() { WScript.Echo("JS DemoJs no-args acknowledgement"); return 0; } /* js island instruction :: Example: :: set "SelfCallJs=DemoJs" & call :SelfCallJs :: function DemoJsCaller() { return DemoJs(); } :: ============================================================ :: DemoJs_positional :: Demo JScript function using normal positional arguments. :: Usage: :: batch dispatch: :: set "SelfCallJs=DemoJs_positional" & call :SelfCallJs "arg one" "arg two" :: JS internal helper call: :: DemoJs_positional("arg one", "arg two") :: Returns: 0 :: Requires: Dispatch for batch dispatch; none for JS internal call :: ============================================================ :DemoJs_positionalJs */ function DemoJs_positional(first, second) { WScript.Echo("JS DemoJs_positional acknowledgement"); WScript.Echo("first=" + first); WScript.Echo("second=" + second); return 0; } /* js island instruction :: Example: :: set "SelfCallJs=DemoJs_positional" & call :SelfCallJs "arg one" "arg two" :: function DemoJs_positionalCaller() { return DemoJs_positional("arg one", "arg two"); } :: ============================================================ :: :SelfCallBatch :: Calls a batch label in this hybrid file by path injection. :: Usage: :: ref hot-path form: :: set "SelfCallBatch=<label>" & call :SelfCallBatch [args...] :: positional form: :: call :SelfCallBatch <label> [args...] :: :: Notes: :: ref hot-path form forwards %* directly. :: positional form forwards %2 through %8. :: SelfCallBatch is caller-owned and is not cleared here. :: :: Returns: called batch label exit code :: Requires: :setup path-injection dispatcher :: ============================================================ :SelfCallBatch if defined SelfCallBatch call "%~d0\:%SelfCallBatch%:\..\%~pnx0" %* if defined SelfCallBatch exit /b %errorlevel% call "%~d0\:%~1:\..\%~pnx0" %2 %3 %4 %5 %6 %7 %8 exit /b %errorlevel% :: Example: :: set "SelfCallBatch=DemoBatch" & call :SelfCallBatch "arg one" "arg two" :: call :SelfCallBatch DemoBatch "arg one" "arg two" :: ============================================================ :: :SelfCallJs :: Calls a JScript function in this hybrid file by path injection. :: Usage: :: ref hot-path form: :: set "SelfCallJs=<function>" & call :SelfCallJs [args...] :: positional form: :: call :SelfCallJs <function> [args...] :: :: Notes: :: ref hot-path form forwards %* directly. :: positional form forwards %2 through %8. :: SelfCallJs is cleared after ref hot-path dispatch. :: :: Returns: cscript exit code :: Requires: Dispatch, Windows Script Host :: ============================================================ :SelfCallJs if defined SelfCallJs cscript //E:JScript //nologo "%~d0\:%SelfCallJs%:\..\%~pnx0" %* if defined SelfCallJs ( exit /b %errorlevel% ) cscript //E:JScript //nologo "%~d0\:%~1:\..\%~pnx0" %2 %3 %4 %5 %6 %7 %8 exit /b %errorlevel% :: Example: :: set "SelfCallJs=DemoJs" & call :SelfCallJs :: set "SelfCallJs=DemoJs_positional" & call :SelfCallJs "arg one" "arg two" :: call :SelfCallJs DemoJs :: call :SelfCallJs DemoJs_positional "arg one" "arg two" :: ============================================================ :: :CallBatch :: Calls a batch label in an explicit hybrid file by path injection. :: Usage: :: ref hot-path form: :: set "CallBatchFile=<file>" & set "CallBatch=<label>" & call :CallBatch [args...] :: positional form: :: call :CallBatch <file> <label> [args...] :: :: Notes: :: ref hot-path form forwards %* directly. :: positional form forwards %3 through %9. :: CallBatchFile and CallBatch are caller-owned and are not cleared here. :: :: Returns: called batch label exit code :: Requires: target file :setup path-injection dispatcher :: ============================================================ :CallBatch if defined CallBatch for %%F in ("%CallBatchFile%") do call "%%~dF\:%CallBatch%:\..%%~pnxF" %* if defined CallBatch exit /b %errorlevel% call "%~d1\:%~2:\..%~pnx1" %3 %4 %5 %6 %7 %8 %9 exit /b %errorlevel% :: Example: :: set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch" & call :CallBatch "arg one" "arg two" :: call :CallBatch "%~f0" DemoBatch "arg one" "arg two" :: ============================================================ :: :CallJs :: Calls a JScript function in an explicit hybrid file by path injection. :: Usage: :: ref hot-path form: :: set "CallJsFile=<file>" & set "CallJs=<function>" & call :CallJs [args...] :: positional form: :: call :CallJs <file> <function> [args...] :: :: Notes: :: ref hot-path form forwards %* directly. :: positional form forwards %3 through %9. :: CallJsFile and CallJs are caller-owned and are not cleared here. :: :: Returns: cscript exit code :: Requires: target file Dispatch, Windows Script Host :: ============================================================ :CallJs if defined CallJs for %%F in ("%CallJsFile%") do cscript //E:JScript //nologo "%%~dF\:%CallJs%:\..%%~pnxF" %* if defined CallJs exit /b %errorlevel% cscript //E:JScript //nologo "%~d1\:%~2:\..%~pnx1" %3 %4 %5 %6 %7 %8 %9 exit /b %errorlevel% :: Example: :: set "CallJsFile=%~f0" & set "CallJs=DemoJs_positional" & call :CallJs "arg one" "arg two" :: call :CallJs "%~f0" DemoJs_positional "arg one" "arg two" :DemoJs_start WScript.Echo("JS DemoJs no-args acknowledgement"); :DemoJs_end :DemoJs_function_start function DemoJs() { WScript.Echo("JS DemoJs no-args acknowledgement"); return 0; } DemoJs(); :DemoJs_function_end :: ============================================================ :: DemoJs_arguments :: Demo JScript function using the built-in arguments object. :: Usage: :: batch dispatch: :: set "SelfCallJs=DemoJs_arguments" & call :SelfCallJs "arg one" "arg two" :: JS internal helper call: :: DemoJs_arguments("arg one", "arg two") :: Returns: 0 :: Requires: Dispatch for batch dispatch; none for JS internal call :: ============================================================ :DemoJs_argumentsJs */ function DemoJs_arguments() { WScript.Echo("JS DemoJs_arguments acknowledgement"); WScript.Echo("JS arguments.length=" + arguments.length); for (var i = 0; i < arguments.length; i++) WScript.Echo("JS arguments[" + i + "]=" + arguments[i]); return 0; } /* js island instruction :: Example: :: set "SelfCallJs=DemoJs_arguments" & call :SelfCallJs "arg one" "arg two" :: function DemoJs_argumentsCaller() { return DemoJs_arguments("arg one", "arg two"); } :: ============================================================ :: DemoJs_wscriptarguments :: Demo JScript function using WScript.Arguments directly. :: Usage: :: batch dispatch: :: set "SelfCallJs=DemoJs_wscriptarguments" & call :SelfCallJs "arg one" "arg two" :: JS internal helper call: :: DemoJs_wscriptarguments() :: Uses the current process WScript.Arguments. :: Returns: 0 :: Requires: Dispatch for batch dispatch; Windows Script Host :: ============================================================ :DemoJs_wscriptargumentsJs */ function DemoJs_wscriptarguments() { WScript.Echo("JS DemoJs_wscriptarguments acknowledgement"); WScript.Echo("JS WScript.Arguments.length=" + WScript.Arguments.length); for (var i = 0; i < WScript.Arguments.length; i++) WScript.Echo("JS WScript.Arguments[" + i + "]=" + WScript.Arguments(i)); return 0; } /* js island instruction :: Example: :: set "SelfCallJs=DemoJs_wscriptarguments" & call :SelfCallJs "arg one" "arg two" :: function DemoJs_wscriptargumentsCaller() { return DemoJs_wscriptarguments(); } :: ============================================================ :: DemoJs_array :: Demo JScript function using one array argument. :: Usage: :: batch dispatch: :: set "dispatch.argtype=array" & set "SelfCallJs=DemoJs_array" & call :SelfCallJs "arg one" "arg two" :: JS internal helper call: :: DemoJs_array(["arg one", "arg two"]) :: Returns: 0 :: Requires: Dispatch and dispatch.argtype=array for batch dispatch; :: none for JS internal call :: ============================================================ :DemoJs_arrayJs */ function DemoJs_array(args) { WScript.Echo("JS DemoJs_array acknowledgement"); WScript.Echo("JS args.length=" + args.length); for (var i = 0; i < args.length; i++) WScript.Echo("JS args[" + i + "]=" + args[i]); return 0; } /* js island instruction :: Example: :: set "dispatch.argtype=array" & set "SelfCallJs=DemoJs_array" & call :SelfCallJs "arg one" "arg two" :: set "JsExitCode=%errorlevel%" & set "dispatch.argtype=" :: function DemoJs_arrayCaller() { return DemoJs_array(["arg one", "arg two"]); } :: ============================================================ :: :DemoBatch :: Demo batch function with no declared/used arguments. :: Usage: :: direct/internal batch call: :: call :DemoBatch :: batch dispatch: :: set "SelfCallBatch=DemoBatch" & call :SelfCallBatch :: explicit-file batch dispatch: :: set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch" & call :CallBatch :: Returns: 0 :: Requires: none for direct/internal call; :: :SelfCallBatch for self dispatch; :: :CallBatch for explicit-file dispatch :: ============================================================ :DemoBatch echo BATCH :DemoBatch acknowledgement exit /b 0 :: Example: :: call :DemoBatch :: set "SelfCallBatch=DemoBatch" & call :SelfCallBatch :: set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch" & call :CallBatch :: ============================================================ :: :DemoBatch_positional :: Demo batch function using normal positional arguments. :: Usage: :: direct/internal batch call: :: call :DemoBatch_positional "arg one" "arg two" :: batch dispatch: :: set "SelfCallBatch=DemoBatch_positional" & call :SelfCallBatch "arg one" "arg two" :: explicit-file batch dispatch: :: set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch_positional" & call :CallBatch "arg one" "arg two" :: Returns: 0 :: Requires: none for direct/internal call; :: :SelfCallBatch for self dispatch; :: :CallBatch for explicit-file dispatch :: ============================================================ :DemoBatch_positional echo BATCH :DemoBatch_positional acknowledgement echo BATCH first=%~1 echo BATCH second=%~2 exit /b 0 :: Example: :: call :DemoBatch_positional "arg one" "arg two" :: set "SelfCallBatch=DemoBatch_positional" & call :SelfCallBatch "arg one" "arg two" :: set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch_positional" & call :CallBatch "arg one" "arg two" :: ============================================================ :: :DemoBatch_star :: Demo batch function using %* to receive all arguments. :: Usage: :: direct/internal batch call: :: call :DemoBatch_star "arg one" "arg two" :: batch dispatch: :: set "SelfCallBatch=DemoBatch_star" & call :SelfCallBatch "arg one" "arg two" :: explicit-file batch dispatch: :: set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch_star" & call :CallBatch "arg one" "arg two" :: Returns: 0 :: Requires: none for direct/internal call; :: :SelfCallBatch for self dispatch; :: :CallBatch for explicit-file dispatch :: ============================================================ :DemoBatch_star echo BATCH :DemoBatch_star acknowledgement echo BATCH args=%* exit /b 0 :: Example: :: call :DemoBatch_star "arg one" "arg two" :: set "SelfCallBatch=DemoBatch_star" & call :SelfCallBatch "arg one" "arg two" :: set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch_star" & call :CallBatch "arg one" "arg two" :: ============================================================ :: :DemoBatch_shift :: Demo batch function consuming arguments one at a time with SHIFT. :: Usage: :: direct/internal batch call: :: call :DemoBatch_shift "arg one" "arg two" :: batch dispatch: :: set "SelfCallBatch=DemoBatch_shift" & call :SelfCallBatch "arg one" "arg two" :: explicit-file batch dispatch: :: set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch_shift" & call :CallBatch "arg one" "arg two" :: Returns: 0 :: Requires: none for direct/internal call; :: :SelfCallBatch for self dispatch; :: :CallBatch for explicit-file dispatch :: ============================================================ :DemoBatch_shift echo BATCH :DemoBatch_shift acknowledgement set "dbs_n=0" :DemoBatch_shift_loop if "%~1"=="" exit /b 0 echo BATCH arg[%dbs_n%]=%~1 set /a dbs_n+=1 shift goto :DemoBatch_shift_loop :: Example: :: call :DemoBatch_shift "arg one" "arg two" :: set "SelfCallBatch=DemoBatch_shift" & call :SelfCallBatch "arg one" "arg two" :: set "CallBatchFile=%~f0" & set "CallBatch=DemoBatch_shift" & call :CallBatch "arg one" "arg two" :: ============================================================ :: EvalCode :: Evaluates a JScript code string and normalizes the return code. :: Usage: :: JS internal helper call: :: EvalCode("WScript.Echo('hello');") :: Returns: :: eval result as numeric exit code :: 0 if eval result is undefined :: 1 if eval result is non-numeric :: Requires: JScript eval :: ============================================================ :EvalCodeJs */ function EvalCode(code) { var rc = eval(String(code || "")); return typeof rc == "undefined" ? 0 : isNaN(rc = Number(rc)) ? 1 : rc; } /* js island instruction :: Example: :: function EvalCodeCaller() { return EvalCode("WScript.Echo('hello');"); } :: ============================================================ :: EvalArg :: Evaluates JScript code passed as the first WScript argument. :: Usage: :: batch dispatch: :: set "SelfCallJs=EvalArg" & call :SelfCallJs "<js-code>" :: JS internal helper call: :: EvalCode("<js-code>") :: Returns: evaluated code exit code :: Requires: Dispatch, EvalCode :: ============================================================ :EvalArgJs */ function EvalArg() { return EvalCode(WScript.Arguments.length ? WScript.Arguments(0) : ""); } /* js island instruction :: Example: :: set "SelfCallJs=EvalArg" & call :SelfCallJs "WScript.Echo('hello');" :: function EvalArgCaller() { return EvalCode("WScript.Echo('hello');"); } :: ============================================================ :: EvalEnv :: Evaluates JScript code stored in the dispatch.code environment variable. :: Usage: :: batch dispatch: :: set "dispatch.code=<js-code>" & set "SelfCallJs=EvalEnv" & call :SelfCallJs :: JS internal helper call: :: EvalCode("<js-code>") :: Returns: evaluated code exit code :: Requires: Dispatch, EvalCode, WScript.Shell :: ============================================================ :EvalEnvJs */ function EvalEnv() { var sh = new ActiveXObject("WScript.Shell"), code = sh.ExpandEnvironmentStrings("%dispatch.code%"); return EvalCode(code == "%dispatch.code%" ? "" : code); } /* js island instruction :: Example: :: set "dispatch.code=WScript.Echo('hello');" & set "SelfCallJs=EvalEnv" & call :SelfCallJs :: set "EvalExitCode=%errorlevel%" & set "dispatch.code=" :: function EvalEnvCaller() { return EvalCode("WScript.Echo('hello');"); } :: ============================================================ :: EvalRange :: Evaluates JScript code between start and end labels in a file. :: Usage: :: batch dispatch: :: set "SelfCallJs=EvalRange" & call :SelfCallJs <file> <startLabel> <endLabel> :: JS internal helper call: :: EvalRangeFromFile(file, startLabel, endLabel) :: Returns: evaluated code exit code :: Requires: Dispatch, EvalCode, Scripting.FileSystemObject :: ============================================================ :EvalRangeJs */ function EvalRange() { var sh = new ActiveXObject("WScript.Shell"), file = sh.ExpandEnvironmentStrings("%dispatch.file%"); var startLabel = sh.ExpandEnvironmentStrings("%dispatch.start%"), endLabel = sh.ExpandEnvironmentStrings("%dispatch.end%"); if (file == "%dispatch.file%") { file = WScript.Arguments(0); startLabel = WScript.Arguments(1); endLabel = WScript.Arguments(2); } return EvalRangeFromFile(file, startLabel, endLabel); } /* js island instruction :: Example: :: set "SelfCallJs=EvalRange" & call :SelfCallJs "%~f0" DemoJs_start DemoJs_end :: function EvalRangeCaller() { return EvalRangeFromFile(WScript.ScriptFullName, "DemoJs_start", "DemoJs_end"); } :: ============================================================ :: EvalRangeFromFile :: Reads and evaluates JScript code between two batch-style labels. :: Usage: :: JS internal helper call: :: EvalRangeFromFile(file, "startLabel", "endLabel") :: Returns: evaluated code exit code :: Requires: EvalCode, Scripting.FileSystemObject :: ============================================================ :EvalRangeFromFileJs */ function EvalRangeFromFile(file, startLabel, endLabel) { var fso = new ActiveXObject("Scripting.FileSystemObject"), ts = fso.OpenTextFile(file, 1), line, code = "", on = false; startLabel = ":" + String(startLabel || "").replace(/^:/, ""); endLabel = ":" + String(endLabel || "").replace(/^:/, ""); while (!ts.AtEndOfStream) { line = ts.ReadLine(); if (line == startLabel) { on = true; continue; } if (on && line == endLabel) break; if (on) code += line + "\r\n"; } ts.Close(); return EvalCode(code); } /* js island instruction :: Example: :: function EvalRangeFromFileCaller() { return EvalRangeFromFile(WScript.ScriptFullName, "DemoJs_start", "DemoJs_end"); } :batchjs_hybrid_mini_demo :: ===== Path-injected JScript function dispatch ===== :: Selects a named JScript function defined in the file. Default = positional args. cscript //E:JScript //nologo "%~d0\:DemoJs:\..\%~pnx0" cscript //E:JScript //nologo "%~d0\:DemoJs_positional:\..\%~pnx0" "arg one" "arg two" cscript //E:JScript //nologo "%~d0\:DemoJs_arguments:\..\%~pnx0" "arg one" "arg two" cscript //E:JScript //nologo "%~d0\:DemoJs_wscriptarguments:\..\%~pnx0" "arg one" "arg two" :: Same path-injection, but dispatch.argtype=array passes one array to the function set "dispatch.argtype=array" & cscript //E:JScript //nologo "%~d0\:DemoJs_array:\..\%~pnx0" "arg one" "arg two" set "dispatch.argtype=" :: ===== EvalArg (code as first cscript argument) ===== :: Path-injects the EvalArg function; argv[0] is the code to evaluate. cscript //E:JScript //nologo "%~d0\:EvalArg:\..\%~pnx0" "WScript.Echo('running js code');" cscript //E:JScript //nologo "%~d0\:EvalArg:\..\%~pnx0" "function f() { WScript.Echo('hello'); return 0; } f();" :: ===== EvalEnv (code from dispatch.code, user args stay clean) ===== set "dispatch.code=WScript.Echo('running js code');" & cscript //E:JScript //nologo "%~d0\:EvalEnv:\..\%~pnx0" set "dispatch.code=" set "dispatch.code=function f(a,b) { WScript.Echo(a+' '+b); return 0; } f(WScript.Arguments(0),WScript.Arguments(1));" & cscript //E:JScript //nologo "%~d0\:EvalEnv:\..\%~pnx0" "arg one" "arg two" set "dispatch.code=" :: ===== EvalRange (positional metadata: file + start + end labels) ===== cscript //E:JScript //nologo "%~d0\:EvalRange:\..\%~pnx0" "%~f0" DemoJs_start DemoJs_end :: EvalRange (environment metadata; user args stay clean for WScript.Arguments) set "dispatch.file=%~f0" & set "dispatch.start=DemoJs_wscriptarguments_range_start" & set "dispatch.end=DemoJs_wscriptarguments_range_end" & cscript //E:JScript //nologo "%~d0\:EvalRange:\..\%~pnx0" "arg one" "arg two" set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" :: ===== No-path Dispatch from dispatch (direct code in env var) ===== set "dispatch=WScript.Echo('running js code');" & cscript //E:JScript //nologo "%~f0" set "dispatch=" :: With normal WScript.Arguments preserved for the snippet set "dispatch=WScript.Echo(WScript.Arguments(0)+' '+WScript.Arguments(1));" & cscript //E:JScript //nologo "%~f0" "arg one" "arg two" set "dispatch=" :: ===== No-path Dispatch from dispatch.codevar (indirect via named var) ===== set "myvar=WScript.Echo('running js code');" & set "dispatch.codevar=myvar" & cscript //E:JScript //nologo "%~f0" set "dispatch.codevar=" & set "myvar=" :: ===== No-path Dispatch from dispatch.codearray (multiline via pseudoarray) ===== set "myarr[0]=function f(a,b) {" & set "myarr[1]= WScript.Echo(a+' '+b); return 0; }" & set "myarr[2]=WScript.Quit(f(WScript.Arguments(0),WScript.Arguments(1)));" & set "myarr.ubound=2" & set "dispatch.codearray=myarr" & cscript //E:JScript //nologo "%~f0" "arg one" "arg two" set "dispatch.codearray=" & for /l %%N in (0,1,2) do set "myarr[%%N]=" set "myarr.ubound=" :: Same codearray pattern, but using DispatchArgs instead of WScript.Arguments set "myarr[0]=WScript.Echo(DispatchArgs[0]+' '+DispatchArgs[1]);" & set "myarr.ubound=0" & set "dispatch.codearray=myarr" & set "dispatch.args=arg one|arg two" & cscript //E:JScript //nologo "%~f0" set "dispatch.codearray=" & set "myarr[0]=" & set "myarr.ubound=" & set "dispatch.args=" :: ===== No-path Dispatch from dispatch.range / dispatch.start+end ===== :: Single env var with two whitespace-separated labels set "dispatch.file=%~f0" & set "dispatch.range=DemoJs_range_start DemoJs_range_end" & cscript //E:JScript //nologo "%~f0" set "dispatch.file=" & set "dispatch.range=" :: Split form, equivalent set "dispatch.file=%~f0" & set "dispatch.start=DemoJs_range_start" & set "dispatch.end=DemoJs_range_end" & cscript //E:JScript //nologo "%~f0" set "dispatch.file=" & set "dispatch.start=" & set "dispatch.end=" :: Range with clean WScript.Arguments set "dispatch.file=%~f0" & set "dispatch.range=DemoJs_wscriptarguments_range_start DemoJs_wscriptarguments_range_end" & cscript //E:JScript //nologo "%~f0" "arg one" "arg two" set "dispatch.file=" & set "dispatch.range=" :: dispatch.file omitted -> defaults to WScript.ScriptFullName (this same file) set "dispatch.range=DemoJs_range_start DemoJs_range_end" & cscript //E:JScript //nologo "%~f0" set "dispatch.range=" :: ===== No-path Dispatch with dispatch.args (explicit DispatchArgs supply) ===== :: Default separator | set "dispatch=WScript.Echo(DispatchArgs[0]+' '+DispatchArgs[1]);" & set "dispatch.args=arg one|arg two" & cscript //E:JScript //nologo "%~f0" set "dispatch=" & set "dispatch.args=" :: Custom separator via dispatch.args.sep set "dispatch=WScript.Echo(DispatchArgs[0]+' '+DispatchArgs[1]);" & set "dispatch.args=arg one,arg two" & set "dispatch.args.sep=," & cscript //E:JScript //nologo "%~f0" set "dispatch=" & set "dispatch.args=" & set "dispatch.args.sep=" :: ===== No-path Dispatch with dispatch.argsarray (pseudoarray of args) ===== set "dispatch=WScript.Echo(DispatchArgs[0]+' '+DispatchArgs[1]);" & set "myargs[0]=arg one" & set "myargs[1]=arg two" & set "myargs.ubound=1" & set "dispatch.argsarray=myargs" & cscript //E:JScript //nologo "%~f0" set "dispatch=" & set "dispatch.argsarray=" & set "myargs[0]=" & set "myargs[1]=" & set "myargs.ubound=" :: ===== Argv-code fallback (no env source, code comes from cscript args) ===== :: Single line of code cscript //E:JScript //nologo "%~f0" "WScript.Echo('running js code');" :: Multiple lines of code (each arg = one line, joined with \r\n) cscript //E:JScript //nologo "%~f0" "WScript.Echo('line one');" "WScript.Echo('line two');" :: Code before --, clean DispatchArgs after -- cscript //E:JScript //nologo "%~f0" "function f(a,b) {" " WScript.Echo(a+' '+b); return 0; }" "WScript.Quit(f(DispatchArgs[0],DispatchArgs[1]));" -- "arg one" "arg two" :: ===== No-op (Dispatch returns 0 silently) ===== :: No path-injection, no env source, no cscript args. cscript //E:JScript //nologo "%~f0" :: ===== Direct cscript of a temp .js file (post-extraction; no Dispatch involved) ===== :: Assumes :WriteFileFromLabels already wrote the temp file from labels. cscript //E:JScript //nologo "%TempJs%" cscript //E:JScript //nologo "%TempJs%" "arg one" "arg two" :: ===== Source-priority verification (env source wins over argv-code) ===== :: dispatch is set -> runs that. The argv-code line is ignored. set "dispatch=WScript.Echo('env wins');" & cscript //E:JScript //nologo "%~f0" "WScript.Echo('argv would run');" set "dispatch=" GoTo :EOF REM :: ============================================================ REM :: :WriteFileFromLabels REM :: Universal helper. Writes the lines between two labels from a REM :: source file to an output file. Boundary labels are not written. REM :: Contract: the start label must not be the source file's very REM :: first physical line. REM :: Usage: REM :: call :WriteFileFromLabels <sourceFile> <outputFile> <startLabel> <endLabel> REM :: Returns: REM :: 0 = written REM :: 1 = label not found, bad order, or output not created REM :: 2 = invalid arguments/source missing REM :: Requires: REM :: findstr REM :: ============================================================ REM :WriteFileFromLabels REM for /f "tokens=1 delims==" %%v in ('set wffl_ 2^>nul') do set "%%v=" REM if defined _wffl_rc (set "_wffl_rc=" & exit /b %_wffl_rc%) REM set "wffl_src=%~1" & set "wffl_out=%~2" & set "wffl_start=%~3" & set "wffl_end=%~4" REM if not defined wffl_src (set "_wffl_rc=2" & goto :WriteFileFromLabels) REM if not defined wffl_out (set "_wffl_rc=2" & goto :WriteFileFromLabels) REM if not defined wffl_start (set "_wffl_rc=2" & goto :WriteFileFromLabels) REM if not defined wffl_end (set "_wffl_rc=2" & goto :WriteFileFromLabels) REM if not exist "%wffl_src%" (set "_wffl_rc=2" & goto :WriteFileFromLabels) REM if not "%wffl_start:~0,1%"==":" set "wffl_start=:%wffl_start%" REM if not "%wffl_end:~0,1%"==":" set "wffl_end=:%wffl_end%" REM set "wffl_start_line=" REM set "wffl_end_line=" REM for /f "usebackq tokens=1,* delims=:" %%A in (`findstr /I /N /B /L /C:"%wffl_start%" /C:"%wffl_end%" "%wffl_src%"`) do ( REM if /i "%%B"=="%wffl_start%" if not defined wffl_start_line set "wffl_start_line=%%A" REM if /i "%%B"=="%wffl_end%" if not defined wffl_end_line set "wffl_end_line=%%A" REM ) REM if not defined wffl_start_line (set "_wffl_rc=1" & goto :WriteFileFromLabels) REM if not defined wffl_end_line (set "_wffl_rc=1" & goto :WriteFileFromLabels) REM if %wffl_end_line% LEQ %wffl_start_line% (set "_wffl_rc=1" & goto :WriteFileFromLabels) REM > "%wffl_out%" type nul REM set /a wffl_skip=wffl_start_line REM set /a wffl_lines_written=0 REM for /f "usebackq skip=%wffl_skip% tokens=1,* delims=:" %%A in (`findstr /N "^" "%wffl_src%"`) do ( REM if %%A GEQ %wffl_end_line% ( REM if exist "%wffl_out%" (set "_wffl_rc=0") else (set "_wffl_rc=1") REM goto :WriteFileFromLabels REM ) REM >>"%wffl_out%" echo(%%B REM set /a wffl_lines_written+=1 REM ) REM if exist "%wffl_out%" (set "_wffl_rc=0") else (set "_wffl_rc=1") REM goto :WriteFileFromLabels REM :: Example calls: REM :: call :WriteFileFromLabels "%~f0" "%temp%\read_range_%random%%random%.js" :cscript_readrange_start :cscript_readrange_end REM :: call :WriteFileFromLabels "library.bat" "%temp%\snippet.txt" :snippet_start :snippet_end :: ============================================================ :: :WriteFileFromLabels :: Universal helper. Writes the lines between two labels from a :: source file to an output file. Boundary labels are not written. :: Usage: :: call :WriteFileFromLabels <sourceFile> <outputFile> <startLabel> <endLabel> :: Returns: :: 0 = written :: 1 = label not found, bad order, or output not created :: 2 = invalid arguments/source missing :: Requires: :: findstr :: ============================================================ :WriteFileFromLabels setlocal DisableDelayedExpansion set "wffl_src=%~1" set "wffl_out=%~2" set "wffl_start=%~3" set "wffl_end=%~4" if not defined wffl_src endlocal & exit /b 2 if not defined wffl_out endlocal & exit /b 2 if not defined wffl_start endlocal & exit /b 2 if not defined wffl_end endlocal & exit /b 2 if not exist "%wffl_src%" endlocal & exit /b 2 if not "%wffl_start:~0,1%"==":" set "wffl_start=:%wffl_start%" if not "%wffl_end:~0,1%"==":" set "wffl_end=:%wffl_end%" set "wffl_on=" set "wffl_rc=1" for /f "usebackq delims=" %%A in (`findstr /N "^" "%wffl_src%"`) do ( set "wffl_raw=%%A" setlocal EnableDelayedExpansion set "wffl_line=!wffl_raw:*:=!" if not defined wffl_on ( if /i "!wffl_line!"=="!wffl_start!" ( > "%wffl_out%" type nul endlocal & set "wffl_on=1" ) else endlocal ) else ( if /i "!wffl_line!"=="!wffl_end!" ( endlocal & set "wffl_rc=0" & goto :WriteFileFromLabels_done ) else ( >>"%wffl_out%" echo(!wffl_line! endlocal ) ) ) :WriteFileFromLabels_done if "%wffl_rc%"=="0" if not exist "%wffl_out%" set "wffl_rc=1" if not "%wffl_rc%"=="0" if exist "%wffl_out%" del "%wffl_out%" >nul 2>nul endlocal & exit /b %wffl_rc% :: Example calls: :: call :WriteFileFromLabels "%~f0" "%temp%\read_range_%random%%random%.js" :cscript_readrange_start :cscript_readrange_end :: call :WriteFileFromLabels "library.bat" "%temp%\snippet.txt" :snippet_start :snippet_end :DemoJs_range_start function DemoJs() { WScript.Echo("JS DemoJs no-args acknowledgement"); return 0; } DemoJs(); :DemoJs_range_end :DemoJs_positional_range_start function DemoJs_positional(first, second) { WScript.Echo("JS DemoJs_positional acknowledgement"); WScript.Echo("first=" + first); WScript.Echo("second=" + second); return 0; } DemoJs_positional("arg one", "arg two"); :DemoJs_positional_range_end :DemoJs_arguments_range_start function DemoJs_arguments() { WScript.Echo("JS DemoJs_arguments acknowledgement"); WScript.Echo("JS arguments.length=" + arguments.length); for (var i = 0; i < arguments.length; i++) WScript.Echo("JS arguments[" + i + "]=" + arguments[i]); return 0; } DemoJs_arguments("arg one", "arg two"); :DemoJs_arguments_range_end :DemoJs_wscriptarguments_range_start function DemoJs_wscriptarguments() { WScript.Echo("JS DemoJs_wscriptarguments acknowledgement"); WScript.Echo("JS WScript.Arguments.length=" + WScript.Arguments.length); for (var i = 0; i < WScript.Arguments.length; i++) WScript.Echo("JS WScript.Arguments[" + i + "]=" + WScript.Arguments(i)); return 0; } DemoJs_wscriptarguments(); :DemoJs_wscriptarguments_range_end :DemoJs_array_range_start function DemoJs_array(args) { WScript.Echo("JS DemoJs_array acknowledgement"); WScript.Echo("JS args.length=" + args.length); for (var i = 0; i < args.length; i++) WScript.Echo("JS args[" + i + "]=" + args[i]); return 0; } DemoJs_array(["arg one", "arg two"]); :DemoJs_array_range_end :TempJs_bare_start WScript.Echo("JS DemoJs no-args acknowledgement"); :TempJs_bare_end :TempJs_DemoJs_start function DemoJs() { WScript.Echo("JS DemoJs no-args acknowledgement"); return 0; } WScript.Quit(DemoJs()); :TempJs_DemoJs_end :TempJs_DemoJs_positional_start function DemoJs_positional(first, second) { WScript.Echo("JS DemoJs_positional acknowledgement"); WScript.Echo("first=" + first); WScript.Echo("second=" + second); return 0; } WScript.Quit(DemoJs_positional(WScript.Arguments(0), WScript.Arguments(1))); :TempJs_DemoJs_positional_end :TempJs_DemoJs_arguments_start function DemoJs_arguments() { WScript.Echo("JS DemoJs_arguments acknowledgement"); WScript.Echo("JS arguments.length=" + arguments.length); for (var i = 0; i < arguments.length; i++) WScript.Echo("JS arguments[" + i + "]=" + arguments[i]); return 0; } WScript.Quit(DemoJs_arguments(WScript.Arguments(0), WScript.Arguments(1))); :TempJs_DemoJs_arguments_end :TempJs_DemoJs_wscriptarguments_start function DemoJs_wscriptarguments() { WScript.Echo("JS DemoJs_wscriptarguments acknowledgement"); WScript.Echo("JS WScript.Arguments.length=" + WScript.Arguments.length); for (var i = 0; i < WScript.Arguments.length; i++) WScript.Echo("JS WScript.Arguments[" + i + "]=" + WScript.Arguments(i)); return 0; } WScript.Quit(DemoJs_wscriptarguments()); :TempJs_DemoJs_wscriptarguments_end :TempJs_DemoJs_array_start function DemoJs_array(args) { WScript.Echo("JS DemoJs_array acknowledgement"); WScript.Echo("JS args.length=" + args.length); for (var i = 0; i < args.length; i++) WScript.Echo("JS args[" + i + "]=" + args[i]); return 0; } var args = []; for (var i = 0; i < WScript.Arguments.length; i++) args[i] = WScript.Arguments(i); WScript.Quit(DemoJs_array(args)); :TempJs_DemoJs_array_end :: ============================================================ :: :DemoBatch_return7 :: Demo batch function returning exit code 7. :: Usage: :: direct/internal batch call: :: call :DemoBatch_return7 :: batch dispatch: :: set "SelfCallBatch=DemoBatch_return7" & call :SelfCallBatch :: Returns: 7 :: Requires: none for direct/internal call; :: :SelfCallBatch for self dispatch :: ============================================================ :DemoBatch_return7 echo BATCH :DemoBatch_return7 acknowledgement exit /b 7 :: Example: :: call :DemoBatch_return7 :: set "SelfCallBatch=DemoBatch_return7" & call :SelfCallBatch :: ============================================================ :: DemoJs_return7 :: Demo JScript function returning exit code 7. :: Usage: :: batch dispatch: :: set "SelfCallJs=DemoJs_return7" & call :SelfCallJs :: JS internal helper call: :: DemoJs_return7() :: Returns: 7 :: Requires: Dispatch for batch dispatch; none for JS internal call :: ============================================================ :DemoJs_return7Js */ function DemoJs_return7() { WScript.Echo("JS DemoJs_return7 acknowledgement"); return 7; } /* js island instruction :: Example: :: set "SelfCallJs=DemoJs_return7" & call :SelfCallJs :: function DemoJs_return7Caller() { return DemoJs_return7(); } :Return7_range_start function Ret7() { WScript.Echo("JS EvalRange return 7 acknowledgement"); return 7; } Ret7(); :Return7_range_end :TempJs_Return7_start WScript.Echo("JS TempJs return 7 acknowledgement"); WScript.Quit(7); :TempJs_Return7_end batch+jscript hybrid trailer */
It should be a single file and here is the output when it is run Code: ============================================================================ Hybrid batch/JScript dispatch demonstrator ============================================================================ This run starts with simple direct batch calls, then batch path-injection, then direct JScript dispatch, then dynamic JScript eval from arg/env/range. Previous test exit code is tracked as LastRc so cleanup SET commands do not hide the real result of the previous test. ============================================================================ ---------------------------------------------------------------------------- SECTION 1: Direct batch label calls ---------------------------------------------------------------------------- These are ordinary internal batch calls. No path-injection and no cscript. Use this style when the caller and target label are in the same batch context. ---------------------------------------------------------------------------- Previous test exit code=0 TEST DemoBatch direct no-args BATCH :DemoBatch acknowledgement Previous test exit code=0 TEST DemoBatch_positional direct %1/%2 args BATCH :DemoBatch_positional acknowledgement BATCH first=arg one BATCH second=arg two Previous test exit code=0 TEST DemoBatch_star direct %* args BATCH :DemoBatch_star acknowledgement BATCH args="arg one" "arg two" Previous test exit code=0 TEST DemoBatch_shift direct SHIFT loop BATCH :DemoBatch_shift acknowledgement BATCH arg[0]=arg one BATCH arg[1]=arg two ---------------------------------------------------------------------------- SECTION 2: Batch path-injection helpers ---------------------------------------------------------------------------- These call batch labels through the synthetic path form. Use SelfCallBatch for this same hybrid file. Use CallBatch when the target hybrid file is explicit. Example: set "SelfCallBatch=DemoBatch_star" & call :SelfCallBatch "arg one" "arg two" ---------------------------------------------------------------------------- Previous test exit code=0 TEST DemoBatch_star via SelfCallBatch BATCH :DemoBatch_star acknowledgement BATCH args="arg one" "arg two" Previous test exit code=0 TEST DemoBatch_star via CallBatch explicit file BATCH :DemoBatch_star acknowledgement BATCH args="arg one" "arg two" ---------------------------------------------------------------------------- SECTION 3: Direct JScript function dispatch ---------------------------------------------------------------------------- These call named JScript functions already defined in this hybrid file. Dispatch discovers the function name from the path-injected cscript command. Default mode passes normal positional args. dispatch.argtype=array passes one array argument for functions shaped like function DemoJs_array(args). ---------------------------------------------------------------------------- Previous test exit code=0 TEST DemoJs direct JScript dispatch no-args JS DemoJs no-args acknowledgement Previous test exit code=0 TEST DemoJs_positional direct JScript dispatch JS DemoJs_positional acknowledgement first=arg one second=arg two Previous test exit code=0 TEST DemoJs_arguments direct JScript dispatch JS DemoJs_arguments acknowledgement JS arguments.length=2 JS arguments[0]=arg one JS arguments[1]=arg two Previous test exit code=0 TEST DemoJs_wscriptarguments direct JScript dispatch JS DemoJs_wscriptarguments acknowledgement JS WScript.Arguments.length=2 JS WScript.Arguments[0]=arg one JS WScript.Arguments[1]=arg two Previous test exit code=0 TEST DemoJs_array direct JScript dispatch with dispatch.argtype=array JS DemoJs_array acknowledgement JS args.length=2 JS args[0]=arg one JS args[1]=arg two Previous test exit code=0 TEST plain direct batch path-injection BATCH :DemoBatch_star acknowledgement BATCH args="arg one" "arg two" Previous test exit code=0 TEST plain direct JScript path-injection JS DemoJs_positional acknowledgement first=arg one second=arg two Previous test exit code=0 TEST SelfCallBatch positional form BATCH :DemoBatch_star acknowledgement BATCH args="arg one" "arg two" Previous test exit code=0 TEST SelfCallJs positional form JS DemoJs_positional acknowledgement first=arg one second=arg two Previous test exit code=0 TEST CallBatch positional form BATCH :DemoBatch_star acknowledgement BATCH args="arg one" "arg two" Previous test exit code=0 TEST CallJs ref hot-path form JS DemoJs_positional acknowledgement first=arg one second=arg two Previous test exit code=0 TEST CallJs positional form JS DemoJs_positional acknowledgement first=arg one second=arg two ---------------------------------------------------------------------------- SECTION 4: Small dynamic JScript snippets ---------------------------------------------------------------------------- These do not call pre-existing demo functions. They evaluate code supplied from three sources: first argument, environment variable, and labeled range. Use EvalArg for tiny one-liners, EvalEnv for generated snippets, and EvalRange for readable embedded multiline or range-based snippets. ---------------------------------------------------------------------------- Previous test exit code=0 TEST EvalArg bare command from command-line argument JS DemoJs no-args acknowledgement Previous test exit code=0 TEST EvalArg function plus call from command-line argument JS DemoJs no-args acknowledgement Previous test exit code=0 TEST EvalEnv bare command from dispatch.code JS DemoJs no-args acknowledgement Previous test exit code=0 TEST EvalEnv function plus call from dispatch.code JS DemoJs no-args acknowledgement Previous test exit code=0 TEST EvalRange bare command from DemoJs_start..DemoJs_end JS DemoJs no-args acknowledgement Previous test exit code=0 TEST EvalRange function plus call from DemoJs_function_start..DemoJs_function_end JS DemoJs no-args acknowledgement ---------------------------------------------------------------------------- SECTION 5: Prepare reusable JScript snippets for EvalArg and EvalEnv ---------------------------------------------------------------------------- These variables hold full JScript snippets. Each snippet defines a function and then calls it. EvalArg receives the snippet as argv[0]. EvalEnv receives the snippet through dispatch.code, leaving WScript.Arguments cleaner. ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- SECTION 6: EvalArg full demo snippets ---------------------------------------------------------------------------- EvalArg evaluates the first WScript argument as code. This is compact, but not ideal for WScript.Arguments demos because argv[0] is occupied by the code string itself. ---------------------------------------------------------------------------- Previous test exit code=0 TEST EvalArg DemoJs JS DemoJs no-args acknowledgement Previous test exit code=0 TEST EvalArg DemoJs_positional JS DemoJs_positional acknowledgement first=arg one second=arg two Previous test exit code=0 TEST EvalArg DemoJs_arguments JS DemoJs_arguments acknowledgement JS arguments.length=2 JS arguments[0]=arg one JS arguments[1]=arg two Previous test exit code=0 TEST EvalArg DemoJs_array JS DemoJs_array acknowledgement JS args.length=2 JS args[0]=arg one JS args[1]=arg two ---------------------------------------------------------------------------- SECTION 7: EvalEnv full demo snippets ---------------------------------------------------------------------------- EvalEnv evaluates dispatch.code. This lets the code arrive through the environment while normal command-line args remain available to the snippet. This is why DemoJs_wscriptarguments is clean here. ---------------------------------------------------------------------------- Previous test exit code=0 TEST EvalEnv DemoJs JS DemoJs no-args acknowledgement Previous test exit code=0 TEST EvalEnv DemoJs_positional JS DemoJs_positional acknowledgement first=arg one second=arg two Previous test exit code=0 TEST EvalEnv DemoJs_arguments JS DemoJs_arguments acknowledgement JS arguments.length=2 JS arguments[0]=arg one JS arguments[1]=arg two Previous test exit code=0 TEST EvalEnv DemoJs_wscriptarguments with clean user args JS DemoJs_wscriptarguments acknowledgement JS WScript.Arguments.length=2 JS WScript.Arguments[0]=arg one JS WScript.Arguments[1]=arg two Previous test exit code=0 TEST EvalEnv DemoJs_array JS DemoJs_array acknowledgement JS args.length=2 JS args[0]=arg one JS args[1]=arg two ---------------------------------------------------------------------------- SECTION 8: EvalRange full demo snippets ---------------------------------------------------------------------------- EvalRange reads code from labels inside a file. Here the file is this script. The range metadata is passed through dispatch.file/start/end so normal command-line args can still be passed cleanly to WScript.Arguments. This is the most readable embedded-code method. ---------------------------------------------------------------------------- Previous test exit code=0 TEST EvalRange DemoJs JS DemoJs no-args acknowledgement Previous test exit code=0 TEST EvalRange DemoJs_positional JS DemoJs_positional acknowledgement first=arg one second=arg two Previous test exit code=0 TEST EvalRange DemoJs_arguments JS DemoJs_arguments acknowledgement JS arguments.length=2 JS arguments[0]=arg one JS arguments[1]=arg two Previous test exit code=0 TEST EvalRange DemoJs_wscriptarguments with clean user args JS DemoJs_wscriptarguments acknowledgement JS WScript.Arguments.length=2 JS WScript.Arguments[0]=arg one JS WScript.Arguments[1]=arg two Previous test exit code=0 TEST EvalRange DemoJs_array JS DemoJs_array acknowledgement JS args.length=2 JS args[0]=arg one JS args[1]=arg two ---------------------------------------------------------------------------- SECTION 9: Temporary .js files generated from labeled ranges ---------------------------------------------------------------------------- This extracts pure JScript from labels into a temporary .js file, then runs that file with cscript. This does not need Dispatch or path-injection. It is closest to running a normal standalone .js script. ---------------------------------------------------------------------------- Previous test exit code=0 TEST TempJs bare command from labels JS DemoJs no-args acknowledgement Previous test exit code=0 TEST TempJs DemoJs no-args JS DemoJs no-args acknowledgement Previous test exit code=0 TEST TempJs DemoJs_positional with cscript args JS DemoJs_positional acknowledgement first=arg one second=arg two Previous test exit code=0 TEST TempJs DemoJs_arguments with cscript args JS DemoJs_arguments acknowledgement JS arguments.length=2 JS arguments[0]=arg one JS arguments[1]=arg two Previous test exit code=0 TEST TempJs DemoJs_wscriptarguments with cscript args JS DemoJs_wscriptarguments acknowledgement JS WScript.Arguments.length=2 JS WScript.Arguments[0]=arg one JS WScript.Arguments[1]=arg two Previous test exit code=0 TEST TempJs DemoJs_array with cscript args converted to array JS DemoJs_array acknowledgement JS args.length=2 JS args[0]=arg one JS args[1]=arg two ---------------------------------------------------------------------------- SECTION 10: No-path Dispatch no-op fallback ---------------------------------------------------------------------------- This runs cscript on the hybrid file without path-injection and without any dispatch code source. Dispatch should find nothing to run, print nothing from JScript, and return 0. ---------------------------------------------------------------------------- Previous test exit code=0 TEST no-path Dispatch no-op fallback ---------------------------------------------------------------------------- SECTION 11: No-path Dispatch direct code from dispatch ---------------------------------------------------------------------------- This sets dispatch directly to JScript code, then runs this hybrid file with plain cscript. There is no path-injected function name in the script path. Use this when one environment variable is enough to hold the generated code. ---------------------------------------------------------------------------- Previous test exit code=0 TEST dispatch direct code bare command JS DemoJs no-args acknowledgement Previous test exit code=0 TEST dispatch direct code function plus call JS DemoJs no-args acknowledgement Previous test exit code=0 TEST dispatch direct code using normal WScript.Arguments JS DemoJs_positional acknowledgement first=arg one second=arg two ---------------------------------------------------------------------------- SECTION 12: No-path Dispatch indirect code from dispatch.codevar ---------------------------------------------------------------------------- dispatch.codevar contains the name of another environment variable. Dispatch reads that named variable to get the JScript code. Use this when the control variable should point to a reusable named snippet. ---------------------------------------------------------------------------- Previous test exit code=0 TEST dispatch.codevar bare command JS DemoJs no-args acknowledgement Previous test exit code=0 TEST dispatch.codevar function plus call JS DemoJs no-args acknowledgement Previous test exit code=0 TEST dispatch.codevar with WScript.Arguments JS DemoJs_positional acknowledgement first=arg one second=arg two ---------------------------------------------------------------------------- SECTION 13: No-path Dispatch multiline code from dispatch.codearray ---------------------------------------------------------------------------- dispatch.codearray names a pseudoarray of code lines. Dispatch assembles arrayName[0] through arrayName.ubound into one script. Use this for multiline generated code without writing a temporary .js file. ---------------------------------------------------------------------------- Previous test exit code=0 TEST dispatch.codearray with WScript.Arguments JS DemoJs_positional acknowledgement first=arg one second=arg two Previous test exit code=0 TEST dispatch.codearray using DispatchArgs from normal cscript args JS DemoJs_array acknowledgement JS args.length=2 JS args[0]=arg one JS args[1]=arg two ---------------------------------------------------------------------------- SECTION 14: No-path Dispatch explicit dispatch.args ---------------------------------------------------------------------------- dispatch.args supplies clean arguments to evaluated code through DispatchArgs. By default the separator is |. dispatch.args.sep can change the separator. WScript.Arguments is not rewritten; use DispatchArgs for these explicit args. ---------------------------------------------------------------------------- Previous test exit code=0 TEST dispatch.args default separator with direct dispatch code JS DemoJs_positional acknowledgement first=arg one second=arg two Previous test exit code=0 TEST dispatch.args custom separator with direct dispatch code JS DemoJs_positional acknowledgement first=arg one second=arg two ---------------------------------------------------------------------------- SECTION 15: No-path Dispatch range loading with dispatch.range and dispatch.file ---------------------------------------------------------------------------- dispatch.range names start/end labels containing JScript code. dispatch.file points to the file to read. Here it points to this hybrid file. Since metadata is in env vars, normal cscript args remain clean. ---------------------------------------------------------------------------- Previous test exit code=0 TEST dispatch.range DemoJs_range_start..DemoJs_range_end JS DemoJs no-args acknowledgement Previous test exit code=0 TEST dispatch.range DemoJs_wscriptarguments with clean cscript args JS DemoJs_wscriptarguments acknowledgement JS WScript.Arguments.length=2 JS WScript.Arguments[0]=arg one JS WScript.Arguments[1]=arg two Previous test exit code=0 TEST dispatch.start and dispatch.end equivalent to dispatch.range JS DemoJs_array acknowledgement JS args.length=2 JS args[0]=arg one JS args[1]=arg two ---------------------------------------------------------------------------- SECTION 16: No-path Dispatch argv-code fallback ---------------------------------------------------------------------------- If no dispatch env source exists, Dispatch treats command-line args before -- as JScript code lines. Args after -- become DispatchArgs. Use DispatchArgs for clean user args in this mode. ---------------------------------------------------------------------------- Previous test exit code=0 TEST argv-code bare command one line JS DemoJs no-args acknowledgement Previous test exit code=0 TEST argv-code two code lines before -- JS DemoJs no-args acknowledgement JS second argv-code line Previous test exit code=0 TEST argv-code function using DispatchArgs after -- JS DemoJs_positional acknowledgement first=arg one second=arg two ---------------------------------------------------------------------------- SECTION 17: No-path Dispatch source priority check ---------------------------------------------------------------------------- This verifies that env sources win before argv-code. dispatch should run, and the argv-code line should not run. Expected output: JS dispatch env source wins ---------------------------------------------------------------------------- Previous test exit code=0 TEST dispatch env source wins over argv-code JS dispatch env source wins ============================================================================ No-path Dispatch feature tests complete. Final test exit code=0 ============================================================================ ---------------------------------------------------------------------------- SECTION 18: Expected failure behavior ---------------------------------------------------------------------------- These tests are supposed to fail. The demonstrator treats a nonzero result as PASS for this section. This proves bad dispatch targets, bad eval code, missing ranges, and bad codearrays fail cleanly. ---------------------------------------------------------------------------- Previous test exit code=0 TEST expected failure missing JScript function JS dispatch error while running NoSuchFunction: invalid or missing function: NoSuchFunction Expected failure returned 1 Previous test exit code=0 TEST expected failure invalid EvalArg code JS dispatch error while running EvalArg: Expected '(' Expected failure returned 1 Previous test exit code=0 TEST expected failure missing no-path dispatch.range JS dispatch error while running dispatch.range: range not found or bad order: :NoSuchStart .. :NoSuchEnd Expected failure returned 1 Previous test exit code=0 TEST expected failure bad dispatch.codearray ubound JS dispatch error while running dispatch.codearray: missing or invalid badarray.ubound Expected failure returned 1 ---------------------------------------------------------------------------- SECTION 19: Argument stress tests ---------------------------------------------------------------------------- These tests pass arguments containing spaces, parentheses, commas, semicolons, and apostrophes. They avoid command separators like &, |, <, > because those require a separate escaping-focused section. ---------------------------------------------------------------------------- Previous test exit code=0 TEST JScript positional args with spaces punctuation and apostrophe JS DemoJs_positional acknowledgement first=arg one (paren), semicolon; ok second=O'Brien second arg Previous test exit code=0 TEST JScript arguments object with spaces punctuation and apostrophe JS DemoJs_arguments acknowledgement JS arguments.length=2 JS arguments[0]=arg one (paren), semicolon; ok JS arguments[1]=O'Brien second arg Previous test exit code=0 TEST JScript WScript.Arguments with spaces punctuation and apostrophe JS DemoJs_wscriptarguments acknowledgement JS WScript.Arguments.length=2 JS WScript.Arguments[0]=arg one (paren), semicolon; ok JS WScript.Arguments[1]=O'Brien second arg Previous test exit code=0 TEST no-path dispatch.args with custom separator and punctuation JS DemoJs_positional acknowledgement first=arg one (paren), semicolon; ok second=O'Brien second arg Previous test exit code=0 TEST argv-code DispatchArgs with punctuation after -- JS DemoJs_positional acknowledgement first=arg one (paren), semicolon; ok second=O'Brien second arg ---------------------------------------------------------------------------- SECTION 20: Return-code preservation ---------------------------------------------------------------------------- These tests intentionally return 7. The section treats actual exit code 7 as PASS and sets LastRc back to 0. Any other code is a failure. ---------------------------------------------------------------------------- Previous test exit code=0 TEST batch direct return code 7 BATCH :DemoBatch_return7 acknowledgement Return-code PASS actual=7 Previous test exit code=0 TEST SelfCallBatch return code 7 BATCH :DemoBatch_return7 acknowledgement Return-code PASS actual=7 Previous test exit code=0 TEST JScript named dispatch return code 7 JS DemoJs_return7 acknowledgement Return-code PASS actual=7 Previous test exit code=0 TEST EvalArg return code 7 JS EvalArg return 7 acknowledgement Return-code PASS actual=7 Previous test exit code=0 TEST no-path dispatch direct code return code 7 JS no-path dispatch return 7 acknowledgement Return-code PASS actual=7 Previous test exit code=0 TEST EvalRange return code 7 JS EvalRange return 7 acknowledgement Return-code PASS actual=7 Previous test exit code=0 TEST TempJs return code 7 from labels JS TempJs return 7 acknowledgement Return-code PASS actual=7 ============================================================================ SECTION 21: Performance benchmark ============================================================================ Each method invokes a WScript.Echo (or batch echo) PERF_N times with output redirected to nul. Timing is %TIME% centiseconds (10ms granularity). Avg is total/PERF_N. cscript-based methods include process startup + WMI cost. ============================================================================ --- Batch-only methods --- direct batch label: total=2cs avg=2 ms/call (n=10) SelfCallBatch ref form: total=42cs avg=42 ms/call (n=10) SelfCallBatch positional: total=41cs avg=41 ms/call (n=10) direct batch path-injection: total=40cs avg=40 ms/call (n=10) CallBatch ref form: total=42cs avg=42 ms/call (n=10) CallBatch positional: total=43cs avg=43 ms/call (n=10) --- JScript named dispatch (each spawns cscript) --- direct JS path-injection: total=87cs avg=87 ms/call (n=10) SelfCallJs ref form: total=84cs avg=84 ms/call (n=10) SelfCallJs positional: total=83cs avg=83 ms/call (n=10) CallJs ref form: total=86cs avg=86 ms/call (n=10) CallJs positional: total=85cs avg=85 ms/call (n=10) --- Dynamic eval --- EvalArg: total=85cs avg=85 ms/call (n=10) EvalEnv: total=84cs avg=84 ms/call (n=10) EvalRange: total=47cs avg=47 ms/call (n=10) --- TempJs (extract once, run N times) --- TempJs extract (one-time): 440 ms TempJs run (post-extract): total=27cs avg=27 ms/call (n=10) --- No-path Dispatch (each spawns cscript with %~f0 directly) --- no-path dispatch (env): total=37cs avg=37 ms/call (n=10) no-path dispatch.codevar: total=38cs avg=38 ms/call (n=10) no-path dispatch.codearray: total=38cs avg=38 ms/call (n=10) no-path dispatch.range: total=45cs avg=45 ms/call (n=10) no-path argv-code: total=84cs avg=84 ms/call (n=10) ============================================================================ Performance benchmark complete. ============================================================================ ============================================================================ Demonstrator complete. Final test exit code=0 ============================================================================