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