Bug Summary

File:tools/lldb/source/Interpreter/Args.cpp
Location:line 692, column 42
Description:Access to field 'validator' results in a dereference of a null pointer (loaded from variable 'def')

Annotated Source Code

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/CommandInterpreter.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 = nullptr;
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...")((!"Unhandled case statement, we must handle this...") ? static_cast
<void> (0) : __assert_fail ("!\"Unhandled case statement, we must handle this...\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.6~svn219601/tools/lldb/source/Interpreter/Args.cpp"
, 210, __PRETTY_FUNCTION__))
;
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 == nullptr)
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(nullptr);
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 nullptr;
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 nullptr;
447}
448
449const char **
450Args::GetConstArgumentVector() const
451{
452 if (!m_argv.empty())
453 return (const char **)&m_argv[0];
454 return nullptr;
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)((idx < m_argv.size() - 1) ? static_cast<void> (0) :
__assert_fail ("idx < m_argv.size() - 1", "/tmp/buildd/llvm-toolchain-snapshot-3.6~svn219601/tools/lldb/source/Interpreter/Args.cpp"
, 542, __PRETTY_FUNCTION__))
;
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 nullptr;
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)((idx < m_argv.size() - 1) ? static_cast<void> (0) :
__assert_fail ("idx < m_argv.size() - 1", "/tmp/buildd/llvm-toolchain-snapshot-3.6~svn219601/tools/lldb/source/Interpreter/Args.cpp"
, 566, __PRETTY_FUNCTION__))
;
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 Option *long_options = options.GetLongOptions();
625 if (long_options == nullptr)
1
Taking false branch
626 {
627 error.SetErrorStringWithFormat("invalid long options");
628 return error;
629 }
630
631 for (int i=0; long_options[i].definition != nullptr; ++i)
2
Assuming pointer value is null
3
Loop condition is false. Execution continues on line 648
632 {
633 if (long_options[i].flag == nullptr)
634 {
635 if (isprint8(long_options[i].val))
636 {
637 sstr << (char)long_options[i].val;
638 switch (long_options[i].definition->option_has_arg)
639 {
640 default:
641 case OptionParser::eNoArgument: break;
642 case OptionParser::eRequiredArgument: sstr << ':'; break;
643 case OptionParser::eOptionalArgument: sstr << "::"; break;
644 }
645 }
646 }
647 }
648 OptionParser::Prepare();
649 int val;
650 while (1)
4
Loop condition is true. Entering loop body
13
Loop condition is true. Entering loop body
22
Loop condition is true. Entering loop body
31
Loop condition is true. Entering loop body
651 {
652 int long_options_index = -1;
653 val = OptionParser::Parse(GetArgumentCount(),
654 GetArgumentVector(),
655 sstr.GetData(),
656 long_options,
657 &long_options_index);
658 if (val == -1)
5
Taking false branch
14
Taking false branch
23
Taking false branch
32
Taking false branch
659 break;
660
661 // Did we get an error?
662 if (val == '?')
6
Taking false branch
15
Taking false branch
24
Taking false branch
33
Taking false branch
663 {
664 error.SetErrorStringWithFormat("unknown or ambiguous option");
665 break;
666 }
667 // The option auto-set itself
668 if (val == 0)
7
Assuming 'val' is not equal to 0
8
Taking false branch
16
Assuming 'val' is not equal to 0
17
Taking false branch
25
Assuming 'val' is not equal to 0
26
Taking false branch
34
Assuming 'val' is not equal to 0
35
Taking false branch
669 continue;
670
671 ((Options *) &options)->OptionSeen (val);
672
673 // Lookup the long option index
674 if (long_options_index == -1)
9
Taking false branch
18
Taking false branch
27
Taking false branch
36
Taking true branch
675 {
676 for (int i=0;
677 long_options[i].definition || long_options[i].flag || long_options[i].val;
678 ++i)
679 {
680 if (long_options[i].val == val)
37
Taking true branch
681 {
682 long_options_index = i;
683 break;
38
Execution continues on line 688
684 }
685 }
686 }
687 // Call the callback with the option
688 if (long_options_index >= 0)
10
Assuming 'long_options_index' is < 0
11
Taking false branch
19
Assuming 'long_options_index' is < 0
20
Taking false branch
28
Assuming 'long_options_index' is < 0
29
Taking false branch
39
Taking true branch
689 {
690 const OptionDefinition *def = long_options[long_options_index].definition;
40
'def' initialized to a null pointer value
691 CommandInterpreter &interpreter = options.GetInterpreter();
692 OptionValidator *validator = def->validator;
41
Access to field 'validator' results in a dereference of a null pointer (loaded from variable 'def')
693 if (validator && !validator->IsValid(*interpreter.GetPlatform(true), interpreter.GetExecutionContext()))
694 {
695 error.SetErrorStringWithFormat("Option \"%s\" invalid. %s", def->long_option, def->validator->LongConditionString());
696 }
697 else
698 {
699 error = options.SetOptionValue(long_options_index,
700 (def->option_has_arg == OptionParser::eNoArgument) ? nullptr : OptionParser::GetOptionArgument());
701 }
702 }
703 else
704 {
705 error.SetErrorStringWithFormat("invalid option with value '%i'", val);
706 }
707 if (error.Fail())
12
Taking false branch
21
Taking false branch
30
Taking false branch
708 break;
709 }
710
711 // Update our ARGV now that get options has consumed all the options
712 m_argv.erase(m_argv.begin(), m_argv.begin() + OptionParser::GetOptionIndex());
713 UpdateArgsAfterOptionParsing ();
714 return error;
715}
716
717void
718Args::Clear ()
719{
720 m_args.clear ();
721 m_argv.clear ();
722 m_args_quote_char.clear();
723}
724
725int32_t
726Args::StringToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr)
727{
728 if (s && s[0])
729 {
730 char *end = nullptr;
731 const long sval = ::strtol (s, &end, base);
732 if (*end == '\0')
733 {
734 if (success_ptr)
735 *success_ptr = ((sval <= INT32_MAX(2147483647)) && (sval >= INT32_MIN(-2147483647-1)));
736 return (int32_t)sval; // All characters were used, return the result
737 }
738 }
739 if (success_ptr) *success_ptr = false;
740 return fail_value;
741}
742
743uint32_t
744Args::StringToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr)
745{
746 if (s && s[0])
747 {
748 char *end = nullptr;
749 const unsigned long uval = ::strtoul (s, &end, base);
750 if (*end == '\0')
751 {
752 if (success_ptr)
753 *success_ptr = (uval <= UINT32_MAX(4294967295U));
754 return (uint32_t)uval; // All characters were used, return the result
755 }
756 }
757 if (success_ptr) *success_ptr = false;
758 return fail_value;
759}
760
761
762int64_t
763Args::StringToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr)
764{
765 if (s && s[0])
766 {
767 char *end = nullptr;
768 int64_t uval = ::strtoll (s, &end, base);
769 if (*end == '\0')
770 {
771 if (success_ptr) *success_ptr = true;
772 return uval; // All characters were used, return the result
773 }
774 }
775 if (success_ptr) *success_ptr = false;
776 return fail_value;
777}
778
779uint64_t
780Args::StringToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr)
781{
782 if (s && s[0])
783 {
784 char *end = nullptr;
785 uint64_t uval = ::strtoull (s, &end, base);
786 if (*end == '\0')
787 {
788 if (success_ptr) *success_ptr = true;
789 return uval; // All characters were used, return the result
790 }
791 }
792 if (success_ptr) *success_ptr = false;
793 return fail_value;
794}
795
796lldb::addr_t
797Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::addr_t fail_value, Error *error_ptr)
798{
799 bool error_set = false;
800 if (s && s[0])
801 {
802 char *end = nullptr;
803 lldb::addr_t addr = ::strtoull (s, &end, 0);
804 if (*end == '\0')
805 {
806 if (error_ptr)
807 error_ptr->Clear();
808 return addr; // All characters were used, return the result
809 }
810 // Try base 16 with no prefix...
811 addr = ::strtoull (s, &end, 16);
812 if (*end == '\0')
813 {
814 if (error_ptr)
815 error_ptr->Clear();
816 return addr; // All characters were used, return the result
817 }
818
819 if (exe_ctx)
820 {
821 Target *target = exe_ctx->GetTargetPtr();
822 if (target)
823 {
824 lldb::ValueObjectSP valobj_sp;
825 EvaluateExpressionOptions options;
826 options.SetCoerceToId(false);
827 options.SetUnwindOnError(true);
828 options.SetKeepInMemory(false);
829 options.SetTryAllThreads(true);
830
831 ExpressionResults expr_result = target->EvaluateExpression(s,
832 exe_ctx->GetFramePtr(),
833 valobj_sp,
834 options);
835
836 bool success = false;
837 if (expr_result == eExpressionCompleted)
838 {
839 if (valobj_sp)
840 valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable(valobj_sp->GetDynamicValueType(), true);
841 // Get the address to watch.
842 if (valobj_sp)
843 addr = valobj_sp->GetValueAsUnsigned(fail_value, &success);
844 if (success)
845 {
846 if (error_ptr)
847 error_ptr->Clear();
848 return addr;
849 }
850 else
851 {
852 if (error_ptr)
853 {
854 error_set = true;
855 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());
856 }
857 }
858
859 }
860 else
861 {
862 // Since the compiler can't handle things like "main + 12" we should
863 // try to do this for now. The compliler doesn't like adding offsets
864 // to function pointer types.
865 static RegularExpression g_symbol_plus_offset_regex("^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$");
866 RegularExpression::Match regex_match(3);
867 if (g_symbol_plus_offset_regex.Execute(s, &regex_match))
868 {
869 uint64_t offset = 0;
870 bool add = true;
871 std::string name;
872 std::string str;
873 if (regex_match.GetMatchAtIndex(s, 1, name))
874 {
875 if (regex_match.GetMatchAtIndex(s, 2, str))
876 {
877 add = str[0] == '+';
878
879 if (regex_match.GetMatchAtIndex(s, 3, str))
880 {
881 offset = Args::StringToUInt64(str.c_str(), 0, 0, &success);
882
883 if (success)
884 {
885 Error error;
886 addr = StringToAddress (exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS(18446744073709551615UL), &error);
887 if (addr != LLDB_INVALID_ADDRESS(18446744073709551615UL))
888 {
889 if (add)
890 return addr + offset;
891 else
892 return addr - offset;
893 }
894 }
895 }
896 }
897 }
898 }
899
900 if (error_ptr)
901 {
902 error_set = true;
903 error_ptr->SetErrorStringWithFormat("address expression \"%s\" evaluation failed", s);
904 }
905 }
906 }
907 }
908 }
909 if (error_ptr)
910 {
911 if (!error_set)
912 error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", s);
913 }
914 return fail_value;
915}
916
917const char *
918Args::StripSpaces (std::string &s, bool leading, bool trailing, bool return_null_if_empty)
919{
920 static const char *k_white_space = " \t\v";
921 if (!s.empty())
922 {
923 if (leading)
924 {
925 size_t pos = s.find_first_not_of (k_white_space);
926 if (pos == std::string::npos)
927 s.clear();
928 else if (pos > 0)
929 s.erase(0, pos);
930 }
931
932 if (trailing)
933 {
934 size_t rpos = s.find_last_not_of(k_white_space);
935 if (rpos != std::string::npos && rpos + 1 < s.size())
936 s.erase(rpos + 1);
937 }
938 }
939 if (return_null_if_empty && s.empty())
940 return nullptr;
941 return s.c_str();
942}
943
944bool
945Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr)
946{
947 if (s && s[0])
948 {
949 if (::strcasecmp (s, "false") == 0 ||
950 ::strcasecmp (s, "off") == 0 ||
951 ::strcasecmp (s, "no") == 0 ||
952 ::strcmp (s, "0") == 0)
953 {
954 if (success_ptr)
955 *success_ptr = true;
956 return false;
957 }
958 else
959 if (::strcasecmp (s, "true") == 0 ||
960 ::strcasecmp (s, "on") == 0 ||
961 ::strcasecmp (s, "yes") == 0 ||
962 ::strcmp (s, "1") == 0)
963 {
964 if (success_ptr) *success_ptr = true;
965 return true;
966 }
967 }
968 if (success_ptr) *success_ptr = false;
969 return fail_value;
970}
971
972const char *
973Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t &update)
974{
975 major = UINT32_MAX(4294967295U);
976 minor = UINT32_MAX(4294967295U);
977 update = UINT32_MAX(4294967295U);
978
979 if (s && s[0])
980 {
981 char *pos = nullptr;
982 unsigned long uval32 = ::strtoul (s, &pos, 0);
983 if (pos == s)
984 return s;
985 major = uval32;
986 if (*pos == '\0')
987 {
988 return pos; // Decoded major and got end of string
989 }
990 else if (*pos == '.')
991 {
992 const char *minor_cstr = pos + 1;
993 uval32 = ::strtoul (minor_cstr, &pos, 0);
994 if (pos == minor_cstr)
995 return pos; // Didn't get any digits for the minor version...
996 minor = uval32;
997 if (*pos == '.')
998 {
999 const char *update_cstr = pos + 1;
1000 uval32 = ::strtoul (update_cstr, &pos, 0);
1001 if (pos == update_cstr)
1002 return pos;
1003 update = uval32;
1004 }
1005 return pos;
1006 }
1007 }
1008 return nullptr;
1009}
1010
1011const char *
1012Args::GetShellSafeArgument (const char *unsafe_arg, std::string &safe_arg)
1013{
1014 safe_arg.assign (unsafe_arg);
1015 size_t prev_pos = 0;
1016 while (prev_pos < safe_arg.size())
1017 {
1018 // Escape spaces and quotes
1019 size_t pos = safe_arg.find_first_of(" '\"", prev_pos);
1020 if (pos != std::string::npos)
1021 {
1022 safe_arg.insert (pos, 1, '\\');
1023 prev_pos = pos + 2;
1024 }
1025 else
1026 break;
1027 }
1028 return safe_arg.c_str();
1029}
1030
1031
1032int64_t
1033Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error)
1034{
1035 if (enum_values)
1036 {
1037 if (s && s[0])
1038 {
1039 for (int i = 0; enum_values[i].string_value != nullptr ; i++)
1040 {
1041 if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value)
1042 {
1043 error.Clear();
1044 return enum_values[i].value;
1045 }
1046 }
1047 }
1048
1049 StreamString strm;
1050 strm.PutCString ("invalid enumeration value, valid values are: ");
1051 for (int i = 0; enum_values[i].string_value != nullptr; i++)
1052 {
1053 strm.Printf ("%s\"%s\"",
1054 i > 0 ? ", " : "",
1055 enum_values[i].string_value);
1056 }
1057 error.SetErrorString(strm.GetData());
1058 }
1059 else
1060 {
1061 error.SetErrorString ("invalid enumeration argument");
1062 }
1063 return fail_value;
1064}
1065
1066ScriptLanguage
1067Args::StringToScriptLanguage (const char *s, ScriptLanguage fail_value, bool *success_ptr)
1068{
1069 if (s && s[0])
1070 {
1071 if ((::strcasecmp (s, "python") == 0) ||
1072 (::strcasecmp (s, "default") == 0 && eScriptLanguagePython == eScriptLanguageDefault))
1073 {
1074 if (success_ptr) *success_ptr = true;
1075 return eScriptLanguagePython;
1076 }
1077 if (::strcasecmp (s, "none"))
1078 {
1079 if (success_ptr) *success_ptr = true;
1080 return eScriptLanguageNone;
1081 }
1082 }
1083 if (success_ptr) *success_ptr = false;
1084 return fail_value;
1085}
1086
1087Error
1088Args::StringToFormat
1089(
1090 const char *s,
1091 lldb::Format &format,
1092 size_t *byte_size_ptr
1093)
1094{
1095 format = eFormatInvalid;
1096 Error error;
1097
1098 if (s && s[0])
1099 {
1100 if (byte_size_ptr)
1101 {
1102 if (isdigit (s[0]))
1103 {
1104 char *format_char = nullptr;
1105 unsigned long byte_size = ::strtoul (s, &format_char, 0);
1106 if (byte_size != ULONG_MAX(9223372036854775807L *2UL+1UL))
1107 *byte_size_ptr = byte_size;
1108 s = format_char;
1109 }
1110 else
1111 *byte_size_ptr = 0;
1112 }
1113
1114 const bool partial_match_ok = true;
1115 if (!FormatManager::GetFormatFromCString (s, partial_match_ok, format))
1116 {
1117 StreamString error_strm;
1118 error_strm.Printf ("Invalid format character or name '%s'. Valid values are:\n", s);
1119 for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1))
1120 {
1121 char format_char = FormatManager::GetFormatAsFormatChar(f);
1122 if (format_char)
1123 error_strm.Printf ("'%c' or ", format_char);
1124
1125 error_strm.Printf ("\"%s\"", FormatManager::GetFormatAsCString(f));
1126 error_strm.EOL();
1127 }
1128
1129 if (byte_size_ptr)
1130 error_strm.PutCString ("An optional byte size can precede the format character.\n");
1131 error.SetErrorString(error_strm.GetString().c_str());
1132 }
1133
1134 if (error.Fail())
1135 return error;
1136 }
1137 else
1138 {
1139 error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid");
1140 }
1141 return error;
1142}
1143
1144lldb::Encoding
1145Args::StringToEncoding (const char *s, lldb::Encoding fail_value)
1146{
1147 if (s && s[0])
1148 {
1149 if (strcmp(s, "uint") == 0)
1150 return eEncodingUint;
1151 else if (strcmp(s, "sint") == 0)
1152 return eEncodingSint;
1153 else if (strcmp(s, "ieee754") == 0)
1154 return eEncodingIEEE754;
1155 else if (strcmp(s, "vector") == 0)
1156 return eEncodingVector;
1157 }
1158 return fail_value;
1159}
1160
1161uint32_t
1162Args::StringToGenericRegister (const char *s)
1163{
1164 if (s && s[0])
1165 {
1166 if (strcmp(s, "pc") == 0)
1167 return LLDB_REGNUM_GENERIC_PC0;
1168 else if (strcmp(s, "sp") == 0)
1169 return LLDB_REGNUM_GENERIC_SP1;
1170 else if (strcmp(s, "fp") == 0)
1171 return LLDB_REGNUM_GENERIC_FP2;
1172 else if (strcmp(s, "ra") == 0 || strcmp(s, "lr") == 0)
1173 return LLDB_REGNUM_GENERIC_RA3;
1174 else if (strcmp(s, "flags") == 0)
1175 return LLDB_REGNUM_GENERIC_FLAGS4;
1176 else if (strncmp(s, "arg", 3) == 0)
1177 {
1178 if (s[3] && s[4] == '\0')
1179 {
1180 switch (s[3])
1181 {
1182 case '1': return LLDB_REGNUM_GENERIC_ARG15;
1183 case '2': return LLDB_REGNUM_GENERIC_ARG26;
1184 case '3': return LLDB_REGNUM_GENERIC_ARG37;
1185 case '4': return LLDB_REGNUM_GENERIC_ARG48;
1186 case '5': return LLDB_REGNUM_GENERIC_ARG59;
1187 case '6': return LLDB_REGNUM_GENERIC_ARG610;
1188 case '7': return LLDB_REGNUM_GENERIC_ARG711;
1189 case '8': return LLDB_REGNUM_GENERIC_ARG812;
1190 }
1191 }
1192 }
1193 }
1194 return LLDB_INVALID_REGNUM(4294967295U);
1195}
1196
1197
1198void
1199Args::LongestCommonPrefix (std::string &common_prefix)
1200{
1201 arg_sstr_collection::iterator pos, end = m_args.end();
1202 pos = m_args.begin();
1203 if (pos == end)
1204 common_prefix.clear();
1205 else
1206 common_prefix = (*pos);
1207
1208 for (++pos; pos != end; ++pos)
1209 {
1210 size_t new_size = (*pos).size();
1211
1212 // First trim common_prefix if it is longer than the current element:
1213 if (common_prefix.size() > new_size)
1214 common_prefix.erase (new_size);
1215
1216 // Then trim it at the first disparity:
1217
1218 for (size_t i = 0; i < common_prefix.size(); i++)
1219 {
1220 if ((*pos)[i] != common_prefix[i])
1221 {
1222 common_prefix.erase(i);
1223 break;
1224 }
1225 }
1226
1227 // If we've emptied the common prefix, we're done.
1228 if (common_prefix.empty())
1229 break;
1230 }
1231}
1232
1233size_t
1234Args::FindArgumentIndexForOption (Option *long_options, int long_options_index)
1235{
1236 char short_buffer[3];
1237 char long_buffer[255];
1238 ::snprintf (short_buffer, sizeof (short_buffer), "-%c", long_options[long_options_index].val);
1239 ::snprintf (long_buffer, sizeof (long_buffer), "--%s", long_options[long_options_index].definition->long_option);
1240 size_t end = GetArgumentCount ();
1241 size_t idx = 0;
1242 while (idx < end)
1243 {
1244 if ((::strncmp (GetArgumentAtIndex (idx), short_buffer, strlen (short_buffer)) == 0)
1245 || (::strncmp (GetArgumentAtIndex (idx), long_buffer, strlen (long_buffer)) == 0))
1246 {
1247 return idx;
1248 }
1249 ++idx;
1250 }
1251
1252 return end;
1253}
1254
1255bool
1256Args::IsPositionalArgument (const char *arg)
1257{
1258 if (arg == nullptr)
1259 return false;
1260
1261 bool is_positional = true;
1262 char *cptr = (char *) arg;
1263
1264 if (cptr[0] == '%')
1265 {
1266 ++cptr;
1267 while (isdigit (cptr[0]))
1268 ++cptr;
1269 if (cptr[0] != '\0')
1270 is_positional = false;
1271 }
1272 else
1273 is_positional = false;
1274
1275 return is_positional;
1276}
1277
1278void
1279Args::ParseAliasOptions (Options &options,
1280 CommandReturnObject &result,
1281 OptionArgVector *option_arg_vector,
1282 std::string &raw_input_string)
1283{
1284 StreamString sstr;
1285 int i;
1286 Option *long_options = options.GetLongOptions();
1287
1288 if (long_options == nullptr)
1289 {
1290 result.AppendError ("invalid long options");
1291 result.SetStatus (eReturnStatusFailed);
1292 return;
1293 }
1294
1295 for (i = 0; long_options[i].definition != nullptr; ++i)
1296 {
1297 if (long_options[i].flag == nullptr)
1298 {
1299 sstr << (char) long_options[i].val;
1300 switch (long_options[i].definition->option_has_arg)
1301 {
1302 default:
1303 case OptionParser::eNoArgument:
1304 break;
1305 case OptionParser::eRequiredArgument:
1306 sstr << ":";
1307 break;
1308 case OptionParser::eOptionalArgument:
1309 sstr << "::";
1310 break;
1311 }
1312 }
1313 }
1314
1315 OptionParser::Prepare();
1316 int val;
1317 while (1)
1318 {
1319 int long_options_index = -1;
1320 val = OptionParser::Parse (GetArgumentCount(),
1321 GetArgumentVector(),
1322 sstr.GetData(),
1323 long_options,
1324 &long_options_index);
1325
1326 if (val == -1)
1327 break;
1328
1329 if (val == '?')
1330 {
1331 result.AppendError ("unknown or ambiguous option");
1332 result.SetStatus (eReturnStatusFailed);
1333 break;
1334 }
1335
1336 if (val == 0)
1337 continue;
1338
1339 options.OptionSeen (val);
1340
1341 // Look up the long option index
1342 if (long_options_index == -1)
1343 {
1344 for (int j = 0;
1345 long_options[j].definition || long_options[j].flag || long_options[j].val;
1346 ++j)
1347 {
1348 if (long_options[j].val == val)
1349 {
1350 long_options_index = j;
1351 break;
1352 }
1353 }
1354 }
1355
1356 // See if the option takes an argument, and see if one was supplied.
1357 if (long_options_index >= 0)
1358 {
1359 StreamString option_str;
1360 option_str.Printf ("-%c", val);
1361 const OptionDefinition *def = long_options[long_options_index].definition;
1362 int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
1363
1364 switch (has_arg)
1365 {
1366 case OptionParser::eNoArgument:
1367 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
1368 OptionArgValue (OptionParser::eNoArgument, "<no-argument>")));
1369 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1370 break;
1371 case OptionParser::eRequiredArgument:
1372 if (OptionParser::GetOptionArgument() != nullptr)
1373 {
1374 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
1375 OptionArgValue (OptionParser::eRequiredArgument,
1376 std::string (OptionParser::GetOptionArgument()))));
1377 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1378 }
1379 else
1380 {
1381 result.AppendErrorWithFormat ("Option '%s' is missing argument specifier.\n",
1382 option_str.GetData());
1383 result.SetStatus (eReturnStatusFailed);
1384 }
1385 break;
1386 case OptionParser::eOptionalArgument:
1387 if (OptionParser::GetOptionArgument() != nullptr)
1388 {
1389 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
1390 OptionArgValue (OptionParser::eOptionalArgument,
1391 std::string (OptionParser::GetOptionArgument()))));
1392 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1393 }
1394 else
1395 {
1396 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
1397 OptionArgValue (OptionParser::eOptionalArgument, "<no-argument>")));
1398 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1399 }
1400 break;
1401 default:
1402 result.AppendErrorWithFormat ("error with options table; invalid value in has_arg field for option '%c'.\n", val);
1403 result.SetStatus (eReturnStatusFailed);
1404 break;
1405 }
1406 }
1407 else
1408 {
1409 result.AppendErrorWithFormat ("Invalid option with value '%c'.\n", val);
1410 result.SetStatus (eReturnStatusFailed);
1411 }
1412
1413 if (long_options_index >= 0)
1414 {
1415 // Find option in the argument list; also see if it was supposed to take an argument and if one was
1416 // supplied. Remove option (and argument, if given) from the argument list. Also remove them from
1417 // the raw_input_string, if one was passed in.
1418 size_t idx = FindArgumentIndexForOption (long_options, long_options_index);
1419 if (idx < GetArgumentCount())
1420 {
1421 if (raw_input_string.size() > 0)
1422 {
1423 const char *tmp_arg = GetArgumentAtIndex (idx);
1424 size_t pos = raw_input_string.find (tmp_arg);
1425 if (pos != std::string::npos)
1426 raw_input_string.erase (pos, strlen (tmp_arg));
1427 }
1428 ReplaceArgumentAtIndex (idx, "");
1429 if ((long_options[long_options_index].definition->option_has_arg != OptionParser::eNoArgument)
1430 && (OptionParser::GetOptionArgument() != nullptr)
1431 && (idx+1 < GetArgumentCount())
1432 && (strcmp (OptionParser::GetOptionArgument(), GetArgumentAtIndex(idx+1)) == 0))
1433 {
1434 if (raw_input_string.size() > 0)
1435 {
1436 const char *tmp_arg = GetArgumentAtIndex (idx+1);
1437 size_t pos = raw_input_string.find (tmp_arg);
1438 if (pos != std::string::npos)
1439 raw_input_string.erase (pos, strlen (tmp_arg));
1440 }
1441 ReplaceArgumentAtIndex (idx+1, "");
1442 }
1443 }
1444 }
1445
1446 if (!result.Succeeded())
1447 break;
1448 }
1449}
1450
1451void
1452Args::ParseArgsForCompletion
1453(
1454 Options &options,
1455 OptionElementVector &option_element_vector,
1456 uint32_t cursor_index
1457)
1458{
1459 StreamString sstr;
1460 Option *long_options = options.GetLongOptions();
1461 option_element_vector.clear();
1462
1463 if (long_options == nullptr)
1464 {
1465 return;
1466 }
1467
1468 // Leading : tells getopt to return a : for a missing option argument AND
1469 // to suppress error messages.
1470
1471 sstr << ":";
1472 for (int i = 0; long_options[i].definition != nullptr; ++i)
1473 {
1474 if (long_options[i].flag == nullptr)
1475 {
1476 sstr << (char) long_options[i].val;
1477 switch (long_options[i].definition->option_has_arg)
1478 {
1479 default:
1480 case OptionParser::eNoArgument:
1481 break;
1482 case OptionParser::eRequiredArgument:
1483 sstr << ":";
1484 break;
1485 case OptionParser::eOptionalArgument:
1486 sstr << "::";
1487 break;
1488 }
1489 }
1490 }
1491
1492 OptionParser::Prepare();
1493 OptionParser::EnableError(false);
1494
1495 int val;
1496 const OptionDefinition *opt_defs = options.GetDefinitions();
1497
1498 // Fooey... OptionParser::Parse permutes the GetArgumentVector to move the options to the front.
1499 // So we have to build another Arg and pass that to OptionParser::Parse 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 = OptionParser::Parse (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 OptionParser::Parse 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 (static_cast<size_t>(OptionParser::GetOptionIndex()) < dummy_vec.size() - 1
1536 && (strcmp (dummy_vec[OptionParser::GetOptionIndex()-1], "--") == 0))
1537 {
1538 dash_dash_pos = OptionParser::GetOptionIndex() - 1;
1539 if (static_cast<size_t>(OptionParser::GetOptionIndex() - 1) == cursor_index)
1540 {
1541 option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDoubleDash, OptionParser::GetOptionIndex() - 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, OptionParser::GetOptionIndex() - 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 = OptionParser::GetOptionErrorCause();
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].definition || 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 const OptionDefinition *def = long_options[long_options_index].definition;
1601 int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
1602 switch (has_arg)
1603 {
1604 case OptionParser::eNoArgument:
1605 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, 0));
1606 break;
1607 case OptionParser::eRequiredArgument:
1608 if (OptionParser::GetOptionArgument() != nullptr)
1609 {
1610 int arg_index;
1611 if (missing_argument)
1612 arg_index = -1;
1613 else
1614 arg_index = OptionParser::GetOptionIndex() - 1;
1615
1616 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, arg_index));
1617 }
1618 else
1619 {
1620 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, -1));
1621 }
1622 break;
1623 case OptionParser::eOptionalArgument:
1624 if (OptionParser::GetOptionArgument() != nullptr)
1625 {
1626 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, OptionParser::GetOptionIndex() - 1));
1627 }
1628 else
1629 {
1630 option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 2, OptionParser::GetOptionIndex() - 1));
1631 }
1632 break;
1633 default:
1634 // The options table is messed up. Here we'll just continue
1635 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1,
1636 OptionArgElement::eUnrecognizedArg));
1637 break;
1638 }
1639 }
1640 else
1641 {
1642 option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, OptionParser::GetOptionIndex() - 1,
1643 OptionArgElement::eUnrecognizedArg));
1644 }
1645 }
1646
1647 // Finally we have to handle the case where the cursor index points at a single "-". We want to mark that in
1648 // the option_element_vector, but only if it is not after the "--". But it turns out that OptionParser::Parse just ignores
1649 // an isolated "-". So we have to look it up by hand here. We only care if it is AT the cursor position.
1650 // Note, a single quoted dash is not the same as a single dash...
1651
1652 if ((static_cast<int32_t>(dash_dash_pos) == -1 || cursor_index < dash_dash_pos)
1653 && m_args_quote_char[cursor_index] == '\0'
1654 && strcmp (GetArgumentAtIndex(cursor_index), "-") == 0)
1655 {
1656 option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDash, cursor_index,
1657 OptionArgElement::eBareDash));
1658
1659 }
1660}
1661
1662void
1663Args::EncodeEscapeSequences (const char *src, std::string &dst)
1664{
1665 dst.clear();
1666 if (src)
1667 {
1668 for (const char *p = src; *p != '\0'; ++p)
1669 {
1670 size_t non_special_chars = ::strcspn (p, "\\");
1671 if (non_special_chars > 0)
1672 {
1673 dst.append(p, non_special_chars);
1674 p += non_special_chars;
1675 if (*p == '\0')
1676 break;
1677 }
1678
1679 if (*p == '\\')
1680 {
1681 ++p; // skip the slash
1682 switch (*p)
1683 {
1684 case 'a' : dst.append(1, '\a'); break;
1685 case 'b' : dst.append(1, '\b'); break;
1686 case 'f' : dst.append(1, '\f'); break;
1687 case 'n' : dst.append(1, '\n'); break;
1688 case 'r' : dst.append(1, '\r'); break;
1689 case 't' : dst.append(1, '\t'); break;
1690 case 'v' : dst.append(1, '\v'); break;
1691 case '\\': dst.append(1, '\\'); break;
1692 case '\'': dst.append(1, '\''); break;
1693 case '"' : dst.append(1, '"'); break;
1694 case '0' :
1695 // 1 to 3 octal chars
1696 {
1697 // Make a string that can hold onto the initial zero char,
1698 // up to 3 octal digits, and a terminating NULL.
1699 char oct_str[5] = { '\0', '\0', '\0', '\0', '\0' };
1700
1701 int i;
1702 for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i)
1703 oct_str[i] = p[i];
1704
1705 // We don't want to consume the last octal character since
1706 // the main for loop will do this for us, so we advance p by
1707 // one less than i (even if i is zero)
1708 p += i - 1;
1709 unsigned long octal_value = ::strtoul (oct_str, nullptr, 8);
1710 if (octal_value <= UINT8_MAX(255))
1711 {
1712 dst.append(1, (char)octal_value);
1713 }
1714 }
1715 break;
1716
1717 case 'x':
1718 // hex number in the format
1719 if (isxdigit(p[1]))
1720 {
1721 ++p; // Skip the 'x'
1722
1723 // Make a string that can hold onto two hex chars plus a
1724 // NULL terminator
1725 char hex_str[3] = { *p, '\0', '\0' };
1726 if (isxdigit(p[1]))
1727 {
1728 ++p; // Skip the first of the two hex chars
1729 hex_str[1] = *p;
1730 }
1731
1732 unsigned long hex_value = strtoul (hex_str, nullptr, 16);
1733 if (hex_value <= UINT8_MAX(255))
1734 dst.append (1, (char)hex_value);
1735 }
1736 else
1737 {
1738 dst.append(1, 'x');
1739 }
1740 break;
1741
1742 default:
1743 // Just desensitize any other character by just printing what
1744 // came after the '\'
1745 dst.append(1, *p);
1746 break;
1747
1748 }
1749 }
1750 }
1751 }
1752}
1753
1754
1755void
1756Args::ExpandEscapedCharacters (const char *src, std::string &dst)
1757{
1758 dst.clear();
1759 if (src)
1760 {
1761 for (const char *p = src; *p != '\0'; ++p)
1762 {
1763 if (isprint8(*p))
1764 dst.append(1, *p);
1765 else
1766 {
1767 switch (*p)
1768 {
1769 case '\a': dst.append("\\a"); break;
1770 case '\b': dst.append("\\b"); break;
1771 case '\f': dst.append("\\f"); break;
1772 case '\n': dst.append("\\n"); break;
1773 case '\r': dst.append("\\r"); break;
1774 case '\t': dst.append("\\t"); break;
1775 case '\v': dst.append("\\v"); break;
1776 case '\'': dst.append("\\'"); break;
1777 case '"': dst.append("\\\""); break;
1778 case '\\': dst.append("\\\\"); break;
1779 default:
1780 {
1781 // Just encode as octal
1782 dst.append("\\0");
1783 char octal_str[32];
1784 snprintf(octal_str, sizeof(octal_str), "%o", *p);
1785 dst.append(octal_str);
1786 }
1787 break;
1788 }
1789 }
1790 }
1791 }
1792}
1793