puts stderr "Sorry - only single input file supported. Supply a file extension or use a <scriptset>_wrap.toml config with a single input file for now - implementation incomplete"
return false
}
#todo - split template at each <ext-*-subprocess> etc marker and build a dict of parts
#if {[llength $list_input_files] > 1} {
# #todo
# puts stderr "Sorry - only single input file supported. Supply a file extension or use a <scriptset>_wrap.toml config with a single input file for now - implementation incomplete"
# return false
#}
#hack - process one input
set filepath [lindex $list_input_files 0]
set fdscript [open $filepath r]
fconfigure $fdscript -translation binary
set script_data [read $fdscript]
close $fdscript
puts stdout "Read [string length $script_data] bytes of template data.."
set script_lines [split $script_data \n]
puts stdout "Displaying first 3 lines of your script between dashed lines..."
puts stdout "Target for script data is '$output_file'"
puts stdout "Language of script being wrapped is [a bold yellow]$lang[a]"
if {$opt_askme} {
set answer [util::askuser "Does this look correct? Y|N"]
if {[string tolower $answer] ne "y"} {
puts stderr "mix new aborting due to user response '$answer' (required Y or y to proceed) use -askme 0 to avoid prompts."
return
}
}
}
set start_idx 0
set end_idx 0
set line_idx 0
set existing_payload [list]
set template_ranges [list]
set data_items [list]
set trange [list 0]
set line_idx -1
set opentag ""
foreach ln $template_lines {
if {[string match "#<$lang-pre-launch-subprocess>*" $ln]} {
set start_idx $line_idx
} elseif {[string match "#</$lang-pre-launch-subprocess>*" $ln]} {
set end_idx $line_idx
break
} elseif {$start_idx > 0} {
if {$end_idx > 0} {
lappend existing_payload [string trim $ln]
}
incr line_idx
if {$opentag eq ""} {
if {[string match ": <<asadmin_start>>*" $ln]} {
set opentag asadmin
lset trange 1 $line_idx ;#include tag in template
lappend template_ranges $trange
set trange [list $line_idx]
set asadmin [dict get $configd as_admin]
set scr "@SET \"asadmin=$asadmin\""
lappend data_items $scr
} elseif {[string match ": <<nextshell_start>>*" $ln]} {
set opentag nextshell
lset trange 1 $line_idx
lappend template_ranges $trange
set trange [list $line_idx]
set nextshell_script [_get_nextshell_script $configd]
#puts stderr "-------------------"
#puts stderr "$nextshell_script"
lappend data_items $nextshell_script
} elseif {[string match "#<*-payload>*" $ln]} {
regexp {#<(.*)-payload>.*} $ln _ lang
if {[dict exists $lang_data $lang]} {
set script_lines [dict get $lang_data $lang]
set opentag payload-$lang
lset trange 1 $line_idx
lappend template_ranges $trange
lappend data_items [join $script_lines \n]
}
}
} else {
switch -- [string range $opentag 0 6] {
asadmin {
if {[string match ": <<asadmin_end>>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
nextshe {
if {[string match ": <<nextshell_end>>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
payload {
set lang [string range $opentag 8 end] ;#payload-xxx
if {[string match "#</$lang-payload>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
}
}
incr line_idx
}
if {($start_idx == 0) || ($end_idx == 0)} {
error "wrap_in_multishell was unable to find payload area in template marked with #<$lang-pre-launch-subprocess> and #</$lang-pre-launch-subprocess> on separate lines"
if {$opentag eq ""} {
lset trange 1 end
lappend template_ranges $trange
} else {
error "multishell - unable to find closing tag for '$opentag'"
}
set existing_string [join $existing_payload \n]
if {[string length [string trim $existing_string]]} {
puts stderr "Sorry - only single input file supported. Supply a file extension or use a <scriptset>_wrap.toml config with a single input file for now - implementation incomplete"
return false
}
#todo - split template at each <ext-*-subprocess> etc marker and build a dict of parts
#if {[llength $list_input_files] > 1} {
# #todo
# puts stderr "Sorry - only single input file supported. Supply a file extension or use a <scriptset>_wrap.toml config with a single input file for now - implementation incomplete"
# return false
#}
#hack - process one input
set filepath [lindex $list_input_files 0]
set fdscript [open $filepath r]
fconfigure $fdscript -translation binary
set script_data [read $fdscript]
close $fdscript
puts stdout "Read [string length $script_data] bytes of template data.."
set script_lines [split $script_data \n]
puts stdout "Displaying first 3 lines of your script between dashed lines..."
puts stdout "Target for script data is '$output_file'"
puts stdout "Language of script being wrapped is [a bold yellow]$lang[a]"
if {$opt_askme} {
set answer [util::askuser "Does this look correct? Y|N"]
if {[string tolower $answer] ne "y"} {
puts stderr "mix new aborting due to user response '$answer' (required Y or y to proceed) use -askme 0 to avoid prompts."
return
}
}
}
set start_idx 0
set end_idx 0
set line_idx 0
set existing_payload [list]
set template_ranges [list]
set data_items [list]
set trange [list 0]
set line_idx -1
set opentag ""
foreach ln $template_lines {
if {[string match "#<$lang-pre-launch-subprocess>*" $ln]} {
set start_idx $line_idx
} elseif {[string match "#</$lang-pre-launch-subprocess>*" $ln]} {
set end_idx $line_idx
break
} elseif {$start_idx > 0} {
if {$end_idx > 0} {
lappend existing_payload [string trim $ln]
}
incr line_idx
if {$opentag eq ""} {
if {[string match ": <<asadmin_start>>*" $ln]} {
set opentag asadmin
lset trange 1 $line_idx ;#include tag in template
lappend template_ranges $trange
set trange [list $line_idx]
set asadmin [dict get $configd as_admin]
set scr "@SET \"asadmin=$asadmin\""
lappend data_items $scr
} elseif {[string match ": <<nextshell_start>>*" $ln]} {
set opentag nextshell
lset trange 1 $line_idx
lappend template_ranges $trange
set trange [list $line_idx]
set nextshell_script [_get_nextshell_script $configd]
#puts stderr "-------------------"
#puts stderr "$nextshell_script"
lappend data_items $nextshell_script
} elseif {[string match "#<*-payload>*" $ln]} {
regexp {#<(.*)-payload>.*} $ln _ lang
if {[dict exists $lang_data $lang]} {
set script_lines [dict get $lang_data $lang]
set opentag payload-$lang
lset trange 1 $line_idx
lappend template_ranges $trange
lappend data_items [join $script_lines \n]
}
}
} else {
switch -- [string range $opentag 0 6] {
asadmin {
if {[string match ": <<asadmin_end>>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
nextshe {
if {[string match ": <<nextshell_end>>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
payload {
set lang [string range $opentag 8 end] ;#payload-xxx
if {[string match "#</$lang-payload>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
}
}
incr line_idx
}
if {($start_idx == 0) || ($end_idx == 0)} {
error "wrap_in_multishell was unable to find payload area in template marked with #<$lang-pre-launch-subprocess> and #</$lang-pre-launch-subprocess> on separate lines"
if {$opentag eq ""} {
lset trange 1 end
lappend template_ranges $trange
} else {
error "multishell - unable to find closing tag for '$opentag'"
}
set existing_string [join $existing_payload \n]
if {[string length [string trim $existing_string]]} {
@REM On windows, change the value of nextshell to one of the listed 2 digit values if desired, and add code within payload sections for tcl,sh,bash,powershell as appropriate.
@REM This wrapper can be edited manually (carefully!) - or sh,bash,tcl,powershell scripts can be wrapped using the Tcl-based punkshell system
@REM e.g from within a running punkshell: deck scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM On unix-like systems, call with sh, bash or tclsh. (powershell untested on unix - and requires wscript if security elevation is used)
@REM Due to lack of shebang (#! line) Unix-like systems will probably (hopefully) default to sh if the script is called without an interpreter - but it may depend on the shell in use when called.
@REM Change the value of nextshell to one of the supported types, and add code within payload sections for tcl,sh,bash,powershell as appropriate.
@REM This wrapper can be edited manually (carefully!) - or bash,tcl,perl,powershell scripts can be wrapped using the Tcl-based punkshell system
@REM e.g from within a running punkshell: dev scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM Call with sh, bash, perl, or tclsh. (powershell untested on unix)
@REM Due to lack of shebang (#! line) Unix-like systems will hopefully default to a flavour of sh that can divert to bash if the script is called without an interpreter - but it may depend on the shell in use when called.
@REM If you find yourself really wanting/needing to add a shebang line - do so on the basis that the script will exist on unix-like systems only.
@REM in batch scripts - array syntax with square brackets is a simulation of arrays or associative arrays.
@REM note that many shells linked as sh do not support substition syntax and may fail - e.g dash etc - generally bash should be used in this context
@REM for batch - only win32 is relevant - but other scripts on other platforms also parse the nextshell block to determine next shell to launch
@REM nextshellpath and nextshelltype indices (underscore-padded to 16wide) are "other" plus those returned by Tcl platform pkg e.g win32,linux,freebsd,macosx
@REM The horrible underscore-padded fixed-widths are to keep the batch labels aligned whilst allowing values to be set
@REM If more than 32 chars needed for a target, it can still be done but overall script padding may need checking/adjusting
@REM If more than 64 chars needed for a target, it can still be done but overall script padding may need checking/adjusting
@REM Supporting more explicit oses than those listed may also require script padding adjustment
@rem asadmin is for automatic elevation to administrator. Separate window will be created (seems unavoidable with current elevation mechanism) and user will still get security prompt (probably reasonable).
:<asadmin>
:<<asadmin_start>>
@SET"asadmin=0"
:</asadmin>
:<<asadmin_end>>
@REM @ECHO nextshelltype is %nextshelltype[win32___________]%
if (-not([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)){
# If not elevated, relaunch with elevated privileges
# -Wait e.g for starting a service or other operations which remainder of script may depend on
:heredoc1 - hide from powershell using @ and squote above. close sqote for unix shells + ' \
:.bat/.cmd launch section, leading colon hides from cmd, trailing slash hides next line from tcl + \
:"[Hide @GOTO; Hide =begin; Hide @REM] #not necessary but can help avoid errs in testing" +
:<< 'HEREDOC1B_HIDE_FROM_BASH_AND_SH'
:STRONG SUGGESTION: DO NOT MODIFY FIRST LINE OF THIS SCRIPT - except for first double quoted section.
:shebang line is not required on unix or windows and will reduce functionality and/or portability.
:Even comment lines can be part of the functionality of this script (both on unix and windows) - modify with care.
@GOTO:skip_perl_pod_start ^;
=begin excludeperl
:skip_perl_pod_start
:Continuation char at end of this line and rem with curly-braces used to exlude Tcl from the whole cmd block \
:{
:STRONG SUGGESTION: DO NOT MODIFY FIRST LINE OF THIS SCRIPT. shebang #! line is not required on unix or windows and will reduce functionality and/or portability.
:Even comment lines can be part of the functionality of this script (both on unix and windows) - modify with care.
@REM On windows, change the value of nextshell to one of the listed 2 digit values if desired, and add code within payload sections for tcl,sh,bash,powershell as appropriate.
@REM This wrapper can be edited manually (carefully!) - or sh,bash,tcl,powershell scripts can be wrapped using the Tcl-based punkshell system
@REM e.g from within a running punkshell: pmix scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM e.g from within a running punkshell: deck scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM On unix-like systems, call with sh, bash or tclsh. (powershell untested on unix - and requires wscript if security elevation is used)
@REM Due to lack of shebang (#! line) Unix-like systems will probably (hopefully) default to sh if the script is called without an interpreter - but it may depend on the shell in use when called.
@REM If you find yourself really wanting/needing to add a shebang line - do so on the basis that the script will exist on unix-like systems only.
@REM in batch scripts - array syntax with square brackets is a simulation of arrays or associative arrays.
@REM note that many shells linked as sh do not support substition syntax and may fail - e.g dash etc - generally bash should be used in this context
@REM for batch - only win32 is relevant - but other scripts on other platforms also parse the nextshell block to determine next shell to launch
@REM nextshellpath and nextshelltype indices (underscore-padded to 16wide) are "other" plus those returned by Tcl platform pkg e.g win32,linux,freebsd,macosx
@REM The horrible underscore-padded fixed-widths are to keep the batch labels aligned whilst allowing values to be set
@REM If more than 32 chars needed for a target, it can still be done but overall script padding may need checking/adjusting
@REM Supporting more explicit oses than those listed may also require script padding adjustment
@rem asadmin is for automatic elevation to administrator. Separate window will be created (seems unavoidable with current elevation mechanism) and user will still get security prompt (probably reasonable).
:<asadmin>
@SET"asadmin=0"
:</asadmin>
@REM nextshell set to index for validshells .eg 10 for pwsh
@ -49,16 +73,16 @@ set -- "$@" "a=[list shebangless punk MULTISHELL tclsh sh bash cmd pwsh powershe
@REM -- Due to this issue -seemingly trivial edits of the batch file section can break the script! (for Windows anyway)
@REM -- Even something as simple as adding or removing an @REM
@REM -- From within punkshell - use:
@REM -- pmix scriptwrap.checkfile <filepath>
@REM -- deck scriptwrap.checkfile <filepath>
@REM -- to check your templates or final wrapped scripts for byte boundary issues
@REM -- It will report any labels that are on boundaries
@REM -- This is why the nextshell value above is a 2 digit key instead of a string - so that editing the value doesn't change the byte offsets.
@REM -- Editing your sh,bash,tcl,pwsh payloads is much less likely to cause an issue. There is the possibility of the final batch :exit_multishell label spanning a boundary - so testing using pmix scriptwrap.checkfile is still recommended.
@REM -- Editing your sh,bash,tcl,pwsh payloads is much less likely to cause an issue. There is the possibility of the final batch :exit_multishell label spanning a boundary - so testing using deck scriptwrap.checkfile is still recommended.
@REM -- Alternatively, as you should do anyway - test the final script on windows
@REM -- Aside from adding comments/whitespace to tweak the location of labels - you can try duplicating the label (e.g just add the label on a line above) but this is not guaranteed to work in all situations.
@REM -- '@REM' is a safer comment mechanism than a leading colon - which is used sparingly here.
@REM -- A colon anywhere in the script that happens to land on a 512 Byte boundary (from file start or from a callsite) could be misinterpreted as a label
@REM -- It is unknown what versions of cmd interpreters behave this way - and pmix scriptwrap.checkfile doesn't check all such boundaries.
@REM -- It is unknown what versions of cmd interpreters behave this way - and deck scriptwrap.checkfile doesn't check all such boundaries.
@REm -- For this reason, batch labels should be chosen to be relatively unlikely to collide with other strings in the file, and simple names such as :exit or :end should probably be avoided
:heredoc1 - hide from powershell using @ and squote above. close sqote for unix shells + ' \
:.bat/.cmd launch section, leading colon hides from cmd, trailing slash hides next line from tcl + \
:"[Hide @GOTO; Hide =begin; Hide @REM] #not necessary but can help avoid errs in testing" +
:"[rename set s;proc Hide x {proc $x args {}};Hide :]" "\$(function : {<#pwsh#>})" ^
set-- "$@""a=[list shebangless punk MULTISHELL tclsh sh bash cmd pwsh powershell;proc Hide x {proc $x args {}}; Hide <#;Hide set;s 1 list]"; set -- : "$@";$1 = @'
:heredoc1 - hide from powershell using @ and squote above. (close sqote for unix shells) ' \
:.bat/.cmd launch section, leading colon hides from cmd, trailing slash hides next line from tcl \
:"[Hide @ECHO; Hide ); Hide (;Hide echo; Hide @REM]#not necessary but can help avoid errs in testing"
:<< 'HEREDOC1B_HIDE_FROM_BASH_AND_SH'
:STRONG SUGGESTION: DO NOT MODIFY FIRST LINE OF THIS SCRIPT - except for first double quoted section.
:shebang line is not required on unix or windows and will reduce functionality and/or portability.
:Even comment lines can be part of the functionality of this script (both on unix and windows) - modify with care.
@GOTO:skip_perl_pod_start ^;
=begin excludeperl
:skip_perl_pod_start
:Continuation char at end of this line and rem with curly-braces used to exlude Tcl from the whole cmd block \
:{
:STRONG SUGGESTION: DO NOT MODIFY FIRST LINE OF THIS SCRIPT. shebang #! line is not required on unix or windows and will reduce functionality and/or portability.
:Even comment lines can be part of the functionality of this script (both on unix and windows) - modify with care.
@REM On windows, change the value of nextshell to one of the listed 2 digit values if desired, and add code within payload sections for tcl,sh,bash,powershell as appropriate.
@REM This wrapper can be edited manually (carefully!) - or sh,bash,tcl,powershell scripts can be wrapped using the Tcl-based punkshell system
@REM e.g from within a running punkshell: deck scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM e.g from within a running punkshell: pmix scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM On unix-like systems, call with sh, bash or tclsh. (powershell untested on unix - and requires wscript if security elevation is used)
@REM Due to lack of shebang (#! line) Unix-like systems will probably (hopefully) default to sh if the script is called without an interpreter - but it may depend on the shell in use when called.
@REM If you find yourself really wanting/needing to add a shebang line - do so on the basis that the script will exist on unix-like systems only.
@ -54,16 +49,16 @@ set -- "$@" "a=[Hide <#;Hide set;s 1 list]"; set -- : "$@";$1 = @'
@REM -- Due to this issue -seemingly trivial edits of the batch file section can break the script! (for Windows anyway)
@REM -- Even something as simple as adding or removing an @REM
@REM -- From within punkshell - use:
@REM -- deck scriptwrap.checkfile <filepath>
@REM -- pmix scriptwrap.checkfile <filepath>
@REM -- to check your templates or final wrapped scripts for byte boundary issues
@REM -- It will report any labels that are on boundaries
@REM -- This is why the nextshell value above is a 2 digit key instead of a string - so that editing the value doesn't change the byte offsets.
@REM -- Editing your sh,bash,tcl,pwsh payloads is much less likely to cause an issue. There is the possibility of the final batch :exit_multishell label spanning a boundary - so testing using deck scriptwrap.checkfile is still recommended.
@REM -- Editing your sh,bash,tcl,pwsh payloads is much less likely to cause an issue. There is the possibility of the final batch :exit_multishell label spanning a boundary - so testing using pmix scriptwrap.checkfile is still recommended.
@REM -- Alternatively, as you should do anyway - test the final script on windows
@REM -- Aside from adding comments/whitespace to tweak the location of labels - you can try duplicating the label (e.g just add the label on a line above) but this is not guaranteed to work in all situations.
@REM -- '@REM' is a safer comment mechanism than a leading colon - which is used sparingly here.
@REM -- A colon anywhere in the script that happens to land on a 512 Byte boundary (from file start or from a callsite) could be misinterpreted as a label
@REM -- It is unknown what versions of cmd interpreters behave this way - and deck scriptwrap.checkfile doesn't check all such boundaries.
@REM -- It is unknown what versions of cmd interpreters behave this way - and pmix scriptwrap.checkfile doesn't check all such boundaries.
@REm -- For this reason, batch labels should be chosen to be relatively unlikely to collide with other strings in the file, and simple names such as :exit or :end should probably be avoided
@REM On windows, change the value of nextshell to one of the listed 2 digit values if desired, and add code within payload sections for tcl,sh,bash,powershell as appropriate.
@REM This wrapper can be edited manually (carefully!) - or sh,bash,tcl,powershell scripts can be wrapped using the Tcl-based punkshell system
@REM e.g from within a running punkshell: deck scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM On unix-like systems, call with sh, bash or tclsh. (powershell untested on unix - and requires wscript if security elevation is used)
@REM Due to lack of shebang (#! line) Unix-like systems will probably (hopefully) default to sh if the script is called without an interpreter - but it may depend on the shell in use when called.
@REM If you find yourself really wanting/needing to add a shebang line - do so on the basis that the script will exist on unix-like systems only.
@rem asadmin is for automatic elevation to administrator. Separate window will be created (seems unavoidable with current elevation mechanism) and user will still get security prompt (probably reasonable).
:<asadmin>
@SET"asadmin=0"
:</asadmin>
@REM nextshell set to index for validshells .eg 10 for pwsh
@REM -- cmd/batch file section (ignored on unix but should be left in place)
@REM -- This section intended mainly to launch the next shell (and to escalate privileges if necessary)
@REM -- Avoid customising this if you are not familiar with batch scripting. cmd/batch script can be useful, but is probably the least expressive language and most error prone.
@REM -- For example - as this file needs to use unix-style lf line-endings - the label scanner is susceptible to the 512Byte boundary issue: https://www.dostips.com/forum/viewtopic.php?t=8988#p58888
@REM -- This label issue can be triggered/abused in files with crlf line endings too - but it is less likely to happen accidentaly.
@REm -- See also: https://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/4095133#4095133
@REM -- Due to this issue -seemingly trivial edits of the batch file section can break the script! (for Windows anyway)
@REM -- Even something as simple as adding or removing an @REM
@REM -- From within punkshell - use:
@REM -- deck scriptwrap.checkfile <filepath>
@REM -- to check your templates or final wrapped scripts for byte boundary issues
@REM -- It will report any labels that are on boundaries
@REM -- This is why the nextshell value above is a 2 digit key instead of a string - so that editing the value doesn't change the byte offsets.
@REM -- Editing your sh,bash,tcl,pwsh payloads is much less likely to cause an issue. There is the possibility of the final batch :exit_multishell label spanning a boundary - so testing using deck scriptwrap.checkfile is still recommended.
@REM -- Alternatively, as you should do anyway - test the final script on windows
@REM -- Aside from adding comments/whitespace to tweak the location of labels - you can try duplicating the label (e.g just add the label on a line above) but this is not guaranteed to work in all situations.
@REM -- '@REM' is a safer comment mechanism than a leading colon - which is used sparingly here.
@REM -- A colon anywhere in the script that happens to land on a 512 Byte boundary (from file start or from a callsite) could be misinterpreted as a label
@REM -- It is unknown what versions of cmd interpreters behave this way - and deck scriptwrap.checkfile doesn't check all such boundaries.
@REm -- For this reason, batch labels should be chosen to be relatively unlikely to collide with other strings in the file, and simple names such as :exit or :end should probably be avoided
puts stderr "Sorry - only single input file supported. Supply a file extension or use a <scriptset>_wrap.toml config with a single input file for now - implementation incomplete"
return false
}
#todo - split template at each <ext-*-subprocess> etc marker and build a dict of parts
#if {[llength $list_input_files] > 1} {
# #todo
# puts stderr "Sorry - only single input file supported. Supply a file extension or use a <scriptset>_wrap.toml config with a single input file for now - implementation incomplete"
# return false
#}
#hack - process one input
set filepath [lindex $list_input_files 0]
set fdscript [open $filepath r]
fconfigure $fdscript -translation binary
set script_data [read $fdscript]
close $fdscript
puts stdout "Read [string length $script_data] bytes of template data.."
set script_lines [split $script_data \n]
puts stdout "Displaying first 3 lines of your script between dashed lines..."
puts stdout "Target for script data is '$output_file'"
puts stdout "Language of script being wrapped is [a bold yellow]$lang[a]"
if {$opt_askme} {
set answer [util::askuser "Does this look correct? Y|N"]
if {[string tolower $answer] ne "y"} {
puts stderr "mix new aborting due to user response '$answer' (required Y or y to proceed) use -askme 0 to avoid prompts."
return
}
}
}
set start_idx 0
set end_idx 0
set line_idx 0
set existing_payload [list]
set template_ranges [list]
set data_items [list]
set trange [list 0]
set line_idx -1
set opentag ""
foreach ln $template_lines {
if {[string match "#<$lang-pre-launch-subprocess>*" $ln]} {
set start_idx $line_idx
} elseif {[string match "#</$lang-pre-launch-subprocess>*" $ln]} {
set end_idx $line_idx
break
} elseif {$start_idx > 0} {
if {$end_idx > 0} {
lappend existing_payload [string trim $ln]
}
incr line_idx
if {$opentag eq ""} {
if {[string match ": <<asadmin_start>>*" $ln]} {
set opentag asadmin
lset trange 1 $line_idx ;#include tag in template
lappend template_ranges $trange
set trange [list $line_idx]
set asadmin [dict get $configd as_admin]
set scr "@SET \"asadmin=$asadmin\""
lappend data_items $scr
} elseif {[string match ": <<nextshell_start>>*" $ln]} {
set opentag nextshell
lset trange 1 $line_idx
lappend template_ranges $trange
set trange [list $line_idx]
set nextshell_script [_get_nextshell_script $configd]
#puts stderr "-------------------"
#puts stderr "$nextshell_script"
lappend data_items $nextshell_script
} elseif {[string match "#<*-payload>*" $ln]} {
regexp {#<(.*)-payload>.*} $ln _ lang
if {[dict exists $lang_data $lang]} {
set script_lines [dict get $lang_data $lang]
set opentag payload-$lang
lset trange 1 $line_idx
lappend template_ranges $trange
lappend data_items [join $script_lines \n]
}
}
} else {
switch -- [string range $opentag 0 6] {
asadmin {
if {[string match ": <<asadmin_end>>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
nextshe {
if {[string match ": <<nextshell_end>>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
payload {
set lang [string range $opentag 8 end] ;#payload-xxx
if {[string match "#</$lang-payload>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
}
}
incr line_idx
}
if {($start_idx == 0) || ($end_idx == 0)} {
error "wrap_in_multishell was unable to find payload area in template marked with #<$lang-pre-launch-subprocess> and #</$lang-pre-launch-subprocess> on separate lines"
if {$opentag eq ""} {
lset trange 1 end
lappend template_ranges $trange
} else {
error "multishell - unable to find closing tag for '$opentag'"
}
set existing_string [join $existing_payload \n]
if {[string length [string trim $existing_string]]} {
puts stderr "Sorry - only single input file supported. Supply a file extension or use a <scriptset>_wrap.toml config with a single input file for now - implementation incomplete"
return false
}
#todo - split template at each <ext-*-subprocess> etc marker and build a dict of parts
#if {[llength $list_input_files] > 1} {
# #todo
# puts stderr "Sorry - only single input file supported. Supply a file extension or use a <scriptset>_wrap.toml config with a single input file for now - implementation incomplete"
# return false
#}
#hack - process one input
set filepath [lindex $list_input_files 0]
set fdscript [open $filepath r]
fconfigure $fdscript -translation binary
set script_data [read $fdscript]
close $fdscript
puts stdout "Read [string length $script_data] bytes of template data.."
set script_lines [split $script_data \n]
puts stdout "Displaying first 3 lines of your script between dashed lines..."
puts stdout "Target for script data is '$output_file'"
puts stdout "Language of script being wrapped is [a bold yellow]$lang[a]"
if {$opt_askme} {
set answer [util::askuser "Does this look correct? Y|N"]
if {[string tolower $answer] ne "y"} {
puts stderr "mix new aborting due to user response '$answer' (required Y or y to proceed) use -askme 0 to avoid prompts."
return
}
}
}
set start_idx 0
set end_idx 0
set line_idx 0
set existing_payload [list]
set template_ranges [list]
set data_items [list]
set trange [list 0]
set line_idx -1
set opentag ""
foreach ln $template_lines {
if {[string match "#<$lang-pre-launch-subprocess>*" $ln]} {
set start_idx $line_idx
} elseif {[string match "#</$lang-pre-launch-subprocess>*" $ln]} {
set end_idx $line_idx
break
} elseif {$start_idx > 0} {
if {$end_idx > 0} {
lappend existing_payload [string trim $ln]
}
incr line_idx
if {$opentag eq ""} {
if {[string match ": <<asadmin_start>>*" $ln]} {
set opentag asadmin
lset trange 1 $line_idx ;#include tag in template
lappend template_ranges $trange
set trange [list $line_idx]
set asadmin [dict get $configd as_admin]
set scr "@SET \"asadmin=$asadmin\""
lappend data_items $scr
} elseif {[string match ": <<nextshell_start>>*" $ln]} {
set opentag nextshell
lset trange 1 $line_idx
lappend template_ranges $trange
set trange [list $line_idx]
set nextshell_script [_get_nextshell_script $configd]
#puts stderr "-------------------"
#puts stderr "$nextshell_script"
lappend data_items $nextshell_script
} elseif {[string match "#<*-payload>*" $ln]} {
regexp {#<(.*)-payload>.*} $ln _ lang
if {[dict exists $lang_data $lang]} {
set script_lines [dict get $lang_data $lang]
set opentag payload-$lang
lset trange 1 $line_idx
lappend template_ranges $trange
lappend data_items [join $script_lines \n]
}
}
} else {
switch -- [string range $opentag 0 6] {
asadmin {
if {[string match ": <<asadmin_end>>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
nextshe {
if {[string match ": <<nextshell_end>>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
payload {
set lang [string range $opentag 8 end] ;#payload-xxx
if {[string match "#</$lang-payload>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
}
}
incr line_idx
}
if {($start_idx == 0) || ($end_idx == 0)} {
error "wrap_in_multishell was unable to find payload area in template marked with #<$lang-pre-launch-subprocess> and #</$lang-pre-launch-subprocess> on separate lines"
if {$opentag eq ""} {
lset trange 1 end
lappend template_ranges $trange
} else {
error "multishell - unable to find closing tag for '$opentag'"
}
set existing_string [join $existing_payload \n]
if {[string length [string trim $existing_string]]} {
puts stderr "Sorry - only single input file supported. Supply a file extension or use a <scriptset>_wrap.toml config with a single input file for now - implementation incomplete"
return false
}
#todo - split template at each <ext-*-subprocess> etc marker and build a dict of parts
#if {[llength $list_input_files] > 1} {
# #todo
# puts stderr "Sorry - only single input file supported. Supply a file extension or use a <scriptset>_wrap.toml config with a single input file for now - implementation incomplete"
# return false
#}
#hack - process one input
set filepath [lindex $list_input_files 0]
set fdscript [open $filepath r]
fconfigure $fdscript -translation binary
set script_data [read $fdscript]
close $fdscript
puts stdout "Read [string length $script_data] bytes of template data.."
set script_lines [split $script_data \n]
puts stdout "Displaying first 3 lines of your script between dashed lines..."
puts stdout "Target for script data is '$output_file'"
puts stdout "Language of script being wrapped is [a bold yellow]$lang[a]"
if {$opt_askme} {
set answer [util::askuser "Does this look correct? Y|N"]
if {[string tolower $answer] ne "y"} {
puts stderr "mix new aborting due to user response '$answer' (required Y or y to proceed) use -askme 0 to avoid prompts."
return
}
}
}
set start_idx 0
set end_idx 0
set line_idx 0
set existing_payload [list]
set template_ranges [list]
set data_items [list]
set trange [list 0]
set line_idx -1
set opentag ""
foreach ln $template_lines {
if {[string match "#<$lang-pre-launch-subprocess>*" $ln]} {
set start_idx $line_idx
} elseif {[string match "#</$lang-pre-launch-subprocess>*" $ln]} {
set end_idx $line_idx
break
} elseif {$start_idx > 0} {
if {$end_idx > 0} {
lappend existing_payload [string trim $ln]
}
incr line_idx
if {$opentag eq ""} {
if {[string match ": <<asadmin_start>>*" $ln]} {
set opentag asadmin
lset trange 1 $line_idx ;#include tag in template
lappend template_ranges $trange
set trange [list $line_idx]
set asadmin [dict get $configd as_admin]
set scr "@SET \"asadmin=$asadmin\""
lappend data_items $scr
} elseif {[string match ": <<nextshell_start>>*" $ln]} {
set opentag nextshell
lset trange 1 $line_idx
lappend template_ranges $trange
set trange [list $line_idx]
set nextshell_script [_get_nextshell_script $configd]
#puts stderr "-------------------"
#puts stderr "$nextshell_script"
lappend data_items $nextshell_script
} elseif {[string match "#<*-payload>*" $ln]} {
regexp {#<(.*)-payload>.*} $ln _ lang
if {[dict exists $lang_data $lang]} {
set script_lines [dict get $lang_data $lang]
set opentag payload-$lang
lset trange 1 $line_idx
lappend template_ranges $trange
lappend data_items [join $script_lines \n]
}
}
} else {
switch -- [string range $opentag 0 6] {
asadmin {
if {[string match ": <<asadmin_end>>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
nextshe {
if {[string match ": <<nextshell_end>>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
payload {
set lang [string range $opentag 8 end] ;#payload-xxx
if {[string match "#</$lang-payload>*" $ln]} {
set trange [list $line_idx]
set opentag ""
}
}
}
}
incr line_idx
}
if {($start_idx == 0) || ($end_idx == 0)} {
error "wrap_in_multishell was unable to find payload area in template marked with #<$lang-pre-launch-subprocess> and #</$lang-pre-launch-subprocess> on separate lines"
if {$opentag eq ""} {
lset trange 1 end
lappend template_ranges $trange
} else {
error "multishell - unable to find closing tag for '$opentag'"
}
set existing_string [join $existing_payload \n]
if {[string length [string trim $existing_string]]} {
@REM On windows, change the value of nextshell to one of the listed 2 digit values if desired, and add code within payload sections for tcl,sh,bash,powershell as appropriate.
@REM This wrapper can be edited manually (carefully!) - or sh,bash,tcl,powershell scripts can be wrapped using the Tcl-based punkshell system
@REM e.g from within a running punkshell: deck scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM On unix-like systems, call with sh, bash or tclsh. (powershell untested on unix - and requires wscript if security elevation is used)
@REM Due to lack of shebang (#! line) Unix-like systems will probably (hopefully) default to sh if the script is called without an interpreter - but it may depend on the shell in use when called.
@REM Change the value of nextshell to one of the supported types, and add code within payload sections for tcl,sh,bash,powershell as appropriate.
@REM This wrapper can be edited manually (carefully!) - or bash,tcl,perl,powershell scripts can be wrapped using the Tcl-based punkshell system
@REM e.g from within a running punkshell: dev scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM Call with sh, bash, perl, or tclsh. (powershell untested on unix)
@REM Due to lack of shebang (#! line) Unix-like systems will hopefully default to a flavour of sh that can divert to bash if the script is called without an interpreter - but it may depend on the shell in use when called.
@REM If you find yourself really wanting/needing to add a shebang line - do so on the basis that the script will exist on unix-like systems only.
@REM in batch scripts - array syntax with square brackets is a simulation of arrays or associative arrays.
@REM note that many shells linked as sh do not support substition syntax and may fail - e.g dash etc - generally bash should be used in this context
@REM for batch - only win32 is relevant - but other scripts on other platforms also parse the nextshell block to determine next shell to launch
@REM nextshellpath and nextshelltype indices (underscore-padded to 16wide) are "other" plus those returned by Tcl platform pkg e.g win32,linux,freebsd,macosx
@REM The horrible underscore-padded fixed-widths are to keep the batch labels aligned whilst allowing values to be set
@REM If more than 32 chars needed for a target, it can still be done but overall script padding may need checking/adjusting
@REM If more than 64 chars needed for a target, it can still be done but overall script padding may need checking/adjusting
@REM Supporting more explicit oses than those listed may also require script padding adjustment
@rem asadmin is for automatic elevation to administrator. Separate window will be created (seems unavoidable with current elevation mechanism) and user will still get security prompt (probably reasonable).
:<asadmin>
:<<asadmin_start>>
@SET"asadmin=0"
:</asadmin>
:<<asadmin_end>>
@REM @ECHO nextshelltype is %nextshelltype[win32___________]%
if (-not([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)){
# If not elevated, relaunch with elevated privileges
# -Wait e.g for starting a service or other operations which remainder of script may depend on
:heredoc1 - hide from powershell using @ and squote above. close sqote for unix shells + ' \
:.bat/.cmd launch section, leading colon hides from cmd, trailing slash hides next line from tcl + \
:"[Hide @GOTO; Hide =begin; Hide @REM] #not necessary but can help avoid errs in testing" +
:<< 'HEREDOC1B_HIDE_FROM_BASH_AND_SH'
:STRONG SUGGESTION: DO NOT MODIFY FIRST LINE OF THIS SCRIPT - except for first double quoted section.
:shebang line is not required on unix or windows and will reduce functionality and/or portability.
:Even comment lines can be part of the functionality of this script (both on unix and windows) - modify with care.
@GOTO:skip_perl_pod_start ^;
=begin excludeperl
:skip_perl_pod_start
:Continuation char at end of this line and rem with curly-braces used to exlude Tcl from the whole cmd block \
:{
:STRONG SUGGESTION: DO NOT MODIFY FIRST LINE OF THIS SCRIPT. shebang #! line is not required on unix or windows and will reduce functionality and/or portability.
:Even comment lines can be part of the functionality of this script (both on unix and windows) - modify with care.
@REM On windows, change the value of nextshell to one of the listed 2 digit values if desired, and add code within payload sections for tcl,sh,bash,powershell as appropriate.
@REM This wrapper can be edited manually (carefully!) - or sh,bash,tcl,powershell scripts can be wrapped using the Tcl-based punkshell system
@REM e.g from within a running punkshell: pmix scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM e.g from within a running punkshell: deck scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM On unix-like systems, call with sh, bash or tclsh. (powershell untested on unix - and requires wscript if security elevation is used)
@REM Due to lack of shebang (#! line) Unix-like systems will probably (hopefully) default to sh if the script is called without an interpreter - but it may depend on the shell in use when called.
@REM If you find yourself really wanting/needing to add a shebang line - do so on the basis that the script will exist on unix-like systems only.
@REM in batch scripts - array syntax with square brackets is a simulation of arrays or associative arrays.
@REM note that many shells linked as sh do not support substition syntax and may fail - e.g dash etc - generally bash should be used in this context
@REM for batch - only win32 is relevant - but other scripts on other platforms also parse the nextshell block to determine next shell to launch
@REM nextshellpath and nextshelltype indices (underscore-padded to 16wide) are "other" plus those returned by Tcl platform pkg e.g win32,linux,freebsd,macosx
@REM The horrible underscore-padded fixed-widths are to keep the batch labels aligned whilst allowing values to be set
@REM If more than 32 chars needed for a target, it can still be done but overall script padding may need checking/adjusting
@REM Supporting more explicit oses than those listed may also require script padding adjustment
@rem asadmin is for automatic elevation to administrator. Separate window will be created (seems unavoidable with current elevation mechanism) and user will still get security prompt (probably reasonable).
:<asadmin>
@SET"asadmin=0"
:</asadmin>
@REM nextshell set to index for validshells .eg 10 for pwsh
@ -49,16 +73,16 @@ set -- "$@" "a=[list shebangless punk MULTISHELL tclsh sh bash cmd pwsh powershe
@REM -- Due to this issue -seemingly trivial edits of the batch file section can break the script! (for Windows anyway)
@REM -- Even something as simple as adding or removing an @REM
@REM -- From within punkshell - use:
@REM -- pmix scriptwrap.checkfile <filepath>
@REM -- deck scriptwrap.checkfile <filepath>
@REM -- to check your templates or final wrapped scripts for byte boundary issues
@REM -- It will report any labels that are on boundaries
@REM -- This is why the nextshell value above is a 2 digit key instead of a string - so that editing the value doesn't change the byte offsets.
@REM -- Editing your sh,bash,tcl,pwsh payloads is much less likely to cause an issue. There is the possibility of the final batch :exit_multishell label spanning a boundary - so testing using pmix scriptwrap.checkfile is still recommended.
@REM -- Editing your sh,bash,tcl,pwsh payloads is much less likely to cause an issue. There is the possibility of the final batch :exit_multishell label spanning a boundary - so testing using deck scriptwrap.checkfile is still recommended.
@REM -- Alternatively, as you should do anyway - test the final script on windows
@REM -- Aside from adding comments/whitespace to tweak the location of labels - you can try duplicating the label (e.g just add the label on a line above) but this is not guaranteed to work in all situations.
@REM -- '@REM' is a safer comment mechanism than a leading colon - which is used sparingly here.
@REM -- A colon anywhere in the script that happens to land on a 512 Byte boundary (from file start or from a callsite) could be misinterpreted as a label
@REM -- It is unknown what versions of cmd interpreters behave this way - and pmix scriptwrap.checkfile doesn't check all such boundaries.
@REM -- It is unknown what versions of cmd interpreters behave this way - and deck scriptwrap.checkfile doesn't check all such boundaries.
@REm -- For this reason, batch labels should be chosen to be relatively unlikely to collide with other strings in the file, and simple names such as :exit or :end should probably be avoided
:heredoc1 - hide from powershell using @ and squote above. close sqote for unix shells + ' \
:.bat/.cmd launch section, leading colon hides from cmd, trailing slash hides next line from tcl + \
:"[Hide @GOTO; Hide =begin; Hide @REM] #not necessary but can help avoid errs in testing" +
:"[rename set s;proc Hide x {proc $x args {}};Hide :]" "\$(function : {<#pwsh#>})" ^
set-- "$@""a=[list shebangless punk MULTISHELL tclsh sh bash cmd pwsh powershell;proc Hide x {proc $x args {}}; Hide <#;Hide set;s 1 list]"; set -- : "$@";$1 = @'
:heredoc1 - hide from powershell using @ and squote above. (close sqote for unix shells) ' \
:.bat/.cmd launch section, leading colon hides from cmd, trailing slash hides next line from tcl \
:"[Hide @ECHO; Hide ); Hide (;Hide echo; Hide @REM]#not necessary but can help avoid errs in testing"
:<< 'HEREDOC1B_HIDE_FROM_BASH_AND_SH'
:STRONG SUGGESTION: DO NOT MODIFY FIRST LINE OF THIS SCRIPT - except for first double quoted section.
:shebang line is not required on unix or windows and will reduce functionality and/or portability.
:Even comment lines can be part of the functionality of this script (both on unix and windows) - modify with care.
@GOTO:skip_perl_pod_start ^;
=begin excludeperl
:skip_perl_pod_start
:Continuation char at end of this line and rem with curly-braces used to exlude Tcl from the whole cmd block \
:{
:STRONG SUGGESTION: DO NOT MODIFY FIRST LINE OF THIS SCRIPT. shebang #! line is not required on unix or windows and will reduce functionality and/or portability.
:Even comment lines can be part of the functionality of this script (both on unix and windows) - modify with care.
@REM On windows, change the value of nextshell to one of the listed 2 digit values if desired, and add code within payload sections for tcl,sh,bash,powershell as appropriate.
@REM This wrapper can be edited manually (carefully!) - or sh,bash,tcl,powershell scripts can be wrapped using the Tcl-based punkshell system
@REM e.g from within a running punkshell: deck scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM e.g from within a running punkshell: pmix scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM On unix-like systems, call with sh, bash or tclsh. (powershell untested on unix - and requires wscript if security elevation is used)
@REM Due to lack of shebang (#! line) Unix-like systems will probably (hopefully) default to sh if the script is called without an interpreter - but it may depend on the shell in use when called.
@REM If you find yourself really wanting/needing to add a shebang line - do so on the basis that the script will exist on unix-like systems only.
@ -54,16 +49,16 @@ set -- "$@" "a=[Hide <#;Hide set;s 1 list]"; set -- : "$@";$1 = @'
@REM -- Due to this issue -seemingly trivial edits of the batch file section can break the script! (for Windows anyway)
@REM -- Even something as simple as adding or removing an @REM
@REM -- From within punkshell - use:
@REM -- deck scriptwrap.checkfile <filepath>
@REM -- pmix scriptwrap.checkfile <filepath>
@REM -- to check your templates or final wrapped scripts for byte boundary issues
@REM -- It will report any labels that are on boundaries
@REM -- This is why the nextshell value above is a 2 digit key instead of a string - so that editing the value doesn't change the byte offsets.
@REM -- Editing your sh,bash,tcl,pwsh payloads is much less likely to cause an issue. There is the possibility of the final batch :exit_multishell label spanning a boundary - so testing using deck scriptwrap.checkfile is still recommended.
@REM -- Editing your sh,bash,tcl,pwsh payloads is much less likely to cause an issue. There is the possibility of the final batch :exit_multishell label spanning a boundary - so testing using pmix scriptwrap.checkfile is still recommended.
@REM -- Alternatively, as you should do anyway - test the final script on windows
@REM -- Aside from adding comments/whitespace to tweak the location of labels - you can try duplicating the label (e.g just add the label on a line above) but this is not guaranteed to work in all situations.
@REM -- '@REM' is a safer comment mechanism than a leading colon - which is used sparingly here.
@REM -- A colon anywhere in the script that happens to land on a 512 Byte boundary (from file start or from a callsite) could be misinterpreted as a label
@REM -- It is unknown what versions of cmd interpreters behave this way - and deck scriptwrap.checkfile doesn't check all such boundaries.
@REM -- It is unknown what versions of cmd interpreters behave this way - and pmix scriptwrap.checkfile doesn't check all such boundaries.
@REm -- For this reason, batch labels should be chosen to be relatively unlikely to collide with other strings in the file, and simple names such as :exit or :end should probably be avoided
@REM On windows, change the value of nextshell to one of the listed 2 digit values if desired, and add code within payload sections for tcl,sh,bash,powershell as appropriate.
@REM This wrapper can be edited manually (carefully!) - or sh,bash,tcl,powershell scripts can be wrapped using the Tcl-based punkshell system
@REM e.g from within a running punkshell: deck scriptwrap.multishell <inputfilepath> -outputfolder <folderpath>
@REM On unix-like systems, call with sh, bash or tclsh. (powershell untested on unix - and requires wscript if security elevation is used)
@REM Due to lack of shebang (#! line) Unix-like systems will probably (hopefully) default to sh if the script is called without an interpreter - but it may depend on the shell in use when called.
@REM If you find yourself really wanting/needing to add a shebang line - do so on the basis that the script will exist on unix-like systems only.
@rem asadmin is for automatic elevation to administrator. Separate window will be created (seems unavoidable with current elevation mechanism) and user will still get security prompt (probably reasonable).
:<asadmin>
@SET"asadmin=0"
:</asadmin>
@REM nextshell set to index for validshells .eg 10 for pwsh
@REM -- cmd/batch file section (ignored on unix but should be left in place)
@REM -- This section intended mainly to launch the next shell (and to escalate privileges if necessary)
@REM -- Avoid customising this if you are not familiar with batch scripting. cmd/batch script can be useful, but is probably the least expressive language and most error prone.
@REM -- For example - as this file needs to use unix-style lf line-endings - the label scanner is susceptible to the 512Byte boundary issue: https://www.dostips.com/forum/viewtopic.php?t=8988#p58888
@REM -- This label issue can be triggered/abused in files with crlf line endings too - but it is less likely to happen accidentaly.
@REm -- See also: https://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/4095133#4095133
@REM -- Due to this issue -seemingly trivial edits of the batch file section can break the script! (for Windows anyway)
@REM -- Even something as simple as adding or removing an @REM
@REM -- From within punkshell - use:
@REM -- deck scriptwrap.checkfile <filepath>
@REM -- to check your templates or final wrapped scripts for byte boundary issues
@REM -- It will report any labels that are on boundaries
@REM -- This is why the nextshell value above is a 2 digit key instead of a string - so that editing the value doesn't change the byte offsets.
@REM -- Editing your sh,bash,tcl,pwsh payloads is much less likely to cause an issue. There is the possibility of the final batch :exit_multishell label spanning a boundary - so testing using deck scriptwrap.checkfile is still recommended.
@REM -- Alternatively, as you should do anyway - test the final script on windows
@REM -- Aside from adding comments/whitespace to tweak the location of labels - you can try duplicating the label (e.g just add the label on a line above) but this is not guaranteed to work in all situations.
@REM -- '@REM' is a safer comment mechanism than a leading colon - which is used sparingly here.
@REM -- A colon anywhere in the script that happens to land on a 512 Byte boundary (from file start or from a callsite) could be misinterpreted as a label
@REM -- It is unknown what versions of cmd interpreters behave this way - and deck scriptwrap.checkfile doesn't check all such boundaries.
@REm -- For this reason, batch labels should be chosen to be relatively unlikely to collide with other strings in the file, and simple names such as :exit or :end should probably be avoided