82 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			Tcl
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			Tcl
		
	
	
	
	
	
| # advice.tcl - Generic advice package.
 | |
| # Copyright (C) 1998 Cygnus Solutions.
 | |
| # Written by Tom Tromey <tromey@cygnus.com>.
 | |
| 
 | |
| # Please note that I adapted this from some code I wrote elsewhere,
 | |
| # for non-Cygnus reasons.  Don't complain to me if you see something
 | |
| # like it somewhere else.
 | |
| 
 | |
| 
 | |
| # Internal state.
 | |
| defarray ADVICE_state
 | |
| 
 | |
| # This is a helper proc that does all the actual work.
 | |
| proc ADVICE_do {command argList} {
 | |
|   global ADVICE_state
 | |
| 
 | |
|   # Run before advice.
 | |
|   if {[info exists ADVICE_state(before,$command)]} {
 | |
|     foreach item $ADVICE_state(before,$command) {
 | |
|       # We purposely let errors in advice go uncaught.
 | |
|       uplevel $item $argList
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   # Run the command itself.
 | |
|   set code [catch \
 | |
| 	      [list uplevel \#0 $ADVICE_state(original,$command) $argList] \
 | |
| 	      result]
 | |
| 
 | |
|   # Run the after advice.
 | |
|   if {[info exists ADVICE_state(after,$command)]} {
 | |
|     foreach item $ADVICE_state(after,$command) {
 | |
|       # We purposely let errors in advice go uncaught.
 | |
|       uplevel $item [list $code $result] $argList
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   # Return just as the original command would.
 | |
|   return -code $code $result
 | |
| }
 | |
| 
 | |
| # Put some advice on a proc or command.
 | |
| #  WHEN says when to run the advice - `before' or `after' the
 | |
| #     advisee is run.
 | |
| #  WHAT is the name of the proc or command to advise.
 | |
| #  ADVISOR is the advice.  It is passed the arguments to the advisee
 | |
| #     call as its arguments.  In addition, `after' advisors are
 | |
| #     passed the return code and return value of the proc as their
 | |
| #     first and second arguments.
 | |
| proc advise {when what advisor} {
 | |
|   global ADVICE_state
 | |
| 
 | |
|   if {! [info exists ADVICE_state(original,$what)]} {
 | |
|     set newName [gensym]
 | |
|     rename $what $newName
 | |
|     set ADVICE_state(original,$what) $newName
 | |
| 
 | |
|     # Create a new proc which just runs our internal command with the
 | |
|     # correct arguments.
 | |
|     uplevel \#0 [list proc $what args \
 | |
| 		   [format {ADVICE_do %s $args} $what]]
 | |
|   }
 | |
| 
 | |
|   lappend ADVICE_state($when,$what) $advisor
 | |
| }
 | |
| 
 | |
| # Remove some previously-set advice.  Note that we could undo the
 | |
| # `rename' when the last advisor is removed.  This adds complexity,
 | |
| # though, and there isn't much reason to.
 | |
| proc unadvise {when what advisor} {
 | |
|   global ADVICE_state
 | |
| 
 | |
|   if {[info exists ADVICE_state($when,$what)]} {
 | |
|     set newList {}
 | |
|     foreach item $ADVICE_state($when,$what) {
 | |
|       if {[string compare $advisor $item]} {
 | |
| 	lappend newList $item
 | |
|       }
 | |
|     }
 | |
|     set ADVICE_state($when,$what) $newList
 | |
|   }
 | |
| }
 |