TCL Unload a TCL script

Unload a TCL script

# Script: unloadtcl.tcl
# Version: 1.1
# Author: Wingman <Wingman@WINGDesign.de>

# Description: This scripts allows you to load/unload tcl scripts via
# partyline.

# DCC Commands:
# .loadtcl <scriptname>
# .unloadtcl <scriptname>
# .viewtcls <loaded/all>

# Updates:
# 1.1 (16. Nov 99) added .viewtcls all, settings for dir, pattern, automaticlly
#     rehash/restart, now .loadtcl notifies loaded tcls and don't let you load 
#     the same tcl twice. Also fixed some unbind bugs.

# Known bugs:
# it can't unbind bindings, which are set via foreach e.g. userinfo.tcl

# Settings:

# 0 = no rehash/restart, 1 = rehash, 2 = restart
set ul(refresh) 1
set ul(dir) "scripts"
set ul(pattern) "*.tcl"

# Bindings:
bind dcc n unloadtcl dcc:unloadtcl
bind dcc n loadtcl dcc:loadtcl
bind dcc n viewtcls dcc:viewtcls 

# Procedures - You don't have to edit anything below.

proc ul:get_scripts {} {
  global config
  set loaded_scripts ""
  set file [open $config r]
  while {![eof $file]} {
    set line [gets $file]
    if {[string match "source*" $line]} {
      set script "[string range $line 15 end]"
      if {[string match "/" $script]} {
        set script [lindex [split $script /] [incr [llength [split $script /]] -1]]
        set path [string range $line 0 [string length $script]]
      }
      append loaded_scripts "$script "
    }
  }
  close $file
  return $loaded_scripts
}

proc dcc:loadtcl { hand idx arg } {
  global config ul
  if {[llength $arg] < 1} {
    putdcc $idx "Usage: .loadtcl <scriptname>"
    return
  } 
  if {![file exists scripts/$arg]} {
    putdcc $idx "Can't find tcl $arg."
    return
  }
  if {[lsearch "[ul:get_scripts]" $arg] != -1} {
    putdcc $idx "Tcl script already loaded: $arg"
    return
  }
  set file [open $config a+]
  puts $file "source scripts/$arg"
  close $file
  putdcc $idx "Done. $arg successfully loaded."
  if {$ul(refresh) == 1} { 
    rehash
  } elseif {$ul(refresh) == 2} {
    restart
  } {
    putdcc $idx "Now do a .rehash or .restart."
  }
  return 1
}

