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
31using namespace lldb;
32using namespace lldb_private;
33
34//----------------------------------------------------------------------
35// Args constructor
36//----------------------------------------------------------------------
37Args::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
47Args::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//----------------------------------------------------------------------
63Args::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//----------------------------------------------------------------------
78const Args &
79Args::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//----------------------------------------------------------------------
94Args::~Args ()
95{
96}
97
98void
99Args::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
114bool
115Args::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
128bool
129Args::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
150void
151Args::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
159void
160Args::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
362void
363Args::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
404void
405Args::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
417size_t
418Args::GetArgumentCount() const
419{
420    if (m_argv.empty())
421        return 0;
422    return m_argv.size() - 1;
423}
424
425const char *
426Args::GetArgumentAtIndex (size_t idx) const
427{
428    if (idx < m_argv.size())
429        return m_argv[idx];
430    return NULL;
431}
432
433char
434Args::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
441char **
442Args::GetArgumentVector()
443{
444    if (!m_argv.empty())
445        return (char **)&m_argv[0];
446    return NULL;
447}
448
449const char **
450Args::GetConstArgumentVector() const
451{
452    if (!m_argv.empty())
453        return (const char **)&m_argv[0];
454    return NULL;
455}
456
457void
458Args::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
470const char *
471Args::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
479void
480Args::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
487void
488Args::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
497const char *
498Args::AppendArgument (const char *arg_cstr, char quote_char)
499{
500    return InsertArgumentAtIndex (GetArgumentCount(), arg_cstr, quote_char);
501}
502
503const char *
504Args::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
528const char *
529Args::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
552void
553Args::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
573void
574Args::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
594void
595Args::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
619Error
620Args::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
712void
713Args::Clear ()
714{
715    m_args.clear ();
716    m_argv.clear ();
717    m_args_quote_char.clear();
718}
719
720int32_t
721Args::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
738uint32_t
739Args::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
757int64_t
758Args::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
774uint64_t
775Args::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
791lldb::addr_t
792Args::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
909const char *
910Args::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
936bool
937Args::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
964const char *
965Args::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
1003const char *
1004Args::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
1024int64_t
1025Args::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
1058ScriptLanguage
1059Args::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
1079Error
1080Args::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
1136lldb::Encoding
1137Args::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
1153uint32_t
1154Args::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
1190void
1191Args::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
1225size_t
1226Args::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
1247bool
1248Args::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
1270void
1271Args::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
1446void
1447Args::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
1658void
1659Args::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
1751void
1752Args::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