You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
14 KiB
356 lines
14 KiB
namespace eval shellspy::callbacks { |
|
package require shellfilter |
|
|
|
|
|
#each member of args - ist not itself a list - and cannot be treated as one. |
|
#things like [concat {*}args] will generall break things further down the line |
|
proc cmdshellb {args} { |
|
shellfilter::log::open callback_cmdb {-syslog 127.0.0.1:514} |
|
shellfilter::log::write callback_cmdb "cmdshellb got [llength $args] arguments" |
|
shellfilter::log::write callback_cmdb "cmdshellb got '$args'" |
|
|
|
if {[lindex $args 0] eq "cmdb"} { |
|
set curlyparts [lrange $args 1 end] |
|
shellfilter::log::write callback_cmdb "cmdshellb curlyparts '$curlyparts'" |
|
#we lose grouping info by joining like this.. |
|
#set tail [string trim [join $curlyparts " "]] |
|
set tailinfo [shellfilter::list_element_info $curlyparts] |
|
|
|
shellfilter::log::write callback_cmdb "cmdshellb tailinfo '$tailinfo'" |
|
#e.g |
|
#% set y {{"c:/test/etc"} true {'blah1'} {'blah 2'}} |
|
#% lappend y \\\\\\ |
|
#{"c:/test/etc"} true {'blah1'} {'blah 2'} \\\\\\ |
|
#% foreach i [shellfilter::list_element_info $y] {puts $i} |
|
# 0 |
|
# wouldbrace 1 wouldescape 0 has_braces 0 has_inner_braces 0 apparentwrap doublequotes head_tail_chars {{"} {"}} head_tail_names {dq dq} len 13 difflen 2 |
|
# 1 |
|
# wouldbrace 0 wouldescape 0 has_braces 0 has_inner_braces 0 apparentwrap not-determined head_tail_chars {t e} head_tail_names {t e} len 4 difflen 0 |
|
# 2 |
|
# wouldbrace 0 wouldescape 0 has_braces 0 has_inner_braces 0 apparentwrap singlequotes head_tail_chars {' '} head_tail_names {sqote sqote} len 7 difflen 0 |
|
# 3 |
|
# wouldbrace 1 wouldescape 0 has_braces 0 has_inner_braces 0 apparentwrap singlequotes head_tail_chars {' '} head_tail_names {sqote sqote} len 8 difflen 2 |
|
# 4 |
|
# wouldbrace 0 wouldescape 1 has_braces 0 has_inner_braces 0 apparentwrap not-determined head_tail_chars {\\ \\} head_tail_names {\\ \\} len 3 difflen 3 |
|
|
|
|
|
#sample arglist - 7 items |
|
#((c:\lua\luajit.exe |
|
#C:\Users\sleek\vimfiles\plugged\vim-flog/lua/flog/graph_bin.lua |
|
#__START |
|
#true |
|
#git -C C:/repo/3p/ansi-to-html --literal-pathspecs log --parents --topo-order --no-color --pretty=format:__START\%n\%h\%n\%p\%n\%D\%n\%ad\ \[\%h\]\ \{\%an\}\%d\ \%s --date=iso --no-merges --max-count=2000 -- ) |
|
#> |
|
#C:\Users\sleek\AppData\Local\Temp\VRR6A67.tmp) |
|
|
|
|
|
#complex method.. lists at levels.. |
|
set taillist [list] |
|
set level 0 ;#bracket depth.. incr each opening bracket "(" |
|
set leveldict [dict create] |
|
dict set leveldict 0 [list] |
|
|
|
#simpler method.. string |
|
set output "" |
|
dict for {idx info} $tailinfo { |
|
set item [lindex $curlyparts $idx] |
|
set itemlen [string length $item] |
|
if {[dict get $info apparentwrap] eq "brackets"} { |
|
set chars [split $item ""] |
|
set opening [lsearch -all $chars "("] |
|
set closing [lsearch -all $chars ")"] |
|
if {[llength $opening] == [llength $closing]} { |
|
#dict lappend leveldict 0 $item ;#element individually wrapped in brackets and balanced, pass through |
|
append output "$item " |
|
} else { |
|
#robustness warning: we examine outer brackets only, and are ignoring that things like {((a)(b)} {((a)(b} |
|
# are composed of multiple elements for now .. as there should have been a space between the (a) & (b) elements anyway, |
|
# in which case we would only see things like {((a)} or {(a} |
|
set ltrimmed [string trimleft $item "("] |
|
set countleft [expr {$itemlen - [string length $ltrimmed]}] |
|
|
|
set rtrimmed [string trimright $item ")"] |
|
set countright [expr {$itemlen - [string length $rtrimmed]}] |
|
|
|
#simpler method.. |
|
append output "$item " |
|
|
|
} |
|
} else { |
|
set lcharname [lindex [dict get $info head_tail_names] 0] |
|
set rcharname [lindex [dict get $info head_tail_names] 1] |
|
|
|
if {$lcharname eq "lbracket"} { |
|
set ltrimmed [string trimleft $item "("] |
|
set countleft [expr {$itemlen - [string length $ltrimmed]}] |
|
set braces [string repeat "(" $countleft] |
|
|
|
set testlist [list] |
|
lappend testlist $ltrimmed |
|
set testinfo [shellfilter::list_element_info $testlist] |
|
set testelement [dict get $testinfo 0] |
|
if {[dict get $testelement wouldbrace]} { |
|
#append output "${braces}\"$ltrimmed\" " |
|
append output "${braces} $ltrimmed " |
|
} else { |
|
append output "${braces} $ltrimmed " |
|
} |
|
|
|
} elseif {$rcharname eq "rbracket"} { |
|
set rtrimmed [string trimright $item ")" ] |
|
set countright [expr {$itemlen - [string length $rtrimmed]}] |
|
set braces [string repeat ")" $countright] |
|
set testlist [list] |
|
lappend testlist $rtrimmed |
|
set testinfo [shellfilter::list_element_info $testlist] |
|
set testelement [dict get $testinfo 0] |
|
if {[dict get $testelement wouldbrace]} { |
|
#append output "\"$rtrimmed\"${braces} " |
|
if {[string first " " $rtrimmed] > 0} { |
|
append output "\"$rtrimmed\" ${braces} " |
|
} else { |
|
append output "$rtrimmed ${braces} " |
|
} |
|
} else { |
|
append output "${rtrimmed} ${braces} " |
|
} |
|
|
|
|
|
} else { |
|
set testlist [list] |
|
lappend testlist $item |
|
set testinfo [shellfilter::list_element_info $testlist] |
|
set testelement [dict get $testinfo 0] |
|
if {[dict get $testelement wouldbrace]} { |
|
#append output "\"$item\" " |
|
if {[string first " " $item] > 0} { |
|
append output "\"$item\" " |
|
} else { |
|
append output "$item " |
|
} |
|
} else { |
|
append output "$item " |
|
} |
|
} |
|
|
|
} |
|
|
|
} |
|
shellfilter::log::write callback_cmdb "cmdshellb about to parse_cmd_brackets '$output'" |
|
#$output now has quoted all items that 'wouldbrace' |
|
set curly_list [shellfilter::parse_cmd_brackets $output] |
|
if {[llength $curly_list] == 1} { |
|
#we expect the whole set of arguments was wrapped in a set of brackets |
|
set curly_items [lindex $curly_list 0] |
|
} else { |
|
#unexpected.. root level of string had multiple bracketed sections |
|
#try using the curly_list directly warn? |
|
set curly_items $curly_list |
|
} |
|
#e.g |
|
# ((c:\lua\luajit.exe -v) > C:\Users\sleek\AppData\Local\Temp\V7NCBF.tmp) |
|
#=> |
|
# {{{c:\lua\luajit.exe} -v} > {C:\Users\sleek\AppData\Local\Temp\V7NCBF.tmp}} |
|
|
|
#what is the proper way to flatten? |
|
|
|
set comspec [lindex $curly_items 0] |
|
if {[llength $comspec] >1} { |
|
set commandlist [concat $comspec [lrange $curly_items 1 end]] |
|
} else { |
|
set commandlist $curly_items |
|
} |
|
|
|
set commandlist [floghack_singlearg callback_cmdb {*}$commandlist] |
|
return $commandlist |
|
} else { |
|
shellfilter::log::write callback_cmdb "first arg: [lindex $args 0] vs 'cmdb'" |
|
error "first arg: [lindex $args 0] vs 'cmdb'" |
|
#return $args |
|
} |
|
} |
|
proc cmdshell {args} { |
|
if {[catch { |
|
set args [floghack_singlearg callback_cmdshell {*}$args] |
|
} errMsg]} { |
|
error "FLOGHACK callback_cmdshell error $errMsg" |
|
} |
|
|
|
|
|
#set args [concat [lindex $args 0] [lrange $args 1 end]] |
|
return $args |
|
} |
|
proc cmdshelluc {args} { |
|
if {[catch { |
|
set args [floghack_singlearg callback_cmdshelluc {*}$args] |
|
} errMsg]} { |
|
error "FLOGHACK callback_cmdshelluc error $errMsg" |
|
} |
|
|
|
#set args [concat [lindex $args 0] [lrange $args 1 end]] |
|
return $args |
|
} |
|
|
|
proc powershell {args} { |
|
if {[catch { |
|
set args [floghack "callback_powershell" {*}$args] |
|
} errMsg]} { |
|
error "FLOGHACK callback_powershell error $errMsg" |
|
} |
|
return $args |
|
|
|
} |
|
proc raw {args} { |
|
if {[catch { |
|
set args [floghack_singlearg "callback_raw" {*}$args] |
|
} errMsg]} { |
|
error "FLOGHACK callback_raw error $errMsg" |
|
} |
|
#set args [concat [split [lindex $args 0]] [lrange $args 1 end]] ;#definitely bad! |
|
|
|
|
|
return $args |
|
} |
|
|
|
#hack for c: drive - extend as necessary |
|
#todo - customize! |
|
# various hacks may be necessary for home dirs temp files etc! |
|
proc sh {args} { |
|
if {[catch { |
|
set args [floghack callback_sh {*}$args] |
|
} errMsg]} { |
|
error "FLOGHACK callback_sh error $errMsg" |
|
} |
|
|
|
|
|
|
|
set final [list] |
|
foreach a $args { |
|
if {[string match -nocase {*c:/*} $a]} { |
|
set a [string map [list {c:/} {/c/}] $a] |
|
lappend final $a |
|
} elseif {[string match -nocase {*c:\\*} $a]} { |
|
set a [string map [list \\ / ] $a] |
|
set a [string map [list {c:/} {/c/} {C:/} {/C/}] $a] |
|
lappend final $a |
|
} else { |
|
lappend final $a |
|
} |
|
} |
|
return $final |
|
} |
|
proc wsl {args} { |
|
set args [floghack_singlearg callback_wsl {*}$args] |
|
#wsl bash-style /mnt/c paths to be convertd |
|
set args [convert_mnt_win {*}$args] |
|
|
|
#review - seems bad |
|
#flatten first element which arrives wrapped |
|
#set args [concat [lindex $args 0] [lrange $args 1 end]] |
|
|
|
|
|
return $args |
|
} |
|
proc bash {args} { |
|
set args [floghack callback_bash {*}$args] |
|
return [convert_mnt_win {*}$args] |
|
} |
|
|
|
|
|
|
|
#helper functions |
|
proc convert_mnt_win {args} { |
|
set final [list] |
|
foreach a $args { |
|
if {[string match -nocase {*c:\\*} $a]} { |
|
set a [string map [list \\ / ] $a] |
|
} |
|
#bash seems to be strict about lowercase /mnt/c |
|
if {[string match -nocase {*c:/*} $a]} { |
|
set a [string map [list {c:/} {/mnt/c/} {C:/} {/mnt/c/}] $a] |
|
} |
|
lappend final $a |
|
} |
|
shellfilter::log::write callback_convert_mnt_win "convert_mnt_win commandlist '$final'" |
|
return $final |
|
} |
|
|
|
#when we get the git command and args together as one element in the commandlist |
|
proc floghack_singlearg {logtag args} { |
|
#return $args |
|
shellfilter::log::write $logtag "floghack_singlearg got $logtag '$args'" |
|
set newargs [list] |
|
foreach a $args { |
|
if {[string match "*pretty=format:__START*" $a]} { |
|
set a [string map [list "pretty=format:__" "pretty=format:\"__"] $a] |
|
set a [string map [list " --date=" "\" --date="] $a] |
|
set a [string map [list \\ ""] $a] ;# a bad idea? |
|
lappend newargs $a |
|
} else { |
|
lappend newargs $a |
|
} |
|
} |
|
shellfilter::log::write $logtag "floghack_singlearg hacked commandlist '$newargs'" |
|
return $newargs |
|
} |
|
|
|
|
|
proc floghack {logtag args} { |
|
|
|
#return $args |
|
shellfilter::log::write $logtag "floghack got [llength $args] args: '$args'" |
|
set indent " " |
|
set i 0 |
|
foreach a $args { |
|
shellfilter::log::write $logtag "floghack ${indent}$i $a" |
|
incr i |
|
} |
|
|
|
#Flog/luajit hack |
|
#wrong way |
|
#if {[string first "pretty=format:__START" $args] > 0} { |
|
# set args [string map [list "pretty=format:" "pretty=format:'" " --date=" "' --date=" ] $args] |
|
#} |
|
set newargs [list] |
|
|
|
set pretty "" |
|
set pstart [lsearch $args "--pretty=format:__START*"] |
|
set pafter [lsearch $args "--date=*"] |
|
if {$pstart > 0} { |
|
set newargs [lrange $args 0 $pstart-1] |
|
set parts [lrange $args $pstart $pafter-1] |
|
set i 1 |
|
foreach p $parts { |
|
if {$i == 1} { |
|
set pretty [string map [list "format:__" "format:\"__"] $p] |
|
#set pretty $p |
|
} else { |
|
append pretty " $p" |
|
} |
|
if {$i == [llength $parts]} { |
|
append pretty "\"" |
|
} |
|
incr i |
|
} |
|
set pretty [string map [list \\ ""] $pretty] |
|
lappend newargs $pretty |
|
#lappend newargs "--pretty=format:%h" |
|
set newargs [concat $newargs [lrange $args $pafter end]] ;#concat of 2 lists.. should be ok |
|
} else { |
|
set newargs $args |
|
} |
|
|
|
|
|
shellfilter::log::write $logtag "floghack hacked commandlist '$newargs'" |
|
|
|
|
|
return $newargs |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|