blob: 7cb137555d1bfd81bbfd36c443d6054f19280418 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- Args.cpp ------------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// C Includes
11#include <getopt.h>
12#include <histedit.h>
13
14// C++ Includes
15// Other libraries and framework includes
16// Project includes
17#include "lldb/Core/Args.h"
18#include "lldb/Core/Stream.h"
19#include "lldb/Core/StreamFile.h"
20#include "lldb/Core/StreamString.h"
21#include "lldb/Core/Options.h"
22#include "lldb/Interpreter/CommandReturnObject.h"
23
24namespace lldb_private {
25
26class Tokenizer
27{
28public:
29 Tokenizer (const char *separator_chars = NULL) :
30 m_tokenizer(NULL)
31 {
32 m_tokenizer = ::tok_init (separator_chars);
33 }
34
35 ~Tokenizer ()
36 {
37 if (m_tokenizer)
38 {
39 ::tok_end (m_tokenizer);
40 m_tokenizer = NULL;
41 }
42 }
43
44 void
45 Reset ()
46 {
47 assert (m_tokenizer);
48 ::tok_reset (m_tokenizer);
49 }
50
51 int
52 TokenizeLineInfo (const ::LineInfo *line_info)
53 {
54 assert (m_tokenizer);
55 return ::tok_line (m_tokenizer,
56 line_info,
57 &m_argc,
58 &m_argv,
59 &m_cursor_arg_index,
60 &m_cursor_arg_offset);
61 }
62
63 int
64 TokenizeCString (const char *cstr)
65 {
66 assert (m_tokenizer);
67 m_cursor_arg_index = -1;
68 m_cursor_arg_offset = -1;
69 return ::tok_str (m_tokenizer,
70 cstr,
71 &m_argc,
72 &m_argv);
73 }
74
75
76 int
77 GetArgCount () const
78 {
79 return m_argc;
80 }
81
82 const char **
83 GetArgVector () const
84 {
85 return m_argv;
86 }
87
88 int
89 GetCursoreArgIndex () const
90 {
91 return m_cursor_arg_index;
92 }
93
94 int
95 GetCursoreArgOffset () const
96 {
97 return m_cursor_arg_offset;
98 }
99
100
101protected:
102 struct tokenizer* m_tokenizer;
103 const char **m_argv;
104 int m_argc;
105 int m_cursor_arg_index;
106 int m_cursor_arg_offset;
107};
108
109} // namespace lldb_private
110
111using namespace lldb;
112using namespace lldb_private;
113
114static const char *k_space_characters = "\t\n\v\f\r ";
115static const char *k_space_characters_with_slash = "\t\n\v\f\r \\";
116
117
118//----------------------------------------------------------------------
119// Args constructor
120//----------------------------------------------------------------------
121Args::Args (const char *command) :
122 m_args(),
123 m_argv()
124{
125 SetCommandString (command);
126}
127
128
129Args::Args (const char *command, size_t len) :
130 m_args(),
131 m_argv()
132{
133 SetCommandString (command, len);
134}
135
136
137
138//----------------------------------------------------------------------
139// Destructor
140//----------------------------------------------------------------------
141Args::~Args ()
142{
143}
144
145void
146Args::Dump (Stream *s)
147{
148// int argc = GetArgumentCount();
149//
150// arg_sstr_collection::const_iterator pos, begin = m_args.begin(), end = m_args.end();
151// for (pos = m_args.begin(); pos != end; ++pos)
152// {
153// s->Indent();
154// s->Printf("args[%zu]=%s\n", std::distance(begin, pos), pos->c_str());
155// }
156// s->EOL();
157 const int argc = m_argv.size();
158 for (int i=0; i<argc; ++i)
159 {
160 s->Indent();
161 const char *arg_cstr = m_argv[i];
162 if (arg_cstr)
163 s->Printf("argv[%i]=\"%s\"\n", i, arg_cstr);
164 else
165 s->Printf("argv[%i]=NULL\n", i);
166 }
167 s->EOL();
168}
169
170bool
171Args::GetCommandString (std::string &command)
172{
173 command.clear();
174 int argc = GetArgumentCount();
175 for (int i=0; i<argc; ++i)
176 {
177 if (i > 0)
178 command += ' ';
179 command += m_argv[i];
180 }
181 return argc > 0;
182}
183
184void
185Args::SetCommandString (const char *command, size_t len)
186{
187 // Use std::string to make sure we get a NULL terminated string we can use
188 // as "command" could point to a string within a large string....
189 std::string null_terminated_command(command, len);
190 SetCommandString(null_terminated_command.c_str());
191}
192
193void
194Args::SetCommandString (const char *command)
195{
196 m_args.clear();
197 m_argv.clear();
198 if (command && command[0])
199 {
200 const char *arg_start;
201 const char *next_arg_start;
202 for (arg_start = command, next_arg_start = NULL;
203 arg_start && arg_start[0];
204 arg_start = next_arg_start, next_arg_start = NULL)
205 {
206 // Skip any leading space characters
207 arg_start = ::strspn (arg_start, k_space_characters) + arg_start;
208
209 // If there were only space characters to the end of the line, then
210 // we're done.
211 if (*arg_start == '\0')
212 break;
213
214 std::string arg;
215 const char *arg_end = NULL;
216
217 switch (*arg_start)
218 {
219 case '\'':
220 case '"':
221 case '`':
222 {
223 // Look for either a quote character, or the backslash
224 // character
225 const char quote_char = *arg_start;
226 char find_chars[3] = { quote_char, '\\' , '\0'};
227 bool is_backtick = (quote_char == '`');
228 if (quote_char == '"' || quote_char == '`')
229 m_args_quote_char.push_back(quote_char);
230 else
231 m_args_quote_char.push_back('\0');
232
233 while (*arg_start != '\0')
234 {
235 arg_end = ::strcspn (arg_start + 1, find_chars) + arg_start + 1;
236
237 if (*arg_end == '\0')
238 {
239 arg.append (arg_start);
240 break;
241 }
242
243 // Watch out for quote characters prefixed with '\'
244 if (*arg_end == '\\')
245 {
246 if (arg_end[1] == quote_char)
247 {
248 // The character following the '\' is our quote
249 // character so strip the backslash character
250 arg.append (arg_start, arg_end);
251 }
252 else
253 {
254 // The character following the '\' is NOT our
255 // quote character, so include the backslash
256 // and continue
257 arg.append (arg_start, arg_end + 1);
258 }
259 arg_start = arg_end + 1;
260 continue;
261 }
262 else
263 {
264 arg.append (arg_start, arg_end + 1);
265 next_arg_start = arg_end + 1;
266 break;
267 }
268 }
269
270 // Skip single and double quotes, but leave backtick quotes
271 if (!is_backtick)
272 {
273 char first_c = arg[0];
274 arg.erase(0,1);
275 // Only erase the last character if it is the same as the first.
276 // Otherwise, we're parsing an incomplete command line, and we
277 // would be stripping off the last character of that string.
278 if (arg[arg.size() - 1] == first_c)
279 arg.erase(arg.size() - 1, 1);
280 }
281 }
282 break;
283 default:
284 {
285 m_args_quote_char.push_back('\0');
286 // Look for the next non-escaped space character
287 while (*arg_start != '\0')
288 {
289 arg_end = ::strcspn (arg_start, k_space_characters_with_slash) + arg_start;
290
291 if (arg_end == NULL)
292 {
293 arg.append(arg_start);
294 break;
295 }
296
297 if (*arg_end == '\\')
298 {
299 // Append up to the '\' char
300 arg.append (arg_start, arg_end);
301
302 if (arg_end[1] == '\0')
303 break;
304
305 // Append the character following the '\' if it isn't
306 // the end of the string
307 arg.append (1, arg_end[1]);
308 arg_start = arg_end + 2;
309 continue;
310 }
311 else
312 {
313 arg.append (arg_start, arg_end);
314 next_arg_start = arg_end;
315 break;
316 }
317 }
318 }
319 break;
320 }
321
322 m_args.push_back(arg);
323 }
324 }
325 UpdateArgvFromArgs();
326}
327
328void
329Args::UpdateArgsAfterOptionParsing()
330{
331 // Now m_argv might be out of date with m_args, so we need to fix that
332 arg_cstr_collection::const_iterator argv_pos, argv_end = m_argv.end();
333 arg_sstr_collection::iterator args_pos;
334 arg_quote_char_collection::iterator quotes_pos;
335
336 for (argv_pos = m_argv.begin(), args_pos = m_args.begin(), quotes_pos = m_args_quote_char.begin();
337 argv_pos != argv_end && args_pos != m_args.end();
338 ++argv_pos)
339 {
340 const char *argv_cstr = *argv_pos;
341 if (argv_cstr == NULL)
342 break;
343
344 while (args_pos != m_args.end())
345 {
346 const char *args_cstr = args_pos->c_str();
347 if (args_cstr == argv_cstr)
348 {
349 // We found the argument that matches the C string in the
350 // vector, so we can now look for the next one
351 ++args_pos;
352 ++quotes_pos;
353 break;
354 }
355 else
356 {
357 quotes_pos = m_args_quote_char.erase (quotes_pos);
358 args_pos = m_args.erase (args_pos);
359 }
360 }
361 }
362
363 if (args_pos != m_args.end())
364 m_args.erase (args_pos, m_args.end());
365
366 if (quotes_pos != m_args_quote_char.end())
367 m_args_quote_char.erase (quotes_pos, m_args_quote_char.end());
368}
369
370void
371Args::UpdateArgvFromArgs()
372{
373 m_argv.clear();
374 arg_sstr_collection::const_iterator pos, end = m_args.end();
375 for (pos = m_args.begin(); pos != end; ++pos)
376 m_argv.push_back(pos->c_str());
377 m_argv.push_back(NULL);
378}
379
380size_t
381Args::GetArgumentCount() const
382{
383 if (m_argv.empty())
384 return 0;
385 return m_argv.size() - 1;
386}
387
388const char *
389Args::GetArgumentAtIndex (size_t idx) const
390{
391 if (idx < m_argv.size())
392 return m_argv[idx];
393 return NULL;
394}
395
396char
397Args::GetArgumentQuoteCharAtIndex (size_t idx) const
398{
399 if (idx < m_args_quote_char.size())
400 return m_args_quote_char[idx];
401 return '\0';
402}
403
404char **
405Args::GetArgumentVector()
406{
407 if (!m_argv.empty())
408 return (char **)&m_argv[0];
409 return NULL;
410}
411
412const char **
413Args::GetConstArgumentVector() const
414{
415 if (!m_argv.empty())
416 return (const char **)&m_argv[0];
417 return NULL;
418}
419
420void
421Args::Shift ()
422{
423 // Don't pop the last NULL terminator from the argv array
424 if (m_argv.size() > 1)
425 {
426 m_argv.erase(m_argv.begin());
427 m_args.pop_front();
428 m_args_quote_char.erase(m_args_quote_char.begin());
429 }
430}
431
432const char *
433Args::Unshift (const char *arg_cstr, char quote_char)
434{
435 m_args.push_front(arg_cstr);
436 m_argv.insert(m_argv.begin(), m_args.front().c_str());
437 m_args_quote_char.insert(m_args_quote_char.begin(), quote_char);
438 return GetArgumentAtIndex (0);
439}
440
441void
442Args::AppendArguments (const Args &rhs)
443{
444 const size_t rhs_argc = rhs.GetArgumentCount();
445 for (size_t i=0; i<rhs_argc; ++i)
446 AppendArgument(rhs.GetArgumentAtIndex(i));
447}
448
449const char *
450Args::AppendArgument (const char *arg_cstr, char quote_char)
451{
452 return InsertArgumentAtIndex (GetArgumentCount(), arg_cstr, quote_char);
453}
454
455const char *
456Args::InsertArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
457{
458 // Since we are using a std::list to hold onto the copied C string and
459 // we don't have direct access to the elements, we have to iterate to
460 // find the value.
461 arg_sstr_collection::iterator pos, end = m_args.end();
462 size_t i = idx;
463 for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
464 --i;
465
466 pos = m_args.insert(pos, arg_cstr);
467
468
469 m_args_quote_char.insert(m_args_quote_char.begin() + idx, quote_char);
470
471 UpdateArgvFromArgs();
472 return GetArgumentAtIndex(idx);
473}
474
475const char *
476Args::ReplaceArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
477{
478 // Since we are using a std::list to hold onto the copied C string and
479 // we don't have direct access to the elements, we have to iterate to
480 // find the value.
481 arg_sstr_collection::iterator pos, end = m_args.end();
482 size_t i = idx;
483 for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
484 --i;
485
486 if (pos != end)
487 {
488 pos->assign(arg_cstr);
489 assert(idx < m_argv.size() - 1);
490 m_argv[idx] = pos->c_str();
491 m_args_quote_char[idx] = quote_char;
492 return GetArgumentAtIndex(idx);
493 }
494 return NULL;
495}
496
497void
498Args::DeleteArgumentAtIndex (size_t idx)
499{
500 // Since we are using a std::list to hold onto the copied C string and
501 // we don't have direct access to the elements, we have to iterate to
502 // find the value.
503 arg_sstr_collection::iterator pos, end = m_args.end();
504 size_t i = idx;
505 for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
506 --i;
507
508 if (pos != end)
509 {
510 m_args.erase (pos);
511 assert(idx < m_argv.size() - 1);
512 m_argv.erase(m_argv.begin() + idx);
513 m_args_quote_char.erase(m_args_quote_char.begin() + idx);
514 }
515}
516
517void
518Args::SetArguments (int argc, const char **argv)
519{
520 // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is
521 // no need to clear it here.
522 m_args.clear();
523 m_args_quote_char.clear();
524
525 // Make a copy of the arguments in our internal buffer
526 size_t i;
527 // First copy each string
528 for (i=0; i<argc; ++i)
529 {
530 m_args.push_back (argv[i]);
531 if ((argv[i][0] == '"') || (argv[i][0] == '`'))
532 m_args_quote_char.push_back (argv[i][0]);
533 else
534 m_args_quote_char.push_back ('\0');
535 }
536
537 UpdateArgvFromArgs();
538}
539
540
541Error
542Args::ParseOptions (Options &options)
543{
544 StreamString sstr;
545 int i;
546 Error error;
547 struct option *long_options = options.GetLongOptions();
548 if (long_options == NULL)
549 {
550 error.SetErrorStringWithFormat("Invalid long options.\n");
551 return error;
552 }
553
554 for (i=0; long_options[i].name != NULL; ++i)
555 {
556 if (long_options[i].flag == NULL)
557 {
558 sstr << (char)long_options[i].val;
559 switch (long_options[i].has_arg)
560 {
561 default:
562 case no_argument: break;
563 case required_argument: sstr << ':'; break;
564 case optional_argument: sstr << "::"; break;
565 }
566 }
567 }
568 optreset = 1;
569 optind = 1;
570 int val;
571 while (1)
572 {
573 int long_options_index = -1;
574 val = ::getopt_long(GetArgumentCount(), GetArgumentVector(), sstr.GetData(), long_options,
575 &long_options_index);
576 if (val == -1)
577 break;
578
579 // Did we get an error?
580 if (val == '?')
581 {
582 error.SetErrorStringWithFormat("Unknown or ambiguous option.\n");
583 break;
584 }
585 // The option auto-set itself
586 if (val == 0)
587 continue;
588
589 ((Options *) &options)->OptionSeen (val);
590
591 // Lookup the long option index
592 if (long_options_index == -1)
593 {
594 for (int i=0;
595 long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
596 ++i)
597 {
598 if (long_options[i].val == val)
599 {
600 long_options_index = i;
601 break;
602 }
603 }
604 }
605 // Call the callback with the option
606 if (long_options_index >= 0)
607 {
608 error = options.SetOptionValue(long_options_index,
609 long_options[long_options_index].has_arg == no_argument ? NULL : optarg);
610 }
611 else
612 {
613 error.SetErrorStringWithFormat("Invalid option with value '%i'.\n", val);
614 }
615 if (error.Fail())
616 break;
617 }
618
619 // Update our ARGV now that get options has consumed all the options
620 m_argv.erase(m_argv.begin(), m_argv.begin() + optind);
621 UpdateArgsAfterOptionParsing ();
622 return error;
623}
624
625void
626Args::Clear ()
627{
628 m_args.clear ();
629 m_argv.clear ();
630 m_args_quote_char.clear();
631}
632
633int32_t
634Args::StringToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr)
635{
636 if (s && s[0])
637 {
638 char *end = NULL;
639 int32_t uval = ::strtol (s, &end, base);
640 if (*end == '\0')
641 {
642 if (success_ptr) *success_ptr = true;
643 return uval; // All characters were used, return the result
644 }
645 }
646 if (success_ptr) *success_ptr = false;
647 return fail_value;
648}
649
650uint32_t
651Args::StringToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr)
652{
653 if (s && s[0])
654 {
655 char *end = NULL;
656 uint32_t uval = ::strtoul (s, &end, base);
657 if (*end == '\0')
658 {
659 if (success_ptr) *success_ptr = true;
660 return uval; // All characters were used, return the result
661 }
662 }
663 if (success_ptr) *success_ptr = false;
664 return fail_value;
665}
666
667
668int64_t
669Args::StringToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr)
670{
671 if (s && s[0])
672 {
673 char *end = NULL;
674 int64_t uval = ::strtoll (s, &end, base);
675 if (*end == '\0')
676 {
677 if (success_ptr) *success_ptr = true;
678 return uval; // All characters were used, return the result
679 }
680 }
681 if (success_ptr) *success_ptr = false;
682 return fail_value;
683}
684
685uint64_t
686Args::StringToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr)
687{
688 if (s && s[0])
689 {
690 char *end = NULL;
691 uint64_t uval = ::strtoull (s, &end, base);
692 if (*end == '\0')
693 {
694 if (success_ptr) *success_ptr = true;
695 return uval; // All characters were used, return the result
696 }
697 }
698 if (success_ptr) *success_ptr = false;
699 return fail_value;
700}
701
702lldb::addr_t
703Args::StringToAddress (const char *s, lldb::addr_t fail_value, bool *success_ptr)
704{
705 if (s && s[0])
706 {
707 char *end = NULL;
708 lldb::addr_t addr = ::strtoull (s, &end, 0);
709 if (*end == '\0')
710 {
711 if (success_ptr) *success_ptr = true;
712 return addr; // All characters were used, return the result
713 }
714 // Try base 16 with no prefix...
715 addr = ::strtoull (s, &end, 16);
716 if (*end == '\0')
717 {
718 if (success_ptr) *success_ptr = true;
719 return addr; // All characters were used, return the result
720 }
721 }
722 if (success_ptr) *success_ptr = false;
723 return fail_value;
724}
725
726bool
727Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr)
728{
729 if (s && s[0])
730 {
731 if (::strcasecmp (s, "false") == 0 ||
732 ::strcasecmp (s, "off") == 0 ||
733 ::strcasecmp (s, "no") == 0 ||
734 ::strcmp (s, "0") == 0)
735 {
736 if (success_ptr)
737 *success_ptr = true;
738 return false;
739 }
740 else
741 if (::strcasecmp (s, "true") == 0 ||
742 ::strcasecmp (s, "on") == 0 ||
743 ::strcasecmp (s, "yes") == 0 ||
744 ::strcmp (s, "1") == 0)
745 {
746 if (success_ptr) *success_ptr = true;
747 return true;
748 }
749 }
750 if (success_ptr) *success_ptr = false;
751 return fail_value;
752}
753
754int32_t
755Args::StringToOptionEnum (const char *s, lldb::OptionEnumValueElement *enum_values, int32_t fail_value, bool *success_ptr)
756{
757 if (enum_values && s && s[0])
758 {
759 for (int i = 0; enum_values[i].string_value != NULL ; i++)
760 {
761 if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value)
762 {
763 if (success_ptr) *success_ptr = true;
764 return enum_values[i].value;
765 }
766 }
767 }
768 if (success_ptr) *success_ptr = false;
769
770 return fail_value;
771}
772
773ScriptLanguage
774Args::StringToScriptLanguage (const char *s, ScriptLanguage fail_value, bool *success_ptr)
775{
776 if (s && s[0])
777 {
778 if ((::strcasecmp (s, "python") == 0) ||
779 (::strcasecmp (s, "default") == 0 && eScriptLanguagePython == eScriptLanguageDefault))
780 {
781 if (success_ptr) *success_ptr = true;
782 return eScriptLanguagePython;
783 }
784 if (::strcasecmp (s, "none"))
785 {
786 if (success_ptr) *success_ptr = true;
787 return eScriptLanguageNone;
788 }
789 }
790 if (success_ptr) *success_ptr = false;
791 return fail_value;
792}
793
794Error
795Args::StringToFormat
796(
797 const char *s,
798 lldb::Format &format
799)
800{
801 format = eFormatInvalid;
802 Error error;
803
804 if (s && s[0])
805 {
806 switch (s[0])
807 {
808 case 'y': format = eFormatBytes; break;
809 case 'Y': format = eFormatBytesWithASCII; break;
810 case 'b': format = eFormatBinary; break;
811 case 'B': format = eFormatBoolean; break;
812 case 'c': format = eFormatChar; break;
813 case 'C': format = eFormatCharPrintable; break;
814 case 'o': format = eFormatOctal; break;
815 case 'i':
816 case 'd': format = eFormatDecimal; break;
817 case 'u': format = eFormatUnsigned; break;
818 case 'x': format = eFormatHex; break;
819 case 'f':
820 case 'e':
821 case 'g': format = eFormatFloat; break;
822 case 'p': format = eFormatPointer; break;
823 case 's': format = eFormatCString; break;
824 default:
825 error.SetErrorStringWithFormat("Invalid format character '%c'. Valid values are:\n"
826 " b - binary\n"
827 " B - boolean\n"
828 " c - char\n"
829 " C - printable char\n"
830 " d - signed decimal\n"
831 " e - float\n"
832 " f - float\n"
833 " g - float\n"
834 " i - signed decimal\n"
835 " o - octal\n"
836 " s - c-string\n"
837 " u - unsigned decimal\n"
838 " x - hex\n"
839 " y - bytes\n"
840 " Y - bytes with ASCII\n", s[0]);
841 break;
842 }
843
844 if (error.Fail())
845 return error;
846 }
847 else
848 {
849 error.SetErrorStringWithFormat("%s option string.\n", s ? "empty" : "invalid");
850 }
851 return error;
852}
853
854void
855Args::LongestCommonPrefix (std::string &common_prefix)
856{
857 arg_sstr_collection::iterator pos, end = m_args.end();
858 pos = m_args.begin();
859 if (pos == end)
860 common_prefix.clear();
861 else
862 common_prefix = (*pos);
863
864 for (++pos; pos != end; ++pos)
865 {
866 int new_size = (*pos).size();
867
868 // First trim common_prefix if it is longer than the current element:
869 if (common_prefix.size() > new_size)
870 common_prefix.erase (new_size);
871
872 // Then trim it at the first disparity:
873
874 for (int i = 0; i < common_prefix.size(); i++)
875 {
876 if ((*pos)[i] != common_prefix[i])
877 {
878 common_prefix.erase(i);
879 break;
880 }
881 }
882
883 // If we've emptied the common prefix, we're done.
884 if (common_prefix.empty())
885 break;
886 }
887}
888
889void
890Args::ParseAliasOptions
891(
892 Options &options,
893 CommandReturnObject &result,
894 OptionArgVector *option_arg_vector
895)
896{
897 StreamString sstr;
898 int i;
899 struct option *long_options = options.GetLongOptions();
900
901 if (long_options == NULL)
902 {
903 result.AppendError ("invalid long options");
904 result.SetStatus (eReturnStatusFailed);
905 return;
906 }
907
908 for (i = 0; long_options[i].name != NULL; ++i)
909 {
910 if (long_options[i].flag == NULL)
911 {
912 sstr << (char) long_options[i].val;
913 switch (long_options[i].has_arg)
914 {
915 default:
916 case no_argument:
917 break;
918 case required_argument:
919 sstr << ":";
920 break;
921 case optional_argument:
922 sstr << "::";
923 break;
924 }
925 }
926 }
927
928 optreset = 1;
929 optind = 1;
930 int val;
931 while (1)
932 {
933 int long_options_index = -1;
934 val = ::getopt_long (GetArgumentCount(), GetArgumentVector(), sstr.GetData(), long_options,
935 &long_options_index);
936
937 if (val == -1)
938 break;
939
940 if (val == '?')
941 {
942 result.AppendError ("unknown or ambiguous option");
943 result.SetStatus (eReturnStatusFailed);
944 break;
945 }
946
947 if (val == 0)
948 continue;
949
950 ((Options *) &options)->OptionSeen (val);
951
952 // Look up the long option index
953 if (long_options_index == -1)
954 {
955 for (int j = 0;
956 long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val;
957 ++j)
958 {
959 if (long_options[j].val == val)
960 {
961 long_options_index = j;
962 break;
963 }
964 }
965 }
966
967 // See if the option takes an argument, and see if one was supplied.
968 if (long_options_index >= 0)
969 {
970 StreamString option_str;
971 option_str.Printf ("-%c", (char) val);
972
973 switch (long_options[long_options_index].has_arg)
974 {
975 case no_argument:
976 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), "<no-argument>"));
977 break;
978 case required_argument:
979 if (optarg != NULL)
980 {
981 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
982 std::string (optarg)));
983 result.SetStatus (eReturnStatusSuccessFinishNoResult);
984 }
985 else
986 {
987 result.AppendErrorWithFormat ("Option '%s' is missing argument specifier.\n",
988 option_str.GetData());
989 result.SetStatus (eReturnStatusFailed);
990 }
991 break;
992 case optional_argument:
993 if (optarg != NULL)
994 {
995 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
996 std::string (optarg)));
997 result.SetStatus (eReturnStatusSuccessFinishNoResult);
998 }
999 else
1000 {
1001 option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
1002 "<no-argument>"));
1003 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1004 }
1005 break;
1006 default:
1007 result.AppendErrorWithFormat
1008 ("error with options table; invalid value in has_arg field for option '%c'.\n",
1009 (char) val);
1010 result.SetStatus (eReturnStatusFailed);
1011 break;
1012 }
1013 }
1014 else
1015 {
1016 result.AppendErrorWithFormat ("Invalid option with value '%c'.\n", (char) val);
1017 result.SetStatus (eReturnStatusFailed);
1018 }
1019 if (!result.Succeeded())
1020 break;
1021 }
1022}
1023
1024void
1025Args::ParseArgsForCompletion
1026(
1027 Options &options,
1028 OptionElementVector &option_element_vector
1029)
1030{
1031 StreamString sstr;
1032 int i;
1033 struct option *long_options = options.GetLongOptions();
1034 option_element_vector.clear();
1035
1036 if (long_options == NULL)
1037 {
1038 return;
1039 }
1040
1041 // Leading : tells getopt to return a : for a missing option argument AND
1042 // to suppress error messages.
1043
1044 sstr << ":";
1045 for (i = 0; long_options[i].name != NULL; ++i)
1046 {
1047 if (long_options[i].flag == NULL)
1048 {
1049 sstr << (char) long_options[i].val;
1050 switch (long_options[i].has_arg)
1051 {
1052 default:
1053 case no_argument:
1054 break;
1055 case required_argument:
1056 sstr << ":";
1057 break;
1058 case optional_argument:
1059 sstr << "::";
1060 break;
1061 }
1062 }
1063 }
1064
1065 optreset = 1;
1066 optind = 1;
1067 opterr = 0;
1068
1069 int val;
1070 const OptionDefinition *opt_defs = options.GetDefinitions();
1071
1072 // Fooey... getopt_long permutes the GetArgumentVector for no apparent reason.
1073 // So we have to build another Arg and pass that to getopt_long so it doesn't
1074 // screw up the one we have.
1075
1076 std::vector<const char *> dummy_vec(GetArgumentVector(), GetArgumentVector() + GetArgumentCount() + 1);
1077
1078 while (1)
1079 {
1080 bool missing_argument = false;
1081 int parse_start = optind;
1082 int long_options_index = -1;
1083 val = ::getopt_long (dummy_vec.size() - 1,(char *const *) dummy_vec.data(), sstr.GetData(), long_options,
1084 &long_options_index);
1085
1086 if (val == -1)
1087 break;
1088
1089 else if (val == '?')
1090 {
1091 option_element_vector.push_back (OptionArgElement (-1, parse_start, -1));
1092 continue;
1093 }
1094 else if (val == 0)
1095 {
1096 continue;
1097 }
1098 else if (val == ':')
1099 {
1100 // This is a missing argument.
1101 val = optopt;
1102 missing_argument = true;
1103 }
1104
1105 ((Options *) &options)->OptionSeen (val);
1106
1107 // Look up the long option index
1108 if (long_options_index == -1)
1109 {
1110 for (int j = 0;
1111 long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val;
1112 ++j)
1113 {
1114 if (long_options[j].val == val)
1115 {
1116 long_options_index = j;
1117 break;
1118 }
1119 }
1120 }
1121
1122 // See if the option takes an argument, and see if one was supplied.
1123 if (long_options_index >= 0)
1124 {
1125 int opt_defs_index = -1;
1126 for (int i = 0; ; i++)
1127 {
1128 if (opt_defs[i].short_option == 0)
1129 break;
1130 else if (opt_defs[i].short_option == val)
1131 {
1132 opt_defs_index = i;
1133 break;
1134 }
1135 }
1136
1137 switch (long_options[long_options_index].has_arg)
1138 {
1139 case no_argument:
1140 option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, 0));
1141 break;
1142 case required_argument:
1143 if (optarg != NULL)
1144 {
1145 int arg_index;
1146 if (missing_argument)
1147 arg_index = -1;
1148 else
1149 arg_index = parse_start + 1;
1150
1151 option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, arg_index));
1152 }
1153 else
1154 {
1155 option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, -1));
1156 }
1157 break;
1158 case optional_argument:
1159 if (optarg != NULL)
1160 {
1161 option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, 0));
1162 }
1163 else
1164 {
1165 option_element_vector.push_back (OptionArgElement (opt_defs_index, parse_start, parse_start + 1));
1166 }
1167 break;
1168 default:
1169 // The options table is messed up. Here we'll just continue
1170 option_element_vector.push_back (OptionArgElement (-1, parse_start, -1));
1171 break;
1172 }
1173 }
1174 else
1175 {
1176 option_element_vector.push_back (OptionArgElement (-1, parse_start, -1));
1177 }
1178 }
1179}