Fix bug with parsing concatenated switches in wxCmdLineParser.
[wxWidgets.git] / src / common / cmdline.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/cmdline.cpp
3 // Purpose: wxCmdLineParser implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 05.01.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/dynarray.h"
29 #include "wx/string.h"
30 #include "wx/log.h"
31 #include "wx/intl.h"
32 #include "wx/app.h"
33 #endif //WX_PRECOMP
34
35 #include "wx/cmdline.h"
36
37 #if wxUSE_CMDLINE_PARSER
38
39 #include <ctype.h>
40
41 #include "wx/datetime.h"
42 #include "wx/msgout.h"
43 #include "wx/filename.h"
44 #include "wx/apptrait.h"
45
46 // ----------------------------------------------------------------------------
47 // private functions
48 // ----------------------------------------------------------------------------
49
50 static wxString GetTypeName(wxCmdLineParamType type);
51
52 static wxString GetOptionName(wxString::const_iterator p,
53 wxString::const_iterator end,
54 const wxChar *allowedChars);
55
56 static wxString GetShortOptionName(wxString::const_iterator p,
57 wxString::const_iterator end);
58
59 static wxString GetLongOptionName(wxString::const_iterator p,
60 wxString::const_iterator end);
61
62 // ----------------------------------------------------------------------------
63 // private structs
64 // ----------------------------------------------------------------------------
65
66 // an internal representation of an option
67 struct wxCmdLineOption
68 {
69 wxCmdLineOption(wxCmdLineEntryType k,
70 const wxString& shrt,
71 const wxString& lng,
72 const wxString& desc,
73 wxCmdLineParamType typ,
74 int fl)
75 {
76 // wxCMD_LINE_USAGE_TEXT uses only description, shortName and longName is empty
77 if ( k != wxCMD_LINE_USAGE_TEXT )
78 {
79 wxASSERT_MSG
80 (
81 !shrt.empty() || !lng.empty(),
82 wxT("option should have at least one name")
83 );
84
85 wxASSERT_MSG
86 (
87 GetShortOptionName(shrt.begin(), shrt.end()).Len() == shrt.Len(),
88 wxT("Short option contains invalid characters")
89 );
90
91 wxASSERT_MSG
92 (
93 GetLongOptionName(lng.begin(), lng.end()).Len() == lng.Len(),
94 wxT("Long option contains invalid characters")
95 );
96 }
97
98 kind = k;
99
100 shortName = shrt;
101 longName = lng;
102 description = desc;
103
104 type = typ;
105 flags = fl;
106
107 m_hasVal = false;
108 }
109
110 // can't use union easily here, so just store all possible data fields, we
111 // don't waste much (might still use union later if the number of supported
112 // types increases, so always use the accessor functions and don't access
113 // the fields directly!)
114
115 void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const
116 {
117 wxASSERT_MSG( type == typ, wxT("type mismatch in wxCmdLineOption") );
118 }
119
120 double GetDoubleVal() const
121 { Check(wxCMD_LINE_VAL_DOUBLE); return m_doubleVal; }
122 long GetLongVal() const
123 { Check(wxCMD_LINE_VAL_NUMBER); return m_longVal; }
124 const wxString& GetStrVal() const
125 { Check(wxCMD_LINE_VAL_STRING); return m_strVal; }
126 #if wxUSE_DATETIME
127 const wxDateTime& GetDateVal() const
128 { Check(wxCMD_LINE_VAL_DATE); return m_dateVal; }
129 #endif // wxUSE_DATETIME
130
131 void SetDoubleVal(double val)
132 { Check(wxCMD_LINE_VAL_DOUBLE); m_doubleVal = val; m_hasVal = true; }
133 void SetLongVal(long val)
134 { Check(wxCMD_LINE_VAL_NUMBER); m_longVal = val; m_hasVal = true; }
135 void SetStrVal(const wxString& val)
136 { Check(wxCMD_LINE_VAL_STRING); m_strVal = val; m_hasVal = true; }
137 #if wxUSE_DATETIME
138 void SetDateVal(const wxDateTime& val)
139 { Check(wxCMD_LINE_VAL_DATE); m_dateVal = val; m_hasVal = true; }
140 #endif // wxUSE_DATETIME
141
142 void SetHasValue(bool hasValue = true) { m_hasVal = hasValue; }
143 bool HasValue() const { return m_hasVal; }
144
145 public:
146 wxCmdLineEntryType kind;
147 wxString shortName,
148 longName,
149 description;
150 wxCmdLineParamType type;
151 int flags;
152
153 private:
154 bool m_hasVal;
155
156 double m_doubleVal;
157 long m_longVal;
158 wxString m_strVal;
159 #if wxUSE_DATETIME
160 wxDateTime m_dateVal;
161 #endif // wxUSE_DATETIME
162 };
163
164 struct wxCmdLineParam
165 {
166 wxCmdLineParam(const wxString& desc,
167 wxCmdLineParamType typ,
168 int fl)
169 : description(desc)
170 {
171 type = typ;
172 flags = fl;
173 }
174
175 wxString description;
176 wxCmdLineParamType type;
177 int flags;
178 };
179
180 WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions);
181 WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams);
182
183 #include "wx/arrimpl.cpp"
184
185 WX_DEFINE_OBJARRAY(wxArrayOptions)
186 WX_DEFINE_OBJARRAY(wxArrayParams)
187
188 // the parser internal state
189 struct wxCmdLineParserData
190 {
191 // options
192 wxString m_switchChars; // characters which may start an option
193 bool m_enableLongOptions; // true if long options are enabled
194 wxString m_logo; // some extra text to show in Usage()
195
196 // cmd line data
197 wxArrayString m_arguments; // == argv, argc == m_arguments.GetCount()
198 wxArrayOptions m_options; // all possible options and switches
199 wxArrayParams m_paramDesc; // description of all possible params
200 wxArrayString m_parameters; // all params found
201
202 // methods
203 wxCmdLineParserData();
204 void SetArguments(int argc, char **argv);
205 #if wxUSE_UNICODE
206 void SetArguments(int argc, wxChar **argv);
207 void SetArguments(int argc, const wxCmdLineArgsArray& argv);
208 #endif // wxUSE_UNICODE
209 void SetArguments(const wxString& cmdline);
210
211 int FindOption(const wxString& name);
212 int FindOptionByLongName(const wxString& name);
213 };
214
215 // ============================================================================
216 // implementation
217 // ============================================================================
218
219 // ----------------------------------------------------------------------------
220 // wxCmdLineParserData
221 // ----------------------------------------------------------------------------
222
223 wxCmdLineParserData::wxCmdLineParserData()
224 {
225 m_enableLongOptions = true;
226 #ifdef __UNIX_LIKE__
227 m_switchChars = wxT("-");
228 #else // !Unix
229 m_switchChars = wxT("/-");
230 #endif
231 }
232
233 void wxCmdLineParserData::SetArguments(int argc, char **argv)
234 {
235 m_arguments.clear();
236
237 for ( int n = 0; n < argc; n++ )
238 {
239 m_arguments.push_back(wxString::FromAscii(argv[n]));
240 }
241 }
242
243 #if wxUSE_UNICODE
244
245 void wxCmdLineParserData::SetArguments(int argc, wxChar **argv)
246 {
247 m_arguments.clear();
248
249 for ( int n = 0; n < argc; n++ )
250 {
251 m_arguments.push_back(argv[n]);
252 }
253 }
254
255 void wxCmdLineParserData::SetArguments(int WXUNUSED(argc),
256 const wxCmdLineArgsArray& argv)
257 {
258 m_arguments = argv.GetArguments();
259 }
260
261 #endif // wxUSE_UNICODE
262
263 void wxCmdLineParserData::SetArguments(const wxString& cmdLine)
264 {
265 m_arguments.clear();
266
267 if(wxTheApp && wxTheApp->argc > 0)
268 m_arguments.push_back(wxTheApp->argv[0]);
269 else
270 m_arguments.push_back(wxEmptyString);
271
272 wxArrayString args = wxCmdLineParser::ConvertStringToArgs(cmdLine);
273
274 WX_APPEND_ARRAY(m_arguments, args);
275 }
276
277 int wxCmdLineParserData::FindOption(const wxString& name)
278 {
279 if ( !name.empty() )
280 {
281 size_t count = m_options.GetCount();
282 for ( size_t n = 0; n < count; n++ )
283 {
284 if ( m_options[n].shortName == name )
285 {
286 // found
287 return n;
288 }
289 }
290 }
291
292 return wxNOT_FOUND;
293 }
294
295 int wxCmdLineParserData::FindOptionByLongName(const wxString& name)
296 {
297 size_t count = m_options.GetCount();
298 for ( size_t n = 0; n < count; n++ )
299 {
300 if ( m_options[n].longName == name )
301 {
302 // found
303 return n;
304 }
305 }
306
307 return wxNOT_FOUND;
308 }
309
310 // ----------------------------------------------------------------------------
311 // construction and destruction
312 // ----------------------------------------------------------------------------
313
314 void wxCmdLineParser::Init()
315 {
316 m_data = new wxCmdLineParserData;
317 }
318
319 void wxCmdLineParser::SetCmdLine(int argc, char **argv)
320 {
321 m_data->SetArguments(argc, argv);
322 }
323
324 #if wxUSE_UNICODE
325
326 void wxCmdLineParser::SetCmdLine(int argc, wxChar **argv)
327 {
328 m_data->SetArguments(argc, argv);
329 }
330
331 void wxCmdLineParser::SetCmdLine(int argc, const wxCmdLineArgsArray& argv)
332 {
333 m_data->SetArguments(argc, argv);
334 }
335
336 #endif // wxUSE_UNICODE
337
338 void wxCmdLineParser::SetCmdLine(const wxString& cmdline)
339 {
340 m_data->SetArguments(cmdline);
341 }
342
343 wxCmdLineParser::~wxCmdLineParser()
344 {
345 delete m_data;
346 }
347
348 // ----------------------------------------------------------------------------
349 // options
350 // ----------------------------------------------------------------------------
351
352 void wxCmdLineParser::SetSwitchChars(const wxString& switchChars)
353 {
354 m_data->m_switchChars = switchChars;
355 }
356
357 void wxCmdLineParser::EnableLongOptions(bool enable)
358 {
359 m_data->m_enableLongOptions = enable;
360 }
361
362 bool wxCmdLineParser::AreLongOptionsEnabled() const
363 {
364 return m_data->m_enableLongOptions;
365 }
366
367 void wxCmdLineParser::SetLogo(const wxString& logo)
368 {
369 m_data->m_logo = logo;
370 }
371
372 // ----------------------------------------------------------------------------
373 // command line construction
374 // ----------------------------------------------------------------------------
375
376 void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc *desc)
377 {
378 for ( ;; desc++ )
379 {
380 switch ( desc->kind )
381 {
382 case wxCMD_LINE_SWITCH:
383 AddSwitch(desc->shortName, desc->longName,
384 wxGetTranslation(desc->description),
385 desc->flags);
386 break;
387
388 case wxCMD_LINE_OPTION:
389 AddOption(desc->shortName, desc->longName,
390 wxGetTranslation(desc->description),
391 desc->type, desc->flags);
392 break;
393
394 case wxCMD_LINE_PARAM:
395 AddParam(wxGetTranslation(desc->description),
396 desc->type, desc->flags);
397 break;
398
399 case wxCMD_LINE_USAGE_TEXT:
400 AddUsageText(wxGetTranslation(desc->description));
401 break;
402
403 default:
404 wxFAIL_MSG( wxT("unknown command line entry type") );
405 // still fall through
406
407 case wxCMD_LINE_NONE:
408 return;
409 }
410 }
411 }
412
413 void wxCmdLineParser::AddSwitch(const wxString& shortName,
414 const wxString& longName,
415 const wxString& desc,
416 int flags)
417 {
418 wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND,
419 wxT("duplicate switch") );
420
421 wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_SWITCH,
422 shortName, longName, desc,
423 wxCMD_LINE_VAL_NONE, flags);
424
425 m_data->m_options.Add(option);
426 }
427
428 void wxCmdLineParser::AddOption(const wxString& shortName,
429 const wxString& longName,
430 const wxString& desc,
431 wxCmdLineParamType type,
432 int flags)
433 {
434 wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND,
435 wxT("duplicate option") );
436
437 wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_OPTION,
438 shortName, longName, desc,
439 type, flags);
440
441 m_data->m_options.Add(option);
442 }
443
444 void wxCmdLineParser::AddParam(const wxString& desc,
445 wxCmdLineParamType type,
446 int flags)
447 {
448 // do some consistency checks: a required parameter can't follow an
449 // optional one and nothing should follow a parameter with MULTIPLE flag
450 #if wxDEBUG_LEVEL
451 if ( !m_data->m_paramDesc.IsEmpty() )
452 {
453 wxCmdLineParam& param = m_data->m_paramDesc.Last();
454
455 wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE),
456 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
457
458 if ( !(flags & wxCMD_LINE_PARAM_OPTIONAL) )
459 {
460 wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL),
461 wxT("a required parameter can't follow an optional one") );
462 }
463 }
464 #endif // wxDEBUG_LEVEL
465
466 wxCmdLineParam *param = new wxCmdLineParam(desc, type, flags);
467
468 m_data->m_paramDesc.Add(param);
469 }
470
471 void wxCmdLineParser::AddUsageText(const wxString& text)
472 {
473 wxASSERT_MSG( !text.empty(), wxT("text can't be empty") );
474
475 wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_USAGE_TEXT,
476 wxEmptyString, wxEmptyString,
477 text, wxCMD_LINE_VAL_NONE, 0);
478
479 m_data->m_options.Add(option);
480 }
481
482 // ----------------------------------------------------------------------------
483 // access to parse command line
484 // ----------------------------------------------------------------------------
485
486 bool wxCmdLineParser::Found(const wxString& name) const
487 {
488 int i = m_data->FindOption(name);
489 if ( i == wxNOT_FOUND )
490 i = m_data->FindOptionByLongName(name);
491
492 wxCHECK_MSG( i != wxNOT_FOUND, false, wxT("unknown switch") );
493
494 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
495 if ( !opt.HasValue() )
496 return false;
497
498 return true;
499 }
500
501 bool wxCmdLineParser::Found(const wxString& name, wxString *value) const
502 {
503 int i = m_data->FindOption(name);
504 if ( i == wxNOT_FOUND )
505 i = m_data->FindOptionByLongName(name);
506
507 wxCHECK_MSG( i != wxNOT_FOUND, false, wxT("unknown option") );
508
509 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
510 if ( !opt.HasValue() )
511 return false;
512
513 wxCHECK_MSG( value, false, wxT("NULL pointer in wxCmdLineOption::Found") );
514
515 *value = opt.GetStrVal();
516
517 return true;
518 }
519
520 bool wxCmdLineParser::Found(const wxString& name, long *value) const
521 {
522 int i = m_data->FindOption(name);
523 if ( i == wxNOT_FOUND )
524 i = m_data->FindOptionByLongName(name);
525
526 wxCHECK_MSG( i != wxNOT_FOUND, false, wxT("unknown option") );
527
528 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
529 if ( !opt.HasValue() )
530 return false;
531
532 wxCHECK_MSG( value, false, wxT("NULL pointer in wxCmdLineOption::Found") );
533
534 *value = opt.GetLongVal();
535
536 return true;
537 }
538
539 bool wxCmdLineParser::Found(const wxString& name, double *value) const
540 {
541 int i = m_data->FindOption(name);
542 if ( i == wxNOT_FOUND )
543 i = m_data->FindOptionByLongName(name);
544
545 wxCHECK_MSG( i != wxNOT_FOUND, false, wxT("unknown option") );
546
547 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
548 if ( !opt.HasValue() )
549 return false;
550
551 wxCHECK_MSG( value, false, wxT("NULL pointer in wxCmdLineOption::Found") );
552
553 *value = opt.GetDoubleVal();
554
555 return true;
556 }
557
558 #if wxUSE_DATETIME
559 bool wxCmdLineParser::Found(const wxString& name, wxDateTime *value) const
560 {
561 int i = m_data->FindOption(name);
562 if ( i == wxNOT_FOUND )
563 i = m_data->FindOptionByLongName(name);
564
565 wxCHECK_MSG( i != wxNOT_FOUND, false, wxT("unknown option") );
566
567 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
568 if ( !opt.HasValue() )
569 return false;
570
571 wxCHECK_MSG( value, false, wxT("NULL pointer in wxCmdLineOption::Found") );
572
573 *value = opt.GetDateVal();
574
575 return true;
576 }
577 #endif // wxUSE_DATETIME
578
579 size_t wxCmdLineParser::GetParamCount() const
580 {
581 return m_data->m_parameters.size();
582 }
583
584 wxString wxCmdLineParser::GetParam(size_t n) const
585 {
586 wxCHECK_MSG( n < GetParamCount(), wxEmptyString, wxT("invalid param index") );
587
588 return m_data->m_parameters[n];
589 }
590
591 // Resets switches and options
592 void wxCmdLineParser::Reset()
593 {
594 for ( size_t i = 0; i < m_data->m_options.GetCount(); i++ )
595 {
596 wxCmdLineOption& opt = m_data->m_options[i];
597 opt.SetHasValue(false);
598 }
599 }
600
601
602 // ----------------------------------------------------------------------------
603 // the real work is done here
604 // ----------------------------------------------------------------------------
605
606 int wxCmdLineParser::Parse(bool showUsage)
607 {
608 bool maybeOption = true; // can the following arg be an option?
609 bool ok = true; // true until an error is detected
610 bool helpRequested = false; // true if "-h" was given
611 bool hadRepeatableParam = false; // true if found param with MULTIPLE flag
612
613 size_t currentParam = 0; // the index in m_paramDesc
614
615 size_t countParam = m_data->m_paramDesc.GetCount();
616 wxString errorMsg;
617
618 Reset();
619
620 // parse everything
621 wxString arg;
622 size_t count = m_data->m_arguments.size();
623 for ( size_t n = 1; ok && (n < count); n++ ) // 0 is program name
624 {
625 arg = m_data->m_arguments[n];
626
627 // special case: "--" should be discarded and all following arguments
628 // should be considered as parameters, even if they start with '-' and
629 // not like options (this is POSIX-like)
630 if ( arg == wxT("--") )
631 {
632 maybeOption = false;
633
634 continue;
635 }
636
637 // empty argument or just '-' is not an option but a parameter
638 if ( maybeOption && arg.length() > 1 &&
639 // FIXME-UTF8: use wc_str() after removing ANSI build
640 wxStrchr(m_data->m_switchChars.c_str(), arg[0u]) )
641 {
642 bool isLong;
643 wxString name;
644 int optInd = wxNOT_FOUND; // init to suppress warnings
645
646 // an option or a switch: find whether it's a long or a short one
647 if ( arg.length() >= 3 && arg[0u] == wxT('-') && arg[1u] == wxT('-') )
648 {
649 // a long one
650 isLong = true;
651
652 // Skip leading "--"
653 wxString::const_iterator p = arg.begin() + 2;
654
655 bool longOptionsEnabled = AreLongOptionsEnabled();
656
657 name = GetLongOptionName(p, arg.end());
658
659 if (longOptionsEnabled)
660 {
661 optInd = m_data->FindOptionByLongName(name);
662 if ( optInd == wxNOT_FOUND )
663 {
664 errorMsg << wxString::Format(_("Unknown long option '%s'"), name.c_str())
665 << wxT('\n');
666 }
667 }
668 else
669 {
670 optInd = wxNOT_FOUND; // Sanity check
671
672 // Print the argument including leading "--"
673 name.Prepend( wxT("--") );
674 errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str())
675 << wxT('\n');
676 }
677
678 }
679 else // not a long option
680 {
681 isLong = false;
682
683 // a short one: as they can be cumulated, we try to find the
684 // longest substring which is a valid option
685 wxString::const_iterator p = arg.begin() + 1;
686
687 name = GetShortOptionName(p, arg.end());
688
689 size_t len = name.length();
690 do
691 {
692 if ( len == 0 )
693 {
694 // we couldn't find a valid option name in the
695 // beginning of this string
696 errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str())
697 << wxT('\n');
698
699 break;
700 }
701 else
702 {
703 optInd = m_data->FindOption(name.Left(len));
704
705 // will try with one character less the next time
706 len--;
707 }
708 }
709 while ( optInd == wxNOT_FOUND );
710
711 len++; // compensates extra len-- above
712 if ( (optInd != wxNOT_FOUND) && (len != name.length()) )
713 {
714 // first of all, the option name is only part of this
715 // string
716 name = name.Left(len);
717
718 // our option is only part of this argument, there is
719 // something else in it - it is either the value of this
720 // option or other switches if it is a switch
721 if ( m_data->m_options[(size_t)optInd].kind
722 == wxCMD_LINE_SWITCH )
723 {
724 // pretend that all the rest of the argument is the
725 // next argument, in fact
726 wxString arg2 = arg[0u];
727 arg2 += arg.Mid(len + 1); // +1 for leading '-'
728
729 m_data->m_arguments.insert
730 (m_data->m_arguments.begin() + n + 1, arg2);
731 count++;
732
733 // only leave the part which wasn't extracted into the
734 // next argument in this one
735 arg = arg.Left(len + 1);
736 }
737 //else: it's our value, we'll deal with it below
738 }
739 }
740
741 if ( optInd == wxNOT_FOUND )
742 {
743 ok = false;
744
745 continue; // will break, in fact
746 }
747
748 // look at what follows:
749
750 // +1 for leading '-'
751 wxString::const_iterator p = arg.begin() + 1 + name.length();
752 wxString::const_iterator end = arg.end();
753
754 if ( isLong )
755 ++p; // for another leading '-'
756
757 wxCmdLineOption& opt = m_data->m_options[(size_t)optInd];
758 if ( opt.kind == wxCMD_LINE_SWITCH )
759 {
760 // we must check that there is no value following the switch
761 if ( p != arg.end() )
762 {
763 errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str())
764 << wxT('\n');
765 ok = false;
766 }
767 else // no value, as expected
768 {
769 // nothing more to do
770 opt.SetHasValue();
771
772 if ( opt.flags & wxCMD_LINE_OPTION_HELP )
773 {
774 helpRequested = true;
775
776 // it's not an error, but we still stop here
777 ok = false;
778 }
779 }
780 }
781 else // it's an option. not a switch
782 {
783 switch ( p == end ? '\0' : (*p).GetValue() )
784 {
785 case '=':
786 case ':':
787 // the value follows
788 ++p;
789 break;
790
791 case '\0':
792 // the value is in the next argument
793 if ( ++n == count )
794 {
795 // ... but there is none
796 errorMsg << wxString::Format(_("Option '%s' requires a value."),
797 name.c_str())
798 << wxT('\n');
799
800 ok = false;
801 }
802 else
803 {
804 // ... take it from there
805 p = m_data->m_arguments[n].begin();
806 end = m_data->m_arguments[n].end();
807 }
808 break;
809
810 default:
811 // the value is right here: this may be legal or
812 // not depending on the option style
813 if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR )
814 {
815 errorMsg << wxString::Format(_("Separator expected after the option '%s'."),
816 name.c_str())
817 << wxT('\n');
818
819 ok = false;
820 }
821 }
822
823 if ( ok )
824 {
825 wxString value(p, end);
826 switch ( opt.type )
827 {
828 default:
829 wxFAIL_MSG( wxT("unknown option type") );
830 // still fall through
831
832 case wxCMD_LINE_VAL_STRING:
833 opt.SetStrVal(value);
834 break;
835
836 case wxCMD_LINE_VAL_NUMBER:
837 {
838 long val;
839 if ( value.ToLong(&val) )
840 {
841 opt.SetLongVal(val);
842 }
843 else
844 {
845 errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
846 value.c_str(), name.c_str())
847 << wxT('\n');
848
849 ok = false;
850 }
851 }
852 break;
853
854 case wxCMD_LINE_VAL_DOUBLE:
855 {
856 double val;
857 if ( value.ToDouble(&val) )
858 {
859 opt.SetDoubleVal(val);
860 }
861 else
862 {
863 errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
864 value.c_str(), name.c_str())
865 << wxT('\n');
866
867 ok = false;
868 }
869 }
870 break;
871
872 #if wxUSE_DATETIME
873 case wxCMD_LINE_VAL_DATE:
874 {
875 wxDateTime dt;
876 wxString::const_iterator end;
877 if ( !dt.ParseDate(value, &end) || end != value.end() )
878 {
879 errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
880 name.c_str(), value.c_str())
881 << wxT('\n');
882
883 ok = false;
884 }
885 else
886 {
887 opt.SetDateVal(dt);
888 }
889 }
890 break;
891 #endif // wxUSE_DATETIME
892 }
893 }
894 }
895 }
896 else // not an option, must be a parameter
897 {
898 if ( currentParam < countParam )
899 {
900 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
901
902 // TODO check the param type
903
904 m_data->m_parameters.push_back(arg);
905
906 if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
907 {
908 currentParam++;
909 }
910 else
911 {
912 wxASSERT_MSG( currentParam == countParam - 1,
913 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
914
915 // remember that we did have this last repeatable parameter
916 hadRepeatableParam = true;
917 }
918 }
919 else
920 {
921 errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str())
922 << wxT('\n');
923
924 ok = false;
925 }
926 }
927 }
928
929 // verify that all mandatory options were given
930 if ( ok )
931 {
932 size_t countOpt = m_data->m_options.GetCount();
933 for ( size_t n = 0; ok && (n < countOpt); n++ )
934 {
935 wxCmdLineOption& opt = m_data->m_options[n];
936 if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
937 {
938 wxString optName;
939 if ( !opt.longName )
940 {
941 optName = opt.shortName;
942 }
943 else
944 {
945 if ( AreLongOptionsEnabled() )
946 {
947 optName.Printf( _("%s (or %s)"),
948 opt.shortName.c_str(),
949 opt.longName.c_str() );
950 }
951 else
952 {
953 optName.Printf( wxT("%s"),
954 opt.shortName.c_str() );
955 }
956 }
957
958 errorMsg << wxString::Format(_("The value for the option '%s' must be specified."),
959 optName.c_str())
960 << wxT('\n');
961
962 ok = false;
963 }
964 }
965
966 for ( ; ok && (currentParam < countParam); currentParam++ )
967 {
968 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
969 if ( (currentParam == countParam - 1) &&
970 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
971 hadRepeatableParam )
972 {
973 // special case: currentParam wasn't incremented, but we did
974 // have it, so don't give error
975 continue;
976 }
977
978 if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
979 {
980 errorMsg << wxString::Format(_("The required parameter '%s' was not specified."),
981 param.description.c_str())
982 << wxT('\n');
983
984 ok = false;
985 }
986 }
987 }
988
989 // if there was an error during parsing the command line, show this error
990 // and also the usage message if it had been requested
991 if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
992 {
993 wxMessageOutput* msgOut = wxMessageOutput::Get();
994 if ( msgOut )
995 {
996 wxString usage;
997 if ( showUsage )
998 usage = GetUsageString();
999
1000 msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() );
1001 }
1002 else
1003 {
1004 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1005 }
1006 }
1007
1008 return ok ? 0 : helpRequested ? -1 : 1;
1009 }
1010
1011 // ----------------------------------------------------------------------------
1012 // give the usage message
1013 // ----------------------------------------------------------------------------
1014
1015 void wxCmdLineParser::Usage() const
1016 {
1017 wxMessageOutput* msgOut = wxMessageOutput::Get();
1018 if ( msgOut )
1019 {
1020 msgOut->Printf( wxT("%s"), GetUsageString().c_str() );
1021 }
1022 else
1023 {
1024 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1025 }
1026 }
1027
1028 wxString wxCmdLineParser::GetUsageString() const
1029 {
1030 wxString appname;
1031 if ( m_data->m_arguments.empty() )
1032 {
1033 if ( wxTheApp )
1034 appname = wxTheApp->GetAppName();
1035 }
1036 else // use argv[0]
1037 {
1038 appname = wxFileName(m_data->m_arguments[0]).GetName();
1039 }
1040
1041 // we construct the brief cmd line desc on the fly, but not the detailed
1042 // help message below because we want to align the options descriptions
1043 // and for this we must first know the longest one of them
1044 wxString usage;
1045 wxArrayString namesOptions, descOptions;
1046
1047 if ( !m_data->m_logo.empty() )
1048 {
1049 usage << m_data->m_logo << wxT('\n');
1050 }
1051
1052 usage << wxString::Format(_("Usage: %s"), appname.c_str());
1053
1054 // the switch char is usually '-' but this can be changed with
1055 // SetSwitchChars() and then the first one of possible chars is used
1056 wxChar chSwitch = !m_data->m_switchChars ? wxT('-')
1057 : m_data->m_switchChars[0u];
1058
1059 bool areLongOptionsEnabled = AreLongOptionsEnabled();
1060 size_t n, count = m_data->m_options.GetCount();
1061 for ( n = 0; n < count; n++ )
1062 {
1063 wxCmdLineOption& opt = m_data->m_options[n];
1064 wxString option;
1065
1066 if ( opt.kind != wxCMD_LINE_USAGE_TEXT )
1067 {
1068 usage << wxT(' ');
1069 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1070 {
1071 usage << wxT('[');
1072 }
1073
1074 if ( !opt.shortName.empty() )
1075 {
1076 usage << chSwitch << opt.shortName;
1077 }
1078 else if ( areLongOptionsEnabled && !opt.longName.empty() )
1079 {
1080 usage << wxT("--") << opt.longName;
1081 }
1082 else
1083 {
1084 if (!opt.longName.empty())
1085 {
1086 wxFAIL_MSG( wxT("option with only a long name while long ")
1087 wxT("options are disabled") );
1088 }
1089 else
1090 {
1091 wxFAIL_MSG( wxT("option without neither short nor long name") );
1092 }
1093 }
1094
1095 if ( !opt.shortName.empty() )
1096 {
1097 option << wxT(" ") << chSwitch << opt.shortName;
1098 }
1099
1100 if ( areLongOptionsEnabled && !opt.longName.empty() )
1101 {
1102 option << (option.empty() ? wxT(" ") : wxT(", "))
1103 << wxT("--") << opt.longName;
1104 }
1105
1106 if ( opt.kind != wxCMD_LINE_SWITCH )
1107 {
1108 wxString val;
1109 val << wxT('<') << GetTypeName(opt.type) << wxT('>');
1110 usage << wxT(' ') << val;
1111 option << (!opt.longName ? wxT(':') : wxT('=')) << val;
1112 }
1113
1114 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1115 {
1116 usage << wxT(']');
1117 }
1118 }
1119
1120 namesOptions.push_back(option);
1121 descOptions.push_back(opt.description);
1122 }
1123
1124 count = m_data->m_paramDesc.GetCount();
1125 for ( n = 0; n < count; n++ )
1126 {
1127 wxCmdLineParam& param = m_data->m_paramDesc[n];
1128
1129 usage << wxT(' ');
1130 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1131 {
1132 usage << wxT('[');
1133 }
1134
1135 usage << param.description;
1136
1137 if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
1138 {
1139 usage << wxT("...");
1140 }
1141
1142 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1143 {
1144 usage << wxT(']');
1145 }
1146 }
1147
1148 usage << wxT('\n');
1149
1150 // set to number of our own options, not counting the standard ones
1151 count = namesOptions.size();
1152
1153 // get option names & descriptions for standard options, if any:
1154 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
1155 wxString stdDesc;
1156 if ( traits )
1157 stdDesc = traits->GetStandardCmdLineOptions(namesOptions, descOptions);
1158
1159 // now construct the detailed help message
1160 size_t len, lenMax = 0;
1161 for ( n = 0; n < namesOptions.size(); n++ )
1162 {
1163 len = namesOptions[n].length();
1164 if ( len > lenMax )
1165 lenMax = len;
1166 }
1167
1168 for ( n = 0; n < namesOptions.size(); n++ )
1169 {
1170 if ( n == count )
1171 usage << wxT('\n') << stdDesc;
1172
1173 len = namesOptions[n].length();
1174 // desc contains text if name is empty
1175 if (len == 0)
1176 {
1177 usage << descOptions[n] << wxT('\n');
1178 }
1179 else
1180 {
1181 usage << namesOptions[n]
1182 << wxString(wxT(' '), lenMax - len) << wxT('\t')
1183 << descOptions[n]
1184 << wxT('\n');
1185 }
1186 }
1187
1188 return usage;
1189 }
1190
1191 // ----------------------------------------------------------------------------
1192 // private functions
1193 // ----------------------------------------------------------------------------
1194
1195 static wxString GetTypeName(wxCmdLineParamType type)
1196 {
1197 wxString s;
1198 switch ( type )
1199 {
1200 default:
1201 wxFAIL_MSG( wxT("unknown option type") );
1202 // still fall through
1203
1204 case wxCMD_LINE_VAL_STRING:
1205 s = _("str");
1206 break;
1207
1208 case wxCMD_LINE_VAL_NUMBER:
1209 s = _("num");
1210 break;
1211
1212 case wxCMD_LINE_VAL_DOUBLE:
1213 s = _("double");
1214 break;
1215
1216 case wxCMD_LINE_VAL_DATE:
1217 s = _("date");
1218 break;
1219 }
1220
1221 return s;
1222 }
1223
1224 /*
1225 Returns a string which is equal to the string pointed to by p, but up to the
1226 point where p contains an character that's not allowed.
1227 Allowable characters are letters and numbers, and characters pointed to by
1228 the parameter allowedChars.
1229
1230 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1231 this function returns "abcde-".
1232 */
1233 static wxString GetOptionName(wxString::const_iterator p,
1234 wxString::const_iterator end,
1235 const wxChar *allowedChars)
1236 {
1237 wxString argName;
1238
1239 while ( p != end && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) )
1240 {
1241 argName += *p++;
1242 }
1243
1244 return argName;
1245 }
1246
1247 // Besides alphanumeric characters, short and long options can
1248 // have other characters.
1249
1250 // A short option additionally can have these
1251 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1252
1253 // A long option can have the same characters as a short option and a '-'.
1254 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1255 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1256
1257 static wxString GetShortOptionName(wxString::const_iterator p,
1258 wxString::const_iterator end)
1259 {
1260 return GetOptionName(p, end, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION);
1261 }
1262
1263 static wxString GetLongOptionName(wxString::const_iterator p,
1264 wxString::const_iterator end)
1265 {
1266 return GetOptionName(p, end, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION);
1267 }
1268
1269 #endif // wxUSE_CMDLINE_PARSER
1270
1271 // ----------------------------------------------------------------------------
1272 // global functions
1273 // ----------------------------------------------------------------------------
1274
1275 /*
1276 This function is mainly used under Windows (as under Unix we always get the
1277 command line arguments as argc/argv anyhow) and so it tries to follow
1278 Windows conventions for the command line handling, not Unix ones. For
1279 instance, backslash is not special except when it precedes double quote when
1280 it does quote it.
1281 */
1282
1283 /* static */
1284 wxArrayString
1285 wxCmdLineParser::ConvertStringToArgs(const wxString& cmdline,
1286 wxCmdLineSplitType type)
1287 {
1288 wxArrayString args;
1289
1290 wxString arg;
1291 arg.reserve(1024);
1292
1293 const wxString::const_iterator end = cmdline.end();
1294 wxString::const_iterator p = cmdline.begin();
1295
1296 for ( ;; )
1297 {
1298 // skip white space
1299 while ( p != end && (*p == ' ' || *p == '\t') )
1300 ++p;
1301
1302 // anything left?
1303 if ( p == end )
1304 break;
1305
1306 // parse this parameter
1307 bool lastBS = false,
1308 isInsideQuotes = false;
1309 wxChar chDelim = '\0';
1310 for ( arg.clear(); p != end; ++p )
1311 {
1312 const wxChar ch = *p;
1313
1314 if ( type == wxCMD_LINE_SPLIT_DOS )
1315 {
1316 if ( ch == '"' )
1317 {
1318 if ( !lastBS )
1319 {
1320 isInsideQuotes = !isInsideQuotes;
1321
1322 // don't put quote in arg
1323 continue;
1324 }
1325 //else: quote has no special meaning but the backslash
1326 // still remains -- makes no sense but this is what
1327 // Windows does
1328 }
1329 // note that backslash does *not* quote the space, only quotes do
1330 else if ( !isInsideQuotes && (ch == ' ' || ch == '\t') )
1331 {
1332 ++p; // skip this space anyhow
1333 break;
1334 }
1335
1336 lastBS = !lastBS && ch == '\\';
1337 }
1338 else // type == wxCMD_LINE_SPLIT_UNIX
1339 {
1340 if ( !lastBS )
1341 {
1342 if ( isInsideQuotes )
1343 {
1344 if ( ch == chDelim )
1345 {
1346 isInsideQuotes = false;
1347
1348 continue; // don't use the quote itself
1349 }
1350 }
1351 else // not in quotes and not escaped
1352 {
1353 if ( ch == '\'' || ch == '"' )
1354 {
1355 isInsideQuotes = true;
1356 chDelim = ch;
1357
1358 continue; // don't use the quote itself
1359 }
1360
1361 if ( ch == ' ' || ch == '\t' )
1362 {
1363 ++p; // skip this space anyhow
1364 break;
1365 }
1366 }
1367
1368 lastBS = ch == '\\';
1369 if ( lastBS )
1370 continue;
1371 }
1372 else // escaped by backslash, just use as is
1373 {
1374 lastBS = false;
1375 }
1376 }
1377
1378 arg += ch;
1379 }
1380
1381 args.push_back(arg);
1382 }
1383
1384 return args;
1385 }