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