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
41 #include "wx/datetime.h"
42 #include "wx/msgout.h"
43 #include "wx/filename.h"
44 #include "wx/apptrait.h"
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 static wxString
GetTypeName(wxCmdLineParamType type
);
52 static wxString
GetOptionName(wxString::const_iterator p
,
53 wxString::const_iterator end
,
54 const wxChar
*allowedChars
);
56 static wxString
GetShortOptionName(wxString::const_iterator p
,
57 wxString::const_iterator end
);
59 static wxString
GetLongOptionName(wxString::const_iterator p
,
60 wxString::const_iterator end
);
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
66 // an internal representation of an option
67 struct wxCmdLineOption
69 wxCmdLineOption(wxCmdLineEntryType k
,
73 wxCmdLineParamType typ
,
76 // wxCMD_LINE_USAGE_TEXT uses only description, shortName and longName is empty
77 if ( k
!= wxCMD_LINE_USAGE_TEXT
)
81 !shrt
.empty() || !lng
.empty(),
82 wxT("option should have at least one name")
87 GetShortOptionName(shrt
.begin(), shrt
.end()).Len() == shrt
.Len(),
88 wxT("Short option contains invalid characters")
93 GetLongOptionName(lng
.begin(), lng
.end()).Len() == lng
.Len(),
94 wxT("Long option contains invalid characters")
110 // can't use union easily here, so just store all possible data fields, we
111 // don't waste much (might still use union later if the number of supported
112 // types increases, so always use the accessor functions and don't access
113 // the fields directly!)
115 void Check(wxCmdLineParamType
WXUNUSED_UNLESS_DEBUG(typ
)) const
117 wxASSERT_MSG( type
== typ
, _T("type mismatch in wxCmdLineOption") );
120 double GetDoubleVal() const
121 { Check(wxCMD_LINE_VAL_DOUBLE
); return m_doubleVal
; }
122 long GetLongVal() const
123 { Check(wxCMD_LINE_VAL_NUMBER
); return m_longVal
; }
124 const wxString
& GetStrVal() const
125 { Check(wxCMD_LINE_VAL_STRING
); return m_strVal
; }
127 const wxDateTime
& GetDateVal() const
128 { Check(wxCMD_LINE_VAL_DATE
); return m_dateVal
; }
129 #endif // wxUSE_DATETIME
131 void SetDoubleVal(double val
)
132 { Check(wxCMD_LINE_VAL_DOUBLE
); m_doubleVal
= val
; m_hasVal
= true; }
133 void SetLongVal(long val
)
134 { Check(wxCMD_LINE_VAL_NUMBER
); m_longVal
= val
; m_hasVal
= true; }
135 void SetStrVal(const wxString
& val
)
136 { Check(wxCMD_LINE_VAL_STRING
); m_strVal
= val
; m_hasVal
= true; }
138 void SetDateVal(const wxDateTime
& val
)
139 { Check(wxCMD_LINE_VAL_DATE
); m_dateVal
= val
; m_hasVal
= true; }
140 #endif // wxUSE_DATETIME
142 void SetHasValue(bool hasValue
= true) { m_hasVal
= hasValue
; }
143 bool HasValue() const { return m_hasVal
; }
146 wxCmdLineEntryType kind
;
150 wxCmdLineParamType type
;
160 wxDateTime m_dateVal
;
161 #endif // wxUSE_DATETIME
164 struct wxCmdLineParam
166 wxCmdLineParam(const wxString
& desc
,
167 wxCmdLineParamType typ
,
175 wxString description
;
176 wxCmdLineParamType type
;
180 WX_DECLARE_OBJARRAY(wxCmdLineOption
, wxArrayOptions
);
181 WX_DECLARE_OBJARRAY(wxCmdLineParam
, wxArrayParams
);
183 #include "wx/arrimpl.cpp"
185 WX_DEFINE_OBJARRAY(wxArrayOptions
)
186 WX_DEFINE_OBJARRAY(wxArrayParams
)
188 // the parser internal state
189 struct wxCmdLineParserData
192 wxString m_switchChars
; // characters which may start an option
193 bool m_enableLongOptions
; // true if long options are enabled
194 wxString m_logo
; // some extra text to show in Usage()
197 wxArrayString m_arguments
; // == argv, argc == m_arguments.GetCount()
198 wxArrayOptions m_options
; // all possible options and switches
199 wxArrayParams m_paramDesc
; // description of all possible params
200 wxArrayString m_parameters
; // all params found
203 wxCmdLineParserData();
204 void SetArguments(int argc
, char **argv
);
206 void SetArguments(int argc
, wxChar
**argv
);
207 void SetArguments(int argc
, const wxCmdLineArgsArray
& argv
);
208 #endif // wxUSE_UNICODE
209 void SetArguments(const wxString
& cmdline
);
211 int FindOption(const wxString
& name
);
212 int FindOptionByLongName(const wxString
& name
);
215 // ============================================================================
217 // ============================================================================
219 // ----------------------------------------------------------------------------
220 // wxCmdLineParserData
221 // ----------------------------------------------------------------------------
223 wxCmdLineParserData::wxCmdLineParserData()
225 m_enableLongOptions
= true;
227 m_switchChars
= _T("-");
229 m_switchChars
= _T("/-");
233 void wxCmdLineParserData::SetArguments(int argc
, char **argv
)
237 for ( int n
= 0; n
< argc
; n
++ )
239 m_arguments
.push_back(wxString::FromAscii(argv
[n
]));
245 void wxCmdLineParserData::SetArguments(int argc
, wxChar
**argv
)
249 for ( int n
= 0; n
< argc
; n
++ )
251 m_arguments
.push_back(argv
[n
]);
255 void wxCmdLineParserData::SetArguments(int WXUNUSED(argc
),
256 const wxCmdLineArgsArray
& argv
)
258 m_arguments
= argv
.GetArguments();
261 #endif // wxUSE_UNICODE
263 void wxCmdLineParserData::SetArguments(const wxString
& cmdLine
)
267 if(wxTheApp
&& wxTheApp
->argc
> 0)
268 m_arguments
.push_back(wxTheApp
->argv
[0]);
270 m_arguments
.push_back(wxEmptyString
);
272 wxArrayString args
= wxCmdLineParser::ConvertStringToArgs(cmdLine
);
274 WX_APPEND_ARRAY(m_arguments
, args
);
277 int wxCmdLineParserData::FindOption(const wxString
& name
)
281 size_t count
= m_options
.GetCount();
282 for ( size_t n
= 0; n
< count
; n
++ )
284 if ( m_options
[n
].shortName
== name
)
295 int wxCmdLineParserData::FindOptionByLongName(const wxString
& name
)
297 size_t count
= m_options
.GetCount();
298 for ( size_t n
= 0; n
< count
; n
++ )
300 if ( m_options
[n
].longName
== name
)
310 // ----------------------------------------------------------------------------
311 // construction and destruction
312 // ----------------------------------------------------------------------------
314 void wxCmdLineParser::Init()
316 m_data
= new wxCmdLineParserData
;
319 void wxCmdLineParser::SetCmdLine(int argc
, char **argv
)
321 m_data
->SetArguments(argc
, argv
);
326 void wxCmdLineParser::SetCmdLine(int argc
, wxChar
**argv
)
328 m_data
->SetArguments(argc
, argv
);
331 void wxCmdLineParser::SetCmdLine(int argc
, const wxCmdLineArgsArray
& argv
)
333 m_data
->SetArguments(argc
, argv
);
336 #endif // wxUSE_UNICODE
338 void wxCmdLineParser::SetCmdLine(const wxString
& cmdline
)
340 m_data
->SetArguments(cmdline
);
343 wxCmdLineParser::~wxCmdLineParser()
348 // ----------------------------------------------------------------------------
350 // ----------------------------------------------------------------------------
352 void wxCmdLineParser::SetSwitchChars(const wxString
& switchChars
)
354 m_data
->m_switchChars
= switchChars
;
357 void wxCmdLineParser::EnableLongOptions(bool enable
)
359 m_data
->m_enableLongOptions
= enable
;
362 bool wxCmdLineParser::AreLongOptionsEnabled() const
364 return m_data
->m_enableLongOptions
;
367 void wxCmdLineParser::SetLogo(const wxString
& logo
)
369 m_data
->m_logo
= logo
;
372 // ----------------------------------------------------------------------------
373 // command line construction
374 // ----------------------------------------------------------------------------
376 void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc
*desc
)
380 switch ( desc
->kind
)
382 case wxCMD_LINE_SWITCH
:
383 AddSwitch(desc
->shortName
, desc
->longName
,
384 wxGetTranslation(desc
->description
),
388 case wxCMD_LINE_OPTION
:
389 AddOption(desc
->shortName
, desc
->longName
,
390 wxGetTranslation(desc
->description
),
391 desc
->type
, desc
->flags
);
394 case wxCMD_LINE_PARAM
:
395 AddParam(wxGetTranslation(desc
->description
),
396 desc
->type
, desc
->flags
);
399 case wxCMD_LINE_USAGE_TEXT
:
400 AddUsageText(wxGetTranslation(desc
->description
));
404 wxFAIL_MSG( _T("unknown command line entry type") );
405 // still fall through
407 case wxCMD_LINE_NONE
:
413 void wxCmdLineParser::AddSwitch(const wxString
& shortName
,
414 const wxString
& longName
,
415 const wxString
& desc
,
418 wxASSERT_MSG( m_data
->FindOption(shortName
) == wxNOT_FOUND
,
419 _T("duplicate switch") );
421 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_SWITCH
,
422 shortName
, longName
, desc
,
423 wxCMD_LINE_VAL_NONE
, flags
);
425 m_data
->m_options
.Add(option
);
428 void wxCmdLineParser::AddOption(const wxString
& shortName
,
429 const wxString
& longName
,
430 const wxString
& desc
,
431 wxCmdLineParamType type
,
434 wxASSERT_MSG( m_data
->FindOption(shortName
) == wxNOT_FOUND
,
435 _T("duplicate option") );
437 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_OPTION
,
438 shortName
, longName
, desc
,
441 m_data
->m_options
.Add(option
);
444 void wxCmdLineParser::AddParam(const wxString
& desc
,
445 wxCmdLineParamType type
,
448 // do some consistency checks: a required parameter can't follow an
449 // optional one and nothing should follow a parameter with MULTIPLE flag
451 if ( !m_data
->m_paramDesc
.IsEmpty() )
453 wxCmdLineParam
& param
= m_data
->m_paramDesc
.Last();
455 wxASSERT_MSG( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
),
456 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
458 if ( !(flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
460 wxASSERT_MSG( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
),
461 _T("a required parameter can't follow an optional one") );
464 #endif // wxDEBUG_LEVEL
466 wxCmdLineParam
*param
= new wxCmdLineParam(desc
, type
, flags
);
468 m_data
->m_paramDesc
.Add(param
);
471 void wxCmdLineParser::AddUsageText(const wxString
& text
)
473 wxASSERT_MSG( !text
.empty(), wxT("text can't be empty") );
475 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_USAGE_TEXT
,
476 wxEmptyString
, wxEmptyString
,
477 text
, wxCMD_LINE_VAL_NONE
, 0);
479 m_data
->m_options
.Add(option
);
482 // ----------------------------------------------------------------------------
483 // access to parse command line
484 // ----------------------------------------------------------------------------
486 bool wxCmdLineParser::Found(const wxString
& name
) const
488 int i
= m_data
->FindOption(name
);
489 if ( i
== wxNOT_FOUND
)
490 i
= m_data
->FindOptionByLongName(name
);
492 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, _T("unknown switch") );
494 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
495 if ( !opt
.HasValue() )
501 bool wxCmdLineParser::Found(const wxString
& name
, wxString
*value
) const
503 int i
= m_data
->FindOption(name
);
504 if ( i
== wxNOT_FOUND
)
505 i
= m_data
->FindOptionByLongName(name
);
507 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, _T("unknown option") );
509 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
510 if ( !opt
.HasValue() )
513 wxCHECK_MSG( value
, false, _T("NULL pointer in wxCmdLineOption::Found") );
515 *value
= opt
.GetStrVal();
520 bool wxCmdLineParser::Found(const wxString
& name
, long *value
) const
522 int i
= m_data
->FindOption(name
);
523 if ( i
== wxNOT_FOUND
)
524 i
= m_data
->FindOptionByLongName(name
);
526 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, _T("unknown option") );
528 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
529 if ( !opt
.HasValue() )
532 wxCHECK_MSG( value
, false, _T("NULL pointer in wxCmdLineOption::Found") );
534 *value
= opt
.GetLongVal();
539 bool wxCmdLineParser::Found(const wxString
& name
, double *value
) const
541 int i
= m_data
->FindOption(name
);
542 if ( i
== wxNOT_FOUND
)
543 i
= m_data
->FindOptionByLongName(name
);
545 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, _T("unknown option") );
547 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
548 if ( !opt
.HasValue() )
551 wxCHECK_MSG( value
, false, _T("NULL pointer in wxCmdLineOption::Found") );
553 *value
= opt
.GetDoubleVal();
559 bool wxCmdLineParser::Found(const wxString
& name
, wxDateTime
*value
) const
561 int i
= m_data
->FindOption(name
);
562 if ( i
== wxNOT_FOUND
)
563 i
= m_data
->FindOptionByLongName(name
);
565 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, _T("unknown option") );
567 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
568 if ( !opt
.HasValue() )
571 wxCHECK_MSG( value
, false, _T("NULL pointer in wxCmdLineOption::Found") );
573 *value
= opt
.GetDateVal();
577 #endif // wxUSE_DATETIME
579 size_t wxCmdLineParser::GetParamCount() const
581 return m_data
->m_parameters
.size();
584 wxString
wxCmdLineParser::GetParam(size_t n
) const
586 wxCHECK_MSG( n
< GetParamCount(), wxEmptyString
, _T("invalid param index") );
588 return m_data
->m_parameters
[n
];
591 // Resets switches and options
592 void wxCmdLineParser::Reset()
594 for ( size_t i
= 0; i
< m_data
->m_options
.GetCount(); i
++ )
596 wxCmdLineOption
& opt
= m_data
->m_options
[i
];
597 opt
.SetHasValue(false);
602 // ----------------------------------------------------------------------------
603 // the real work is done here
604 // ----------------------------------------------------------------------------
606 int wxCmdLineParser::Parse(bool showUsage
)
608 bool maybeOption
= true; // can the following arg be an option?
609 bool ok
= true; // true until an error is detected
610 bool helpRequested
= false; // true if "-h" was given
611 bool hadRepeatableParam
= false; // true if found param with MULTIPLE flag
613 size_t currentParam
= 0; // the index in m_paramDesc
615 size_t countParam
= m_data
->m_paramDesc
.GetCount();
622 size_t count
= m_data
->m_arguments
.size();
623 for ( size_t n
= 1; ok
&& (n
< count
); n
++ ) // 0 is program name
625 arg
= m_data
->m_arguments
[n
];
627 // special case: "--" should be discarded and all following arguments
628 // should be considered as parameters, even if they start with '-' and
629 // not like options (this is POSIX-like)
630 if ( arg
== _T("--") )
637 // empty argument or just '-' is not an option but a parameter
638 if ( maybeOption
&& arg
.length() > 1 &&
639 // FIXME-UTF8: use wc_str() after removing ANSI build
640 wxStrchr(m_data
->m_switchChars
.c_str(), arg
[0u]) )
644 int optInd
= wxNOT_FOUND
; // init to suppress warnings
646 // an option or a switch: find whether it's a long or a short one
647 if ( arg
.length() >= 3 && arg
[0u] == _T('-') && arg
[1u] == _T('-') )
653 wxString::const_iterator p
= arg
.begin() + 2;
655 bool longOptionsEnabled
= AreLongOptionsEnabled();
657 name
= GetLongOptionName(p
, arg
.end());
659 if (longOptionsEnabled
)
661 optInd
= m_data
->FindOptionByLongName(name
);
662 if ( optInd
== wxNOT_FOUND
)
664 errorMsg
<< wxString::Format(_("Unknown long option '%s'"), name
.c_str())
670 optInd
= wxNOT_FOUND
; // Sanity check
672 // Print the argument including leading "--"
673 name
.Prepend( wxT("--") );
674 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
679 else // not a long option
683 // a short one: as they can be cumulated, we try to find the
684 // longest substring which is a valid option
685 wxString::const_iterator p
= arg
.begin() + 1;
687 name
= GetShortOptionName(p
, arg
.end());
689 size_t len
= name
.length();
694 // we couldn't find a valid option name in the
695 // beginning of this string
696 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
703 optInd
= m_data
->FindOption(name
.Left(len
));
705 // will try with one character less the next time
709 while ( optInd
== wxNOT_FOUND
);
711 len
++; // compensates extra len-- above
712 if ( (optInd
!= wxNOT_FOUND
) && (len
!= name
.length()) )
714 // first of all, the option name is only part of this
716 name
= name
.Left(len
);
718 // our option is only part of this argument, there is
719 // something else in it - it is either the value of this
720 // option or other switches if it is a switch
721 if ( m_data
->m_options
[(size_t)optInd
].kind
722 == wxCMD_LINE_SWITCH
)
724 // pretend that all the rest of the argument is the
725 // next argument, in fact
726 wxString arg2
= arg
[0u];
727 arg2
+= arg
.Mid(len
+ 1); // +1 for leading '-'
729 m_data
->m_arguments
.insert
730 (m_data
->m_arguments
.begin() + n
+ 1, arg2
);
733 //else: it's our value, we'll deal with it below
737 if ( optInd
== wxNOT_FOUND
)
741 continue; // will break, in fact
744 // look at what follows:
746 // +1 for leading '-'
747 wxString::const_iterator p
= arg
.begin() + 1 + name
.length();
748 wxString::const_iterator end
= arg
.end();
751 ++p
; // for another leading '-'
753 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)optInd
];
754 if ( opt
.kind
== wxCMD_LINE_SWITCH
)
756 // we must check that there is no value following the switch
757 if ( p
!= arg
.end() )
759 errorMsg
<< wxString::Format(_("Unexpected characters following option '%s'."), name
.c_str())
763 else // no value, as expected
765 // nothing more to do
768 if ( opt
.flags
& wxCMD_LINE_OPTION_HELP
)
770 helpRequested
= true;
772 // it's not an error, but we still stop here
777 else // it's an option. not a switch
779 switch ( p
== end
? '\0' : (*p
).GetValue() )
788 // the value is in the next argument
791 // ... but there is none
792 errorMsg
<< wxString::Format(_("Option '%s' requires a value."),
800 // ... take it from there
801 p
= m_data
->m_arguments
[n
].begin();
802 end
= m_data
->m_arguments
[n
].end();
807 // the value is right here: this may be legal or
808 // not depending on the option style
809 if ( opt
.flags
& wxCMD_LINE_NEEDS_SEPARATOR
)
811 errorMsg
<< wxString::Format(_("Separator expected after the option '%s'."),
821 wxString
value(p
, end
);
825 wxFAIL_MSG( _T("unknown option type") );
826 // still fall through
828 case wxCMD_LINE_VAL_STRING
:
829 opt
.SetStrVal(value
);
832 case wxCMD_LINE_VAL_NUMBER
:
835 if ( value
.ToLong(&val
) )
841 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
842 value
.c_str(), name
.c_str())
850 case wxCMD_LINE_VAL_DOUBLE
:
853 if ( value
.ToDouble(&val
) )
855 opt
.SetDoubleVal(val
);
859 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
860 value
.c_str(), name
.c_str())
869 case wxCMD_LINE_VAL_DATE
:
872 wxString::const_iterator end
;
873 if ( !dt
.ParseDate(value
) || end
!= value
.end() )
875 errorMsg
<< wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
876 name
.c_str(), value
.c_str())
887 #endif // wxUSE_DATETIME
892 else // not an option, must be a parameter
894 if ( currentParam
< countParam
)
896 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
898 // TODO check the param type
900 m_data
->m_parameters
.push_back(arg
);
902 if ( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) )
908 wxASSERT_MSG( currentParam
== countParam
- 1,
909 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
911 // remember that we did have this last repeatable parameter
912 hadRepeatableParam
= true;
917 errorMsg
<< wxString::Format(_("Unexpected parameter '%s'"), arg
.c_str())
925 // verify that all mandatory options were given
928 size_t countOpt
= m_data
->m_options
.GetCount();
929 for ( size_t n
= 0; ok
&& (n
< countOpt
); n
++ )
931 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
932 if ( (opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) && !opt
.HasValue() )
937 optName
= opt
.shortName
;
941 if ( AreLongOptionsEnabled() )
943 optName
.Printf( _("%s (or %s)"),
944 opt
.shortName
.c_str(),
945 opt
.longName
.c_str() );
949 optName
.Printf( wxT("%s"),
950 opt
.shortName
.c_str() );
954 errorMsg
<< wxString::Format(_("The value for the option '%s' must be specified."),
962 for ( ; ok
&& (currentParam
< countParam
); currentParam
++ )
964 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
965 if ( (currentParam
== countParam
- 1) &&
966 (param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) &&
969 // special case: currentParam wasn't incremented, but we did
970 // have it, so don't give error
974 if ( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
976 errorMsg
<< wxString::Format(_("The required parameter '%s' was not specified."),
977 param
.description
.c_str())
985 // if there was an error during parsing the command line, show this error
986 // and also the usage message if it had been requested
987 if ( !ok
&& (!errorMsg
.empty() || (helpRequested
&& showUsage
)) )
989 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
994 usage
= GetUsageString();
996 msgOut
->Printf( wxT("%s%s"), usage
.c_str(), errorMsg
.c_str() );
1000 wxFAIL_MSG( _T("no wxMessageOutput object?") );
1004 return ok
? 0 : helpRequested
? -1 : 1;
1007 // ----------------------------------------------------------------------------
1008 // give the usage message
1009 // ----------------------------------------------------------------------------
1011 void wxCmdLineParser::Usage() const
1013 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1016 msgOut
->Printf( wxT("%s"), GetUsageString().c_str() );
1020 wxFAIL_MSG( _T("no wxMessageOutput object?") );
1024 wxString
wxCmdLineParser::GetUsageString() const
1027 if ( m_data
->m_arguments
.empty() )
1030 appname
= wxTheApp
->GetAppName();
1034 appname
= wxFileName(m_data
->m_arguments
[0]).GetName();
1037 // we construct the brief cmd line desc on the fly, but not the detailed
1038 // help message below because we want to align the options descriptions
1039 // and for this we must first know the longest one of them
1041 wxArrayString namesOptions
, descOptions
;
1043 if ( !m_data
->m_logo
.empty() )
1045 usage
<< m_data
->m_logo
<< _T('\n');
1048 usage
<< wxString::Format(_("Usage: %s"), appname
.c_str());
1050 // the switch char is usually '-' but this can be changed with
1051 // SetSwitchChars() and then the first one of possible chars is used
1052 wxChar chSwitch
= !m_data
->m_switchChars
? _T('-')
1053 : m_data
->m_switchChars
[0u];
1055 bool areLongOptionsEnabled
= AreLongOptionsEnabled();
1056 size_t n
, count
= m_data
->m_options
.GetCount();
1057 for ( n
= 0; n
< count
; n
++ )
1059 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1062 if ( opt
.kind
!= wxCMD_LINE_USAGE_TEXT
)
1065 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1070 if ( !opt
.shortName
.empty() )
1072 usage
<< chSwitch
<< opt
.shortName
;
1074 else if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1076 usage
<< _T("--") << opt
.longName
;
1080 if (!opt
.longName
.empty())
1082 wxFAIL_MSG( wxT("option with only a long name while long ")
1083 wxT("options are disabled") );
1087 wxFAIL_MSG( _T("option without neither short nor long name") );
1091 if ( !opt
.shortName
.empty() )
1093 option
<< _T(" ") << chSwitch
<< opt
.shortName
;
1096 if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1098 option
<< (option
.empty() ? _T(" ") : _T(", "))
1099 << _T("--") << opt
.longName
;
1102 if ( opt
.kind
!= wxCMD_LINE_SWITCH
)
1105 val
<< _T('<') << GetTypeName(opt
.type
) << _T('>');
1106 usage
<< _T(' ') << val
;
1107 option
<< (!opt
.longName
? _T(':') : _T('=')) << val
;
1110 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1116 namesOptions
.push_back(option
);
1117 descOptions
.push_back(opt
.description
);
1120 count
= m_data
->m_paramDesc
.GetCount();
1121 for ( n
= 0; n
< count
; n
++ )
1123 wxCmdLineParam
& param
= m_data
->m_paramDesc
[n
];
1126 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1131 usage
<< param
.description
;
1133 if ( param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
)
1138 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1146 // set to number of our own options, not counting the standard ones
1147 count
= namesOptions
.size();
1149 // get option names & descriptions for standard options, if any:
1150 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
1153 stdDesc
= traits
->GetStandardCmdLineOptions(namesOptions
, descOptions
);
1155 // now construct the detailed help message
1156 size_t len
, lenMax
= 0;
1157 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1159 len
= namesOptions
[n
].length();
1164 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1167 usage
<< _T('\n') << stdDesc
;
1169 len
= namesOptions
[n
].length();
1170 // desc contains text if name is empty
1173 usage
<< descOptions
[n
] << _T('\n');
1177 usage
<< namesOptions
[n
]
1178 << wxString(_T(' '), lenMax
- len
) << _T('\t')
1187 // ----------------------------------------------------------------------------
1188 // private functions
1189 // ----------------------------------------------------------------------------
1191 static wxString
GetTypeName(wxCmdLineParamType type
)
1197 wxFAIL_MSG( _T("unknown option type") );
1198 // still fall through
1200 case wxCMD_LINE_VAL_STRING
:
1204 case wxCMD_LINE_VAL_NUMBER
:
1208 case wxCMD_LINE_VAL_DOUBLE
:
1212 case wxCMD_LINE_VAL_DATE
:
1221 Returns a string which is equal to the string pointed to by p, but up to the
1222 point where p contains an character that's not allowed.
1223 Allowable characters are letters and numbers, and characters pointed to by
1224 the parameter allowedChars.
1226 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1227 this function returns "abcde-".
1229 static wxString
GetOptionName(wxString::const_iterator p
,
1230 wxString::const_iterator end
,
1231 const wxChar
*allowedChars
)
1235 while ( p
!= end
&& (wxIsalnum(*p
) || wxStrchr(allowedChars
, *p
)) )
1243 // Besides alphanumeric characters, short and long options can
1244 // have other characters.
1246 // A short option additionally can have these
1247 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1249 // A long option can have the same characters as a short option and a '-'.
1250 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1251 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1253 static wxString
GetShortOptionName(wxString::const_iterator p
,
1254 wxString::const_iterator end
)
1256 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION
);
1259 static wxString
GetLongOptionName(wxString::const_iterator p
,
1260 wxString::const_iterator end
)
1262 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION
);
1265 #endif // wxUSE_CMDLINE_PARSER
1267 // ----------------------------------------------------------------------------
1269 // ----------------------------------------------------------------------------
1272 This function is mainly used under Windows (as under Unix we always get the
1273 command line arguments as argc/argv anyhow) and so it tries to follow
1274 Windows conventions for the command line handling, not Unix ones. For
1275 instance, backslash is not special except when it precedes double quote when
1281 wxCmdLineParser::ConvertStringToArgs(const wxString
& cmdline
,
1282 wxCmdLineSplitType type
)
1289 const wxString::const_iterator end
= cmdline
.end();
1290 wxString::const_iterator p
= cmdline
.begin();
1295 while ( p
!= end
&& (*p
== ' ' || *p
== '\t') )
1302 // parse this parameter
1303 bool lastBS
= false,
1304 isInsideQuotes
= false;
1305 wxChar chDelim
= '\0';
1306 for ( arg
.clear(); p
!= end
; ++p
)
1308 const wxChar ch
= *p
;
1310 if ( type
== wxCMD_LINE_SPLIT_DOS
)
1316 isInsideQuotes
= !isInsideQuotes
;
1318 // don't put quote in arg
1321 //else: quote has no special meaning but the backslash
1322 // still remains -- makes no sense but this is what
1325 // note that backslash does *not* quote the space, only quotes do
1326 else if ( !isInsideQuotes
&& (ch
== ' ' || ch
== '\t') )
1328 ++p
; // skip this space anyhow
1332 lastBS
= !lastBS
&& ch
== '\\';
1334 else // type == wxCMD_LINE_SPLIT_UNIX
1338 if ( isInsideQuotes
)
1340 if ( ch
== chDelim
)
1342 isInsideQuotes
= false;
1344 continue; // don't use the quote itself
1347 else // not in quotes and not escaped
1349 if ( ch
== '\'' || ch
== '"' )
1351 isInsideQuotes
= true;
1354 continue; // don't use the quote itself
1357 if ( ch
== ' ' || ch
== '\t' )
1359 ++p
; // skip this space anyhow
1364 lastBS
= ch
== '\\';
1368 else // escaped by backslash, just use as is
1377 args
.push_back(arg
);