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 if ( arg
== wxT("-ApplePersistenceIgnoreState") )
693 // empty argument or just '-' is not an option but a parameter
694 if ( maybeOption
&& arg
.length() > 1 &&
695 // FIXME-UTF8: use wc_str() after removing ANSI build
696 wxStrchr(m_data
->m_switchChars
.c_str(), arg
[0u]) )
700 int optInd
= wxNOT_FOUND
; // init to suppress warnings
702 // an option or a switch: find whether it's a long or a short one
703 if ( arg
.length() >= 3 && arg
[0u] == wxT('-') && arg
[1u] == wxT('-') )
709 wxString::const_iterator p
= arg
.begin() + 2;
711 bool longOptionsEnabled
= AreLongOptionsEnabled();
713 name
= GetLongOptionName(p
, arg
.end());
715 if (longOptionsEnabled
)
719 optInd
= m_data
->FindOptionByLongName(name
);
720 if ( optInd
== wxNOT_FOUND
)
722 // Check if this could be a negatable long option.
723 if ( name
.Last() == '-' )
727 optInd
= m_data
->FindOptionByLongName(name
);
728 if ( optInd
!= wxNOT_FOUND
)
730 if ( !(m_data
->m_options
[optInd
].flags
&
731 wxCMD_LINE_SWITCH_NEGATABLE
) )
735 _("Option '%s' can't be negated"),
738 optInd
= wxNOT_FOUND
;
743 if ( optInd
== wxNOT_FOUND
)
745 if ( errorOpt
.empty() )
749 _("Unknown long option '%s'"),
754 errorMsg
<< errorOpt
<< wxT('\n');
760 optInd
= wxNOT_FOUND
; // Sanity check
762 // Print the argument including leading "--"
763 name
.Prepend( wxT("--") );
764 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
769 else // not a long option
773 // a short one: as they can be cumulated, we try to find the
774 // longest substring which is a valid option
775 wxString::const_iterator p
= arg
.begin() + 1;
777 name
= GetShortOptionName(p
, arg
.end());
779 size_t len
= name
.length();
784 // we couldn't find a valid option name in the
785 // beginning of this string
786 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
793 optInd
= m_data
->FindOption(name
.Left(len
));
795 // will try with one character less the next time
799 while ( optInd
== wxNOT_FOUND
);
801 len
++; // compensates extra len-- above
802 if ( (optInd
!= wxNOT_FOUND
) && (len
!= name
.length()) )
804 // first of all, the option name is only part of this
806 name
= name
.Left(len
);
808 // our option is only part of this argument, there is
809 // something else in it - it is either the value of this
810 // option or other switches if it is a switch
811 if ( m_data
->m_options
[(size_t)optInd
].kind
812 == wxCMD_LINE_SWITCH
)
814 // if the switch is negatable and it is just followed
815 // by '-' the '-' is considered to be part of this
817 if ( (m_data
->m_options
[(size_t)optInd
].flags
&
818 wxCMD_LINE_SWITCH_NEGATABLE
) &&
822 // pretend that all the rest of the argument is the
823 // next argument, in fact
824 wxString arg2
= arg
[0u];
825 arg2
+= arg
.Mid(len
+ 1); // +1 for leading '-'
827 m_data
->m_arguments
.insert
828 (m_data
->m_arguments
.begin() + n
+ 1, arg2
);
831 // only leave the part which wasn't extracted into the
832 // next argument in this one
833 arg
= arg
.Left(len
+ 1);
835 //else: it's our value, we'll deal with it below
839 if ( optInd
== wxNOT_FOUND
)
843 continue; // will break, in fact
846 // look at what follows:
848 // +1 for leading '-'
849 wxString::const_iterator p
= arg
.begin() + 1 + name
.length();
850 wxString::const_iterator end
= arg
.end();
853 ++p
; // for another leading '-'
855 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)optInd
];
856 if ( opt
.kind
== wxCMD_LINE_SWITCH
)
858 // we must check that there is no value following the switch
859 bool negated
= (opt
.flags
& wxCMD_LINE_SWITCH_NEGATABLE
) &&
860 p
!= arg
.end() && *p
== '-';
862 if ( !negated
&& p
!= arg
.end() )
864 errorMsg
<< wxString::Format(_("Unexpected characters following option '%s'."), name
.c_str())
868 else // no value, as expected
870 // nothing more to do
875 if ( opt
.flags
& wxCMD_LINE_OPTION_HELP
)
877 helpRequested
= true;
879 // it's not an error, but we still stop here
884 else // it's an option. not a switch
886 switch ( p
== end
? '\0' : (*p
).GetValue() )
895 // the value is in the next argument
898 // ... but there is none
899 errorMsg
<< wxString::Format(_("Option '%s' requires a value."),
907 // ... take it from there
908 p
= m_data
->m_arguments
[n
].begin();
909 end
= m_data
->m_arguments
[n
].end();
914 // the value is right here: this may be legal or
915 // not depending on the option style
916 if ( opt
.flags
& wxCMD_LINE_NEEDS_SEPARATOR
)
918 errorMsg
<< wxString::Format(_("Separator expected after the option '%s'."),
928 wxString
value(p
, end
);
932 wxFAIL_MSG( wxT("unknown option type") );
933 // still fall through
935 case wxCMD_LINE_VAL_STRING
:
936 opt
.SetStrVal(value
);
939 case wxCMD_LINE_VAL_NUMBER
:
942 if ( value
.ToLong(&val
) )
948 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
949 value
.c_str(), name
.c_str())
957 case wxCMD_LINE_VAL_DOUBLE
:
960 if ( value
.ToDouble(&val
) )
962 opt
.SetDoubleVal(val
);
966 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
967 value
.c_str(), name
.c_str())
976 case wxCMD_LINE_VAL_DATE
:
979 wxString::const_iterator endDate
;
980 if ( !dt
.ParseDate(value
, &endDate
) || endDate
!= value
.end() )
982 errorMsg
<< wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
983 name
.c_str(), value
.c_str())
994 #endif // wxUSE_DATETIME
999 else // not an option, must be a parameter
1001 if ( currentParam
< countParam
)
1003 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
1005 // TODO check the param type
1007 m_data
->m_parameters
.push_back(arg
);
1009 if ( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) )
1015 wxASSERT_MSG( currentParam
== countParam
- 1,
1016 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
1018 // remember that we did have this last repeatable parameter
1019 hadRepeatableParam
= true;
1024 errorMsg
<< wxString::Format(_("Unexpected parameter '%s'"), arg
.c_str())
1032 // verify that all mandatory options were given
1035 size_t countOpt
= m_data
->m_options
.GetCount();
1036 for ( size_t n
= 0; ok
&& (n
< countOpt
); n
++ )
1038 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1039 if ( (opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) && !opt
.HasValue() )
1042 if ( !opt
.longName
)
1044 optName
= opt
.shortName
;
1048 if ( AreLongOptionsEnabled() )
1050 optName
.Printf( _("%s (or %s)"),
1051 opt
.shortName
.c_str(),
1052 opt
.longName
.c_str() );
1056 optName
.Printf( wxT("%s"),
1057 opt
.shortName
.c_str() );
1061 errorMsg
<< wxString::Format(_("The value for the option '%s' must be specified."),
1069 for ( ; ok
&& (currentParam
< countParam
); currentParam
++ )
1071 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
1072 if ( (currentParam
== countParam
- 1) &&
1073 (param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) &&
1074 hadRepeatableParam
)
1076 // special case: currentParam wasn't incremented, but we did
1077 // have it, so don't give error
1081 if ( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
1083 errorMsg
<< wxString::Format(_("The required parameter '%s' was not specified."),
1084 param
.description
.c_str())
1092 // if there was an error during parsing the command line, show this error
1093 // and also the usage message if it had been requested
1094 if ( !ok
&& (!errorMsg
.empty() || (helpRequested
&& showUsage
)) )
1096 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1101 usage
= GetUsageString();
1103 msgOut
->Printf( wxT("%s%s"), usage
.c_str(), errorMsg
.c_str() );
1107 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1111 return ok
? 0 : helpRequested
? -1 : 1;
1114 // ----------------------------------------------------------------------------
1115 // give the usage message
1116 // ----------------------------------------------------------------------------
1118 void wxCmdLineParser::Usage() const
1120 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1123 msgOut
->Printf( wxT("%s"), GetUsageString().c_str() );
1127 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1131 wxString
wxCmdLineParser::GetUsageString() const
1134 if ( m_data
->m_arguments
.empty() )
1137 appname
= wxTheApp
->GetAppName();
1141 appname
= wxFileName(m_data
->m_arguments
[0]).GetName();
1144 // we construct the brief cmd line desc on the fly, but not the detailed
1145 // help message below because we want to align the options descriptions
1146 // and for this we must first know the longest one of them
1148 wxArrayString namesOptions
, descOptions
;
1150 if ( !m_data
->m_logo
.empty() )
1152 usage
<< m_data
->m_logo
<< wxT('\n');
1155 usage
<< wxString::Format(_("Usage: %s"), appname
.c_str());
1157 // the switch char is usually '-' but this can be changed with
1158 // SetSwitchChars() and then the first one of possible chars is used
1159 wxChar chSwitch
= !m_data
->m_switchChars
? wxT('-')
1160 : m_data
->m_switchChars
[0u];
1162 bool areLongOptionsEnabled
= AreLongOptionsEnabled();
1163 size_t n
, count
= m_data
->m_options
.GetCount();
1164 for ( n
= 0; n
< count
; n
++ )
1166 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1167 wxString option
, negator
;
1169 if ( opt
.kind
!= wxCMD_LINE_USAGE_TEXT
)
1172 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1177 if ( opt
.flags
& wxCMD_LINE_SWITCH_NEGATABLE
)
1178 negator
= wxT("[-]");
1180 if ( !opt
.shortName
.empty() )
1182 usage
<< chSwitch
<< opt
.shortName
<< negator
;
1184 else if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1186 usage
<< wxT("--") << opt
.longName
<< negator
;
1190 if (!opt
.longName
.empty())
1192 wxFAIL_MSG( wxT("option with only a long name while long ")
1193 wxT("options are disabled") );
1197 wxFAIL_MSG( wxT("option without neither short nor long name") );
1201 if ( !opt
.shortName
.empty() )
1203 option
<< wxT(" ") << chSwitch
<< opt
.shortName
;
1206 if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1208 option
<< (option
.empty() ? wxT(" ") : wxT(", "))
1209 << wxT("--") << opt
.longName
;
1212 if ( opt
.kind
!= wxCMD_LINE_SWITCH
)
1215 val
<< wxT('<') << GetTypeName(opt
.type
) << wxT('>');
1216 usage
<< wxT(' ') << val
;
1217 option
<< (!opt
.longName
? wxT(':') : wxT('=')) << val
;
1220 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1226 namesOptions
.push_back(option
);
1227 descOptions
.push_back(opt
.description
);
1230 count
= m_data
->m_paramDesc
.GetCount();
1231 for ( n
= 0; n
< count
; n
++ )
1233 wxCmdLineParam
& param
= m_data
->m_paramDesc
[n
];
1236 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1241 usage
<< param
.description
;
1243 if ( param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
)
1245 usage
<< wxT("...");
1248 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1256 // set to number of our own options, not counting the standard ones
1257 count
= namesOptions
.size();
1259 // get option names & descriptions for standard options, if any:
1260 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
1263 stdDesc
= traits
->GetStandardCmdLineOptions(namesOptions
, descOptions
);
1265 // now construct the detailed help message
1266 size_t len
, lenMax
= 0;
1267 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1269 len
= namesOptions
[n
].length();
1274 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1277 usage
<< wxT('\n') << stdDesc
;
1279 len
= namesOptions
[n
].length();
1280 // desc contains text if name is empty
1283 usage
<< descOptions
[n
] << wxT('\n');
1287 usage
<< namesOptions
[n
]
1288 << wxString(wxT(' '), lenMax
- len
) << wxT('\t')
1297 // ----------------------------------------------------------------------------
1298 // private functions
1299 // ----------------------------------------------------------------------------
1301 static wxString
GetTypeName(wxCmdLineParamType type
)
1307 wxFAIL_MSG( wxT("unknown option type") );
1308 // still fall through
1310 case wxCMD_LINE_VAL_STRING
:
1314 case wxCMD_LINE_VAL_NUMBER
:
1318 case wxCMD_LINE_VAL_DOUBLE
:
1322 case wxCMD_LINE_VAL_DATE
:
1331 Returns a string which is equal to the string pointed to by p, but up to the
1332 point where p contains an character that's not allowed.
1333 Allowable characters are letters and numbers, and characters pointed to by
1334 the parameter allowedChars.
1336 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1337 this function returns "abcde-".
1339 static wxString
GetOptionName(wxString::const_iterator p
,
1340 wxString::const_iterator end
,
1341 const wxChar
*allowedChars
)
1345 while ( p
!= end
&& (wxIsalnum(*p
) || wxStrchr(allowedChars
, *p
)) )
1353 // Besides alphanumeric characters, short and long options can
1354 // have other characters.
1356 // A short option additionally can have these
1357 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1359 // A long option can have the same characters as a short option and a '-'.
1360 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1361 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1363 static wxString
GetShortOptionName(wxString::const_iterator p
,
1364 wxString::const_iterator end
)
1366 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION
);
1369 static wxString
GetLongOptionName(wxString::const_iterator p
,
1370 wxString::const_iterator end
)
1372 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION
);
1375 #endif // wxUSE_CMDLINE_PARSER
1377 // ----------------------------------------------------------------------------
1379 // ----------------------------------------------------------------------------
1382 This function is mainly used under Windows (as under Unix we always get the
1383 command line arguments as argc/argv anyhow) and so it tries to follow
1384 Windows conventions for the command line handling, not Unix ones. For
1385 instance, backslash is not special except when it precedes double quote when
1388 TODO: Rewrite this to follow the even more complicated rule used by Windows
1389 CommandLineToArgv():
1391 * A string of backslashes not followed by a quotation mark has no special
1393 * An even number of backslashes followed by a quotation mark is treated as
1394 pairs of protected backslashes, followed by a word terminator.
1395 * An odd number of backslashes followed by a quotation mark is treated as
1396 pairs of protected backslashes, followed by a protected quotation mark.
1398 See http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
1400 It could also be useful to provide a converse function which is also
1403 http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
1408 wxCmdLineParser::ConvertStringToArgs(const wxString
& cmdline
,
1409 wxCmdLineSplitType type
)
1416 const wxString::const_iterator end
= cmdline
.end();
1417 wxString::const_iterator p
= cmdline
.begin();
1422 while ( p
!= end
&& (*p
== ' ' || *p
== '\t') )
1429 // parse this parameter
1430 bool lastBS
= false,
1431 isInsideQuotes
= false;
1432 wxChar chDelim
= '\0';
1433 for ( arg
.clear(); p
!= end
; ++p
)
1435 const wxChar ch
= *p
;
1437 if ( type
== wxCMD_LINE_SPLIT_DOS
)
1443 isInsideQuotes
= !isInsideQuotes
;
1445 // don't put quote in arg
1448 //else: quote has no special meaning but the backslash
1449 // still remains -- makes no sense but this is what
1452 // note that backslash does *not* quote the space, only quotes do
1453 else if ( !isInsideQuotes
&& (ch
== ' ' || ch
== '\t') )
1455 ++p
; // skip this space anyhow
1459 lastBS
= !lastBS
&& ch
== '\\';
1461 else // type == wxCMD_LINE_SPLIT_UNIX
1465 if ( isInsideQuotes
)
1467 if ( ch
== chDelim
)
1469 isInsideQuotes
= false;
1471 continue; // don't use the quote itself
1474 else // not in quotes and not escaped
1476 if ( ch
== '\'' || ch
== '"' )
1478 isInsideQuotes
= true;
1481 continue; // don't use the quote itself
1484 if ( ch
== ' ' || ch
== '\t' )
1486 ++p
; // skip this space anyhow
1491 lastBS
= ch
== '\\';
1495 else // escaped by backslash, just use as is
1504 args
.push_back(arg
);