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