xref: /NextBSD/contrib/llvm/tools/lldb/source/Interpreter/Args.cpp (revision 84d351007654069f9643c8e4b4802a7f5f08ee42)
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, &regex_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