/* * TraceCmd.java -- * * This file implements the Tcl "trace" command. * * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and * redistribution of this file, and for a DISCLAIMER OF ALL * WARRANTIES. * * RCS: @(#) $Id: TraceCmd.java,v 1.1.1.1 1998/10/14 21:09:19 cvsadmin Exp $ * */ package tcl.lang; import java.util.*; /* * The TraceCmd class implements the Command interface for specifying * a new Tcl command. The method cmdProc implements the built-in Tcl * command "trace" which is used to manupilate variable traces. See * user documentation for more details. */ class TraceCmd implements Command { /* * Valid sub-commands for the trace command. */ static final private String validCmds[] = { "variable", "vdelete", "vinfo", }; static final private int OPT_VARIABLE = 0; static final private int OPT_VDELETE = 1; static final private int OPT_VINFO = 2; /* * An array for quickly generating the Tcl strings corresponding to * the TCL.TRACE_READS, TCL.TRACE_WRITES and TCL.TRACE_UNSETS flags. */ private static TclObject opStr[] = initOptStr(); /* *---------------------------------------------------------------------- * * initOptStr -- * * This static method is called when the TraceCmd class is loaded * into the VM. It initializes the opStr array. * * Results: * Initial value for opStr. * * Side effects: * The TclObjects stored in opStr are preserve()'ed. * *---------------------------------------------------------------------- */ private static TclObject[] initOptStr() { TclObject strings[] = new TclObject[8]; strings[0] = TclString.newInstance("error"); strings[1] = TclString.newInstance("r"); strings[2] = TclString.newInstance("w"); strings[3] = TclString.newInstance("rw"); strings[4] = TclString.newInstance("u"); strings[5] = TclString.newInstance("ru"); strings[6] = TclString.newInstance("wu"); strings[7] = TclString.newInstance("rwu"); for (int i = 0; i < 8; i++) { strings[i].preserve(); } return strings; } /* *---------------------------------------------------------------------- * * cmdProc -- * * This procedure is invoked as part of the Command interface to * process the "trace" Tcl command. See the user documentation for * details on what it does. * * Results: * None. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ public void cmdProc( Interp interp, /* Current interpreter. */ TclObject argv[]) /* Argument list. */ throws TclException /* A standard Tcl exception. */ { int len; if (argv.length < 2) { throw new TclNumArgsException(interp, 1, argv, "option arg ?arg ...?"); } int opt = TclIndex.get(interp, argv[1], validCmds, "option", 0); switch (opt) { case OPT_VARIABLE: case OPT_VDELETE: if (argv.length != 5) { if (opt == OPT_VARIABLE) { throw new TclNumArgsException(interp, 1, argv, "variable name ops command"); } else { throw new TclNumArgsException(interp, 1, argv, "vdelete name ops command"); } } int flags = 0; String ops = argv[3].toString(); len = ops.length(); check_ops: { for (int i = 0; i < len; i++) { switch (ops.charAt(i)) { case 'r': flags |= TCL.TRACE_READS; break; case 'w': flags |= TCL.TRACE_WRITES; break; case 'u': flags |= TCL.TRACE_UNSETS; break; default: flags = 0; break check_ops; } } } if (flags == 0) { throw new TclException(interp, "bad operations \"" + argv[3] + "\": should be one or more of rwu"); } if (opt == OPT_VARIABLE) { CmdTraceProc trace = new CmdTraceProc(argv[4].toString(), flags); interp.varFrame.traceVar(argv[2], trace, flags); } else { /* * Search through all of our traces on this variable to * see if there's one with the given command. If so, then * delete the first one that matches. */ Vector traces = interp.varFrame.getTraces(argv[2], 0); if (traces != null) { len = traces.size(); for (int i = 0; i < len; i++) { TraceRecord rec = (TraceRecord)traces.elementAt(i); if (rec.trace instanceof CmdTraceProc) { CmdTraceProc proc = (CmdTraceProc)(rec.trace); if (proc.flags == flags && proc.command.toString(). equals(argv[4].toString())) { interp.varFrame.untraceVar(argv[2], proc, flags); break; } } } } } break; case OPT_VINFO: if (argv.length != 3) { throw new TclNumArgsException(interp, 2, argv, "name"); } Vector traces = interp.varFrame.getTraces(argv[2], 0); if (traces != null) { len = traces.size(); TclObject list = TclList.newInstance(); TclObject cmd = null; list.preserve(); try { for (int i = 0; i < len; i++) { TraceRecord rec = (TraceRecord)traces.elementAt(i); if (rec.trace instanceof CmdTraceProc) { CmdTraceProc proc = (CmdTraceProc)(rec.trace); int mode = proc.flags; mode &= (TCL.TRACE_READS|TCL.TRACE_WRITES |TCL.TRACE_UNSETS); mode /= TCL.TRACE_READS; cmd = TclList.newInstance(); TclList.append(interp, cmd, opStr[mode]); TclList.append(interp, cmd, TclString.newInstance( proc.command)); TclList.append(interp, list, cmd); } } interp.setResult(list); } finally { list.release(); } } break; } } } // TraceCmd /* * The CmdTraceProc object holds the information for a specific * trace. */ class CmdTraceProc implements VarTrace { /* * The command holds the Tcl script that will execute. The flags * hold the mode flags that define what conditions to fire under. */ String command; int flags; /* *---------------------------------------------------------------------- * * CmdTraceProc -- * * This function is a constructor for a CmdTraceProc. It simply * stores the flags and command used for this trace proc. * details on what it does. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ CmdTraceProc(String cmd, int newFlags) { flags = newFlags; command = cmd; } /* *---------------------------------------------------------------------- * * traceProc -- * * This function gets called when a variable is used in a way that * would cause this particular trace to fire. It will evaluate * the script associated with this trace. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ public void traceProc( Interp interp, // The current interpreter. String part1, // A Tcl variable or array name. String part2, // Array element name or NULL. int flags) // Mode flags: TCL.TRACE_READS, TCL.TRACE_WRITES or // TCL.TRACE_UNSETS. throws TclException // A standard Tcl exception. { if (((this.flags & flags) != 0) && ((flags & TCL.INTERP_DESTROYED) == 0)) { StringBuffer sbuf = new StringBuffer(command); try { Util.appendElement(interp, sbuf, part1); if (part2 != null) { Util.appendElement(interp, sbuf, part2); } else { Util.appendElement(interp, sbuf, ""); } if ((flags & TCL.TRACE_READS) != 0) { Util.appendElement(interp, sbuf, "r"); } else if ((flags & TCL.TRACE_WRITES) != 0) { Util.appendElement(interp, sbuf, "w"); } else if ((flags & TCL.TRACE_UNSETS) != 0) { Util.appendElement(interp, sbuf, "u"); } } catch (TclException e) { throw new TclRuntimeError("unexpected TclException: " + e); } /* * Execute the command. */ interp.eval(sbuf.toString(), 0); } } } //CmdTraceProc