Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Commands/CommandObjectMultiword.cpp
39587 views
1
//===-- CommandObjectMultiword.cpp ----------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "lldb/Interpreter/CommandObjectMultiword.h"
10
#include "lldb/Interpreter/CommandInterpreter.h"
11
#include "lldb/Interpreter/CommandReturnObject.h"
12
#include "lldb/Interpreter/Options.h"
13
#include <optional>
14
15
using namespace lldb;
16
using namespace lldb_private;
17
18
// CommandObjectMultiword
19
20
CommandObjectMultiword::CommandObjectMultiword(CommandInterpreter &interpreter,
21
const char *name,
22
const char *help,
23
const char *syntax,
24
uint32_t flags)
25
: CommandObject(interpreter, name, help, syntax, flags),
26
m_can_be_removed(false) {}
27
28
CommandObjectMultiword::~CommandObjectMultiword() = default;
29
30
CommandObjectSP
31
CommandObjectMultiword::GetSubcommandSPExact(llvm::StringRef sub_cmd) {
32
if (m_subcommand_dict.empty())
33
return {};
34
35
auto pos = m_subcommand_dict.find(std::string(sub_cmd));
36
if (pos == m_subcommand_dict.end())
37
return {};
38
39
return pos->second;
40
}
41
42
CommandObjectSP CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd,
43
StringList *matches) {
44
if (m_subcommand_dict.empty())
45
return {};
46
47
CommandObjectSP return_cmd_sp = GetSubcommandSPExact(sub_cmd);
48
if (return_cmd_sp) {
49
if (matches)
50
matches->AppendString(sub_cmd);
51
return return_cmd_sp;
52
}
53
54
CommandObject::CommandMap::iterator pos;
55
56
StringList local_matches;
57
if (matches == nullptr)
58
matches = &local_matches;
59
int num_matches =
60
AddNamesMatchingPartialString(m_subcommand_dict, sub_cmd, *matches);
61
62
if (num_matches == 1) {
63
// Cleaner, but slightly less efficient would be to call back into this
64
// function, since I now know I have an exact match...
65
66
sub_cmd = matches->GetStringAtIndex(0);
67
pos = m_subcommand_dict.find(std::string(sub_cmd));
68
if (pos != m_subcommand_dict.end())
69
return_cmd_sp = pos->second;
70
}
71
72
return return_cmd_sp;
73
}
74
75
CommandObject *
76
CommandObjectMultiword::GetSubcommandObject(llvm::StringRef sub_cmd,
77
StringList *matches) {
78
return GetSubcommandSP(sub_cmd, matches).get();
79
}
80
81
bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name,
82
const CommandObjectSP &cmd_obj_sp) {
83
if (cmd_obj_sp)
84
lldbassert((&GetCommandInterpreter() == &cmd_obj_sp->GetCommandInterpreter()) &&
85
"tried to add a CommandObject from a different interpreter");
86
87
CommandMap::iterator pos;
88
bool success = true;
89
90
pos = m_subcommand_dict.find(std::string(name));
91
if (pos == m_subcommand_dict.end()) {
92
m_subcommand_dict[std::string(name)] = cmd_obj_sp;
93
} else
94
success = false;
95
96
return success;
97
}
98
99
llvm::Error CommandObjectMultiword::LoadUserSubcommand(
100
llvm::StringRef name, const CommandObjectSP &cmd_obj_sp, bool can_replace) {
101
Status result;
102
if (cmd_obj_sp)
103
lldbassert((&GetCommandInterpreter() == &cmd_obj_sp->GetCommandInterpreter()) &&
104
"tried to add a CommandObject from a different interpreter");
105
if (!IsUserCommand()) {
106
return llvm::createStringError(llvm::inconvertibleErrorCode(),
107
"can't add a user subcommand to a builtin container command.");
108
}
109
// Make sure this a user command if it isn't already:
110
cmd_obj_sp->SetIsUserCommand(true);
111
112
std::string str_name(name);
113
114
auto pos = m_subcommand_dict.find(str_name);
115
if (pos == m_subcommand_dict.end()) {
116
m_subcommand_dict[str_name] = cmd_obj_sp;
117
return llvm::Error::success();
118
}
119
120
const char *error_str = nullptr;
121
if (!can_replace)
122
error_str = "sub-command already exists";
123
if (!(*pos).second->IsUserCommand())
124
error_str = "can't replace a builtin subcommand";
125
126
if (error_str) {
127
return llvm::createStringError(llvm::inconvertibleErrorCode(), error_str);
128
}
129
m_subcommand_dict[str_name] = cmd_obj_sp;
130
return llvm::Error::success();
131
}
132
133
llvm::Error CommandObjectMultiword::RemoveUserSubcommand(llvm::StringRef cmd_name,
134
bool must_be_multiword) {
135
CommandMap::iterator pos;
136
std::string str_name(cmd_name);
137
138
pos = m_subcommand_dict.find(str_name);
139
if (pos == m_subcommand_dict.end()) {
140
return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' not found.",
141
str_name.c_str());
142
}
143
if (!(*pos).second->IsUserCommand()) {
144
return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' not a user command.",
145
str_name.c_str());
146
}
147
148
if (must_be_multiword && !(*pos).second->IsMultiwordObject()) {
149
return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' is not a container command",
150
str_name.c_str());
151
}
152
if (!must_be_multiword && (*pos).second->IsMultiwordObject()) {
153
return llvm::createStringError(llvm::inconvertibleErrorCode(),"subcommand '%s' is not a user command",
154
str_name.c_str());
155
}
156
157
m_subcommand_dict.erase(pos);
158
159
return llvm::Error::success();
160
}
161
162
void CommandObjectMultiword::Execute(const char *args_string,
163
CommandReturnObject &result) {
164
Args args(args_string);
165
const size_t argc = args.GetArgumentCount();
166
if (argc == 0) {
167
this->CommandObject::GenerateHelpText(result);
168
return;
169
}
170
171
auto sub_command = args[0].ref();
172
if (sub_command.empty()) {
173
result.AppendError("Need to specify a non-empty subcommand.");
174
return;
175
}
176
177
if (m_subcommand_dict.empty()) {
178
result.AppendErrorWithFormat("'%s' does not have any subcommands.\n",
179
GetCommandName().str().c_str());
180
return;
181
}
182
183
StringList matches;
184
CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
185
if (sub_cmd_obj != nullptr) {
186
// Now call CommandObject::Execute to process options in `rest_of_line`.
187
// From there the command-specific version of Execute will be called, with
188
// the processed arguments.
189
190
args.Shift();
191
sub_cmd_obj->Execute(args_string, result);
192
return;
193
}
194
195
std::string error_msg;
196
const size_t num_subcmd_matches = matches.GetSize();
197
if (num_subcmd_matches > 0)
198
error_msg.assign("ambiguous command ");
199
else
200
error_msg.assign("invalid command ");
201
202
error_msg.append("'");
203
error_msg.append(std::string(GetCommandName()));
204
error_msg.append(" ");
205
error_msg.append(std::string(sub_command));
206
error_msg.append("'.");
207
208
if (num_subcmd_matches > 0) {
209
error_msg.append(" Possible completions:");
210
for (const std::string &match : matches) {
211
error_msg.append("\n\t");
212
error_msg.append(match);
213
}
214
}
215
error_msg.append("\n");
216
result.AppendRawError(error_msg.c_str());
217
}
218
219
void CommandObjectMultiword::GenerateHelpText(Stream &output_stream) {
220
// First time through here, generate the help text for the object and push it
221
// to the return result object as well
222
223
CommandObject::GenerateHelpText(output_stream);
224
output_stream.PutCString("\nThe following subcommands are supported:\n\n");
225
226
CommandMap::iterator pos;
227
uint32_t max_len = FindLongestCommandWord(m_subcommand_dict);
228
229
if (max_len)
230
max_len += 4; // Indent the output by 4 spaces.
231
232
for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
233
std::string indented_command(" ");
234
indented_command.append(pos->first);
235
if (pos->second->WantsRawCommandString()) {
236
std::string help_text(std::string(pos->second->GetHelp()));
237
help_text.append(" Expects 'raw' input (see 'help raw-input'.)");
238
m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
239
"--", help_text, max_len);
240
} else
241
m_interpreter.OutputFormattedHelpText(output_stream, indented_command,
242
"--", pos->second->GetHelp(),
243
max_len);
244
}
245
246
output_stream.PutCString("\nFor more help on any particular subcommand, type "
247
"'help <command> <subcommand>'.\n");
248
}
249
250
void CommandObjectMultiword::HandleCompletion(CompletionRequest &request) {
251
auto arg0 = request.GetParsedLine()[0].ref();
252
if (request.GetCursorIndex() == 0) {
253
StringList new_matches, descriptions;
254
AddNamesMatchingPartialString(m_subcommand_dict, arg0, new_matches,
255
&descriptions);
256
request.AddCompletions(new_matches, descriptions);
257
258
if (new_matches.GetSize() == 1 &&
259
new_matches.GetStringAtIndex(0) != nullptr &&
260
(arg0 == new_matches.GetStringAtIndex(0))) {
261
StringList temp_matches;
262
CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
263
if (cmd_obj != nullptr) {
264
if (request.GetParsedLine().GetArgumentCount() != 1) {
265
request.GetParsedLine().Shift();
266
request.AppendEmptyArgument();
267
cmd_obj->HandleCompletion(request);
268
}
269
}
270
}
271
return;
272
}
273
274
StringList new_matches;
275
CommandObject *sub_command_object = GetSubcommandObject(arg0, &new_matches);
276
277
// The subcommand is ambiguous. The completion isn't meaningful.
278
if (!sub_command_object)
279
return;
280
281
// Remove the one match that we got from calling GetSubcommandObject.
282
new_matches.DeleteStringAtIndex(0);
283
request.AddCompletions(new_matches);
284
request.ShiftArguments();
285
sub_command_object->HandleCompletion(request);
286
}
287
288
std::optional<std::string>
289
CommandObjectMultiword::GetRepeatCommand(Args &current_command_args,
290
uint32_t index) {
291
index++;
292
if (current_command_args.GetArgumentCount() <= index)
293
return std::nullopt;
294
CommandObject *sub_command_object =
295
GetSubcommandObject(current_command_args[index].ref());
296
if (sub_command_object == nullptr)
297
return std::nullopt;
298
return sub_command_object->GetRepeatCommand(current_command_args, index);
299
}
300
301
CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter,
302
const char *name, const char *help,
303
const char *syntax, uint32_t flags)
304
: CommandObject(interpreter, name, help, syntax, flags) {}
305
306
CommandObjectProxy::~CommandObjectProxy() = default;
307
308
Options *CommandObjectProxy::GetOptions() {
309
CommandObject *proxy_command = GetProxyCommandObject();
310
if (proxy_command)
311
return proxy_command->GetOptions();
312
return CommandObject::GetOptions();
313
}
314
315
llvm::StringRef CommandObjectProxy::GetHelp() {
316
CommandObject *proxy_command = GetProxyCommandObject();
317
if (proxy_command)
318
return proxy_command->GetHelp();
319
return CommandObject::GetHelp();
320
}
321
322
llvm::StringRef CommandObjectProxy::GetSyntax() {
323
CommandObject *proxy_command = GetProxyCommandObject();
324
if (proxy_command)
325
return proxy_command->GetSyntax();
326
return CommandObject::GetSyntax();
327
}
328
329
llvm::StringRef CommandObjectProxy::GetHelpLong() {
330
CommandObject *proxy_command = GetProxyCommandObject();
331
if (proxy_command)
332
return proxy_command->GetHelpLong();
333
return CommandObject::GetHelpLong();
334
}
335
336
bool CommandObjectProxy::IsRemovable() const {
337
const CommandObject *proxy_command =
338
const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
339
if (proxy_command)
340
return proxy_command->IsRemovable();
341
return false;
342
}
343
344
bool CommandObjectProxy::IsMultiwordObject() {
345
CommandObject *proxy_command = GetProxyCommandObject();
346
if (proxy_command)
347
return proxy_command->IsMultiwordObject();
348
return false;
349
}
350
351
CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() {
352
CommandObject *proxy_command = GetProxyCommandObject();
353
if (proxy_command)
354
return proxy_command->GetAsMultiwordCommand();
355
return nullptr;
356
}
357
358
void CommandObjectProxy::GenerateHelpText(Stream &result) {
359
CommandObject *proxy_command = GetProxyCommandObject();
360
if (proxy_command)
361
proxy_command->GenerateHelpText(result);
362
else
363
CommandObject::GenerateHelpText(result);
364
}
365
366
lldb::CommandObjectSP
367
CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,
368
StringList *matches) {
369
CommandObject *proxy_command = GetProxyCommandObject();
370
if (proxy_command)
371
return proxy_command->GetSubcommandSP(sub_cmd, matches);
372
return lldb::CommandObjectSP();
373
}
374
375
CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd,
376
StringList *matches) {
377
CommandObject *proxy_command = GetProxyCommandObject();
378
if (proxy_command)
379
return proxy_command->GetSubcommandObject(sub_cmd, matches);
380
return nullptr;
381
}
382
383
bool CommandObjectProxy::LoadSubCommand(
384
llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
385
CommandObject *proxy_command = GetProxyCommandObject();
386
if (proxy_command)
387
return proxy_command->LoadSubCommand(cmd_name, command_sp);
388
return false;
389
}
390
391
bool CommandObjectProxy::WantsRawCommandString() {
392
CommandObject *proxy_command = GetProxyCommandObject();
393
if (proxy_command)
394
return proxy_command->WantsRawCommandString();
395
return false;
396
}
397
398
bool CommandObjectProxy::WantsCompletion() {
399
CommandObject *proxy_command = GetProxyCommandObject();
400
if (proxy_command)
401
return proxy_command->WantsCompletion();
402
return false;
403
}
404
405
void CommandObjectProxy::HandleCompletion(CompletionRequest &request) {
406
CommandObject *proxy_command = GetProxyCommandObject();
407
if (proxy_command)
408
proxy_command->HandleCompletion(request);
409
}
410
411
void CommandObjectProxy::HandleArgumentCompletion(
412
CompletionRequest &request, OptionElementVector &opt_element_vector) {
413
CommandObject *proxy_command = GetProxyCommandObject();
414
if (proxy_command)
415
proxy_command->HandleArgumentCompletion(request, opt_element_vector);
416
}
417
418
std::optional<std::string>
419
CommandObjectProxy::GetRepeatCommand(Args &current_command_args,
420
uint32_t index) {
421
CommandObject *proxy_command = GetProxyCommandObject();
422
if (proxy_command)
423
return proxy_command->GetRepeatCommand(current_command_args, index);
424
return std::nullopt;
425
}
426
427
llvm::StringRef CommandObjectProxy::GetUnsupportedError() {
428
return "command is not implemented";
429
}
430
431
void CommandObjectProxy::Execute(const char *args_string,
432
CommandReturnObject &result) {
433
if (CommandObject *proxy_command = GetProxyCommandObject())
434
proxy_command->Execute(args_string, result);
435
else
436
result.AppendError(GetUnsupportedError());
437
}
438
439