blob: e12e99095dc8b73f4bf8171794f0b2c9c758e32f [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- Args.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
Daniel Malea93a64302012-12-05 00:20:57 +000010#include "lldb/lldb-python.h"
11
Chris Lattner30fdc8d2010-06-08 16:52:24 +000012// C Includes
Eli Friedman5661f922010-06-09 10:59:23 +000013#include <cstdlib>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000014// C++ Includes
15// Other libraries and framework includes
16// Project includes
Jim Ingham40af72e2010-06-15 19:49:27 +000017#include "lldb/Interpreter/Args.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000018#include "lldb/Core/Stream.h"
19#include "lldb/Core/StreamFile.h"
20#include "lldb/Core/StreamString.h"
Enrico Granata5548cb52013-01-28 23:47:25 +000021#include "lldb/DataFormatters/FormatManager.h"
Vince Harron5275aaa2015-01-15 20:08:35 +000022#include "lldb/Host/StringConvert.h"
Jim Ingham40af72e2010-06-15 19:49:27 +000023#include "lldb/Interpreter/Options.h"
Zachary Turnerd37221d2014-07-09 16:31:49 +000024#include "lldb/Interpreter/CommandInterpreter.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000025#include "lldb/Interpreter/CommandReturnObject.h"
Greg Claytonb9d5df52012-12-06 22:49:16 +000026#include "lldb/Target/Process.h"
Jason Molendab57e4a12013-11-04 09:33:30 +000027#include "lldb/Target/StackFrame.h"
Greg Claytonb9d5df52012-12-06 22:49:16 +000028#include "lldb/Target/Target.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000029
Chris Lattner30fdc8d2010-06-08 16:52:24 +000030using namespace lldb;
31using namespace lldb_private;
32
Chris Lattner30fdc8d2010-06-08 16:52:24 +000033//----------------------------------------------------------------------
34// Args constructor
35//----------------------------------------------------------------------
Pavel Labath00b7f952015-03-02 12:46:22 +000036Args::Args (llvm::StringRef command) :
Chris Lattner30fdc8d2010-06-08 16:52:24 +000037 m_args(),
Greg Clayton8b82f082011-04-12 05:54:46 +000038 m_argv(),
39 m_args_quote_char()
Chris Lattner30fdc8d2010-06-08 16:52:24 +000040{
Pavel Labath00b7f952015-03-02 12:46:22 +000041 SetCommandString (command);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000042}
43
44
Chris Lattner30fdc8d2010-06-08 16:52:24 +000045//----------------------------------------------------------------------
Greg Clayton8b82f082011-04-12 05:54:46 +000046// We have to be very careful on the copy constructor of this class
47// to make sure we copy all of the string values, but we can't copy the
48// rhs.m_argv into m_argv since it will point to the "const char *" c
49// strings in rhs.m_args. We need to copy the string list and update our
50// own m_argv appropriately.
51//----------------------------------------------------------------------
52Args::Args (const Args &rhs) :
53 m_args (rhs.m_args),
54 m_argv (),
55 m_args_quote_char(rhs.m_args_quote_char)
56{
57 UpdateArgvFromArgs();
58}
59
60//----------------------------------------------------------------------
61// We have to be very careful on the copy constructor of this class
62// to make sure we copy all of the string values, but we can't copy the
63// rhs.m_argv into m_argv since it will point to the "const char *" c
64// strings in rhs.m_args. We need to copy the string list and update our
65// own m_argv appropriately.
66//----------------------------------------------------------------------
67const Args &
68Args::operator= (const Args &rhs)
69{
70 // Make sure we aren't assigning to self
71 if (this != &rhs)
72 {
73 m_args = rhs.m_args;
74 m_args_quote_char = rhs.m_args_quote_char;
75 UpdateArgvFromArgs();
76 }
77 return *this;
78}
79
80//----------------------------------------------------------------------
Chris Lattner30fdc8d2010-06-08 16:52:24 +000081// Destructor
82//----------------------------------------------------------------------
83Args::~Args ()
84{
85}
86
87void
88Args::Dump (Stream *s)
89{
Greg Claytonc7bece562013-01-25 18:06:21 +000090 const size_t argc = m_argv.size();
91 for (size_t i=0; i<argc; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000092 {
93 s->Indent();
94 const char *arg_cstr = m_argv[i];
95 if (arg_cstr)
Greg Claytonc7bece562013-01-25 18:06:21 +000096 s->Printf("argv[%zi]=\"%s\"\n", i, arg_cstr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000097 else
Greg Claytonc7bece562013-01-25 18:06:21 +000098 s->Printf("argv[%zi]=NULL\n", i);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000099 }
100 s->EOL();
101}
102
103bool
Greg Claytonda91b172012-04-25 22:30:32 +0000104Args::GetCommandString (std::string &command) const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000105{
106 command.clear();
Greg Claytonc7bece562013-01-25 18:06:21 +0000107 const size_t argc = GetArgumentCount();
108 for (size_t i=0; i<argc; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000109 {
110 if (i > 0)
111 command += ' ';
112 command += m_argv[i];
113 }
114 return argc > 0;
115}
116
Caroline Tice2d5289d2010-12-10 00:26:54 +0000117bool
Greg Claytonda91b172012-04-25 22:30:32 +0000118Args::GetQuotedCommandString (std::string &command) const
Caroline Tice2d5289d2010-12-10 00:26:54 +0000119{
120 command.clear ();
Greg Claytonc7bece562013-01-25 18:06:21 +0000121 const size_t argc = GetArgumentCount();
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000122 for (size_t i = 0; i < argc; ++i)
Caroline Tice2d5289d2010-12-10 00:26:54 +0000123 {
124 if (i > 0)
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000125 command.append (1, ' ');
126 char quote_char = GetArgumentQuoteCharAtIndex(i);
127 if (quote_char)
Caroline Tice2d5289d2010-12-10 00:26:54 +0000128 {
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000129 command.append (1, quote_char);
130 command.append (m_argv[i]);
131 command.append (1, quote_char);
Caroline Tice2d5289d2010-12-10 00:26:54 +0000132 }
133 else
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000134 command.append (m_argv[i]);
Caroline Tice2d5289d2010-12-10 00:26:54 +0000135 }
136 return argc > 0;
137}
138
Pavel Labath00b7f952015-03-02 12:46:22 +0000139// A helper function for argument parsing.
140// Parses the initial part of the first argument using normal double quote rules:
141// backslash escapes the double quote and itself. The parsed string is appended to the second
142// argument. The function returns the unparsed portion of the string, starting at the closing
143// quote.
144static llvm::StringRef
145ParseDoubleQuotes(llvm::StringRef quoted, std::string &result)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000146{
Pavel Labath00b7f952015-03-02 12:46:22 +0000147 // Inside double quotes, '\' and '"' are special.
148 static const char *k_escapable_characters = "\"\\";
149 while (true)
150 {
151 // Skip over over regular characters and append them.
152 size_t regular = quoted.find_first_of(k_escapable_characters);
153 result += quoted.substr(0, regular);
154 quoted = quoted.substr(regular);
155
156 // If we have reached the end of string or the closing quote, we're done.
157 if (quoted.empty() || quoted.front() == '"')
158 break;
159
160 // We have found a backslash.
161 quoted = quoted.drop_front();
162
163 if (quoted.empty())
164 {
165 // A lone backslash at the end of string, let's just append it.
166 result += '\\';
167 break;
168 }
169
170 // If the character after the backslash is not a whitelisted escapable character, we
171 // leave the character sequence untouched.
172 if (strchr(k_escapable_characters, quoted.front()) == nullptr)
173 result += '\\';
174
175 result += quoted.front();
176 quoted = quoted.drop_front();
177 }
178
179 return quoted;
180}
181
182// A helper function for SetCommandString.
183// Parses a single argument from the command string, processing quotes and backslashes in a
184// shell-like manner. The parsed argument is appended to the m_args array. The function returns
185// the unparsed portion of the string, starting at the first unqouted, unescaped whitespace
186// character.
187llvm::StringRef
188Args::ParseSingleArgument(llvm::StringRef command)
189{
190 // Argument can be split into multiple discontiguous pieces,
191 // for example:
192 // "Hello ""World"
193 // this would result in a single argument "Hello World" (without/
194 // the quotes) since the quotes would be removed and there is
195 // not space between the strings.
196
197 std::string arg;
198
199 // Since we can have multiple quotes that form a single command
200 // in a command like: "Hello "world'!' (which will make a single
201 // argument "Hello world!") we remember the first quote character
202 // we encounter and use that for the quote character.
203 char first_quote_char = '\0';
204
205 bool arg_complete = false;
206 do
207 {
208 // Skip over over regular characters and append them.
209 size_t regular = command.find_first_of(" \t\"'`\\");
210 arg += command.substr(0, regular);
211 command = command.substr(regular);
212
213 if (command.empty())
214 break;
215
216 char special = command.front();
217 command = command.drop_front();
218 switch (special)
219 {
220 case '\\':
221 if (command.empty())
222 {
223 arg += '\\';
224 break;
225 }
226
227 // If the character after the backslash is not a whitelisted escapable character, we
228 // leave the character sequence untouched.
229 static const char *k_escapable_characters = " \t\\'\"`";
230 if (strchr(k_escapable_characters, command.front()) == nullptr)
231 arg += '\\';
232
233 arg += command.front();
234 command.drop_front();
235
236 break;
237
238 case ' ':
239 case '\t':
240 // We are not inside any quotes, we just found a space after an
241 // argument. We are done.
242 arg_complete = true;
243 break;
244
245 case '"':
246 case '\'':
247 case '`':
248 // We found the start of a quote scope.
249 if (first_quote_char == '\0')
250 first_quote_char = special;
251
252 if (special == '"')
253 command = ParseDoubleQuotes(command, arg);
254 else
255 {
256 // For single quotes, we simply skip ahead to the matching quote character
257 // (or the end of the string).
258 size_t quoted = command.find(special);
259 arg += command.substr(0, quoted);
260 command = command.substr(quoted);
261 }
262
263 // If we found a closing quote, skip it.
264 if (! command.empty())
265 command = command.drop_front();
266
267 break;
268 }
269 } while (!arg_complete);
270
271 m_args.push_back(arg);
272 m_args_quote_char.push_back (first_quote_char);
273 return command;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000274}
275
276void
Pavel Labath00b7f952015-03-02 12:46:22 +0000277Args::SetCommandString (llvm::StringRef command)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000278{
279 m_args.clear();
280 m_argv.clear();
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000281 m_args_quote_char.clear();
282
Pavel Labath00b7f952015-03-02 12:46:22 +0000283 static const char *k_space_separators = " \t";
284 command = command.ltrim(k_space_separators);
285 while (!command.empty())
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000286 {
Pavel Labath00b7f952015-03-02 12:46:22 +0000287 command = ParseSingleArgument(command);
288 command = command.ltrim(k_space_separators);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000289 }
Pavel Labath00b7f952015-03-02 12:46:22 +0000290
291 UpdateArgvFromArgs();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000292}
293
294void
295Args::UpdateArgsAfterOptionParsing()
296{
297 // Now m_argv might be out of date with m_args, so we need to fix that
298 arg_cstr_collection::const_iterator argv_pos, argv_end = m_argv.end();
299 arg_sstr_collection::iterator args_pos;
300 arg_quote_char_collection::iterator quotes_pos;
301
302 for (argv_pos = m_argv.begin(), args_pos = m_args.begin(), quotes_pos = m_args_quote_char.begin();
303 argv_pos != argv_end && args_pos != m_args.end();
304 ++argv_pos)
305 {
306 const char *argv_cstr = *argv_pos;
Ed Masted78c9572014-04-20 00:31:37 +0000307 if (argv_cstr == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000308 break;
309
310 while (args_pos != m_args.end())
311 {
312 const char *args_cstr = args_pos->c_str();
313 if (args_cstr == argv_cstr)
314 {
315 // We found the argument that matches the C string in the
316 // vector, so we can now look for the next one
317 ++args_pos;
318 ++quotes_pos;
319 break;
320 }
321 else
322 {
323 quotes_pos = m_args_quote_char.erase (quotes_pos);
324 args_pos = m_args.erase (args_pos);
325 }
326 }
327 }
328
329 if (args_pos != m_args.end())
330 m_args.erase (args_pos, m_args.end());
331
332 if (quotes_pos != m_args_quote_char.end())
333 m_args_quote_char.erase (quotes_pos, m_args_quote_char.end());
334}
335
336void
337Args::UpdateArgvFromArgs()
338{
339 m_argv.clear();
340 arg_sstr_collection::const_iterator pos, end = m_args.end();
341 for (pos = m_args.begin(); pos != end; ++pos)
342 m_argv.push_back(pos->c_str());
Ed Masted78c9572014-04-20 00:31:37 +0000343 m_argv.push_back(nullptr);
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000344 // Make sure we have enough arg quote chars in the array
345 if (m_args_quote_char.size() < m_args.size())
346 m_args_quote_char.resize (m_argv.size());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000347}
348
349size_t
350Args::GetArgumentCount() const
351{
352 if (m_argv.empty())
353 return 0;
354 return m_argv.size() - 1;
355}
356
357const char *
358Args::GetArgumentAtIndex (size_t idx) const
359{
360 if (idx < m_argv.size())
361 return m_argv[idx];
Ed Masted78c9572014-04-20 00:31:37 +0000362 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000363}
364
365char
366Args::GetArgumentQuoteCharAtIndex (size_t idx) const
367{
368 if (idx < m_args_quote_char.size())
369 return m_args_quote_char[idx];
370 return '\0';
371}
372
373char **
374Args::GetArgumentVector()
375{
376 if (!m_argv.empty())
377 return (char **)&m_argv[0];
Ed Masted78c9572014-04-20 00:31:37 +0000378 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000379}
380
381const char **
382Args::GetConstArgumentVector() const
383{
384 if (!m_argv.empty())
385 return (const char **)&m_argv[0];
Ed Masted78c9572014-04-20 00:31:37 +0000386 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000387}
388
389void
390Args::Shift ()
391{
392 // Don't pop the last NULL terminator from the argv array
393 if (m_argv.size() > 1)
394 {
395 m_argv.erase(m_argv.begin());
396 m_args.pop_front();
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000397 if (!m_args_quote_char.empty())
398 m_args_quote_char.erase(m_args_quote_char.begin());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000399 }
400}
401
402const char *
403Args::Unshift (const char *arg_cstr, char quote_char)
404{
405 m_args.push_front(arg_cstr);
406 m_argv.insert(m_argv.begin(), m_args.front().c_str());
407 m_args_quote_char.insert(m_args_quote_char.begin(), quote_char);
408 return GetArgumentAtIndex (0);
409}
410
411void
412Args::AppendArguments (const Args &rhs)
413{
414 const size_t rhs_argc = rhs.GetArgumentCount();
415 for (size_t i=0; i<rhs_argc; ++i)
416 AppendArgument(rhs.GetArgumentAtIndex(i));
417}
418
Greg Clayton982c9762011-11-03 21:22:33 +0000419void
420Args::AppendArguments (const char **argv)
421{
422 if (argv)
423 {
424 for (uint32_t i=0; argv[i]; ++i)
425 AppendArgument(argv[i]);
426 }
427}
428
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000429const char *
430Args::AppendArgument (const char *arg_cstr, char quote_char)
431{
432 return InsertArgumentAtIndex (GetArgumentCount(), arg_cstr, quote_char);
433}
434
435const char *
436Args::InsertArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
437{
438 // Since we are using a std::list to hold onto the copied C string and
439 // we don't have direct access to the elements, we have to iterate to
440 // find the value.
441 arg_sstr_collection::iterator pos, end = m_args.end();
442 size_t i = idx;
443 for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
444 --i;
445
446 pos = m_args.insert(pos, arg_cstr);
447
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000448 if (idx >= m_args_quote_char.size())
449 {
450 m_args_quote_char.resize(idx + 1);
451 m_args_quote_char[idx] = quote_char;
452 }
453 else
454 m_args_quote_char.insert(m_args_quote_char.begin() + idx, quote_char);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000455
456 UpdateArgvFromArgs();
457 return GetArgumentAtIndex(idx);
458}
459
460const char *
461Args::ReplaceArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
462{
463 // Since we are using a std::list to hold onto the copied C string and
464 // we don't have direct access to the elements, we have to iterate to
465 // find the value.
466 arg_sstr_collection::iterator pos, end = m_args.end();
467 size_t i = idx;
468 for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
469 --i;
470
471 if (pos != end)
472 {
473 pos->assign(arg_cstr);
474 assert(idx < m_argv.size() - 1);
475 m_argv[idx] = pos->c_str();
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000476 if (idx >= m_args_quote_char.size())
477 m_args_quote_char.resize(idx + 1);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000478 m_args_quote_char[idx] = quote_char;
479 return GetArgumentAtIndex(idx);
480 }
Ed Masted78c9572014-04-20 00:31:37 +0000481 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000482}
483
484void
485Args::DeleteArgumentAtIndex (size_t idx)
486{
487 // Since we are using a std::list to hold onto the copied C string and
488 // we don't have direct access to the elements, we have to iterate to
489 // find the value.
490 arg_sstr_collection::iterator pos, end = m_args.end();
491 size_t i = idx;
492 for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
493 --i;
494
495 if (pos != end)
496 {
497 m_args.erase (pos);
498 assert(idx < m_argv.size() - 1);
499 m_argv.erase(m_argv.begin() + idx);
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000500 if (idx < m_args_quote_char.size())
501 m_args_quote_char.erase(m_args_quote_char.begin() + idx);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000502 }
503}
504
505void
Greg Claytonc7bece562013-01-25 18:06:21 +0000506Args::SetArguments (size_t argc, const char **argv)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000507{
508 // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is
509 // no need to clear it here.
510 m_args.clear();
511 m_args_quote_char.clear();
512
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000513 // First copy each string
Greg Clayton982c9762011-11-03 21:22:33 +0000514 for (size_t i=0; i<argc; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000515 {
516 m_args.push_back (argv[i]);
Greg Clayton6ad07dd2010-12-19 03:41:24 +0000517 if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`'))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000518 m_args_quote_char.push_back (argv[i][0]);
519 else
520 m_args_quote_char.push_back ('\0');
521 }
522
523 UpdateArgvFromArgs();
524}
525
Greg Clayton982c9762011-11-03 21:22:33 +0000526void
527Args::SetArguments (const char **argv)
528{
529 // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is
530 // no need to clear it here.
531 m_args.clear();
532 m_args_quote_char.clear();
533
534 if (argv)
535 {
536 // First copy each string
537 for (size_t i=0; argv[i]; ++i)
538 {
539 m_args.push_back (argv[i]);
540 if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`'))
541 m_args_quote_char.push_back (argv[i][0]);
542 else
543 m_args_quote_char.push_back ('\0');
544 }
545 }
546
547 UpdateArgvFromArgs();
548}
549
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000550
551Error
552Args::ParseOptions (Options &options)
553{
554 StreamString sstr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000555 Error error;
Virgile Belloe2607b52013-09-05 16:42:23 +0000556 Option *long_options = options.GetLongOptions();
Ed Masted78c9572014-04-20 00:31:37 +0000557 if (long_options == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000558 {
Greg Clayton86edbf42011-10-26 00:56:27 +0000559 error.SetErrorStringWithFormat("invalid long options");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000560 return error;
561 }
562
Zachary Turnerd37221d2014-07-09 16:31:49 +0000563 for (int i=0; long_options[i].definition != nullptr; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000564 {
Ed Masted78c9572014-04-20 00:31:37 +0000565 if (long_options[i].flag == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000566 {
Daniel Malea90b0c842012-12-05 20:24:57 +0000567 if (isprint8(long_options[i].val))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000568 {
Greg Clayton3bcdfc02012-12-04 00:32:51 +0000569 sstr << (char)long_options[i].val;
Zachary Turnerd37221d2014-07-09 16:31:49 +0000570 switch (long_options[i].definition->option_has_arg)
Greg Clayton3bcdfc02012-12-04 00:32:51 +0000571 {
572 default:
Virgile Belloe2607b52013-09-05 16:42:23 +0000573 case OptionParser::eNoArgument: break;
574 case OptionParser::eRequiredArgument: sstr << ':'; break;
575 case OptionParser::eOptionalArgument: sstr << "::"; break;
Greg Clayton3bcdfc02012-12-04 00:32:51 +0000576 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000577 }
578 }
579 }
Virgile Belloe2607b52013-09-05 16:42:23 +0000580 OptionParser::Prepare();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000581 int val;
582 while (1)
583 {
584 int long_options_index = -1;
Virgile Belloe2607b52013-09-05 16:42:23 +0000585 val = OptionParser::Parse(GetArgumentCount(),
Greg Claytonb7ad58a2013-04-04 20:35:24 +0000586 GetArgumentVector(),
587 sstr.GetData(),
588 long_options,
589 &long_options_index);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000590 if (val == -1)
591 break;
592
593 // Did we get an error?
594 if (val == '?')
595 {
Greg Clayton86edbf42011-10-26 00:56:27 +0000596 error.SetErrorStringWithFormat("unknown or ambiguous option");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000597 break;
598 }
599 // The option auto-set itself
600 if (val == 0)
601 continue;
602
603 ((Options *) &options)->OptionSeen (val);
604
605 // Lookup the long option index
606 if (long_options_index == -1)
607 {
608 for (int i=0;
Zachary Turnerd37221d2014-07-09 16:31:49 +0000609 long_options[i].definition || long_options[i].flag || long_options[i].val;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000610 ++i)
611 {
612 if (long_options[i].val == val)
613 {
614 long_options_index = i;
615 break;
616 }
617 }
618 }
619 // Call the callback with the option
Jason Molenda320e7b32014-10-16 01:26:51 +0000620 if (long_options_index >= 0 && long_options[long_options_index].definition)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000621 {
Zachary Turnerd37221d2014-07-09 16:31:49 +0000622 const OptionDefinition *def = long_options[long_options_index].definition;
623 CommandInterpreter &interpreter = options.GetInterpreter();
624 OptionValidator *validator = def->validator;
625 if (validator && !validator->IsValid(*interpreter.GetPlatform(true), interpreter.GetExecutionContext()))
626 {
627 error.SetErrorStringWithFormat("Option \"%s\" invalid. %s", def->long_option, def->validator->LongConditionString());
628 }
629 else
630 {
631 error = options.SetOptionValue(long_options_index,
Todd Fiala2c77a422014-10-10 01:11:39 +0000632 (def->option_has_arg == OptionParser::eNoArgument) ? nullptr : OptionParser::GetOptionArgument());
Zachary Turnerd37221d2014-07-09 16:31:49 +0000633 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000634 }
635 else
636 {
Greg Clayton86edbf42011-10-26 00:56:27 +0000637 error.SetErrorStringWithFormat("invalid option with value '%i'", val);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000638 }
639 if (error.Fail())
640 break;
641 }
642
643 // Update our ARGV now that get options has consumed all the options
Virgile Belloe2607b52013-09-05 16:42:23 +0000644 m_argv.erase(m_argv.begin(), m_argv.begin() + OptionParser::GetOptionIndex());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000645 UpdateArgsAfterOptionParsing ();
646 return error;
647}
648
649void
650Args::Clear ()
651{
652 m_args.clear ();
653 m_argv.clear ();
654 m_args_quote_char.clear();
655}
656
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000657lldb::addr_t
Greg Claytonb9d5df52012-12-06 22:49:16 +0000658Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::addr_t fail_value, Error *error_ptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000659{
Greg Claytonb9d5df52012-12-06 22:49:16 +0000660 bool error_set = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000661 if (s && s[0])
662 {
Ed Masted78c9572014-04-20 00:31:37 +0000663 char *end = nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000664 lldb::addr_t addr = ::strtoull (s, &end, 0);
665 if (*end == '\0')
666 {
Greg Claytonb9d5df52012-12-06 22:49:16 +0000667 if (error_ptr)
668 error_ptr->Clear();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000669 return addr; // All characters were used, return the result
670 }
671 // Try base 16 with no prefix...
672 addr = ::strtoull (s, &end, 16);
673 if (*end == '\0')
674 {
Greg Claytonb9d5df52012-12-06 22:49:16 +0000675 if (error_ptr)
676 error_ptr->Clear();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000677 return addr; // All characters were used, return the result
678 }
Greg Claytonb9d5df52012-12-06 22:49:16 +0000679
680 if (exe_ctx)
681 {
682 Target *target = exe_ctx->GetTargetPtr();
683 if (target)
684 {
685 lldb::ValueObjectSP valobj_sp;
686 EvaluateExpressionOptions options;
687 options.SetCoerceToId(false);
688 options.SetUnwindOnError(true);
689 options.SetKeepInMemory(false);
Jim Ingham6fbc48b2013-11-07 00:11:47 +0000690 options.SetTryAllThreads(true);
Greg Claytonb9d5df52012-12-06 22:49:16 +0000691
Jim Ingham1624a2d2014-05-05 02:26:40 +0000692 ExpressionResults expr_result = target->EvaluateExpression(s,
Enrico Granataca0e5ad2014-10-09 23:09:40 +0000693 exe_ctx->GetFramePtr(),
694 valobj_sp,
695 options);
Greg Claytonb9d5df52012-12-06 22:49:16 +0000696
697 bool success = false;
Jim Ingham8646d3c2014-05-05 02:47:44 +0000698 if (expr_result == eExpressionCompleted)
Greg Claytonb9d5df52012-12-06 22:49:16 +0000699 {
Enrico Granataca0e5ad2014-10-09 23:09:40 +0000700 if (valobj_sp)
701 valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable(valobj_sp->GetDynamicValueType(), true);
Greg Claytonb9d5df52012-12-06 22:49:16 +0000702 // Get the address to watch.
Enrico Granataca0e5ad2014-10-09 23:09:40 +0000703 if (valobj_sp)
704 addr = valobj_sp->GetValueAsUnsigned(fail_value, &success);
Greg Claytonb9d5df52012-12-06 22:49:16 +0000705 if (success)
706 {
707 if (error_ptr)
708 error_ptr->Clear();
709 return addr;
710 }
711 else
712 {
713 if (error_ptr)
714 {
715 error_set = true;
716 error_ptr->SetErrorStringWithFormat("address expression \"%s\" resulted in a value whose type can't be converted to an address: %s", s, valobj_sp->GetTypeName().GetCString());
717 }
718 }
719
720 }
721 else
722 {
723 // Since the compiler can't handle things like "main + 12" we should
724 // try to do this for now. The compliler doesn't like adding offsets
725 // to function pointer types.
Greg Claytonbc43cab2013-04-03 21:37:16 +0000726 static RegularExpression g_symbol_plus_offset_regex("^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$");
727 RegularExpression::Match regex_match(3);
728 if (g_symbol_plus_offset_regex.Execute(s, &regex_match))
Greg Claytonb9d5df52012-12-06 22:49:16 +0000729 {
730 uint64_t offset = 0;
731 bool add = true;
732 std::string name;
733 std::string str;
Greg Claytonbc43cab2013-04-03 21:37:16 +0000734 if (regex_match.GetMatchAtIndex(s, 1, name))
Greg Claytonb9d5df52012-12-06 22:49:16 +0000735 {
Greg Claytonbc43cab2013-04-03 21:37:16 +0000736 if (regex_match.GetMatchAtIndex(s, 2, str))
Greg Claytonb9d5df52012-12-06 22:49:16 +0000737 {
738 add = str[0] == '+';
739
Greg Claytonbc43cab2013-04-03 21:37:16 +0000740 if (regex_match.GetMatchAtIndex(s, 3, str))
Greg Claytonb9d5df52012-12-06 22:49:16 +0000741 {
Vince Harron5275aaa2015-01-15 20:08:35 +0000742 offset = StringConvert::ToUInt64(str.c_str(), 0, 0, &success);
Greg Claytonb9d5df52012-12-06 22:49:16 +0000743
744 if (success)
745 {
746 Error error;
747 addr = StringToAddress (exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS, &error);
748 if (addr != LLDB_INVALID_ADDRESS)
749 {
750 if (add)
751 return addr + offset;
752 else
753 return addr - offset;
754 }
755 }
756 }
757 }
758 }
759 }
760
761 if (error_ptr)
762 {
763 error_set = true;
764 error_ptr->SetErrorStringWithFormat("address expression \"%s\" evaluation failed", s);
765 }
766 }
767 }
768 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000769 }
Greg Claytonb9d5df52012-12-06 22:49:16 +0000770 if (error_ptr)
771 {
772 if (!error_set)
773 error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", s);
774 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000775 return fail_value;
776}
777
Greg Clayton30820f02013-03-05 23:52:49 +0000778const char *
779Args::StripSpaces (std::string &s, bool leading, bool trailing, bool return_null_if_empty)
780{
781 static const char *k_white_space = " \t\v";
782 if (!s.empty())
783 {
784 if (leading)
785 {
786 size_t pos = s.find_first_not_of (k_white_space);
787 if (pos == std::string::npos)
788 s.clear();
789 else if (pos > 0)
790 s.erase(0, pos);
791 }
792
793 if (trailing)
794 {
795 size_t rpos = s.find_last_not_of(k_white_space);
796 if (rpos != std::string::npos && rpos + 1 < s.size())
797 s.erase(rpos + 1);
798 }
799 }
800 if (return_null_if_empty && s.empty())
Ed Masted78c9572014-04-20 00:31:37 +0000801 return nullptr;
Greg Clayton30820f02013-03-05 23:52:49 +0000802 return s.c_str();
803}
804
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000805bool
806Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr)
807{
Pavel Labathdf50f942015-02-16 13:13:39 +0000808 llvm::StringRef ref = llvm::StringRef(s).trim();
809 if (ref.equals_lower("false") ||
810 ref.equals_lower("off") ||
811 ref.equals_lower("no") ||
812 ref.equals_lower("0"))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000813 {
Pavel Labathdf50f942015-02-16 13:13:39 +0000814 if (success_ptr)
815 *success_ptr = true;
816 return false;
817 }
818 else
819 if (ref.equals_lower("true") ||
820 ref.equals_lower("on") ||
821 ref.equals_lower("yes") ||
822 ref.equals_lower("1"))
823 {
824 if (success_ptr) *success_ptr = true;
825 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000826 }
827 if (success_ptr) *success_ptr = false;
828 return fail_value;
829}
830
Zachary Turner3e7442b2015-01-12 20:44:02 +0000831char
832Args::StringToChar(const char *s, char fail_value, bool *success_ptr)
833{
834 bool success = false;
835 char result = fail_value;
836
837 if (s)
838 {
839 size_t length = strlen(s);
840 if (length == 1)
841 {
842 success = true;
843 result = s[0];
844 }
845 }
846 if (success_ptr)
847 *success_ptr = success;
848 return result;
849}
850
Greg Claytonded470d2011-03-19 01:12:21 +0000851const char *
852Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t &update)
853{
854 major = UINT32_MAX;
855 minor = UINT32_MAX;
856 update = UINT32_MAX;
857
858 if (s && s[0])
859 {
Ed Masted78c9572014-04-20 00:31:37 +0000860 char *pos = nullptr;
Greg Claytonc7bece562013-01-25 18:06:21 +0000861 unsigned long uval32 = ::strtoul (s, &pos, 0);
Greg Claytonded470d2011-03-19 01:12:21 +0000862 if (pos == s)
863 return s;
864 major = uval32;
865 if (*pos == '\0')
866 {
867 return pos; // Decoded major and got end of string
868 }
869 else if (*pos == '.')
870 {
871 const char *minor_cstr = pos + 1;
872 uval32 = ::strtoul (minor_cstr, &pos, 0);
873 if (pos == minor_cstr)
874 return pos; // Didn't get any digits for the minor version...
875 minor = uval32;
876 if (*pos == '.')
877 {
878 const char *update_cstr = pos + 1;
879 uval32 = ::strtoul (update_cstr, &pos, 0);
880 if (pos == update_cstr)
881 return pos;
882 update = uval32;
883 }
884 return pos;
885 }
886 }
Ed Masted78c9572014-04-20 00:31:37 +0000887 return nullptr;
Greg Claytonded470d2011-03-19 01:12:21 +0000888}
889
Greg Clayton144f3a92011-11-15 03:53:30 +0000890const char *
891Args::GetShellSafeArgument (const char *unsafe_arg, std::string &safe_arg)
892{
893 safe_arg.assign (unsafe_arg);
894 size_t prev_pos = 0;
895 while (prev_pos < safe_arg.size())
896 {
897 // Escape spaces and quotes
898 size_t pos = safe_arg.find_first_of(" '\"", prev_pos);
899 if (pos != std::string::npos)
900 {
901 safe_arg.insert (pos, 1, '\\');
902 prev_pos = pos + 2;
903 }
904 else
905 break;
906 }
907 return safe_arg.c_str();
908}
909
Greg Claytonded470d2011-03-19 01:12:21 +0000910
Greg Claytonc7bece562013-01-25 18:06:21 +0000911int64_t
Greg Claytoncf0e4f02011-10-07 18:58:12 +0000912Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000913{
Greg Claytoncf0e4f02011-10-07 18:58:12 +0000914 if (enum_values)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000915 {
Greg Claytoncf0e4f02011-10-07 18:58:12 +0000916 if (s && s[0])
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000917 {
Ed Masted78c9572014-04-20 00:31:37 +0000918 for (int i = 0; enum_values[i].string_value != nullptr ; i++)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000919 {
Greg Claytoncf0e4f02011-10-07 18:58:12 +0000920 if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value)
921 {
922 error.Clear();
923 return enum_values[i].value;
924 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000925 }
926 }
Greg Claytoncf0e4f02011-10-07 18:58:12 +0000927
928 StreamString strm;
929 strm.PutCString ("invalid enumeration value, valid values are: ");
Ed Masted78c9572014-04-20 00:31:37 +0000930 for (int i = 0; enum_values[i].string_value != nullptr; i++)
Greg Claytoncf0e4f02011-10-07 18:58:12 +0000931 {
932 strm.Printf ("%s\"%s\"",
933 i > 0 ? ", " : "",
934 enum_values[i].string_value);
935 }
936 error.SetErrorString(strm.GetData());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000937 }
Greg Claytoncf0e4f02011-10-07 18:58:12 +0000938 else
939 {
940 error.SetErrorString ("invalid enumeration argument");
941 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000942 return fail_value;
943}
944
945ScriptLanguage
946Args::StringToScriptLanguage (const char *s, ScriptLanguage fail_value, bool *success_ptr)
947{
948 if (s && s[0])
949 {
950 if ((::strcasecmp (s, "python") == 0) ||
951 (::strcasecmp (s, "default") == 0 && eScriptLanguagePython == eScriptLanguageDefault))
952 {
953 if (success_ptr) *success_ptr = true;
954 return eScriptLanguagePython;
955 }
956 if (::strcasecmp (s, "none"))
957 {
958 if (success_ptr) *success_ptr = true;
959 return eScriptLanguageNone;
960 }
961 }
962 if (success_ptr) *success_ptr = false;
963 return fail_value;
964}
965
966Error
967Args::StringToFormat
968(
969 const char *s,
Greg Clayton68ebae62011-04-28 20:55:26 +0000970 lldb::Format &format,
Greg Claytonc7bece562013-01-25 18:06:21 +0000971 size_t *byte_size_ptr
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000972)
973{
974 format = eFormatInvalid;
975 Error error;
976
977 if (s && s[0])
978 {
Greg Clayton68ebae62011-04-28 20:55:26 +0000979 if (byte_size_ptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000980 {
Greg Clayton68ebae62011-04-28 20:55:26 +0000981 if (isdigit (s[0]))
982 {
Ed Masted78c9572014-04-20 00:31:37 +0000983 char *format_char = nullptr;
Greg Clayton68ebae62011-04-28 20:55:26 +0000984 unsigned long byte_size = ::strtoul (s, &format_char, 0);
985 if (byte_size != ULONG_MAX)
986 *byte_size_ptr = byte_size;
987 s = format_char;
988 }
989 else
990 *byte_size_ptr = 0;
991 }
992
Greg Claytonbb7f31f2011-06-23 21:22:24 +0000993 const bool partial_match_ok = true;
994 if (!FormatManager::GetFormatFromCString (s, partial_match_ok, format))
Greg Clayton68ebae62011-04-28 20:55:26 +0000995 {
Greg Claytonbb7f31f2011-06-23 21:22:24 +0000996 StreamString error_strm;
997 error_strm.Printf ("Invalid format character or name '%s'. Valid values are:\n", s);
Peter Collingbourne44c9b372011-06-24 01:12:22 +0000998 for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1))
Greg Clayton68ebae62011-04-28 20:55:26 +0000999 {
Greg Claytonbb7f31f2011-06-23 21:22:24 +00001000 char format_char = FormatManager::GetFormatAsFormatChar(f);
1001 if (format_char)
1002 error_strm.Printf ("'%c' or ", format_char);
1003
1004 error_strm.Printf ("\"%s\"", FormatManager::GetFormatAsCString(f));
1005 error_strm.EOL();
Greg Clayton68ebae62011-04-28 20:55:26 +00001006 }
Greg Claytonbb7f31f2011-06-23 21:22:24 +00001007
1008 if (byte_size_ptr)
1009 error_strm.PutCString ("An optional byte size can precede the format character.\n");
1010 error.SetErrorString(error_strm.GetString().c_str());
Greg Clayton68ebae62011-04-28 20:55:26 +00001011 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001012
1013 if (error.Fail())
1014 return error;
1015 }
1016 else
1017 {
Greg Clayton86edbf42011-10-26 00:56:27 +00001018 error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001019 }
1020 return error;
1021}
1022
Greg Clayton2443cbd2012-08-24 01:42:50 +00001023lldb::Encoding
1024Args::StringToEncoding (const char *s, lldb::Encoding fail_value)
1025{
1026 if (s && s[0])
1027 {
1028 if (strcmp(s, "uint") == 0)
1029 return eEncodingUint;
1030 else if (strcmp(s, "sint") == 0)
1031 return eEncodingSint;
1032 else if (strcmp(s, "ieee754") == 0)
1033 return eEncodingIEEE754;
1034 else if (strcmp(s, "vector") == 0)
1035 return eEncodingVector;
1036 }
1037 return fail_value;
1038}
1039
1040uint32_t
1041Args::StringToGenericRegister (const char *s)
1042{
1043 if (s && s[0])
1044 {
1045 if (strcmp(s, "pc") == 0)
1046 return LLDB_REGNUM_GENERIC_PC;
1047 else if (strcmp(s, "sp") == 0)
1048 return LLDB_REGNUM_GENERIC_SP;
1049 else if (strcmp(s, "fp") == 0)
1050 return LLDB_REGNUM_GENERIC_FP;
Jason Molenda2fc43a32014-05-09 04:09:48 +00001051 else if (strcmp(s, "ra") == 0 || strcmp(s, "lr") == 0)
Greg Clayton2443cbd2012-08-24 01:42:50 +00001052 return LLDB_REGNUM_GENERIC_RA;
1053 else if (strcmp(s, "flags") == 0)
1054 return LLDB_REGNUM_GENERIC_FLAGS;
1055 else if (strncmp(s, "arg", 3) == 0)
1056 {
1057 if (s[3] && s[4] == '\0')
1058 {
1059 switch (s[3])
1060 {
1061 case '1': return LLDB_REGNUM_GENERIC_ARG1;
1062 case '2': return LLDB_REGNUM_GENERIC_ARG2;
1063 case '3': return LLDB_REGNUM_GENERIC_ARG3;
1064 case '4': return LLDB_REGNUM_GENERIC_ARG4;
1065 case '5': return LLDB_REGNUM_GENERIC_ARG5;
1066 case '6': return LLDB_REGNUM_GENERIC_ARG6;
1067 case '7': return LLDB_REGNUM_GENERIC_ARG7;
1068 case '8': return LLDB_REGNUM_GENERIC_ARG8;
1069 }
1070 }
1071 }
1072 }
1073 return LLDB_INVALID_REGNUM;
1074}
1075
1076
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001077void
1078Args::LongestCommonPrefix (std::string &common_prefix)
1079{
1080 arg_sstr_collection::iterator pos, end = m_args.end();
1081 pos = m_args.begin();
1082 if (pos == end)
1083 common_prefix.clear();
1084 else
1085 common_prefix = (*pos);
1086
1087 for (++pos; pos != end; ++pos)
1088 {
Greg Claytonc982c762010-07-09 20:39:50 +00001089 size_t new_size = (*pos).size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001090
1091 // First trim common_prefix if it is longer than the current element:
1092 if (common_prefix.size() > new_size)
1093 common_prefix.erase (new_size);
1094
1095 // Then trim it at the first disparity:
1096
Greg Claytonc982c762010-07-09 20:39:50 +00001097 for (size_t i = 0; i < common_prefix.size(); i++)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001098 {
1099 if ((*pos)[i] != common_prefix[i])
1100 {
1101 common_prefix.erase(i);
1102 break;
1103 }
1104 }
1105
1106 // If we've emptied the common prefix, we're done.
1107 if (common_prefix.empty())
1108 break;
1109 }
1110}
1111
Caroline Ticed9d63362010-12-07 19:58:26 +00001112size_t
Virgile Belloe2607b52013-09-05 16:42:23 +00001113Args::FindArgumentIndexForOption (Option *long_options, int long_options_index)
Caroline Ticed9d63362010-12-07 19:58:26 +00001114{
1115 char short_buffer[3];
1116 char long_buffer[255];
Greg Clayton3bcdfc02012-12-04 00:32:51 +00001117 ::snprintf (short_buffer, sizeof (short_buffer), "-%c", long_options[long_options_index].val);
Zachary Turnerd37221d2014-07-09 16:31:49 +00001118 ::snprintf (long_buffer, sizeof (long_buffer), "--%s", long_options[long_options_index].definition->long_option);
Caroline Ticed9d63362010-12-07 19:58:26 +00001119 size_t end = GetArgumentCount ();
1120 size_t idx = 0;
1121 while (idx < end)
1122 {
1123 if ((::strncmp (GetArgumentAtIndex (idx), short_buffer, strlen (short_buffer)) == 0)
1124 || (::strncmp (GetArgumentAtIndex (idx), long_buffer, strlen (long_buffer)) == 0))
1125 {
1126 return idx;
1127 }
1128 ++idx;
1129 }
1130
1131 return end;
1132}
1133
1134bool
1135Args::IsPositionalArgument (const char *arg)
1136{
Ed Masted78c9572014-04-20 00:31:37 +00001137 if (arg == nullptr)
Caroline Ticed9d63362010-12-07 19:58:26 +00001138 return false;
1139
1140 bool is_positional = true;
1141 char *cptr = (char *) arg;
1142
1143 if (cptr[0] == '%')
1144 {
1145 ++cptr;
1146 while (isdigit (cptr[0]))
1147 ++cptr;
1148 if (cptr[0] != '\0')
1149 is_positional = false;
1150 }
1151 else
1152 is_positional = false;
1153
1154 return is_positional;
1155}
1156
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001157void
Caroline Tice636d6ed2010-10-12 17:45:19 +00001158Args::ParseAliasOptions (Options &options,
1159 CommandReturnObject &result,
Caroline Tice844d2302010-12-09 22:52:49 +00001160 OptionArgVector *option_arg_vector,
1161 std::string &raw_input_string)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001162{
1163 StreamString sstr;
1164 int i;
Virgile Belloe2607b52013-09-05 16:42:23 +00001165 Option *long_options = options.GetLongOptions();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001166
Ed Masted78c9572014-04-20 00:31:37 +00001167 if (long_options == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001168 {
1169 result.AppendError ("invalid long options");
1170 result.SetStatus (eReturnStatusFailed);
1171 return;
1172 }
1173
Zachary Turnerd37221d2014-07-09 16:31:49 +00001174 for (i = 0; long_options[i].definition != nullptr; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001175 {
Ed Masted78c9572014-04-20 00:31:37 +00001176 if (long_options[i].flag == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001177 {
1178 sstr << (char) long_options[i].val;
Zachary Turnerd37221d2014-07-09 16:31:49 +00001179 switch (long_options[i].definition->option_has_arg)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001180 {
1181 default:
Virgile Belloe2607b52013-09-05 16:42:23 +00001182 case OptionParser::eNoArgument:
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001183 break;
Virgile Belloe2607b52013-09-05 16:42:23 +00001184 case OptionParser::eRequiredArgument:
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001185 sstr << ":";
1186 break;
Virgile Belloe2607b52013-09-05 16:42:23 +00001187 case OptionParser::eOptionalArgument:
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001188 sstr << "::";
1189 break;
1190 }
1191 }
1192 }
1193
Virgile Belloe2607b52013-09-05 16:42:23 +00001194 OptionParser::Prepare();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001195 int val;
1196 while (1)
1197 {
1198 int long_options_index = -1;
Virgile Belloe2607b52013-09-05 16:42:23 +00001199 val = OptionParser::Parse (GetArgumentCount(),
Greg Claytonb7ad58a2013-04-04 20:35:24 +00001200 GetArgumentVector(),
1201 sstr.GetData(),
1202 long_options,
1203 &long_options_index);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001204
1205 if (val == -1)
1206 break;
1207
1208 if (val == '?')
1209 {
1210 result.AppendError ("unknown or ambiguous option");
1211 result.SetStatus (eReturnStatusFailed);
1212 break;
1213 }
1214
1215 if (val == 0)
1216 continue;
1217
Greg Clayton78d10192014-04-07 21:37:03 +00001218 options.OptionSeen (val);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001219
1220 // Look up the long option index
1221 if (long_options_index == -1)
1222 {
1223 for (int j = 0;
Zachary Turnerd37221d2014-07-09 16:31:49 +00001224 long_options[j].definition || long_options[j].flag || long_options[j].val;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001225 ++j)
1226 {
1227 if (long_options[j].val == val)
1228 {
1229 long_options_index = j;
1230 break;
1231 }
1232 }
1233 }
1234
1235 // See if the option takes an argument, and see if one was supplied.
1236 if (long_options_index >= 0)
1237 {
1238 StreamString option_str;
Greg Clayton3bcdfc02012-12-04 00:32:51 +00001239 option_str.Printf ("-%c", val);
Zachary Turnerd37221d2014-07-09 16:31:49 +00001240 const OptionDefinition *def = long_options[long_options_index].definition;
1241 int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001242
Zachary Turnerd37221d2014-07-09 16:31:49 +00001243 switch (has_arg)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001244 {
Virgile Belloe2607b52013-09-05 16:42:23 +00001245 case OptionParser::eNoArgument:
Caroline Ticed9d63362010-12-07 19:58:26 +00001246 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
Virgile Belloe2607b52013-09-05 16:42:23 +00001247 OptionArgValue (OptionParser::eNoArgument, "<no-argument>")));
Caroline Tice5172e6c2010-09-12 04:48:45 +00001248 result.SetStatus (eReturnStatusSuccessFinishNoResult);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001249 break;
Virgile Belloe2607b52013-09-05 16:42:23 +00001250 case OptionParser::eRequiredArgument:
Ed Masted78c9572014-04-20 00:31:37 +00001251 if (OptionParser::GetOptionArgument() != nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001252 {
1253 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
Virgile Belloe2607b52013-09-05 16:42:23 +00001254 OptionArgValue (OptionParser::eRequiredArgument,
1255 std::string (OptionParser::GetOptionArgument()))));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001256 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1257 }
1258 else
1259 {
1260 result.AppendErrorWithFormat ("Option '%s' is missing argument specifier.\n",
1261 option_str.GetData());
1262 result.SetStatus (eReturnStatusFailed);
1263 }
1264 break;
Virgile Belloe2607b52013-09-05 16:42:23 +00001265 case OptionParser::eOptionalArgument:
Ed Masted78c9572014-04-20 00:31:37 +00001266 if (OptionParser::GetOptionArgument() != nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001267 {
1268 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
Virgile Belloe2607b52013-09-05 16:42:23 +00001269 OptionArgValue (OptionParser::eOptionalArgument,
1270 std::string (OptionParser::GetOptionArgument()))));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001271 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1272 }
1273 else
1274 {
1275 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
Virgile Belloe2607b52013-09-05 16:42:23 +00001276 OptionArgValue (OptionParser::eOptionalArgument, "<no-argument>")));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001277 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1278 }
1279 break;
1280 default:
Greg Clayton3bcdfc02012-12-04 00:32:51 +00001281 result.AppendErrorWithFormat ("error with options table; invalid value in has_arg field for option '%c'.\n", val);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001282 result.SetStatus (eReturnStatusFailed);
1283 break;
1284 }
1285 }
1286 else
1287 {
Greg Clayton3bcdfc02012-12-04 00:32:51 +00001288 result.AppendErrorWithFormat ("Invalid option with value '%c'.\n", val);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001289 result.SetStatus (eReturnStatusFailed);
1290 }
Caroline Tice636d6ed2010-10-12 17:45:19 +00001291
1292 if (long_options_index >= 0)
1293 {
1294 // Find option in the argument list; also see if it was supposed to take an argument and if one was
Caroline Tice844d2302010-12-09 22:52:49 +00001295 // supplied. Remove option (and argument, if given) from the argument list. Also remove them from
1296 // the raw_input_string, if one was passed in.
Caroline Ticed9d63362010-12-07 19:58:26 +00001297 size_t idx = FindArgumentIndexForOption (long_options, long_options_index);
1298 if (idx < GetArgumentCount())
1299 {
Caroline Tice844d2302010-12-09 22:52:49 +00001300 if (raw_input_string.size() > 0)
1301 {
1302 const char *tmp_arg = GetArgumentAtIndex (idx);
1303 size_t pos = raw_input_string.find (tmp_arg);
1304 if (pos != std::string::npos)
1305 raw_input_string.erase (pos, strlen (tmp_arg));
1306 }
Caroline Ticed9d63362010-12-07 19:58:26 +00001307 ReplaceArgumentAtIndex (idx, "");
Zachary Turnerd37221d2014-07-09 16:31:49 +00001308 if ((long_options[long_options_index].definition->option_has_arg != OptionParser::eNoArgument)
Ed Masted78c9572014-04-20 00:31:37 +00001309 && (OptionParser::GetOptionArgument() != nullptr)
Caroline Ticed9d63362010-12-07 19:58:26 +00001310 && (idx+1 < GetArgumentCount())
Virgile Belloe2607b52013-09-05 16:42:23 +00001311 && (strcmp (OptionParser::GetOptionArgument(), GetArgumentAtIndex(idx+1)) == 0))
Caroline Tice844d2302010-12-09 22:52:49 +00001312 {
1313 if (raw_input_string.size() > 0)
1314 {
1315 const char *tmp_arg = GetArgumentAtIndex (idx+1);
1316 size_t pos = raw_input_string.find (tmp_arg);
1317 if (pos != std::string::npos)
1318 raw_input_string.erase (pos, strlen (tmp_arg));
1319 }
Caroline Ticed9d63362010-12-07 19:58:26 +00001320 ReplaceArgumentAtIndex (idx+1, "");
Caroline Tice844d2302010-12-09 22:52:49 +00001321 }
Caroline Ticed9d63362010-12-07 19:58:26 +00001322 }
Caroline Tice636d6ed2010-10-12 17:45:19 +00001323 }
1324
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001325 if (!result.Succeeded())
1326 break;
1327 }
1328}
1329
1330void
1331Args::ParseArgsForCompletion
1332(
1333 Options &options,
Jim Inghamd43e0092010-06-24 20:31:04 +00001334 OptionElementVector &option_element_vector,
1335 uint32_t cursor_index
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001336)
1337{
1338 StreamString sstr;
Virgile Belloe2607b52013-09-05 16:42:23 +00001339 Option *long_options = options.GetLongOptions();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001340 option_element_vector.clear();
1341
Ed Masted78c9572014-04-20 00:31:37 +00001342 if (long_options == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001343 {
1344 return;
1345 }
1346
1347 // Leading : tells getopt to return a : for a missing option argument AND
1348 // to suppress error messages.
1349
1350 sstr << ":";
Zachary Turnerd37221d2014-07-09 16:31:49 +00001351 for (int i = 0; long_options[i].definition != nullptr; ++i)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001352 {
Ed Masted78c9572014-04-20 00:31:37 +00001353 if (long_options[i].flag == nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001354 {
1355 sstr << (char) long_options[i].val;
Zachary Turnerd37221d2014-07-09 16:31:49 +00001356 switch (long_options[i].definition->option_has_arg)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001357 {
1358 default:
Virgile Belloe2607b52013-09-05 16:42:23 +00001359 case OptionParser::eNoArgument:
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001360 break;
Virgile Belloe2607b52013-09-05 16:42:23 +00001361 case OptionParser::eRequiredArgument:
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001362 sstr << ":";
1363 break;
Virgile Belloe2607b52013-09-05 16:42:23 +00001364 case OptionParser::eOptionalArgument:
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001365 sstr << "::";
1366 break;
1367 }
1368 }
1369 }
1370
Virgile Belloe2607b52013-09-05 16:42:23 +00001371 OptionParser::Prepare();
1372 OptionParser::EnableError(false);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001373
1374 int val;
1375 const OptionDefinition *opt_defs = options.GetDefinitions();
1376
Virgile Belloe2607b52013-09-05 16:42:23 +00001377 // Fooey... OptionParser::Parse permutes the GetArgumentVector to move the options to the front.
1378 // So we have to build another Arg and pass that to OptionParser::Parse so it doesn't
Jim Inghamd43e0092010-06-24 20:31:04 +00001379 // change the one we have.
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001380
Greg Claytonc982c762010-07-09 20:39:50 +00001381 std::vector<const char *> dummy_vec (GetArgumentVector(), GetArgumentVector() + GetArgumentCount() + 1);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001382
Jim Inghamd43e0092010-06-24 20:31:04 +00001383 bool failed_once = false;
1384 uint32_t dash_dash_pos = -1;
1385
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001386 while (1)
1387 {
1388 bool missing_argument = false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001389 int long_options_index = -1;
Jim Inghamd43e0092010-06-24 20:31:04 +00001390
Virgile Belloe2607b52013-09-05 16:42:23 +00001391 val = OptionParser::Parse (dummy_vec.size() - 1,
Greg Claytonb7ad58a2013-04-04 20:35:24 +00001392 (char *const *) &dummy_vec.front(),
1393 sstr.GetData(),
1394 long_options,
1395 &long_options_index);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001396
1397 if (val == -1)
Jim Inghamd43e0092010-06-24 20:31:04 +00001398 {
1399 // When we're completing a "--" which is the last option on line,
1400 if (failed_once)
1401 break;
1402
1403 failed_once = true;
1404
1405 // If this is a bare "--" we mark it as such so we can complete it successfully later.
1406 // Handling the "--" is a little tricky, since that may mean end of options or arguments, or the
1407 // user might want to complete options by long name. I make this work by checking whether the
1408 // cursor is in the "--" argument, and if so I assume we're completing the long option, otherwise
Virgile Belloe2607b52013-09-05 16:42:23 +00001409 // I let it pass to OptionParser::Parse which will terminate the option parsing.
Jim Inghamd43e0092010-06-24 20:31:04 +00001410 // Note, in either case we continue parsing the line so we can figure out what other options
1411 // were passed. This will be useful when we come to restricting completions based on what other
1412 // options we've seen on the line.
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001413
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +00001414 if (static_cast<size_t>(OptionParser::GetOptionIndex()) < dummy_vec.size() - 1
Virgile Belloe2607b52013-09-05 16:42:23 +00001415 && (strcmp (dummy_vec[OptionParser::GetOptionIndex()-1], "--") == 0))
Jim Inghamd43e0092010-06-24 20:31:04 +00001416 {
Virgile Belloe2607b52013-09-05 16:42:23 +00001417 dash_dash_pos = OptionParser::GetOptionIndex() - 1;
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +00001418 if (static_cast<size_t>(OptionParser::GetOptionIndex() - 1) == cursor_index)
Jim Inghamd43e0092010-06-24 20:31:04 +00001419 {
Virgile Belloe2607b52013-09-05 16:42:23 +00001420 option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDoubleDash, OptionParser::GetOptionIndex() - 1,
Jim Inghamd43e0092010-06-24 20:31:04 +00001421 OptionArgElement::eBareDoubleDash));
1422 continue;
1423 }
1424 else
1425 break;
1426 }
1427 else
1428 break;
1429 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001430 else if (val == '?')
1431 {
Virgile Belloe2607b52013-09-05 16:42:23 +00001432 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1,
Jim Inghamd43e0092010-06-24 20:31:04 +00001433 OptionArgElement::eUnrecognizedArg));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001434 continue;
1435 }
1436 else if (val == 0)
1437 {
1438 continue;
1439 }
1440 else if (val == ':')
1441 {
1442 // This is a missing argument.
Virgile Belloe2607b52013-09-05 16:42:23 +00001443 val = OptionParser::GetOptionErrorCause();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001444 missing_argument = true;
1445 }
1446
1447 ((Options *) &options)->OptionSeen (val);
1448
1449 // Look up the long option index
1450 if (long_options_index == -1)
1451 {
1452 for (int j = 0;
Zachary Turnerd37221d2014-07-09 16:31:49 +00001453 long_options[j].definition || long_options[j].flag || long_options[j].val;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001454 ++j)
1455 {
1456 if (long_options[j].val == val)
1457 {
1458 long_options_index = j;
1459 break;
1460 }
1461 }
1462 }
1463
1464 // See if the option takes an argument, and see if one was supplied.
1465 if (long_options_index >= 0)
1466 {
1467 int opt_defs_index = -1;
1468 for (int i = 0; ; i++)
1469 {
1470 if (opt_defs[i].short_option == 0)
1471 break;
1472 else if (opt_defs[i].short_option == val)
1473 {
1474 opt_defs_index = i;
1475 break;
1476 }
1477 }
1478
Zachary Turnerd37221d2014-07-09 16:31:49 +00001479 const OptionDefinition *def = long_options[long_options_index].definition;
1480 int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
1481 switch (has_arg)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001482 {
Virgile Belloe2607b52013-09-05 16:42:23 +00001483 case OptionParser::eNoArgument:
1484 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, 0));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001485 break;
Virgile Belloe2607b52013-09-05 16:42:23 +00001486 case OptionParser::eRequiredArgument:
Ed Masted78c9572014-04-20 00:31:37 +00001487 if (OptionParser::GetOptionArgument() != nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001488 {
1489 int arg_index;
1490 if (missing_argument)
1491 arg_index = -1;
1492 else
Virgile Belloe2607b52013-09-05 16:42:23 +00001493 arg_index = OptionParser::GetOptionIndex() - 1;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001494
Virgile Belloe2607b52013-09-05 16:42:23 +00001495 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, arg_index));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001496 }
1497 else
1498 {
Virgile Belloe2607b52013-09-05 16:42:23 +00001499 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, -1));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001500 }
1501 break;
Virgile Belloe2607b52013-09-05 16:42:23 +00001502 case OptionParser::eOptionalArgument:
Ed Masted78c9572014-04-20 00:31:37 +00001503 if (OptionParser::GetOptionArgument() != nullptr)
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001504 {
Virgile Belloe2607b52013-09-05 16:42:23 +00001505 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, OptionParser::GetOptionIndex() - 1));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001506 }
1507 else
1508 {
Virgile Belloe2607b52013-09-05 16:42:23 +00001509 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, OptionParser::GetOptionIndex() - 1));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001510 }
1511 break;
1512 default:
1513 // The options table is messed up. Here we'll just continue
Virgile Belloe2607b52013-09-05 16:42:23 +00001514 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1,
Jim Inghamd43e0092010-06-24 20:31:04 +00001515 OptionArgElement::eUnrecognizedArg));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001516 break;
1517 }
1518 }
1519 else
1520 {
Virgile Belloe2607b52013-09-05 16:42:23 +00001521 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1,
Jim Inghamd43e0092010-06-24 20:31:04 +00001522 OptionArgElement::eUnrecognizedArg));
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001523 }
1524 }
Jim Inghamd43e0092010-06-24 20:31:04 +00001525
1526 // Finally we have to handle the case where the cursor index points at a single "-". We want to mark that in
Virgile Belloe2607b52013-09-05 16:42:23 +00001527 // the option_element_vector, but only if it is not after the "--". But it turns out that OptionParser::Parse just ignores
Jim Inghamd43e0092010-06-24 20:31:04 +00001528 // an isolated "-". So we have to look it up by hand here. We only care if it is AT the cursor position.
Jim Inghamdc498e52014-08-27 22:06:58 +00001529 // Note, a single quoted dash is not the same as a single dash...
Jim Inghamd43e0092010-06-24 20:31:04 +00001530
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +00001531 if ((static_cast<int32_t>(dash_dash_pos) == -1 || cursor_index < dash_dash_pos)
Jim Inghamdc498e52014-08-27 22:06:58 +00001532 && m_args_quote_char[cursor_index] == '\0'
Jim Inghamd43e0092010-06-24 20:31:04 +00001533 && strcmp (GetArgumentAtIndex(cursor_index), "-") == 0)
1534 {
1535 option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDash, cursor_index,
1536 OptionArgElement::eBareDash));
1537
1538 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001539}
Greg Clayton4c054102012-09-01 00:38:36 +00001540
1541void
1542Args::EncodeEscapeSequences (const char *src, std::string &dst)
1543{
1544 dst.clear();
1545 if (src)
1546 {
1547 for (const char *p = src; *p != '\0'; ++p)
1548 {
1549 size_t non_special_chars = ::strcspn (p, "\\");
1550 if (non_special_chars > 0)
1551 {
1552 dst.append(p, non_special_chars);
1553 p += non_special_chars;
1554 if (*p == '\0')
1555 break;
1556 }
1557
1558 if (*p == '\\')
1559 {
1560 ++p; // skip the slash
1561 switch (*p)
1562 {
1563 case 'a' : dst.append(1, '\a'); break;
1564 case 'b' : dst.append(1, '\b'); break;
1565 case 'f' : dst.append(1, '\f'); break;
1566 case 'n' : dst.append(1, '\n'); break;
1567 case 'r' : dst.append(1, '\r'); break;
1568 case 't' : dst.append(1, '\t'); break;
1569 case 'v' : dst.append(1, '\v'); break;
1570 case '\\': dst.append(1, '\\'); break;
1571 case '\'': dst.append(1, '\''); break;
1572 case '"' : dst.append(1, '"'); break;
1573 case '0' :
1574 // 1 to 3 octal chars
1575 {
1576 // Make a string that can hold onto the initial zero char,
1577 // up to 3 octal digits, and a terminating NULL.
1578 char oct_str[5] = { '\0', '\0', '\0', '\0', '\0' };
1579
1580 int i;
1581 for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i)
1582 oct_str[i] = p[i];
1583
1584 // We don't want to consume the last octal character since
1585 // the main for loop will do this for us, so we advance p by
1586 // one less than i (even if i is zero)
1587 p += i - 1;
Ed Masted78c9572014-04-20 00:31:37 +00001588 unsigned long octal_value = ::strtoul (oct_str, nullptr, 8);
Greg Clayton4c054102012-09-01 00:38:36 +00001589 if (octal_value <= UINT8_MAX)
1590 {
Greg Claytonc7bece562013-01-25 18:06:21 +00001591 dst.append(1, (char)octal_value);
Greg Clayton4c054102012-09-01 00:38:36 +00001592 }
1593 }
1594 break;
1595
1596 case 'x':
1597 // hex number in the format
1598 if (isxdigit(p[1]))
1599 {
1600 ++p; // Skip the 'x'
1601
1602 // Make a string that can hold onto two hex chars plus a
1603 // NULL terminator
1604 char hex_str[3] = { *p, '\0', '\0' };
1605 if (isxdigit(p[1]))
1606 {
1607 ++p; // Skip the first of the two hex chars
1608 hex_str[1] = *p;
1609 }
1610
Ed Masted78c9572014-04-20 00:31:37 +00001611 unsigned long hex_value = strtoul (hex_str, nullptr, 16);
Greg Clayton4c054102012-09-01 00:38:36 +00001612 if (hex_value <= UINT8_MAX)
1613 dst.append (1, (char)hex_value);
1614 }
1615 else
1616 {
1617 dst.append(1, 'x');
1618 }
1619 break;
1620
1621 default:
1622 // Just desensitize any other character by just printing what
1623 // came after the '\'
1624 dst.append(1, *p);
1625 break;
1626
1627 }
1628 }
1629 }
1630 }
1631}
1632
1633
1634void
1635Args::ExpandEscapedCharacters (const char *src, std::string &dst)
1636{
1637 dst.clear();
1638 if (src)
1639 {
1640 for (const char *p = src; *p != '\0'; ++p)
1641 {
Daniel Malea90b0c842012-12-05 20:24:57 +00001642 if (isprint8(*p))
Greg Clayton4c054102012-09-01 00:38:36 +00001643 dst.append(1, *p);
1644 else
1645 {
1646 switch (*p)
1647 {
1648 case '\a': dst.append("\\a"); break;
1649 case '\b': dst.append("\\b"); break;
1650 case '\f': dst.append("\\f"); break;
1651 case '\n': dst.append("\\n"); break;
1652 case '\r': dst.append("\\r"); break;
1653 case '\t': dst.append("\\t"); break;
1654 case '\v': dst.append("\\v"); break;
1655 case '\'': dst.append("\\'"); break;
1656 case '"': dst.append("\\\""); break;
1657 case '\\': dst.append("\\\\"); break;
1658 default:
1659 {
1660 // Just encode as octal
1661 dst.append("\\0");
1662 char octal_str[32];
1663 snprintf(octal_str, sizeof(octal_str), "%o", *p);
1664 dst.append(octal_str);
1665 }
1666 break;
1667 }
1668 }
1669 }
1670 }
1671}
1672