blob: b5553d65b8099beee28895f529dc6b0e829035dd [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- CommandObjectMultiword.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
10#include "lldb/Interpreter/CommandObjectMultiword.h"
11// C Includes
12// C++ Includes
13// Other libraries and framework includes
14// Project includes
15#include "lldb/Interpreter/CommandContext.h"
16#include "lldb/Interpreter/CommandInterpreter.h"
Jim Ingham84cdc152010-06-15 19:49:27 +000017#include "lldb/Interpreter/Options.h"
Chris Lattner24943d22010-06-08 16:52:24 +000018#include "lldb/Interpreter/CommandReturnObject.h"
19
20using namespace lldb;
21using namespace lldb_private;
22
23//-------------------------------------------------------------------------
24// CommandObjectMultiword
25//-------------------------------------------------------------------------
26
27CommandObjectMultiword::CommandObjectMultiword
28(
29 const char *name,
30 const char *help,
31 const char *syntax,
32 uint32_t flags
33) :
34 CommandObject (name, help, syntax, flags)
35{
36}
37
38CommandObjectMultiword::~CommandObjectMultiword ()
39{
40}
41
42CommandObjectSP
43CommandObjectMultiword::GetSubcommandSP (const char *sub_cmd, StringList *matches)
44{
45 CommandObjectSP return_cmd_sp;
46 CommandObject::CommandMap::iterator pos;
47
48 if (!m_subcommand_dict.empty())
49 {
50 pos = m_subcommand_dict.find (sub_cmd);
51 if (pos != m_subcommand_dict.end())
52 return_cmd_sp = pos->second;
53 else
54 {
55
56 StringList local_matches;
57 if (matches == NULL)
58 matches = &local_matches;
59 int num_matches = CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, sub_cmd, *matches);
60
61 if (num_matches == 1)
62 {
63 // Cleaner, but slightly less efficient would be to call back into this function, since I now
64 // know I have an exact match...
65
66 sub_cmd = matches->GetStringAtIndex(0);
67 pos = m_subcommand_dict.find(sub_cmd);
68 if (pos != m_subcommand_dict.end())
69 return_cmd_sp = pos->second;
70 }
71 }
72 }
73 return return_cmd_sp;
74}
75
76CommandObject *
77CommandObjectMultiword::GetSubcommandObject (const char *sub_cmd, StringList *matches)
78{
79 return GetSubcommandSP(sub_cmd, matches).get();
80}
81
82bool
83CommandObjectMultiword::LoadSubCommand (CommandObjectSP cmd_obj, const char *name,
84 CommandInterpreter *interpreter)
85{
86 CommandMap::iterator pos;
87 bool success = true;
88
89 pos = m_subcommand_dict.find(name);
90 if (pos == m_subcommand_dict.end())
91 {
92 m_subcommand_dict[name] = cmd_obj;
93 interpreter->CrossRegisterCommand (name, GetCommandName());
94 }
95 else
96 success = false;
97
98 return success;
99}
100
101bool
102CommandObjectMultiword::Execute
103(
104 Args& args,
105 CommandContext *context,
106 CommandInterpreter *interpreter,
107 CommandReturnObject &result
108)
109{
110 const size_t argc = args.GetArgumentCount();
111 if (argc == 0)
112 {
113 GenerateHelpText (result, interpreter);
114 }
115 else
116 {
117 const char *sub_command = args.GetArgumentAtIndex (0);
118
119 if (sub_command)
120 {
121 if (::strcasecmp (sub_command, "help") == 0)
122 {
123 GenerateHelpText (result, interpreter);
124 }
125 else if (!m_subcommand_dict.empty())
126 {
127 StringList matches;
128 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
129 if (sub_cmd_obj != NULL)
130 {
131 // Now call CommandObject::Execute to process and options in 'rest_of_line'. From there
132 // the command-specific version of Execute will be called, with the processed arguments.
133
134 args.Shift();
135
136 sub_cmd_obj->ExecuteWithOptions (args, context, interpreter, result);
137 }
138 else
139 {
140 std::string error_msg;
141 int num_subcmd_matches = matches.GetSize();
142 if (num_subcmd_matches > 0)
143 error_msg.assign ("ambiguous command ");
144 else
145 error_msg.assign ("invalid command ");
146
147 error_msg.append ("'");
148 error_msg.append (GetCommandName());
149 error_msg.append (" ");
150 error_msg.append (sub_command);
151 error_msg.append ("'");
152
153 if (num_subcmd_matches > 0)
154 {
155 error_msg.append (" Possible completions:");
156 for (int i = 0; i < num_subcmd_matches; i++)
157 {
158 error_msg.append ("\n\t");
159 error_msg.append (matches.GetStringAtIndex (i));
160 }
161 }
162 error_msg.append ("\n");
163 result.AppendRawError (error_msg.c_str(), error_msg.size());
164 result.SetStatus (eReturnStatusFailed);
165 }
166 }
167 else
168 {
169 result.AppendErrorWithFormat ("'%s' does not have any subcommands.\n", GetCommandName());
170 result.SetStatus (eReturnStatusFailed);
171 }
172 }
173 }
174
175 return result.Succeeded();
176}
177
178void
179CommandObjectMultiword::GenerateHelpText (CommandReturnObject &result, CommandInterpreter *interpreter)
180{
181 // First time through here, generate the help text for the object and
182 // push it to the return result object as well
183
184 StreamString &output_stream = result.GetOutputStream();
185 output_stream.PutCString ("The following subcommands are supported:\n\n");
186
187 CommandMap::iterator pos;
188 std::string longest_word = interpreter->FindLongestCommandWord (m_subcommand_dict);
189 uint32_t max_len = 0;
190
191 if (! longest_word.empty())
192 max_len = strlen (longest_word.c_str()) + 4; // Indent the output by 4 spaces.
193
194 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
195 {
196 std::string indented_command (" ");
197 indented_command.append (pos->first);
198 interpreter->OutputFormattedHelpText (result.GetOutputStream(), indented_command.c_str(), "--",
199 pos->second->GetHelp(), max_len);
200 }
201
202 output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n");
203
204 result.SetStatus (eReturnStatusSuccessFinishNoResult);
205}
206
207int
208CommandObjectMultiword::HandleCompletion
209(
210 Args &input,
211 int &cursor_index,
212 int &cursor_char_position,
213 int match_start_point,
214 int max_return_elements,
215 CommandInterpreter *interpreter,
216 StringList &matches
217)
218{
219 if (cursor_index == 0)
220 {
221 CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, input.GetArgumentAtIndex(0), matches);
222
223 if (matches.GetSize() == 1
224 && matches.GetStringAtIndex(0) != NULL
225 && strcmp (input.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0)
226 {
227 StringList temp_matches;
228 CommandObject *cmd_obj = GetSubcommandObject (input.GetArgumentAtIndex(0), &temp_matches);
229 if (cmd_obj != NULL)
230 {
231 matches.DeleteStringAtIndex (0);
232 input.Shift();
233 cursor_char_position = 0;
234 input.AppendArgument ("");
235 return cmd_obj->HandleCompletion (input, cursor_index, cursor_char_position, match_start_point,
236 max_return_elements, interpreter, matches);
237 }
238 else
239 return matches.GetSize();
240 }
241 else
242 return matches.GetSize();
243 }
244 else
245 {
246 CommandObject *sub_command_object = GetSubcommandObject (input.GetArgumentAtIndex(0), &matches);
247 if (sub_command_object == NULL)
248 {
249 return matches.GetSize();
250 }
251 else
252 {
253 // Remove the one match that we got from calling GetSubcommandObject.
254 matches.DeleteStringAtIndex(0);
255 input.Shift();
256 cursor_index--;
257 return sub_command_object->HandleCompletion (input, cursor_index, cursor_char_position, match_start_point,
258 max_return_elements, interpreter, matches);
259 }
260
261 }
262}
263