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