]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/cmdline.cpp
really show the window after creation (calling Show(TRUE) doesn't do it any more)
[wxWidgets.git] / src / common / cmdline.cpp
... / ...
CommitLineData
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#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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
53static wxString GetTypeName(wxCmdLineParamType type);
54
55static wxString GetOptionName(const wxChar *p, const wxChar *allowedChars);
56
57static wxString GetShortOptionName(const wxChar *p);
58
59static wxString GetLongOptionName(const wxChar *p);
60
61// ----------------------------------------------------------------------------
62// private structs
63// ----------------------------------------------------------------------------
64
65// an internal representation of an option
66struct 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
134public:
135 wxCmdLineEntryType kind;
136 wxString shortName,
137 longName,
138 description;
139 wxCmdLineParamType type;
140 int flags;
141
142private:
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
152struct 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
168WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions);
169WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams);
170
171#include "wx/arrimpl.cpp"
172
173WX_DEFINE_OBJARRAY(wxArrayOptions);
174WX_DEFINE_OBJARRAY(wxArrayParams);
175
176// the parser internal state
177struct 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
207wxCmdLineParserData::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
217void wxCmdLineParserData::SetArguments(int argc, wxChar **argv)
218{
219 m_arguments.clear();
220
221 for ( int n = 0; n < argc; n++ )
222 {
223 m_arguments.push_back(argv[n]);
224 }
225}
226
227void wxCmdLineParserData::SetArguments(const wxString& cmdLine)
228{
229 m_arguments.clear();
230
231 m_arguments.push_back(wxTheApp->GetAppName());
232
233 wxArrayString args = wxCmdLineParser::ConvertStringToArgs(cmdLine);
234
235 WX_APPEND_ARRAY(m_arguments, args);
236}
237
238int 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
256int 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
275void wxCmdLineParser::Init()
276{
277 m_data = new wxCmdLineParserData;
278}
279
280void wxCmdLineParser::SetCmdLine(int argc, wxChar **argv)
281{
282 m_data->SetArguments(argc, argv);
283}
284
285void wxCmdLineParser::SetCmdLine(const wxString& cmdline)
286{
287 m_data->SetArguments(cmdline);
288}
289
290wxCmdLineParser::~wxCmdLineParser()
291{
292 delete m_data;
293}
294
295// ----------------------------------------------------------------------------
296// options
297// ----------------------------------------------------------------------------
298
299void wxCmdLineParser::SetSwitchChars(const wxString& switchChars)
300{
301 m_data->m_switchChars = switchChars;
302}
303
304void wxCmdLineParser::EnableLongOptions(bool enable)
305{
306 m_data->m_enableLongOptions = enable;
307}
308
309bool wxCmdLineParser::AreLongOptionsEnabled()
310{
311 return m_data->m_enableLongOptions;
312}
313
314void wxCmdLineParser::SetLogo(const wxString& logo)
315{
316 m_data->m_logo = logo;
317}
318
319// ----------------------------------------------------------------------------
320// command line construction
321// ----------------------------------------------------------------------------
322
323void 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
353void 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
368void 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
384void 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
415bool 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
430bool 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
449bool 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
469bool 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
489size_t wxCmdLineParser::GetParamCount() const
490{
491 return m_data->m_parameters.size();
492}
493
494wxString 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
502void 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
516int 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.size();
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
636 (m_data->m_arguments.begin() + n + 1, arg2);
637 count++;
638 }
639 //else: it's our value, we'll deal with it below
640 }
641 }
642
643 if ( optInd == wxNOT_FOUND )
644 {
645 ok = false;
646
647 continue; // will break, in fact
648 }
649
650 wxCmdLineOption& opt = m_data->m_options[(size_t)optInd];
651 if ( opt.kind == wxCMD_LINE_SWITCH )
652 {
653 // nothing more to do
654 opt.SetHasValue();
655
656 if ( opt.flags & wxCMD_LINE_OPTION_HELP )
657 {
658 helpRequested = true;
659
660 // it's not an error, but we still stop here
661 ok = false;
662 }
663 }
664 else
665 {
666 // get the value
667
668 // +1 for leading '-'
669 const wxChar *p = arg.c_str() + 1 + name.length();
670 if ( isLong )
671 {
672 p++; // for another leading '-'
673
674 if ( *p++ != _T('=') )
675 {
676 errorMsg << wxString::Format(_("Option '%s' requires a value, '=' expected."), name.c_str()) << wxT("\n");
677
678 ok = false;
679 }
680 }
681 else
682 {
683 switch ( *p )
684 {
685 case _T('='):
686 case _T(':'):
687 // the value follows
688 p++;
689 break;
690
691 case 0:
692 // the value is in the next argument
693 if ( ++n == count )
694 {
695 // ... but there is none
696 errorMsg << wxString::Format(_("Option '%s' requires a value."),
697 name.c_str()) << wxT("\n");
698
699 ok = false;
700 }
701 else
702 {
703 // ... take it from there
704 p = m_data->m_arguments[n].c_str();
705 }
706 break;
707
708 default:
709 // the value is right here: this may be legal or
710 // not depending on the option style
711 if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR )
712 {
713 errorMsg << wxString::Format(_("Separator expected after the option '%s'."),
714 name.c_str()) << wxT("\n");
715
716 ok = false;
717 }
718 }
719 }
720
721 if ( ok )
722 {
723 wxString value = p;
724 switch ( opt.type )
725 {
726 default:
727 wxFAIL_MSG( _T("unknown option type") );
728 // still fall through
729
730 case wxCMD_LINE_VAL_STRING:
731 opt.SetStrVal(value);
732 break;
733
734 case wxCMD_LINE_VAL_NUMBER:
735 {
736 long val;
737 if ( value.ToLong(&val) )
738 {
739 opt.SetLongVal(val);
740 }
741 else
742 {
743 errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
744 value.c_str(), name.c_str()) << wxT("\n");
745
746 ok = false;
747 }
748 }
749 break;
750
751#if wxUSE_DATETIME
752 case wxCMD_LINE_VAL_DATE:
753 {
754 wxDateTime dt;
755 const wxChar *res = dt.ParseDate(value);
756 if ( !res || *res )
757 {
758 errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
759 name.c_str(), value.c_str()) << wxT("\n");
760
761 ok = false;
762 }
763 else
764 {
765 opt.SetDateVal(dt);
766 }
767 }
768 break;
769#endif // wxUSE_DATETIME
770 }
771 }
772 }
773 }
774 else
775 {
776 // a parameter
777 if ( currentParam < countParam )
778 {
779 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
780
781 // TODO check the param type
782
783 m_data->m_parameters.push_back(arg);
784
785 if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
786 {
787 currentParam++;
788 }
789 else
790 {
791 wxASSERT_MSG( currentParam == countParam - 1,
792 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
793
794 // remember that we did have this last repeatable parameter
795 hadRepeatableParam = true;
796 }
797 }
798 else
799 {
800 errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str()) << wxT("\n");
801
802 ok = false;
803 }
804 }
805 }
806
807 // verify that all mandatory options were given
808 if ( ok )
809 {
810 size_t countOpt = m_data->m_options.GetCount();
811 for ( size_t n = 0; ok && (n < countOpt); n++ )
812 {
813 wxCmdLineOption& opt = m_data->m_options[n];
814 if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
815 {
816 wxString optName;
817 if ( !opt.longName )
818 {
819 optName = opt.shortName;
820 }
821 else
822 {
823 if ( AreLongOptionsEnabled() )
824 {
825 optName.Printf( _("%s (or %s)"),
826 opt.shortName.c_str(),
827 opt.longName.c_str() );
828 }
829 else
830 {
831 optName.Printf( wxT("%s"),
832 opt.shortName.c_str() );
833 }
834 }
835
836 errorMsg << wxString::Format(_("The value for the option '%s' must be specified."),
837 optName.c_str()) << wxT("\n");
838
839 ok = false;
840 }
841 }
842
843 for ( ; ok && (currentParam < countParam); currentParam++ )
844 {
845 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
846 if ( (currentParam == countParam - 1) &&
847 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
848 hadRepeatableParam )
849 {
850 // special case: currentParam wasn't incremented, but we did
851 // have it, so don't give error
852 continue;
853 }
854
855 if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
856 {
857 errorMsg << wxString::Format(_("The required parameter '%s' was not specified."),
858 param.description.c_str()) << wxT("\n");
859
860 ok = false;
861 }
862 }
863 }
864
865 // if there was an error during parsing the command line, show this error
866 // and also the usage message if it had been requested
867 if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
868 {
869 wxMessageOutput* msgOut = wxMessageOutput::Get();
870 if ( msgOut )
871 {
872 wxString usage;
873 if ( showUsage )
874 usage = GetUsageString();
875
876 msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() );
877 }
878 else
879 {
880 wxFAIL_MSG( _T("no wxMessageOutput object?") );
881 }
882 }
883
884 return ok ? 0 : helpRequested ? -1 : 1;
885}
886
887// ----------------------------------------------------------------------------
888// give the usage message
889// ----------------------------------------------------------------------------
890
891void wxCmdLineParser::Usage()
892{
893 wxMessageOutput* msgOut = wxMessageOutput::Get();
894 if ( msgOut )
895 {
896 msgOut->Printf( wxT("%s"), GetUsageString().c_str() );
897 }
898 else
899 {
900 wxFAIL_MSG( _T("no wxMessageOutput object?") );
901 }
902}
903
904wxString wxCmdLineParser::GetUsageString()
905{
906 wxString appname = wxTheApp->GetAppName();
907 if ( !appname )
908 {
909 wxCHECK_MSG( m_data->m_arguments.size() != 0, wxEmptyString,
910 _T("no program name") );
911
912 appname = wxFileNameFromPath(m_data->m_arguments[0]);
913 wxStripExtension(appname);
914 }
915
916 // we construct the brief cmd line desc on the fly, but not the detailed
917 // help message below because we want to align the options descriptions
918 // and for this we must first know the longest one of them
919 wxString usage;
920 wxArrayString namesOptions, descOptions;
921
922 if ( !m_data->m_logo.empty() )
923 {
924 usage << m_data->m_logo << _T('\n');
925 }
926
927 usage << wxString::Format(_("Usage: %s"), appname.c_str());
928
929 // the switch char is usually '-' but this can be changed with
930 // SetSwitchChars() and then the first one of possible chars is used
931 wxChar chSwitch = !m_data->m_switchChars ? _T('-')
932 : m_data->m_switchChars[0u];
933
934 bool areLongOptionsEnabled = AreLongOptionsEnabled();
935 size_t n, count = m_data->m_options.GetCount();
936 for ( n = 0; n < count; n++ )
937 {
938 wxCmdLineOption& opt = m_data->m_options[n];
939
940 usage << _T(' ');
941 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
942 {
943 usage << _T('[');
944 }
945
946 if ( !opt.shortName.empty() )
947 {
948 usage << chSwitch << opt.shortName;
949 }
950 else if ( areLongOptionsEnabled && !opt.longName.empty() )
951 {
952 usage << _T("--") << opt.longName;
953 }
954 else
955 {
956 if (!opt.longName.empty())
957 {
958 wxFAIL_MSG( wxT("option with only a long name while long ")
959 wxT("options are disabled") );
960 }
961 else
962 {
963 wxFAIL_MSG( _T("option without neither short nor long name") );
964 }
965 }
966
967 wxString option;
968
969 if ( !opt.shortName.empty() )
970 {
971 option << _T(" ") << chSwitch << opt.shortName;
972 }
973
974 if ( areLongOptionsEnabled && !opt.longName.empty() )
975 {
976 option << (option.empty() ? _T(" ") : _T(", "))
977 << _T("--") << opt.longName;
978 }
979
980 if ( opt.kind != wxCMD_LINE_SWITCH )
981 {
982 wxString val;
983 val << _T('<') << GetTypeName(opt.type) << _T('>');
984 usage << _T(' ') << val;
985 option << (!opt.longName ? _T(':') : _T('=')) << val;
986 }
987
988 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
989 {
990 usage << _T(']');
991 }
992
993 namesOptions.push_back(option);
994 descOptions.push_back(opt.description);
995 }
996
997 count = m_data->m_paramDesc.GetCount();
998 for ( n = 0; n < count; n++ )
999 {
1000 wxCmdLineParam& param = m_data->m_paramDesc[n];
1001
1002 usage << _T(' ');
1003 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1004 {
1005 usage << _T('[');
1006 }
1007
1008 usage << param.description;
1009
1010 if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
1011 {
1012 usage << _T("...");
1013 }
1014
1015 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1016 {
1017 usage << _T(']');
1018 }
1019 }
1020
1021 usage << _T('\n');
1022
1023 // now construct the detailed help message
1024 size_t len, lenMax = 0;
1025 count = namesOptions.size();
1026 for ( n = 0; n < count; n++ )
1027 {
1028 len = namesOptions[n].length();
1029 if ( len > lenMax )
1030 lenMax = len;
1031 }
1032
1033 for ( n = 0; n < count; n++ )
1034 {
1035 len = namesOptions[n].length();
1036 usage << namesOptions[n]
1037 << wxString(_T(' '), lenMax - len) << _T('\t')
1038 << descOptions[n]
1039 << _T('\n');
1040 }
1041
1042 return usage;
1043}
1044
1045// ----------------------------------------------------------------------------
1046// private functions
1047// ----------------------------------------------------------------------------
1048
1049static wxString GetTypeName(wxCmdLineParamType type)
1050{
1051 wxString s;
1052 switch ( type )
1053 {
1054 default:
1055 wxFAIL_MSG( _T("unknown option type") );
1056 // still fall through
1057
1058 case wxCMD_LINE_VAL_STRING:
1059 s = _("str");
1060 break;
1061
1062 case wxCMD_LINE_VAL_NUMBER:
1063 s = _("num");
1064 break;
1065
1066 case wxCMD_LINE_VAL_DATE:
1067 s = _("date");
1068 break;
1069 }
1070
1071 return s;
1072}
1073
1074/*
1075Returns a string which is equal to the string pointed to by p, but up to the
1076point where p contains an character that's not allowed.
1077Allowable characters are letters and numbers, and characters pointed to by
1078the parameter allowedChars.
1079
1080For example, if p points to "abcde-@-_", and allowedChars is "-_",
1081this function returns "abcde-".
1082*/
1083static wxString GetOptionName(const wxChar *p,
1084 const wxChar *allowedChars)
1085{
1086 wxString argName;
1087
1088 while ( *p && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) )
1089 {
1090 argName += *p++;
1091 }
1092
1093 return argName;
1094}
1095
1096// Besides alphanumeric characters, short and long options can
1097// have other characters.
1098
1099// A short option additionally can have these
1100#define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1101
1102// A long option can have the same characters as a short option and a '-'.
1103#define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1104 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1105
1106static wxString GetShortOptionName(const wxChar *p)
1107{
1108 return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION);
1109}
1110
1111static wxString GetLongOptionName(const wxChar *p)
1112{
1113 return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION);
1114}
1115
1116#endif // wxUSE_CMDLINE_PARSER
1117
1118// ----------------------------------------------------------------------------
1119// global functions
1120// ----------------------------------------------------------------------------
1121
1122/*
1123 This function is mainly used under Windows (as under Unix we always get the
1124 command line arguments as argc/argv anyhow) and so it tries to follow
1125 Windows conventions for the command line handling, not Unix ones. For
1126 instance, backslash is not special except when it precedes double quote when
1127 it does quote it.
1128 */
1129
1130/* static */
1131wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxChar *p)
1132{
1133 wxArrayString args;
1134
1135 wxString arg;
1136 arg.reserve(1024);
1137
1138 bool isInsideQuotes = false;
1139 for ( ;; )
1140 {
1141 // skip white space
1142 while ( *p == _T(' ') || *p == _T('\t') )
1143 p++;
1144
1145 // anything left?
1146 if ( *p == _T('\0') )
1147 break;
1148
1149 // parse this parameter
1150 bool endParam = false;
1151 bool lastBS = false;
1152 for ( arg.clear(); !endParam; p++ )
1153 {
1154 switch ( *p )
1155 {
1156 case _T('"'):
1157 if ( !lastBS )
1158 {
1159 isInsideQuotes = !isInsideQuotes;
1160
1161 // don't put quote in arg
1162 continue;
1163 }
1164 //else: quote has no special meaning but the backslash
1165 // still remains -- makes no sense but this is what
1166 // Windows does
1167 break;
1168
1169 case _T(' '):
1170 case _T('\t'):
1171 // backslash does *not* quote the space, only quotes do
1172 if ( isInsideQuotes )
1173 {
1174 // skip assignment below
1175 break;
1176 }
1177 // fall through
1178
1179 case _T('\0'):
1180 endParam = true;
1181
1182 break;
1183 }
1184
1185 if ( endParam )
1186 {
1187 break;
1188 }
1189
1190 lastBS = *p == _T('\\');
1191
1192 arg += *p;
1193 }
1194
1195 args.push_back(arg);
1196 }
1197
1198 return args;
1199}
1200