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
, wxT("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
= wxT("-");
229 m_switchChars
= wxT("/-");
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( wxT("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 wxT("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 wxT("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 wxT("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 wxT("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, wxT("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, wxT("unknown option") );
509 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
510 if ( !opt
.HasValue() )
513 wxCHECK_MSG( value
, false, wxT("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, wxT("unknown option") );
528 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
529 if ( !opt
.HasValue() )
532 wxCHECK_MSG( value
, false, wxT("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, wxT("unknown option") );
547 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
548 if ( !opt
.HasValue() )
551 wxCHECK_MSG( value
, false, wxT("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, wxT("unknown option") );
567 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
568 if ( !opt
.HasValue() )
571 wxCHECK_MSG( value
, false, wxT("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
, wxT("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
== wxT("--") )
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] == wxT('-') && arg
[1u] == wxT('-') )
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 // only leave the part which wasn't extracted into the
734 // next argument in this one
735 arg
= arg
.Left(len
+ 1);
737 //else: it's our value, we'll deal with it below
741 if ( optInd
== wxNOT_FOUND
)
745 continue; // will break, in fact
748 // look at what follows:
750 // +1 for leading '-'
751 wxString::const_iterator p
= arg
.begin() + 1 + name
.length();
752 wxString::const_iterator end
= arg
.end();
755 ++p
; // for another leading '-'
757 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)optInd
];
758 if ( opt
.kind
== wxCMD_LINE_SWITCH
)
760 // we must check that there is no value following the switch
761 if ( p
!= arg
.end() )
763 errorMsg
<< wxString::Format(_("Unexpected characters following option '%s'."), name
.c_str())
767 else // no value, as expected
769 // nothing more to do
772 if ( opt
.flags
& wxCMD_LINE_OPTION_HELP
)
774 helpRequested
= true;
776 // it's not an error, but we still stop here
781 else // it's an option. not a switch
783 switch ( p
== end
? '\0' : (*p
).GetValue() )
792 // the value is in the next argument
795 // ... but there is none
796 errorMsg
<< wxString::Format(_("Option '%s' requires a value."),
804 // ... take it from there
805 p
= m_data
->m_arguments
[n
].begin();
806 end
= m_data
->m_arguments
[n
].end();
811 // the value is right here: this may be legal or
812 // not depending on the option style
813 if ( opt
.flags
& wxCMD_LINE_NEEDS_SEPARATOR
)
815 errorMsg
<< wxString::Format(_("Separator expected after the option '%s'."),
825 wxString
value(p
, end
);
829 wxFAIL_MSG( wxT("unknown option type") );
830 // still fall through
832 case wxCMD_LINE_VAL_STRING
:
833 opt
.SetStrVal(value
);
836 case wxCMD_LINE_VAL_NUMBER
:
839 if ( value
.ToLong(&val
) )
845 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
846 value
.c_str(), name
.c_str())
854 case wxCMD_LINE_VAL_DOUBLE
:
857 if ( value
.ToDouble(&val
) )
859 opt
.SetDoubleVal(val
);
863 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
864 value
.c_str(), name
.c_str())
873 case wxCMD_LINE_VAL_DATE
:
876 wxString::const_iterator end
;
877 if ( !dt
.ParseDate(value
, &end
) || end
!= value
.end() )
879 errorMsg
<< wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
880 name
.c_str(), value
.c_str())
891 #endif // wxUSE_DATETIME
896 else // not an option, must be a parameter
898 if ( currentParam
< countParam
)
900 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
902 // TODO check the param type
904 m_data
->m_parameters
.push_back(arg
);
906 if ( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) )
912 wxASSERT_MSG( currentParam
== countParam
- 1,
913 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
915 // remember that we did have this last repeatable parameter
916 hadRepeatableParam
= true;
921 errorMsg
<< wxString::Format(_("Unexpected parameter '%s'"), arg
.c_str())
929 // verify that all mandatory options were given
932 size_t countOpt
= m_data
->m_options
.GetCount();
933 for ( size_t n
= 0; ok
&& (n
< countOpt
); n
++ )
935 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
936 if ( (opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) && !opt
.HasValue() )
941 optName
= opt
.shortName
;
945 if ( AreLongOptionsEnabled() )
947 optName
.Printf( _("%s (or %s)"),
948 opt
.shortName
.c_str(),
949 opt
.longName
.c_str() );
953 optName
.Printf( wxT("%s"),
954 opt
.shortName
.c_str() );
958 errorMsg
<< wxString::Format(_("The value for the option '%s' must be specified."),
966 for ( ; ok
&& (currentParam
< countParam
); currentParam
++ )
968 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
969 if ( (currentParam
== countParam
- 1) &&
970 (param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) &&
973 // special case: currentParam wasn't incremented, but we did
974 // have it, so don't give error
978 if ( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
980 errorMsg
<< wxString::Format(_("The required parameter '%s' was not specified."),
981 param
.description
.c_str())
989 // if there was an error during parsing the command line, show this error
990 // and also the usage message if it had been requested
991 if ( !ok
&& (!errorMsg
.empty() || (helpRequested
&& showUsage
)) )
993 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
998 usage
= GetUsageString();
1000 msgOut
->Printf( wxT("%s%s"), usage
.c_str(), errorMsg
.c_str() );
1004 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1008 return ok
? 0 : helpRequested
? -1 : 1;
1011 // ----------------------------------------------------------------------------
1012 // give the usage message
1013 // ----------------------------------------------------------------------------
1015 void wxCmdLineParser::Usage() const
1017 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1020 msgOut
->Printf( wxT("%s"), GetUsageString().c_str() );
1024 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1028 wxString
wxCmdLineParser::GetUsageString() const
1031 if ( m_data
->m_arguments
.empty() )
1034 appname
= wxTheApp
->GetAppName();
1038 appname
= wxFileName(m_data
->m_arguments
[0]).GetName();
1041 // we construct the brief cmd line desc on the fly, but not the detailed
1042 // help message below because we want to align the options descriptions
1043 // and for this we must first know the longest one of them
1045 wxArrayString namesOptions
, descOptions
;
1047 if ( !m_data
->m_logo
.empty() )
1049 usage
<< m_data
->m_logo
<< wxT('\n');
1052 usage
<< wxString::Format(_("Usage: %s"), appname
.c_str());
1054 // the switch char is usually '-' but this can be changed with
1055 // SetSwitchChars() and then the first one of possible chars is used
1056 wxChar chSwitch
= !m_data
->m_switchChars
? wxT('-')
1057 : m_data
->m_switchChars
[0u];
1059 bool areLongOptionsEnabled
= AreLongOptionsEnabled();
1060 size_t n
, count
= m_data
->m_options
.GetCount();
1061 for ( n
= 0; n
< count
; n
++ )
1063 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1066 if ( opt
.kind
!= wxCMD_LINE_USAGE_TEXT
)
1069 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1074 if ( !opt
.shortName
.empty() )
1076 usage
<< chSwitch
<< opt
.shortName
;
1078 else if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1080 usage
<< wxT("--") << opt
.longName
;
1084 if (!opt
.longName
.empty())
1086 wxFAIL_MSG( wxT("option with only a long name while long ")
1087 wxT("options are disabled") );
1091 wxFAIL_MSG( wxT("option without neither short nor long name") );
1095 if ( !opt
.shortName
.empty() )
1097 option
<< wxT(" ") << chSwitch
<< opt
.shortName
;
1100 if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1102 option
<< (option
.empty() ? wxT(" ") : wxT(", "))
1103 << wxT("--") << opt
.longName
;
1106 if ( opt
.kind
!= wxCMD_LINE_SWITCH
)
1109 val
<< wxT('<') << GetTypeName(opt
.type
) << wxT('>');
1110 usage
<< wxT(' ') << val
;
1111 option
<< (!opt
.longName
? wxT(':') : wxT('=')) << val
;
1114 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1120 namesOptions
.push_back(option
);
1121 descOptions
.push_back(opt
.description
);
1124 count
= m_data
->m_paramDesc
.GetCount();
1125 for ( n
= 0; n
< count
; n
++ )
1127 wxCmdLineParam
& param
= m_data
->m_paramDesc
[n
];
1130 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1135 usage
<< param
.description
;
1137 if ( param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
)
1139 usage
<< wxT("...");
1142 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1150 // set to number of our own options, not counting the standard ones
1151 count
= namesOptions
.size();
1153 // get option names & descriptions for standard options, if any:
1154 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
1157 stdDesc
= traits
->GetStandardCmdLineOptions(namesOptions
, descOptions
);
1159 // now construct the detailed help message
1160 size_t len
, lenMax
= 0;
1161 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1163 len
= namesOptions
[n
].length();
1168 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1171 usage
<< wxT('\n') << stdDesc
;
1173 len
= namesOptions
[n
].length();
1174 // desc contains text if name is empty
1177 usage
<< descOptions
[n
] << wxT('\n');
1181 usage
<< namesOptions
[n
]
1182 << wxString(wxT(' '), lenMax
- len
) << wxT('\t')
1191 // ----------------------------------------------------------------------------
1192 // private functions
1193 // ----------------------------------------------------------------------------
1195 static wxString
GetTypeName(wxCmdLineParamType type
)
1201 wxFAIL_MSG( wxT("unknown option type") );
1202 // still fall through
1204 case wxCMD_LINE_VAL_STRING
:
1208 case wxCMD_LINE_VAL_NUMBER
:
1212 case wxCMD_LINE_VAL_DOUBLE
:
1216 case wxCMD_LINE_VAL_DATE
:
1225 Returns a string which is equal to the string pointed to by p, but up to the
1226 point where p contains an character that's not allowed.
1227 Allowable characters are letters and numbers, and characters pointed to by
1228 the parameter allowedChars.
1230 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1231 this function returns "abcde-".
1233 static wxString
GetOptionName(wxString::const_iterator p
,
1234 wxString::const_iterator end
,
1235 const wxChar
*allowedChars
)
1239 while ( p
!= end
&& (wxIsalnum(*p
) || wxStrchr(allowedChars
, *p
)) )
1247 // Besides alphanumeric characters, short and long options can
1248 // have other characters.
1250 // A short option additionally can have these
1251 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1253 // A long option can have the same characters as a short option and a '-'.
1254 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1255 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1257 static wxString
GetShortOptionName(wxString::const_iterator p
,
1258 wxString::const_iterator end
)
1260 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION
);
1263 static wxString
GetLongOptionName(wxString::const_iterator p
,
1264 wxString::const_iterator end
)
1266 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION
);
1269 #endif // wxUSE_CMDLINE_PARSER
1271 // ----------------------------------------------------------------------------
1273 // ----------------------------------------------------------------------------
1276 This function is mainly used under Windows (as under Unix we always get the
1277 command line arguments as argc/argv anyhow) and so it tries to follow
1278 Windows conventions for the command line handling, not Unix ones. For
1279 instance, backslash is not special except when it precedes double quote when
1285 wxCmdLineParser::ConvertStringToArgs(const wxString
& cmdline
,
1286 wxCmdLineSplitType type
)
1293 const wxString::const_iterator end
= cmdline
.end();
1294 wxString::const_iterator p
= cmdline
.begin();
1299 while ( p
!= end
&& (*p
== ' ' || *p
== '\t') )
1306 // parse this parameter
1307 bool lastBS
= false,
1308 isInsideQuotes
= false;
1309 wxChar chDelim
= '\0';
1310 for ( arg
.clear(); p
!= end
; ++p
)
1312 const wxChar ch
= *p
;
1314 if ( type
== wxCMD_LINE_SPLIT_DOS
)
1320 isInsideQuotes
= !isInsideQuotes
;
1322 // don't put quote in arg
1325 //else: quote has no special meaning but the backslash
1326 // still remains -- makes no sense but this is what
1329 // note that backslash does *not* quote the space, only quotes do
1330 else if ( !isInsideQuotes
&& (ch
== ' ' || ch
== '\t') )
1332 ++p
; // skip this space anyhow
1336 lastBS
= !lastBS
&& ch
== '\\';
1338 else // type == wxCMD_LINE_SPLIT_UNIX
1342 if ( isInsideQuotes
)
1344 if ( ch
== chDelim
)
1346 isInsideQuotes
= false;
1348 continue; // don't use the quote itself
1351 else // not in quotes and not escaped
1353 if ( ch
== '\'' || ch
== '"' )
1355 isInsideQuotes
= true;
1358 continue; // don't use the quote itself
1361 if ( ch
== ' ' || ch
== '\t' )
1363 ++p
; // skip this space anyhow
1368 lastBS
= ch
== '\\';
1372 else // escaped by backslash, just use as is
1381 args
.push_back(arg
);