proc dcc:unloadtcl { hand idx arg } {
  global config ul 
  if {[llength $arg] < 1} {
    putdcc $idx "Usage: .unloadtcl <scriptname>"
    putdcc $idx "       try '.viewtcls loaded' for a list of loaded scripts"
    return 
  }
  if {![file exists scripts/$arg]} {
    putdcc $idx "Can't find tcl: $arg."
    return
  }
  set file [open $config r]
  while {![eof $file]} {
    set line [gets $file]
    if {![string match "source scripts/$arg *" $line] && ![string match "source scripts/$arg" $line]} {
      lappend content $line
    } {
      set foo 1
    }
  }
  close $file
  if {![info exists foo]} {
    putdcc $idx "Can't find loaded tcl: $arg."
    return
  }
  set file [open $config w]
  foreach line $content { puts $file $line }
  close $file
  set ubc_success 0
  set ubc_failed 0
  set proc_success 0
  set proc_failed 0
  set file [open scripts/$arg r]
  while {![eof $file]} {
    set line [gets $file]
    if {([string match "* bind *" $line] || [string match "bind *" $line]) && ![string match "*#*" $line]} {
      set foo1  [lindex $line 1]
      if {[string match "*\$*" $foo1]} {
        set varname [lindex [split $foo1 \$] 1]
	if {[string match "*(*" $varname]} {
	  global [lindex [split $varname (] 0]
	} {
	  global $varname
	}
	set foo1 [set $varname]
      }
      set foo2 [lindex $line 2]
      if {[string match "*\$*" $foo2]} {
	if {[llength [split $foo2 |]] == 2} {
	  set gflag [lindex [split $foo2 |] 0]
	  set cflag [lindex [split $foo2 |] 1]
	  if {[string index $gflag 0] == "\$"} {
 	    global [string trimleft $gflag $]
	    set foo2 "[set [string trimleft $gflag $]]"
	  } {
	    set foo2 "$gflag"
	  }
	  if {[string index $cflag 1] == "\$"} {
	    global [string trimleft $cflag $]
	    append foo2 "|[set [string trimleft $cflag $]]"
	  } {
	    append foo2 "|$cflag"
	  }
	} elseif {[llength [split $foo2 &]] == 2} {
          set gflag [lindex [split $foo2 &] 0]
          set cflag [lindex [split $foo2 &] 1]
          if {[string index $gflag 0] == "\$"} {
            global [string trimleft $gflag $]
            set foo2 "[set [string trimleft $gflag $]]"
          } {
            set foo2 "$gflag"
          }
          if {[string index $cflag 1] == "\$"} {
            global [string trimleft $cflag $]
            append foo2 "&[set [string trimleft $cflag $]]"
          } {
            append foo2 "&$cflag"
          }
	} else {
          set varname [lindex [split $foo2 "\$"] 1]
          if {[string match "*(*" $varname]} {
            global [lindex [split $varname (] 0]
          } {
            global $varname
	  }
	  set foo2 [set $varname]
	}
      }
      set foo3 [lindex $line 3]
      if {[string match "*\$*" $foo3]} {
        set varname [lindex [split $foo3 \$] 1]
        if {[string match "*(*" $varname]} {
	  global [lindex [split $varname (] 0]
	} {
          global $varname
	}
	set foo3 [set $varname]
      }
      set foo4 [lindex $line 4]
      catch { unbind $foo1 $foo2 $foo3 $foo4 } error
      if {[string match "TCL error:*" $error]} {
        putdcc $idx " *** error, while executing: unbind $foo1 $foo2 $foo3 $foo4"
	putdcc $idx "     msg: $error"
	incr ubc_failed
      } {
        incr ubc_success
      }
    }
    if {[string match "*proc *\{*\}*\{*" $line]} {
      set procname [lindex [lindex [split $line \{] 0] 1]
      catch { rename $procname "" } error
      if {[string match "TCL error:*" $error]} {
        putdcc $idx " *** error while executing: rename $procname \"\""
	putdcc $idx "     msg: $error"
	incr proc_failed
      } {
        incr proc_success
      }
    }
  }
  close $file
  putdcc $idx "All Done. Showing report:"
  putdcc $idx "  Unbinded $ubc_success commands."
  if {$ubc_failed > 0} {
    putdcc $idx "   * failed: $ubc_failed commands."
  }
  putdcc $idx "  Deleted $proc_success procedures."
  if {$proc_failed > 0} {
    putdcc $idx "   * failed: $proc_failed procedures."
  }
  if {$ul(refresh) == 1} {
    rehash
  } elseif {$ul(refresh) == 2} {
    restart
  } {
    putdcc $idx "I recommend to do an rehash or better a .restart!"
  }
  return 1
}

proc dcc:viewtcls { hand idx arg } {
  global ul
  set loaded_scripts [ul:get_scripts]
  if {[string tolower $arg] == "loaded"} {  
    putlog "#$hand# viewtcls $arg"
    if {![info exists loaded_scripts]} {
      putdcc $idx "No tcls loaded."
    } {
      putdcc $idx "List of loaded tcls:"
      foreach script $loaded_scripts {
        putdcc $idx " $script"
      }
    }
    return
  } elseif {[string tolower $arg] == "all"} {
    catch { glob $ul(dir)/$ul(pattern) } tclfiles
    if {[lrange "$tclfiles" 0 4] == "no files matched glob pattern"} {
      putdcc $idx "Can't find any tcl ($ul(pattern)) script in $ul(dir)."
      return 1
    }
    foreach script $tclfiles {
      if {[lsearch -exact "$loaded_scripts" [string range $script [expr [string length $ul(dir)]+1] end]] == -1} {
        putdcc $idx "  [string range $script [expr [string length $ul(dir)]+1] end]"
      } {
        putdcc $idx "  [string range $script [expr [string length $ul(dir)]+1] end] (loaded)"
      }
    }
    return 1
  }
putdcc $idx "Usage: .viewtcls <loaded/all>"
return
}

#putlog "UnloadTCL v1.1 by Wingman loaded."