/////////////////////////////////////////////////////////////////////// #region Public Constructors public _Hash( ICommandData commandData ) : base(commandData) { lock (syncRoot) { if (defaultAlgorithms == null) { try { defaultAlgorithms = GetAlgorithms(); } catch (Exception e) { TraceOps.DebugTrace( e, typeof(_Hash).Name, TracePriority.InternalError); } // // HACK: Prevent this block from being entered again for // this application domain. // if (defaultAlgorithms == null) { defaultAlgorithms = new StringList(); } } } }
/////////////////////////////////////////////////////////////////////// internal static bool Dispose( IEvent @event /* in */ ) { try { IDisposable disposable = @event as IDisposable; if (disposable != null) { disposable.Dispose(); /* throw */ disposable = null; return(true); } } catch (Exception e) { TraceOps.DebugTrace( e, typeof(Event).Name, TracePriority.EventError); } return(false); }
/////////////////////////////////////////////////////////////////////// public ReturnCode VerifyModule( ref Result error ) { if (String.IsNullOrEmpty(fileName)) { error = "invalid Tcl native module file name"; return(ReturnCode.Error); } if (!NativeOps.IsValidHandle(module)) { error = "invalid Tcl native module handle"; return(ReturnCode.Error); } // // HACK: We cannot actually verify the native module handle on any // non-Windows operating system. // if (!PlatformOps.IsWindowsOperatingSystem()) { return(ReturnCode.Ok); } try { IntPtr newModule = NativeOps.GetModuleHandle(fileName); if (newModule == IntPtr.Zero) { error = String.Format( "bad Tcl native module handle {0}, file name {1} is " + "no longer loaded", module, FormatOps.WrapOrNull( fileName)); TraceOps.DebugTrace(String.Format( "VerifyModule: {0}", FormatOps.WrapOrNull(error)), typeof(TclModule).Name, TracePriority.NativeError); return(ReturnCode.Error); } if (newModule != module) { // // NOTE: This situation should really never happen. If it // does, that indicates that the native Tcl module // was unloaded and then reloaded out from under the // native Tcl integration subsystem. // error = String.Format( "bad Tcl native module handle {0}, got {1} for file " + "name {2}", module, newModule, FormatOps.WrapOrNull( fileName)); TraceOps.DebugTrace(String.Format( "VerifyModule: {0}", FormatOps.WrapOrNull(error)), typeof(TclModule).Name, TracePriority.NativeError); return(ReturnCode.Error); } return(ReturnCode.Ok); } catch (Exception e) { error = e; } return(ReturnCode.Error); }
public override ReturnCode Execute( Interpreter interpreter, IClientData clientData, ArgumentList arguments, ref Result result ) { ReturnCode code; if (interpreter != null) { if (arguments != null) { if (arguments.Count >= 1) { OptionDictionary options = new OptionDictionary( new IOption[] { new Option(null, OptionFlags.Unsafe, Index.Invalid, Index.Invalid, "-force", null), new Option(null, OptionFlags.Unsafe, Index.Invalid, Index.Invalid, "-fail", null), new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-message", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-current", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null) }); int argumentIndex = Index.Invalid; if (arguments.Count > 1) { code = interpreter.GetOptions(options, arguments, 0, 1, Index.Invalid, false, ref argumentIndex, ref result); } else { code = ReturnCode.Ok; } if (code == ReturnCode.Ok) { if ((argumentIndex == Index.Invalid) || ((argumentIndex + 1) == arguments.Count)) { bool force = false; if (options.IsPresent("-force")) { force = true; } bool fail = false; if (options.IsPresent("-fail")) { fail = true; } Variant value = null; string message = null; if (options.IsPresent("-message", ref value)) { message = value.ToString(); } // // NOTE: The default exit code is "success" (i.e. zero). // ExitCode exitCode = ResultOps.SuccessExitCode(); if (options.IsPresent("-current")) { exitCode = interpreter.ExitCode; } // // NOTE: Was an exit code specified in the command? // if (argumentIndex != Index.Invalid) { object enumValue = EnumOps.TryParseEnum( typeof(ExitCode), arguments[argumentIndex], true, true, ref result); if (enumValue is ExitCode) { exitCode = (ExitCode)enumValue; } else { result = ScriptOps.BadValue( null, "exit code", arguments[argumentIndex], Enum.GetNames(typeof(ExitCode)), null, ", or an integer"); code = ReturnCode.Error; } } // // NOTE: Make sure we succeeded at coverting the exit code to an integer. // if (code == ReturnCode.Ok) { // // NOTE: Make sure the interpreter host, if any, agrees to exit (i.e. it may deny the // request if the application is doing something that should not be interrupted). // code = interpreter.CanExit(exitCode, force, fail, message, ref result); if (code == ReturnCode.Ok) { // // NOTE: Exit the application (either by marking the current interpreter as "exited" // or physically exiting the containing process). // TraceOps.DebugTrace(String.Format( "Execute: {0}, interpreter = {1}, message = {2}", force && fail ? "forcibly failing" : force ? "forcibly exiting" : "exiting", FormatOps.InterpreterNoThrow(interpreter), FormatOps.WrapOrNull(message)), typeof(Exit).Name, TracePriority.Command); if (force) { #if !MONO if (fail && !CommonOps.Runtime.IsMono()) { try { // // NOTE: Using this method to exit a script is NOT recommended unless // you are trying to prevent damaging another part of the system. // // MONO: This method is not supported by the Mono runtime. // Environment.FailFast(message); /* NOT REACHED */ result = "failed to exit process"; code = ReturnCode.Error; } catch (Exception e) { result = e; code = ReturnCode.Error; } } else #endif { // // BUGFIX: Try to dispose our containing interpreter now. We must do // this to prevent it from being disposed on a random GC thread. // try { interpreter.Dispose(); interpreter = null; } catch (Exception e) { result = e; code = ReturnCode.Error; } // // NOTE: If we could not dispose the interpreter properly, complain; // however, keep exiting anyway. // if (code != ReturnCode.Ok) { DebugOps.Complain(interpreter, code, result); } try { // // NOTE: Using this method to exit a script is NOT recommended unless // you are running a standalone script in the Eagle Shell (i.e. // you are not hosted within another application). // Environment.Exit((int)exitCode); /* NOT REACHED */ result = "failed to exit process"; code = ReturnCode.Error; } catch (Exception e) { result = e; code = ReturnCode.Error; } } } else { interpreter.ExitCode = exitCode; interpreter.Exit = true; result = String.Empty; code = ReturnCode.Ok; } } } } else { if ((argumentIndex != Index.Invalid) && Option.LooksLikeOption(arguments[argumentIndex])) { result = OptionDictionary.BadOption(options, arguments[argumentIndex]); } else { result = "wrong # args: should be \"exit ?options? ?returnCode?\""; } code = ReturnCode.Error; } } } else { result = "wrong # args: should be \"exit ?options? ?returnCode?\""; code = ReturnCode.Error; } } else { result = "invalid argument list"; code = ReturnCode.Error; } } else { result = "invalid interpreter"; code = ReturnCode.Error; } return(code); }
/////////////////////////////////////////////////////////////////////// #region INotify Members public override ReturnCode Notify( Interpreter interpreter, IScriptEventArgs eventArgs, IClientData clientData, ArgumentList arguments, ref Result result ) { // // NOTE: If we are disabled -OR- there are no event arguments -OR- // this event does not match the kind we are interested in // then just return "success" now. // if (disabled || (eventArgs == null) || !FlagOps.HasFlags( eventArgs.NotifyTypes, NotifyType.Engine, false) || !FlagOps.HasFlags( eventArgs.NotifyFlags, NotifyFlags.Executed, false)) { return(ReturnCode.Ok); } // // NOTE: In "direct" mode, skip [almost] all the tracing ceremony // and just call into Trace.WriteLine(). Otherwise, use the // TraceOps class and all its special handling. Either way, // figure out the String.Format() arguments ahead of time, // based on our current "normalize" and "ellipsis" settings. // try { string arg0 = FormatOps.WrapTraceOrNull( normalizeArguments, ellipsisArguments, quoteArguments, displayArguments, eventArgs.Arguments); string arg1 = FormatOps.WrapTraceOrNull( normalizeResult, ellipsisResult, quoteResult, displayResult, eventArgs.Result); if (direct) { // // NOTE: This is just an extremely thin wrapper around // the Trace.WriteLine method. // DebugOps.TraceWriteLine(String.Format( directFormat, arg0, arg1), directCategory); } else { // // NOTE: Use the tracing subsystem. // TraceOps.DebugTrace(String.Format( normalFormat, arg0, arg1), normalCategory, TracePriority.EngineDebug); } return(ReturnCode.Ok); } catch (Exception e) { TraceOps.DebugTrace( e, typeof(Trace).Name, TracePriority.EngineError); result = e; return(ReturnCode.Error); } }
public override ReturnCode Execute( Interpreter interpreter, IClientData clientData, ArgumentList arguments, ref Result result ) { ReturnCode code = ReturnCode.Ok; if (interpreter != null) { if (arguments != null) { if (arguments.Count >= 2) { OptionDictionary options = new OptionDictionary( new IOption[] { new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-debug", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-commandline", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-dequote", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-quoteall", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-unicode", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-ignorestderr", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-killonerror", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-keepnewline", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-noexitcode", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocapture", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-shell", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocarriagereturns", null), // simple switch new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-trimall", null), // simple switch new Option(typeof(ExitCode), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-success", null), // success exit code new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-domainname", null), new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-username", null), new Option(null, OptionFlags.MustHaveSecureStringValue, Index.Invalid, Index.Invalid, "-password", null), new Option(null, OptionFlags.MustHaveListValue, Index.Invalid, Index.Invalid, "-preprocessarguments", null), // command new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-directory", null), // directory name new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-processid", null), // varName for processId new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-exitcode", null), // varName for exitCode new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-stdin", null), // varName for StdIn input new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-stdout", null), // varName for StdOut output new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-stderr", null), // varName for StdErr output new Option(typeof(EventFlags), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-eventflags", new Variant(interpreter.EngineEventFlags)), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null) }); int argumentIndex = Index.Invalid; code = interpreter.GetOptions(options, arguments, 0, 1, Index.Invalid, true, ref argumentIndex, ref result); if (code == ReturnCode.Ok) { if (argumentIndex != Index.Invalid) { bool debug = false; if (options.IsPresent("-debug")) { debug = true; } bool commandLine = false; if (options.IsPresent("-commandline")) { commandLine = true; } bool dequote = false; if (options.IsPresent("-dequote")) { dequote = true; } bool quoteAll = false; if (options.IsPresent("-quoteall")) { quoteAll = true; } bool captureExitCode = true; if (options.IsPresent("-noexitcode")) { captureExitCode = false; } bool captureInput = true; bool captureOutput = true; if (options.IsPresent("-nocapture")) { captureInput = false; captureOutput = false; } bool useUnicode = false; if (options.IsPresent("-unicode")) { useUnicode = true; } bool ignoreStdErr = false; if (options.IsPresent("-ignorestderr")) { ignoreStdErr = true; } bool killOnError = false; if (options.IsPresent("-killonerror")) { killOnError = true; } bool keepNewLine = false; if (options.IsPresent("-keepnewline")) { keepNewLine = true; } bool carriageReturns = true; if (options.IsPresent("-nocarriagereturns")) { carriageReturns = false; } bool trimAll = false; if (options.IsPresent("-trimall")) { trimAll = true; } bool useShellExecute = false; if (options.IsPresent("-shell")) { useShellExecute = true; } Variant value = null; ExitCode?successExitCode = null; if (options.IsPresent("-success", ref value)) { successExitCode = (ExitCode)value.Value; } string domainName = null; if (options.IsPresent("-domainname", ref value)) { domainName = value.ToString(); } string userName = null; if (options.IsPresent("-username", ref value)) { userName = value.ToString(); } SecureString password = null; if (options.IsPresent("-password", ref value)) { password = (SecureString)value.Value; } string directory = null; if (options.IsPresent("-directory", ref value)) { directory = value.ToString(); } string processIdVarName = null; if (options.IsPresent("-processid", ref value)) { processIdVarName = value.ToString(); } string exitCodeVarName = null; if (options.IsPresent("-exitcode", ref value)) { exitCodeVarName = value.ToString(); } string stdInVarName = null; if (options.IsPresent("-stdin", ref value)) { stdInVarName = value.ToString(); } string stdOutVarName = null; if (options.IsPresent("-stdout", ref value)) { stdOutVarName = value.ToString(); } string stdErrVarName = null; if (options.IsPresent("-stderr", ref value)) { stdErrVarName = value.ToString(); } EventFlags eventFlags = interpreter.EngineEventFlags; if (options.IsPresent("-eventflags", ref value)) { eventFlags = (EventFlags)value.Value; } StringList list = null; if (options.IsPresent("-preprocessarguments", ref value)) { list = (StringList)value.Value; } int argumentStopIndex = arguments.Count - 1; bool background = false; if (arguments[arguments.Count - 1] == Characters.Ampersand.ToString()) { argumentStopIndex--; background = true; } string execFileName = arguments[argumentIndex]; if (!PathOps.IsRemoteUri(execFileName)) { execFileName = PathOps.GetNativePath(execFileName); } string execArguments = null; if ((argumentIndex + 1) < arguments.Count) { if (commandLine) { execArguments = RuntimeOps.BuildCommandLine( ArgumentList.GetRangeAsStringList(arguments, argumentIndex + 1, argumentStopIndex, dequote), quoteAll); } else { execArguments = ListOps.Concat(arguments, argumentIndex + 1, argumentStopIndex); } } Result input = null; if ((code == ReturnCode.Ok) && !useShellExecute && captureInput && (stdInVarName != null)) { code = interpreter.GetVariableValue(VariableFlags.None, stdInVarName, ref input, ref result); } if (debug) { TraceOps.DebugTrace(String.Format( "Execute: interpreter = {0}, domainName = {1}, userName = {2}, " + "password = {3}, execFileName = {4}, execArguments = {5}, " + "directory = {6}, input = {7}, eventFlags = {8}, debug = {9}, " + "commandLine = {10}, dequote = {11}, quoteAll = {12}, " + "useShellExecute = {13}, captureExitCode = {14}, " + "captureInput = {15}, captureOutput = {16}, useUnicode = {17}, " + "ignoreStdErr = {18}, killOnError = {19}, keepNewLine = {20}, " + "carriageReturns = {21}, trimAll = {22}, background = {23}, " + "successExitCode = {24}, processIdVarName = {25}, exitCodeVarName = {26}, " + "stdInVarName = {27}, stdOutVarName = {28}, stdErrVarName = {29}", FormatOps.InterpreterNoThrow(interpreter), FormatOps.WrapOrNull(domainName), FormatOps.WrapOrNull(userName), FormatOps.WrapOrNull(password), FormatOps.WrapOrNull(execFileName), FormatOps.WrapOrNull(execArguments), FormatOps.WrapOrNull(directory), FormatOps.WrapOrNull(input), FormatOps.WrapOrNull(eventFlags), debug, commandLine, dequote, quoteAll, useShellExecute, captureExitCode, captureInput, captureOutput, useUnicode, ignoreStdErr, killOnError, keepNewLine, carriageReturns, trimAll, background, FormatOps.WrapOrNull(successExitCode), FormatOps.WrapOrNull(processIdVarName), FormatOps.WrapOrNull(exitCodeVarName), FormatOps.WrapOrNull(stdInVarName), FormatOps.WrapOrNull(stdOutVarName), FormatOps.WrapOrNull(stdErrVarName)), typeof(Exec).Name, TracePriority.Command); } int processId = 0; ExitCode exitCode = ResultOps.SuccessExitCode(); Result error = null; if (code == ReturnCode.Ok) { if (list != null) { list.Add(execFileName); list.Add(directory); list.Add(execArguments); code = interpreter.EvaluateScript(list.ToString(), ref result); if (code == ReturnCode.Return) { execArguments = result; code = ReturnCode.Ok; } else if (code == ReturnCode.Continue) { code = ReturnCode.Ok; goto done; } } if (code == ReturnCode.Ok) { code = ProcessOps.ExecuteProcess( interpreter, domainName, userName, password, execFileName, execArguments, directory, input, eventFlags, useShellExecute, captureExitCode, captureOutput, useUnicode, ignoreStdErr, killOnError, keepNewLine, background, !background, ref processId, ref exitCode, ref result, ref error); } } done: if (debug) { TraceOps.DebugTrace(String.Format( "Execute: interpreter = {0}, domainName = {1}, userName = {2}, " + "password = {3}, execFileName = {4}, execArguments = {5}, " + "directory = {6}, input = {7}, eventFlags = {8}, debug = {9}, " + "commandLine = {10}, dequote = {11}, quoteAll = {12}, " + "useShellExecute = {13}, captureExitCode = {14}, " + "captureInput = {15}, captureOutput = {16}, useUnicode = {17}, " + "ignoreStdErr = {18}, killOnError = {19}, keepNewLine = {20}, " + "carriageReturns = {21}, trimAll = {22}, background = {23}, " + "successExitCode = {24}, processIdVarName = {25}, exitCodeVarName = {26}, " + "stdInVarName = {27}, stdOutVarName = {28}, stdErrVarName = {29}, " + "processId = {30}, exitCode = {31}, result = {32}, error = {33}", FormatOps.InterpreterNoThrow(interpreter), FormatOps.WrapOrNull(domainName), FormatOps.WrapOrNull(userName), FormatOps.WrapOrNull(password), FormatOps.WrapOrNull(execFileName), FormatOps.WrapOrNull(execArguments), FormatOps.WrapOrNull(directory), FormatOps.WrapOrNull(input), FormatOps.WrapOrNull(eventFlags), debug, commandLine, dequote, quoteAll, useShellExecute, captureExitCode, captureInput, captureOutput, useUnicode, ignoreStdErr, killOnError, keepNewLine, carriageReturns, trimAll, background, FormatOps.WrapOrNull(successExitCode), FormatOps.WrapOrNull(processIdVarName), FormatOps.WrapOrNull(exitCodeVarName), FormatOps.WrapOrNull(stdInVarName), FormatOps.WrapOrNull(stdOutVarName), FormatOps.WrapOrNull(stdErrVarName), processId, exitCode, FormatOps.WrapOrNull(true, true, result), FormatOps.WrapOrNull(true, true, error)), typeof(Exec).Name, TracePriority.Command); } // // NOTE: Even upon failure, always set the variable to contain // process Id, if applicable. // if (processIdVarName != null) { /* IGNORED */ interpreter.SetVariableValue( /* EXEMPT */ VariableFlags.NoReady, processIdVarName, processId.ToString(), null); } if (code == ReturnCode.Ok) { // // NOTE: Remove all carriage returns from output (leaving // only line feeds as line separators)? // if (!carriageReturns) { if (!String.IsNullOrEmpty(result)) { result = result.Replace( Characters.CarriageReturnString, String.Empty); } if (!String.IsNullOrEmpty(error)) { error = error.Replace( Characters.CarriageReturnString, String.Empty); } } // // NOTE: Remove all surrounding whitespace from the output? // if (trimAll) { if (!String.IsNullOrEmpty(result)) { result = result.Trim(); } if (!String.IsNullOrEmpty(error)) { error = error.Trim(); } } // // NOTE: Now, "result" contains any StdOut output and "error" // contains any StdErr output. // if ((code == ReturnCode.Ok) && !background && captureExitCode && (exitCodeVarName != null)) { code = interpreter.SetVariableValue(VariableFlags.None, exitCodeVarName, exitCode.ToString(), null, ref error); } if ((code == ReturnCode.Ok) && !useShellExecute && !background && captureOutput && (stdOutVarName != null)) { code = interpreter.SetVariableValue(VariableFlags.None, stdOutVarName, result, null, ref error); } if ((code == ReturnCode.Ok) && !useShellExecute && !background && captureOutput && (stdErrVarName != null)) { code = interpreter.SetVariableValue(VariableFlags.None, stdErrVarName, error, null, ref error); } // // NOTE: If they specified a "success" exit code, make sure // that is the same as the exit code we actually got // from the process. // if ((code == ReturnCode.Ok) && !background && captureExitCode && (successExitCode != null) && (exitCode != successExitCode)) { /* IGNORED */ interpreter.SetVariableValue( /* EXEMPT */ Engine.ErrorCodeVariableFlags, TclVars.ErrorCode, StringList.MakeList( "CHILDSTATUS", processId, exitCode), null); Engine.SetErrorCodeSet(interpreter, true); error = "child process exited abnormally"; code = ReturnCode.Error; } if (code != ReturnCode.Ok) { // // NOTE: Transfer error to command result. // result = error; } } else { // // NOTE: Transfer error to command result. // result = error; } } else { result = "wrong # args: should be \"exec ?options? arg ?arg ...?\""; code = ReturnCode.Error; } } } else { result = "wrong # args: should be \"exec ?options? arg ?arg ...?\""; code = ReturnCode.Error; } } else { result = "invalid argument list"; code = ReturnCode.Error; } } else { result = "invalid interpreter"; code = ReturnCode.Error; } return(code); }
/////////////////////////////////////////////////////////////////////// public virtual void TrimExcess( /* O(N) */ int minimumCount, /* in */ int maximumCount, /* in */ int minimumRemoveCount, /* in */ int maximumRemoveCount, /* in */ int minimumAccessCount, /* in */ int maximumAccessCount, /* in */ ref int possibleRemoveCount /* out */ ) { // // NOTE: Initially, assume that we cannot do any trimming, due to // the parameters specified by the caller; later, this may // change. // possibleRemoveCount = 0; // // NOTE: Is there a maximum number of items configured for this // cache? If not, do nothing. // if (maximumCount >= 0) { // // NOTE: Grab the current number of items in this cache and see // if it exceeds the configured maximum. // int beforeCount = this.Count; if (beforeCount > maximumCount) { // // NOTE: Figure out how many milliseconds it has been since // we last trimmed excess elements, if ever. // double milliseconds = GetLastTrimMilliseconds(); // // NOTE: If we have never trimmed excess elements or it has // been longer than the configured time span, do it // again now. // if ((milliseconds == Milliseconds.Never) || (milliseconds > trimMilliseconds)) { // // NOTE: How many items need to be removed to fit // within the upper limit? // int removeCount = beforeCount - maximumCount; // // NOTE: We know that some trimming is possible; // if the correct parameters are specified // by the caller. // possibleRemoveCount = removeCount; // // NOTE: If there is no lower limit on the number // of items that should remain in the cache // -OR- the number of items that to remain // in the cache satisfies it, then proceed // with removing the items. // if (((minimumCount < 0) || ((beforeCount - removeCount) >= minimumCount)) && ((minimumRemoveCount < 0) || (removeCount >= minimumRemoveCount))) { // // NOTE: If the number of items to be removed // exceeds the specified maximum, just // make it the specified maximum. // if ((maximumRemoveCount >= 0) && (removeCount > maximumRemoveCount)) { removeCount = maximumRemoveCount; } // // NOTE: Try to remove the specified number of // items. This MAY have no effect -OR- // it may cause the removal of a different // number of items. // int foundCount = 0; int removedCount = 0; Remove(minimumAccessCount, maximumAccessCount, removeCount, ref foundCount, ref removedCount); /////////////////////////////////////////////////// #if DEBUG if (removedCount != removeCount) { int afterCount = this.Count; TraceOps.DebugTrace(String.Format( "TrimExcess: minimumAccessCount = {0}, " + "maximumAccessCount = {1}, " + "removeCount = {2}, foundCount = {3}, " + "removedCount = {4}, beforeCount = {5}, " + "afterCount = {6}, trimCount = {7}", minimumAccessCount, maximumAccessCount, removeCount, foundCount, removedCount, beforeCount, afterCount, trimCount), GetType().Name, TracePriority.EngineDebug); } #endif /////////////////////////////////////////////////// // // NOTE: Ok, we have successfully trimmed the // excess elements, record the current // time so that we will not do it again // too soon. // lastTrim = Now; lastTrimCount = removedCount; // // NOTE: Another trim operation was completed. // trimCount++; } } } } }
/////////////////////////////////////////////////////////////////////////////////////////////// private /* protected virtual */ void Dispose( bool disposing ) /* throw */ { TraceOps.DebugTrace(String.Format( "Dispose: called, disposing = {0}, disposed = {1}", disposing, disposed), typeof(TclBridge).Name, TracePriority.CleanupDebug); if (!disposed) { if (!this.disposing) { // // NOTE: We are now disposing this object (prevent re-entrancy). // this.disposing = true; // // NOTE: This method should not normally throw; however, if it does // we do not want our disposing flag to be stuck set to true. // try { //if (disposing) //{ // //////////////////////////////////// // // dispose managed resources here... // //////////////////////////////////// //} ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// // // NOTE: If necessary (and possible), delete the Tcl command via the // token we saved earlier (when the Tcl command was created). // ReturnCode deleteCode = ReturnCode.Ok; Result deleteError = null; // // NOTE: If we have a valid command token then we are still hooked to // Tcl via our inbound native delegates and we must unhook // successfully or throw to prevent our internal object state // from being made inconsistent. // if (token != IntPtr.Zero) { if (interpreter != null) { ITclApi tclApi = TclApi.GetTclApi(interpreter); // // BUGFIX: We want to force deletion of this bridged command // if the force flag was specified upon creation OR // if the command is not actively being used. // deleteCode = TclWrapper.DeleteCommandFromToken( tclApi, interp, forceDelete || (objCmdProcLevels == 0), ref token, ref deleteError); } else { deleteError = "invalid interpreter"; deleteCode = ReturnCode.Error; } } // // NOTE: Did we succeed in deleting the command from Tcl, if it // was necessary? // if (!noComplain && (deleteCode != ReturnCode.Ok)) { // // NOTE: If the command deletion was necessary and it failed // for any reason, complain very loudly. // DebugOps.Complain(interpreter, deleteCode, deleteError); // // BUGFIX: Also, we must throw an exception here to prevent // the delegates from being disposed while Tcl still // refers to them (tclLoad-1.2 GC race). // throw new ScriptException(deleteCode, deleteError); } // // NOTE: If necessary, release the GCHandle that is keeping this // object alive. // if (handle.IsAllocated) { handle.Free(); } // // NOTE: We do not own these objects; therefore, we just null out // the references to them (in case we are the only thing // keeping them alive). // interpreter = null; execute = null; clientData = null; // // NOTE: Zero out our Tcl interpreter. We do not delete it because // we do not own it. // interp = IntPtr.Zero; // // NOTE: Zero out our created Tcl command token. We should not need // to call Tcl to delete the actual command because by this time // it should already have been deleted. // token = IntPtr.Zero; // // NOTE: Finally, we should be able to safely remove our references // to the Tcl callback delegates at this point because we already // deleted the Tcl command related to them. // objCmdProc = null; cmdDeleteProc = null; // // NOTE: Zero out our command nesting level. // objCmdProcLevels = 0; // // NOTE: This object is now disposed. // disposed = true; } finally { // // NOTE: We are no longer disposing this object. // this.disposing = false; } } } }
/////////////////////////////////////////////////////////////////////////////////////////////// // // -- CmdDeleteProc -- // // DeleteProc will be invoked when (if) name is deleted. This can occur through a // call to Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, or Tcl_DeleteInterp, or // by replacing name in another call to Tcl_CreateObjCommand. DeleteProc is // invoked before the command is deleted, and gives the application an // opportunity to release any structures associated with the command. // private static void CmdDeleteProc( IntPtr clientData ) { // // NOTE: We need to kill the associated TclBridge object // instance and remove any references to the bridge // from the containing interpreter. // try { // // NOTE: Rehydrate the handle from the clientData that Tcl just // passed us. // GCHandle handle = GCHandle.FromIntPtr(clientData); /* throw */ // // NOTE: Make sure the handle has a valid target. // if (handle.IsAllocated && (handle.Target != null)) { // // NOTE: Attempt to cast the handle to a TclBridge object; if this // fails, we cannot continue to handle this call. // TclBridge tclBridge = handle.Target as TclBridge; if (tclBridge != null) { // // NOTE: Skip messing with the TclBridge or interpreter object if it is // already being disposed (i.e. we are NOT being called directly // due to the command being removed from the Tcl interpreter or // the Tcl interpreter being deleted). The caller of the dispose // method will handle removing the TclBridge object from the // collection in the interpreter. // if (!tclBridge.disposing) { // // NOTE: Grab the associated interpreter from the TclBridge // object. // Interpreter interpreter = tclBridge.interpreter; // // NOTE: Remove all instances of the TclBridge object from its // interpreter. // if (interpreter != null) { /* IGNORED */ interpreter.RemoveTclBridges(tclBridge); } // // NOTE: Prevent the Dispose method from trying to delete the Tcl // command itself (since it is already being deleted). // tclBridge.token = IntPtr.Zero; // // NOTE: Cleanup all the resources used by this TclBridge object. // In theory, this object disposal can throw; however, in // practice we know that it does not attempt to do anything // that can actually "fail" unless it has a valid command // token, which we have already cleared (Tcl has notified us, // by calling this delegate, that it has already deleted the // command in question). // tclBridge.Dispose(); /* throw */ } } else { TraceOps.DebugTrace( "invalid Tcl bridge object", typeof(Tcl_CmdDeleteProc).Name, TracePriority.MarshalError); } } else { TraceOps.DebugTrace( "invalid GC handle", typeof(Tcl_CmdDeleteProc).Name, TracePriority.MarshalError); } } catch (Exception e) { // // NOTE: Nothing we can do here except log the failure. // TraceOps.DebugTrace( e, typeof(Tcl_CmdDeleteProc).Name, TracePriority.NativeError); } }
/////////////////////////////////////////////////////////////////////////////////////////////// #region Tcl Command Callbacks /////////////////////////////////////////////////////////////////////////////////////////////// // **** WARNING ***** BEGIN CODE DIRECTLY CALLED BY THE NATIVE TCL RUNTIME ***** WARNING **** / /////////////////////////////////////////////////////////////////////////////////////////////// // // -- ObjCmdProc -- // // When proc is invoked, the clientData and interp parameters will be copies of // the clientData and interp arguments given to Tcl_CreateObjCommand. Typically, // clientData points to an application-specific data structure that describes // what to do when the command procedure is invoked. Objc and objv describe the // arguments to the command, objc giving the number of argument objects // (including the command name) and objv giving the values of the arguments. The // objv array will contain objc values, pointing to the argument objects. Unlike // argv[argv] used in a string-based command procedure, objv[objc] will not // contain NULL. Additionally, when proc is invoked, it must not modify the // contents of the objv array by assigning new pointer values to any element of // the array (for example, objv[2] = NULL) because this will cause memory to be // lost and the runtime stack to be corrupted. The CONST in the declaration of // objv will cause ANSI-compliant compilers to report any such attempted // assignment as an error. However, it is acceptable to modify the internal // representation of any individual object argument. For instance, the user may // call Tcl_GetIntFromObj on objv[2] to obtain the integer representation of that // object; that call may change the type of the object that objv[2] points at, // but will not change where objv[2] points. proc must return an integer code // that is either TCL_OK, TCL_ERROR, TCL_RETURN, TCL_BREAK, or TCL_CONTINUE. See // the Tcl overview man page for details on what these codes mean. Most normal // commands will only return TCL_OK or TCL_ERROR. In addition, if proc needs to // return a non-empty result, it can call Tcl_SetObjResult to set the // interpreter's result. In the case of a TCL_OK return code this gives the // result of the command, and in the case of TCL_ERROR this gives an error // message. Before invoking a command procedure, Tcl_EvalObjEx sets interpreter's // result to point to an object representing an empty string, so simple commands // can return an empty result by doing nothing at all. The contents of the objv // array belong to Tcl and are not guaranteed to persist once proc returns: proc // should not modify them. Call Tcl_SetObjResult if you want to return something // from the objv array. // private static ReturnCode ObjCmdProc( IntPtr clientData, IntPtr interp, int objc, IntPtr objv ) { ReturnCode code; try { // // NOTE: Rehydrate the handle from the clientData that Tcl just // passed us. // GCHandle handle = GCHandle.FromIntPtr(clientData); /* throw */ // // NOTE: Make sure the handle has a valid target. // if (handle.IsAllocated && (handle.Target != null)) { // // NOTE: Attempt to cast the handle to a TclBridge object; if this // fails, we cannot continue to handle this call. // TclBridge tclBridge = handle.Target as TclBridge; if (tclBridge != null) { Interlocked.Increment(ref tclBridge.objCmdProcLevels); try { // // NOTE: Grab the interpreter reference NOW, it may go bye bye if the // TclBridge object gets disposed. // Interpreter interpreter = tclBridge.interpreter; if (interpreter != null) { // // NOTE: Cache the fields of the interpreter object that we will // need to access below without holding a lock. // ITclApi tclApi = TclApi.GetTclApi(interpreter); EngineFlags savedEngineFlags = interpreter.BeginExternalExecution(); bool noCacheArgument = false; #if ARGUMENT_CACHE if (Engine.HasNoCacheArgument(savedEngineFlags)) { noCacheArgument = true; } #endif try { if (tclApi != null) { Result result = null; IExecute execute = tclBridge.execute; if (execute != null) { ArgumentList arguments = new ArgumentList(); for (int index = 0; index < objc; index++) { IntPtr objPtr = Marshal.ReadIntPtr(objv, index * IntPtr.Size); string value = TclWrapper.GetString(tclApi, objPtr); if (value == null) { value = String.Empty; } arguments.Add(Argument.GetOrCreate( interpreter, value, noCacheArgument)); } string name = (arguments.Count > 0) ? arguments[0] : null; try { code = interpreter.Execute( name, execute, tclBridge.clientData, arguments, ref result); } catch (Exception e) { result = String.Format( "caught exception while executing: {0}", e); code = ReturnCode.Error; } } else { result = "invalid execute object"; code = ReturnCode.Error; } // // NOTE: Set the Tcl interpreter result to the result of the // Eagle command. // if (!String.IsNullOrEmpty(result)) { TclWrapper.SetResult( tclApi, interp, TclWrapper.NewString(tclApi, result)); } else { TclWrapper.ResetResult(tclApi, interp); } } else { // // NOTE: There is no available Tcl API object; therefore, we // cannot set the Tcl interpreter result. // TraceOps.DebugTrace( "invalid Tcl API object", typeof(Tcl_ObjCmdProc).Name, TracePriority.MarshalError); code = ReturnCode.Error; } } finally { /* IGNORED */ interpreter.EndAndCleanupExternalExecution(savedEngineFlags); } } else { // // NOTE: An invalid interpreter means that we have no Tcl API object to // work with either, punt on setting the Tcl interpreter result. // TraceOps.DebugTrace( "invalid interpreter", typeof(Tcl_ObjCmdProc).Name, TracePriority.MarshalError); code = ReturnCode.Error; } } finally { Interlocked.Decrement(ref tclBridge.objCmdProcLevels); } } else { // // NOTE: What now? We have no way of communicating with Tcl at this // point. // TraceOps.DebugTrace( "invalid Tcl bridge object", typeof(Tcl_ObjCmdProc).Name, TracePriority.MarshalError); code = ReturnCode.Error; } } else { // // NOTE: Again, nothing we can do at this point. // TraceOps.DebugTrace( "invalid GC handle", typeof(Tcl_ObjCmdProc).Name, TracePriority.MarshalError); code = ReturnCode.Error; } } catch (Exception e) { // // NOTE: Nothing we can do here except log the failure. // TraceOps.DebugTrace( e, typeof(Tcl_ObjCmdProc).Name, TracePriority.NativeError); // // NOTE: At this point, we may not even be able to get to the Tcl API object // we need to set the Tcl interpreter result; therefore, we are going // to punt for now. // code = ReturnCode.Error; } return(code); }
/////////////////////////////////////////////////////////////////////// #region Private private static bool IsPresent( OptionDictionary options, string name, bool noCase, bool strict, ref Variant value, ref int index ) { if (options != null) { if (name != null) { if (noCase) { // // HACK: Perform a linear search of the options. We // should not need to do this since the options // are in a dictionary; however, we want to // preserve the "case-sensitive" semantics unless // otherwise requested by the caller. // bool found = false; foreach (KeyValuePair <string, IOption> pair in options) { if (String.Compare(pair.Key, 0, name, 0, name.Length, StringOps.SystemNoCaseStringComparisonType) == 0) { found = true; IOption option = pair.Value; if ((option != null) && option.IsPresent(options, ref value)) { index = option.Index; return(true); } } } if (strict && !found) { // // NOTE: This should not really happen, issue a // debug trace. // TraceOps.DebugTrace(String.Format( "IsPresent: {0}", BadOption(options, name)), typeof(OptionDictionary).Name, TracePriority.Command); } } else { IOption option; if (options.TryGetValue(name, out option)) { if ((option != null) && option.IsPresent(options, ref value)) { index = option.Index; return(true); } } else if (strict) { // // NOTE: This should not really happen, issue a // debug trace. // TraceOps.DebugTrace(String.Format( "IsPresent: {0}", BadOption(options, name)), typeof(OptionDictionary).Name, TracePriority.Command); } } } } return(false); }