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")
113 // can't use union easily here, so just store all possible data fields, we
114 // don't waste much (might still use union later if the number of supported
115 // types increases, so always use the accessor functions and don't access
116 // the fields directly!)
118 void Check(wxCmdLineParamType
WXUNUSED_UNLESS_DEBUG(typ
)) const
120 wxASSERT_MSG( type
== typ
, wxT("type mismatch in wxCmdLineOption") );
123 double GetDoubleVal() const
124 { Check(wxCMD_LINE_VAL_DOUBLE
); return m_doubleVal
; }
125 long GetLongVal() const
126 { Check(wxCMD_LINE_VAL_NUMBER
); return m_longVal
; }
127 const wxString
& GetStrVal() const
128 { Check(wxCMD_LINE_VAL_STRING
); return m_strVal
; }
130 const wxDateTime
& GetDateVal() const
131 { Check(wxCMD_LINE_VAL_DATE
); return m_dateVal
; }
132 #endif // wxUSE_DATETIME
134 void SetDoubleVal(double val
)
135 { Check(wxCMD_LINE_VAL_DOUBLE
); m_doubleVal
= val
; m_hasVal
= true; }
136 void SetLongVal(long val
)
137 { Check(wxCMD_LINE_VAL_NUMBER
); m_longVal
= val
; m_hasVal
= true; }
138 void SetStrVal(const wxString
& val
)
139 { Check(wxCMD_LINE_VAL_STRING
); m_strVal
= val
; m_hasVal
= true; }
141 void SetDateVal(const wxDateTime
& val
)
142 { Check(wxCMD_LINE_VAL_DATE
); m_dateVal
= val
; m_hasVal
= true; }
143 #endif // wxUSE_DATETIME
145 void SetHasValue(bool hasValue
= true) { m_hasVal
= hasValue
; }
146 bool HasValue() const { return m_hasVal
; }
148 void SetNegated() { m_isNegated
= true; }
149 bool IsNegated() const { return m_isNegated
; }
152 wxCmdLineEntryType kind
;
156 wxCmdLineParamType type
;
167 wxDateTime m_dateVal
;
168 #endif // wxUSE_DATETIME
171 struct wxCmdLineParam
173 wxCmdLineParam(const wxString
& desc
,
174 wxCmdLineParamType typ
,
182 wxString description
;
183 wxCmdLineParamType type
;
187 WX_DECLARE_OBJARRAY(wxCmdLineOption
, wxArrayOptions
);
188 WX_DECLARE_OBJARRAY(wxCmdLineParam
, wxArrayParams
);
190 #include "wx/arrimpl.cpp"
192 WX_DEFINE_OBJARRAY(wxArrayOptions
)
193 WX_DEFINE_OBJARRAY(wxArrayParams
)
195 // the parser internal state
196 struct wxCmdLineParserData
199 wxString m_switchChars
; // characters which may start an option
200 bool m_enableLongOptions
; // true if long options are enabled
201 wxString m_logo
; // some extra text to show in Usage()
204 wxArrayString m_arguments
; // == argv, argc == m_arguments.GetCount()
205 wxArrayOptions m_options
; // all possible options and switches
206 wxArrayParams m_paramDesc
; // description of all possible params
207 wxArrayString m_parameters
; // all params found
210 wxCmdLineParserData();
211 void SetArguments(int argc
, char **argv
);
213 void SetArguments(int argc
, wxChar
**argv
);
214 void SetArguments(int argc
, const wxCmdLineArgsArray
& argv
);
215 #endif // wxUSE_UNICODE
216 void SetArguments(const wxString
& cmdline
);
218 int FindOption(const wxString
& name
);
219 int FindOptionByLongName(const wxString
& name
);
222 // ============================================================================
224 // ============================================================================
226 // ----------------------------------------------------------------------------
227 // wxCmdLineParserData
228 // ----------------------------------------------------------------------------
230 wxCmdLineParserData::wxCmdLineParserData()
232 m_enableLongOptions
= true;
234 m_switchChars
= wxT("-");
236 m_switchChars
= wxT("/-");
243 // Small helper function setting locale for all categories.
245 // We define it because wxSetlocale() can't be easily used with wxScopeGuard as
246 // it has several overloads -- while this one can.
247 inline char *SetAllLocaleFacets(const char *loc
)
249 return wxSetlocale(LC_ALL
, loc
);
252 } // private namespace
254 void wxCmdLineParserData::SetArguments(int argc
, char **argv
)
258 // Command-line arguments are supposed to be in the user locale encoding
259 // (what else?) but wxLocale probably wasn't initialized yet as we're
260 // called early during the program startup and so our locale might not have
261 // been set from the environment yet. To work around this problem we
262 // temporarily change the locale here. The only drawback is that changing
263 // the locale is thread-unsafe but precisely because we're called so early
264 // it's hopefully safe to assume that no other threads had been created yet.
265 char * const locOld
= SetAllLocaleFacets("");
266 wxON_BLOCK_EXIT1( SetAllLocaleFacets
, locOld
);
268 for ( int n
= 0; n
< argc
; n
++ )
270 // try to interpret the string as being in the current locale
271 wxString
arg(argv
[n
]);
273 // but just in case we guessed wrongly and the conversion failed, do
274 // try to salvage at least something
275 if ( arg
.empty() && argv
[n
][0] != '\0' )
276 arg
= wxString(argv
[n
], wxConvISO8859_1
);
278 m_arguments
.push_back(arg
);
284 void wxCmdLineParserData::SetArguments(int argc
, wxChar
**argv
)
288 for ( int n
= 0; n
< argc
; n
++ )
290 m_arguments
.push_back(argv
[n
]);
294 void wxCmdLineParserData::SetArguments(int WXUNUSED(argc
),
295 const wxCmdLineArgsArray
& argv
)
297 m_arguments
= argv
.GetArguments();
300 #endif // wxUSE_UNICODE
302 void wxCmdLineParserData::SetArguments(const wxString
& cmdLine
)
306 if(wxTheApp
&& wxTheApp
->argc
> 0)
307 m_arguments
.push_back(wxTheApp
->argv
[0]);
309 m_arguments
.push_back(wxEmptyString
);
311 wxArrayString args
= wxCmdLineParser::ConvertStringToArgs(cmdLine
);
313 WX_APPEND_ARRAY(m_arguments
, args
);
316 int wxCmdLineParserData::FindOption(const wxString
& name
)
320 size_t count
= m_options
.GetCount();
321 for ( size_t n
= 0; n
< count
; n
++ )
323 if ( m_options
[n
].shortName
== name
)
334 int wxCmdLineParserData::FindOptionByLongName(const wxString
& name
)
336 size_t count
= m_options
.GetCount();
337 for ( size_t n
= 0; n
< count
; n
++ )
339 if ( m_options
[n
].longName
== name
)
349 // ----------------------------------------------------------------------------
350 // construction and destruction
351 // ----------------------------------------------------------------------------
353 void wxCmdLineParser::Init()
355 m_data
= new wxCmdLineParserData
;
358 void wxCmdLineParser::SetCmdLine(int argc
, char **argv
)
360 m_data
->SetArguments(argc
, argv
);
365 void wxCmdLineParser::SetCmdLine(int argc
, wxChar
**argv
)
367 m_data
->SetArguments(argc
, argv
);
370 void wxCmdLineParser::SetCmdLine(int argc
, const wxCmdLineArgsArray
& argv
)
372 m_data
->SetArguments(argc
, argv
);
375 #endif // wxUSE_UNICODE
377 void wxCmdLineParser::SetCmdLine(const wxString
& cmdline
)
379 m_data
->SetArguments(cmdline
);
382 wxCmdLineParser::~wxCmdLineParser()
387 // ----------------------------------------------------------------------------
389 // ----------------------------------------------------------------------------
391 void wxCmdLineParser::SetSwitchChars(const wxString
& switchChars
)
393 m_data
->m_switchChars
= switchChars
;
396 void wxCmdLineParser::EnableLongOptions(bool enable
)
398 m_data
->m_enableLongOptions
= enable
;
401 bool wxCmdLineParser::AreLongOptionsEnabled() const
403 return m_data
->m_enableLongOptions
;
406 void wxCmdLineParser::SetLogo(const wxString
& logo
)
408 m_data
->m_logo
= logo
;
411 // ----------------------------------------------------------------------------
412 // command line construction
413 // ----------------------------------------------------------------------------
415 void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc
*desc
)
419 switch ( desc
->kind
)
421 case wxCMD_LINE_SWITCH
:
422 AddSwitch(desc
->shortName
, desc
->longName
,
423 wxGetTranslation(desc
->description
),
427 case wxCMD_LINE_OPTION
:
428 AddOption(desc
->shortName
, desc
->longName
,
429 wxGetTranslation(desc
->description
),
430 desc
->type
, desc
->flags
);
433 case wxCMD_LINE_PARAM
:
434 AddParam(wxGetTranslation(desc
->description
),
435 desc
->type
, desc
->flags
);
438 case wxCMD_LINE_USAGE_TEXT
:
439 AddUsageText(wxGetTranslation(desc
->description
));
443 wxFAIL_MSG( wxT("unknown command line entry type") );
444 // still fall through
446 case wxCMD_LINE_NONE
:
452 void wxCmdLineParser::AddSwitch(const wxString
& shortName
,
453 const wxString
& longName
,
454 const wxString
& desc
,
457 wxASSERT_MSG( m_data
->FindOption(shortName
) == wxNOT_FOUND
,
458 wxT("duplicate switch") );
460 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_SWITCH
,
461 shortName
, longName
, desc
,
462 wxCMD_LINE_VAL_NONE
, flags
);
464 m_data
->m_options
.Add(option
);
467 void wxCmdLineParser::AddOption(const wxString
& shortName
,
468 const wxString
& longName
,
469 const wxString
& desc
,
470 wxCmdLineParamType type
,
473 wxASSERT_MSG( m_data
->FindOption(shortName
) == wxNOT_FOUND
,
474 wxT("duplicate option") );
476 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_OPTION
,
477 shortName
, longName
, desc
,
480 m_data
->m_options
.Add(option
);
483 void wxCmdLineParser::AddParam(const wxString
& desc
,
484 wxCmdLineParamType type
,
487 // do some consistency checks: a required parameter can't follow an
488 // optional one and nothing should follow a parameter with MULTIPLE flag
490 if ( !m_data
->m_paramDesc
.IsEmpty() )
492 wxCmdLineParam
& param
= m_data
->m_paramDesc
.Last();
494 wxASSERT_MSG( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
),
495 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
497 if ( !(flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
499 wxASSERT_MSG( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
),
500 wxT("a required parameter can't follow an optional one") );
503 #endif // wxDEBUG_LEVEL
505 wxCmdLineParam
*param
= new wxCmdLineParam(desc
, type
, flags
);
507 m_data
->m_paramDesc
.Add(param
);
510 void wxCmdLineParser::AddUsageText(const wxString
& text
)
512 wxASSERT_MSG( !text
.empty(), wxT("text can't be empty") );
514 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_USAGE_TEXT
,
515 wxEmptyString
, wxEmptyString
,
516 text
, wxCMD_LINE_VAL_NONE
, 0);
518 m_data
->m_options
.Add(option
);
521 // ----------------------------------------------------------------------------
522 // access to parse command line
523 // ----------------------------------------------------------------------------
525 bool wxCmdLineParser::Found(const wxString
& name
) const
527 return FoundSwitch(name
) != wxCMD_SWITCH_NOT_FOUND
;
530 wxCmdLineSwitchState
wxCmdLineParser::FoundSwitch(const wxString
& name
) const
532 int i
= m_data
->FindOption(name
);
533 if ( i
== wxNOT_FOUND
)
534 i
= m_data
->FindOptionByLongName(name
);
536 wxCHECK_MSG( i
!= wxNOT_FOUND
, wxCMD_SWITCH_NOT_FOUND
, wxT("unknown switch") );
538 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
539 if ( !opt
.HasValue() )
540 return wxCMD_SWITCH_NOT_FOUND
;
542 return opt
.IsNegated() ? wxCMD_SWITCH_OFF
: wxCMD_SWITCH_ON
;
545 bool wxCmdLineParser::Found(const wxString
& name
, wxString
*value
) const
547 int i
= m_data
->FindOption(name
);
548 if ( i
== wxNOT_FOUND
)
549 i
= m_data
->FindOptionByLongName(name
);
551 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
553 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
554 if ( !opt
.HasValue() )
557 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
559 *value
= opt
.GetStrVal();
564 bool wxCmdLineParser::Found(const wxString
& name
, long *value
) const
566 int i
= m_data
->FindOption(name
);
567 if ( i
== wxNOT_FOUND
)
568 i
= m_data
->FindOptionByLongName(name
);
570 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
572 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
573 if ( !opt
.HasValue() )
576 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
578 *value
= opt
.GetLongVal();
583 bool wxCmdLineParser::Found(const wxString
& name
, double *value
) const
585 int i
= m_data
->FindOption(name
);
586 if ( i
== wxNOT_FOUND
)
587 i
= m_data
->FindOptionByLongName(name
);
589 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
591 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
592 if ( !opt
.HasValue() )
595 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
597 *value
= opt
.GetDoubleVal();
603 bool wxCmdLineParser::Found(const wxString
& name
, wxDateTime
*value
) const
605 int i
= m_data
->FindOption(name
);
606 if ( i
== wxNOT_FOUND
)
607 i
= m_data
->FindOptionByLongName(name
);
609 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, wxT("unknown option") );
611 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
612 if ( !opt
.HasValue() )
615 wxCHECK_MSG( value
, false, wxT("NULL pointer in wxCmdLineOption::Found") );
617 *value
= opt
.GetDateVal();
621 #endif // wxUSE_DATETIME
623 size_t wxCmdLineParser::GetParamCount() const
625 return m_data
->m_parameters
.size();
628 wxString
wxCmdLineParser::GetParam(size_t n
) const
630 wxCHECK_MSG( n
< GetParamCount(), wxEmptyString
, wxT("invalid param index") );
632 return m_data
->m_parameters
[n
];
635 // Resets switches and options
636 void wxCmdLineParser::Reset()
638 for ( size_t i
= 0; i
< m_data
->m_options
.GetCount(); i
++ )
640 wxCmdLineOption
& opt
= m_data
->m_options
[i
];
641 opt
.SetHasValue(false);
646 // ----------------------------------------------------------------------------
647 // the real work is done here
648 // ----------------------------------------------------------------------------
650 int wxCmdLineParser::Parse(bool showUsage
)
652 bool maybeOption
= true; // can the following arg be an option?
653 bool ok
= true; // true until an error is detected
654 bool helpRequested
= false; // true if "-h" was given
655 bool hadRepeatableParam
= false; // true if found param with MULTIPLE flag
657 size_t currentParam
= 0; // the index in m_paramDesc
659 size_t countParam
= m_data
->m_paramDesc
.GetCount();
666 size_t count
= m_data
->m_arguments
.size();
667 for ( size_t n
= 1; ok
&& (n
< count
); n
++ ) // 0 is program name
669 arg
= m_data
->m_arguments
[n
];
671 // special case: "--" should be discarded and all following arguments
672 // should be considered as parameters, even if they start with '-' and
673 // not like options (this is POSIX-like)
674 if ( arg
== wxT("--") )
681 // empty argument or just '-' is not an option but a parameter
682 if ( maybeOption
&& arg
.length() > 1 &&
683 // FIXME-UTF8: use wc_str() after removing ANSI build
684 wxStrchr(m_data
->m_switchChars
.c_str(), arg
[0u]) )
688 int optInd
= wxNOT_FOUND
; // init to suppress warnings
690 // an option or a switch: find whether it's a long or a short one
691 if ( arg
.length() >= 3 && arg
[0u] == wxT('-') && arg
[1u] == wxT('-') )
697 wxString::const_iterator p
= arg
.begin() + 2;
699 bool longOptionsEnabled
= AreLongOptionsEnabled();
701 name
= GetLongOptionName(p
, arg
.end());
703 if (longOptionsEnabled
)
705 optInd
= m_data
->FindOptionByLongName(name
);
706 if ( optInd
== wxNOT_FOUND
)
708 errorMsg
<< wxString::Format(_("Unknown long option '%s'"), name
.c_str())
714 optInd
= wxNOT_FOUND
; // Sanity check
716 // Print the argument including leading "--"
717 name
.Prepend( wxT("--") );
718 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
723 else // not a long option
727 // a short one: as they can be cumulated, we try to find the
728 // longest substring which is a valid option
729 wxString::const_iterator p
= arg
.begin() + 1;
731 name
= GetShortOptionName(p
, arg
.end());
733 size_t len
= name
.length();
738 // we couldn't find a valid option name in the
739 // beginning of this string
740 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
747 optInd
= m_data
->FindOption(name
.Left(len
));
749 // will try with one character less the next time
753 while ( optInd
== wxNOT_FOUND
);
755 len
++; // compensates extra len-- above
756 if ( (optInd
!= wxNOT_FOUND
) && (len
!= name
.length()) )
758 // first of all, the option name is only part of this
760 name
= name
.Left(len
);
762 // our option is only part of this argument, there is
763 // something else in it - it is either the value of this
764 // option or other switches if it is a switch
765 if ( m_data
->m_options
[(size_t)optInd
].kind
766 == wxCMD_LINE_SWITCH
)
768 // if the switch is negatable and it is just followed
769 // by '-' the '-' is considered to be part of this
771 if ( (m_data
->m_options
[(size_t)optInd
].flags
&
772 wxCMD_LINE_SWITCH_NEGATABLE
) &&
776 // pretend that all the rest of the argument is the
777 // next argument, in fact
778 wxString arg2
= arg
[0u];
779 arg2
+= arg
.Mid(len
+ 1); // +1 for leading '-'
781 m_data
->m_arguments
.insert
782 (m_data
->m_arguments
.begin() + n
+ 1, arg2
);
785 // only leave the part which wasn't extracted into the
786 // next argument in this one
787 arg
= arg
.Left(len
+ 1);
789 //else: it's our value, we'll deal with it below
793 if ( optInd
== wxNOT_FOUND
)
797 continue; // will break, in fact
800 // look at what follows:
802 // +1 for leading '-'
803 wxString::const_iterator p
= arg
.begin() + 1 + name
.length();
804 wxString::const_iterator end
= arg
.end();
807 ++p
; // for another leading '-'
809 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)optInd
];
810 if ( opt
.kind
== wxCMD_LINE_SWITCH
)
812 // we must check that there is no value following the switch
813 bool negated
= (opt
.flags
& wxCMD_LINE_SWITCH_NEGATABLE
) &&
814 p
!= arg
.end() && *p
== '-';
816 if ( !negated
&& p
!= arg
.end() )
818 errorMsg
<< wxString::Format(_("Unexpected characters following option '%s'."), name
.c_str())
822 else // no value, as expected
824 // nothing more to do
829 if ( opt
.flags
& wxCMD_LINE_OPTION_HELP
)
831 helpRequested
= true;
833 // it's not an error, but we still stop here
838 else // it's an option. not a switch
840 switch ( p
== end
? '\0' : (*p
).GetValue() )
849 // the value is in the next argument
852 // ... but there is none
853 errorMsg
<< wxString::Format(_("Option '%s' requires a value."),
861 // ... take it from there
862 p
= m_data
->m_arguments
[n
].begin();
863 end
= m_data
->m_arguments
[n
].end();
868 // the value is right here: this may be legal or
869 // not depending on the option style
870 if ( opt
.flags
& wxCMD_LINE_NEEDS_SEPARATOR
)
872 errorMsg
<< wxString::Format(_("Separator expected after the option '%s'."),
882 wxString
value(p
, end
);
886 wxFAIL_MSG( wxT("unknown option type") );
887 // still fall through
889 case wxCMD_LINE_VAL_STRING
:
890 opt
.SetStrVal(value
);
893 case wxCMD_LINE_VAL_NUMBER
:
896 if ( value
.ToLong(&val
) )
902 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
903 value
.c_str(), name
.c_str())
911 case wxCMD_LINE_VAL_DOUBLE
:
914 if ( value
.ToDouble(&val
) )
916 opt
.SetDoubleVal(val
);
920 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
921 value
.c_str(), name
.c_str())
930 case wxCMD_LINE_VAL_DATE
:
933 wxString::const_iterator end
;
934 if ( !dt
.ParseDate(value
, &end
) || end
!= value
.end() )
936 errorMsg
<< wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
937 name
.c_str(), value
.c_str())
948 #endif // wxUSE_DATETIME
953 else // not an option, must be a parameter
955 if ( currentParam
< countParam
)
957 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
959 // TODO check the param type
961 m_data
->m_parameters
.push_back(arg
);
963 if ( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) )
969 wxASSERT_MSG( currentParam
== countParam
- 1,
970 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
972 // remember that we did have this last repeatable parameter
973 hadRepeatableParam
= true;
978 errorMsg
<< wxString::Format(_("Unexpected parameter '%s'"), arg
.c_str())
986 // verify that all mandatory options were given
989 size_t countOpt
= m_data
->m_options
.GetCount();
990 for ( size_t n
= 0; ok
&& (n
< countOpt
); n
++ )
992 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
993 if ( (opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) && !opt
.HasValue() )
998 optName
= opt
.shortName
;
1002 if ( AreLongOptionsEnabled() )
1004 optName
.Printf( _("%s (or %s)"),
1005 opt
.shortName
.c_str(),
1006 opt
.longName
.c_str() );
1010 optName
.Printf( wxT("%s"),
1011 opt
.shortName
.c_str() );
1015 errorMsg
<< wxString::Format(_("The value for the option '%s' must be specified."),
1023 for ( ; ok
&& (currentParam
< countParam
); currentParam
++ )
1025 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
1026 if ( (currentParam
== countParam
- 1) &&
1027 (param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) &&
1028 hadRepeatableParam
)
1030 // special case: currentParam wasn't incremented, but we did
1031 // have it, so don't give error
1035 if ( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
1037 errorMsg
<< wxString::Format(_("The required parameter '%s' was not specified."),
1038 param
.description
.c_str())
1046 // if there was an error during parsing the command line, show this error
1047 // and also the usage message if it had been requested
1048 if ( !ok
&& (!errorMsg
.empty() || (helpRequested
&& showUsage
)) )
1050 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1055 usage
= GetUsageString();
1057 msgOut
->Printf( wxT("%s%s"), usage
.c_str(), errorMsg
.c_str() );
1061 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1065 return ok
? 0 : helpRequested
? -1 : 1;
1068 // ----------------------------------------------------------------------------
1069 // give the usage message
1070 // ----------------------------------------------------------------------------
1072 void wxCmdLineParser::Usage() const
1074 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1077 msgOut
->Printf( wxT("%s"), GetUsageString().c_str() );
1081 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1085 wxString
wxCmdLineParser::GetUsageString() const
1088 if ( m_data
->m_arguments
.empty() )
1091 appname
= wxTheApp
->GetAppName();
1095 appname
= wxFileName(m_data
->m_arguments
[0]).GetName();
1098 // we construct the brief cmd line desc on the fly, but not the detailed
1099 // help message below because we want to align the options descriptions
1100 // and for this we must first know the longest one of them
1102 wxArrayString namesOptions
, descOptions
;
1104 if ( !m_data
->m_logo
.empty() )
1106 usage
<< m_data
->m_logo
<< wxT('\n');
1109 usage
<< wxString::Format(_("Usage: %s"), appname
.c_str());
1111 // the switch char is usually '-' but this can be changed with
1112 // SetSwitchChars() and then the first one of possible chars is used
1113 wxChar chSwitch
= !m_data
->m_switchChars
? wxT('-')
1114 : m_data
->m_switchChars
[0u];
1116 bool areLongOptionsEnabled
= AreLongOptionsEnabled();
1117 size_t n
, count
= m_data
->m_options
.GetCount();
1118 for ( n
= 0; n
< count
; n
++ )
1120 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1121 wxString option
, negator
;
1123 if ( opt
.kind
!= wxCMD_LINE_USAGE_TEXT
)
1126 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1131 if ( opt
.flags
& wxCMD_LINE_SWITCH_NEGATABLE
)
1132 negator
= wxT("[-]");
1134 if ( !opt
.shortName
.empty() )
1136 usage
<< chSwitch
<< opt
.shortName
<< negator
;
1138 else if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1140 usage
<< wxT("--") << opt
.longName
<< negator
;
1144 if (!opt
.longName
.empty())
1146 wxFAIL_MSG( wxT("option with only a long name while long ")
1147 wxT("options are disabled") );
1151 wxFAIL_MSG( wxT("option without neither short nor long name") );
1155 if ( !opt
.shortName
.empty() )
1157 option
<< wxT(" ") << chSwitch
<< opt
.shortName
;
1160 if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1162 option
<< (option
.empty() ? wxT(" ") : wxT(", "))
1163 << wxT("--") << opt
.longName
;
1166 if ( opt
.kind
!= wxCMD_LINE_SWITCH
)
1169 val
<< wxT('<') << GetTypeName(opt
.type
) << wxT('>');
1170 usage
<< wxT(' ') << val
;
1171 option
<< (!opt
.longName
? wxT(':') : wxT('=')) << val
;
1174 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1180 namesOptions
.push_back(option
);
1181 descOptions
.push_back(opt
.description
);
1184 count
= m_data
->m_paramDesc
.GetCount();
1185 for ( n
= 0; n
< count
; n
++ )
1187 wxCmdLineParam
& param
= m_data
->m_paramDesc
[n
];
1190 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1195 usage
<< param
.description
;
1197 if ( param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
)
1199 usage
<< wxT("...");
1202 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1210 // set to number of our own options, not counting the standard ones
1211 count
= namesOptions
.size();
1213 // get option names & descriptions for standard options, if any:
1214 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
1217 stdDesc
= traits
->GetStandardCmdLineOptions(namesOptions
, descOptions
);
1219 // now construct the detailed help message
1220 size_t len
, lenMax
= 0;
1221 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1223 len
= namesOptions
[n
].length();
1228 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1231 usage
<< wxT('\n') << stdDesc
;
1233 len
= namesOptions
[n
].length();
1234 // desc contains text if name is empty
1237 usage
<< descOptions
[n
] << wxT('\n');
1241 usage
<< namesOptions
[n
]
1242 << wxString(wxT(' '), lenMax
- len
) << wxT('\t')
1251 // ----------------------------------------------------------------------------
1252 // private functions
1253 // ----------------------------------------------------------------------------
1255 static wxString
GetTypeName(wxCmdLineParamType type
)
1261 wxFAIL_MSG( wxT("unknown option type") );
1262 // still fall through
1264 case wxCMD_LINE_VAL_STRING
:
1268 case wxCMD_LINE_VAL_NUMBER
:
1272 case wxCMD_LINE_VAL_DOUBLE
:
1276 case wxCMD_LINE_VAL_DATE
:
1285 Returns a string which is equal to the string pointed to by p, but up to the
1286 point where p contains an character that's not allowed.
1287 Allowable characters are letters and numbers, and characters pointed to by
1288 the parameter allowedChars.
1290 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1291 this function returns "abcde-".
1293 static wxString
GetOptionName(wxString::const_iterator p
,
1294 wxString::const_iterator end
,
1295 const wxChar
*allowedChars
)
1299 while ( p
!= end
&& (wxIsalnum(*p
) || wxStrchr(allowedChars
, *p
)) )
1307 // Besides alphanumeric characters, short and long options can
1308 // have other characters.
1310 // A short option additionally can have these
1311 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1313 // A long option can have the same characters as a short option and a '-'.
1314 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1315 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1317 static wxString
GetShortOptionName(wxString::const_iterator p
,
1318 wxString::const_iterator end
)
1320 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION
);
1323 static wxString
GetLongOptionName(wxString::const_iterator p
,
1324 wxString::const_iterator end
)
1326 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION
);
1329 #endif // wxUSE_CMDLINE_PARSER
1331 // ----------------------------------------------------------------------------
1333 // ----------------------------------------------------------------------------
1336 This function is mainly used under Windows (as under Unix we always get the
1337 command line arguments as argc/argv anyhow) and so it tries to follow
1338 Windows conventions for the command line handling, not Unix ones. For
1339 instance, backslash is not special except when it precedes double quote when
1345 wxCmdLineParser::ConvertStringToArgs(const wxString
& cmdline
,
1346 wxCmdLineSplitType type
)
1353 const wxString::const_iterator end
= cmdline
.end();
1354 wxString::const_iterator p
= cmdline
.begin();
1359 while ( p
!= end
&& (*p
== ' ' || *p
== '\t') )
1366 // parse this parameter
1367 bool lastBS
= false,
1368 isInsideQuotes
= false;
1369 wxChar chDelim
= '\0';
1370 for ( arg
.clear(); p
!= end
; ++p
)
1372 const wxChar ch
= *p
;
1374 if ( type
== wxCMD_LINE_SPLIT_DOS
)
1380 isInsideQuotes
= !isInsideQuotes
;
1382 // don't put quote in arg
1385 //else: quote has no special meaning but the backslash
1386 // still remains -- makes no sense but this is what
1389 // note that backslash does *not* quote the space, only quotes do
1390 else if ( !isInsideQuotes
&& (ch
== ' ' || ch
== '\t') )
1392 ++p
; // skip this space anyhow
1396 lastBS
= !lastBS
&& ch
== '\\';
1398 else // type == wxCMD_LINE_SPLIT_UNIX
1402 if ( isInsideQuotes
)
1404 if ( ch
== chDelim
)
1406 isInsideQuotes
= false;
1408 continue; // don't use the quote itself
1411 else // not in quotes and not escaped
1413 if ( ch
== '\'' || ch
== '"' )
1415 isInsideQuotes
= true;
1418 continue; // don't use the quote itself
1421 if ( ch
== ' ' || ch
== '\t' )
1423 ++p
; // skip this space anyhow
1428 lastBS
= ch
== '\\';
1432 else // escaped by backslash, just use as is
1441 args
.push_back(arg
);