1 //===-- 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
10 // C Includes
11 #include <cstdlib>
12 // C++ Includes
13 // Other libraries and framework includes
14 // Project includes
15 #include "lldb/Interpreter/Args.h"
16 #include "lldb/Core/Stream.h"
17 #include "lldb/Core/StreamFile.h"
18 #include "lldb/Core/StreamString.h"
19 #include "lldb/DataFormatters/FormatManager.h"
20 #include "lldb/Host/StringConvert.h"
21 #include "lldb/Interpreter/Options.h"
22 #include "lldb/Interpreter/CommandInterpreter.h"
23 #include "lldb/Interpreter/CommandReturnObject.h"
24 #include "lldb/Target/Process.h"
25 #include "lldb/Target/StackFrame.h"
26 #include "lldb/Target/Target.h"
27
28 using namespace lldb;
29 using namespace lldb_private;
30
31 //----------------------------------------------------------------------
32 // Args constructor
33 //----------------------------------------------------------------------
Args(llvm::StringRef command)34 Args::Args (llvm::StringRef command) :
35 m_args(),
36 m_argv(),
37 m_args_quote_char()
38 {
39 SetCommandString (command);
40 }
41
42
43 //----------------------------------------------------------------------
44 // We have to be very careful on the copy constructor of this class
45 // to make sure we copy all of the string values, but we can't copy the
46 // rhs.m_argv into m_argv since it will point to the "const char *" c
47 // strings in rhs.m_args. We need to copy the string list and update our
48 // own m_argv appropriately.
49 //----------------------------------------------------------------------
Args(const Args & rhs)50 Args::Args (const Args &rhs) :
51 m_args (rhs.m_args),
52 m_argv (),
53 m_args_quote_char(rhs.m_args_quote_char)
54 {
55 UpdateArgvFromArgs();
56 }
57
58 //----------------------------------------------------------------------
59 // We have to be very careful on the copy constructor of this class
60 // to make sure we copy all of the string values, but we can't copy the
61 // rhs.m_argv into m_argv since it will point to the "const char *" c
62 // strings in rhs.m_args. We need to copy the string list and update our
63 // own m_argv appropriately.
64 //----------------------------------------------------------------------
65 const Args &
operator =(const Args & rhs)66 Args::operator= (const Args &rhs)
67 {
68 // Make sure we aren't assigning to self
69 if (this != &rhs)
70 {
71 m_args = rhs.m_args;
72 m_args_quote_char = rhs.m_args_quote_char;
73 UpdateArgvFromArgs();
74 }
75 return *this;
76 }
77
78 //----------------------------------------------------------------------
79 // Destructor
80 //----------------------------------------------------------------------
~Args()81 Args::~Args ()
82 {
83 }
84
85 void
Dump(Stream * s)86 Args::Dump (Stream *s)
87 {
88 const size_t argc = m_argv.size();
89 for (size_t i=0; i<argc; ++i)
90 {
91 s->Indent();
92 const char *arg_cstr = m_argv[i];
93 if (arg_cstr)
94 s->Printf("argv[%zi]=\"%s\"\n", i, arg_cstr);
95 else
96 s->Printf("argv[%zi]=NULL\n", i);
97 }
98 s->EOL();
99 }
100
101 bool
GetCommandString(std::string & command) const102 Args::GetCommandString (std::string &command) const
103 {
104 command.clear();
105 const size_t argc = GetArgumentCount();
106 for (size_t i=0; i<argc; ++i)
107 {
108 if (i > 0)
109 command += ' ';
110 command += m_argv[i];
111 }
112 return argc > 0;
113 }
114
115 bool
GetQuotedCommandString(std::string & command) const116 Args::GetQuotedCommandString (std::string &command) const
117 {
118 command.clear ();
119 const size_t argc = GetArgumentCount();
120 for (size_t i = 0; i < argc; ++i)
121 {
122 if (i > 0)
123 command.append (1, ' ');
124 char quote_char = GetArgumentQuoteCharAtIndex(i);
125 if (quote_char)
126 {
127 command.append (1, quote_char);
128 command.append (m_argv[i]);
129 command.append (1, quote_char);
130 }
131 else
132 command.append (m_argv[i]);
133 }
134 return argc > 0;
135 }
136
137 // A helper function for argument parsing.
138 // Parses the initial part of the first argument using normal double quote rules:
139 // backslash escapes the double quote and itself. The parsed string is appended to the second
140 // argument. The function returns the unparsed portion of the string, starting at the closing
141 // quote.
142 static llvm::StringRef
ParseDoubleQuotes(llvm::StringRef quoted,std::string & result)143 ParseDoubleQuotes(llvm::StringRef quoted, std::string &result)
144 {
145 // Inside double quotes, '\' and '"' are special.
146 static const char *k_escapable_characters = "\"\\";
147 while (true)
148 {
149 // Skip over over regular characters and append them.
150 size_t regular = quoted.find_first_of(k_escapable_characters);
151 result += quoted.substr(0, regular);
152 quoted = quoted.substr(regular);
153
154 // If we have reached the end of string or the closing quote, we're done.
155 if (quoted.empty() || quoted.front() == '"')
156 break;
157
158 // We have found a backslash.
159 quoted = quoted.drop_front();
160
161 if (quoted.empty())
162 {
163 // A lone backslash at the end of string, let's just append it.
164 result += '\\';
165 break;
166 }
167
168 // If the character after the backslash is not a whitelisted escapable character, we
169 // leave the character sequence untouched.
170 if (strchr(k_escapable_characters, quoted.front()) == nullptr)
171 result += '\\';
172
173 result += quoted.front();
174 quoted = quoted.drop_front();
175 }
176
177 return quoted;
178 }
179
180 // A helper function for SetCommandString.
181 // Parses a single argument from the command string, processing quotes and backslashes in a
182 // shell-like manner. The parsed argument is appended to the m_args array. The function returns
183 // the unparsed portion of the string, starting at the first unqouted, unescaped whitespace
184 // character.
185 llvm::StringRef
ParseSingleArgument(llvm::StringRef command)186 Args::ParseSingleArgument(llvm::StringRef command)
187 {
188 // Argument can be split into multiple discontiguous pieces,
189 // for example:
190 // "Hello ""World"
191 // this would result in a single argument "Hello World" (without/
192 // the quotes) since the quotes would be removed and there is
193 // not space between the strings.
194
195 std::string arg;
196
197 // Since we can have multiple quotes that form a single command
198 // in a command like: "Hello "world'!' (which will make a single
199 // argument "Hello world!") we remember the first quote character
200 // we encounter and use that for the quote character.
201 char first_quote_char = '\0';
202
203 bool arg_complete = false;
204 do
205 {
206 // Skip over over regular characters and append them.
207 size_t regular = command.find_first_of(" \t\"'`\\");
208 arg += command.substr(0, regular);
209 command = command.substr(regular);
210
211 if (command.empty())
212 break;
213
214 char special = command.front();
215 command = command.drop_front();
216 switch (special)
217 {
218 case '\\':
219 if (command.empty())
220 {
221 arg += '\\';
222 break;
223 }
224
225 // If the character after the backslash is not a whitelisted escapable character, we
226 // leave the character sequence untouched.
227 if (strchr(" \t\\'\"`", command.front()) == nullptr)
228 arg += '\\';
229
230 arg += command.front();
231 command = command.drop_front();
232
233 break;
234
235 case ' ':
236 case '\t':
237 // We are not inside any quotes, we just found a space after an
238 // argument. We are done.
239 arg_complete = true;
240 break;
241
242 case '"':
243 case '\'':
244 case '`':
245 // We found the start of a quote scope.
246 if (first_quote_char == '\0')
247 first_quote_char = special;
248
249 if (special == '"')
250 command = ParseDoubleQuotes(command, arg);
251 else
252 {
253 // For single quotes, we simply skip ahead to the matching quote character
254 // (or the end of the string).
255 size_t quoted = command.find(special);
256 arg += command.substr(0, quoted);
257 command = command.substr(quoted);
258 }
259
260 // If we found a closing quote, skip it.
261 if (! command.empty())
262 command = command.drop_front();
263
264 break;
265 }
266 } while (!arg_complete);
267
268 m_args.push_back(arg);
269 m_args_quote_char.push_back (first_quote_char);
270 return command;
271 }
272
273 void
SetCommandString(llvm::StringRef command)274 Args::SetCommandString (llvm::StringRef command)
275 {
276 m_args.clear();
277 m_argv.clear();
278 m_args_quote_char.clear();
279
280 static const char *k_space_separators = " \t";
281 command = command.ltrim(k_space_separators);
282 while (!command.empty())
283 {
284 command = ParseSingleArgument(command);
285 command = command.ltrim(k_space_separators);
286 }
287
288 UpdateArgvFromArgs();
289 }
290
291 void
UpdateArgsAfterOptionParsing()292 Args::UpdateArgsAfterOptionParsing()
293 {
294 // Now m_argv might be out of date with m_args, so we need to fix that
295 arg_cstr_collection::const_iterator argv_pos, argv_end = m_argv.end();
296 arg_sstr_collection::iterator args_pos;
297 arg_quote_char_collection::iterator quotes_pos;
298
299 for (argv_pos = m_argv.begin(), args_pos = m_args.begin(), quotes_pos = m_args_quote_char.begin();
300 argv_pos != argv_end && args_pos != m_args.end();
301 ++argv_pos)
302 {
303 const char *argv_cstr = *argv_pos;
304 if (argv_cstr == nullptr)
305 break;
306
307 while (args_pos != m_args.end())
308 {
309 const char *args_cstr = args_pos->c_str();
310 if (args_cstr == argv_cstr)
311 {
312 // We found the argument that matches the C string in the
313 // vector, so we can now look for the next one
314 ++args_pos;
315 ++quotes_pos;
316 break;
317 }
318 else
319 {
320 quotes_pos = m_args_quote_char.erase (quotes_pos);
321 args_pos = m_args.erase (args_pos);
322 }
323 }
324 }
325
326 if (args_pos != m_args.end())
327 m_args.erase (args_pos, m_args.end());
328
329 if (quotes_pos != m_args_quote_char.end())
330 m_args_quote_char.erase (quotes_pos, m_args_quote_char.end());
331 }
332
333 void
UpdateArgvFromArgs()334 Args::UpdateArgvFromArgs()
335 {
336 m_argv.clear();
337 arg_sstr_collection::const_iterator pos, end = m_args.end();
338 for (pos = m_args.begin(); pos != end; ++pos)
339 m_argv.push_back(pos->c_str());
340 m_argv.push_back(nullptr);
341 // Make sure we have enough arg quote chars in the array
342 if (m_args_quote_char.size() < m_args.size())
343 m_args_quote_char.resize (m_argv.size());
344 }
345
346 size_t
GetArgumentCount() const347 Args::GetArgumentCount() const
348 {
349 if (m_argv.empty())
350 return 0;
351 return m_argv.size() - 1;
352 }
353
354 const char *
GetArgumentAtIndex(size_t idx) const355 Args::GetArgumentAtIndex (size_t idx) const
356 {
357 if (idx < m_argv.size())
358 return m_argv[idx];
359 return nullptr;
360 }
361
362 char
GetArgumentQuoteCharAtIndex(size_t idx) const363 Args::GetArgumentQuoteCharAtIndex (size_t idx) const
364 {
365 if (idx < m_args_quote_char.size())
366 return m_args_quote_char[idx];
367 return '\0';
368 }
369
370 char **
GetArgumentVector()371 Args::GetArgumentVector()
372 {
373 if (!m_argv.empty())
374 return (char **)&m_argv[0];
375 return nullptr;
376 }
377
378 const char **
GetConstArgumentVector() const379 Args::GetConstArgumentVector() const
380 {
381 if (!m_argv.empty())
382 return (const char **)&m_argv[0];
383 return nullptr;
384 }
385
386 void
Shift()387 Args::Shift ()
388 {
389 // Don't pop the last NULL terminator from the argv array
390 if (m_argv.size() > 1)
391 {
392 m_argv.erase(m_argv.begin());
393 m_args.pop_front();
394 if (!m_args_quote_char.empty())
395 m_args_quote_char.erase(m_args_quote_char.begin());
396 }
397 }
398
399 const char *
Unshift(const char * arg_cstr,char quote_char)400 Args::Unshift (const char *arg_cstr, char quote_char)
401 {
402 m_args.push_front(arg_cstr);
403 m_argv.insert(m_argv.begin(), m_args.front().c_str());
404 m_args_quote_char.insert(m_args_quote_char.begin(), quote_char);
405 return GetArgumentAtIndex (0);
406 }
407
408 void
AppendArguments(const Args & rhs)409 Args::AppendArguments (const Args &rhs)
410 {
411 const size_t rhs_argc = rhs.GetArgumentCount();
412 for (size_t i=0; i<rhs_argc; ++i)
413 AppendArgument(rhs.GetArgumentAtIndex(i),
414 rhs.GetArgumentQuoteCharAtIndex(i));
415 }
416
417 void
AppendArguments(const char ** argv)418 Args::AppendArguments (const char **argv)
419 {
420 if (argv)
421 {
422 for (uint32_t i=0; argv[i]; ++i)
423 AppendArgument(argv[i]);
424 }
425 }
426
427 const char *
AppendArgument(const char * arg_cstr,char quote_char)428 Args::AppendArgument (const char *arg_cstr, char quote_char)
429 {
430 return InsertArgumentAtIndex (GetArgumentCount(), arg_cstr, quote_char);
431 }
432
433 const char *
InsertArgumentAtIndex(size_t idx,const char * arg_cstr,char quote_char)434 Args::InsertArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
435 {
436 // Since we are using a std::list to hold onto the copied C string and
437 // we don't have direct access to the elements, we have to iterate to
438 // find the value.
439 arg_sstr_collection::iterator pos, end = m_args.end();
440 size_t i = idx;
441 for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
442 --i;
443
444 pos = m_args.insert(pos, arg_cstr);
445
446 if (idx >= m_args_quote_char.size())
447 {
448 m_args_quote_char.resize(idx + 1);
449 m_args_quote_char[idx] = quote_char;
450 }
451 else
452 m_args_quote_char.insert(m_args_quote_char.begin() + idx, quote_char);
453
454 UpdateArgvFromArgs();
455 return GetArgumentAtIndex(idx);
456 }
457
458 const char *
ReplaceArgumentAtIndex(size_t idx,const char * arg_cstr,char quote_char)459 Args::ReplaceArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
460 {
461 // Since we are using a std::list to hold onto the copied C string and
462 // we don't have direct access to the elements, we have to iterate to
463 // find the value.
464 arg_sstr_collection::iterator pos, end = m_args.end();
465 size_t i = idx;
466 for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
467 --i;
468
469 if (pos != end)
470 {
471 pos->assign(arg_cstr);
472 assert(idx < m_argv.size() - 1);
473 m_argv[idx] = pos->c_str();
474 if (idx >= m_args_quote_char.size())
475 m_args_quote_char.resize(idx + 1);
476 m_args_quote_char[idx] = quote_char;
477 return GetArgumentAtIndex(idx);
478 }
479 return nullptr;
480 }
481
482 void
DeleteArgumentAtIndex(size_t idx)483 Args::DeleteArgumentAtIndex (size_t idx)
484 {
485 // Since we are using a std::list to hold onto the copied C string and
486 // we don't have direct access to the elements, we have to iterate to
487 // find the value.
488 arg_sstr_collection::iterator pos, end = m_args.end();
489 size_t i = idx;
490 for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
491 --i;
492
493 if (pos != end)
494 {
495 m_args.erase (pos);
496 assert(idx < m_argv.size() - 1);
497 m_argv.erase(m_argv.begin() + idx);
498 if (idx < m_args_quote_char.size())
499 m_args_quote_char.erase(m_args_quote_char.begin() + idx);
500 }
501 }
502
503 void
SetArguments(size_t argc,const char ** argv)504 Args::SetArguments (size_t argc, const char **argv)
505 {
506 // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is
507 // no need to clear it here.
508 m_args.clear();
509 m_args_quote_char.clear();
510
511 // First copy each string
512 for (size_t i=0; i<argc; ++i)
513 {
514 m_args.push_back (argv[i]);
515 if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`'))
516 m_args_quote_char.push_back (argv[i][0]);
517 else
518 m_args_quote_char.push_back ('\0');
519 }
520
521 UpdateArgvFromArgs();
522 }
523
524 void
SetArguments(const char ** argv)525 Args::SetArguments (const char **argv)
526 {
527 // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is
528 // no need to clear it here.
529 m_args.clear();
530 m_args_quote_char.clear();
531
532 if (argv)
533 {
534 // First copy each string
535 for (size_t i=0; argv[i]; ++i)
536 {
537 m_args.push_back (argv[i]);
538 if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`'))
539 m_args_quote_char.push_back (argv[i][0]);
540 else
541 m_args_quote_char.push_back ('\0');
542 }
543 }
544
545 UpdateArgvFromArgs();
546 }
547
548
549 Error
ParseOptions(Options & options)550 Args::ParseOptions (Options &options)
551 {
552 StreamString sstr;
553 Error error;
554 Option *long_options = options.GetLongOptions();
555 if (long_options == nullptr)
556 {
557 error.SetErrorStringWithFormat("invalid long options");
558 return error;
559 }
560
561 for (int i=0; long_options[i].definition != nullptr; ++i)
562 {
563 if (long_options[i].flag == nullptr)
564 {
565 if (isprint8(long_options[i].val))
566 {
567 sstr << (char)long_options[i].val;
568 switch (long_options[i].definition->option_has_arg)
569 {
570 default:
571 case OptionParser::eNoArgument: break;
572 case OptionParser::eRequiredArgument: sstr << ':'; break;
573 case OptionParser::eOptionalArgument: sstr << "::"; break;
574 }
575 }
576 }
577 }
578 OptionParser::Prepare();
579 int val;
580 while (1)
581 {
582 int long_options_index = -1;
583 val = OptionParser::Parse(GetArgumentCount(),
584 GetArgumentVector(),
585 sstr.GetData(),
586 long_options,
587 &long_options_index);
588 if (val == -1)
589 break;
590
591 // Did we get an error?
592 if (val == '?')
593 {
594 error.SetErrorStringWithFormat("unknown or ambiguous option");
595 break;
596 }
597 // The option auto-set itself
598 if (val == 0)
599 continue;
600
601 ((Options *) &options)->OptionSeen (val);
602
603 // Lookup the long option index
604 if (long_options_index == -1)
605 {
606 for (int i=0;
607 long_options[i].definition || long_options[i].flag || long_options[i].val;
608 ++i)
609 {
610 if (long_options[i].val == val)
611 {
612 long_options_index = i;
613 break;
614 }
615 }
616 }
617 // Call the callback with the option
618 if (long_options_index >= 0 && long_options[long_options_index].definition)
619 {
620 const OptionDefinition *def = long_options[long_options_index].definition;
621 CommandInterpreter &interpreter = options.GetInterpreter();
622 OptionValidator *validator = def->validator;
623 if (validator && !validator->IsValid(*interpreter.GetPlatform(true), interpreter.GetExecutionContext()))
624 {
625 error.SetErrorStringWithFormat("Option \"%s\" invalid. %s", def->long_option, def->validator->LongConditionString());
626 }
627 else
628 {
629 error = options.SetOptionValue(long_options_index,
630 (def->option_has_arg == OptionParser::eNoArgument) ? nullptr : OptionParser::GetOptionArgument());
631 }
632 }
633 else
634 {
635 error.SetErrorStringWithFormat("invalid option with value '%i'", val);
636 }
637 if (error.Fail())
638 break;
639 }
640
641 // Update our ARGV now that get options has consumed all the options
642 m_argv.erase(m_argv.begin(), m_argv.begin() + OptionParser::GetOptionIndex());
643 UpdateArgsAfterOptionParsing ();
644 return error;
645 }
646
647 void
Clear()648 Args::Clear ()
649 {
650 m_args.clear ();
651 m_argv.clear ();
652 m_args_quote_char.clear();
653 }
654
655 lldb::addr_t
StringToAddress(const ExecutionContext * exe_ctx,const char * s,lldb::addr_t fail_value,Error * error_ptr)656 Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::addr_t fail_value, Error *error_ptr)
657 {
658 bool error_set = false;
659 if (s && s[0])
660 {
661 char *end = nullptr;
662 lldb::addr_t addr = ::strtoull (s, &end, 0);
663 if (*end == '\0')
664 {
665 if (error_ptr)
666 error_ptr->Clear();
667 return addr; // All characters were used, return the result
668 }
669 // Try base 16 with no prefix...
670 addr = ::strtoull (s, &end, 16);
671 if (*end == '\0')
672 {
673 if (error_ptr)
674 error_ptr->Clear();
675 return addr; // All characters were used, return the result
676 }
677
678 if (exe_ctx)
679 {
680 Target *target = exe_ctx->GetTargetPtr();
681 if (target)
682 {
683 lldb::ValueObjectSP valobj_sp;
684 EvaluateExpressionOptions options;
685 options.SetCoerceToId(false);
686 options.SetUnwindOnError(true);
687 options.SetKeepInMemory(false);
688 options.SetTryAllThreads(true);
689
690 ExpressionResults expr_result = target->EvaluateExpression(s,
691 exe_ctx->GetFramePtr(),
692 valobj_sp,
693 options);
694
695 bool success = false;
696 if (expr_result == eExpressionCompleted)
697 {
698 if (valobj_sp)
699 valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable(valobj_sp->GetDynamicValueType(), true);
700 // Get the address to watch.
701 if (valobj_sp)
702 addr = valobj_sp->GetValueAsUnsigned(fail_value, &success);
703 if (success)
704 {
705 if (error_ptr)
706 error_ptr->Clear();
707 return addr;
708 }
709 else
710 {
711 if (error_ptr)
712 {
713 error_set = true;
714 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());
715 }
716 }
717
718 }
719 else
720 {
721 // Since the compiler can't handle things like "main + 12" we should
722 // try to do this for now. The compliler doesn't like adding offsets
723 // to function pointer types.
724 static RegularExpression g_symbol_plus_offset_regex("^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$");
725 RegularExpression::Match regex_match(3);
726 if (g_symbol_plus_offset_regex.Execute(s, ®ex_match))
727 {
728 uint64_t offset = 0;
729 bool add = true;
730 std::string name;
731 std::string str;
732 if (regex_match.GetMatchAtIndex(s, 1, name))
733 {
734 if (regex_match.GetMatchAtIndex(s, 2, str))
735 {
736 add = str[0] == '+';
737
738 if (regex_match.GetMatchAtIndex(s, 3, str))
739 {
740 offset = StringConvert::ToUInt64(str.c_str(), 0, 0, &success);
741
742 if (success)
743 {
744 Error error;
745 addr = StringToAddress (exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS, &error);
746 if (addr != LLDB_INVALID_ADDRESS)
747 {
748 if (add)
749 return addr + offset;
750 else
751 return addr - offset;
752 }
753 }
754 }
755 }
756 }
757 }
758
759 if (error_ptr)
760 {
761 error_set = true;
762 error_ptr->SetErrorStringWithFormat("address expression \"%s\" evaluation failed", s);
763 }
764 }
765 }
766 }
767 }
768 if (error_ptr)
769 {
770 if (!error_set)
771 error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", s);
772 }
773 return fail_value;
774 }
775
776 const char *
StripSpaces(std::string & s,bool leading,bool trailing,bool return_null_if_empty)777 Args::StripSpaces (std::string &s, bool leading, bool trailing, bool return_null_if_empty)
778 {
779 static const char *k_white_space = " \t\v";
780 if (!s.empty())
781 {
782 if (leading)
783 {
784 size_t pos = s.find_first_not_of (k_white_space);
785 if (pos == std::string::npos)
786 s.clear();
787 else if (pos > 0)
788 s.erase(0, pos);
789 }
790
791 if (trailing)
792 {
793 size_t rpos = s.find_last_not_of(k_white_space);
794 if (rpos != std::string::npos && rpos + 1 < s.size())
795 s.erase(rpos + 1);
796 }
797 }
798 if (return_null_if_empty && s.empty())
799 return nullptr;
800 return s.c_str();
801 }
802
803 bool
StringToBoolean(const char * s,bool fail_value,bool * success_ptr)804 Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr)
805 {
806 llvm::StringRef ref = llvm::StringRef(s).trim();
807 if (ref.equals_lower("false") ||
808 ref.equals_lower("off") ||
809 ref.equals_lower("no") ||
810 ref.equals_lower("0"))
811 {
812 if (success_ptr)
813 *success_ptr = true;
814 return false;
815 }
816 else
817 if (ref.equals_lower("true") ||
818 ref.equals_lower("on") ||
819 ref.equals_lower("yes") ||
820 ref.equals_lower("1"))
821 {
822 if (success_ptr) *success_ptr = true;
823 return true;
824 }
825 if (success_ptr) *success_ptr = false;
826 return fail_value;
827 }
828
829 char
StringToChar(const char * s,char fail_value,bool * success_ptr)830 Args::StringToChar(const char *s, char fail_value, bool *success_ptr)
831 {
832 bool success = false;
833 char result = fail_value;
834
835 if (s)
836 {
837 size_t length = strlen(s);
838 if (length == 1)
839 {
840 success = true;
841 result = s[0];
842 }
843 }
844 if (success_ptr)
845 *success_ptr = success;
846 return result;
847 }
848
849 const char *
StringToVersion(const char * s,uint32_t & major,uint32_t & minor,uint32_t & update)850 Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t &update)
851 {
852 major = UINT32_MAX;
853 minor = UINT32_MAX;
854 update = UINT32_MAX;
855
856 if (s && s[0])
857 {
858 char *pos = nullptr;
859 unsigned long uval32 = ::strtoul (s, &pos, 0);
860 if (pos == s)
861 return s;
862 major = uval32;
863 if (*pos == '\0')
864 {
865 return pos; // Decoded major and got end of string
866 }
867 else if (*pos == '.')
868 {
869 const char *minor_cstr = pos + 1;
870 uval32 = ::strtoul (minor_cstr, &pos, 0);
871 if (pos == minor_cstr)
872 return pos; // Didn't get any digits for the minor version...
873 minor = uval32;
874 if (*pos == '.')
875 {
876 const char *update_cstr = pos + 1;
877 uval32 = ::strtoul (update_cstr, &pos, 0);
878 if (pos == update_cstr)
879 return pos;
880 update = uval32;
881 }
882 return pos;
883 }
884 }
885 return nullptr;
886 }
887
888 const char *
GetShellSafeArgument(const char * unsafe_arg,std::string & safe_arg)889 Args::GetShellSafeArgument (const char *unsafe_arg, std::string &safe_arg)
890 {
891 safe_arg.assign (unsafe_arg);
892 size_t prev_pos = 0;
893 while (prev_pos < safe_arg.size())
894 {
895 // Escape spaces and quotes
896 size_t pos = safe_arg.find_first_of(" '\"", prev_pos);
897 if (pos != std::string::npos)
898 {
899 safe_arg.insert (pos, 1, '\\');
900 prev_pos = pos + 2;
901 }
902 else
903 break;
904 }
905 return safe_arg.c_str();
906 }
907
908
909 int64_t
StringToOptionEnum(const char * s,OptionEnumValueElement * enum_values,int32_t fail_value,Error & error)910 Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error)
911 {
912 if (enum_values)
913 {
914 if (s && s[0])
915 {
916 for (int i = 0; enum_values[i].string_value != nullptr ; i++)
917 {
918 if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value)
919 {
920 error.Clear();
921 return enum_values[i].value;
922 }
923 }
924 }
925
926 StreamString strm;
927 strm.PutCString ("invalid enumeration value, valid values are: ");
928 for (int i = 0; enum_values[i].string_value != nullptr; i++)
929 {
930 strm.Printf ("%s\"%s\"",
931 i > 0 ? ", " : "",
932 enum_values[i].string_value);
933 }
934 error.SetErrorString(strm.GetData());
935 }
936 else
937 {
938 error.SetErrorString ("invalid enumeration argument");
939 }
940 return fail_value;
941 }
942
943 ScriptLanguage
StringToScriptLanguage(const char * s,ScriptLanguage fail_value,bool * success_ptr)944 Args::StringToScriptLanguage (const char *s, ScriptLanguage fail_value, bool *success_ptr)
945 {
946 if (s && s[0])
947 {
948 if ((::strcasecmp (s, "python") == 0) ||
949 (::strcasecmp (s, "default") == 0 && eScriptLanguagePython == eScriptLanguageDefault))
950 {
951 if (success_ptr) *success_ptr = true;
952 return eScriptLanguagePython;
953 }
954 if (::strcasecmp (s, "none"))
955 {
956 if (success_ptr) *success_ptr = true;
957 return eScriptLanguageNone;
958 }
959 }
960 if (success_ptr) *success_ptr = false;
961 return fail_value;
962 }
963
964 Error
StringToFormat(const char * s,lldb::Format & format,size_t * byte_size_ptr)965 Args::StringToFormat
966 (
967 const char *s,
968 lldb::Format &format,
969 size_t *byte_size_ptr
970 )
971 {
972 format = eFormatInvalid;
973 Error error;
974
975 if (s && s[0])
976 {
977 if (byte_size_ptr)
978 {
979 if (isdigit (s[0]))
980 {
981 char *format_char = nullptr;
982 unsigned long byte_size = ::strtoul (s, &format_char, 0);
983 if (byte_size != ULONG_MAX)
984 *byte_size_ptr = byte_size;
985 s = format_char;
986 }
987 else
988 *byte_size_ptr = 0;
989 }
990
991 const bool partial_match_ok = true;
992 if (!FormatManager::GetFormatFromCString (s, partial_match_ok, format))
993 {
994 StreamString error_strm;
995 error_strm.Printf ("Invalid format character or name '%s'. Valid values are:\n", s);
996 for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1))
997 {
998 char format_char = FormatManager::GetFormatAsFormatChar(f);
999 if (format_char)
1000 error_strm.Printf ("'%c' or ", format_char);
1001
1002 error_strm.Printf ("\"%s\"", FormatManager::GetFormatAsCString(f));
1003 error_strm.EOL();
1004 }
1005
1006 if (byte_size_ptr)
1007 error_strm.PutCString ("An optional byte size can precede the format character.\n");
1008 error.SetErrorString(error_strm.GetString().c_str());
1009 }
1010
1011 if (error.Fail())
1012 return error;
1013 }
1014 else
1015 {
1016 error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid");
1017 }
1018 return error;
1019 }
1020
1021 lldb::Encoding
StringToEncoding(const char * s,lldb::Encoding fail_value)1022 Args::StringToEncoding (const char *s, lldb::Encoding fail_value)
1023 {
1024 if (s && s[0])
1025 {
1026 if (strcmp(s, "uint") == 0)
1027 return eEncodingUint;
1028 else if (strcmp(s, "sint") == 0)
1029 return eEncodingSint;
1030 else if (strcmp(s, "ieee754") == 0)
1031 return eEncodingIEEE754;
1032 else if (strcmp(s, "vector") == 0)
1033 return eEncodingVector;
1034 }
1035 return fail_value;
1036 }
1037
1038 uint32_t
StringToGenericRegister(const char * s)1039 Args::StringToGenericRegister (const char *s)
1040 {
1041 if (s && s[0])
1042 {
1043 if (strcmp(s, "pc") == 0)
1044 return LLDB_REGNUM_GENERIC_PC;
1045 else if (strcmp(s, "sp") == 0)
1046 return LLDB_REGNUM_GENERIC_SP;
1047 else if (strcmp(s, "fp") == 0)
1048 return LLDB_REGNUM_GENERIC_FP;
1049 else if (strcmp(s, "ra") == 0 || strcmp(s, "lr") == 0)
1050 return LLDB_REGNUM_GENERIC_RA;
1051 else if (strcmp(s, "flags") == 0)
1052 return LLDB_REGNUM_GENERIC_FLAGS;
1053 else if (strncmp(s, "arg", 3) == 0)
1054 {
1055 if (s[3] && s[4] == '\0')
1056 {
1057 switch (s[3])
1058 {
1059 case '1': return LLDB_REGNUM_GENERIC_ARG1;
1060 case '2': return LLDB_REGNUM_GENERIC_ARG2;
1061 case '3': return LLDB_REGNUM_GENERIC_ARG3;
1062 case '4': return LLDB_REGNUM_GENERIC_ARG4;
1063 case '5': return LLDB_REGNUM_GENERIC_ARG5;
1064 case '6': return LLDB_REGNUM_GENERIC_ARG6;
1065 case '7': return LLDB_REGNUM_GENERIC_ARG7;
1066 case '8': return LLDB_REGNUM_GENERIC_ARG8;
1067 }
1068 }
1069 }
1070 }
1071 return LLDB_INVALID_REGNUM;
1072 }
1073
1074
1075 void
LongestCommonPrefix(std::string & common_prefix)1076 Args::LongestCommonPrefix (std::string &common_prefix)
1077 {
1078 arg_sstr_collection::iterator pos, end = m_args.end();
1079 pos = m_args.begin();
1080 if (pos == end)
1081 common_prefix.clear();
1082 else
1083 common_prefix = (*pos);
1084
1085 for (++pos; pos != end; ++pos)
1086 {
1087 size_t new_size = (*pos).size();
1088
1089 // First trim common_prefix if it is longer than the current element:
1090 if (common_prefix.size() > new_size)
1091 common_prefix.erase (new_size);
1092
1093 // Then trim it at the first disparity:
1094
1095 for (size_t i = 0; i < common_prefix.size(); i++)
1096 {
1097 if ((*pos)[i] != common_prefix[i])
1098 {
1099 common_prefix.erase(i);
1100 break;
1101 }
1102 }
1103
1104 // If we've emptied the common prefix, we're done.
1105 if (common_prefix.empty())
1106 break;
1107 }
1108 }
1109
1110 size_t
FindArgumentIndexForOption(Option * long_options,int long_options_index)1111 Args::FindArgumentIndexForOption (Option *long_options, int long_options_index)
1112 {
1113 char short_buffer[3];
1114 char long_buffer[255];
1115 ::snprintf (short_buffer, sizeof (short_buffer), "-%c", long_options[long_options_index].val);
1116 ::snprintf (long_buffer, sizeof (long_buffer), "--%s", long_options[long_options_index].definition->long_option);
1117 size_t end = GetArgumentCount ();
1118 size_t idx = 0;
1119 while (idx < end)
1120 {
1121 if ((::strncmp (GetArgumentAtIndex (idx), short_buffer, strlen (short_buffer)) == 0)
1122 || (::strncmp (GetArgumentAtIndex (idx), long_buffer, strlen (long_buffer)) == 0))
1123 {
1124 return idx;
1125 }
1126 ++idx;
1127 }
1128
1129 return end;
1130 }
1131
1132 bool
IsPositionalArgument(const char * arg)1133 Args::IsPositionalArgument (const char *arg)
1134 {
1135 if (arg == nullptr)
1136 return false;
1137
1138 bool is_positional = true;
1139 const char *cptr = arg;
1140
1141 if (cptr[0] == '%')
1142 {
1143 ++cptr;
1144 while (isdigit (cptr[0]))
1145 ++cptr;
1146 if (cptr[0] != '\0')
1147 is_positional = false;
1148 }
1149 else
1150 is_positional = false;
1151
1152 return is_positional;
1153 }
1154
1155 void
ParseAliasOptions(Options & options,CommandReturnObject & result,OptionArgVector * option_arg_vector,std::string & raw_input_string)1156 Args::ParseAliasOptions (Options &options,
1157 CommandReturnObject &result,
1158 OptionArgVector *option_arg_vector,
1159 std::string &raw_input_string)
1160 {
1161 StreamString sstr;
1162 int i;
1163 Option *long_options = options.GetLongOptions();
1164
1165 if (long_options == nullptr)
1166 {
1167 result.AppendError ("invalid long options");
1168 result.SetStatus (eReturnStatusFailed);
1169 return;
1170 }
1171
1172 for (i = 0; long_options[i].definition != nullptr; ++i)
1173 {
1174 if (long_options[i].flag == nullptr)
1175 {
1176 sstr << (char) long_options[i].val;
1177 switch (long_options[i].definition->option_has_arg)
1178 {
1179 default:
1180 case OptionParser::eNoArgument:
1181 break;
1182 case OptionParser::eRequiredArgument:
1183 sstr << ":";
1184 break;
1185 case OptionParser::eOptionalArgument:
1186 sstr << "::";
1187 break;
1188 }
1189 }
1190 }
1191
1192 OptionParser::Prepare();
1193 int val;
1194 while (1)
1195 {
1196 int long_options_index = -1;
1197 val = OptionParser::Parse (GetArgumentCount(),
1198 GetArgumentVector(),
1199 sstr.GetData(),
1200 long_options,
1201 &long_options_index);
1202
1203 if (val == -1)
1204 break;
1205
1206 if (val == '?')
1207 {
1208 result.AppendError ("unknown or ambiguous option");
1209 result.SetStatus (eReturnStatusFailed);
1210 break;
1211 }
1212
1213 if (val == 0)
1214 continue;
1215
1216 options.OptionSeen (val);
1217
1218 // Look up the long option index
1219 if (long_options_index == -1)
1220 {
1221 for (int j = 0;
1222 long_options[j].definition || long_options[j].flag || long_options[j].val;
1223 ++j)
1224 {
1225 if (long_options[j].val == val)
1226 {
1227 long_options_index = j;
1228 break;
1229 }
1230 }
1231 }
1232
1233 // See if the option takes an argument, and see if one was supplied.
1234 if (long_options_index >= 0)
1235 {
1236 StreamString option_str;
1237 option_str.Printf ("-%c", val);
1238 const OptionDefinition *def = long_options[long_options_index].definition;
1239 int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
1240
1241 switch (has_arg)
1242 {
1243 case OptionParser::eNoArgument:
1244 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
1245 OptionArgValue (OptionParser::eNoArgument, "<no-argument>")));
1246 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1247 break;
1248 case OptionParser::eRequiredArgument:
1249 if (OptionParser::GetOptionArgument() != nullptr)
1250 {
1251 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
1252 OptionArgValue (OptionParser::eRequiredArgument,
1253 std::string (OptionParser::GetOptionArgument()))));
1254 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1255 }
1256 else
1257 {
1258 result.AppendErrorWithFormat ("Option '%s' is missing argument specifier.\n",
1259 option_str.GetData());
1260 result.SetStatus (eReturnStatusFailed);
1261 }
1262 break;
1263 case OptionParser::eOptionalArgument:
1264 if (OptionParser::GetOptionArgument() != nullptr)
1265 {
1266 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
1267 OptionArgValue (OptionParser::eOptionalArgument,
1268 std::string (OptionParser::GetOptionArgument()))));
1269 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1270 }
1271 else
1272 {
1273 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
1274 OptionArgValue (OptionParser::eOptionalArgument, "<no-argument>")));
1275 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1276 }
1277 break;
1278 default:
1279 result.AppendErrorWithFormat ("error with options table; invalid value in has_arg field for option '%c'.\n", val);
1280 result.SetStatus (eReturnStatusFailed);
1281 break;
1282 }
1283 }
1284 else
1285 {
1286 result.AppendErrorWithFormat ("Invalid option with value '%c'.\n", val);
1287 result.SetStatus (eReturnStatusFailed);
1288 }
1289
1290 if (long_options_index >= 0)
1291 {
1292 // Find option in the argument list; also see if it was supposed to take an argument and if one was
1293 // supplied. Remove option (and argument, if given) from the argument list. Also remove them from
1294 // the raw_input_string, if one was passed in.
1295 size_t idx = FindArgumentIndexForOption (long_options, long_options_index);
1296 if (idx < GetArgumentCount())
1297 {
1298 if (raw_input_string.size() > 0)
1299 {
1300 const char *tmp_arg = GetArgumentAtIndex (idx);
1301 size_t pos = raw_input_string.find (tmp_arg);
1302 if (pos != std::string::npos)
1303 raw_input_string.erase (pos, strlen (tmp_arg));
1304 }
1305 ReplaceArgumentAtIndex (idx, "");
1306 if ((long_options[long_options_index].definition->option_has_arg != OptionParser::eNoArgument)
1307 && (OptionParser::GetOptionArgument() != nullptr)
1308 && (idx+1 < GetArgumentCount())
1309 && (strcmp (OptionParser::GetOptionArgument(), GetArgumentAtIndex(idx+1)) == 0))
1310 {
1311 if (raw_input_string.size() > 0)
1312 {
1313 const char *tmp_arg = GetArgumentAtIndex (idx+1);
1314 size_t pos = raw_input_string.find (tmp_arg);
1315 if (pos != std::string::npos)
1316 raw_input_string.erase (pos, strlen (tmp_arg));
1317 }
1318 ReplaceArgumentAtIndex (idx+1, "");
1319 }
1320 }
1321 }
1322
1323 if (!result.Succeeded())
1324 break;
1325 }
1326 }
1327
1328 void
ParseArgsForCompletion(Options & options,OptionElementVector & option_element_vector,uint32_t cursor_index)1329 Args::ParseArgsForCompletion
1330 (
1331 Options &options,
1332 OptionElementVector &option_element_vector,
1333 uint32_t cursor_index
1334 )
1335 {
1336 StreamString sstr;
1337 Option *long_options = options.GetLongOptions();
1338 option_element_vector.clear();
1339
1340 if (long_options == nullptr)
1341 {
1342 return;
1343 }
1344
1345 // Leading : tells getopt to return a : for a missing option argument AND
1346 // to suppress error messages.
1347
1348 sstr << ":";
1349 for (int i = 0; long_options[i].definition != nullptr; ++i)
1350 {
1351 if (long_options[i].flag == nullptr)
1352 {
1353 sstr << (char) long_options[i].val;
1354 switch (long_options[i].definition->option_has_arg)
1355 {
1356 default:
1357 case OptionParser::eNoArgument:
1358 break;
1359 case OptionParser::eRequiredArgument:
1360 sstr << ":";
1361 break;
1362 case OptionParser::eOptionalArgument:
1363 sstr << "::";
1364 break;
1365 }
1366 }
1367 }
1368
1369 OptionParser::Prepare();
1370 OptionParser::EnableError(false);
1371
1372 int val;
1373 const OptionDefinition *opt_defs = options.GetDefinitions();
1374
1375 // Fooey... OptionParser::Parse permutes the GetArgumentVector to move the options to the front.
1376 // So we have to build another Arg and pass that to OptionParser::Parse so it doesn't
1377 // change the one we have.
1378
1379 std::vector<const char *> dummy_vec (GetArgumentVector(), GetArgumentVector() + GetArgumentCount() + 1);
1380
1381 bool failed_once = false;
1382 uint32_t dash_dash_pos = -1;
1383
1384 while (1)
1385 {
1386 bool missing_argument = false;
1387 int long_options_index = -1;
1388
1389 val = OptionParser::Parse (dummy_vec.size() - 1,
1390 (char *const *) &dummy_vec.front(),
1391 sstr.GetData(),
1392 long_options,
1393 &long_options_index);
1394
1395 if (val == -1)
1396 {
1397 // When we're completing a "--" which is the last option on line,
1398 if (failed_once)
1399 break;
1400
1401 failed_once = true;
1402
1403 // If this is a bare "--" we mark it as such so we can complete it successfully later.
1404 // Handling the "--" is a little tricky, since that may mean end of options or arguments, or the
1405 // user might want to complete options by long name. I make this work by checking whether the
1406 // cursor is in the "--" argument, and if so I assume we're completing the long option, otherwise
1407 // I let it pass to OptionParser::Parse which will terminate the option parsing.
1408 // Note, in either case we continue parsing the line so we can figure out what other options
1409 // were passed. This will be useful when we come to restricting completions based on what other
1410 // options we've seen on the line.
1411
1412 if (static_cast<size_t>(OptionParser::GetOptionIndex()) < dummy_vec.size() - 1
1413 && (strcmp (dummy_vec[OptionParser::GetOptionIndex()-1], "--") == 0))
1414 {
1415 dash_dash_pos = OptionParser::GetOptionIndex() - 1;
1416 if (static_cast<size_t>(OptionParser::GetOptionIndex() - 1) == cursor_index)
1417 {
1418 option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDoubleDash, OptionParser::GetOptionIndex() - 1,
1419 OptionArgElement::eBareDoubleDash));
1420 continue;
1421 }
1422 else
1423 break;
1424 }
1425 else
1426 break;
1427 }
1428 else if (val == '?')
1429 {
1430 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1,
1431 OptionArgElement::eUnrecognizedArg));
1432 continue;
1433 }
1434 else if (val == 0)
1435 {
1436 continue;
1437 }
1438 else if (val == ':')
1439 {
1440 // This is a missing argument.
1441 val = OptionParser::GetOptionErrorCause();
1442 missing_argument = true;
1443 }
1444
1445 ((Options *) &options)->OptionSeen (val);
1446
1447 // Look up the long option index
1448 if (long_options_index == -1)
1449 {
1450 for (int j = 0;
1451 long_options[j].definition || long_options[j].flag || long_options[j].val;
1452 ++j)
1453 {
1454 if (long_options[j].val == val)
1455 {
1456 long_options_index = j;
1457 break;
1458 }
1459 }
1460 }
1461
1462 // See if the option takes an argument, and see if one was supplied.
1463 if (long_options_index >= 0)
1464 {
1465 int opt_defs_index = -1;
1466 for (int i = 0; ; i++)
1467 {
1468 if (opt_defs[i].short_option == 0)
1469 break;
1470 else if (opt_defs[i].short_option == val)
1471 {
1472 opt_defs_index = i;
1473 break;
1474 }
1475 }
1476
1477 const OptionDefinition *def = long_options[long_options_index].definition;
1478 int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
1479 switch (has_arg)
1480 {
1481 case OptionParser::eNoArgument:
1482 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, 0));
1483 break;
1484 case OptionParser::eRequiredArgument:
1485 if (OptionParser::GetOptionArgument() != nullptr)
1486 {
1487 int arg_index;
1488 if (missing_argument)
1489 arg_index = -1;
1490 else
1491 arg_index = OptionParser::GetOptionIndex() - 1;
1492
1493 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, arg_index));
1494 }
1495 else
1496 {
1497 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, -1));
1498 }
1499 break;
1500 case OptionParser::eOptionalArgument:
1501 if (OptionParser::GetOptionArgument() != nullptr)
1502 {
1503 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, OptionParser::GetOptionIndex() - 1));
1504 }
1505 else
1506 {
1507 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, OptionParser::GetOptionIndex() - 1));
1508 }
1509 break;
1510 default:
1511 // The options table is messed up. Here we'll just continue
1512 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1,
1513 OptionArgElement::eUnrecognizedArg));
1514 break;
1515 }
1516 }
1517 else
1518 {
1519 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1,
1520 OptionArgElement::eUnrecognizedArg));
1521 }
1522 }
1523
1524 // Finally we have to handle the case where the cursor index points at a single "-". We want to mark that in
1525 // the option_element_vector, but only if it is not after the "--". But it turns out that OptionParser::Parse just ignores
1526 // an isolated "-". So we have to look it up by hand here. We only care if it is AT the cursor position.
1527 // Note, a single quoted dash is not the same as a single dash...
1528
1529 if ((static_cast<int32_t>(dash_dash_pos) == -1 || cursor_index < dash_dash_pos)
1530 && m_args_quote_char[cursor_index] == '\0'
1531 && strcmp (GetArgumentAtIndex(cursor_index), "-") == 0)
1532 {
1533 option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDash, cursor_index,
1534 OptionArgElement::eBareDash));
1535
1536 }
1537 }
1538
1539 void
EncodeEscapeSequences(const char * src,std::string & dst)1540 Args::EncodeEscapeSequences (const char *src, std::string &dst)
1541 {
1542 dst.clear();
1543 if (src)
1544 {
1545 for (const char *p = src; *p != '\0'; ++p)
1546 {
1547 size_t non_special_chars = ::strcspn (p, "\\");
1548 if (non_special_chars > 0)
1549 {
1550 dst.append(p, non_special_chars);
1551 p += non_special_chars;
1552 if (*p == '\0')
1553 break;
1554 }
1555
1556 if (*p == '\\')
1557 {
1558 ++p; // skip the slash
1559 switch (*p)
1560 {
1561 case 'a' : dst.append(1, '\a'); break;
1562 case 'b' : dst.append(1, '\b'); break;
1563 case 'f' : dst.append(1, '\f'); break;
1564 case 'n' : dst.append(1, '\n'); break;
1565 case 'r' : dst.append(1, '\r'); break;
1566 case 't' : dst.append(1, '\t'); break;
1567 case 'v' : dst.append(1, '\v'); break;
1568 case '\\': dst.append(1, '\\'); break;
1569 case '\'': dst.append(1, '\''); break;
1570 case '"' : dst.append(1, '"'); break;
1571 case '0' :
1572 // 1 to 3 octal chars
1573 {
1574 // Make a string that can hold onto the initial zero char,
1575 // up to 3 octal digits, and a terminating NULL.
1576 char oct_str[5] = { '\0', '\0', '\0', '\0', '\0' };
1577
1578 int i;
1579 for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i)
1580 oct_str[i] = p[i];
1581
1582 // We don't want to consume the last octal character since
1583 // the main for loop will do this for us, so we advance p by
1584 // one less than i (even if i is zero)
1585 p += i - 1;
1586 unsigned long octal_value = ::strtoul (oct_str, nullptr, 8);
1587 if (octal_value <= UINT8_MAX)
1588 {
1589 dst.append(1, (char)octal_value);
1590 }
1591 }
1592 break;
1593
1594 case 'x':
1595 // hex number in the format
1596 if (isxdigit(p[1]))
1597 {
1598 ++p; // Skip the 'x'
1599
1600 // Make a string that can hold onto two hex chars plus a
1601 // NULL terminator
1602 char hex_str[3] = { *p, '\0', '\0' };
1603 if (isxdigit(p[1]))
1604 {
1605 ++p; // Skip the first of the two hex chars
1606 hex_str[1] = *p;
1607 }
1608
1609 unsigned long hex_value = strtoul (hex_str, nullptr, 16);
1610 if (hex_value <= UINT8_MAX)
1611 dst.append (1, (char)hex_value);
1612 }
1613 else
1614 {
1615 dst.append(1, 'x');
1616 }
1617 break;
1618
1619 default:
1620 // Just desensitize any other character by just printing what
1621 // came after the '\'
1622 dst.append(1, *p);
1623 break;
1624
1625 }
1626 }
1627 }
1628 }
1629 }
1630
1631
1632 void
ExpandEscapedCharacters(const char * src,std::string & dst)1633 Args::ExpandEscapedCharacters (const char *src, std::string &dst)
1634 {
1635 dst.clear();
1636 if (src)
1637 {
1638 for (const char *p = src; *p != '\0'; ++p)
1639 {
1640 if (isprint8(*p))
1641 dst.append(1, *p);
1642 else
1643 {
1644 switch (*p)
1645 {
1646 case '\a': dst.append("\\a"); break;
1647 case '\b': dst.append("\\b"); break;
1648 case '\f': dst.append("\\f"); break;
1649 case '\n': dst.append("\\n"); break;
1650 case '\r': dst.append("\\r"); break;
1651 case '\t': dst.append("\\t"); break;
1652 case '\v': dst.append("\\v"); break;
1653 case '\'': dst.append("\\'"); break;
1654 case '"': dst.append("\\\""); break;
1655 case '\\': dst.append("\\\\"); break;
1656 default:
1657 {
1658 // Just encode as octal
1659 dst.append("\\0");
1660 char octal_str[32];
1661 snprintf(octal_str, sizeof(octal_str), "%o", *p);
1662 dst.append(octal_str);
1663 }
1664 break;
1665 }
1666 }
1667 }
1668 }
1669 }
1670
1671