blob: 2ffee58fbc22fdc2f48753525a114554e20db9b3 [file] [log] [blame]
Jim Inghamebc09c32010-07-07 03:36:20 +00001//===-- CommandObjectSource.cpp ---------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Jim Inghamebc09c32010-07-07 03:36:20 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
Greg Clayton0e5e5a72011-04-20 22:55:21 +000013#include "llvm/ADT/StringRef.h"
14
Jim Inghamebc09c32010-07-07 03:36:20 +000015// Project includes
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +000016#include "CommandObjectCommands.h"
Enrico Granata46d4aa22016-02-29 23:22:53 +000017#include "CommandObjectHelp.h"
Jim Inghamebc09c32010-07-07 03:36:20 +000018#include "lldb/Core/Debugger.h"
Greg Clayton44d93782014-01-27 23:43:24 +000019#include "lldb/Core/IOHandler.h"
Enrico Granatabe93a352011-08-16 16:49:25 +000020#include "lldb/Core/StringList.h"
Greg Claytonde164aa2011-04-20 16:37:46 +000021#include "lldb/Interpreter/Args.h"
Enrico Granata7594f142013-06-17 22:51:50 +000022#include "lldb/Interpreter/CommandHistory.h"
Jim Inghamebc09c32010-07-07 03:36:20 +000023#include "lldb/Interpreter/CommandInterpreter.h"
Greg Claytonde164aa2011-04-20 16:37:46 +000024#include "lldb/Interpreter/CommandObjectRegexCommand.h"
Jim Inghamebc09c32010-07-07 03:36:20 +000025#include "lldb/Interpreter/CommandReturnObject.h"
Enrico Granata012d4fc2013-06-11 01:26:35 +000026#include "lldb/Interpreter/OptionValueBoolean.h"
Enrico Granata45d0e232016-03-31 01:10:54 +000027#include "lldb/Interpreter/OptionValueString.h"
Enrico Granata7594f142013-06-17 22:51:50 +000028#include "lldb/Interpreter/OptionValueUInt64.h"
Jim Inghamebc09c32010-07-07 03:36:20 +000029#include "lldb/Interpreter/Options.h"
Enrico Granata99f0b8f2011-08-17 01:30:04 +000030#include "lldb/Interpreter/ScriptInterpreter.h"
Jim Inghamebc09c32010-07-07 03:36:20 +000031
32using namespace lldb;
33using namespace lldb_private;
34
Jim Inghamebc09c32010-07-07 03:36:20 +000035//-------------------------------------------------------------------------
36// CommandObjectCommandsSource
37//-------------------------------------------------------------------------
38
Jim Ingham5a988412012-06-08 21:56:10 +000039class CommandObjectCommandsHistory : public CommandObjectParsed
Jim Inghama5a97eb2011-07-12 03:12:18 +000040{
Jim Ingham5a988412012-06-08 21:56:10 +000041public:
42 CommandObjectCommandsHistory(CommandInterpreter &interpreter) :
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +000043 CommandObjectParsed(interpreter,
44 "command history",
45 "Dump the history of commands in this session.",
46 nullptr),
Todd Fialae1cfbc72016-08-11 23:51:28 +000047 m_options()
Jim Ingham5a988412012-06-08 21:56:10 +000048 {
49 }
50
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +000051 ~CommandObjectCommandsHistory() override = default;
Jim Ingham5a988412012-06-08 21:56:10 +000052
Bruce Mitchener13d21e92015-10-07 16:56:17 +000053 Options *
54 GetOptions () override
Jim Ingham5a988412012-06-08 21:56:10 +000055 {
56 return &m_options;
57 }
58
59protected:
Jim Inghama5a97eb2011-07-12 03:12:18 +000060 class CommandOptions : public Options
61 {
62 public:
Todd Fialae1cfbc72016-08-11 23:51:28 +000063 CommandOptions() :
64 Options(),
Enrico Granata7594f142013-06-17 22:51:50 +000065 m_start_idx(0),
66 m_stop_idx(0),
67 m_count(0),
Enrico Granata63123b62013-06-17 23:28:27 +000068 m_clear(false)
Jim Inghama5a97eb2011-07-12 03:12:18 +000069 {
70 }
71
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +000072 ~CommandOptions() override = default;
Jim Inghama5a97eb2011-07-12 03:12:18 +000073
Bruce Mitchener13d21e92015-10-07 16:56:17 +000074 Error
Todd Fialae1cfbc72016-08-11 23:51:28 +000075 SetOptionValue (uint32_t option_idx, const char *option_arg,
76 ExecutionContext *execution_context) override
Jim Inghama5a97eb2011-07-12 03:12:18 +000077 {
78 Error error;
Greg Clayton3bcdfc02012-12-04 00:32:51 +000079 const int short_option = m_getopt_table[option_idx].val;
Jim Inghama5a97eb2011-07-12 03:12:18 +000080
81 switch (short_option)
82 {
83 case 'c':
Pavel Labathc95f7e22015-02-20 11:14:59 +000084 error = m_count.SetValueFromString(option_arg,eVarSetOperationAssign);
Jim Inghama5a97eb2011-07-12 03:12:18 +000085 break;
86 case 's':
Enrico Granata7594f142013-06-17 22:51:50 +000087 if (option_arg && strcmp("end", option_arg) == 0)
88 {
89 m_start_idx.SetCurrentValue(UINT64_MAX);
90 m_start_idx.SetOptionWasSet();
91 }
92 else
Pavel Labathc95f7e22015-02-20 11:14:59 +000093 error = m_start_idx.SetValueFromString(option_arg,eVarSetOperationAssign);
Enrico Granata7594f142013-06-17 22:51:50 +000094 break;
95 case 'e':
Pavel Labathc95f7e22015-02-20 11:14:59 +000096 error = m_stop_idx.SetValueFromString(option_arg,eVarSetOperationAssign);
Enrico Granata7594f142013-06-17 22:51:50 +000097 break;
Enrico Granata63123b62013-06-17 23:28:27 +000098 case 'C':
99 m_clear.SetCurrentValue(true);
100 m_clear.SetOptionWasSet();
Jim Inghama5a97eb2011-07-12 03:12:18 +0000101 break;
102 default:
Greg Clayton86edbf42011-10-26 00:56:27 +0000103 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
Jim Inghama5a97eb2011-07-12 03:12:18 +0000104 break;
105 }
106
107 return error;
108 }
109
110 void
Todd Fialae1cfbc72016-08-11 23:51:28 +0000111 OptionParsingStarting (ExecutionContext *execution_context) override
Jim Inghama5a97eb2011-07-12 03:12:18 +0000112 {
Enrico Granata7594f142013-06-17 22:51:50 +0000113 m_start_idx.Clear();
114 m_stop_idx.Clear();
115 m_count.Clear();
Enrico Granata63123b62013-06-17 23:28:27 +0000116 m_clear.Clear();
Jim Inghama5a97eb2011-07-12 03:12:18 +0000117 }
118
119 const OptionDefinition*
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000120 GetDefinitions () override
Jim Inghama5a97eb2011-07-12 03:12:18 +0000121 {
122 return g_option_table;
123 }
124
125 // Options table: Required for subclasses of Options.
126
127 static OptionDefinition g_option_table[];
128
129 // Instance variables to hold the values for command options.
130
Enrico Granata7594f142013-06-17 22:51:50 +0000131 OptionValueUInt64 m_start_idx;
132 OptionValueUInt64 m_stop_idx;
133 OptionValueUInt64 m_count;
Enrico Granata63123b62013-06-17 23:28:27 +0000134 OptionValueBoolean m_clear;
Jim Inghama5a97eb2011-07-12 03:12:18 +0000135 };
136
Jim Inghama5a97eb2011-07-12 03:12:18 +0000137 bool
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000138 DoExecute (Args& command, CommandReturnObject &result) override
Jim Inghama5a97eb2011-07-12 03:12:18 +0000139 {
Enrico Granata63123b62013-06-17 23:28:27 +0000140 if (m_options.m_clear.GetCurrentValue() && m_options.m_clear.OptionWasSet())
Enrico Granata7594f142013-06-17 22:51:50 +0000141 {
142 m_interpreter.GetCommandHistory().Clear();
143 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
144 }
145 else
146 {
147 if (m_options.m_start_idx.OptionWasSet() && m_options.m_stop_idx.OptionWasSet() && m_options.m_count.OptionWasSet())
148 {
149 result.AppendError("--count, --start-index and --end-index cannot be all specified in the same invocation");
150 result.SetStatus(lldb::eReturnStatusFailed);
151 }
152 else
153 {
Virgile Bello84400ec2013-08-27 16:22:29 +0000154 std::pair<bool,uint64_t> start_idx(m_options.m_start_idx.OptionWasSet(),m_options.m_start_idx.GetCurrentValue());
155 std::pair<bool,uint64_t> stop_idx(m_options.m_stop_idx.OptionWasSet(),m_options.m_stop_idx.GetCurrentValue());
156 std::pair<bool,uint64_t> count(m_options.m_count.OptionWasSet(),m_options.m_count.GetCurrentValue());
Enrico Granata7594f142013-06-17 22:51:50 +0000157
158 const CommandHistory& history(m_interpreter.GetCommandHistory());
159
160 if (start_idx.first && start_idx.second == UINT64_MAX)
161 {
162 if (count.first)
163 {
164 start_idx.second = history.GetSize() - count.second;
165 stop_idx.second = history.GetSize() - 1;
166 }
167 else if (stop_idx.first)
168 {
169 start_idx.second = stop_idx.second;
170 stop_idx.second = history.GetSize() - 1;
171 }
172 else
173 {
174 start_idx.second = 0;
175 stop_idx.second = history.GetSize() - 1;
176 }
177 }
178 else
179 {
180 if (!start_idx.first && !stop_idx.first && !count.first)
181 {
182 start_idx.second = 0;
183 stop_idx.second = history.GetSize() - 1;
184 }
185 else if (start_idx.first)
186 {
187 if (count.first)
188 {
189 stop_idx.second = start_idx.second + count.second - 1;
190 }
191 else if (!stop_idx.first)
192 {
193 stop_idx.second = history.GetSize() - 1;
194 }
195 }
196 else if (stop_idx.first)
197 {
198 if (count.first)
199 {
200 if (stop_idx.second >= count.second)
201 start_idx.second = stop_idx.second - count.second + 1;
202 else
203 start_idx.second = 0;
204 }
205 }
206 else /* if (count.first) */
207 {
208 start_idx.second = 0;
209 stop_idx.second = count.second - 1;
210 }
211 }
212 history.Dump(result.GetOutputStream(), start_idx.second, stop_idx.second);
213 }
214 }
Jim Inghama5a97eb2011-07-12 03:12:18 +0000215 return result.Succeeded();
216
217 }
Jim Ingham5a988412012-06-08 21:56:10 +0000218
219 CommandOptions m_options;
Jim Inghama5a97eb2011-07-12 03:12:18 +0000220};
221
222OptionDefinition
223CommandObjectCommandsHistory::CommandOptions::g_option_table[] =
224{
Kate Stoneac9c3a62016-08-26 23:28:47 +0000225 // clang-format off
226 {LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "How many history commands to print."},
227 {LLDB_OPT_SET_1, false, "start-index", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)."},
228 {LLDB_OPT_SET_1, false, "end-index", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands."},
229 {LLDB_OPT_SET_2, false, "clear", 'C', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Clears the current command history."},
230 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
231 // clang-format on
Jim Inghama5a97eb2011-07-12 03:12:18 +0000232};
233
Jim Inghama5a97eb2011-07-12 03:12:18 +0000234//-------------------------------------------------------------------------
235// CommandObjectCommandsSource
236//-------------------------------------------------------------------------
237
Jim Ingham5a988412012-06-08 21:56:10 +0000238class CommandObjectCommandsSource : public CommandObjectParsed
Jim Inghamebc09c32010-07-07 03:36:20 +0000239{
Jim Ingham5a988412012-06-08 21:56:10 +0000240public:
Kate Stone7428a182016-07-14 22:03:10 +0000241 CommandObjectCommandsSource(CommandInterpreter &interpreter)
242 : CommandObjectParsed(interpreter, "command source", "Read and execute LLDB commands from the file <filename>.",
243 nullptr),
Todd Fialae1cfbc72016-08-11 23:51:28 +0000244 m_options()
Jim Ingham5a988412012-06-08 21:56:10 +0000245 {
246 CommandArgumentEntry arg;
247 CommandArgumentData file_arg;
248
249 // Define the first (and only) variant of this arg.
250 file_arg.arg_type = eArgTypeFilename;
251 file_arg.arg_repetition = eArgRepeatPlain;
252
253 // There is only one variant this argument could be; put it into the argument entry.
254 arg.push_back (file_arg);
255
256 // Push the data for the first argument into the m_arguments vector.
257 m_arguments.push_back (arg);
258 }
259
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000260 ~CommandObjectCommandsSource() override = default;
Jim Ingham5a988412012-06-08 21:56:10 +0000261
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000262 const char*
263 GetRepeatCommand (Args &current_command_args, uint32_t index) override
Jim Ingham5a988412012-06-08 21:56:10 +0000264 {
265 return "";
266 }
267
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000268 int
Jim Ingham5a988412012-06-08 21:56:10 +0000269 HandleArgumentCompletion (Args &input,
270 int &cursor_index,
271 int &cursor_char_position,
272 OptionElementVector &opt_element_vector,
273 int match_start_point,
274 int max_return_elements,
275 bool &word_complete,
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000276 StringList &matches) override
Jim Ingham5a988412012-06-08 21:56:10 +0000277 {
278 std::string completion_str (input.GetArgumentAtIndex(cursor_index));
279 completion_str.erase (cursor_char_position);
Todd Fialae1cfbc72016-08-11 23:51:28 +0000280
281 CommandCompletions::InvokeCommonCompletionCallbacks(GetCommandInterpreter(),
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000282 CommandCompletions::eDiskFileCompletion,
283 completion_str.c_str(),
284 match_start_point,
285 max_return_elements,
286 nullptr,
287 word_complete,
288 matches);
Jim Ingham5a988412012-06-08 21:56:10 +0000289 return matches.GetSize();
290 }
291
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000292 Options *
293 GetOptions () override
Jim Ingham5a988412012-06-08 21:56:10 +0000294 {
295 return &m_options;
296 }
297
298protected:
Jim Inghame16c50a2011-02-18 00:54:25 +0000299 class CommandOptions : public Options
300 {
301 public:
Todd Fialae1cfbc72016-08-11 23:51:28 +0000302 CommandOptions() :
303 Options(),
Greg Clayton340b0302014-02-05 17:57:57 +0000304 m_stop_on_error (true),
305 m_silent_run (false),
306 m_stop_on_continue (true)
Greg Claytoneb0103f2011-04-07 22:46:35 +0000307 {
308 }
Jim Inghame16c50a2011-02-18 00:54:25 +0000309
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000310 ~CommandOptions() override = default;
Jim Inghame16c50a2011-02-18 00:54:25 +0000311
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000312 Error
Todd Fialae1cfbc72016-08-11 23:51:28 +0000313 SetOptionValue (uint32_t option_idx, const char *option_arg,
314 ExecutionContext *execution_context) override
Jim Inghame16c50a2011-02-18 00:54:25 +0000315 {
316 Error error;
Greg Clayton3bcdfc02012-12-04 00:32:51 +0000317 const int short_option = m_getopt_table[option_idx].val;
Jim Inghame16c50a2011-02-18 00:54:25 +0000318
319 switch (short_option)
320 {
321 case 'e':
Pavel Labathc95f7e22015-02-20 11:14:59 +0000322 error = m_stop_on_error.SetValueFromString(option_arg);
Jim Inghame16c50a2011-02-18 00:54:25 +0000323 break;
Greg Clayton340b0302014-02-05 17:57:57 +0000324
Jim Inghame16c50a2011-02-18 00:54:25 +0000325 case 'c':
Pavel Labathc95f7e22015-02-20 11:14:59 +0000326 error = m_stop_on_continue.SetValueFromString(option_arg);
Jim Inghame16c50a2011-02-18 00:54:25 +0000327 break;
Greg Clayton340b0302014-02-05 17:57:57 +0000328
Michael Sartain60986172013-07-09 23:22:53 +0000329 case 's':
Pavel Labathc95f7e22015-02-20 11:14:59 +0000330 error = m_silent_run.SetValueFromString(option_arg);
Michael Sartain60986172013-07-09 23:22:53 +0000331 break;
Greg Clayton340b0302014-02-05 17:57:57 +0000332
Jim Inghame16c50a2011-02-18 00:54:25 +0000333 default:
Greg Clayton86edbf42011-10-26 00:56:27 +0000334 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
Jim Inghame16c50a2011-02-18 00:54:25 +0000335 break;
336 }
337
338 return error;
339 }
340
341 void
Todd Fialae1cfbc72016-08-11 23:51:28 +0000342 OptionParsingStarting (ExecutionContext *execution_context) override
Jim Inghame16c50a2011-02-18 00:54:25 +0000343 {
Enrico Granata012d4fc2013-06-11 01:26:35 +0000344 m_stop_on_error.Clear();
Greg Clayton340b0302014-02-05 17:57:57 +0000345 m_silent_run.Clear();
346 m_stop_on_continue.Clear();
Jim Inghame16c50a2011-02-18 00:54:25 +0000347 }
348
Greg Claytone0d378b2011-03-24 21:19:54 +0000349 const OptionDefinition*
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000350 GetDefinitions () override
Jim Inghame16c50a2011-02-18 00:54:25 +0000351 {
352 return g_option_table;
353 }
354
355 // Options table: Required for subclasses of Options.
356
Greg Claytone0d378b2011-03-24 21:19:54 +0000357 static OptionDefinition g_option_table[];
Jim Inghame16c50a2011-02-18 00:54:25 +0000358
359 // Instance variables to hold the values for command options.
360
Enrico Granata012d4fc2013-06-11 01:26:35 +0000361 OptionValueBoolean m_stop_on_error;
Jim Ingham7d8555c2014-11-18 19:12:13 +0000362 OptionValueBoolean m_silent_run;
Greg Clayton340b0302014-02-05 17:57:57 +0000363 OptionValueBoolean m_stop_on_continue;
Jim Inghame16c50a2011-02-18 00:54:25 +0000364 };
365
Jim Inghamebc09c32010-07-07 03:36:20 +0000366 bool
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000367 DoExecute(Args& command, CommandReturnObject &result) override
Jim Inghamebc09c32010-07-07 03:36:20 +0000368 {
Greg Claytonc7bece562013-01-25 18:06:21 +0000369 const size_t argc = command.GetArgumentCount();
Jim Inghamebc09c32010-07-07 03:36:20 +0000370 if (argc == 1)
371 {
Jim Ingham5a988412012-06-08 21:56:10 +0000372 const char *filename = command.GetArgumentAtIndex(0);
Jim Inghamebc09c32010-07-07 03:36:20 +0000373
Johnny Chen1ee38532010-10-20 21:40:50 +0000374 FileSpec cmd_file (filename, true);
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000375 ExecutionContext *exe_ctx = nullptr; // Just use the default context.
Greg Clayton340b0302014-02-05 17:57:57 +0000376
377 // If any options were set, then use them
378 if (m_options.m_stop_on_error.OptionWasSet() ||
379 m_options.m_silent_run.OptionWasSet() ||
380 m_options.m_stop_on_continue.OptionWasSet())
381 {
382 // Use user set settings
Jim Ingham26c7bf92014-10-11 00:38:27 +0000383 CommandInterpreterRunOptions options;
384 options.SetStopOnContinue(m_options.m_stop_on_continue.GetCurrentValue());
385 options.SetStopOnError (m_options.m_stop_on_error.GetCurrentValue());
Jim Ingham7d8555c2014-11-18 19:12:13 +0000386 options.SetEchoCommands (!m_options.m_silent_run.GetCurrentValue());
387 options.SetPrintResults (!m_options.m_silent_run.GetCurrentValue());
Jim Ingham26c7bf92014-10-11 00:38:27 +0000388
Greg Clayton340b0302014-02-05 17:57:57 +0000389 m_interpreter.HandleCommandsFromFile (cmd_file,
390 exe_ctx,
Jim Ingham26c7bf92014-10-11 00:38:27 +0000391 options,
Greg Clayton340b0302014-02-05 17:57:57 +0000392 result);
Greg Clayton340b0302014-02-05 17:57:57 +0000393 }
394 else
395 {
396 // No options were set, inherit any settings from nested "command source" commands,
397 // or set to sane default settings...
Jim Ingham26c7bf92014-10-11 00:38:27 +0000398 CommandInterpreterRunOptions options;
Greg Clayton340b0302014-02-05 17:57:57 +0000399 m_interpreter.HandleCommandsFromFile (cmd_file,
400 exe_ctx,
Jim Ingham26c7bf92014-10-11 00:38:27 +0000401 options,
Greg Clayton340b0302014-02-05 17:57:57 +0000402 result);
Greg Clayton340b0302014-02-05 17:57:57 +0000403 }
Jim Inghamebc09c32010-07-07 03:36:20 +0000404 }
405 else
406 {
407 result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName());
408 result.SetStatus (eReturnStatusFailed);
409 }
410 return result.Succeeded();
Jim Inghamebc09c32010-07-07 03:36:20 +0000411 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000412
Jim Ingham5a988412012-06-08 21:56:10 +0000413 CommandOptions m_options;
Jim Inghamebc09c32010-07-07 03:36:20 +0000414};
415
Greg Claytone0d378b2011-03-24 21:19:54 +0000416OptionDefinition
Jim Inghame16c50a2011-02-18 00:54:25 +0000417CommandObjectCommandsSource::CommandOptions::g_option_table[] =
418{
Kate Stoneac9c3a62016-08-26 23:28:47 +0000419 // clang-format off
420 {LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on error."},
421 {LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true, stop executing commands on continue."},
422 {LLDB_OPT_SET_ALL, false, "silent-run", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "If true don't echo commands while executing."},
423 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
424 // clang-format on
Jim Inghame16c50a2011-02-18 00:54:25 +0000425};
426
Jim Inghamebc09c32010-07-07 03:36:20 +0000427#pragma mark CommandObjectCommandsAlias
428//-------------------------------------------------------------------------
429// CommandObjectCommandsAlias
430//-------------------------------------------------------------------------
431
Enrico Granatabe93a352011-08-16 16:49:25 +0000432static const char *g_python_command_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
433 "You must define a Python function with this signature:\n"
Greg Clayton44d93782014-01-27 23:43:24 +0000434 "def my_command_impl(debugger, args, result, internal_dict):\n";
Enrico Granatabe93a352011-08-16 16:49:25 +0000435
Jim Ingham5a988412012-06-08 21:56:10 +0000436class CommandObjectCommandsAlias : public CommandObjectRaw
Jim Inghamebc09c32010-07-07 03:36:20 +0000437{
Enrico Granata45d0e232016-03-31 01:10:54 +0000438protected:
439 class CommandOptions : public OptionGroup
440 {
441 public:
442 CommandOptions () :
443 OptionGroup(),
444 m_help(),
445 m_long_help()
446 {}
447
448 ~CommandOptions() override = default;
449
450 uint32_t
451 GetNumDefinitions () override
452 {
453 return 3;
454 }
455
456 const OptionDefinition*
457 GetDefinitions () override
458 {
459 return g_option_table;
460 }
461
462 Error
Todd Fialae1cfbc72016-08-11 23:51:28 +0000463 SetOptionValue (uint32_t option_idx,
464 const char *option_value,
465 ExecutionContext *execution_context) override
Enrico Granata45d0e232016-03-31 01:10:54 +0000466 {
467 Error error;
468
469 const int short_option = g_option_table[option_idx].short_option;
470
471 switch (short_option)
472 {
473 case 'h':
474 m_help.SetCurrentValue(option_value);
475 m_help.SetOptionWasSet();
476 break;
477
478 case 'H':
479 m_long_help.SetCurrentValue(option_value);
480 m_long_help.SetOptionWasSet();
481 break;
482
483 default:
484 error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
485 break;
486 }
487
488 return error;
489 }
490
491 void
Todd Fialae1cfbc72016-08-11 23:51:28 +0000492 OptionParsingStarting (ExecutionContext *execution_context) override
Enrico Granata45d0e232016-03-31 01:10:54 +0000493 {
494 m_help.Clear();
495 m_long_help.Clear();
496 }
497
498 // Options table: Required for subclasses of Options.
499
500 static OptionDefinition g_option_table[];
501 OptionValueString m_help;
502 OptionValueString m_long_help;
503 };
504
505 OptionGroupOptions m_option_group;
506 CommandOptions m_command_options;
507
Jim Inghamebc09c32010-07-07 03:36:20 +0000508public:
Enrico Granata45d0e232016-03-31 01:10:54 +0000509 Options *
510 GetOptions () override
511 {
512 return &m_option_group;
513 }
514
Kate Stone7428a182016-07-14 22:03:10 +0000515 CommandObjectCommandsAlias(CommandInterpreter &interpreter)
516 : CommandObjectRaw(interpreter, "command alias", "Define a custom command in terms of an existing command.",
517 nullptr),
Todd Fialae1cfbc72016-08-11 23:51:28 +0000518 m_option_group(),
Kate Stone7428a182016-07-14 22:03:10 +0000519 m_command_options()
Jim Inghamebc09c32010-07-07 03:36:20 +0000520 {
Enrico Granata45d0e232016-03-31 01:10:54 +0000521 m_option_group.Append(&m_command_options);
522 m_option_group.Finalize();
523
Jim Inghamebc09c32010-07-07 03:36:20 +0000524 SetHelpLong(
Kate Stoneea671fb2015-07-14 05:48:36 +0000525"'alias' allows the user to create a short-cut or abbreviation for long \
526commands, multi-word commands, and commands that take particular options. \
527Below are some simple examples of how one might use the 'alias' command:" R"(
528
529(lldb) command alias sc script
530
531 Creates the abbreviation 'sc' for the 'script' command.
532
533(lldb) command alias bp breakpoint
534
535)" " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \
536breakpoint commands are two-word commands, the user would still need to \
537enter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." R"(
538
539(lldb) command alias bpl breakpoint list
540
541 Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'.
542
543)" "An alias can include some options for the command, with the values either \
544filled in at the time the alias is created, or specified as positional \
545arguments, to be filled in when the alias is invoked. The following example \
546shows how to create aliases with options:" R"(
547
548(lldb) command alias bfl breakpoint set -f %1 -l %2
549
550)" " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \
551options already part of the alias. So if the user wants to set a breakpoint \
552by file and line without explicitly having to use the -f and -l options, the \
553user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \
554for the actual arguments that will be passed when the alias command is used. \
555The number in the placeholder refers to the position/order the actual value \
556occupies when the alias is used. All the occurrences of '%1' in the alias \
557will be replaced with the first argument, all the occurrences of '%2' in the \
558alias will be replaced with the second argument, and so on. This also allows \
559actual arguments to be used multiple times within an alias (see 'process \
560launch' example below)." R"(
561
562)" "Note: the positional arguments must substitute as whole words in the resultant \
563command, so you can't at present do something like this to append the file extension \
564\".cpp\":" R"(
565
566(lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2
567
568)" "For more complex aliasing, use the \"command regex\" command instead. In the \
569'bfl' case above, the actual file value will be filled in with the first argument \
570following 'bfl' and the actual line number value will be filled in with the second \
571argument. The user would use this alias as follows:" R"(
572
573(lldb) command alias bfl breakpoint set -f %1 -l %2
574(lldb) bfl my-file.c 137
575
576This would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'.
577
578Another example:
579
580(lldb) command alias pltty process launch -s -o %1 -e %1
581(lldb) pltty /dev/tty0
582
583 Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0'
584
585)" "If the user always wanted to pass the same value to a particular option, the \
586alias could be defined with that value directly in the alias as a constant, \
587rather than using a positional placeholder:" R"(
588
589(lldb) command alias bl3 breakpoint set -f %1 -l 3
590
591 Always sets a breakpoint on line 3 of whatever file is indicated.)"
592 );
Jim Inghamebc09c32010-07-07 03:36:20 +0000593
Caroline Tice405fe672010-10-04 22:28:36 +0000594 CommandArgumentEntry arg1;
595 CommandArgumentEntry arg2;
596 CommandArgumentEntry arg3;
597 CommandArgumentData alias_arg;
598 CommandArgumentData cmd_arg;
599 CommandArgumentData options_arg;
600
601 // Define the first (and only) variant of this arg.
602 alias_arg.arg_type = eArgTypeAliasName;
603 alias_arg.arg_repetition = eArgRepeatPlain;
604
605 // There is only one variant this argument could be; put it into the argument entry.
606 arg1.push_back (alias_arg);
607
608 // Define the first (and only) variant of this arg.
609 cmd_arg.arg_type = eArgTypeCommandName;
610 cmd_arg.arg_repetition = eArgRepeatPlain;
611
612 // There is only one variant this argument could be; put it into the argument entry.
613 arg2.push_back (cmd_arg);
614
615 // Define the first (and only) variant of this arg.
616 options_arg.arg_type = eArgTypeAliasOptions;
617 options_arg.arg_repetition = eArgRepeatOptional;
618
619 // There is only one variant this argument could be; put it into the argument entry.
620 arg3.push_back (options_arg);
621
622 // Push the data for the first argument into the m_arguments vector.
623 m_arguments.push_back (arg1);
624 m_arguments.push_back (arg2);
625 m_arguments.push_back (arg3);
Jim Inghamebc09c32010-07-07 03:36:20 +0000626 }
627
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000628 ~CommandObjectCommandsAlias() override = default;
Jim Inghamebc09c32010-07-07 03:36:20 +0000629
Jim Ingham5a988412012-06-08 21:56:10 +0000630protected:
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000631 bool
632 DoExecute (const char *raw_command_line, CommandReturnObject &result) override
Caroline Tice844d2302010-12-09 22:52:49 +0000633 {
Enrico Granata45d0e232016-03-31 01:10:54 +0000634 if (!raw_command_line || !raw_command_line[0])
635 {
Enrico Granatad72e4122016-04-08 17:56:57 +0000636 result.AppendError ("'command alias' requires at least two arguments");
Enrico Granata45d0e232016-03-31 01:10:54 +0000637 return false;
638 }
Todd Fialae1cfbc72016-08-11 23:51:28 +0000639
640 ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
641 m_option_group.NotifyOptionParsingStarting(&exe_ctx);
Enrico Granata45d0e232016-03-31 01:10:54 +0000642
643 const char * remainder = nullptr;
644
645 if (raw_command_line[0] == '-')
646 {
647 // We have some options and these options MUST end with --.
648 const char *end_options = nullptr;
649 const char *s = raw_command_line;
650 while (s && s[0])
651 {
652 end_options = ::strstr (s, "--");
653 if (end_options)
654 {
655 end_options += 2; // Get past the "--"
656 if (::isspace (end_options[0]))
657 {
658 remainder = end_options;
659 while (::isspace (*remainder))
660 ++remainder;
661 break;
662 }
663 }
664 s = end_options;
665 }
666
667 if (end_options)
668 {
669 Args args (llvm::StringRef(raw_command_line, end_options - raw_command_line));
670 if (!ParseOptions (args, result))
671 return false;
672
Todd Fialae1cfbc72016-08-11 23:51:28 +0000673 Error error (m_option_group.NotifyOptionParsingFinished(&exe_ctx));
Enrico Granata45d0e232016-03-31 01:10:54 +0000674 if (error.Fail())
675 {
676 result.AppendError (error.AsCString());
677 result.SetStatus (eReturnStatusFailed);
678 return false;
679 }
680 }
681 }
682 if (nullptr == remainder)
683 remainder = raw_command_line;
684
685 std::string raw_command_string (remainder);
686 Args args (raw_command_string.c_str());
Caroline Tice844d2302010-12-09 22:52:49 +0000687
688 size_t argc = args.GetArgumentCount();
689
690 if (argc < 2)
691 {
Enrico Granatad72e4122016-04-08 17:56:57 +0000692 result.AppendError ("'command alias' requires at least two arguments");
Caroline Tice844d2302010-12-09 22:52:49 +0000693 result.SetStatus (eReturnStatusFailed);
694 return false;
695 }
696
697 // Get the alias command.
698
699 const std::string alias_command = args.GetArgumentAtIndex (0);
Enrico Granatad72e4122016-04-08 17:56:57 +0000700 if (alias_command.size() > 1 &&
701 alias_command[0] == '-')
702 {
703 result.AppendError("aliases starting with a dash are not supported");
704 if (alias_command == "--help" || alias_command == "--long-help")
705 {
706 result.AppendWarning("if trying to pass options to 'command alias' add a -- at the end of the options");
707 }
708 result.SetStatus (eReturnStatusFailed);
709 return false;
710 }
Enrico Granatabe93a352011-08-16 16:49:25 +0000711
Caroline Tice844d2302010-12-09 22:52:49 +0000712 // Strip the new alias name off 'raw_command_string' (leave it on args, which gets passed to 'Execute', which
713 // does the stripping itself.
714 size_t pos = raw_command_string.find (alias_command);
715 if (pos == 0)
716 {
717 raw_command_string = raw_command_string.substr (alias_command.size());
718 pos = raw_command_string.find_first_not_of (' ');
719 if ((pos != std::string::npos) && (pos > 0))
720 raw_command_string = raw_command_string.substr (pos);
721 }
722 else
723 {
724 result.AppendError ("Error parsing command string. No alias created.");
725 result.SetStatus (eReturnStatusFailed);
726 return false;
727 }
728
729
730 // Verify that the command is alias-able.
731 if (m_interpreter.CommandExists (alias_command.c_str()))
732 {
733 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
734 alias_command.c_str());
735 result.SetStatus (eReturnStatusFailed);
736 return false;
737 }
738
739 // Get CommandObject that is being aliased. The command name is read from the front of raw_command_string.
740 // raw_command_string is returned with the name of the command object stripped off the front.
Enrico Granatad72e4122016-04-08 17:56:57 +0000741 std::string original_raw_command_string(raw_command_string);
Caroline Tice844d2302010-12-09 22:52:49 +0000742 CommandObject *cmd_obj = m_interpreter.GetCommandObjectForCommand (raw_command_string);
743
744 if (!cmd_obj)
745 {
Enrico Granatad72e4122016-04-08 17:56:57 +0000746 result.AppendErrorWithFormat ("invalid command given to 'command alias'. '%s' does not begin with a valid command."
747 " No alias created.", original_raw_command_string.c_str());
Caroline Tice844d2302010-12-09 22:52:49 +0000748 result.SetStatus (eReturnStatusFailed);
749 return false;
750 }
751 else if (!cmd_obj->WantsRawCommandString ())
752 {
753 // Note that args was initialized with the original command, and has not been updated to this point.
754 // Therefore can we pass it to the version of Execute that does not need/expect raw input in the alias.
Jim Ingham5a988412012-06-08 21:56:10 +0000755 return HandleAliasingNormalCommand (args, result);
Caroline Tice844d2302010-12-09 22:52:49 +0000756 }
757 else
758 {
Jim Ingham5a988412012-06-08 21:56:10 +0000759 return HandleAliasingRawCommand (alias_command, raw_command_string, *cmd_obj, result);
760 }
761 return result.Succeeded();
762 }
763
764 bool
765 HandleAliasingRawCommand (const std::string &alias_command, std::string &raw_command_string, CommandObject &cmd_obj, CommandReturnObject &result)
766 {
Caroline Tice844d2302010-12-09 22:52:49 +0000767 // Verify & handle any options/arguments passed to the alias command
768
769 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
Enrico Granata5e550302016-03-08 03:00:27 +0000770
Enrico Granata212130a2016-03-08 05:37:15 +0000771 if (CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj.GetCommandName(), false))
772 {
773 if (m_interpreter.AliasExists (alias_command.c_str())
774 || m_interpreter.UserCommandExists (alias_command.c_str()))
775 {
776 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
777 alias_command.c_str());
778 }
Enrico Granata45d0e232016-03-31 01:10:54 +0000779 if (CommandAlias *alias = m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp, raw_command_string.c_str()))
Enrico Granata212130a2016-03-08 05:37:15 +0000780 {
Enrico Granata45d0e232016-03-31 01:10:54 +0000781 if (m_command_options.m_help.OptionWasSet())
782 alias->SetHelp(m_command_options.m_help.GetCurrentValue());
783 if (m_command_options.m_long_help.OptionWasSet())
784 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
Enrico Granata212130a2016-03-08 05:37:15 +0000785 result.SetStatus (eReturnStatusSuccessFinishNoResult);
786 }
787 else
788 {
789 result.AppendError ("Unable to create requested alias.\n");
790 result.SetStatus (eReturnStatusFailed);
791 }
Caroline Ticeca90c472011-05-06 21:37:15 +0000792
Caroline Tice472362e2010-12-14 18:51:39 +0000793 }
794 else
795 {
796 result.AppendError ("Unable to create requested alias.\n");
797 result.SetStatus (eReturnStatusFailed);
798 }
Enrico Granata212130a2016-03-08 05:37:15 +0000799
Jim Ingham5a988412012-06-08 21:56:10 +0000800 return result.Succeeded ();
Caroline Tice844d2302010-12-09 22:52:49 +0000801 }
Jim Ingham5a988412012-06-08 21:56:10 +0000802
Jim Inghamebc09c32010-07-07 03:36:20 +0000803 bool
Jim Ingham5a988412012-06-08 21:56:10 +0000804 HandleAliasingNormalCommand (Args& args, CommandReturnObject &result)
Jim Inghamebc09c32010-07-07 03:36:20 +0000805 {
Caroline Tice867b185d2010-09-21 23:25:40 +0000806 size_t argc = args.GetArgumentCount();
Jim Inghamebc09c32010-07-07 03:36:20 +0000807
808 if (argc < 2)
Greg Claytonc982c762010-07-09 20:39:50 +0000809 {
Enrico Granatad72e4122016-04-08 17:56:57 +0000810 result.AppendError ("'command alias' requires at least two arguments");
Jim Inghamebc09c32010-07-07 03:36:20 +0000811 result.SetStatus (eReturnStatusFailed);
812 return false;
Greg Claytonc982c762010-07-09 20:39:50 +0000813 }
Jim Inghamebc09c32010-07-07 03:36:20 +0000814
815 const std::string alias_command = args.GetArgumentAtIndex(0);
816 const std::string actual_command = args.GetArgumentAtIndex(1);
817
818 args.Shift(); // Shift the alias command word off the argument vector.
819 args.Shift(); // Shift the old command word off the argument vector.
820
821 // Verify that the command is alias'able, and get the appropriate command object.
822
Greg Claytona7015092010-09-18 01:14:36 +0000823 if (m_interpreter.CommandExists (alias_command.c_str()))
Jim Inghamebc09c32010-07-07 03:36:20 +0000824 {
825 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
826 alias_command.c_str());
827 result.SetStatus (eReturnStatusFailed);
828 }
829 else
830 {
Greg Claytona7015092010-09-18 01:14:36 +0000831 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true));
Jim Inghamebc09c32010-07-07 03:36:20 +0000832 CommandObjectSP subcommand_obj_sp;
833 bool use_subcommand = false;
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000834 if (command_obj_sp)
Jim Inghamebc09c32010-07-07 03:36:20 +0000835 {
836 CommandObject *cmd_obj = command_obj_sp.get();
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000837 CommandObject *sub_cmd_obj = nullptr;
Jim Inghamebc09c32010-07-07 03:36:20 +0000838 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
Jim Inghamebc09c32010-07-07 03:36:20 +0000839
Caroline Tice844d2302010-12-09 22:52:49 +0000840 while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0)
Jim Inghamebc09c32010-07-07 03:36:20 +0000841 {
842 if (argc >= 3)
843 {
844 const std::string sub_command = args.GetArgumentAtIndex(0);
845 assert (sub_command.length() != 0);
Greg Clayton998255b2012-10-13 02:07:45 +0000846 subcommand_obj_sp = cmd_obj->GetSubcommandSP (sub_command.c_str());
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000847 if (subcommand_obj_sp)
Jim Inghamebc09c32010-07-07 03:36:20 +0000848 {
849 sub_cmd_obj = subcommand_obj_sp.get();
850 use_subcommand = true;
851 args.Shift(); // Shift the sub_command word off the argument vector.
Caroline Tice844d2302010-12-09 22:52:49 +0000852 cmd_obj = sub_cmd_obj;
Jim Inghamebc09c32010-07-07 03:36:20 +0000853 }
854 else
855 {
Caroline Ticef415eeb2010-11-02 19:00:04 +0000856 result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'. "
857 "Unable to create alias.\n",
858 sub_command.c_str(), actual_command.c_str());
Jim Inghamebc09c32010-07-07 03:36:20 +0000859 result.SetStatus (eReturnStatusFailed);
860 return false;
861 }
862 }
863 }
864
865 // Verify & handle any options/arguments passed to the alias command
866
Enrico Granata212130a2016-03-08 05:37:15 +0000867 std::string args_string;
868
Jim Inghamebc09c32010-07-07 03:36:20 +0000869 if (args.GetArgumentCount () > 0)
870 {
Caroline Ticeca90c472011-05-06 21:37:15 +0000871 CommandObjectSP tmp_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false);
872 if (use_subcommand)
873 tmp_sp = m_interpreter.GetCommandSPExact (sub_cmd_obj->GetCommandName(), false);
874
Caroline Ticeca90c472011-05-06 21:37:15 +0000875 args.GetCommandString (args_string);
Jim Inghamebc09c32010-07-07 03:36:20 +0000876 }
Enrico Granata212130a2016-03-08 05:37:15 +0000877
Greg Claytona7015092010-09-18 01:14:36 +0000878 if (m_interpreter.AliasExists (alias_command.c_str())
879 || m_interpreter.UserCommandExists (alias_command.c_str()))
Jim Inghamebc09c32010-07-07 03:36:20 +0000880 {
Enrico Granata212130a2016-03-08 05:37:15 +0000881 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
Jim Inghamebc09c32010-07-07 03:36:20 +0000882 alias_command.c_str());
883 }
Enrico Granata212130a2016-03-08 05:37:15 +0000884
Enrico Granata45d0e232016-03-31 01:10:54 +0000885 if (CommandAlias *alias = m_interpreter.AddAlias(alias_command.c_str(),
886 use_subcommand ? subcommand_obj_sp : command_obj_sp,
887 args_string.c_str()))
Enrico Granata212130a2016-03-08 05:37:15 +0000888 {
Enrico Granata45d0e232016-03-31 01:10:54 +0000889 if (m_command_options.m_help.OptionWasSet())
890 alias->SetHelp(m_command_options.m_help.GetCurrentValue());
891 if (m_command_options.m_long_help.OptionWasSet())
892 alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue());
Enrico Granata212130a2016-03-08 05:37:15 +0000893 result.SetStatus (eReturnStatusSuccessFinishNoResult);
894 }
Jim Inghamebc09c32010-07-07 03:36:20 +0000895 else
Enrico Granata212130a2016-03-08 05:37:15 +0000896 {
897 result.AppendError ("Unable to create requested alias.\n");
898 result.SetStatus (eReturnStatusFailed);
899 return false;
900 }
Jim Inghamebc09c32010-07-07 03:36:20 +0000901 }
902 else
903 {
904 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str());
905 result.SetStatus (eReturnStatusFailed);
Caroline Ticee7941792010-10-28 23:17:48 +0000906 return false;
Jim Inghamebc09c32010-07-07 03:36:20 +0000907 }
908 }
909
910 return result.Succeeded();
911 }
912};
913
Enrico Granata45d0e232016-03-31 01:10:54 +0000914OptionDefinition
915CommandObjectCommandsAlias::CommandOptions::g_option_table[] =
916{
Kate Stoneac9c3a62016-08-26 23:28:47 +0000917 // clang-format off
918 {LLDB_OPT_SET_ALL, false, "help", 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Help text for this command"},
919 {LLDB_OPT_SET_ALL, false, "long-help", 'H', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "Long help text for this command"},
920 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
921 // clang-format on
Enrico Granata45d0e232016-03-31 01:10:54 +0000922};
923
Jim Inghamebc09c32010-07-07 03:36:20 +0000924#pragma mark CommandObjectCommandsUnalias
925//-------------------------------------------------------------------------
926// CommandObjectCommandsUnalias
927//-------------------------------------------------------------------------
928
Jim Ingham5a988412012-06-08 21:56:10 +0000929class CommandObjectCommandsUnalias : public CommandObjectParsed
Jim Inghamebc09c32010-07-07 03:36:20 +0000930{
931public:
Kate Stone7428a182016-07-14 22:03:10 +0000932 CommandObjectCommandsUnalias(CommandInterpreter &interpreter)
933 : CommandObjectParsed(interpreter, "command unalias",
934 "Delete one or more custom commands defined by 'command alias'.", nullptr)
Jim Inghamebc09c32010-07-07 03:36:20 +0000935 {
Caroline Tice405fe672010-10-04 22:28:36 +0000936 CommandArgumentEntry arg;
937 CommandArgumentData alias_arg;
938
939 // Define the first (and only) variant of this arg.
940 alias_arg.arg_type = eArgTypeAliasName;
941 alias_arg.arg_repetition = eArgRepeatPlain;
942
943 // There is only one variant this argument could be; put it into the argument entry.
944 arg.push_back (alias_arg);
945
946 // Push the data for the first argument into the m_arguments vector.
947 m_arguments.push_back (arg);
Jim Inghamebc09c32010-07-07 03:36:20 +0000948 }
949
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000950 ~CommandObjectCommandsUnalias() override = default;
Jim Inghamebc09c32010-07-07 03:36:20 +0000951
Jim Ingham5a988412012-06-08 21:56:10 +0000952protected:
Jim Inghamebc09c32010-07-07 03:36:20 +0000953 bool
Bruce Mitchener13d21e92015-10-07 16:56:17 +0000954 DoExecute (Args& args, CommandReturnObject &result) override
Jim Inghamebc09c32010-07-07 03:36:20 +0000955 {
956 CommandObject::CommandMap::iterator pos;
957 CommandObject *cmd_obj;
958
959 if (args.GetArgumentCount() != 0)
960 {
961 const char *command_name = args.GetArgumentAtIndex(0);
Greg Claytona7015092010-09-18 01:14:36 +0000962 cmd_obj = m_interpreter.GetCommandObject(command_name);
Jim Inghamebc09c32010-07-07 03:36:20 +0000963 if (cmd_obj)
964 {
Greg Claytona7015092010-09-18 01:14:36 +0000965 if (m_interpreter.CommandExists (command_name))
Jim Inghamebc09c32010-07-07 03:36:20 +0000966 {
Greg Claytonb5472782015-01-09 19:08:20 +0000967 if (cmd_obj->IsRemovable())
968 {
969 result.AppendErrorWithFormat ("'%s' is not an alias, it is a debugger command which can be removed using the 'command delete' command.\n",
970 command_name);
971 }
972 else
973 {
974 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
975 command_name);
976 }
Jim Inghamebc09c32010-07-07 03:36:20 +0000977 result.SetStatus (eReturnStatusFailed);
978 }
979 else
980 {
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +0000981 if (!m_interpreter.RemoveAlias(command_name))
Jim Inghamebc09c32010-07-07 03:36:20 +0000982 {
Greg Claytona7015092010-09-18 01:14:36 +0000983 if (m_interpreter.AliasExists (command_name))
Jim Inghamebc09c32010-07-07 03:36:20 +0000984 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n",
985 command_name);
986 else
987 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name);
988 result.SetStatus (eReturnStatusFailed);
989 }
990 else
991 result.SetStatus (eReturnStatusSuccessFinishNoResult);
992 }
993 }
994 else
995 {
996 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a "
997 "current list of commands.\n",
998 command_name);
999 result.SetStatus (eReturnStatusFailed);
1000 }
1001 }
1002 else
1003 {
1004 result.AppendError ("must call 'unalias' with a valid alias");
1005 result.SetStatus (eReturnStatusFailed);
1006 }
1007
1008 return result.Succeeded();
1009 }
1010};
1011
Greg Claytonb5472782015-01-09 19:08:20 +00001012#pragma mark CommandObjectCommandsDelete
1013//-------------------------------------------------------------------------
1014// CommandObjectCommandsDelete
1015//-------------------------------------------------------------------------
1016
1017class CommandObjectCommandsDelete : public CommandObjectParsed
1018{
1019public:
Kate Stone7428a182016-07-14 22:03:10 +00001020 CommandObjectCommandsDelete(CommandInterpreter &interpreter)
1021 : CommandObjectParsed(interpreter, "command delete",
1022 "Delete one or more custom commands defined by 'command regex'.", nullptr)
Greg Claytonb5472782015-01-09 19:08:20 +00001023 {
1024 CommandArgumentEntry arg;
1025 CommandArgumentData alias_arg;
1026
1027 // Define the first (and only) variant of this arg.
1028 alias_arg.arg_type = eArgTypeCommandName;
1029 alias_arg.arg_repetition = eArgRepeatPlain;
1030
1031 // There is only one variant this argument could be; put it into the argument entry.
1032 arg.push_back (alias_arg);
1033
1034 // Push the data for the first argument into the m_arguments vector.
1035 m_arguments.push_back (arg);
1036 }
1037
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001038 ~CommandObjectCommandsDelete() override = default;
Greg Claytonb5472782015-01-09 19:08:20 +00001039
1040protected:
1041 bool
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001042 DoExecute (Args& args, CommandReturnObject &result) override
Greg Claytonb5472782015-01-09 19:08:20 +00001043 {
1044 CommandObject::CommandMap::iterator pos;
1045
1046 if (args.GetArgumentCount() != 0)
1047 {
1048 const char *command_name = args.GetArgumentAtIndex(0);
1049 if (m_interpreter.CommandExists (command_name))
1050 {
1051 if (m_interpreter.RemoveCommand (command_name))
1052 {
1053 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1054 }
1055 else
1056 {
1057 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
1058 command_name);
1059 result.SetStatus (eReturnStatusFailed);
1060 }
1061 }
1062 else
1063 {
Enrico Granata46d4aa22016-02-29 23:22:53 +00001064 StreamString error_msg_stream;
1065 const bool generate_apropos = true;
1066 const bool generate_type_lookup = false;
1067 CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage(&error_msg_stream,
1068 command_name,
1069 nullptr,
1070 nullptr,
1071 generate_apropos,
1072 generate_type_lookup);
1073 result.AppendErrorWithFormat ("%s", error_msg_stream.GetData());
Greg Claytonb5472782015-01-09 19:08:20 +00001074 result.SetStatus (eReturnStatusFailed);
1075 }
1076 }
1077 else
1078 {
Kate Stone7428a182016-07-14 22:03:10 +00001079 result.AppendErrorWithFormat(
1080 "must call '%s' with one or more valid user defined regular expression command names",
1081 GetCommandName());
Greg Claytonb5472782015-01-09 19:08:20 +00001082 result.SetStatus (eReturnStatusFailed);
1083 }
1084
1085 return result.Succeeded();
1086 }
1087};
1088
Greg Claytonde164aa2011-04-20 16:37:46 +00001089//-------------------------------------------------------------------------
1090// CommandObjectCommandsAddRegex
1091//-------------------------------------------------------------------------
Jim Ingham5a988412012-06-08 21:56:10 +00001092#pragma mark CommandObjectCommandsAddRegex
Greg Claytonde164aa2011-04-20 16:37:46 +00001093
Greg Clayton44d93782014-01-27 23:43:24 +00001094class CommandObjectCommandsAddRegex :
1095 public CommandObjectParsed,
Greg Claytonea508632014-11-18 00:43:17 +00001096 public IOHandlerDelegateMultiline
Greg Claytonde164aa2011-04-20 16:37:46 +00001097{
1098public:
Kate Stone7428a182016-07-14 22:03:10 +00001099 CommandObjectCommandsAddRegex(CommandInterpreter &interpreter)
1100 : CommandObjectParsed(interpreter, "command regex",
1101 "Define a custom command in terms of existing commands by matching regular expressions.",
1102 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
1103 IOHandlerDelegateMultiline("", IOHandlerDelegate::Completion::LLDBCommand),
Todd Fialae1cfbc72016-08-11 23:51:28 +00001104 m_options()
Greg Claytonde164aa2011-04-20 16:37:46 +00001105 {
Kate Stoneea671fb2015-07-14 05:48:36 +00001106 SetHelpLong(R"(
1107)" "This command allows the user to create powerful regular expression commands \
1108with substitutions. The regular expressions and substitutions are specified \
1109using the regular expression substitution format of:" R"(
1110
1111 s/<regex>/<subst>/
1112
1113)" "<regex> is a regular expression that can use parenthesis to capture regular \
1114expression input and substitute the captured matches in the output using %1 \
1115for the first match, %2 for the second, and so on." R"(
1116
1117)" "The regular expressions can all be specified on the command line if more than \
1118one argument is provided. If just the command name is provided on the command \
1119line, then the regular expressions and substitutions can be entered on separate \
1120lines, followed by an empty line to terminate the command definition." R"(
1121
1122EXAMPLES
1123
1124)" "The following example will define a regular expression command named 'f' that \
1125will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \
1126a number follows 'f':" R"(
1127
1128 (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"
1129 );
Greg Claytonde164aa2011-04-20 16:37:46 +00001130 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001131
1132 ~CommandObjectCommandsAddRegex() override = default;
1133
Jim Ingham5a988412012-06-08 21:56:10 +00001134protected:
Greg Claytonea508632014-11-18 00:43:17 +00001135 void
1136 IOHandlerActivated (IOHandler &io_handler) override
Greg Clayton44d93782014-01-27 23:43:24 +00001137 {
1138 StreamFileSP output_sp(io_handler.GetOutputStreamFile());
1139 if (output_sp)
1140 {
1141 output_sp->PutCString("Enter one of more sed substitution commands in the form: 's/<regex>/<subst>/'.\nTerminate the substitution list with an empty line.\n");
1142 output_sp->Flush();
1143 }
1144 }
1145
Greg Claytonea508632014-11-18 00:43:17 +00001146 void
1147 IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override
Greg Clayton44d93782014-01-27 23:43:24 +00001148 {
1149 io_handler.SetIsDone(true);
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001150 if (m_regex_cmd_ap)
Greg Clayton44d93782014-01-27 23:43:24 +00001151 {
1152 StringList lines;
1153 if (lines.SplitIntoLines (data))
1154 {
1155 const size_t num_lines = lines.GetSize();
1156 bool check_only = false;
1157 for (size_t i=0; i<num_lines; ++i)
1158 {
Greg Clayton44d93782014-01-27 23:43:24 +00001159 llvm::StringRef bytes_strref (lines[i]);
1160 Error error = AppendRegexSubstitution (bytes_strref, check_only);
1161 if (error.Fail())
1162 {
1163 if (!m_interpreter.GetDebugger().GetCommandInterpreter().GetBatchCommandMode())
1164 {
1165 StreamSP out_stream = m_interpreter.GetDebugger().GetAsyncOutputStream();
1166 out_stream->Printf("error: %s\n", error.AsCString());
1167 }
1168 }
1169 }
1170 }
1171 if (m_regex_cmd_ap->HasRegexEntries())
1172 {
1173 CommandObjectSP cmd_sp (m_regex_cmd_ap.release());
1174 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1175 }
1176 }
1177 }
Greg Clayton44d93782014-01-27 23:43:24 +00001178
Greg Claytonde164aa2011-04-20 16:37:46 +00001179 bool
Eric Christopherb0a18142014-11-18 22:40:27 +00001180 DoExecute (Args& command, CommandReturnObject &result) override
Greg Claytonde164aa2011-04-20 16:37:46 +00001181 {
Jim Ingham5a988412012-06-08 21:56:10 +00001182 const size_t argc = command.GetArgumentCount();
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001183 if (argc == 0)
Greg Claytonde164aa2011-04-20 16:37:46 +00001184 {
Jason Molenda69c12cc2011-11-10 22:43:35 +00001185 result.AppendError ("usage: 'command regex <command-name> [s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001186 result.SetStatus (eReturnStatusFailed);
1187 }
1188 else
1189 {
1190 Error error;
Jim Ingham5a988412012-06-08 21:56:10 +00001191 const char *name = command.GetArgumentAtIndex(0);
Greg Claytonde164aa2011-04-20 16:37:46 +00001192 m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter,
1193 name,
1194 m_options.GetHelp (),
1195 m_options.GetSyntax (),
Greg Claytonb5472782015-01-09 19:08:20 +00001196 10,
1197 0,
1198 true));
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001199
1200 if (argc == 1)
Greg Claytonde164aa2011-04-20 16:37:46 +00001201 {
Greg Clayton44d93782014-01-27 23:43:24 +00001202 Debugger &debugger = m_interpreter.GetDebugger();
Kate Stonee30f11d2014-11-17 19:06:59 +00001203 bool color_prompt = debugger.GetUseColor();
Greg Clayton44d93782014-01-27 23:43:24 +00001204 const bool multiple_lines = true; // Get multiple lines
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001205 IOHandlerSP io_handler_sp(new IOHandlerEditline(debugger,
1206 IOHandler::Type::Other,
1207 "lldb-regex", // Name of input reader for history
1208 "> ", // Prompt
1209 nullptr, // Continuation prompt
1210 multiple_lines,
1211 color_prompt,
1212 0, // Don't show line numbers
1213 *this));
Greg Clayton44d93782014-01-27 23:43:24 +00001214
1215 if (io_handler_sp)
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001216 {
Greg Clayton44d93782014-01-27 23:43:24 +00001217 debugger.PushIOHandler(io_handler_sp);
1218 result.SetStatus (eReturnStatusSuccessFinishNoResult);
Greg Claytonde164aa2011-04-20 16:37:46 +00001219 }
1220 }
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001221 else
1222 {
1223 for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx)
1224 {
Jim Ingham5a988412012-06-08 21:56:10 +00001225 llvm::StringRef arg_strref (command.GetArgumentAtIndex(arg_idx));
Greg Clayton44d93782014-01-27 23:43:24 +00001226 bool check_only = false;
1227 error = AppendRegexSubstitution (arg_strref, check_only);
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001228 if (error.Fail())
1229 break;
1230 }
1231
1232 if (error.Success())
1233 {
1234 AddRegexCommandToInterpreter();
1235 }
1236 }
1237 if (error.Fail())
1238 {
1239 result.AppendError (error.AsCString());
1240 result.SetStatus (eReturnStatusFailed);
1241 }
Greg Claytonde164aa2011-04-20 16:37:46 +00001242 }
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001243
Greg Claytonde164aa2011-04-20 16:37:46 +00001244 return result.Succeeded();
1245 }
1246
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001247 Error
Greg Clayton44d93782014-01-27 23:43:24 +00001248 AppendRegexSubstitution (const llvm::StringRef &regex_sed, bool check_only)
Greg Claytonde164aa2011-04-20 16:37:46 +00001249 {
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001250 Error error;
1251
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001252 if (!m_regex_cmd_ap)
Greg Claytonde164aa2011-04-20 16:37:46 +00001253 {
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001254 error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'",
1255 (int)regex_sed.size(),
1256 regex_sed.data());
1257 return error;
Greg Claytonde164aa2011-04-20 16:37:46 +00001258 }
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001259
1260 size_t regex_sed_size = regex_sed.size();
1261
1262 if (regex_sed_size <= 1)
1263 {
1264 error.SetErrorStringWithFormat("regular expression substitution string is too short: '%.*s'",
1265 (int)regex_sed.size(),
1266 regex_sed.data());
1267 return error;
1268 }
1269
1270 if (regex_sed[0] != 's')
1271 {
1272 error.SetErrorStringWithFormat("regular expression substitution string doesn't start with 's': '%.*s'",
1273 (int)regex_sed.size(),
1274 regex_sed.data());
1275 return error;
1276 }
1277 const size_t first_separator_char_pos = 1;
1278 // use the char that follows 's' as the regex separator character
1279 // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
1280 const char separator_char = regex_sed[first_separator_char_pos];
1281 const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1);
1282
1283 if (second_separator_char_pos == std::string::npos)
1284 {
Greg Claytonea508632014-11-18 00:43:17 +00001285 error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s' in '%.*s'",
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001286 separator_char,
1287 (int)(regex_sed.size() - first_separator_char_pos - 1),
Greg Claytonea508632014-11-18 00:43:17 +00001288 regex_sed.data() + (first_separator_char_pos + 1),
1289 (int)regex_sed.size(),
1290 regex_sed.data());
1291 return error;
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001292 }
1293
1294 const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1);
1295
1296 if (third_separator_char_pos == std::string::npos)
1297 {
Greg Claytonea508632014-11-18 00:43:17 +00001298 error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s' in '%.*s'",
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001299 separator_char,
1300 (int)(regex_sed.size() - second_separator_char_pos - 1),
Greg Claytonea508632014-11-18 00:43:17 +00001301 regex_sed.data() + (second_separator_char_pos + 1),
1302 (int)regex_sed.size(),
1303 regex_sed.data());
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001304 return error;
1305 }
1306
1307 if (third_separator_char_pos != regex_sed_size - 1)
1308 {
1309 // Make sure that everything that follows the last regex
1310 // separator char
1311 if (regex_sed.find_first_not_of("\t\n\v\f\r ", third_separator_char_pos + 1) != std::string::npos)
1312 {
1313 error.SetErrorStringWithFormat("extra data found after the '%.*s' regular expression substitution string: '%.*s'",
1314 (int)third_separator_char_pos + 1,
1315 regex_sed.data(),
1316 (int)(regex_sed.size() - third_separator_char_pos - 1),
1317 regex_sed.data() + (third_separator_char_pos + 1));
1318 return error;
1319 }
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001320 }
1321 else if (first_separator_char_pos + 1 == second_separator_char_pos)
1322 {
1323 error.SetErrorStringWithFormat("<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
1324 separator_char,
1325 separator_char,
1326 separator_char,
1327 (int)regex_sed.size(),
1328 regex_sed.data());
1329 return error;
1330 }
1331 else if (second_separator_char_pos + 1 == third_separator_char_pos)
1332 {
1333 error.SetErrorStringWithFormat("<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
1334 separator_char,
1335 separator_char,
1336 separator_char,
1337 (int)regex_sed.size(),
1338 regex_sed.data());
1339 return error;
1340 }
Greg Clayton44d93782014-01-27 23:43:24 +00001341
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001342 if (!check_only)
Greg Clayton44d93782014-01-27 23:43:24 +00001343 {
1344 std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1));
1345 std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1));
1346 m_regex_cmd_ap->AddRegexCommand (regex.c_str(),
1347 subst.c_str());
1348 }
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001349 return error;
Greg Claytonde164aa2011-04-20 16:37:46 +00001350 }
1351
1352 void
Greg Clayton0e5e5a72011-04-20 22:55:21 +00001353 AddRegexCommandToInterpreter()
Greg Claytonde164aa2011-04-20 16:37:46 +00001354 {
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001355 if (m_regex_cmd_ap)
Greg Claytonde164aa2011-04-20 16:37:46 +00001356 {
1357 if (m_regex_cmd_ap->HasRegexEntries())
1358 {
1359 CommandObjectSP cmd_sp (m_regex_cmd_ap.release());
1360 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
1361 }
1362 }
1363 }
1364
Greg Claytonde164aa2011-04-20 16:37:46 +00001365private:
Greg Clayton7b0992d2013-04-18 22:45:39 +00001366 std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_ap;
Greg Claytonde164aa2011-04-20 16:37:46 +00001367
1368 class CommandOptions : public Options
1369 {
1370 public:
Todd Fialae1cfbc72016-08-11 23:51:28 +00001371 CommandOptions() :
1372 Options()
Greg Claytonde164aa2011-04-20 16:37:46 +00001373 {
1374 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001375
1376 ~CommandOptions() override = default;
1377
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001378 Error
Todd Fialae1cfbc72016-08-11 23:51:28 +00001379 SetOptionValue (uint32_t option_idx, const char *option_arg,
1380 ExecutionContext *execution_context) override
Greg Claytonde164aa2011-04-20 16:37:46 +00001381 {
1382 Error error;
Greg Clayton3bcdfc02012-12-04 00:32:51 +00001383 const int short_option = m_getopt_table[option_idx].val;
Greg Claytonde164aa2011-04-20 16:37:46 +00001384
1385 switch (short_option)
1386 {
1387 case 'h':
1388 m_help.assign (option_arg);
1389 break;
1390 case 's':
1391 m_syntax.assign (option_arg);
1392 break;
Greg Claytonde164aa2011-04-20 16:37:46 +00001393 default:
Greg Clayton86edbf42011-10-26 00:56:27 +00001394 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
Greg Claytonde164aa2011-04-20 16:37:46 +00001395 break;
1396 }
1397
1398 return error;
1399 }
1400
1401 void
Todd Fialae1cfbc72016-08-11 23:51:28 +00001402 OptionParsingStarting (ExecutionContext *execution_context) override
Greg Claytonde164aa2011-04-20 16:37:46 +00001403 {
1404 m_help.clear();
1405 m_syntax.clear();
1406 }
1407
1408 const OptionDefinition*
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001409 GetDefinitions () override
Greg Claytonde164aa2011-04-20 16:37:46 +00001410 {
1411 return g_option_table;
1412 }
1413
1414 // Options table: Required for subclasses of Options.
1415
1416 static OptionDefinition g_option_table[];
1417
1418 const char *
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001419 GetHelp()
Greg Claytonde164aa2011-04-20 16:37:46 +00001420 {
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001421 return (m_help.empty() ? nullptr : m_help.c_str());
Greg Claytonde164aa2011-04-20 16:37:46 +00001422 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001423
Greg Claytonde164aa2011-04-20 16:37:46 +00001424 const char *
1425 GetSyntax ()
1426 {
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001427 return (m_syntax.empty() ? nullptr : m_syntax.c_str());
Greg Claytonde164aa2011-04-20 16:37:46 +00001428 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001429
Greg Claytonde164aa2011-04-20 16:37:46 +00001430 protected:
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001431 // Instance variables to hold the values for command options.
1432
Greg Claytonde164aa2011-04-20 16:37:46 +00001433 std::string m_help;
1434 std::string m_syntax;
1435 };
Jim Ingham5a988412012-06-08 21:56:10 +00001436
Eric Christopherb0a18142014-11-18 22:40:27 +00001437 Options *
1438 GetOptions () override
Greg Claytonde164aa2011-04-20 16:37:46 +00001439 {
1440 return &m_options;
1441 }
Jim Ingham5a988412012-06-08 21:56:10 +00001442
1443 CommandOptions m_options;
Greg Claytonde164aa2011-04-20 16:37:46 +00001444};
1445
Greg Claytonde164aa2011-04-20 16:37:46 +00001446OptionDefinition
1447CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] =
1448{
Kate Stoneac9c3a62016-08-26 23:28:47 +00001449 // clang-format off
1450 {LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "The help text to display for this command."},
1451 {LLDB_OPT_SET_1, false, "syntax", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."},
1452 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
1453 // clang-format on
Greg Claytonde164aa2011-04-20 16:37:46 +00001454};
1455
Jim Ingham5a988412012-06-08 21:56:10 +00001456class CommandObjectPythonFunction : public CommandObjectRaw
Enrico Granata223383e2011-08-16 23:24:13 +00001457{
Enrico Granata223383e2011-08-16 23:24:13 +00001458public:
Enrico Granata223383e2011-08-16 23:24:13 +00001459 CommandObjectPythonFunction (CommandInterpreter &interpreter,
1460 std::string name,
Enrico Granata0a305db2011-11-07 22:57:04 +00001461 std::string funct,
Enrico Granata735152e2014-09-15 17:52:44 +00001462 std::string help,
Enrico Granata0a305db2011-11-07 22:57:04 +00001463 ScriptedCommandSynchronicity synch) :
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001464 CommandObjectRaw(interpreter,
1465 name.c_str(),
1466 nullptr,
1467 nullptr),
Jim Ingham5a988412012-06-08 21:56:10 +00001468 m_function_name(funct),
Enrico Granatafac939e2012-09-18 21:53:02 +00001469 m_synchro(synch),
1470 m_fetched_help_long(false)
Enrico Granata223383e2011-08-16 23:24:13 +00001471 {
Enrico Granata735152e2014-09-15 17:52:44 +00001472 if (!help.empty())
1473 SetHelp(help.c_str());
1474 else
1475 {
1476 StreamString stream;
1477 stream.Printf("For more information run 'help %s'",name.c_str());
1478 SetHelp(stream.GetData());
1479 }
Enrico Granata223383e2011-08-16 23:24:13 +00001480 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001481
1482 ~CommandObjectPythonFunction() override = default;
1483
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001484 bool
1485 IsRemovable () const override
Jim Ingham5a988412012-06-08 21:56:10 +00001486 {
1487 return true;
1488 }
1489
1490 const std::string&
1491 GetFunctionName ()
1492 {
1493 return m_function_name;
1494 }
1495
1496 ScriptedCommandSynchronicity
1497 GetSynchronicity ()
1498 {
1499 return m_synchro;
1500 }
1501
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001502 const char *
1503 GetHelpLong () override
Enrico Granatafac939e2012-09-18 21:53:02 +00001504 {
1505 if (!m_fetched_help_long)
1506 {
1507 ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
1508 if (scripter)
1509 {
1510 std::string docstring;
1511 m_fetched_help_long = scripter->GetDocumentationForItem(m_function_name.c_str(),docstring);
1512 if (!docstring.empty())
Enrico Granatabfb75e92016-03-22 22:12:59 +00001513 SetHelpLong(docstring.c_str());
Enrico Granatafac939e2012-09-18 21:53:02 +00001514 }
1515 }
1516 return CommandObjectRaw::GetHelpLong();
1517 }
1518
Jim Ingham5a988412012-06-08 21:56:10 +00001519protected:
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001520 bool
1521 DoExecute (const char *raw_command_line, CommandReturnObject &result) override
Enrico Granata223383e2011-08-16 23:24:13 +00001522 {
1523 ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
1524
1525 Error error;
1526
Jim Ingham70f11f82012-06-27 17:25:36 +00001527 result.SetStatus(eReturnStatusInvalid);
1528
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001529 if (!scripter || !scripter->RunScriptBasedCommand(m_function_name.c_str(),
1530 raw_command_line,
1531 m_synchro,
1532 result,
1533 error,
1534 m_exe_ctx))
Enrico Granata223383e2011-08-16 23:24:13 +00001535 {
1536 result.AppendError(error.AsCString());
1537 result.SetStatus(eReturnStatusFailed);
1538 }
1539 else
Jim Ingham70f11f82012-06-27 17:25:36 +00001540 {
1541 // Don't change the status if the command already set it...
1542 if (result.GetStatus() == eReturnStatusInvalid)
1543 {
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001544 if (result.GetOutputData() == nullptr || result.GetOutputData()[0] == '\0')
Jim Ingham70f11f82012-06-27 17:25:36 +00001545 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1546 else
1547 result.SetStatus(eReturnStatusSuccessFinishResult);
1548 }
1549 }
Enrico Granata223383e2011-08-16 23:24:13 +00001550
1551 return result.Succeeded();
1552 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001553
1554private:
1555 std::string m_function_name;
1556 ScriptedCommandSynchronicity m_synchro;
1557 bool m_fetched_help_long;
Enrico Granata223383e2011-08-16 23:24:13 +00001558};
1559
Enrico Granata9fe00e52015-03-13 02:20:41 +00001560class CommandObjectScriptingObject : public CommandObjectRaw
1561{
Enrico Granata9fe00e52015-03-13 02:20:41 +00001562public:
Enrico Granata9fe00e52015-03-13 02:20:41 +00001563 CommandObjectScriptingObject (CommandInterpreter &interpreter,
1564 std::string name,
Zachary Turner0641ca12015-03-17 20:04:04 +00001565 StructuredData::GenericSP cmd_obj_sp,
Enrico Granata9fe00e52015-03-13 02:20:41 +00001566 ScriptedCommandSynchronicity synch) :
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001567 CommandObjectRaw(interpreter,
1568 name.c_str(),
1569 nullptr,
1570 nullptr),
1571 m_cmd_obj_sp(cmd_obj_sp),
1572 m_synchro(synch),
1573 m_fetched_help_short(false),
1574 m_fetched_help_long(false)
Enrico Granata9fe00e52015-03-13 02:20:41 +00001575 {
1576 StreamString stream;
1577 stream.Printf("For more information run 'help %s'",name.c_str());
1578 SetHelp(stream.GetData());
Enrico Granatae87764f2015-05-27 05:04:35 +00001579 if (ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter())
1580 GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp));
Enrico Granata9fe00e52015-03-13 02:20:41 +00001581 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001582
1583 ~CommandObjectScriptingObject() override = default;
1584
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001585 bool
1586 IsRemovable () const override
Enrico Granata9fe00e52015-03-13 02:20:41 +00001587 {
1588 return true;
1589 }
1590
Zachary Turner0641ca12015-03-17 20:04:04 +00001591 StructuredData::GenericSP
Enrico Granata9fe00e52015-03-13 02:20:41 +00001592 GetImplementingObject ()
1593 {
1594 return m_cmd_obj_sp;
1595 }
1596
1597 ScriptedCommandSynchronicity
1598 GetSynchronicity ()
1599 {
1600 return m_synchro;
1601 }
Enrico Granata6f79bb22015-03-13 22:22:28 +00001602
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001603 const char *
1604 GetHelp () override
Enrico Granata6f79bb22015-03-13 22:22:28 +00001605 {
1606 if (!m_fetched_help_short)
1607 {
1608 ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
1609 if (scripter)
1610 {
1611 std::string docstring;
1612 m_fetched_help_short = scripter->GetShortHelpForCommandObject(m_cmd_obj_sp,docstring);
1613 if (!docstring.empty())
Enrico Granatabfb75e92016-03-22 22:12:59 +00001614 SetHelp(docstring.c_str());
Enrico Granata6f79bb22015-03-13 22:22:28 +00001615 }
1616 }
1617 return CommandObjectRaw::GetHelp();
1618 }
Enrico Granata9fe00e52015-03-13 02:20:41 +00001619
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001620 const char *
1621 GetHelpLong () override
Enrico Granata9fe00e52015-03-13 02:20:41 +00001622 {
Enrico Granata6f79bb22015-03-13 22:22:28 +00001623 if (!m_fetched_help_long)
1624 {
1625 ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
1626 if (scripter)
1627 {
1628 std::string docstring;
1629 m_fetched_help_long = scripter->GetLongHelpForCommandObject(m_cmd_obj_sp,docstring);
1630 if (!docstring.empty())
Enrico Granatabfb75e92016-03-22 22:12:59 +00001631 SetHelpLong(docstring.c_str());
Enrico Granata6f79bb22015-03-13 22:22:28 +00001632 }
1633 }
Enrico Granata9fe00e52015-03-13 02:20:41 +00001634 return CommandObjectRaw::GetHelpLong();
1635 }
1636
1637protected:
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001638 bool
1639 DoExecute (const char *raw_command_line, CommandReturnObject &result) override
Enrico Granata9fe00e52015-03-13 02:20:41 +00001640 {
1641 ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
1642
1643 Error error;
1644
1645 result.SetStatus(eReturnStatusInvalid);
1646
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001647 if (!scripter || !scripter->RunScriptBasedCommand(m_cmd_obj_sp,
1648 raw_command_line,
1649 m_synchro,
1650 result,
1651 error,
1652 m_exe_ctx))
Enrico Granata9fe00e52015-03-13 02:20:41 +00001653 {
1654 result.AppendError(error.AsCString());
1655 result.SetStatus(eReturnStatusFailed);
1656 }
1657 else
1658 {
1659 // Don't change the status if the command already set it...
1660 if (result.GetStatus() == eReturnStatusInvalid)
1661 {
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001662 if (result.GetOutputData() == nullptr || result.GetOutputData()[0] == '\0')
Enrico Granata9fe00e52015-03-13 02:20:41 +00001663 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1664 else
1665 result.SetStatus(eReturnStatusSuccessFinishResult);
1666 }
1667 }
1668
1669 return result.Succeeded();
1670 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001671
1672private:
1673 StructuredData::GenericSP m_cmd_obj_sp;
1674 ScriptedCommandSynchronicity m_synchro;
1675 bool m_fetched_help_short: 1;
1676 bool m_fetched_help_long: 1;
Enrico Granata9fe00e52015-03-13 02:20:41 +00001677};
1678
Enrico Granataa9dbf432011-10-17 21:45:27 +00001679//-------------------------------------------------------------------------
1680// CommandObjectCommandsScriptImport
1681//-------------------------------------------------------------------------
1682
Jim Ingham5a988412012-06-08 21:56:10 +00001683class CommandObjectCommandsScriptImport : public CommandObjectParsed
Enrico Granataa9dbf432011-10-17 21:45:27 +00001684{
Jim Ingham5a988412012-06-08 21:56:10 +00001685public:
1686 CommandObjectCommandsScriptImport (CommandInterpreter &interpreter) :
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001687 CommandObjectParsed(interpreter,
1688 "command script import",
1689 "Import a scripting module in LLDB.",
1690 nullptr),
Todd Fialae1cfbc72016-08-11 23:51:28 +00001691 m_options()
Jim Ingham5a988412012-06-08 21:56:10 +00001692 {
1693 CommandArgumentEntry arg1;
1694 CommandArgumentData cmd_arg;
1695
1696 // Define the first (and only) variant of this arg.
1697 cmd_arg.arg_type = eArgTypeFilename;
Enrico Granata3b00e352015-06-16 18:31:04 +00001698 cmd_arg.arg_repetition = eArgRepeatPlus;
Jim Ingham5a988412012-06-08 21:56:10 +00001699
1700 // There is only one variant this argument could be; put it into the argument entry.
1701 arg1.push_back (cmd_arg);
1702
1703 // Push the data for the first argument into the m_arguments vector.
1704 m_arguments.push_back (arg1);
1705 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001706
1707 ~CommandObjectCommandsScriptImport() override = default;
1708
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001709 int
Jim Ingham5a988412012-06-08 21:56:10 +00001710 HandleArgumentCompletion (Args &input,
1711 int &cursor_index,
1712 int &cursor_char_position,
1713 OptionElementVector &opt_element_vector,
1714 int match_start_point,
1715 int max_return_elements,
1716 bool &word_complete,
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001717 StringList &matches) override
Jim Ingham5a988412012-06-08 21:56:10 +00001718 {
1719 std::string completion_str (input.GetArgumentAtIndex(cursor_index));
1720 completion_str.erase (cursor_char_position);
Todd Fialae1cfbc72016-08-11 23:51:28 +00001721
1722 CommandCompletions::InvokeCommonCompletionCallbacks(GetCommandInterpreter(),
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001723 CommandCompletions::eDiskFileCompletion,
1724 completion_str.c_str(),
1725 match_start_point,
1726 max_return_elements,
1727 nullptr,
1728 word_complete,
1729 matches);
Jim Ingham5a988412012-06-08 21:56:10 +00001730 return matches.GetSize();
1731 }
1732
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001733 Options *
1734 GetOptions () override
Jim Ingham5a988412012-06-08 21:56:10 +00001735 {
1736 return &m_options;
1737 }
1738
1739protected:
Enrico Granata0a305db2011-11-07 22:57:04 +00001740 class CommandOptions : public Options
1741 {
1742 public:
Todd Fialae1cfbc72016-08-11 23:51:28 +00001743 CommandOptions() :
1744 Options()
Enrico Granata0a305db2011-11-07 22:57:04 +00001745 {
1746 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001747
1748 ~CommandOptions() override = default;
1749
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001750 Error
Todd Fialae1cfbc72016-08-11 23:51:28 +00001751 SetOptionValue (uint32_t option_idx, const char *option_arg,
1752 ExecutionContext *execution_context) override
Enrico Granata0a305db2011-11-07 22:57:04 +00001753 {
1754 Error error;
Greg Clayton3bcdfc02012-12-04 00:32:51 +00001755 const int short_option = m_getopt_table[option_idx].val;
Enrico Granata0a305db2011-11-07 22:57:04 +00001756
1757 switch (short_option)
1758 {
1759 case 'r':
1760 m_allow_reload = true;
1761 break;
1762 default:
1763 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
1764 break;
1765 }
1766
1767 return error;
1768 }
1769
1770 void
Todd Fialae1cfbc72016-08-11 23:51:28 +00001771 OptionParsingStarting(ExecutionContext *execution_context) override
Enrico Granata0a305db2011-11-07 22:57:04 +00001772 {
Enrico Granatae0c70f12013-05-31 01:03:09 +00001773 m_allow_reload = true;
Enrico Granata0a305db2011-11-07 22:57:04 +00001774 }
1775
1776 const OptionDefinition*
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001777 GetDefinitions () override
Enrico Granata0a305db2011-11-07 22:57:04 +00001778 {
1779 return g_option_table;
1780 }
1781
1782 // Options table: Required for subclasses of Options.
1783
1784 static OptionDefinition g_option_table[];
1785
1786 // Instance variables to hold the values for command options.
1787
1788 bool m_allow_reload;
1789 };
Enrico Granata0a305db2011-11-07 22:57:04 +00001790
Enrico Granataa9dbf432011-10-17 21:45:27 +00001791 bool
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001792 DoExecute (Args& command, CommandReturnObject &result) override
Enrico Granataa9dbf432011-10-17 21:45:27 +00001793 {
Enrico Granataa9dbf432011-10-17 21:45:27 +00001794 if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython)
1795 {
1796 result.AppendError ("only scripting language supported for module importing is currently Python");
1797 result.SetStatus (eReturnStatusFailed);
1798 return false;
1799 }
1800
Jim Ingham5a988412012-06-08 21:56:10 +00001801 size_t argc = command.GetArgumentCount();
Enrico Granata3b00e352015-06-16 18:31:04 +00001802 if (0 == argc)
Enrico Granataa9dbf432011-10-17 21:45:27 +00001803 {
Enrico Granata3b00e352015-06-16 18:31:04 +00001804 result.AppendError("command script import needs one or more arguments");
Enrico Granataa9dbf432011-10-17 21:45:27 +00001805 result.SetStatus (eReturnStatusFailed);
1806 return false;
1807 }
1808
Ed Maste0e978482015-06-17 17:29:56 +00001809 for (size_t i = 0;
Enrico Granata3b00e352015-06-16 18:31:04 +00001810 i < argc;
1811 i++)
Enrico Granataa9dbf432011-10-17 21:45:27 +00001812 {
Enrico Granata3b00e352015-06-16 18:31:04 +00001813 std::string path = command.GetArgumentAtIndex(i);
1814 Error error;
1815
1816 const bool init_session = true;
1817 // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that
1818 // commands won't ever be recursively invoked, but it's actually possible to craft
1819 // a Python script that does other "command script imports" in __lldb_init_module
1820 // the real fix is to have recursive commands possible with a CommandInvocation object
1821 // separate from the CommandObject itself, so that recursive command invocations
1822 // won't stomp on each other (wrt to execution contents, options, and more)
1823 m_exe_ctx.Clear();
1824 if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(),
1825 m_options.m_allow_reload,
1826 init_session,
1827 error))
1828 {
1829 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1830 }
1831 else
1832 {
1833 result.AppendErrorWithFormat("module importing failed: %s", error.AsCString());
1834 result.SetStatus (eReturnStatusFailed);
1835 }
Enrico Granataa9dbf432011-10-17 21:45:27 +00001836 }
1837
1838 return result.Succeeded();
1839 }
Enrico Granata0a305db2011-11-07 22:57:04 +00001840
Jim Ingham5a988412012-06-08 21:56:10 +00001841 CommandOptions m_options;
Enrico Granataa9dbf432011-10-17 21:45:27 +00001842};
Enrico Granata223383e2011-08-16 23:24:13 +00001843
Enrico Granata0a305db2011-11-07 22:57:04 +00001844OptionDefinition
1845CommandObjectCommandsScriptImport::CommandOptions::g_option_table[] =
1846{
Kate Stoneac9c3a62016-08-26 23:28:47 +00001847 // clang-format off
1848 {LLDB_OPT_SET_1, false, "allow-reload", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not."},
1849 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr }
1850 // clang-format on
Enrico Granata0a305db2011-11-07 22:57:04 +00001851};
1852
Enrico Granata223383e2011-08-16 23:24:13 +00001853//-------------------------------------------------------------------------
1854// CommandObjectCommandsScriptAdd
1855//-------------------------------------------------------------------------
1856
Greg Clayton44d93782014-01-27 23:43:24 +00001857class CommandObjectCommandsScriptAdd :
1858 public CommandObjectParsed,
1859 public IOHandlerDelegateMultiline
Enrico Granata223383e2011-08-16 23:24:13 +00001860{
Jim Ingham5a988412012-06-08 21:56:10 +00001861public:
1862 CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) :
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001863 CommandObjectParsed(interpreter,
1864 "command script add",
1865 "Add a scripted function as an LLDB command.",
1866 nullptr),
Greg Claytonc3d874a2014-05-08 16:59:00 +00001867 IOHandlerDelegateMultiline ("DONE"),
Todd Fialae1cfbc72016-08-11 23:51:28 +00001868 m_options()
Jim Ingham5a988412012-06-08 21:56:10 +00001869 {
1870 CommandArgumentEntry arg1;
1871 CommandArgumentData cmd_arg;
1872
1873 // Define the first (and only) variant of this arg.
1874 cmd_arg.arg_type = eArgTypeCommandName;
1875 cmd_arg.arg_repetition = eArgRepeatPlain;
1876
1877 // There is only one variant this argument could be; put it into the argument entry.
1878 arg1.push_back (cmd_arg);
1879
1880 // Push the data for the first argument into the m_arguments vector.
1881 m_arguments.push_back (arg1);
1882 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001883
1884 ~CommandObjectCommandsScriptAdd() override = default;
1885
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001886 Options *
1887 GetOptions () override
Jim Ingham5a988412012-06-08 21:56:10 +00001888 {
1889 return &m_options;
1890 }
1891
1892protected:
Enrico Granata223383e2011-08-16 23:24:13 +00001893 class CommandOptions : public Options
1894 {
1895 public:
Todd Fialae1cfbc72016-08-11 23:51:28 +00001896 CommandOptions() :
1897 Options(),
Enrico Granata9fe00e52015-03-13 02:20:41 +00001898 m_class_name(),
1899 m_funct_name(),
1900 m_short_help(),
1901 m_synchronicity(eScriptedCommandSynchronicitySynchronous)
Enrico Granata223383e2011-08-16 23:24:13 +00001902 {
1903 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00001904
1905 ~CommandOptions() override = default;
1906
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001907 Error
Todd Fialae1cfbc72016-08-11 23:51:28 +00001908 SetOptionValue (uint32_t option_idx, const char *option_arg,
1909 ExecutionContext *execution_context) override
Enrico Granata223383e2011-08-16 23:24:13 +00001910 {
1911 Error error;
Greg Clayton3bcdfc02012-12-04 00:32:51 +00001912 const int short_option = m_getopt_table[option_idx].val;
Enrico Granata223383e2011-08-16 23:24:13 +00001913
1914 switch (short_option)
1915 {
1916 case 'f':
Enrico Granata735152e2014-09-15 17:52:44 +00001917 if (option_arg)
1918 m_funct_name.assign(option_arg);
1919 break;
Enrico Granata9fe00e52015-03-13 02:20:41 +00001920 case 'c':
1921 if (option_arg)
1922 m_class_name.assign(option_arg);
1923 break;
Enrico Granata735152e2014-09-15 17:52:44 +00001924 case 'h':
1925 if (option_arg)
1926 m_short_help.assign(option_arg);
Enrico Granata223383e2011-08-16 23:24:13 +00001927 break;
Enrico Granata0a305db2011-11-07 22:57:04 +00001928 case 's':
Greg Clayton44d93782014-01-27 23:43:24 +00001929 m_synchronicity = (ScriptedCommandSynchronicity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
Enrico Granata0a305db2011-11-07 22:57:04 +00001930 if (!error.Success())
1931 error.SetErrorStringWithFormat ("unrecognized value for synchronicity '%s'", option_arg);
1932 break;
Enrico Granata223383e2011-08-16 23:24:13 +00001933 default:
Greg Clayton86edbf42011-10-26 00:56:27 +00001934 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
Enrico Granata223383e2011-08-16 23:24:13 +00001935 break;
1936 }
1937
1938 return error;
1939 }
1940
1941 void
Todd Fialae1cfbc72016-08-11 23:51:28 +00001942 OptionParsingStarting(ExecutionContext *execution_context) override
Enrico Granata223383e2011-08-16 23:24:13 +00001943 {
Enrico Granata9fe00e52015-03-13 02:20:41 +00001944 m_class_name.clear();
Enrico Granata735152e2014-09-15 17:52:44 +00001945 m_funct_name.clear();
1946 m_short_help.clear();
Greg Clayton44d93782014-01-27 23:43:24 +00001947 m_synchronicity = eScriptedCommandSynchronicitySynchronous;
Enrico Granata223383e2011-08-16 23:24:13 +00001948 }
1949
1950 const OptionDefinition*
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001951 GetDefinitions () override
Enrico Granata223383e2011-08-16 23:24:13 +00001952 {
1953 return g_option_table;
1954 }
1955
1956 // Options table: Required for subclasses of Options.
1957
1958 static OptionDefinition g_option_table[];
1959
1960 // Instance variables to hold the values for command options.
1961
Enrico Granata9fe00e52015-03-13 02:20:41 +00001962 std::string m_class_name;
Enrico Granata223383e2011-08-16 23:24:13 +00001963 std::string m_funct_name;
Enrico Granata735152e2014-09-15 17:52:44 +00001964 std::string m_short_help;
Greg Clayton44d93782014-01-27 23:43:24 +00001965 ScriptedCommandSynchronicity m_synchronicity;
Enrico Granata223383e2011-08-16 23:24:13 +00001966 };
Jim Ingham5a988412012-06-08 21:56:10 +00001967
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001968 void
1969 IOHandlerActivated (IOHandler &io_handler) override
Enrico Granata223383e2011-08-16 23:24:13 +00001970 {
Greg Clayton44d93782014-01-27 23:43:24 +00001971 StreamFileSP output_sp(io_handler.GetOutputStreamFile());
1972 if (output_sp)
Enrico Granata223383e2011-08-16 23:24:13 +00001973 {
Greg Clayton44d93782014-01-27 23:43:24 +00001974 output_sp->PutCString(g_python_command_instructions);
1975 output_sp->Flush();
Enrico Granata223383e2011-08-16 23:24:13 +00001976 }
Greg Clayton44d93782014-01-27 23:43:24 +00001977 }
Enrico Granata223383e2011-08-16 23:24:13 +00001978
Greg Clayton44d93782014-01-27 23:43:24 +00001979
Bruce Mitchener13d21e92015-10-07 16:56:17 +00001980 void
1981 IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override
Greg Clayton44d93782014-01-27 23:43:24 +00001982 {
1983 StreamFileSP error_sp = io_handler.GetErrorStreamFile();
1984
1985 ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
1986 if (interpreter)
1987 {
1988
1989 StringList lines;
1990 lines.SplitIntoLines(data);
1991 if (lines.GetSize() > 0)
1992 {
1993 std::string funct_name_str;
1994 if (interpreter->GenerateScriptAliasFunction (lines, funct_name_str))
1995 {
1996 if (funct_name_str.empty())
1997 {
1998 error_sp->Printf ("error: unable to obtain a function name, didn't add python command.\n");
1999 error_sp->Flush();
2000 }
2001 else
2002 {
2003 // everything should be fine now, let's add this alias
2004
2005 CommandObjectSP command_obj_sp(new CommandObjectPythonFunction (m_interpreter,
2006 m_cmd_name,
2007 funct_name_str.c_str(),
Enrico Granata735152e2014-09-15 17:52:44 +00002008 m_short_help,
Greg Clayton44d93782014-01-27 23:43:24 +00002009 m_synchronicity));
2010
2011 if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, true))
2012 {
2013 error_sp->Printf ("error: unable to add selected command, didn't add python command.\n");
2014 error_sp->Flush();
2015 }
2016 }
2017 }
2018 else
2019 {
2020 error_sp->Printf ("error: unable to create function, didn't add python command.\n");
2021 error_sp->Flush();
2022 }
2023 }
2024 else
2025 {
2026 error_sp->Printf ("error: empty function, didn't add python command.\n");
2027 error_sp->Flush();
2028 }
2029 }
2030 else
2031 {
2032 error_sp->Printf ("error: script interpreter missing, didn't add python command.\n");
2033 error_sp->Flush();
2034 }
2035
2036 io_handler.SetIsDone(true);
Greg Clayton44d93782014-01-27 23:43:24 +00002037 }
2038
Jim Ingham5a988412012-06-08 21:56:10 +00002039protected:
Enrico Granata223383e2011-08-16 23:24:13 +00002040 bool
Bruce Mitchener13d21e92015-10-07 16:56:17 +00002041 DoExecute (Args& command, CommandReturnObject &result) override
Enrico Granata223383e2011-08-16 23:24:13 +00002042 {
Enrico Granata99f0b8f2011-08-17 01:30:04 +00002043 if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython)
2044 {
2045 result.AppendError ("only scripting language supported for scripted commands is currently Python");
2046 result.SetStatus (eReturnStatusFailed);
2047 return false;
2048 }
2049
Jim Ingham5a988412012-06-08 21:56:10 +00002050 size_t argc = command.GetArgumentCount();
Enrico Granata223383e2011-08-16 23:24:13 +00002051
2052 if (argc != 1)
2053 {
2054 result.AppendError ("'command script add' requires one argument");
2055 result.SetStatus (eReturnStatusFailed);
2056 return false;
2057 }
2058
Enrico Granata735152e2014-09-15 17:52:44 +00002059 // Store the options in case we get multi-line input
Greg Clayton44d93782014-01-27 23:43:24 +00002060 m_cmd_name = command.GetArgumentAtIndex(0);
Enrico Granata735152e2014-09-15 17:52:44 +00002061 m_short_help.assign(m_options.m_short_help);
Greg Clayton44d93782014-01-27 23:43:24 +00002062 m_synchronicity = m_options.m_synchronicity;
Enrico Granata223383e2011-08-16 23:24:13 +00002063
Enrico Granata9fe00e52015-03-13 02:20:41 +00002064 if (m_options.m_class_name.empty())
Enrico Granata223383e2011-08-16 23:24:13 +00002065 {
Enrico Granata9fe00e52015-03-13 02:20:41 +00002066 if (m_options.m_funct_name.empty())
2067 {
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00002068 m_interpreter.GetPythonCommandsFromIOHandler(" ", // Prompt
2069 *this, // IOHandlerDelegate
2070 true, // Run IOHandler in async mode
2071 nullptr); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions
Enrico Granata9fe00e52015-03-13 02:20:41 +00002072 }
2073 else
2074 {
2075 CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter,
2076 m_cmd_name,
2077 m_options.m_funct_name,
2078 m_options.m_short_help,
2079 m_synchronicity));
2080 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true))
2081 {
2082 result.SetStatus (eReturnStatusSuccessFinishNoResult);
2083 }
2084 else
2085 {
2086 result.AppendError("cannot add command");
2087 result.SetStatus (eReturnStatusFailed);
2088 }
2089 }
Enrico Granata223383e2011-08-16 23:24:13 +00002090 }
2091 else
2092 {
Enrico Granata9fe00e52015-03-13 02:20:41 +00002093 ScriptInterpreter *interpreter = GetCommandInterpreter().GetScriptInterpreter();
2094 if (!interpreter)
2095 {
2096 result.AppendError("cannot find ScriptInterpreter");
2097 result.SetStatus(eReturnStatusFailed);
2098 return false;
2099 }
2100
2101 auto cmd_obj_sp = interpreter->CreateScriptCommandObject(m_options.m_class_name.c_str());
2102 if (!cmd_obj_sp)
2103 {
2104 result.AppendError("cannot create helper object");
2105 result.SetStatus(eReturnStatusFailed);
2106 return false;
2107 }
2108
2109 CommandObjectSP new_cmd(new CommandObjectScriptingObject(m_interpreter,
2110 m_cmd_name,
2111 cmd_obj_sp,
2112 m_synchronicity));
Greg Clayton44d93782014-01-27 23:43:24 +00002113 if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true))
Enrico Granata223383e2011-08-16 23:24:13 +00002114 {
2115 result.SetStatus (eReturnStatusSuccessFinishNoResult);
2116 }
2117 else
2118 {
2119 result.AppendError("cannot add command");
2120 result.SetStatus (eReturnStatusFailed);
2121 }
2122 }
2123
2124 return result.Succeeded();
Enrico Granata223383e2011-08-16 23:24:13 +00002125 }
Jim Ingham5a988412012-06-08 21:56:10 +00002126
2127 CommandOptions m_options;
Greg Clayton44d93782014-01-27 23:43:24 +00002128 std::string m_cmd_name;
Enrico Granata735152e2014-09-15 17:52:44 +00002129 std::string m_short_help;
Greg Clayton44d93782014-01-27 23:43:24 +00002130 ScriptedCommandSynchronicity m_synchronicity;
Enrico Granata223383e2011-08-16 23:24:13 +00002131};
2132
Enrico Granata0a305db2011-11-07 22:57:04 +00002133static OptionEnumValueElement g_script_synchro_type[] =
2134{
2135 { eScriptedCommandSynchronicitySynchronous, "synchronous", "Run synchronous"},
2136 { eScriptedCommandSynchronicityAsynchronous, "asynchronous", "Run asynchronous"},
2137 { eScriptedCommandSynchronicityCurrentValue, "current", "Do not alter current setting"},
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00002138 { 0, nullptr, nullptr }
Enrico Granata0a305db2011-11-07 22:57:04 +00002139};
2140
Enrico Granata223383e2011-08-16 23:24:13 +00002141OptionDefinition
2142CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] =
2143{
Kate Stoneac9c3a62016-08-26 23:28:47 +00002144 // clang-format off
2145 {LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name."},
2146 {LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name."},
2147 {LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeHelpText, "The help text to display for this command."},
2148 {LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, nullptr, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."},
2149 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
2150 // clang-format on
Enrico Granata223383e2011-08-16 23:24:13 +00002151};
2152
2153//-------------------------------------------------------------------------
2154// CommandObjectCommandsScriptList
2155//-------------------------------------------------------------------------
2156
Jim Ingham5a988412012-06-08 21:56:10 +00002157class CommandObjectCommandsScriptList : public CommandObjectParsed
Enrico Granata223383e2011-08-16 23:24:13 +00002158{
Enrico Granata223383e2011-08-16 23:24:13 +00002159public:
2160 CommandObjectCommandsScriptList(CommandInterpreter &interpreter) :
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00002161 CommandObjectParsed(interpreter,
2162 "command script list",
2163 "List defined scripted commands.",
2164 nullptr)
Enrico Granata223383e2011-08-16 23:24:13 +00002165 {
2166 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00002167
2168 ~CommandObjectCommandsScriptList() override = default;
2169
Enrico Granata223383e2011-08-16 23:24:13 +00002170 bool
Bruce Mitchener13d21e92015-10-07 16:56:17 +00002171 DoExecute (Args& command, CommandReturnObject &result) override
Enrico Granata223383e2011-08-16 23:24:13 +00002172 {
Enrico Granata223383e2011-08-16 23:24:13 +00002173 m_interpreter.GetHelp(result,
2174 CommandInterpreter::eCommandTypesUserDef);
2175
2176 result.SetStatus (eReturnStatusSuccessFinishResult);
2177
2178 return true;
Enrico Granata223383e2011-08-16 23:24:13 +00002179 }
2180};
2181
2182//-------------------------------------------------------------------------
2183// CommandObjectCommandsScriptClear
2184//-------------------------------------------------------------------------
2185
Jim Ingham5a988412012-06-08 21:56:10 +00002186class CommandObjectCommandsScriptClear : public CommandObjectParsed
Enrico Granata223383e2011-08-16 23:24:13 +00002187{
Enrico Granata223383e2011-08-16 23:24:13 +00002188public:
2189 CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) :
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00002190 CommandObjectParsed(interpreter,
2191 "command script clear",
2192 "Delete all scripted commands.",
2193 nullptr)
Enrico Granata223383e2011-08-16 23:24:13 +00002194 {
2195 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00002196
2197 ~CommandObjectCommandsScriptClear() override = default;
2198
Jim Ingham5a988412012-06-08 21:56:10 +00002199protected:
Enrico Granata223383e2011-08-16 23:24:13 +00002200 bool
Bruce Mitchener13d21e92015-10-07 16:56:17 +00002201 DoExecute (Args& command, CommandReturnObject &result) override
Enrico Granata223383e2011-08-16 23:24:13 +00002202 {
Enrico Granata223383e2011-08-16 23:24:13 +00002203 m_interpreter.RemoveAllUser();
2204
2205 result.SetStatus (eReturnStatusSuccessFinishResult);
2206
2207 return true;
Enrico Granata223383e2011-08-16 23:24:13 +00002208 }
2209};
2210
2211//-------------------------------------------------------------------------
2212// CommandObjectCommandsScriptDelete
2213//-------------------------------------------------------------------------
2214
Jim Ingham5a988412012-06-08 21:56:10 +00002215class CommandObjectCommandsScriptDelete : public CommandObjectParsed
Enrico Granata223383e2011-08-16 23:24:13 +00002216{
Enrico Granata223383e2011-08-16 23:24:13 +00002217public:
2218 CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) :
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00002219 CommandObjectParsed(interpreter,
2220 "command script delete",
2221 "Delete a scripted command.",
2222 nullptr)
Enrico Granata223383e2011-08-16 23:24:13 +00002223 {
2224 CommandArgumentEntry arg1;
2225 CommandArgumentData cmd_arg;
2226
2227 // Define the first (and only) variant of this arg.
2228 cmd_arg.arg_type = eArgTypeCommandName;
2229 cmd_arg.arg_repetition = eArgRepeatPlain;
2230
2231 // There is only one variant this argument could be; put it into the argument entry.
2232 arg1.push_back (cmd_arg);
2233
2234 // Push the data for the first argument into the m_arguments vector.
2235 m_arguments.push_back (arg1);
2236 }
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00002237
2238 ~CommandObjectCommandsScriptDelete() override = default;
2239
Jim Ingham5a988412012-06-08 21:56:10 +00002240protected:
Enrico Granata223383e2011-08-16 23:24:13 +00002241 bool
Bruce Mitchener13d21e92015-10-07 16:56:17 +00002242 DoExecute (Args& command, CommandReturnObject &result) override
Enrico Granata223383e2011-08-16 23:24:13 +00002243 {
2244
Jim Ingham5a988412012-06-08 21:56:10 +00002245 size_t argc = command.GetArgumentCount();
Enrico Granata223383e2011-08-16 23:24:13 +00002246
2247 if (argc != 1)
2248 {
2249 result.AppendError ("'command script delete' requires one argument");
2250 result.SetStatus (eReturnStatusFailed);
2251 return false;
2252 }
2253
Jim Ingham5a988412012-06-08 21:56:10 +00002254 const char* cmd_name = command.GetArgumentAtIndex(0);
Enrico Granata223383e2011-08-16 23:24:13 +00002255
2256 if (cmd_name && *cmd_name && m_interpreter.HasUserCommands() && m_interpreter.UserCommandExists(cmd_name))
2257 {
2258 m_interpreter.RemoveUser(cmd_name);
2259 result.SetStatus (eReturnStatusSuccessFinishResult);
2260 }
2261 else
2262 {
2263 result.AppendErrorWithFormat ("command %s not found", cmd_name);
2264 result.SetStatus (eReturnStatusFailed);
2265 }
2266
2267 return result.Succeeded();
Enrico Granata223383e2011-08-16 23:24:13 +00002268 }
2269};
2270
2271#pragma mark CommandObjectMultiwordCommandsScript
2272
2273//-------------------------------------------------------------------------
2274// CommandObjectMultiwordCommandsScript
2275//-------------------------------------------------------------------------
2276
2277class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword
2278{
2279public:
Kate Stone7428a182016-07-14 22:03:10 +00002280 CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter)
2281 : CommandObjectMultiword(interpreter, "command script",
2282 "Commands for managing custom commands implemented by interpreter scripts.",
2283 "command script <subcommand> [<subcommand-options>]")
Enrico Granata223383e2011-08-16 23:24:13 +00002284 {
Greg Claytonb5472782015-01-09 19:08:20 +00002285 LoadSubCommand ("add", CommandObjectSP (new CommandObjectCommandsScriptAdd (interpreter)));
2286 LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsScriptDelete (interpreter)));
2287 LoadSubCommand ("clear", CommandObjectSP (new CommandObjectCommandsScriptClear (interpreter)));
Enrico Granata223383e2011-08-16 23:24:13 +00002288 LoadSubCommand ("list", CommandObjectSP (new CommandObjectCommandsScriptList (interpreter)));
Greg Claytonb5472782015-01-09 19:08:20 +00002289 LoadSubCommand ("import", CommandObjectSP (new CommandObjectCommandsScriptImport (interpreter)));
Enrico Granata223383e2011-08-16 23:24:13 +00002290 }
2291
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00002292 ~CommandObjectMultiwordCommandsScript() override = default;
Enrico Granata223383e2011-08-16 23:24:13 +00002293};
2294
Jim Inghamebc09c32010-07-07 03:36:20 +00002295#pragma mark CommandObjectMultiwordCommands
2296
2297//-------------------------------------------------------------------------
2298// CommandObjectMultiwordCommands
2299//-------------------------------------------------------------------------
2300
Kate Stone7428a182016-07-14 22:03:10 +00002301CommandObjectMultiwordCommands::CommandObjectMultiwordCommands(CommandInterpreter &interpreter)
2302 : CommandObjectMultiword(interpreter, "command", "Commands for managing custom LLDB commands.",
2303 "command <subcommand> [<subcommand-options>]")
Jim Inghamebc09c32010-07-07 03:36:20 +00002304{
Greg Claytona7015092010-09-18 01:14:36 +00002305 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
2306 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
2307 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
Greg Claytonb5472782015-01-09 19:08:20 +00002308 LoadSubCommand ("delete", CommandObjectSP (new CommandObjectCommandsDelete (interpreter)));
Greg Claytonde164aa2011-04-20 16:37:46 +00002309 LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter)));
Greg Claytonb5472782015-01-09 19:08:20 +00002310 LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter)));
2311 LoadSubCommand ("script", CommandObjectSP (new CommandObjectMultiwordCommandsScript (interpreter)));
Jim Inghamebc09c32010-07-07 03:36:20 +00002312}
2313
Eugene Zelenko6e3d8e72016-02-22 23:46:47 +00002314CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default;