1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/cmdline.cpp
3 // Purpose: wxCmdLineParser implementation
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2000 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
28 #include "wx/dynarray.h"
29 #include "wx/string.h"
35 #include "wx/cmdline.h"
37 #if wxUSE_CMDLINE_PARSER
40 #include <locale.h> // for LC_ALL
42 #include "wx/datetime.h"
43 #include "wx/msgout.h"
44 #include "wx/filename.h"
45 #include "wx/apptrait.h"
46 #include "wx/scopeguard.h"
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 static wxString
GetTypeName(wxCmdLineParamType type
);
54 static wxString
GetOptionName(wxString::const_iterator p
,
55 wxString::const_iterator end
,
56 const wxChar
*allowedChars
);
58 static wxString
GetShortOptionName(wxString::const_iterator p
,
59 wxString::const_iterator end
);
61 static wxString
GetLongOptionName(wxString::const_iterator p
,
62 wxString::const_iterator end
);
64 // ----------------------------------------------------------------------------
66 // ----------------------------------------------------------------------------
68 // an internal representation of an option
69 struct wxCmdLineOption
71 wxCmdLineOption(wxCmdLineEntryType k
,
75 wxCmdLineParamType typ
,
78 // wxCMD_LINE_USAGE_TEXT uses only description, shortName and longName is empty
79 if ( k
!= wxCMD_LINE_USAGE_TEXT
)
83 !shrt
.empty() || !lng
.empty(),
84 wxT("option should have at least one name")
89 GetShortOptionName(shrt
.begin(), shrt
.end()).Len() == shrt
.Len(),
90 wxT("Short option contains invalid characters")
95 GetLongOptionName(lng
.begin(), lng
.end()).Len() == lng
.Len(),
96 wxT("Long option contains invalid characters")
112 // can't use union easily here, so just store all possible data fields, we
113 // don't waste much (might still use union later if the number of supported
114 // types increases, so always use the accessor functions and don't access
115 // the fields directly!)
117 void Check(wxCmdLineParamType
WXUNUSED_UNLESS_DEBUG(typ
)) const
119 wxASSERT_MSG( type
== typ
, wxT("type mismatch in wxCmdLineOption") );
122 double GetDoubleVal() const
123 { Check(wxCMD_LINE_VAL_DOUBLE
); return m_doubleVal
; }
124 long GetLongVal() const
125 { Check(wxCMD_LINE_VAL_NUMBER
); return m_longVal
; }
126 const wxString
& GetStrVal() const
127 { Check(wxCMD_LINE_VAL_STRING
); return m_strVal
; }
129 const wxDateTime
& GetDateVal() const
130 { Check(wxCMD_LINE_VAL_DATE
); return m_dateVal
; }
131 #endif // wxUSE_DATETIME
133 void SetDoubleVal(double val
)
134 { Check(wxCMD_LINE_VAL_DOUBLE
); m_doubleVal
= val
; m_hasVal
= true; }
135 void SetLongVal(long val
)
136 { Check(wxCMD_LINE_VAL_NUMBER
); m_longVal
= val
; m_hasVal
= true; }
137 void SetStrVal(const wxString
& val
)
138 { Check(wxCMD_LINE_VAL_STRING
); m_strVal
= val
; m_hasVal
= true; }
140 void SetDateVal(const wxDateTime
& val
)
141 { Check(wxCMD_LINE_VAL_DATE
); m_dateVal
= val
; m_hasVal
= true; }
142 #endif // wxUSE_DATETIME
144 void SetHasValue() { m_hasVal
= true; }
145 bool HasValue() const { return m_hasVal
; }
147 void SetNegated() { m_isNegated
= true; }
148 bool IsNegated() const { return m_isNegated
; }
150 // Reset to the initial state, called before parsing another command line.
158 wxCmdLineEntryType kind
;
162 wxCmdLineParamType type
;
173 wxDateTime m_dateVal
;
174 #endif // wxUSE_DATETIME
177 struct wxCmdLineParam
179 wxCmdLineParam(const wxString
& desc
,
180 wxCmdLineParamType typ
,
188 wxString description
;
189 wxCmdLineParamType type
;
193 WX_DECLARE_OBJARRAY(wxCmdLineOption
, wxArrayOptions
);
194 WX_DECLARE_OBJARRAY(wxCmdLineParam
, wxArrayParams
);
196 #include "wx/arrimpl.cpp"
198 WX_DEFINE_OBJARRAY(wxArrayOptions
)
199 WX_DEFINE_OBJARRAY(wxArrayParams
)
201 // the parser internal state
202 struct wxCmdLineParserData
205 wxString m_switchChars
; // characters which may start an option
206 bool m_enableLongOptions
; // true if long options are enabled
207 wxString m_logo
; // some extra text to show in Usage()
210 wxArrayString m_arguments
; // == argv, argc == m_arguments.GetCount()
211 wxArrayOptions m_options
; // all possible options and switches
212 wxArrayParams m_paramDesc
; // description of all possible params
213 wxArrayString m_parameters
; // all params found
216 wxCmdLineParserData();
217 void SetArguments(int argc
, char **argv
);
219 void SetArguments(int argc
, wxChar
**argv
);
220 void SetArguments(int argc
, const wxCmdLineArgsArray
& argv
);
221 #endif // wxUSE_UNICODE
222 void SetArguments(const wxString
& cmdline
);
224 int FindOption(const wxString
& name
);
225 int FindOptionByLongName(const wxString
& name
);
228 // ============================================================================
230 // ============================================================================
232 // ----------------------------------------------------------------------------
233 // wxCmdLineParserData
234 // ----------------------------------------------------------------------------
236 wxCmdLineParserData::wxCmdLineParserData()
238 m_enableLongOptions
= true;
240 m_switchChars
= wxT("-");
242 m_switchChars
= wxT("/-");
249 // Small helper function setting locale for all categories.
251 // We define it because wxSetlocale() can't be easily used with wxScopeGuard as
252 // it has several overloads -- while this one can.
253 inline char *SetAllLocaleFacets(const char *loc
)
255 return wxSetlocale(LC_ALL
, loc
);
258 } // private namespace
260 void wxCmdLineParserData::SetArguments(int argc
, char **argv
)
264 // Command-line arguments are supposed to be in the user locale encoding
265 // (what else?) but wxLocale probably wasn't initialized yet as we're
266 // called early during the program startup and so our locale might not have
267 // been set from the environment yet. To work around this problem we
268 // temporarily change the locale here. The only drawback is that changing
269 // the locale is thread-unsafe but precisely because we're called so early
270 // it's hopefully safe to assume that no other threads had been created yet.
271 char * const locOld
= SetAllLocaleFacets("");
272 wxON_BLOCK_EXIT1( SetAllLocaleFacets
, locOld
);
274 for ( int n
= 0; n
< argc
; n
++ )
276 // try to interpret the string as being in the current locale
277 wxString
arg(argv
[n
]);
279 // but just in case we guessed wrongly and the conversion failed, do
280 // try to salvage at least something
281 if ( arg
.empty() && argv
[n
][0] != '\0' )
282 arg
= wxString(argv
[n
], wxConvISO8859_1
);
284 m_arguments
.push_back(arg
);
290 void wxCmdLineParserData::SetArguments(int argc
, wxChar
**argv
)
294 for ( int n
= 0; n
< argc
; n
++ )
296 m_arguments
.push_back(argv
[n
]);
300 void wxCmdLineParserData::SetArguments(int WXUNUSED(argc
),
301 const wxCmdLineArgsArray
& argv
)
303 m_arguments
= argv
.GetArguments();
306 #endif // wxUSE_UNICODE
308 void wxCmdLineParserData::SetArguments(const wxString
& cmdLine
)
312 if(wxTheApp
&& wxTheApp
->argc
> 0)
313 m_arguments
.push_back(wxTheApp
->argv
[0]);
315 m_arguments
.push_back(wxEmptyString
);
317 wxArrayString args
= wxCmdLineParser::ConvertStringToArgs(cmdLine
);
319 WX_APPEND_ARRAY(m_arguments
, args
);
322 int wxCmdLineParserData::FindOption(const wxString
& name
)
326 size_t count
= m_options
.GetCount();
327 for ( size_t n
= 0; n
< count
; n
++ )
329 if ( m_options
[n
].shortName
== name
)
340 int wxCmdLineParserData::FindOptionByLongName(const wxString
& name
)
342 size_t count
= m_options
.GetCount();
343 for ( size_t n
= 0; n
< count
; n
++ )
345 if ( m_options
[n
].longName
== name
)
355 // ----------------------------------------------------------------------------
356 // construction and destruction
357 // ----------------------------------------------------------------------------
359 void wxCmdLineParser::Init()
361 m_data
= new wxCmdLineParserData
;
364 void wxCmdLineParser::SetCmdLine(int argc
, char **argv
)
366 m_data
->SetArguments(argc
, argv
);
371 void wxCmdLineParser::SetCmdLine(int argc
, wxChar
**argv
)
373 m_data
->SetArguments(argc
, argv
);
376 void wxCmdLineParser::SetCmdLine(int argc
, const wxCmdLineArgsArray
& argv
)
378 m_data
->SetArguments(argc
, argv
);
381 #endif // wxUSE_UNICODE
383 void wxCmdLineParser::SetCmdLine(const wxString
& cmdline
)
385 m_data
->SetArguments(cmdline
);
388 wxCmdLineParser::~wxCmdLineParser()
393 // ----------------------------------------------------------------------------
395 // ----------------------------------------------------------------------------
397 void wxCmdLineParser::SetSwitchChars(const wxString
& switchChars
)
399 m_data
->m_switchChars
= switchChars
;
402 void wxCmdLineParser::EnableLongOptions(bool enable
)
404 m_data
->m_enableLongOptions
= enable
;
407 bool wxCmdLineParser::AreLongOptionsEnabled() const
409 return m_data
->m_enableLongOptions
;
412 void wxCmdLineParser::SetLogo(const wxString
& logo
)
414 m_data
->m_logo
= logo
;
417 // ----------------------------------------------------------------------------
418 // command line construction
419 // ----------------------------------------------------------------------------
421 void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc
*desc
)
425 switch ( desc
->kind
)
427 case wxCMD_LINE_SWITCH
:
428 AddSwitch(desc
->shortName
, desc
->longName
,
429 wxGetTranslation(desc
->description
),
433 case wxCMD_LINE_OPTION
:
434 AddOption(desc
->shortName
, desc
->longName
,
435 wxGetTranslation(desc
->description
),
436 desc
->type
, desc
->flags
);
439 case wxCMD_LINE_PARAM
:
440 AddParam(wxGetTranslation(desc
->description
),
441 desc
->type
, desc
->flags
);
444 case wxCMD_LINE_USAGE_TEXT
:
445 AddUsageText(wxGetTranslation(desc
->description
));
449 wxFAIL_MSG( wxT("unknown command line entry type") );
450 // still fall through
452 case wxCMD_LINE_NONE
:
458 void wxCmdLineParser::AddSwitch(const wxString
& shortName
,
459 const wxString
& longName
,
460 const wxString
& desc
,
463 wxASSERT_MSG( m_data
->FindOption(shortName
) == wxNOT_FOUND
,
464 wxT("duplicate switch") );
466 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_SWITCH
,
467 shortName
, longName
, desc
,
468 wxCMD_LINE_VAL_NONE
, flags
);
470 m_data
->m_options
.Add(option
);
473 void wxCmdLineParser::AddOption(const wxString
& shortName
,
474 const wxString
& longName
,
475 const wxString
& desc
,
476 wxCmdLineParamType type
,
479 wxASSERT_MSG( m_data
->FindOption(shortName
) == wxNOT_FOUND
,
480 wxT("duplicate option") );
482 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_OPTION
,
483 shortName
, longName
, desc
,
486 m_data
->m_options
.Add(option
);
489 void wxCmdLineParser::AddParam(const wxString
& desc
,
490 wxCmdLineParamType type
,
493 // do some consistency checks: a required parameter can't follow an
494 // optional one and nothing should follow a parameter with MULTIPLE flag
496 if ( !m_data
->m_paramDesc
.IsEmpty() )
498 wxCmdLineParam
& param
= m_data
->m_paramDesc
.Last();
500 wxASSERT_MSG( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
),
501 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
503 if ( !(flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
505 wxASSERT_MSG( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
),
506 wxT("a required parameter can't follow an optional one") );
509 #endif // wxDEBUG_LEVEL
511 wxCmdLineParam
*param
= new wxCmdLineParam(desc
, type
, flags
);
513 m_data
->m_paramDesc
.Add(param
);
516 void wxCmdLineParser::AddUsageText(const wxString
& text
)
518 wxASSERT_MSG( !text
.empty(), wxT("text can't be empty") );
520 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_USAGE_TEXT
,
521 wxEmptyString
, wxEmptyString
,
522 text
, wxCMD_LINE_VAL_NONE
, 0);
524 m_data
->m_options
.Add(option
);
527 // ----------------------------------------------------------------------------
528 // access to parse command line
529 // ----------------------------------------------------------------------------
531 bool wxCmdLineParser::Found(const wxString
& name
) const
533 return FoundSwitch(name
) != wxCMD_SWITCH_NOT_FOUND
;
536 wxCmdLineSwitchState
wxCmdLineParser::FoundSwitch(const wxString
& name
) const
538 int i
= m_data
->FindOption(name
);
539 if ( i
== wxNOT_FOUND
)
540 i
= m_data
->FindOptionByLongName(name
);
542 wxCHECK_MSG( i
!= wxNOT_FOUND
, wxCMD_SWITCH_NOT_FOUND
, wxT("unknown switch") );
544 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
545 if ( !opt
.HasValue() )
546 return wxCMD_SWITCH_NOT_FOUND
;
548 return opt
.IsNegated() ? wxCMD_SWITCH_OFF
: wxCMD_SWITCH_ON
;
551 bool wxCmdLineParser::Found(const wxString
& name
, wxString
*value
) const
553 int i
= m_data
->FindOption(name
);
554 if ( i
== wxNOT_FOUND
)
555 i
= m_data
->FindOptionByLongName(name
);
557 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
559 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
560 if ( !opt
.HasValue() )
563 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
565 *value
= opt
.GetStrVal();
570 bool wxCmdLineParser::Found(const wxString
& name
, long *value
) const
572 int i
= m_data
->FindOption(name
);
573 if ( i
== wxNOT_FOUND
)
574 i
= m_data
->FindOptionByLongName(name
);
576 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
578 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
579 if ( !opt
.HasValue() )
582 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
584 *value
= opt
.GetLongVal();
589 bool wxCmdLineParser::Found(const wxString
& name
, double *value
) const
591 int i
= m_data
->FindOption(name
);
592 if ( i
== wxNOT_FOUND
)
593 i
= m_data
->FindOptionByLongName(name
);
595 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
597 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
598 if ( !opt
.HasValue() )
601 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
603 *value
= opt
.GetDoubleVal();
609 bool wxCmdLineParser::Found(const wxString
& name
, wxDateTime
*value
) const
611 int i
= m_data
->FindOption(name
);
612 if ( i
== wxNOT_FOUND
)
613 i
= m_data
->FindOptionByLongName(name
);
615 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
617 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
618 if ( !opt
.HasValue() )
621 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
623 *value
= opt
.GetDateVal();
627 #endif // wxUSE_DATETIME
629 size_t wxCmdLineParser::GetParamCount() const
631 return m_data
->m_parameters
.size();
634 wxString
wxCmdLineParser::GetParam(size_t n
) const
636 wxCHECK_MSG( n
< GetParamCount(), wxEmptyString
, wxT("invalid param index") );
638 return m_data
->m_parameters
[n
];
641 // Resets switches and options
642 void wxCmdLineParser::Reset()
644 for ( size_t i
= 0; i
< m_data
->m_options
.GetCount(); i
++ )
646 m_data
->m_options
[i
].Reset();
651 // ----------------------------------------------------------------------------
652 // the real work is done here
653 // ----------------------------------------------------------------------------
655 int wxCmdLineParser::Parse(bool showUsage
)
657 bool maybeOption
= true; // can the following arg be an option?
658 bool ok
= true; // true until an error is detected
659 bool helpRequested
= false; // true if "-h" was given
660 bool hadRepeatableParam
= false; // true if found param with MULTIPLE flag
662 size_t currentParam
= 0; // the index in m_paramDesc
664 size_t countParam
= m_data
->m_paramDesc
.GetCount();
671 size_t count
= m_data
->m_arguments
.size();
672 for ( size_t n
= 1; ok
&& (n
< count
); n
++ ) // 0 is program name
674 arg
= m_data
->m_arguments
[n
];
676 // special case: "--" should be discarded and all following arguments
677 // should be considered as parameters, even if they start with '-' and
678 // not like options (this is POSIX-like)
679 if ( arg
== wxT("--") )
686 // empty argument or just '-' is not an option but a parameter
687 if ( maybeOption
&& arg
.length() > 1 &&
688 // FIXME-UTF8: use wc_str() after removing ANSI build
689 wxStrchr(m_data
->m_switchChars
.c_str(), arg
[0u]) )
693 int optInd
= wxNOT_FOUND
; // init to suppress warnings
695 // an option or a switch: find whether it's a long or a short one
696 if ( arg
.length() >= 3 && arg
[0u] == wxT('-') && arg
[1u] == wxT('-') )
702 wxString::const_iterator p
= arg
.begin() + 2;
704 bool longOptionsEnabled
= AreLongOptionsEnabled();
706 name
= GetLongOptionName(p
, arg
.end());
708 if (longOptionsEnabled
)
712 optInd
= m_data
->FindOptionByLongName(name
);
713 if ( optInd
== wxNOT_FOUND
)
715 // Check if this could be a negatable long option.
716 if ( name
.Last() == '-' )
720 optInd
= m_data
->FindOptionByLongName(name
);
721 if ( optInd
!= wxNOT_FOUND
)
723 if ( !(m_data
->m_options
[optInd
].flags
&
724 wxCMD_LINE_SWITCH_NEGATABLE
) )
728 _("Option '%s' can't be negated"),
731 optInd
= wxNOT_FOUND
;
736 if ( optInd
== wxNOT_FOUND
)
738 if ( errorOpt
.empty() )
742 _("Unknown long option '%s'"),
747 errorMsg
<< errorOpt
<< wxT('\n');
753 optInd
= wxNOT_FOUND
; // Sanity check
755 // Print the argument including leading "--"
756 name
.Prepend( wxT("--") );
757 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
762 else // not a long option
766 // a short one: as they can be cumulated, we try to find the
767 // longest substring which is a valid option
768 wxString::const_iterator p
= arg
.begin() + 1;
770 name
= GetShortOptionName(p
, arg
.end());
772 size_t len
= name
.length();
777 // we couldn't find a valid option name in the
778 // beginning of this string
779 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
786 optInd
= m_data
->FindOption(name
.Left(len
));
788 // will try with one character less the next time
792 while ( optInd
== wxNOT_FOUND
);
794 len
++; // compensates extra len-- above
795 if ( (optInd
!= wxNOT_FOUND
) && (len
!= name
.length()) )
797 // first of all, the option name is only part of this
799 name
= name
.Left(len
);
801 // our option is only part of this argument, there is
802 // something else in it - it is either the value of this
803 // option or other switches if it is a switch
804 if ( m_data
->m_options
[(size_t)optInd
].kind
805 == wxCMD_LINE_SWITCH
)
807 // if the switch is negatable and it is just followed
808 // by '-' the '-' is considered to be part of this
810 if ( (m_data
->m_options
[(size_t)optInd
].flags
&
811 wxCMD_LINE_SWITCH_NEGATABLE
) &&
815 // pretend that all the rest of the argument is the
816 // next argument, in fact
817 wxString arg2
= arg
[0u];
818 arg2
+= arg
.Mid(len
+ 1); // +1 for leading '-'
820 m_data
->m_arguments
.insert
821 (m_data
->m_arguments
.begin() + n
+ 1, arg2
);
824 // only leave the part which wasn't extracted into the
825 // next argument in this one
826 arg
= arg
.Left(len
+ 1);
828 //else: it's our value, we'll deal with it below
832 if ( optInd
== wxNOT_FOUND
)
836 continue; // will break, in fact
839 // look at what follows:
841 // +1 for leading '-'
842 wxString::const_iterator p
= arg
.begin() + 1 + name
.length();
843 wxString::const_iterator end
= arg
.end();
846 ++p
; // for another leading '-'
848 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)optInd
];
849 if ( opt
.kind
== wxCMD_LINE_SWITCH
)
851 // we must check that there is no value following the switch
852 bool negated
= (opt
.flags
& wxCMD_LINE_SWITCH_NEGATABLE
) &&
853 p
!= arg
.end() && *p
== '-';
855 if ( !negated
&& p
!= arg
.end() )
857 errorMsg
<< wxString::Format(_("Unexpected characters following option '%s'."), name
.c_str())
861 else // no value, as expected
863 // nothing more to do
868 if ( opt
.flags
& wxCMD_LINE_OPTION_HELP
)
870 helpRequested
= true;
872 // it's not an error, but we still stop here
877 else // it's an option. not a switch
879 switch ( p
== end
? '\0' : (*p
).GetValue() )
888 // the value is in the next argument
891 // ... but there is none
892 errorMsg
<< wxString::Format(_("Option '%s' requires a value."),
900 // ... take it from there
901 p
= m_data
->m_arguments
[n
].begin();
902 end
= m_data
->m_arguments
[n
].end();
907 // the value is right here: this may be legal or
908 // not depending on the option style
909 if ( opt
.flags
& wxCMD_LINE_NEEDS_SEPARATOR
)
911 errorMsg
<< wxString::Format(_("Separator expected after the option '%s'."),
921 wxString
value(p
, end
);
925 wxFAIL_MSG( wxT("unknown option type") );
926 // still fall through
928 case wxCMD_LINE_VAL_STRING
:
929 opt
.SetStrVal(value
);
932 case wxCMD_LINE_VAL_NUMBER
:
935 if ( value
.ToLong(&val
) )
941 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
942 value
.c_str(), name
.c_str())
950 case wxCMD_LINE_VAL_DOUBLE
:
953 if ( value
.ToDouble(&val
) )
955 opt
.SetDoubleVal(val
);
959 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
960 value
.c_str(), name
.c_str())
969 case wxCMD_LINE_VAL_DATE
:
972 wxString::const_iterator end
;
973 if ( !dt
.ParseDate(value
, &end
) || end
!= value
.end() )
975 errorMsg
<< wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
976 name
.c_str(), value
.c_str())
987 #endif // wxUSE_DATETIME
992 else // not an option, must be a parameter
994 if ( currentParam
< countParam
)
996 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
998 // TODO check the param type
1000 m_data
->m_parameters
.push_back(arg
);
1002 if ( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) )
1008 wxASSERT_MSG( currentParam
== countParam
- 1,
1009 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
1011 // remember that we did have this last repeatable parameter
1012 hadRepeatableParam
= true;
1017 errorMsg
<< wxString::Format(_("Unexpected parameter '%s'"), arg
.c_str())
1025 // verify that all mandatory options were given
1028 size_t countOpt
= m_data
->m_options
.GetCount();
1029 for ( size_t n
= 0; ok
&& (n
< countOpt
); n
++ )
1031 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1032 if ( (opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) && !opt
.HasValue() )
1035 if ( !opt
.longName
)
1037 optName
= opt
.shortName
;
1041 if ( AreLongOptionsEnabled() )
1043 optName
.Printf( _("%s (or %s)"),
1044 opt
.shortName
.c_str(),
1045 opt
.longName
.c_str() );
1049 optName
.Printf( wxT("%s"),
1050 opt
.shortName
.c_str() );
1054 errorMsg
<< wxString::Format(_("The value for the option '%s' must be specified."),
1062 for ( ; ok
&& (currentParam
< countParam
); currentParam
++ )
1064 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
1065 if ( (currentParam
== countParam
- 1) &&
1066 (param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) &&
1067 hadRepeatableParam
)
1069 // special case: currentParam wasn't incremented, but we did
1070 // have it, so don't give error
1074 if ( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
1076 errorMsg
<< wxString::Format(_("The required parameter '%s' was not specified."),
1077 param
.description
.c_str())
1085 // if there was an error during parsing the command line, show this error
1086 // and also the usage message if it had been requested
1087 if ( !ok
&& (!errorMsg
.empty() || (helpRequested
&& showUsage
)) )
1089 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1094 usage
= GetUsageString();
1096 msgOut
->Printf( wxT("%s%s"), usage
.c_str(), errorMsg
.c_str() );
1100 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1104 return ok
? 0 : helpRequested
? -1 : 1;
1107 // ----------------------------------------------------------------------------
1108 // give the usage message
1109 // ----------------------------------------------------------------------------
1111 void wxCmdLineParser::Usage() const
1113 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1116 msgOut
->Printf( wxT("%s"), GetUsageString().c_str() );
1120 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1124 wxString
wxCmdLineParser::GetUsageString() const
1127 if ( m_data
->m_arguments
.empty() )
1130 appname
= wxTheApp
->GetAppName();
1134 appname
= wxFileName(m_data
->m_arguments
[0]).GetName();
1137 // we construct the brief cmd line desc on the fly, but not the detailed
1138 // help message below because we want to align the options descriptions
1139 // and for this we must first know the longest one of them
1141 wxArrayString namesOptions
, descOptions
;
1143 if ( !m_data
->m_logo
.empty() )
1145 usage
<< m_data
->m_logo
<< wxT('\n');
1148 usage
<< wxString::Format(_("Usage: %s"), appname
.c_str());
1150 // the switch char is usually '-' but this can be changed with
1151 // SetSwitchChars() and then the first one of possible chars is used
1152 wxChar chSwitch
= !m_data
->m_switchChars
? wxT('-')
1153 : m_data
->m_switchChars
[0u];
1155 bool areLongOptionsEnabled
= AreLongOptionsEnabled();
1156 size_t n
, count
= m_data
->m_options
.GetCount();
1157 for ( n
= 0; n
< count
; n
++ )
1159 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1160 wxString option
, negator
;
1162 if ( opt
.kind
!= wxCMD_LINE_USAGE_TEXT
)
1165 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1170 if ( opt
.flags
& wxCMD_LINE_SWITCH_NEGATABLE
)
1171 negator
= wxT("[-]");
1173 if ( !opt
.shortName
.empty() )
1175 usage
<< chSwitch
<< opt
.shortName
<< negator
;
1177 else if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1179 usage
<< wxT("--") << opt
.longName
<< negator
;
1183 if (!opt
.longName
.empty())
1185 wxFAIL_MSG( wxT("option with only a long name while long ")
1186 wxT("options are disabled") );
1190 wxFAIL_MSG( wxT("option without neither short nor long name") );
1194 if ( !opt
.shortName
.empty() )
1196 option
<< wxT(" ") << chSwitch
<< opt
.shortName
;
1199 if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1201 option
<< (option
.empty() ? wxT(" ") : wxT(", "))
1202 << wxT("--") << opt
.longName
;
1205 if ( opt
.kind
!= wxCMD_LINE_SWITCH
)
1208 val
<< wxT('<') << GetTypeName(opt
.type
) << wxT('>');
1209 usage
<< wxT(' ') << val
;
1210 option
<< (!opt
.longName
? wxT(':') : wxT('=')) << val
;
1213 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1219 namesOptions
.push_back(option
);
1220 descOptions
.push_back(opt
.description
);
1223 count
= m_data
->m_paramDesc
.GetCount();
1224 for ( n
= 0; n
< count
; n
++ )
1226 wxCmdLineParam
& param
= m_data
->m_paramDesc
[n
];
1229 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1234 usage
<< param
.description
;
1236 if ( param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
)
1238 usage
<< wxT("...");
1241 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1249 // set to number of our own options, not counting the standard ones
1250 count
= namesOptions
.size();
1252 // get option names & descriptions for standard options, if any:
1253 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
1256 stdDesc
= traits
->GetStandardCmdLineOptions(namesOptions
, descOptions
);
1258 // now construct the detailed help message
1259 size_t len
, lenMax
= 0;
1260 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1262 len
= namesOptions
[n
].length();
1267 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1270 usage
<< wxT('\n') << stdDesc
;
1272 len
= namesOptions
[n
].length();
1273 // desc contains text if name is empty
1276 usage
<< descOptions
[n
] << wxT('\n');
1280 usage
<< namesOptions
[n
]
1281 << wxString(wxT(' '), lenMax
- len
) << wxT('\t')
1290 // ----------------------------------------------------------------------------
1291 // private functions
1292 // ----------------------------------------------------------------------------
1294 static wxString
GetTypeName(wxCmdLineParamType type
)
1300 wxFAIL_MSG( wxT("unknown option type") );
1301 // still fall through
1303 case wxCMD_LINE_VAL_STRING
:
1307 case wxCMD_LINE_VAL_NUMBER
:
1311 case wxCMD_LINE_VAL_DOUBLE
:
1315 case wxCMD_LINE_VAL_DATE
:
1324 Returns a string which is equal to the string pointed to by p, but up to the
1325 point where p contains an character that's not allowed.
1326 Allowable characters are letters and numbers, and characters pointed to by
1327 the parameter allowedChars.
1329 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1330 this function returns "abcde-".
1332 static wxString
GetOptionName(wxString::const_iterator p
,
1333 wxString::const_iterator end
,
1334 const wxChar
*allowedChars
)
1338 while ( p
!= end
&& (wxIsalnum(*p
) || wxStrchr(allowedChars
, *p
)) )
1346 // Besides alphanumeric characters, short and long options can
1347 // have other characters.
1349 // A short option additionally can have these
1350 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1352 // A long option can have the same characters as a short option and a '-'.
1353 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1354 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1356 static wxString
GetShortOptionName(wxString::const_iterator p
,
1357 wxString::const_iterator end
)
1359 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION
);
1362 static wxString
GetLongOptionName(wxString::const_iterator p
,
1363 wxString::const_iterator end
)
1365 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION
);
1368 #endif // wxUSE_CMDLINE_PARSER
1370 // ----------------------------------------------------------------------------
1372 // ----------------------------------------------------------------------------
1375 This function is mainly used under Windows (as under Unix we always get the
1376 command line arguments as argc/argv anyhow) and so it tries to follow
1377 Windows conventions for the command line handling, not Unix ones. For
1378 instance, backslash is not special except when it precedes double quote when
1384 wxCmdLineParser::ConvertStringToArgs(const wxString
& cmdline
,
1385 wxCmdLineSplitType type
)
1392 const wxString::const_iterator end
= cmdline
.end();
1393 wxString::const_iterator p
= cmdline
.begin();
1398 while ( p
!= end
&& (*p
== ' ' || *p
== '\t') )
1405 // parse this parameter
1406 bool lastBS
= false,
1407 isInsideQuotes
= false;
1408 wxChar chDelim
= '\0';
1409 for ( arg
.clear(); p
!= end
; ++p
)
1411 const wxChar ch
= *p
;
1413 if ( type
== wxCMD_LINE_SPLIT_DOS
)
1419 isInsideQuotes
= !isInsideQuotes
;
1421 // don't put quote in arg
1424 //else: quote has no special meaning but the backslash
1425 // still remains -- makes no sense but this is what
1428 // note that backslash does *not* quote the space, only quotes do
1429 else if ( !isInsideQuotes
&& (ch
== ' ' || ch
== '\t') )
1431 ++p
; // skip this space anyhow
1435 lastBS
= !lastBS
&& ch
== '\\';
1437 else // type == wxCMD_LINE_SPLIT_UNIX
1441 if ( isInsideQuotes
)
1443 if ( ch
== chDelim
)
1445 isInsideQuotes
= false;
1447 continue; // don't use the quote itself
1450 else // not in quotes and not escaped
1452 if ( ch
== '\'' || ch
== '"' )
1454 isInsideQuotes
= true;
1457 continue; // don't use the quote itself
1460 if ( ch
== ' ' || ch
== '\t' )
1462 ++p
; // skip this space anyhow
1467 lastBS
= ch
== '\\';
1471 else // escaped by backslash, just use as is
1480 args
.push_back(arg
);