/// <summary> TCL.Tcl_TraceVar2 -> traceVar /// /// Trace a variable, given a two-part name consisting of array /// name and element within array. /// /// </summary> /// <param name="part1">1st part of the variable name. /// </param> /// <param name="part2">2nd part of the variable name. /// </param> /// <param name="flags">misc flags that control the actions of this method. /// </param> /// <param name="trace">the trace to comand to add. /// </param> internal static void traceVar( Interp interp, string part1, string part2, TCL.VarFlag flags, VarTrace proc ) { Var[] result; Var var, array; // FIXME: what about the exception problem here? result = lookupVar( interp, part1, part2, ( flags | TCL.VarFlag.LEAVE_ERR_MSG ), "trace", true, true ); if ( result == null ) { throw new TclException( interp, "" ); } var = result[0]; array = result[1]; // Set up trace information. if ( var.traces == null ) { var.traces = new ArrayList( 10 ); } var rec = new TraceRecord(); rec.trace = proc; rec.flags = flags & ( TCL.VarFlag.TRACE_READS | TCL.VarFlag.TRACE_WRITES | TCL.VarFlag.TRACE_UNSETS | TCL.VarFlag.TRACE_ARRAY ); var.traces.Insert( 0, rec ); // FIXME: is this needed ?? It was in Jacl but not 8.1 /* // When inserting a trace for an array on an UNDEFINED variable, // the search IDs for that array are reset. if (array != null && var.isVarUndefined()) { array.sidVec = null; } */ }
public TCL.CompletionCode cmdProc(Interp interp, TclObject[] objv) { int len; if (objv.Length < 2) { throw new TclNumArgsException(interp, 1, objv, "option [arg arg ...]"); } int opt = TclIndex.get(interp, objv[1], validCmds, "option", 0); switch (opt) { case OPT_VARIABLE: case OPT_VDELETE: if (objv.Length != 5) { if (opt == OPT_VARIABLE) { throw new TclNumArgsException(interp, 1, objv, "variable name ops command"); } else { throw new TclNumArgsException(interp, 1, objv, "vdelete name ops command"); } } TCL.VarFlag flags = 0; string ops = objv[3].ToString(); len = ops.Length; { for (int i = 0; i < len; i++) { switch (ops[i]) { case 'r': flags |= TCL.VarFlag.TRACE_READS; break; case 'w': flags |= TCL.VarFlag.TRACE_WRITES; break; case 'u': flags |= TCL.VarFlag.TRACE_UNSETS; break; default: flags = 0; goto check_ops_brk; } } } check_ops_brk: ; if (flags == 0) { throw new TclException(interp, "bad operations \"" + objv[3] + "\": should be one or more of rwu"); } if (opt == OPT_VARIABLE) { CmdTraceProc trace = new CmdTraceProc(objv[4].ToString(), flags); Var.traceVar(interp, objv[2], flags, trace); } 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. ArrayList traces = Var.getTraces(interp, objv[2].ToString(), 0); if (traces != null) { len = traces.Count; for (int i = 0; i < len; i++) { TraceRecord rec = (TraceRecord)traces[i]; if (rec.trace is CmdTraceProc) { CmdTraceProc proc = (CmdTraceProc)rec.trace; if (proc.flags == flags && proc.command.ToString().Equals(objv[4].ToString())) { Var.untraceVar(interp, objv[2], flags, proc); break; } } } } } break; case OPT_VINFO: if (objv.Length != 3) { throw new TclNumArgsException(interp, 2, objv, "name"); } ArrayList traces2 = Var.getTraces(interp, objv[2].ToString(), 0); if (traces2 != null) { len = traces2.Count; TclObject list = TclList.newInstance(); TclObject cmd = null; list.preserve(); try { for (int i = 0; i < len; i++) { TraceRecord rec = (TraceRecord)traces2[i]; if (rec.trace is CmdTraceProc) { CmdTraceProc proc = (CmdTraceProc)rec.trace; TCL.VarFlag mode = proc.flags; mode &= (TCL.VarFlag.TRACE_READS | TCL.VarFlag.TRACE_WRITES | TCL.VarFlag.TRACE_UNSETS); int modeInt = (int)mode; modeInt /= ((int)TCL.VarFlag.TRACE_READS); cmd = TclList.newInstance(); TclList.append(interp, cmd, opStr[modeInt]); TclList.append(interp, cmd, TclString.newInstance(proc.command)); TclList.append(interp, list, cmd); } } interp.setResult(list); } finally { list.release(); } } break; } return(TCL.CompletionCode.RETURN); }