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