blob: 5ab7db62bb8b9a2e7aa2947cc95775dc4e7a5ce1 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- CommandObjectAlias.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 "CommandObjectAlias.h"
11
12
13// C Includes
14// C++ Includes
15// Other libraries and framework includes
16// Project includes
17#include "lldb/Interpreter/CommandObjectMultiword.h"
Jim Ingham84cdc152010-06-15 19:49:27 +000018#include "lldb/Interpreter/Args.h"
19#include "lldb/Interpreter/Options.h"
Chris Lattner24943d22010-06-08 16:52:24 +000020#include "lldb/Interpreter/CommandInterpreter.h"
21#include "lldb/Interpreter/CommandReturnObject.h"
22#include "lldb/Interpreter/CommandInterpreter.h"
23
24using namespace lldb;
25using namespace lldb_private;
26
27//-------------------------------------------------------------------------
28// CommandObjectAlias
29//-------------------------------------------------------------------------
30
31CommandObjectAlias::CommandObjectAlias () :
32 CommandObject ("alias",
33 "Allows users to define their own debugger command abbreviations.",
34 "alias <new_command> <old_command> [<options-for-aliased-command>]")
35{
36 SetHelpLong(
37"'alias' allows the user to create a short-cut or abbreviation for long \n\
38commands, multi-word commands, and commands that take particular options. \n\
39Below are some simple examples of how one might use the 'alias' command: \n\
40\n 'alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\
41 // command. \n\
42 'alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\
43 // command. Since breakpoint commands are two-word \n\
44 // commands, the user will still need to enter the \n\
45 // second word after 'bp', e.g. 'bp enable' or \n\
46 // 'bp delete'. \n\
47 'alias bpi breakpoint list' // Creates the abbreviation 'bpi' for the \n\
48 // two-word command 'breakpoint list'. \n\
49\nAn alias can include some options for the command, with the values either \n\
50filled in at the time the alias is created, or specified as positional \n\
51arguments, to be filled in when the alias is invoked. The following example \n\
52shows how to create aliases with options: \n\
53\n\
54 'alias bfl breakpoint set -f %1 -l %2' \n\
55\nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\
56options already part of the alias. So if the user wants to set a breakpoint \n\
57by file and line without explicitly having to use the -f and -l options, the \n\
58user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\
59for the actual arguments that will be passed when the alias command is used. \n\
60The number in the placeholder refers to the position/order the actual value \n\
61occupies when the alias is used. So all the occurrences of '%1' in the alias \n\
62will be replaced with the first argument, all the occurrences of '%2' in the \n\
63alias will be replaced with the second argument, and so on. This also allows \n\
64actual arguments to be used multiple times within an alias (see 'process \n\
65launch' example below). So in the 'bfl' case, the actual file value will be \n\
66filled in with the first argument following 'bfl' and the actual line number \n\
67value will be filled in with the second argument. The user would use this \n\
68alias as follows: \n\
69\n (dbg) alias bfl breakpoint set -f %1 -l %2 \n\
70 <... some time later ...> \n\
71 (dbg) bfl my-file.c 137 \n\
72\nThis would be the same as if the user had entered \n\
73'breakpoint set -f my-file.c -l 137'. \n\
74\nAnother example: \n\
75\n (dbg) alias pltty process launch -s -o %1 -e %1 \n\
76 (dbg) pltty /dev/tty0 \n\
77 // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\
78\nIf the user always wanted to pass the same value to a particular option, the \n\
79alias could be defined with that value directly in the alias as a constant, \n\
80rather than using a positional placeholder: \n\
81\n alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\
82 // 3 of whatever file is indicated. \n");
83
84}
85
86CommandObjectAlias::~CommandObjectAlias ()
87{
88}
89
90
91bool
92CommandObjectAlias::Execute (Args& args, CommandContext *context, CommandInterpreter *interpreter,
93 CommandReturnObject &result)
94{
95 const int argc = args.GetArgumentCount();
96
97 if (argc < 2)
98 {
99 result.AppendError ("'alias' requires at least two arguments");
100 result.SetStatus (eReturnStatusFailed);
101 return false;
102 }
103
104 const std::string alias_command = args.GetArgumentAtIndex(0);
105 const std::string actual_command = args.GetArgumentAtIndex(1);
106
107 args.Shift(); // Shift the alias command word off the argument vector.
108 args.Shift(); // Shift the old command word off the argument vector.
109
110 // Verify that the command is alias'able, and get the appropriate command object.
111
112 if (interpreter->CommandExists (alias_command.c_str()))
113 {
114 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
115 alias_command.c_str());
116 result.SetStatus (eReturnStatusFailed);
117 }
118 else
119 {
120 CommandObjectSP command_obj_sp(interpreter->GetCommandSP (actual_command.c_str()));
121 CommandObjectSP subcommand_obj_sp;
122 bool use_subcommand = false;
123 if (command_obj_sp.get())
124 {
125 CommandObject *cmd_obj = command_obj_sp.get();
126 CommandObject *sub_cmd_obj;
127 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
128 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
129
130 if (cmd_obj->IsMultiwordObject())
131 {
132 if (argc >= 3)
133 {
134 const std::string sub_command = args.GetArgumentAtIndex(0);
135 assert (sub_command.length() != 0);
136 subcommand_obj_sp =
137 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str()));
138 if (subcommand_obj_sp.get())
139 {
140 sub_cmd_obj = subcommand_obj_sp.get();
141 use_subcommand = true;
142 args.Shift(); // Shift the sub_command word off the argument vector.
143 }
144 else
145 {
146 result.AppendErrorWithFormat ("Error occurred while attempting to look up command '%s %s'.\n",
147 alias_command.c_str(), sub_command.c_str());
148 result.SetStatus (eReturnStatusFailed);
149 return false;
150 }
151 }
152 }
153
154 // Verify & handle any options/arguments passed to the alias command
155
156 if (args.GetArgumentCount () > 0)
157 {
158 if ((!use_subcommand && (cmd_obj->WantsRawCommandString()))
159 || (use_subcommand && (sub_cmd_obj->WantsRawCommandString())))
160 {
161 result.AppendErrorWithFormat ("'%s' cannot be aliased with any options or arguments.\n",
162 (use_subcommand ? sub_cmd_obj->GetCommandName()
163 : cmd_obj->GetCommandName()));
164 result.SetStatus (eReturnStatusFailed);
165 return false;
166 }
167
168 // options or arguments have been passed to the alias command, and must be verified & processed here.
169 if ((!use_subcommand && (cmd_obj->GetOptions() != NULL))
170 || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL)))
171 {
172 Options *options;
173 if (use_subcommand)
174 options = sub_cmd_obj->GetOptions();
175 else
176 options = cmd_obj->GetOptions();
177 options->ResetOptionValues ();
178 args.Unshift ("dummy_arg");
179 args.ParseAliasOptions (*options, result, option_arg_vector);
180 args.Shift ();
181 if (result.Succeeded())
182 options->VerifyPartialOptions (result);
183 if (!result.Succeeded())
184 return false;
185 }
186 else
187 {
188 for (int i = 0; i < args.GetArgumentCount(); ++i)
189 option_arg_vector->push_back (OptionArgPair ("<argument>",
190 std::string (args.GetArgumentAtIndex (i))));
191 }
192 }
193
194 // Create the alias.
195
196 if (interpreter->AliasExists (alias_command.c_str())
197 || interpreter->UserCommandExists (alias_command.c_str()))
198 {
199 OptionArgVectorSP tmp_option_arg_sp (interpreter->GetAliasOptions (alias_command.c_str()));
200 if (tmp_option_arg_sp.get())
201 {
202 if (option_arg_vector->size() == 0)
203 interpreter->RemoveAliasOptions (alias_command.c_str());
204 }
205 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", alias_command.c_str());
206 }
207
208 if (use_subcommand)
209 interpreter->AddAlias (alias_command.c_str(), subcommand_obj_sp);
210 else
211 interpreter->AddAlias (alias_command.c_str(), command_obj_sp);
212 if (option_arg_vector->size() > 0)
213 interpreter->AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
214 result.SetStatus (eReturnStatusSuccessFinishNoResult);
215 }
216 else
217 {
218 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str());
219 result.SetStatus (eReturnStatusFailed);
220 }
221 }
222
223 return result.Succeeded();
224}
225