Exemple #1
0
        ///////////////////////////////////////////////////////////////////////

        private static bool IsSuccess(
            ReturnCode code,     /* in */
            bool okOrReturnOnly, /* in */
            bool allowExceptions /* in */
            )
        {
            if (okOrReturnOnly)
            {
                return(ResultOps.IsOkOrReturn(code));
            }

            return(ResultOps.IsSuccess(code, allowExceptions));
        }
Exemple #2
0
        ///////////////////////////////////////////////////////////////////////

        #region Public Methods
        public ReturnCode Process(
            ref StringBuilder output, /* in, out */
            ref ResultList errors     /* in, out */
            )                         /* ENTRY-POINT, THREAD-SAFE, RE-ENTRANT */
        {
            CheckDisposed();

            if (interpreter == null)
            {
                if (errors == null)
                {
                    errors = new ResultList();
                }

                errors.Add("invalid interpreter");
                return(ReturnCode.Error);
            }

            if (text == null)
            {
                if (errors == null)
                {
                    errors = new ResultList();
                }

                errors.Add("invalid block text");
                return(ReturnCode.Error);
            }

            int localLiteralCount    = 0;
            int localBlockCount      = 0;
            int localEvaluateCount   = 0;
            int localSubstituteCount = 0;
            int localVariableCount   = 0;
            int localFailCount       = 0;
            int localErrorCount      = 0;
            int length = text.Length;
            int index  = 0;

            while (index < length)
            {
                int remaining = length - index;

                int openIndex = text.IndexOf(OpenBlock, index, remaining,
                                             StringOps.SystemStringComparisonType);

                int closeIndex = text.IndexOf(CloseBlock, index, remaining,
                                              StringOps.SystemStringComparisonType);

                if (openIndex != Index.Invalid)
                {
                    int literalLength = openIndex - index;

                    if (literalLength > 0)
                    {
                        if (output == null)
                        {
                            output = NewStringBuilder(remaining);
                        }

                        output.Append(text, index, literalLength);
                        localLiteralCount++;
                    }

                    int savedOpenIndex = openIndex;

                    openIndex += OpenLength;

                    closeIndex = text.IndexOf(
                        CloseBlock, openIndex, length - openIndex,
                        StringOps.SystemStringComparisonType);

                    if (closeIndex != Index.Invalid)
                    {
                        //
                        // NOTE: We found another block to process.
                        //
                        localBlockCount++;

                        //
                        // NOTE: Evaluate the block we just found and insert
                        //       the resulting text.  If a script error is
                        //       raised, either stop (in strict mode) -OR-
                        //       record it and continue (in non-strict mode).
                        //
                        int blockLength = closeIndex - openIndex;

                        //
                        // NOTE: If the block is "empty" (i.e. it contains no
                        //       characters whatsoever, not even whitespace,
                        //       then skip extracting the script and evaluate
                        //       an empty string.  We evaluate an empty string
                        //       just in case the script engine needs to
                        //       perform some "background" tasks at this point,
                        //       such as the processing of asynchronous events.
                        //
                        bool   isSubstitute;
                        bool   isVariable;
                        string blockText;

                        if (blockLength > 0)
                        {
                            //
                            // HACK: Sneak a peek at the first character of the
                            //       block.
                            //
                            char firstCharacter = text[openIndex];

                            //
                            // HACK: If it is the Tcl comment character (i.e.
                            //       '#'), we need to skip that character when
                            //       extracting the block to actually operate
                            //       on.
                            //
                            isSubstitute = IsSubstituteChar(firstCharacter);

                            int blockIndex = openIndex;

                            if (isSubstitute)
                            {
                                isVariable  = false;
                                blockIndex += 1; blockLength -= 1;
                            }
                            else
                            {
                                isVariable = IsVariableChar(firstCharacter);

                                if (isVariable)
                                {
                                    blockIndex += 1; blockLength -= 1;
                                }
                            }

                            blockText = (blockLength > 0) ?
                                        text.Substring(blockIndex, blockLength) :
                                        String.Empty;
                        }
                        else
                        {
                            isSubstitute = false;
                            isVariable   = false;
                            blockText    = String.Empty;
                        }

                        ReturnCode localCode;
                        Result     localResult    = null;
                        int        localErrorLine = 0;

                        //
                        // HACK: If the *VERY* first character of the block is
                        //       the comment character ("#") or the equal sign
                        //       ("="), then do not evaluate the block; rather,
                        //       just perform any textual substitutions inside
                        //       it -OR- replace it with the variable value.
                        //
                        if (isSubstitute)
                        {
                            //
                            // NOTE: We found another substitution to perform.
                            //
                            localSubstituteCount++;

                            localCode = interpreter.SubstituteString(blockText,
                                                                     ref localResult);
                        }
                        else if (isVariable)
                        {
                            //
                            // NOTE: We found another variable to replace.
                            //
                            localVariableCount++;

                            Result localValue = null;
                            Result localError = null;

                            localCode = interpreter.GetVariableValue(
                                VariableFlags.None, blockText, ref localValue,
                                ref localError);

                            if (localCode == ReturnCode.Ok)
                            {
                                localResult = localValue;
                            }
                            else
                            {
                                localResult = localError;
                            }
                        }
                        else
                        {
                            //
                            // NOTE: We found another evaluation to perform.
                            //
                            localEvaluateCount++;

                            localCode = interpreter.EvaluateScript(blockText,
                                                                   ref localResult, ref localErrorLine);
                        }

                        //
                        // NOTE: Was the block was processed successfully?
                        //
                        if (IsSuccess(
                                localCode, okOrReturnOnly, allowExceptions))
                        {
                            if (output == null)
                            {
                                output = NewStringBuilder(remaining);
                            }

                            if ((localResult != null) &&
                                (localResult.Length > 0))
                            {
                                string formatted = trimSpace ?
                                                   (string)localResult.Trim(WhiteSpaceChars) :
                                                   (string)localResult;

                                output.Append(formatted);
                            }
                        }
                        else
                        {
                            string formatted = ResultOps.Format(
                                localCode, localResult, localErrorLine);

                            if (errors == null)
                            {
                                errors = new ResultList();
                            }

                            errors.Add(String.Format(
                                           "block from absolute index {0} to absolute " +
                                           "index {1} had {2} error: {3}", savedOpenIndex,
                                           closeIndex, isSubstitute ? "substitution" :
                                           "evaluation", formatted));

                            if (emitErrors)
                            {
                                if (output == null)
                                {
                                    output = NewStringBuilder(remaining);
                                }

                                output.AppendFormat(
                                    "{0}{0}BLOCK ERROR: {1}{0}{0}",
                                    Environment.NewLine, formatted);
                            }

                            localErrorCount++;

                            if (stopOnError)
                            {
                                break;
                            }
                        }

                        //
                        // NOTE: The very next thing to process is just after
                        //       the closing block tag.
                        //
                        index = closeIndex + CloseLength;
                    }
                    else
                    {
                        //
                        // NOTE: The open tag has no matching close tag.
                        //
                        if (errors == null)
                        {
                            errors = new ResultList();
                        }

                        Result localError = String.Format(
                            "found opening tag \"{0}\" at absolute index " +
                            "{1} and expected closing tag \"{2}\", which " +
                            "was not found", OpenBlock, savedOpenIndex,
                            CloseBlock);

                        errors.Add(localError);

                        if (emitFailures)
                        {
                            if (output == null)
                            {
                                output = NewStringBuilder(remaining);
                            }

                            output.AppendFormat(
                                "{0}{0}PARSE ERROR: {1}{0}{0}",
                                Environment.NewLine, localError);
                        }

                        localFailCount++;

                        if (stopOnFailure)
                        {
                            break;
                        }

                        //
                        // NOTE: The very next thing to process is just
                        //       after the opening block tag.
                        //
                        index = openIndex + OpenLength;
                    }
                }
                else if (closeIndex != Index.Invalid)
                {
                    //
                    // NOTE: The close tag has no matching open tag.
                    //
                    if (errors == null)
                    {
                        errors = new ResultList();
                    }

                    Result localError = String.Format(
                        "found closing tag \"{0}\" at absolute index " +
                        "{1} and expected opening tag \"{2}\", which " +
                        "was not found", CloseBlock, closeIndex,
                        OpenBlock);

                    errors.Add(localError);

                    if (emitFailures)
                    {
                        if (output == null)
                        {
                            output = NewStringBuilder(remaining);
                        }

                        output.AppendFormat(
                            "{0}{0}PARSE ERROR: {1}{0}{0}",
                            Environment.NewLine, localError);
                    }

                    localFailCount++;

                    if (stopOnFailure)
                    {
                        break;
                    }

                    //
                    // NOTE: The very next thing to process is just
                    //       after the closing block tag.
                    //
                    index = closeIndex + CloseLength;
                }
                else
                {
                    if (output == null)
                    {
                        output = NewStringBuilder(remaining);
                    }

                    output.Append(text, index, remaining);
                    localLiteralCount++;

                    index += remaining;
                }
            }

            literalCount    += localLiteralCount;
            blockCount      += localBlockCount;
            evaluateCount   += localEvaluateCount;
            substituteCount += localSubstituteCount;
            variableCount   += localVariableCount;
            failCount       += localFailCount;
            errorCount      += localErrorCount;

            return((localFailCount == 0) && (localErrorCount == 0) ?
                   ReturnCode.Ok : ReturnCode.Error);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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.NoCase | OptionFlags.MustHaveBooleanValue,
                                       Index.Invalid, Index.Invalid, "-statistics", null),
                            new Option(null, OptionFlags.NoCase | OptionFlags.MustHaveBooleanValue,
                                       Index.Invalid, Index.Invalid, "-breakOk", null),
                            new Option(null, OptionFlags.NoCase | OptionFlags.MustHaveBooleanValue,
                                       Index.Invalid, Index.Invalid, "-errorOk", null),
                            new Option(null, OptionFlags.NoCase | OptionFlags.MustHaveBooleanValue,
                                       Index.Invalid, Index.Invalid, "-noCancel", null),
                            new Option(null, OptionFlags.NoCase | OptionFlags.MustHaveBooleanValue,
                                       Index.Invalid, Index.Invalid, "-noHalt", null),
                            new Option(null, OptionFlags.NoCase | OptionFlags.MustHaveBooleanValue,
                                       Index.Invalid, Index.Invalid, "-noEvent", null),
                            new Option(null, OptionFlags.NoCase | OptionFlags.MustHaveBooleanValue,
                                       Index.Invalid, Index.Invalid, "-noExit", null),
                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid,
                                       Option.EndOfOptions, null)
                        });

                        int argumentIndex = Index.Invalid;

                        if (arguments.Count > 3)
                        {
                            code = interpreter.GetOptions(options, arguments, 0, 3, Index.Invalid, true, ref argumentIndex, ref result);
                        }
                        else
                        {
                            code = ReturnCode.Ok;
                        }

                        if (code == ReturnCode.Ok)
                        {
                            if (argumentIndex == Index.Invalid)
                            {
                                long requestedIterations = 1; /* DEFAULT: One iteration. */

                                if (arguments.Count >= 3)
                                {
                                    if (Value.GetWideInteger2(
                                            (IGetValue)arguments[2], ValueFlags.AnyWideInteger,
                                            interpreter.CultureInfo, ref requestedIterations,
                                            ref result) != ReturnCode.Ok)
                                    {
                                        return(ReturnCode.Error);
                                    }
                                }

                                Variant value      = null;
                                bool    statistics = false;

                                if (options.IsPresent("-statistics", ref value))
                                {
                                    statistics = (bool)value.Value;
                                }

                                bool breakOk = false;

                                if (options.IsPresent("-breakOk", ref value))
                                {
                                    breakOk = (bool)value.Value;
                                }

                                bool errorOk = false;

                                if (options.IsPresent("-errorOk", ref value))
                                {
                                    errorOk = (bool)value.Value;
                                }

                                bool noCancel = false;

                                if (options.IsPresent("-noCancel", ref value))
                                {
                                    noCancel = (bool)value.Value;
                                }

                                bool noHalt = false;

                                if (options.IsPresent("-noHalt", ref value))
                                {
                                    noHalt = (bool)value.Value;
                                }

                                bool noExit = false;

                                if (options.IsPresent("-noExit", ref value))
                                {
                                    noExit = (bool)value.Value;
                                }

                                bool noEvent = false;

                                if (options.IsPresent("-noEvent", ref value))
                                {
                                    noEvent = (bool)value.Value;
                                }

                                //
                                // NOTE: These variables are used to keep track of
                                //       the minimum and maximum performance counts
                                //       for a given iteration (i.e. only when the
                                //       statistics option is enabled).
                                //
                                long?minimumIterationCount = null;
                                long?maximumIterationCount = null;

                                //
                                // NOTE: Always start with the number of iterations
                                //       requested by the caller.  Also, record the
                                //       overall starting performance count now.
                                //
                                long actualIterations    = 0;
                                long remainingIterations = requestedIterations;
                                long startCount          = PerformanceOps.GetCount();

                                //
                                // NOTE: If the requested number of iterations is
                                //       exactly negative one, we will keep going
                                //       forever (i.e. until canceled).
                                //
                                try
                                {
                                    while (true)
                                    {
                                        if (remainingIterations == 0)
                                        {
                                            break;
                                        }

                                        long iterationStartCount = statistics ?
                                                                   PerformanceOps.GetCount() : 0;

                                        code = interpreter.EvaluateScript(arguments[1],
                                                                          ref result);

                                        if (statistics)
                                        {
                                            long iterationStopCount =
                                                PerformanceOps.GetCount();

                                            long iterationCount =
                                                iterationStopCount - iterationStartCount;

                                            if ((minimumIterationCount == null) ||
                                                (iterationCount < minimumIterationCount))
                                            {
                                                minimumIterationCount = iterationCount;
                                            }

                                            if ((maximumIterationCount == null) ||
                                                (iterationCount > maximumIterationCount))
                                            {
                                                maximumIterationCount = iterationCount;
                                            }
                                        }

                                        actualIterations++;

                                        if (code == ReturnCode.Continue)
                                        {
                                            continue;
                                        }

                                        if (code != ReturnCode.Ok)
                                        {
                                            break;
                                        }

                                        if (remainingIterations == Count.Invalid)
                                        {
                                            continue;
                                        }

                                        if (--remainingIterations <= 0)
                                        {
                                            break;
                                        }
                                    }
                                }
                                finally
                                {
                                    if (noCancel)
                                    {
                                        /* IGNORED */
                                        Engine.ResetCancel(interpreter,
                                                           CancelFlags.Time);
                                    }

                                    if (noHalt)
                                    {
                                        /* IGNORED */
                                        Engine.ResetHalt(interpreter,
                                                         CancelFlags.Time);
                                    }

                                    if (noEvent)
                                    {
                                        /* IGNORED */
                                        interpreter.ClearEvents();
                                    }

                                    //
                                    // NOTE: If requested, prevent the interactive loop from
                                    //       actually exiting and reset the exit code to be
                                    //       "success".
                                    //
                                    if (noExit && interpreter.Exit)
                                    {
                                        interpreter.ExitCode = ResultOps.SuccessExitCode();
                                        interpreter.Exit     = false;
                                    }
                                }

                                //
                                // NOTE: Make sure the return code indicates "success".
                                //
                                if ((code == ReturnCode.Ok) || (code == ReturnCode.Break) ||
                                    (errorOk && (code == ReturnCode.Error)))
                                {
                                    //
                                    // NOTE: Record the overall ending performance count
                                    //       now.
                                    //
                                    long stopCount = PerformanceOps.GetCount();

                                    //
                                    // NOTE: Calculate the average number of microseconds
                                    //       per iteration based on the starting and ending
                                    //       performance counts and the effective number of
                                    //       iterations.
                                    //
                                    long resultIterations = PerformanceOps.GetIterations(
                                        requestedIterations, actualIterations, code, breakOk);

                                    double averageMicroseconds = (resultIterations != 0) ?
                                                                 PerformanceOps.GetMicroseconds(startCount, stopCount,
                                                                                                resultIterations) : 0;

                                    if (statistics)
                                    {
                                        result = FormatOps.PerformanceWithStatistics(
                                            requestedIterations, actualIterations,
                                            resultIterations, code,
                                            (code == ReturnCode.Error) ? result : null,
                                            startCount, stopCount, averageMicroseconds,
                                            PerformanceOps.GetMicroseconds(
                                                (minimumIterationCount != null) ?
                                                (long)minimumIterationCount : 0, 1),
                                            PerformanceOps.GetMicroseconds(
                                                (maximumIterationCount != null) ?
                                                (long)maximumIterationCount : 0, 1));
                                    }
                                    else
                                    {
                                        result = FormatOps.Performance(averageMicroseconds);
                                    }

                                    //
                                    // NOTE: If the "errorOk" option was used, make sure an
                                    //       "Error" return code gets translated to "Ok".
                                    //
                                    if (errorOk && (code == ReturnCode.Error))
                                    {
                                        Engine.ResetCancel(interpreter,
                                                           CancelFlags.Time);

                                        code = ReturnCode.Ok;
                                    }
                                }
                            }
                            else
                            {
                                result = "wrong # args: should be \"time script ?count? ?options?\"";
                                code   = ReturnCode.Error;
                            }
                        }
                    }
                    else
                    {
                        result = "wrong # args: should be \"time script ?count? ?options?\"";
                        code   = ReturnCode.Error;
                    }
                }
                else
                {
                    result = "invalid argument list";
                    code   = ReturnCode.Error;
                }
            }
            else
            {
                result = "invalid interpreter";
                code   = ReturnCode.Error;
            }

            return(code);
        }
Exemple #5
0
        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);
        }