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
)
710 optInd
= m_data
->FindOptionByLongName(name
);
711 if ( optInd
== wxNOT_FOUND
)
713 errorMsg
<< wxString::Format(_("Unknown long option '%s'"), name
.c_str())
719 optInd
= wxNOT_FOUND
; // Sanity check
721 // Print the argument including leading "--"
722 name
.Prepend( wxT("--") );
723 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
728 else // not a long option
732 // a short one: as they can be cumulated, we try to find the
733 // longest substring which is a valid option
734 wxString::const_iterator p
= arg
.begin() + 1;
736 name
= GetShortOptionName(p
, arg
.end());
738 size_t len
= name
.length();
743 // we couldn't find a valid option name in the
744 // beginning of this string
745 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
752 optInd
= m_data
->FindOption(name
.Left(len
));
754 // will try with one character less the next time
758 while ( optInd
== wxNOT_FOUND
);
760 len
++; // compensates extra len-- above
761 if ( (optInd
!= wxNOT_FOUND
) && (len
!= name
.length()) )
763 // first of all, the option name is only part of this
765 name
= name
.Left(len
);
767 // our option is only part of this argument, there is
768 // something else in it - it is either the value of this
769 // option or other switches if it is a switch
770 if ( m_data
->m_options
[(size_t)optInd
].kind
771 == wxCMD_LINE_SWITCH
)
773 // if the switch is negatable and it is just followed
774 // by '-' the '-' is considered to be part of this
776 if ( (m_data
->m_options
[(size_t)optInd
].flags
&
777 wxCMD_LINE_SWITCH_NEGATABLE
) &&
781 // pretend that all the rest of the argument is the
782 // next argument, in fact
783 wxString arg2
= arg
[0u];
784 arg2
+= arg
.Mid(len
+ 1); // +1 for leading '-'
786 m_data
->m_arguments
.insert
787 (m_data
->m_arguments
.begin() + n
+ 1, arg2
);
790 // only leave the part which wasn't extracted into the
791 // next argument in this one
792 arg
= arg
.Left(len
+ 1);
794 //else: it's our value, we'll deal with it below
798 if ( optInd
== wxNOT_FOUND
)
802 continue; // will break, in fact
805 // look at what follows:
807 // +1 for leading '-'
808 wxString::const_iterator p
= arg
.begin() + 1 + name
.length();
809 wxString::const_iterator end
= arg
.end();
812 ++p
; // for another leading '-'
814 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)optInd
];
815 if ( opt
.kind
== wxCMD_LINE_SWITCH
)
817 // we must check that there is no value following the switch
818 bool negated
= (opt
.flags
& wxCMD_LINE_SWITCH_NEGATABLE
) &&
819 p
!= arg
.end() && *p
== '-';
821 if ( !negated
&& p
!= arg
.end() )
823 errorMsg
<< wxString::Format(_("Unexpected characters following option '%s'."), name
.c_str())
827 else // no value, as expected
829 // nothing more to do
834 if ( opt
.flags
& wxCMD_LINE_OPTION_HELP
)
836 helpRequested
= true;
838 // it's not an error, but we still stop here
843 else // it's an option. not a switch
845 switch ( p
== end
? '\0' : (*p
).GetValue() )
854 // the value is in the next argument
857 // ... but there is none
858 errorMsg
<< wxString::Format(_("Option '%s' requires a value."),
866 // ... take it from there
867 p
= m_data
->m_arguments
[n
].begin();
868 end
= m_data
->m_arguments
[n
].end();
873 // the value is right here: this may be legal or
874 // not depending on the option style
875 if ( opt
.flags
& wxCMD_LINE_NEEDS_SEPARATOR
)
877 errorMsg
<< wxString::Format(_("Separator expected after the option '%s'."),
887 wxString
value(p
, end
);
891 wxFAIL_MSG( wxT("unknown option type") );
892 // still fall through
894 case wxCMD_LINE_VAL_STRING
:
895 opt
.SetStrVal(value
);
898 case wxCMD_LINE_VAL_NUMBER
:
901 if ( value
.ToLong(&val
) )
907 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
908 value
.c_str(), name
.c_str())
916 case wxCMD_LINE_VAL_DOUBLE
:
919 if ( value
.ToDouble(&val
) )
921 opt
.SetDoubleVal(val
);
925 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
926 value
.c_str(), name
.c_str())
935 case wxCMD_LINE_VAL_DATE
:
938 wxString::const_iterator end
;
939 if ( !dt
.ParseDate(value
, &end
) || end
!= value
.end() )
941 errorMsg
<< wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
942 name
.c_str(), value
.c_str())
953 #endif // wxUSE_DATETIME
958 else // not an option, must be a parameter
960 if ( currentParam
< countParam
)
962 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
964 // TODO check the param type
966 m_data
->m_parameters
.push_back(arg
);
968 if ( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) )
974 wxASSERT_MSG( currentParam
== countParam
- 1,
975 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
977 // remember that we did have this last repeatable parameter
978 hadRepeatableParam
= true;
983 errorMsg
<< wxString::Format(_("Unexpected parameter '%s'"), arg
.c_str())
991 // verify that all mandatory options were given
994 size_t countOpt
= m_data
->m_options
.GetCount();
995 for ( size_t n
= 0; ok
&& (n
< countOpt
); n
++ )
997 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
998 if ( (opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) && !opt
.HasValue() )
1001 if ( !opt
.longName
)
1003 optName
= opt
.shortName
;
1007 if ( AreLongOptionsEnabled() )
1009 optName
.Printf( _("%s (or %s)"),
1010 opt
.shortName
.c_str(),
1011 opt
.longName
.c_str() );
1015 optName
.Printf( wxT("%s"),
1016 opt
.shortName
.c_str() );
1020 errorMsg
<< wxString::Format(_("The value for the option '%s' must be specified."),
1028 for ( ; ok
&& (currentParam
< countParam
); currentParam
++ )
1030 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
1031 if ( (currentParam
== countParam
- 1) &&
1032 (param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) &&
1033 hadRepeatableParam
)
1035 // special case: currentParam wasn't incremented, but we did
1036 // have it, so don't give error
1040 if ( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
1042 errorMsg
<< wxString::Format(_("The required parameter '%s' was not specified."),
1043 param
.description
.c_str())
1051 // if there was an error during parsing the command line, show this error
1052 // and also the usage message if it had been requested
1053 if ( !ok
&& (!errorMsg
.empty() || (helpRequested
&& showUsage
)) )
1055 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1060 usage
= GetUsageString();
1062 msgOut
->Printf( wxT("%s%s"), usage
.c_str(), errorMsg
.c_str() );
1066 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1070 return ok
? 0 : helpRequested
? -1 : 1;
1073 // ----------------------------------------------------------------------------
1074 // give the usage message
1075 // ----------------------------------------------------------------------------
1077 void wxCmdLineParser::Usage() const
1079 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1082 msgOut
->Printf( wxT("%s"), GetUsageString().c_str() );
1086 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1090 wxString
wxCmdLineParser::GetUsageString() const
1093 if ( m_data
->m_arguments
.empty() )
1096 appname
= wxTheApp
->GetAppName();
1100 appname
= wxFileName(m_data
->m_arguments
[0]).GetName();
1103 // we construct the brief cmd line desc on the fly, but not the detailed
1104 // help message below because we want to align the options descriptions
1105 // and for this we must first know the longest one of them
1107 wxArrayString namesOptions
, descOptions
;
1109 if ( !m_data
->m_logo
.empty() )
1111 usage
<< m_data
->m_logo
<< wxT('\n');
1114 usage
<< wxString::Format(_("Usage: %s"), appname
.c_str());
1116 // the switch char is usually '-' but this can be changed with
1117 // SetSwitchChars() and then the first one of possible chars is used
1118 wxChar chSwitch
= !m_data
->m_switchChars
? wxT('-')
1119 : m_data
->m_switchChars
[0u];
1121 bool areLongOptionsEnabled
= AreLongOptionsEnabled();
1122 size_t n
, count
= m_data
->m_options
.GetCount();
1123 for ( n
= 0; n
< count
; n
++ )
1125 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1126 wxString option
, negator
;
1128 if ( opt
.kind
!= wxCMD_LINE_USAGE_TEXT
)
1131 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1136 if ( opt
.flags
& wxCMD_LINE_SWITCH_NEGATABLE
)
1137 negator
= wxT("[-]");
1139 if ( !opt
.shortName
.empty() )
1141 usage
<< chSwitch
<< opt
.shortName
<< negator
;
1143 else if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1145 usage
<< wxT("--") << opt
.longName
<< negator
;
1149 if (!opt
.longName
.empty())
1151 wxFAIL_MSG( wxT("option with only a long name while long ")
1152 wxT("options are disabled") );
1156 wxFAIL_MSG( wxT("option without neither short nor long name") );
1160 if ( !opt
.shortName
.empty() )
1162 option
<< wxT(" ") << chSwitch
<< opt
.shortName
;
1165 if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1167 option
<< (option
.empty() ? wxT(" ") : wxT(", "))
1168 << wxT("--") << opt
.longName
;
1171 if ( opt
.kind
!= wxCMD_LINE_SWITCH
)
1174 val
<< wxT('<') << GetTypeName(opt
.type
) << wxT('>');
1175 usage
<< wxT(' ') << val
;
1176 option
<< (!opt
.longName
? wxT(':') : wxT('=')) << val
;
1179 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1185 namesOptions
.push_back(option
);
1186 descOptions
.push_back(opt
.description
);
1189 count
= m_data
->m_paramDesc
.GetCount();
1190 for ( n
= 0; n
< count
; n
++ )
1192 wxCmdLineParam
& param
= m_data
->m_paramDesc
[n
];
1195 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1200 usage
<< param
.description
;
1202 if ( param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
)
1204 usage
<< wxT("...");
1207 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1215 // set to number of our own options, not counting the standard ones
1216 count
= namesOptions
.size();
1218 // get option names & descriptions for standard options, if any:
1219 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
1222 stdDesc
= traits
->GetStandardCmdLineOptions(namesOptions
, descOptions
);
1224 // now construct the detailed help message
1225 size_t len
, lenMax
= 0;
1226 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1228 len
= namesOptions
[n
].length();
1233 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1236 usage
<< wxT('\n') << stdDesc
;
1238 len
= namesOptions
[n
].length();
1239 // desc contains text if name is empty
1242 usage
<< descOptions
[n
] << wxT('\n');
1246 usage
<< namesOptions
[n
]
1247 << wxString(wxT(' '), lenMax
- len
) << wxT('\t')
1256 // ----------------------------------------------------------------------------
1257 // private functions
1258 // ----------------------------------------------------------------------------
1260 static wxString
GetTypeName(wxCmdLineParamType type
)
1266 wxFAIL_MSG( wxT("unknown option type") );
1267 // still fall through
1269 case wxCMD_LINE_VAL_STRING
:
1273 case wxCMD_LINE_VAL_NUMBER
:
1277 case wxCMD_LINE_VAL_DOUBLE
:
1281 case wxCMD_LINE_VAL_DATE
:
1290 Returns a string which is equal to the string pointed to by p, but up to the
1291 point where p contains an character that's not allowed.
1292 Allowable characters are letters and numbers, and characters pointed to by
1293 the parameter allowedChars.
1295 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1296 this function returns "abcde-".
1298 static wxString
GetOptionName(wxString::const_iterator p
,
1299 wxString::const_iterator end
,
1300 const wxChar
*allowedChars
)
1304 while ( p
!= end
&& (wxIsalnum(*p
) || wxStrchr(allowedChars
, *p
)) )
1312 // Besides alphanumeric characters, short and long options can
1313 // have other characters.
1315 // A short option additionally can have these
1316 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1318 // A long option can have the same characters as a short option and a '-'.
1319 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1320 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1322 static wxString
GetShortOptionName(wxString::const_iterator p
,
1323 wxString::const_iterator end
)
1325 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION
);
1328 static wxString
GetLongOptionName(wxString::const_iterator p
,
1329 wxString::const_iterator end
)
1331 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION
);
1334 #endif // wxUSE_CMDLINE_PARSER
1336 // ----------------------------------------------------------------------------
1338 // ----------------------------------------------------------------------------
1341 This function is mainly used under Windows (as under Unix we always get the
1342 command line arguments as argc/argv anyhow) and so it tries to follow
1343 Windows conventions for the command line handling, not Unix ones. For
1344 instance, backslash is not special except when it precedes double quote when
1350 wxCmdLineParser::ConvertStringToArgs(const wxString
& cmdline
,
1351 wxCmdLineSplitType type
)
1358 const wxString::const_iterator end
= cmdline
.end();
1359 wxString::const_iterator p
= cmdline
.begin();
1364 while ( p
!= end
&& (*p
== ' ' || *p
== '\t') )
1371 // parse this parameter
1372 bool lastBS
= false,
1373 isInsideQuotes
= false;
1374 wxChar chDelim
= '\0';
1375 for ( arg
.clear(); p
!= end
; ++p
)
1377 const wxChar ch
= *p
;
1379 if ( type
== wxCMD_LINE_SPLIT_DOS
)
1385 isInsideQuotes
= !isInsideQuotes
;
1387 // don't put quote in arg
1390 //else: quote has no special meaning but the backslash
1391 // still remains -- makes no sense but this is what
1394 // note that backslash does *not* quote the space, only quotes do
1395 else if ( !isInsideQuotes
&& (ch
== ' ' || ch
== '\t') )
1397 ++p
; // skip this space anyhow
1401 lastBS
= !lastBS
&& ch
== '\\';
1403 else // type == wxCMD_LINE_SPLIT_UNIX
1407 if ( isInsideQuotes
)
1409 if ( ch
== chDelim
)
1411 isInsideQuotes
= false;
1413 continue; // don't use the quote itself
1416 else // not in quotes and not escaped
1418 if ( ch
== '\'' || ch
== '"' )
1420 isInsideQuotes
= true;
1423 continue; // don't use the quote itself
1426 if ( ch
== ' ' || ch
== '\t' )
1428 ++p
; // skip this space anyhow
1433 lastBS
= ch
== '\\';
1437 else // escaped by backslash, just use as is
1446 args
.push_back(arg
);