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 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 38 CommandObjectMultiword::~CommandObjectMultiword () 39 { 40 } 41 42 CommandObjectSP 43 CommandObjectMultiword::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 76 CommandObject * 77 CommandObjectMultiword::GetSubcommandObject (const char *sub_cmd, StringList *matches) 78 { 79 return GetSubcommandSP(sub_cmd, matches).get(); 80 } 81 82 bool 83 CommandObjectMultiword::LoadSubCommand 84 ( 85 CommandInterpreter &interpreter, 86 const char *name, 87 const CommandObjectSP& cmd_obj 88 ) 89 { 90 CommandMap::iterator pos; 91 bool success = true; 92 93 pos = m_subcommand_dict.find(name); 94 if (pos == m_subcommand_dict.end()) 95 { 96 m_subcommand_dict[name] = cmd_obj; 97 interpreter.CrossRegisterCommand (name, GetCommandName()); 98 } 99 else 100 success = false; 101 102 return success; 103 } 104 105 bool 106 CommandObjectMultiword::Execute 107 ( 108 CommandInterpreter &interpreter, 109 Args& args, 110 CommandReturnObject &result 111 ) 112 { 113 const size_t argc = args.GetArgumentCount(); 114 if (argc == 0) 115 { 116 GenerateHelpText (interpreter, result); 117 } 118 else 119 { 120 const char *sub_command = args.GetArgumentAtIndex (0); 121 122 if (sub_command) 123 { 124 if (::strcasecmp (sub_command, "help") == 0) 125 { 126 GenerateHelpText (interpreter, result); 127 } 128 else if (!m_subcommand_dict.empty()) 129 { 130 StringList matches; 131 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches); 132 if (sub_cmd_obj != NULL) 133 { 134 // Now call CommandObject::Execute to process and options in 'rest_of_line'. From there 135 // the command-specific version of Execute will be called, with the processed arguments. 136 137 args.Shift(); 138 139 sub_cmd_obj->ExecuteWithOptions (interpreter, args, result); 140 } 141 else 142 { 143 std::string error_msg; 144 int num_subcmd_matches = matches.GetSize(); 145 if (num_subcmd_matches > 0) 146 error_msg.assign ("ambiguous command "); 147 else 148 error_msg.assign ("invalid command "); 149 150 error_msg.append ("'"); 151 error_msg.append (GetCommandName()); 152 error_msg.append (" "); 153 error_msg.append (sub_command); 154 error_msg.append ("'"); 155 156 if (num_subcmd_matches > 0) 157 { 158 error_msg.append (" Possible completions:"); 159 for (int i = 0; i < num_subcmd_matches; i++) 160 { 161 error_msg.append ("\n\t"); 162 error_msg.append (matches.GetStringAtIndex (i)); 163 } 164 } 165 error_msg.append ("\n"); 166 result.AppendRawError (error_msg.c_str(), error_msg.size()); 167 result.SetStatus (eReturnStatusFailed); 168 } 169 } 170 else 171 { 172 result.AppendErrorWithFormat ("'%s' does not have any subcommands.\n", GetCommandName()); 173 result.SetStatus (eReturnStatusFailed); 174 } 175 } 176 } 177 178 return result.Succeeded(); 179 } 180 181 void 182 CommandObjectMultiword::GenerateHelpText (CommandInterpreter &interpreter, CommandReturnObject &result) 183 { 184 // First time through here, generate the help text for the object and 185 // push it to the return result object as well 186 187 StreamString &output_stream = result.GetOutputStream(); 188 output_stream.PutCString ("The following subcommands are supported:\n\n"); 189 190 CommandMap::iterator pos; 191 std::string longest_word = interpreter.FindLongestCommandWord (m_subcommand_dict); 192 uint32_t max_len = 0; 193 194 if (! longest_word.empty()) 195 max_len = strlen (longest_word.c_str()) + 4; // Indent the output by 4 spaces. 196 197 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) 198 { 199 std::string indented_command (" "); 200 indented_command.append (pos->first); 201 interpreter.OutputFormattedHelpText (result.GetOutputStream(), 202 indented_command.c_str(), 203 "--", 204 pos->second->GetHelp(), 205 max_len); 206 } 207 208 output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n"); 209 210 result.SetStatus (eReturnStatusSuccessFinishNoResult); 211 } 212 213 int 214 CommandObjectMultiword::HandleCompletion 215 ( 216 CommandInterpreter &interpreter, 217 Args &input, 218 int &cursor_index, 219 int &cursor_char_position, 220 int match_start_point, 221 int max_return_elements, 222 bool &word_complete, 223 StringList &matches 224 ) 225 { 226 // Any of the command matches will provide a complete word, otherwise the individual 227 // completers will override this. 228 word_complete = true; 229 230 if (cursor_index == 0) 231 { 232 CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, 233 input.GetArgumentAtIndex(0), 234 matches); 235 236 if (matches.GetSize() == 1 237 && matches.GetStringAtIndex(0) != NULL 238 && strcmp (input.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0) 239 { 240 StringList temp_matches; 241 CommandObject *cmd_obj = GetSubcommandObject (input.GetArgumentAtIndex(0), 242 &temp_matches); 243 if (cmd_obj != NULL) 244 { 245 matches.DeleteStringAtIndex (0); 246 input.Shift(); 247 cursor_char_position = 0; 248 input.AppendArgument (""); 249 return cmd_obj->HandleCompletion (interpreter, 250 input, cursor_index, 251 cursor_char_position, 252 match_start_point, 253 max_return_elements, 254 word_complete, 255 matches); 256 } 257 else 258 return matches.GetSize(); 259 } 260 else 261 return matches.GetSize(); 262 } 263 else 264 { 265 CommandObject *sub_command_object = GetSubcommandObject (input.GetArgumentAtIndex(0), 266 &matches); 267 if (sub_command_object == NULL) 268 { 269 return matches.GetSize(); 270 } 271 else 272 { 273 // Remove the one match that we got from calling GetSubcommandObject. 274 matches.DeleteStringAtIndex(0); 275 input.Shift(); 276 cursor_index--; 277 return sub_command_object->HandleCompletion (interpreter, 278 input, 279 cursor_index, 280 cursor_char_position, 281 match_start_point, 282 max_return_elements, 283 word_complete, 284 matches); 285 } 286 287 } 288 } 289 290