Posted to tcl by rar at Tue Jul 10 20:11:46 GMT 2007view raw
- /// <summary>
- /// Dispatch is the callback registered with Tcl API for every added command.
- /// when we get a callback, we look at argv[0] to figure out what command is
- /// desired, and find the actual method in the commandHash and call that with
- /// appropriate arguments.
- /// note this matches delegate Tcl_ObjCmdProc
- /// </summary>
- /// <param name="clientData"></param>
- /// <param name="pinterp"></param>
- /// <param name="argc"></param>
- /// <param name="argv"></param>
- /// <returns></returns>
- public unsafe int Dispatch(IntPtr clientData,
- IntPtr interpPtr,
- Int32 objc,
- IntPtr objv)
- {
- // get the context
- GCHandle contextHandle = (GCHandle)clientData;
- object context = (object)contextHandle.Target;
- // get a/the wrapped interpreter
- TclInterpreter interp = TclInterpreter.GetWrappedInterp(interpPtr);
- // parse objc+objv -> args
- // note that we are marshalling from unmanaged to managed manually here,
- // since C# doesn't know how big the objv array is -- but we do, since it's
- // provided by objc. see also comments for Tcl_ObjCmdProc delegate in TclAPI.cs
- // this should be a reasonably safe bit of unsafe code, as long as we can
- // trust objc. this MAY blow up on 64bit, depending on how smart my use
- // of IntPtr (vs., say, Int32) is.
- // also note that entries in the objv arrays are pointers to TclObjs -- we
- // simply use these pointers (i.e. the address of the TclObj) as opaque
- // handles on which we call Tcl_GetStringFromObj.
- string[] args = new string[objc];
- for (int i = 0; i < objc; i++)
- {
- // we assume here that only strings (or string representations)
- // will be passed; this is a valid assumption, though possibly
- // not the most efficient.
- // question: do we need to make a private copy of this string?
- // i.e. is args[i] going to point to memory managed and mutable
- // by Tcl?
- // answer: apparently not, because the marshalling code does
- // this automatically, at least in our case of converting 8 bit
- // ansi/ascii chars to 16 bit unicode chars.
- // at some point I was getting Invalid Access errors, i.e. there
- // would be a bad pointer getting referenced inside of Tcl_GetString.
- // after rebooting the system, I no longer see this. I suspect this
- // issue is related to how Tcl handles empty strings (i.e. ""), as it
- // was only empty string arguments that were causing the problem.
- // just hit it again, with: Stub setSMA ""
- // it appears to be the case that this happens after some amount of
- // uptime, probably prior to that the bad pointers are to zeroed-out
- // memory so things work ok.
- // this is bug 1038, which may or may not get fixed depending on whether
- // it ever is seen in real use
- IntPtr tclObjAddr = Marshal.ReadIntPtr(objv, i * sizeof(IntPtr));
- args[i] = TclAPI.Tcl_GetString(tclObjAddr);
- }
- // XXX bug 1038 XXX
- // this is a super ugly hack. to get around the problem of crashing when
- // passing in an empty string argument, Stub is aliased to a command that
- // will substitute "" with _EMPTY_STRING_ARG_. so here we need to look
- // through our args, and replace _EMPTY_STRING_ARG_ with ""
- for (int i = 0; i < args.Length; i++)
- {
- if (args[i] == "_EMPTY_STRING_ARG_")
- {
- args[i] = "";
- }
- }
- // get the actual command from the commandHash based on command
- // name from tcl
- // XXX bug 1038 hack XXX
- // if we've wrapped the command, we have to remove the .wrapped bit
- // or we won't find a matching command. uf, hadn't thought of this
- // before...
- // need a more generalized mechanism if we're going to wrap other
- // commands.
- if (args[0] == "Stub.wrapped")
- {
- args[0] = "Stub";
- }
- TclCommand command = commandHash[args[0]] as TclCommand;
- // execute that command, cast the Tcl_Result to an int
- return ((int)command.Execute(args, context, interp));
- }