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