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.

357 lines
14 KiB

1 year ago
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
}
}