]> git.saurik.com Git - wxWidgets.git/blob - src/common/cmdline.cpp
Ensure that component levels map is initialized before it's used (closes #10990).
[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, _T("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 = _T("-");
228 #else // !Unix
229 m_switchChars = _T("/-");
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( _T("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 _T("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 _T("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 _T("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 _T("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, _T("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, _T("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, _T("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, _T("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, _T("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, _T("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, _T("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, _T("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, _T("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, _T("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 == _T("--") )
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] == _T('-') && arg[1u] == _T('-') )
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 << _T('\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 << _T('\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 << _T('\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 //else: it's our value, we'll deal with it below
734 }
735 }
736
737 if ( optInd == wxNOT_FOUND )
738 {
739 ok = false;
740
741 continue; // will break, in fact
742 }
743
744 // look at what follows:
745
746 // +1 for leading '-'
747 wxString::const_iterator p = arg.begin() + 1 + name.length();
748 wxString::const_iterator end = arg.end();
749
750 if ( isLong )
751 ++p; // for another leading '-'
752
753 wxCmdLineOption& opt = m_data->m_options[(size_t)optInd];
754 if ( opt.kind == wxCMD_LINE_SWITCH )
755 {
756 // we must check that there is no value following the switch
757 if ( p != arg.end() )
758 {
759 errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str())
760 << _T('\n');
761 ok = false;
762 }
763 else // no value, as expected
764 {
765 // nothing more to do
766 opt.SetHasValue();
767
768 if ( opt.flags & wxCMD_LINE_OPTION_HELP )
769 {
770 helpRequested = true;
771
772 // it's not an error, but we still stop here
773 ok = false;
774 }
775 }
776 }
777 else // it's an option. not a switch
778 {
779 switch ( p == end ? '\0' : (*p).GetValue() )
780 {
781 case '=':
782 case ':':
783 // the value follows
784 ++p;
785 break;
786
787 case '\0':
788 // the value is in the next argument
789 if ( ++n == count )
790 {
791 // ... but there is none
792 errorMsg << wxString::Format(_("Option '%s' requires a value."),
793 name.c_str())
794 << _T('\n');
795
796 ok = false;
797 }
798 else
799 {
800 // ... take it from there
801 p = m_data->m_arguments[n].begin();
802 end = m_data->m_arguments[n].end();
803 }
804 break;
805
806 default:
807 // the value is right here: this may be legal or
808 // not depending on the option style
809 if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR )
810 {
811 errorMsg << wxString::Format(_("Separator expected after the option '%s'."),
812 name.c_str())
813 << _T('\n');
814
815 ok = false;
816 }
817 }
818
819 if ( ok )
820 {
821 wxString value(p, end);
822 switch ( opt.type )
823 {
824 default:
825 wxFAIL_MSG( _T("unknown option type") );
826 // still fall through
827
828 case wxCMD_LINE_VAL_STRING:
829 opt.SetStrVal(value);
830 break;
831
832 case wxCMD_LINE_VAL_NUMBER:
833 {
834 long val;
835 if ( value.ToLong(&val) )
836 {
837 opt.SetLongVal(val);
838 }
839 else
840 {
841 errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
842 value.c_str(), name.c_str())
843 << _T('\n');
844
845 ok = false;
846 }
847 }
848 break;
849
850 case wxCMD_LINE_VAL_DOUBLE:
851 {
852 double val;
853 if ( value.ToDouble(&val) )
854 {
855 opt.SetDoubleVal(val);
856 }
857 else
858 {
859 errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
860 value.c_str(), name.c_str())
861 << _T('\n');
862
863 ok = false;
864 }
865 }
866 break;
867
868 #if wxUSE_DATETIME
869 case wxCMD_LINE_VAL_DATE:
870 {
871 wxDateTime dt;
872 wxString::const_iterator end;
873 if ( !dt.ParseDate(value, &end) || end != value.end() )
874 {
875 errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
876 name.c_str(), value.c_str())
877 << _T('\n');
878
879 ok = false;
880 }
881 else
882 {
883 opt.SetDateVal(dt);
884 }
885 }
886 break;
887 #endif // wxUSE_DATETIME
888 }
889 }
890 }
891 }
892 else // not an option, must be a parameter
893 {
894 if ( currentParam < countParam )
895 {
896 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
897
898 // TODO check the param type
899
900 m_data->m_parameters.push_back(arg);
901
902 if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
903 {
904 currentParam++;
905 }
906 else
907 {
908 wxASSERT_MSG( currentParam == countParam - 1,
909 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
910
911 // remember that we did have this last repeatable parameter
912 hadRepeatableParam = true;
913 }
914 }
915 else
916 {
917 errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str())
918 << _T('\n');
919
920 ok = false;
921 }
922 }
923 }
924
925 // verify that all mandatory options were given
926 if ( ok )
927 {
928 size_t countOpt = m_data->m_options.GetCount();
929 for ( size_t n = 0; ok && (n < countOpt); n++ )
930 {
931 wxCmdLineOption& opt = m_data->m_options[n];
932 if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
933 {
934 wxString optName;
935 if ( !opt.longName )
936 {
937 optName = opt.shortName;
938 }
939 else
940 {
941 if ( AreLongOptionsEnabled() )
942 {
943 optName.Printf( _("%s (or %s)"),
944 opt.shortName.c_str(),
945 opt.longName.c_str() );
946 }
947 else
948 {
949 optName.Printf( wxT("%s"),
950 opt.shortName.c_str() );
951 }
952 }
953
954 errorMsg << wxString::Format(_("The value for the option '%s' must be specified."),
955 optName.c_str())
956 << _T('\n');
957
958 ok = false;
959 }
960 }
961
962 for ( ; ok && (currentParam < countParam); currentParam++ )
963 {
964 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
965 if ( (currentParam == countParam - 1) &&
966 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
967 hadRepeatableParam )
968 {
969 // special case: currentParam wasn't incremented, but we did
970 // have it, so don't give error
971 continue;
972 }
973
974 if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
975 {
976 errorMsg << wxString::Format(_("The required parameter '%s' was not specified."),
977 param.description.c_str())
978 << _T('\n');
979
980 ok = false;
981 }
982 }
983 }
984
985 // if there was an error during parsing the command line, show this error
986 // and also the usage message if it had been requested
987 if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
988 {
989 wxMessageOutput* msgOut = wxMessageOutput::Get();
990 if ( msgOut )
991 {
992 wxString usage;
993 if ( showUsage )
994 usage = GetUsageString();
995
996 msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() );
997 }
998 else
999 {
1000 wxFAIL_MSG( _T("no wxMessageOutput object?") );
1001 }
1002 }
1003
1004 return ok ? 0 : helpRequested ? -1 : 1;
1005 }
1006
1007 // ----------------------------------------------------------------------------
1008 // give the usage message
1009 // ----------------------------------------------------------------------------
1010
1011 void wxCmdLineParser::Usage() const
1012 {
1013 wxMessageOutput* msgOut = wxMessageOutput::Get();
1014 if ( msgOut )
1015 {
1016 msgOut->Printf( wxT("%s"), GetUsageString().c_str() );
1017 }
1018 else
1019 {
1020 wxFAIL_MSG( _T("no wxMessageOutput object?") );
1021 }
1022 }
1023
1024 wxString wxCmdLineParser::GetUsageString() const
1025 {
1026 wxString appname;
1027 if ( m_data->m_arguments.empty() )
1028 {
1029 if ( wxTheApp )
1030 appname = wxTheApp->GetAppName();
1031 }
1032 else // use argv[0]
1033 {
1034 appname = wxFileName(m_data->m_arguments[0]).GetName();
1035 }
1036
1037 // we construct the brief cmd line desc on the fly, but not the detailed
1038 // help message below because we want to align the options descriptions
1039 // and for this we must first know the longest one of them
1040 wxString usage;
1041 wxArrayString namesOptions, descOptions;
1042
1043 if ( !m_data->m_logo.empty() )
1044 {
1045 usage << m_data->m_logo << _T('\n');
1046 }
1047
1048 usage << wxString::Format(_("Usage: %s"), appname.c_str());
1049
1050 // the switch char is usually '-' but this can be changed with
1051 // SetSwitchChars() and then the first one of possible chars is used
1052 wxChar chSwitch = !m_data->m_switchChars ? _T('-')
1053 : m_data->m_switchChars[0u];
1054
1055 bool areLongOptionsEnabled = AreLongOptionsEnabled();
1056 size_t n, count = m_data->m_options.GetCount();
1057 for ( n = 0; n < count; n++ )
1058 {
1059 wxCmdLineOption& opt = m_data->m_options[n];
1060 wxString option;
1061
1062 if ( opt.kind != wxCMD_LINE_USAGE_TEXT )
1063 {
1064 usage << _T(' ');
1065 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1066 {
1067 usage << _T('[');
1068 }
1069
1070 if ( !opt.shortName.empty() )
1071 {
1072 usage << chSwitch << opt.shortName;
1073 }
1074 else if ( areLongOptionsEnabled && !opt.longName.empty() )
1075 {
1076 usage << _T("--") << opt.longName;
1077 }
1078 else
1079 {
1080 if (!opt.longName.empty())
1081 {
1082 wxFAIL_MSG( wxT("option with only a long name while long ")
1083 wxT("options are disabled") );
1084 }
1085 else
1086 {
1087 wxFAIL_MSG( _T("option without neither short nor long name") );
1088 }
1089 }
1090
1091 if ( !opt.shortName.empty() )
1092 {
1093 option << _T(" ") << chSwitch << opt.shortName;
1094 }
1095
1096 if ( areLongOptionsEnabled && !opt.longName.empty() )
1097 {
1098 option << (option.empty() ? _T(" ") : _T(", "))
1099 << _T("--") << opt.longName;
1100 }
1101
1102 if ( opt.kind != wxCMD_LINE_SWITCH )
1103 {
1104 wxString val;
1105 val << _T('<') << GetTypeName(opt.type) << _T('>');
1106 usage << _T(' ') << val;
1107 option << (!opt.longName ? _T(':') : _T('=')) << val;
1108 }
1109
1110 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1111 {
1112 usage << _T(']');
1113 }
1114 }
1115
1116 namesOptions.push_back(option);
1117 descOptions.push_back(opt.description);
1118 }
1119
1120 count = m_data->m_paramDesc.GetCount();
1121 for ( n = 0; n < count; n++ )
1122 {
1123 wxCmdLineParam& param = m_data->m_paramDesc[n];
1124
1125 usage << _T(' ');
1126 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1127 {
1128 usage << _T('[');
1129 }
1130
1131 usage << param.description;
1132
1133 if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
1134 {
1135 usage << _T("...");
1136 }
1137
1138 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1139 {
1140 usage << _T(']');
1141 }
1142 }
1143
1144 usage << _T('\n');
1145
1146 // set to number of our own options, not counting the standard ones
1147 count = namesOptions.size();
1148
1149 // get option names & descriptions for standard options, if any:
1150 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
1151 wxString stdDesc;
1152 if ( traits )
1153 stdDesc = traits->GetStandardCmdLineOptions(namesOptions, descOptions);
1154
1155 // now construct the detailed help message
1156 size_t len, lenMax = 0;
1157 for ( n = 0; n < namesOptions.size(); n++ )
1158 {
1159 len = namesOptions[n].length();
1160 if ( len > lenMax )
1161 lenMax = len;
1162 }
1163
1164 for ( n = 0; n < namesOptions.size(); n++ )
1165 {
1166 if ( n == count )
1167 usage << _T('\n') << stdDesc;
1168
1169 len = namesOptions[n].length();
1170 // desc contains text if name is empty
1171 if (len == 0)
1172 {
1173 usage << descOptions[n] << _T('\n');
1174 }
1175 else
1176 {
1177 usage << namesOptions[n]
1178 << wxString(_T(' '), lenMax - len) << _T('\t')
1179 << descOptions[n]
1180 << _T('\n');
1181 }
1182 }
1183
1184 return usage;
1185 }
1186
1187 // ----------------------------------------------------------------------------
1188 // private functions
1189 // ----------------------------------------------------------------------------
1190
1191 static wxString GetTypeName(wxCmdLineParamType type)
1192 {
1193 wxString s;
1194 switch ( type )
1195 {
1196 default:
1197 wxFAIL_MSG( _T("unknown option type") );
1198 // still fall through
1199
1200 case wxCMD_LINE_VAL_STRING:
1201 s = _("str");
1202 break;
1203
1204 case wxCMD_LINE_VAL_NUMBER:
1205 s = _("num");
1206 break;
1207
1208 case wxCMD_LINE_VAL_DOUBLE:
1209 s = _("double");
1210 break;
1211
1212 case wxCMD_LINE_VAL_DATE:
1213 s = _("date");
1214 break;
1215 }
1216
1217 return s;
1218 }
1219
1220 /*
1221 Returns a string which is equal to the string pointed to by p, but up to the
1222 point where p contains an character that's not allowed.
1223 Allowable characters are letters and numbers, and characters pointed to by
1224 the parameter allowedChars.
1225
1226 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1227 this function returns "abcde-".
1228 */
1229 static wxString GetOptionName(wxString::const_iterator p,
1230 wxString::const_iterator end,
1231 const wxChar *allowedChars)
1232 {
1233 wxString argName;
1234
1235 while ( p != end && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) )
1236 {
1237 argName += *p++;
1238 }
1239
1240 return argName;
1241 }
1242
1243 // Besides alphanumeric characters, short and long options can
1244 // have other characters.
1245
1246 // A short option additionally can have these
1247 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1248
1249 // A long option can have the same characters as a short option and a '-'.
1250 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1251 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1252
1253 static wxString GetShortOptionName(wxString::const_iterator p,
1254 wxString::const_iterator end)
1255 {
1256 return GetOptionName(p, end, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION);
1257 }
1258
1259 static wxString GetLongOptionName(wxString::const_iterator p,
1260 wxString::const_iterator end)
1261 {
1262 return GetOptionName(p, end, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION);
1263 }
1264
1265 #endif // wxUSE_CMDLINE_PARSER
1266
1267 // ----------------------------------------------------------------------------
1268 // global functions
1269 // ----------------------------------------------------------------------------
1270
1271 /*
1272 This function is mainly used under Windows (as under Unix we always get the
1273 command line arguments as argc/argv anyhow) and so it tries to follow
1274 Windows conventions for the command line handling, not Unix ones. For
1275 instance, backslash is not special except when it precedes double quote when
1276 it does quote it.
1277 */
1278
1279 /* static */
1280 wxArrayString
1281 wxCmdLineParser::ConvertStringToArgs(const wxString& cmdline,
1282 wxCmdLineSplitType type)
1283 {
1284 wxArrayString args;
1285
1286 wxString arg;
1287 arg.reserve(1024);
1288
1289 const wxString::const_iterator end = cmdline.end();
1290 wxString::const_iterator p = cmdline.begin();
1291
1292 for ( ;; )
1293 {
1294 // skip white space
1295 while ( p != end && (*p == ' ' || *p == '\t') )
1296 ++p;
1297
1298 // anything left?
1299 if ( p == end )
1300 break;
1301
1302 // parse this parameter
1303 bool lastBS = false,
1304 isInsideQuotes = false;
1305 wxChar chDelim = '\0';
1306 for ( arg.clear(); p != end; ++p )
1307 {
1308 const wxChar ch = *p;
1309
1310 if ( type == wxCMD_LINE_SPLIT_DOS )
1311 {
1312 if ( ch == '"' )
1313 {
1314 if ( !lastBS )
1315 {
1316 isInsideQuotes = !isInsideQuotes;
1317
1318 // don't put quote in arg
1319 continue;
1320 }
1321 //else: quote has no special meaning but the backslash
1322 // still remains -- makes no sense but this is what
1323 // Windows does
1324 }
1325 // note that backslash does *not* quote the space, only quotes do
1326 else if ( !isInsideQuotes && (ch == ' ' || ch == '\t') )
1327 {
1328 ++p; // skip this space anyhow
1329 break;
1330 }
1331
1332 lastBS = !lastBS && ch == '\\';
1333 }
1334 else // type == wxCMD_LINE_SPLIT_UNIX
1335 {
1336 if ( !lastBS )
1337 {
1338 if ( isInsideQuotes )
1339 {
1340 if ( ch == chDelim )
1341 {
1342 isInsideQuotes = false;
1343
1344 continue; // don't use the quote itself
1345 }
1346 }
1347 else // not in quotes and not escaped
1348 {
1349 if ( ch == '\'' || ch == '"' )
1350 {
1351 isInsideQuotes = true;
1352 chDelim = ch;
1353
1354 continue; // don't use the quote itself
1355 }
1356
1357 if ( ch == ' ' || ch == '\t' )
1358 {
1359 ++p; // skip this space anyhow
1360 break;
1361 }
1362 }
1363
1364 lastBS = ch == '\\';
1365 if ( lastBS )
1366 continue;
1367 }
1368 else // escaped by backslash, just use as is
1369 {
1370 lastBS = false;
1371 }
1372 }
1373
1374 arg += ch;
1375 }
1376
1377 args.push_back(arg);
1378 }
1379
1380 return args;
1381 }