1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/cmdline.cpp
3 // Purpose: wxCmdLineParser implementation
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2000 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
27 #include "wx/dynarray.h"
28 #include "wx/string.h"
34 #include "wx/cmdline.h"
36 #if wxUSE_CMDLINE_PARSER
39 #include <locale.h> // for LC_ALL
41 #include "wx/datetime.h"
42 #include "wx/msgout.h"
43 #include "wx/filename.h"
44 #include "wx/apptrait.h"
45 #include "wx/scopeguard.h"
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
51 static wxString
GetTypeName(wxCmdLineParamType type
);
53 static wxString
GetOptionName(wxString::const_iterator p
,
54 wxString::const_iterator end
,
55 const wxChar
*allowedChars
);
57 static wxString
GetShortOptionName(wxString::const_iterator p
,
58 wxString::const_iterator end
);
60 static wxString
GetLongOptionName(wxString::const_iterator p
,
61 wxString::const_iterator end
);
63 // ----------------------------------------------------------------------------
65 // ----------------------------------------------------------------------------
67 // an internal representation of an option
68 struct wxCmdLineOption
70 wxCmdLineOption(wxCmdLineEntryType k
,
74 wxCmdLineParamType typ
,
77 // wxCMD_LINE_USAGE_TEXT uses only description, shortName and longName is empty
78 if ( k
!= wxCMD_LINE_USAGE_TEXT
)
82 !shrt
.empty() || !lng
.empty(),
83 wxT("option should have at least one name")
88 GetShortOptionName(shrt
.begin(), shrt
.end()).Len() == shrt
.Len(),
89 wxT("Short option contains invalid characters")
94 GetLongOptionName(lng
.begin(), lng
.end()).Len() == lng
.Len(),
95 wxT("Long option contains invalid characters")
111 // can't use union easily here, so just store all possible data fields, we
112 // don't waste much (might still use union later if the number of supported
113 // types increases, so always use the accessor functions and don't access
114 // the fields directly!)
116 void Check(wxCmdLineParamType
WXUNUSED_UNLESS_DEBUG(typ
)) const
118 wxASSERT_MSG( type
== typ
, wxT("type mismatch in wxCmdLineOption") );
121 double GetDoubleVal() const
122 { Check(wxCMD_LINE_VAL_DOUBLE
); return m_doubleVal
; }
123 long GetLongVal() const
124 { Check(wxCMD_LINE_VAL_NUMBER
); return m_longVal
; }
125 const wxString
& GetStrVal() const
126 { Check(wxCMD_LINE_VAL_STRING
); return m_strVal
; }
128 const wxDateTime
& GetDateVal() const
129 { Check(wxCMD_LINE_VAL_DATE
); return m_dateVal
; }
130 #endif // wxUSE_DATETIME
132 void SetDoubleVal(double val
)
133 { Check(wxCMD_LINE_VAL_DOUBLE
); m_doubleVal
= val
; m_hasVal
= true; }
134 void SetLongVal(long val
)
135 { Check(wxCMD_LINE_VAL_NUMBER
); m_longVal
= val
; m_hasVal
= true; }
136 void SetStrVal(const wxString
& val
)
137 { Check(wxCMD_LINE_VAL_STRING
); m_strVal
= val
; m_hasVal
= true; }
139 void SetDateVal(const wxDateTime
& val
)
140 { Check(wxCMD_LINE_VAL_DATE
); m_dateVal
= val
; m_hasVal
= true; }
141 #endif // wxUSE_DATETIME
143 void SetHasValue() { m_hasVal
= true; }
144 bool HasValue() const { return m_hasVal
; }
146 void SetNegated() { m_isNegated
= true; }
147 bool IsNegated() const { return m_isNegated
; }
149 // Reset to the initial state, called before parsing another command line.
157 wxCmdLineEntryType kind
;
161 wxCmdLineParamType type
;
172 wxDateTime m_dateVal
;
173 #endif // wxUSE_DATETIME
176 struct wxCmdLineParam
178 wxCmdLineParam(const wxString
& desc
,
179 wxCmdLineParamType typ
,
187 wxString description
;
188 wxCmdLineParamType type
;
192 WX_DECLARE_OBJARRAY(wxCmdLineOption
, wxArrayOptions
);
193 WX_DECLARE_OBJARRAY(wxCmdLineParam
, wxArrayParams
);
195 #include "wx/arrimpl.cpp"
197 WX_DEFINE_OBJARRAY(wxArrayOptions
)
198 WX_DEFINE_OBJARRAY(wxArrayParams
)
200 // the parser internal state
201 struct wxCmdLineParserData
204 wxString m_switchChars
; // characters which may start an option
205 bool m_enableLongOptions
; // true if long options are enabled
206 wxString m_logo
; // some extra text to show in Usage()
209 wxArrayString m_arguments
; // == argv, argc == m_arguments.GetCount()
210 wxArrayOptions m_options
; // all possible options and switches
211 wxArrayParams m_paramDesc
; // description of all possible params
212 wxArrayString m_parameters
; // all params found
215 wxCmdLineParserData();
216 void SetArguments(int argc
, char **argv
);
218 void SetArguments(int argc
, wxChar
**argv
);
219 void SetArguments(int argc
, const wxCmdLineArgsArray
& argv
);
220 #endif // wxUSE_UNICODE
221 void SetArguments(const wxString
& cmdline
);
223 int FindOption(const wxString
& name
);
224 int FindOptionByLongName(const wxString
& name
);
227 // ============================================================================
229 // ============================================================================
231 // ----------------------------------------------------------------------------
232 // wxCmdLineParserData
233 // ----------------------------------------------------------------------------
235 wxCmdLineParserData::wxCmdLineParserData()
237 m_enableLongOptions
= true;
239 m_switchChars
= wxT("-");
241 m_switchChars
= wxT("/-");
248 // Small helper function setting locale for all categories.
250 // We define it because wxSetlocale() can't be easily used with wxScopeGuard as
251 // it has several overloads -- while this one can.
252 inline char *SetAllLocaleFacets(const char *loc
)
254 return wxSetlocale(LC_ALL
, loc
);
257 } // private namespace
259 void wxCmdLineParserData::SetArguments(int argc
, char **argv
)
263 // Command-line arguments are supposed to be in the user locale encoding
264 // (what else?) but wxLocale probably wasn't initialized yet as we're
265 // called early during the program startup and so our locale might not have
266 // been set from the environment yet. To work around this problem we
267 // temporarily change the locale here. The only drawback is that changing
268 // the locale is thread-unsafe but precisely because we're called so early
269 // it's hopefully safe to assume that no other threads had been created yet.
270 char * const locOld
= SetAllLocaleFacets("");
271 wxON_BLOCK_EXIT1( SetAllLocaleFacets
, locOld
);
273 for ( int n
= 0; n
< argc
; n
++ )
275 // try to interpret the string as being in the current locale
276 wxString
arg(argv
[n
]);
278 // but just in case we guessed wrongly and the conversion failed, do
279 // try to salvage at least something
280 if ( arg
.empty() && argv
[n
][0] != '\0' )
281 arg
= wxString(argv
[n
], wxConvISO8859_1
);
283 m_arguments
.push_back(arg
);
289 void wxCmdLineParserData::SetArguments(int argc
, wxChar
**argv
)
293 for ( int n
= 0; n
< argc
; n
++ )
295 m_arguments
.push_back(argv
[n
]);
299 void wxCmdLineParserData::SetArguments(int WXUNUSED(argc
),
300 const wxCmdLineArgsArray
& argv
)
302 m_arguments
= argv
.GetArguments();
305 #endif // wxUSE_UNICODE
307 void wxCmdLineParserData::SetArguments(const wxString
& cmdLine
)
311 if(wxTheApp
&& wxTheApp
->argc
> 0)
312 m_arguments
.push_back(wxTheApp
->argv
[0]);
314 m_arguments
.push_back(wxEmptyString
);
316 wxArrayString args
= wxCmdLineParser::ConvertStringToArgs(cmdLine
);
318 WX_APPEND_ARRAY(m_arguments
, args
);
321 int wxCmdLineParserData::FindOption(const wxString
& name
)
325 size_t count
= m_options
.GetCount();
326 for ( size_t n
= 0; n
< count
; n
++ )
328 if ( m_options
[n
].shortName
== name
)
339 int wxCmdLineParserData::FindOptionByLongName(const wxString
& name
)
341 size_t count
= m_options
.GetCount();
342 for ( size_t n
= 0; n
< count
; n
++ )
344 if ( m_options
[n
].longName
== name
)
354 // ----------------------------------------------------------------------------
355 // construction and destruction
356 // ----------------------------------------------------------------------------
358 void wxCmdLineParser::Init()
360 m_data
= new wxCmdLineParserData
;
363 void wxCmdLineParser::SetCmdLine(int argc
, char **argv
)
365 m_data
->SetArguments(argc
, argv
);
370 void wxCmdLineParser::SetCmdLine(int argc
, wxChar
**argv
)
372 m_data
->SetArguments(argc
, argv
);
375 void wxCmdLineParser::SetCmdLine(int argc
, const wxCmdLineArgsArray
& argv
)
377 m_data
->SetArguments(argc
, argv
);
380 #endif // wxUSE_UNICODE
382 void wxCmdLineParser::SetCmdLine(const wxString
& cmdline
)
384 m_data
->SetArguments(cmdline
);
387 wxCmdLineParser::~wxCmdLineParser()
392 // ----------------------------------------------------------------------------
394 // ----------------------------------------------------------------------------
396 void wxCmdLineParser::SetSwitchChars(const wxString
& switchChars
)
398 m_data
->m_switchChars
= switchChars
;
401 void wxCmdLineParser::EnableLongOptions(bool enable
)
403 m_data
->m_enableLongOptions
= enable
;
406 bool wxCmdLineParser::AreLongOptionsEnabled() const
408 return m_data
->m_enableLongOptions
;
411 void wxCmdLineParser::SetLogo(const wxString
& logo
)
413 m_data
->m_logo
= logo
;
416 // ----------------------------------------------------------------------------
417 // command line construction
418 // ----------------------------------------------------------------------------
420 void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc
*desc
)
424 switch ( desc
->kind
)
426 case wxCMD_LINE_SWITCH
:
427 AddSwitch(desc
->shortName
, desc
->longName
,
428 wxGetTranslation(desc
->description
),
432 case wxCMD_LINE_OPTION
:
433 AddOption(desc
->shortName
, desc
->longName
,
434 wxGetTranslation(desc
->description
),
435 desc
->type
, desc
->flags
);
438 case wxCMD_LINE_PARAM
:
439 AddParam(wxGetTranslation(desc
->description
),
440 desc
->type
, desc
->flags
);
443 case wxCMD_LINE_USAGE_TEXT
:
444 AddUsageText(wxGetTranslation(desc
->description
));
448 wxFAIL_MSG( wxT("unknown command line entry type") );
449 // still fall through
451 case wxCMD_LINE_NONE
:
457 void wxCmdLineParser::AddSwitch(const wxString
& shortName
,
458 const wxString
& longName
,
459 const wxString
& desc
,
462 wxASSERT_MSG( m_data
->FindOption(shortName
) == wxNOT_FOUND
,
463 wxT("duplicate switch") );
465 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_SWITCH
,
466 shortName
, longName
, desc
,
467 wxCMD_LINE_VAL_NONE
, flags
);
469 m_data
->m_options
.Add(option
);
472 void wxCmdLineParser::AddOption(const wxString
& shortName
,
473 const wxString
& longName
,
474 const wxString
& desc
,
475 wxCmdLineParamType type
,
478 wxASSERT_MSG( m_data
->FindOption(shortName
) == wxNOT_FOUND
,
479 wxT("duplicate option") );
481 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_OPTION
,
482 shortName
, longName
, desc
,
485 m_data
->m_options
.Add(option
);
488 void wxCmdLineParser::AddParam(const wxString
& desc
,
489 wxCmdLineParamType type
,
492 // do some consistency checks: a required parameter can't follow an
493 // optional one and nothing should follow a parameter with MULTIPLE flag
495 if ( !m_data
->m_paramDesc
.IsEmpty() )
497 wxCmdLineParam
& param
= m_data
->m_paramDesc
.Last();
499 wxASSERT_MSG( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
),
500 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
502 if ( !(flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
504 wxASSERT_MSG( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
),
505 wxT("a required parameter can't follow an optional one") );
508 #endif // wxDEBUG_LEVEL
510 wxCmdLineParam
*param
= new wxCmdLineParam(desc
, type
, flags
);
512 m_data
->m_paramDesc
.Add(param
);
515 void wxCmdLineParser::AddUsageText(const wxString
& text
)
517 wxASSERT_MSG( !text
.empty(), wxT("text can't be empty") );
519 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_USAGE_TEXT
,
520 wxEmptyString
, wxEmptyString
,
521 text
, wxCMD_LINE_VAL_NONE
, 0);
523 m_data
->m_options
.Add(option
);
526 // ----------------------------------------------------------------------------
527 // access to parse command line
528 // ----------------------------------------------------------------------------
530 bool wxCmdLineParser::Found(const wxString
& name
) const
532 return FoundSwitch(name
) != wxCMD_SWITCH_NOT_FOUND
;
535 wxCmdLineSwitchState
wxCmdLineParser::FoundSwitch(const wxString
& name
) const
537 int i
= m_data
->FindOption(name
);
538 if ( i
== wxNOT_FOUND
)
539 i
= m_data
->FindOptionByLongName(name
);
541 wxCHECK_MSG( i
!= wxNOT_FOUND
, wxCMD_SWITCH_NOT_FOUND
, wxT("unknown switch") );
543 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
544 if ( !opt
.HasValue() )
545 return wxCMD_SWITCH_NOT_FOUND
;
547 return opt
.IsNegated() ? wxCMD_SWITCH_OFF
: wxCMD_SWITCH_ON
;
550 bool wxCmdLineParser::Found(const wxString
& name
, wxString
*value
) const
552 int i
= m_data
->FindOption(name
);
553 if ( i
== wxNOT_FOUND
)
554 i
= m_data
->FindOptionByLongName(name
);
556 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
558 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
559 if ( !opt
.HasValue() )
562 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
564 *value
= opt
.GetStrVal();
569 bool wxCmdLineParser::Found(const wxString
& name
, long *value
) const
571 int i
= m_data
->FindOption(name
);
572 if ( i
== wxNOT_FOUND
)
573 i
= m_data
->FindOptionByLongName(name
);
575 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
577 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
578 if ( !opt
.HasValue() )
581 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
583 *value
= opt
.GetLongVal();
588 bool wxCmdLineParser::Found(const wxString
& name
, double *value
) const
590 int i
= m_data
->FindOption(name
);
591 if ( i
== wxNOT_FOUND
)
592 i
= m_data
->FindOptionByLongName(name
);
594 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
596 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
597 if ( !opt
.HasValue() )
600 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
602 *value
= opt
.GetDoubleVal();
608 bool wxCmdLineParser::Found(const wxString
& name
, wxDateTime
*value
) const
610 int i
= m_data
->FindOption(name
);
611 if ( i
== wxNOT_FOUND
)
612 i
= m_data
->FindOptionByLongName(name
);
614 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
616 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
617 if ( !opt
.HasValue() )
620 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
622 *value
= opt
.GetDateVal();
626 #endif // wxUSE_DATETIME
628 size_t wxCmdLineParser::GetParamCount() const
630 return m_data
->m_parameters
.size();
633 wxString
wxCmdLineParser::GetParam(size_t n
) const
635 wxCHECK_MSG( n
< GetParamCount(), wxEmptyString
, wxT("invalid param index") );
637 return m_data
->m_parameters
[n
];
640 // Resets switches and options
641 void wxCmdLineParser::Reset()
643 for ( size_t i
= 0; i
< m_data
->m_options
.GetCount(); i
++ )
645 m_data
->m_options
[i
].Reset();
650 // ----------------------------------------------------------------------------
651 // the real work is done here
652 // ----------------------------------------------------------------------------
654 int wxCmdLineParser::Parse(bool showUsage
)
656 bool maybeOption
= true; // can the following arg be an option?
657 bool ok
= true; // true until an error is detected
658 bool helpRequested
= false; // true if "-h" was given
659 bool hadRepeatableParam
= false; // true if found param with MULTIPLE flag
661 size_t currentParam
= 0; // the index in m_paramDesc
663 size_t countParam
= m_data
->m_paramDesc
.GetCount();
670 size_t count
= m_data
->m_arguments
.size();
671 for ( size_t n
= 1; ok
&& (n
< count
); n
++ ) // 0 is program name
673 arg
= m_data
->m_arguments
[n
];
675 // special case: "--" should be discarded and all following arguments
676 // should be considered as parameters, even if they start with '-' and
677 // not like options (this is POSIX-like)
678 if ( arg
== wxT("--") )
685 // empty argument or just '-' is not an option but a parameter
686 if ( maybeOption
&& arg
.length() > 1 &&
687 // FIXME-UTF8: use wc_str() after removing ANSI build
688 wxStrchr(m_data
->m_switchChars
.c_str(), arg
[0u]) )
692 int optInd
= wxNOT_FOUND
; // init to suppress warnings
694 // an option or a switch: find whether it's a long or a short one
695 if ( arg
.length() >= 3 && arg
[0u] == wxT('-') && arg
[1u] == wxT('-') )
701 wxString::const_iterator p
= arg
.begin() + 2;
703 bool longOptionsEnabled
= AreLongOptionsEnabled();
705 name
= GetLongOptionName(p
, arg
.end());
707 if (longOptionsEnabled
)
711 optInd
= m_data
->FindOptionByLongName(name
);
712 if ( optInd
== wxNOT_FOUND
)
714 // Check if this could be a negatable long option.
715 if ( name
.Last() == '-' )
719 optInd
= m_data
->FindOptionByLongName(name
);
720 if ( optInd
!= wxNOT_FOUND
)
722 if ( !(m_data
->m_options
[optInd
].flags
&
723 wxCMD_LINE_SWITCH_NEGATABLE
) )
727 _("Option '%s' can't be negated"),
730 optInd
= wxNOT_FOUND
;
735 if ( optInd
== wxNOT_FOUND
)
737 if ( errorOpt
.empty() )
741 _("Unknown long option '%s'"),
746 errorMsg
<< errorOpt
<< wxT('\n');
752 optInd
= wxNOT_FOUND
; // Sanity check
754 // Print the argument including leading "--"
755 name
.Prepend( wxT("--") );
756 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
761 else // not a long option
765 // a short one: as they can be cumulated, we try to find the
766 // longest substring which is a valid option
767 wxString::const_iterator p
= arg
.begin() + 1;
769 name
= GetShortOptionName(p
, arg
.end());
771 size_t len
= name
.length();
776 // we couldn't find a valid option name in the
777 // beginning of this string
778 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
785 optInd
= m_data
->FindOption(name
.Left(len
));
787 // will try with one character less the next time
791 while ( optInd
== wxNOT_FOUND
);
793 len
++; // compensates extra len-- above
794 if ( (optInd
!= wxNOT_FOUND
) && (len
!= name
.length()) )
796 // first of all, the option name is only part of this
798 name
= name
.Left(len
);
800 // our option is only part of this argument, there is
801 // something else in it - it is either the value of this
802 // option or other switches if it is a switch
803 if ( m_data
->m_options
[(size_t)optInd
].kind
804 == wxCMD_LINE_SWITCH
)
806 // if the switch is negatable and it is just followed
807 // by '-' the '-' is considered to be part of this
809 if ( (m_data
->m_options
[(size_t)optInd
].flags
&
810 wxCMD_LINE_SWITCH_NEGATABLE
) &&
814 // pretend that all the rest of the argument is the
815 // next argument, in fact
816 wxString arg2
= arg
[0u];
817 arg2
+= arg
.Mid(len
+ 1); // +1 for leading '-'
819 m_data
->m_arguments
.insert
820 (m_data
->m_arguments
.begin() + n
+ 1, arg2
);
823 // only leave the part which wasn't extracted into the
824 // next argument in this one
825 arg
= arg
.Left(len
+ 1);
827 //else: it's our value, we'll deal with it below
831 if ( optInd
== wxNOT_FOUND
)
835 continue; // will break, in fact
838 // look at what follows:
840 // +1 for leading '-'
841 wxString::const_iterator p
= arg
.begin() + 1 + name
.length();
842 wxString::const_iterator end
= arg
.end();
845 ++p
; // for another leading '-'
847 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)optInd
];
848 if ( opt
.kind
== wxCMD_LINE_SWITCH
)
850 // we must check that there is no value following the switch
851 bool negated
= (opt
.flags
& wxCMD_LINE_SWITCH_NEGATABLE
) &&
852 p
!= arg
.end() && *p
== '-';
854 if ( !negated
&& p
!= arg
.end() )
856 errorMsg
<< wxString::Format(_("Unexpected characters following option '%s'."), name
.c_str())
860 else // no value, as expected
862 // nothing more to do
867 if ( opt
.flags
& wxCMD_LINE_OPTION_HELP
)
869 helpRequested
= true;
871 // it's not an error, but we still stop here
876 else // it's an option. not a switch
878 switch ( p
== end
? '\0' : (*p
).GetValue() )
887 // the value is in the next argument
890 // ... but there is none
891 errorMsg
<< wxString::Format(_("Option '%s' requires a value."),
899 // ... take it from there
900 p
= m_data
->m_arguments
[n
].begin();
901 end
= m_data
->m_arguments
[n
].end();
906 // the value is right here: this may be legal or
907 // not depending on the option style
908 if ( opt
.flags
& wxCMD_LINE_NEEDS_SEPARATOR
)
910 errorMsg
<< wxString::Format(_("Separator expected after the option '%s'."),
920 wxString
value(p
, end
);
924 wxFAIL_MSG( wxT("unknown option type") );
925 // still fall through
927 case wxCMD_LINE_VAL_STRING
:
928 opt
.SetStrVal(value
);
931 case wxCMD_LINE_VAL_NUMBER
:
934 if ( value
.ToLong(&val
) )
940 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
941 value
.c_str(), name
.c_str())
949 case wxCMD_LINE_VAL_DOUBLE
:
952 if ( value
.ToDouble(&val
) )
954 opt
.SetDoubleVal(val
);
958 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
959 value
.c_str(), name
.c_str())
968 case wxCMD_LINE_VAL_DATE
:
971 wxString::const_iterator endDate
;
972 if ( !dt
.ParseDate(value
, &endDate
) || endDate
!= value
.end() )
974 errorMsg
<< wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
975 name
.c_str(), value
.c_str())
986 #endif // wxUSE_DATETIME
991 else // not an option, must be a parameter
993 if ( currentParam
< countParam
)
995 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
997 // TODO check the param type
999 m_data
->m_parameters
.push_back(arg
);
1001 if ( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) )
1007 wxASSERT_MSG( currentParam
== countParam
- 1,
1008 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
1010 // remember that we did have this last repeatable parameter
1011 hadRepeatableParam
= true;
1016 errorMsg
<< wxString::Format(_("Unexpected parameter '%s'"), arg
.c_str())
1024 // verify that all mandatory options were given
1027 size_t countOpt
= m_data
->m_options
.GetCount();
1028 for ( size_t n
= 0; ok
&& (n
< countOpt
); n
++ )
1030 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1031 if ( (opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) && !opt
.HasValue() )
1034 if ( !opt
.longName
)
1036 optName
= opt
.shortName
;
1040 if ( AreLongOptionsEnabled() )
1042 optName
.Printf( _("%s (or %s)"),
1043 opt
.shortName
.c_str(),
1044 opt
.longName
.c_str() );
1048 optName
.Printf( wxT("%s"),
1049 opt
.shortName
.c_str() );
1053 errorMsg
<< wxString::Format(_("The value for the option '%s' must be specified."),
1061 for ( ; ok
&& (currentParam
< countParam
); currentParam
++ )
1063 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
1064 if ( (currentParam
== countParam
- 1) &&
1065 (param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) &&
1066 hadRepeatableParam
)
1068 // special case: currentParam wasn't incremented, but we did
1069 // have it, so don't give error
1073 if ( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
1075 errorMsg
<< wxString::Format(_("The required parameter '%s' was not specified."),
1076 param
.description
.c_str())
1084 // if there was an error during parsing the command line, show this error
1085 // and also the usage message if it had been requested
1086 if ( !ok
&& (!errorMsg
.empty() || (helpRequested
&& showUsage
)) )
1088 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1093 usage
= GetUsageString();
1095 msgOut
->Printf( wxT("%s%s"), usage
.c_str(), errorMsg
.c_str() );
1099 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1103 return ok
? 0 : helpRequested
? -1 : 1;
1106 // ----------------------------------------------------------------------------
1107 // give the usage message
1108 // ----------------------------------------------------------------------------
1110 void wxCmdLineParser::Usage() const
1112 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1115 msgOut
->Printf( wxT("%s"), GetUsageString().c_str() );
1119 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1123 wxString
wxCmdLineParser::GetUsageString() const
1126 if ( m_data
->m_arguments
.empty() )
1129 appname
= wxTheApp
->GetAppName();
1133 appname
= wxFileName(m_data
->m_arguments
[0]).GetName();
1136 // we construct the brief cmd line desc on the fly, but not the detailed
1137 // help message below because we want to align the options descriptions
1138 // and for this we must first know the longest one of them
1140 wxArrayString namesOptions
, descOptions
;
1142 if ( !m_data
->m_logo
.empty() )
1144 usage
<< m_data
->m_logo
<< wxT('\n');
1147 usage
<< wxString::Format(_("Usage: %s"), appname
.c_str());
1149 // the switch char is usually '-' but this can be changed with
1150 // SetSwitchChars() and then the first one of possible chars is used
1151 wxChar chSwitch
= !m_data
->m_switchChars
? wxT('-')
1152 : m_data
->m_switchChars
[0u];
1154 bool areLongOptionsEnabled
= AreLongOptionsEnabled();
1155 size_t n
, count
= m_data
->m_options
.GetCount();
1156 for ( n
= 0; n
< count
; n
++ )
1158 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1159 wxString option
, negator
;
1161 if ( opt
.kind
!= wxCMD_LINE_USAGE_TEXT
)
1164 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1169 if ( opt
.flags
& wxCMD_LINE_SWITCH_NEGATABLE
)
1170 negator
= wxT("[-]");
1172 if ( !opt
.shortName
.empty() )
1174 usage
<< chSwitch
<< opt
.shortName
<< negator
;
1176 else if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1178 usage
<< wxT("--") << opt
.longName
<< negator
;
1182 if (!opt
.longName
.empty())
1184 wxFAIL_MSG( wxT("option with only a long name while long ")
1185 wxT("options are disabled") );
1189 wxFAIL_MSG( wxT("option without neither short nor long name") );
1193 if ( !opt
.shortName
.empty() )
1195 option
<< wxT(" ") << chSwitch
<< opt
.shortName
;
1198 if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1200 option
<< (option
.empty() ? wxT(" ") : wxT(", "))
1201 << wxT("--") << opt
.longName
;
1204 if ( opt
.kind
!= wxCMD_LINE_SWITCH
)
1207 val
<< wxT('<') << GetTypeName(opt
.type
) << wxT('>');
1208 usage
<< wxT(' ') << val
;
1209 option
<< (!opt
.longName
? wxT(':') : wxT('=')) << val
;
1212 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1218 namesOptions
.push_back(option
);
1219 descOptions
.push_back(opt
.description
);
1222 count
= m_data
->m_paramDesc
.GetCount();
1223 for ( n
= 0; n
< count
; n
++ )
1225 wxCmdLineParam
& param
= m_data
->m_paramDesc
[n
];
1228 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1233 usage
<< param
.description
;
1235 if ( param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
)
1237 usage
<< wxT("...");
1240 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1248 // set to number of our own options, not counting the standard ones
1249 count
= namesOptions
.size();
1251 // get option names & descriptions for standard options, if any:
1252 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
1255 stdDesc
= traits
->GetStandardCmdLineOptions(namesOptions
, descOptions
);
1257 // now construct the detailed help message
1258 size_t len
, lenMax
= 0;
1259 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1261 len
= namesOptions
[n
].length();
1266 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1269 usage
<< wxT('\n') << stdDesc
;
1271 len
= namesOptions
[n
].length();
1272 // desc contains text if name is empty
1275 usage
<< descOptions
[n
] << wxT('\n');
1279 usage
<< namesOptions
[n
]
1280 << wxString(wxT(' '), lenMax
- len
) << wxT('\t')
1289 // ----------------------------------------------------------------------------
1290 // private functions
1291 // ----------------------------------------------------------------------------
1293 static wxString
GetTypeName(wxCmdLineParamType type
)
1299 wxFAIL_MSG( wxT("unknown option type") );
1300 // still fall through
1302 case wxCMD_LINE_VAL_STRING
:
1306 case wxCMD_LINE_VAL_NUMBER
:
1310 case wxCMD_LINE_VAL_DOUBLE
:
1314 case wxCMD_LINE_VAL_DATE
:
1323 Returns a string which is equal to the string pointed to by p, but up to the
1324 point where p contains an character that's not allowed.
1325 Allowable characters are letters and numbers, and characters pointed to by
1326 the parameter allowedChars.
1328 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1329 this function returns "abcde-".
1331 static wxString
GetOptionName(wxString::const_iterator p
,
1332 wxString::const_iterator end
,
1333 const wxChar
*allowedChars
)
1337 while ( p
!= end
&& (wxIsalnum(*p
) || wxStrchr(allowedChars
, *p
)) )
1345 // Besides alphanumeric characters, short and long options can
1346 // have other characters.
1348 // A short option additionally can have these
1349 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1351 // A long option can have the same characters as a short option and a '-'.
1352 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1353 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1355 static wxString
GetShortOptionName(wxString::const_iterator p
,
1356 wxString::const_iterator end
)
1358 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION
);
1361 static wxString
GetLongOptionName(wxString::const_iterator p
,
1362 wxString::const_iterator end
)
1364 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION
);
1367 #endif // wxUSE_CMDLINE_PARSER
1369 // ----------------------------------------------------------------------------
1371 // ----------------------------------------------------------------------------
1374 This function is mainly used under Windows (as under Unix we always get the
1375 command line arguments as argc/argv anyhow) and so it tries to follow
1376 Windows conventions for the command line handling, not Unix ones. For
1377 instance, backslash is not special except when it precedes double quote when
1380 TODO: Rewrite this to follow the even more complicated rule used by Windows
1381 CommandLineToArgv():
1383 * A string of backslashes not followed by a quotation mark has no special
1385 * An even number of backslashes followed by a quotation mark is treated as
1386 pairs of protected backslashes, followed by a word terminator.
1387 * An odd number of backslashes followed by a quotation mark is treated as
1388 pairs of protected backslashes, followed by a protected quotation mark.
1390 See http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
1392 It could also be useful to provide a converse function which is also
1395 http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
1400 wxCmdLineParser::ConvertStringToArgs(const wxString
& cmdline
,
1401 wxCmdLineSplitType type
)
1408 const wxString::const_iterator end
= cmdline
.end();
1409 wxString::const_iterator p
= cmdline
.begin();
1414 while ( p
!= end
&& (*p
== ' ' || *p
== '\t') )
1421 // parse this parameter
1422 bool lastBS
= false,
1423 isInsideQuotes
= false;
1424 wxChar chDelim
= '\0';
1425 for ( arg
.clear(); p
!= end
; ++p
)
1427 const wxChar ch
= *p
;
1429 if ( type
== wxCMD_LINE_SPLIT_DOS
)
1435 isInsideQuotes
= !isInsideQuotes
;
1437 // don't put quote in arg
1440 //else: quote has no special meaning but the backslash
1441 // still remains -- makes no sense but this is what
1444 // note that backslash does *not* quote the space, only quotes do
1445 else if ( !isInsideQuotes
&& (ch
== ' ' || ch
== '\t') )
1447 ++p
; // skip this space anyhow
1451 lastBS
= !lastBS
&& ch
== '\\';
1453 else // type == wxCMD_LINE_SPLIT_UNIX
1457 if ( isInsideQuotes
)
1459 if ( ch
== chDelim
)
1461 isInsideQuotes
= false;
1463 continue; // don't use the quote itself
1466 else // not in quotes and not escaped
1468 if ( ch
== '\'' || ch
== '"' )
1470 isInsideQuotes
= true;
1473 continue; // don't use the quote itself
1476 if ( ch
== ' ' || ch
== '\t' )
1478 ++p
; // skip this space anyhow
1483 lastBS
= ch
== '\\';
1487 else // escaped by backslash, just use as is
1496 args
.push_back(arg
);