CommandObjectExpression.cpp revision 258054
190075Sobrien//===-- CommandObjectExpression.cpp -----------------------------*- C++ -*-===// 290075Sobrien// 3132718Skan// The LLVM Compiler Infrastructure 490075Sobrien// 590075Sobrien// This file is distributed under the University of Illinois Open Source 690075Sobrien// License. See LICENSE.TXT for details. 790075Sobrien// 890075Sobrien//===----------------------------------------------------------------------===// 990075Sobrien 1090075Sobrien#include "lldb/lldb-python.h" 1190075Sobrien 1290075Sobrien#include "CommandObjectExpression.h" 1390075Sobrien 1490075Sobrien// C Includes 1590075Sobrien// C++ Includes 1690075Sobrien// Other libraries and framework includes 1790075Sobrien// Project includes 1890075Sobrien#include "lldb/Interpreter/Args.h" 1990075Sobrien#include "lldb/Core/Value.h" 2090075Sobrien#include "lldb/Core/InputReader.h" 2190075Sobrien#include "lldb/Core/ValueObjectVariable.h" 2290075Sobrien#include "lldb/DataFormatters/ValueObjectPrinter.h" 2390075Sobrien#include "lldb/Expression/ClangExpressionVariable.h" 2490075Sobrien#include "lldb/Expression/ClangUserExpression.h" 25132718Skan#include "lldb/Expression/ClangFunction.h" 26132718Skan#include "lldb/Expression/DWARFExpression.h" 2790075Sobrien#include "lldb/Host/Host.h" 28117395Skan#include "lldb/Core/Debugger.h" 2990075Sobrien#include "lldb/Interpreter/CommandInterpreter.h" 3090075Sobrien#include "lldb/Interpreter/CommandReturnObject.h" 3190075Sobrien#include "lldb/Target/ObjCLanguageRuntime.h" 3290075Sobrien#include "lldb/Symbol/ObjectFile.h" 3390075Sobrien#include "lldb/Symbol/Variable.h" 3490075Sobrien#include "lldb/Target/Process.h" 3590075Sobrien#include "lldb/Target/StackFrame.h" 3690075Sobrien#include "lldb/Target/Target.h" 3790075Sobrien#include "lldb/Target/Thread.h" 3890075Sobrien#include "llvm/ADT/StringRef.h" 3990075Sobrien 4090075Sobrienusing namespace lldb; 41132718Skanusing namespace lldb_private; 4290075Sobrien 4390075SobrienCommandObjectExpression::CommandOptions::CommandOptions () : 4490075Sobrien OptionGroup() 4590075Sobrien{ 4690075Sobrien} 4790075Sobrien 4890075Sobrien 4990075SobrienCommandObjectExpression::CommandOptions::~CommandOptions () 5090075Sobrien{ 5190075Sobrien} 52132718Skan 53132718Skanstatic OptionEnumValueElement g_description_verbosity_type[] = 54132718Skan{ 55132718Skan { eLanguageRuntimeDescriptionDisplayVerbosityCompact, "compact", "Only show the description string"}, 56132718Skan { eLanguageRuntimeDescriptionDisplayVerbosityFull, "full", "Show the full output, including persistent variable's name and type"}, 57132718Skan { 0, NULL, NULL } 58132718Skan}; 59132718Skan 60132718SkanOptionDefinition 6190075SobrienCommandObjectExpression::CommandOptions::g_option_table[] = 6290075Sobrien{ 6390075Sobrien { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Should we run all threads if the execution doesn't complete on one thread."}, 6490075Sobrien { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Ignore breakpoint hits while running expressions"}, 65132718Skan { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger, "Timeout value (in microseconds) for running the expression."}, 6690075Sobrien { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error", 'u', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, or raises a signal. Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."}, 67117395Skan { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug", 'g', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "When specified, debug the JIT code by setting a breakpoint on the first instruction and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."}, 6890075Sobrien { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."}, 6990075Sobrien}; 7090075Sobrien 71117395Skan 7290075Sobrienuint32_t 7390075SobrienCommandObjectExpression::CommandOptions::GetNumDefinitions () 7490075Sobrien{ 75132718Skan return sizeof(g_option_table)/sizeof(OptionDefinition); 76132718Skan} 7790075Sobrien 7890075SobrienError 7990075SobrienCommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &interpreter, 8090075Sobrien uint32_t option_idx, 8190075Sobrien const char *option_arg) 8290075Sobrien{ 8390075Sobrien Error error; 8490075Sobrien 8590075Sobrien const int short_option = g_option_table[option_idx].short_option; 8690075Sobrien 8790075Sobrien switch (short_option) 8890075Sobrien { 8990075Sobrien //case 'l': 9096263Sobrien //if (language.SetLanguageFromCString (option_arg) == false) 9196263Sobrien //{ 9290075Sobrien // error.SetErrorStringWithFormat("invalid language option argument '%s'", option_arg); 9396263Sobrien //} 9490075Sobrien //break; 9596263Sobrien 9696263Sobrien case 'a': 9796263Sobrien { 9890075Sobrien bool success; 9996263Sobrien bool result; 10096263Sobrien result = Args::StringToBoolean(option_arg, true, &success); 10190075Sobrien if (!success) 10290075Sobrien error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg); 10390075Sobrien else 10490075Sobrien try_all_threads = result; 10590075Sobrien } 106132718Skan break; 10790075Sobrien 108132718Skan case 'i': 10990075Sobrien { 11090075Sobrien bool success; 111132718Skan bool tmp_value = Args::StringToBoolean(option_arg, true, &success); 112132718Skan if (success) 113132718Skan ignore_breakpoints = tmp_value; 114132718Skan else 115132718Skan error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg); 116132718Skan break; 117132718Skan } 118132718Skan case 't': 119132718Skan { 120132718Skan bool success; 121132718Skan uint32_t result; 122132718Skan result = Args::StringToUInt32(option_arg, 0, 0, &success); 123132718Skan if (success) 124132718Skan timeout = result; 125132718Skan else 126132718Skan error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg); 127132718Skan } 128132718Skan break; 129132718Skan 130132718Skan case 'u': 131132718Skan { 132132718Skan bool success; 13390075Sobrien bool tmp_value = Args::StringToBoolean(option_arg, true, &success); 13490075Sobrien if (success) 135132718Skan unwind_on_error = tmp_value; 136132718Skan else 137132718Skan error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg); 138117395Skan break; 139117395Skan } 140117395Skan 14190075Sobrien case 'v': 14290075Sobrien if (!option_arg) 14390075Sobrien { 14490075Sobrien m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull; 14590075Sobrien break; 14690075Sobrien } 14790075Sobrien m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); 14890075Sobrien if (!error.Success()) 14990075Sobrien error.SetErrorStringWithFormat ("unrecognized value for description-verbosity '%s'", option_arg); 15090075Sobrien break; 15190075Sobrien 15290075Sobrien case 'g': 15390075Sobrien debug = true; 15490075Sobrien unwind_on_error = false; 15590075Sobrien ignore_breakpoints = false; 15690075Sobrien break; 15790075Sobrien 15890075Sobrien default: 15990075Sobrien error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); 16090075Sobrien break; 16190075Sobrien } 16290075Sobrien 16390075Sobrien return error; 164132718Skan} 165132718Skan 16690075Sobrienvoid 16790075SobrienCommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter) 16890075Sobrien{ 16990075Sobrien Process *process = interpreter.GetExecutionContext().GetProcessPtr(); 17090075Sobrien if (process != NULL) 17190075Sobrien { 17290075Sobrien ignore_breakpoints = process->GetIgnoreBreakpointsInExpressions(); 17390075Sobrien unwind_on_error = process->GetUnwindOnErrorInExpressions(); 17490075Sobrien } 17590075Sobrien else 17690075Sobrien { 17790075Sobrien ignore_breakpoints = false; 17890075Sobrien unwind_on_error = true; 179132718Skan } 180132718Skan 18190075Sobrien show_summary = true; 18290075Sobrien try_all_threads = true; 18390075Sobrien timeout = 0; 18490075Sobrien debug = false; 18590075Sobrien m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact; 18690075Sobrien} 18790075Sobrien 18890075Sobrienconst OptionDefinition* 18990075SobrienCommandObjectExpression::CommandOptions::GetDefinitions () 19090075Sobrien{ 19190075Sobrien return g_option_table; 19290075Sobrien} 19390075Sobrien 19490075SobrienCommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) : 19590075Sobrien CommandObjectRaw (interpreter, 19690075Sobrien "expression", 197132718Skan "Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.", 198132718Skan NULL, 19990075Sobrien eFlagProcessMustBePaused | eFlagTryTargetAPILock), 20090075Sobrien m_option_group (interpreter), 20190075Sobrien m_format_options (eFormatDefault), 202132718Skan m_command_options (), 203132718Skan m_expr_line_count (0), 204132718Skan m_expr_lines () 205132718Skan{ 20690075Sobrien SetHelpLong( 207146895Skan"Timeouts:\n\ 208146895Skan If the expression can be evaluated statically (without runnning code) then it will be.\n\ 209132718Skan Otherwise, by default the expression will run on the current thread with a short timeout:\n\ 210132718Skan currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted\n\ 211132718Skan and resumed with all threads running. You can use the -a option to disable retrying on all\n\ 212132718Skan threads. You can use the -t option to set a shorter timeout.\n\ 213132718Skan\n\ 214132718SkanUser defined variables:\n\ 215132718Skan You can define your own variables for convenience or to be used in subsequent expressions.\n\ 216132718Skan You define them the same way you would define variables in C. If the first character of \n\ 217132718Skan your user defined variable is a $, then the variable's value will be available in future\n\ 218132718Skan expressions, otherwise it will just be available in the current expression.\n\ 219132718Skan\n\ 220132718SkanExamples: \n\ 221132718Skan\n\ 222132718Skan expr my_struct->a = my_array[3] \n\ 223132718Skan expr -f bin -- (index * 8) + 5 \n\ 224132718Skan expr unsigned int $foo = 5\n\ 225132718Skan expr char c[] = \"foo\"; c[0]\n"); 226132718Skan 227132718Skan CommandArgumentEntry arg; 228132718Skan CommandArgumentData expression_arg; 229132718Skan 230117395Skan // Define the first (and only) variant of this arg. 231132718Skan expression_arg.arg_type = eArgTypeExpression; 232132718Skan expression_arg.arg_repetition = eArgRepeatPlain; 233117395Skan 234117395Skan // There is only one variant this argument could be; put it into the argument entry. 235117395Skan arg.push_back (expression_arg); 236117395Skan 237132718Skan // Push the data for the first argument into the m_arguments vector. 238132718Skan m_arguments.push_back (arg); 239117395Skan 240117395Skan // Add the "--format" and "--gdb-format" 241132718Skan m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1); 242117395Skan m_option_group.Append (&m_command_options); 243132718Skan m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2); 244132718Skan m_option_group.Finalize(); 245132718Skan} 246132718Skan 247132718SkanCommandObjectExpression::~CommandObjectExpression () 248132718Skan{ 249132718Skan} 250132718Skan 251132718SkanOptions * 252132718SkanCommandObjectExpression::GetOptions () 253132718Skan{ 254132718Skan return &m_option_group; 255132718Skan} 256117395Skan 257117395Skansize_t 258117395SkanCommandObjectExpression::MultiLineExpressionCallback 25990075Sobrien( 26090075Sobrien void *baton, 26190075Sobrien InputReader &reader, 26290075Sobrien lldb::InputReaderAction notification, 26390075Sobrien const char *bytes, 26490075Sobrien size_t bytes_len 26590075Sobrien) 266132718Skan{ 26790075Sobrien CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton; 26890075Sobrien bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); 26990075Sobrien 270132718Skan switch (notification) 271132718Skan { 27290075Sobrien case eInputReaderActivate: 27390075Sobrien if (!batch_mode) 27490075Sobrien { 27590075Sobrien StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream()); 27690075Sobrien if (async_strm_sp) 27790075Sobrien { 27890075Sobrien async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n"); 27990075Sobrien async_strm_sp->Flush(); 28090075Sobrien } 28190075Sobrien } 28290075Sobrien // Fall through 283132718Skan case eInputReaderReactivate: 284132718Skan break; 285132718Skan 286132718Skan case eInputReaderDeactivate: 287132718Skan break; 288132718Skan 28990075Sobrien case eInputReaderAsynchronousOutputWritten: 29090075Sobrien break; 29190075Sobrien 292132718Skan case eInputReaderGotToken: 293132718Skan ++cmd_object_expr->m_expr_line_count; 294132718Skan if (bytes && bytes_len) 295132718Skan { 296132718Skan cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1); 297132718Skan } 29890075Sobrien 299132718Skan if (bytes_len == 0) 300132718Skan reader.SetIsDone(true); 301132718Skan break; 302132718Skan 303132718Skan case eInputReaderInterrupt: 304132718Skan cmd_object_expr->m_expr_lines.clear(); 305132718Skan reader.SetIsDone (true); 306132718Skan if (!batch_mode) 30790075Sobrien { 30890075Sobrien StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream()); 30990075Sobrien if (async_strm_sp) 310132718Skan { 311132718Skan async_strm_sp->PutCString("Expression evaluation cancelled.\n"); 312132718Skan async_strm_sp->Flush(); 313132718Skan } 314132718Skan } 315132718Skan break; 316132718Skan 317132718Skan case eInputReaderEndOfFile: 318132718Skan reader.SetIsDone (true); 319132718Skan break; 32090075Sobrien 32190075Sobrien case eInputReaderDone: 32290075Sobrien if (cmd_object_expr->m_expr_lines.size() > 0) 32390075Sobrien { 32490075Sobrien StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream(); 325132718Skan StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream(); 326132718Skan cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(), 327132718Skan output_stream.get(), 328132718Skan error_stream.get()); 32990075Sobrien output_stream->Flush(); 33090075Sobrien error_stream->Flush(); 331132718Skan } 33290075Sobrien break; 333132718Skan } 33490075Sobrien 335117395Skan return bytes_len; 336117395Skan} 337132718Skan 338132718Skanbool 339132718SkanCommandObjectExpression::EvaluateExpression 340132718Skan( 341132718Skan const char *expr, 342132718Skan Stream *output_stream, 343117395Skan Stream *error_stream, 344117395Skan CommandReturnObject *result 345132718Skan) 346132718Skan{ 34790075Sobrien // Don't use m_exe_ctx as this might be called asynchronously 348117395Skan // after the command object DoExecute has finished when doing 349117395Skan // multi-line expression that use an input reader... 350117395Skan ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 35190075Sobrien 352132718Skan Target *target = exe_ctx.GetTargetPtr(); 353132718Skan 354117395Skan if (!target) 355117395Skan target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get(); 356117395Skan 35790075Sobrien if (target) 358117395Skan { 359117395Skan lldb::ValueObjectSP result_valobj_sp; 36090075Sobrien 361132718Skan ExecutionResults exe_results; 36290075Sobrien 363117395Skan bool keep_in_memory = true; 364132718Skan 36590075Sobrien EvaluateExpressionOptions options; 366117395Skan options.SetCoerceToId(m_varobj_options.use_objc) 36790075Sobrien .SetUnwindOnError(m_command_options.unwind_on_error) 368117395Skan .SetIgnoreBreakpoints (m_command_options.ignore_breakpoints) 36990075Sobrien .SetKeepInMemory(keep_in_memory) 37090075Sobrien .SetUseDynamic(m_varobj_options.use_dynamic) 37190075Sobrien .SetRunOthers(m_command_options.try_all_threads) 37290075Sobrien .SetDebug(m_command_options.debug); 373132718Skan 374132718Skan if (m_command_options.timeout > 0) 37590075Sobrien options.SetTimeoutUsec(m_command_options.timeout); 37690075Sobrien 37790075Sobrien exe_results = target->EvaluateExpression (expr, 37890075Sobrien exe_ctx.GetFramePtr(), 379117395Skan result_valobj_sp, 380117395Skan options); 381117395Skan 382117395Skan if (result_valobj_sp) 383117395Skan { 384117395Skan Format format = m_format_options.GetFormat(); 385117395Skan 386117395Skan if (result_valobj_sp->GetError().Success()) 387117395Skan { 388117395Skan if (format != eFormatVoid) 389117395Skan { 390117395Skan if (format != eFormatDefault) 391117395Skan result_valobj_sp->SetFormat (format); 392117395Skan 393117395Skan DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(m_command_options.m_verbosity,format)); 394117395Skan 395117395Skan result_valobj_sp->Dump(*output_stream,options); 396117395Skan 397117395Skan if (result) 398117395Skan result->SetStatus (eReturnStatusSuccessFinishResult); 399117395Skan } 400117395Skan } 401117395Skan else 402117395Skan { 403117395Skan if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult) 404117395Skan { 405117395Skan if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid()) 406117395Skan { 407117395Skan error_stream->PutCString("(void)\n"); 408117395Skan } 409117395Skan 410117395Skan if (result) 411117395Skan result->SetStatus (eReturnStatusSuccessFinishResult); 412117395Skan } 413117395Skan else 414117395Skan { 415117395Skan const char *error_cstr = result_valobj_sp->GetError().AsCString(); 416132718Skan if (error_cstr && error_cstr[0]) 417132718Skan { 418117395Skan const size_t error_cstr_len = strlen (error_cstr); 419132718Skan const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n'; 420132718Skan if (strstr(error_cstr, "error:") != error_cstr) 421132718Skan error_stream->PutCString ("error: "); 422132718Skan error_stream->Write(error_cstr, error_cstr_len); 423132718Skan if (!ends_with_newline) 424132718Skan error_stream->EOL(); 425132718Skan } 426132718Skan else 427132718Skan { 428132718Skan error_stream->PutCString ("error: unknown error\n"); 429132718Skan } 430132718Skan 431132718Skan if (result) 432132718Skan result->SetStatus (eReturnStatusFailed); 433132718Skan } 434132718Skan } 435132718Skan } 436132718Skan } 437132718Skan else 438132718Skan { 439132718Skan error_stream->Printf ("error: invalid execution context for expression\n"); 440132718Skan return false; 441132718Skan } 442132718Skan 443132718Skan return true; 44490075Sobrien} 44590075Sobrien 44690075Sobrienbool 44790075SobrienCommandObjectExpression::DoExecute 44890075Sobrien( 44990075Sobrien const char *command, 45090075Sobrien CommandReturnObject &result 45190075Sobrien) 45290075Sobrien{ 45390075Sobrien m_option_group.NotifyOptionParsingStarting(); 45490075Sobrien 45590075Sobrien const char * expr = NULL; 45690075Sobrien 45790075Sobrien if (command[0] == '\0') 45890075Sobrien { 45990075Sobrien m_expr_lines.clear(); 46090075Sobrien m_expr_line_count = 0; 46190075Sobrien 46290075Sobrien InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 46390075Sobrien if (reader_sp) 46490075Sobrien { 46590075Sobrien Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback, 46690075Sobrien this, // baton 46790075Sobrien eInputReaderGranularityLine, // token size, to pass to callback function 46890075Sobrien NULL, // end token 46990075Sobrien NULL, // prompt 47090075Sobrien true)); // echo input 47190075Sobrien if (err.Success()) 47290075Sobrien { 47390075Sobrien m_interpreter.GetDebugger().PushInputReader (reader_sp); 47490075Sobrien result.SetStatus (eReturnStatusSuccessFinishNoResult); 47590075Sobrien } 47690075Sobrien else 47790075Sobrien { 47890075Sobrien result.AppendError (err.AsCString()); 47990075Sobrien result.SetStatus (eReturnStatusFailed); 48090075Sobrien } 48190075Sobrien } 48290075Sobrien else 48390075Sobrien { 48490075Sobrien result.AppendError("out of memory"); 48590075Sobrien result.SetStatus (eReturnStatusFailed); 48690075Sobrien } 48790075Sobrien return result.Succeeded(); 48890075Sobrien } 48990075Sobrien 49090075Sobrien if (command[0] == '-') 49190075Sobrien { 49290075Sobrien // We have some options and these options MUST end with --. 49390075Sobrien const char *end_options = NULL; 49490075Sobrien const char *s = command; 49590075Sobrien while (s && s[0]) 49690075Sobrien { 49790075Sobrien end_options = ::strstr (s, "--"); 49890075Sobrien if (end_options) 49990075Sobrien { 50090075Sobrien end_options += 2; // Get past the "--" 50190075Sobrien if (::isspace (end_options[0])) 50290075Sobrien { 50390075Sobrien expr = end_options; 50490075Sobrien while (::isspace (*expr)) 50590075Sobrien ++expr; 50690075Sobrien break; 50790075Sobrien } 50890075Sobrien } 50990075Sobrien s = end_options; 51090075Sobrien } 51190075Sobrien 51290075Sobrien if (end_options) 51390075Sobrien { 51490075Sobrien Args args (command, end_options - command); 51590075Sobrien if (!ParseOptions (args, result)) 51690075Sobrien return false; 51790075Sobrien 51890075Sobrien Error error (m_option_group.NotifyOptionParsingFinished()); 519132718Skan if (error.Fail()) 520132718Skan { 521132718Skan result.AppendError (error.AsCString()); 522132718Skan result.SetStatus (eReturnStatusFailed); 523132718Skan return false; 524132718Skan } 525132718Skan } 526132718Skan } 527132718Skan 528132718Skan if (expr == NULL) 529132718Skan expr = command; 530132718Skan 531132718Skan if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result)) 532132718Skan return true; 533132718Skan 534132718Skan result.SetStatus (eReturnStatusFailed); 535132718Skan return false; 536132718Skan} 537132718Skan 538132718Skan