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
78 if ( k
!= wxCMD_LINE_USAGE_TEXT
)
82 !shrt
.empty() || !lng
.empty(),
83 wxT("option should have at least one name")
88 GetShortOptionName(shrt
.begin(), shrt
.end()).Len() == shrt
.Len(),
89 wxT("Short option contains invalid characters")
94 GetLongOptionName(lng
.begin(), lng
.end()).Len() == lng
.Len(),
95 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
, _T("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
; }
149 wxCmdLineEntryType kind
;
153 wxCmdLineParamType type
;
163 wxDateTime m_dateVal
;
164 #endif // wxUSE_DATETIME
167 struct wxCmdLineParam
169 wxCmdLineParam(const wxString
& desc
,
170 wxCmdLineParamType typ
,
178 wxString description
;
179 wxCmdLineParamType type
;
183 WX_DECLARE_OBJARRAY(wxCmdLineOption
, wxArrayOptions
);
184 WX_DECLARE_OBJARRAY(wxCmdLineParam
, wxArrayParams
);
186 #include "wx/arrimpl.cpp"
188 WX_DEFINE_OBJARRAY(wxArrayOptions
)
189 WX_DEFINE_OBJARRAY(wxArrayParams
)
191 // the parser internal state
192 struct wxCmdLineParserData
195 wxString m_switchChars
; // characters which may start an option
196 bool m_enableLongOptions
; // true if long options are enabled
197 wxString m_logo
; // some extra text to show in Usage()
200 wxArrayString m_arguments
; // == argv, argc == m_arguments.GetCount()
201 wxArrayOptions m_options
; // all possible options and switches
202 wxArrayParams m_paramDesc
; // description of all possible params
203 wxArrayString m_parameters
; // all params found
206 wxCmdLineParserData();
207 void SetArguments(int argc
, char **argv
);
209 void SetArguments(int argc
, wxChar
**argv
);
210 void SetArguments(int argc
, const wxCmdLineArgsArray
& argv
);
211 #endif // wxUSE_UNICODE
212 void SetArguments(const wxString
& cmdline
);
214 int FindOption(const wxString
& name
);
215 int FindOptionByLongName(const wxString
& name
);
218 // ============================================================================
220 // ============================================================================
222 // ----------------------------------------------------------------------------
223 // wxCmdLineParserData
224 // ----------------------------------------------------------------------------
226 wxCmdLineParserData::wxCmdLineParserData()
228 m_enableLongOptions
= true;
230 m_switchChars
= _T("-");
232 m_switchChars
= _T("/-");
236 void wxCmdLineParserData::SetArguments(int argc
, char **argv
)
240 for ( int n
= 0; n
< argc
; n
++ )
242 m_arguments
.push_back(wxString::FromAscii(argv
[n
]));
248 void wxCmdLineParserData::SetArguments(int argc
, wxChar
**argv
)
252 for ( int n
= 0; n
< argc
; n
++ )
254 m_arguments
.push_back(argv
[n
]);
258 void wxCmdLineParserData::SetArguments(int WXUNUSED(argc
),
259 const wxCmdLineArgsArray
& argv
)
261 m_arguments
= argv
.GetArguments();
264 #endif // wxUSE_UNICODE
266 void wxCmdLineParserData::SetArguments(const wxString
& cmdLine
)
270 if(wxTheApp
&& wxTheApp
->argc
> 0)
271 m_arguments
.push_back(wxTheApp
->argv
[0]);
273 m_arguments
.push_back(wxEmptyString
);
275 wxArrayString args
= wxCmdLineParser::ConvertStringToArgs(cmdLine
);
277 WX_APPEND_ARRAY(m_arguments
, args
);
280 int wxCmdLineParserData::FindOption(const wxString
& name
)
284 size_t count
= m_options
.GetCount();
285 for ( size_t n
= 0; n
< count
; n
++ )
287 if ( m_options
[n
].shortName
== name
)
298 int wxCmdLineParserData::FindOptionByLongName(const wxString
& name
)
300 size_t count
= m_options
.GetCount();
301 for ( size_t n
= 0; n
< count
; n
++ )
303 if ( m_options
[n
].longName
== name
)
313 // ----------------------------------------------------------------------------
314 // construction and destruction
315 // ----------------------------------------------------------------------------
317 void wxCmdLineParser::Init()
319 m_data
= new wxCmdLineParserData
;
322 void wxCmdLineParser::SetCmdLine(int argc
, char **argv
)
324 m_data
->SetArguments(argc
, argv
);
329 void wxCmdLineParser::SetCmdLine(int argc
, wxChar
**argv
)
331 m_data
->SetArguments(argc
, argv
);
334 void wxCmdLineParser::SetCmdLine(int argc
, const wxCmdLineArgsArray
& argv
)
336 m_data
->SetArguments(argc
, argv
);
339 #endif // wxUSE_UNICODE
341 void wxCmdLineParser::SetCmdLine(const wxString
& cmdline
)
343 m_data
->SetArguments(cmdline
);
346 wxCmdLineParser::~wxCmdLineParser()
351 // ----------------------------------------------------------------------------
353 // ----------------------------------------------------------------------------
355 void wxCmdLineParser::SetSwitchChars(const wxString
& switchChars
)
357 m_data
->m_switchChars
= switchChars
;
360 void wxCmdLineParser::EnableLongOptions(bool enable
)
362 m_data
->m_enableLongOptions
= enable
;
365 bool wxCmdLineParser::AreLongOptionsEnabled() const
367 return m_data
->m_enableLongOptions
;
370 void wxCmdLineParser::SetLogo(const wxString
& logo
)
372 m_data
->m_logo
= logo
;
375 // ----------------------------------------------------------------------------
376 // command line construction
377 // ----------------------------------------------------------------------------
379 void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc
*desc
)
383 switch ( desc
->kind
)
385 case wxCMD_LINE_SWITCH
:
386 AddSwitch(desc
->shortName
, desc
->longName
,
387 wxGetTranslation(desc
->description
),
391 case wxCMD_LINE_OPTION
:
392 AddOption(desc
->shortName
, desc
->longName
,
393 wxGetTranslation(desc
->description
),
394 desc
->type
, desc
->flags
);
397 case wxCMD_LINE_PARAM
:
398 AddParam(wxGetTranslation(desc
->description
),
399 desc
->type
, desc
->flags
);
402 case wxCMD_LINE_USAGE_TEXT
:
403 AddUsageText(wxGetTranslation(desc
->description
));
407 wxFAIL_MSG( _T("unknown command line entry type") );
408 // still fall through
410 case wxCMD_LINE_NONE
:
416 void wxCmdLineParser::AddSwitch(const wxString
& shortName
,
417 const wxString
& longName
,
418 const wxString
& desc
,
421 wxASSERT_MSG( m_data
->FindOption(shortName
) == wxNOT_FOUND
,
422 _T("duplicate switch") );
424 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_SWITCH
,
425 shortName
, longName
, desc
,
426 wxCMD_LINE_VAL_NONE
, flags
);
428 m_data
->m_options
.Add(option
);
431 void wxCmdLineParser::AddOption(const wxString
& shortName
,
432 const wxString
& longName
,
433 const wxString
& desc
,
434 wxCmdLineParamType type
,
437 wxASSERT_MSG( m_data
->FindOption(shortName
) == wxNOT_FOUND
,
438 _T("duplicate option") );
440 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_OPTION
,
441 shortName
, longName
, desc
,
444 m_data
->m_options
.Add(option
);
447 void wxCmdLineParser::AddParam(const wxString
& desc
,
448 wxCmdLineParamType type
,
451 // do some consistency checks: a required parameter can't follow an
452 // optional one and nothing should follow a parameter with MULTIPLE flag
454 if ( !m_data
->m_paramDesc
.IsEmpty() )
456 wxCmdLineParam
& param
= m_data
->m_paramDesc
.Last();
458 wxASSERT_MSG( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
),
459 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
461 if ( !(flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
463 wxASSERT_MSG( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
),
464 _T("a required parameter can't follow an optional one") );
469 wxCmdLineParam
*param
= new wxCmdLineParam(desc
, type
, flags
);
471 m_data
->m_paramDesc
.Add(param
);
474 void wxCmdLineParser::AddUsageText(const wxString
& text
)
476 wxASSERT_MSG( !text
.empty(), wxT("text can't be empty") );
478 wxCmdLineOption
*option
= new wxCmdLineOption(wxCMD_LINE_USAGE_TEXT
,
479 wxEmptyString
, wxEmptyString
,
480 text
, wxCMD_LINE_VAL_NONE
, 0);
482 m_data
->m_options
.Add(option
);
485 // ----------------------------------------------------------------------------
486 // access to parse command line
487 // ----------------------------------------------------------------------------
489 bool wxCmdLineParser::Found(const wxString
& name
) const
491 int i
= m_data
->FindOption(name
);
492 if ( i
== wxNOT_FOUND
)
493 i
= m_data
->FindOptionByLongName(name
);
495 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, _T("unknown switch") );
497 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
498 if ( !opt
.HasValue() )
504 bool wxCmdLineParser::Found(const wxString
& name
, wxString
*value
) const
506 int i
= m_data
->FindOption(name
);
507 if ( i
== wxNOT_FOUND
)
508 i
= m_data
->FindOptionByLongName(name
);
510 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, _T("unknown option") );
512 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
513 if ( !opt
.HasValue() )
516 wxCHECK_MSG( value
, false, _T("NULL pointer in wxCmdLineOption::Found") );
518 *value
= opt
.GetStrVal();
523 bool wxCmdLineParser::Found(const wxString
& name
, long *value
) const
525 int i
= m_data
->FindOption(name
);
526 if ( i
== wxNOT_FOUND
)
527 i
= m_data
->FindOptionByLongName(name
);
529 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, _T("unknown option") );
531 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
532 if ( !opt
.HasValue() )
535 wxCHECK_MSG( value
, false, _T("NULL pointer in wxCmdLineOption::Found") );
537 *value
= opt
.GetLongVal();
542 bool wxCmdLineParser::Found(const wxString
& name
, double *value
) const
544 int i
= m_data
->FindOption(name
);
545 if ( i
== wxNOT_FOUND
)
546 i
= m_data
->FindOptionByLongName(name
);
548 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, _T("unknown option") );
550 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
551 if ( !opt
.HasValue() )
554 wxCHECK_MSG( value
, false, _T("NULL pointer in wxCmdLineOption::Found") );
556 *value
= opt
.GetDoubleVal();
562 bool wxCmdLineParser::Found(const wxString
& name
, wxDateTime
*value
) const
564 int i
= m_data
->FindOption(name
);
565 if ( i
== wxNOT_FOUND
)
566 i
= m_data
->FindOptionByLongName(name
);
568 wxCHECK_MSG( i
!= wxNOT_FOUND
, false, _T("unknown option") );
570 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)i
];
571 if ( !opt
.HasValue() )
574 wxCHECK_MSG( value
, false, _T("NULL pointer in wxCmdLineOption::Found") );
576 *value
= opt
.GetDateVal();
580 #endif // wxUSE_DATETIME
582 size_t wxCmdLineParser::GetParamCount() const
584 return m_data
->m_parameters
.size();
587 wxString
wxCmdLineParser::GetParam(size_t n
) const
589 wxCHECK_MSG( n
< GetParamCount(), wxEmptyString
, _T("invalid param index") );
591 return m_data
->m_parameters
[n
];
594 // Resets switches and options
595 void wxCmdLineParser::Reset()
597 for ( size_t i
= 0; i
< m_data
->m_options
.GetCount(); i
++ )
599 wxCmdLineOption
& opt
= m_data
->m_options
[i
];
600 opt
.SetHasValue(false);
605 // ----------------------------------------------------------------------------
606 // the real work is done here
607 // ----------------------------------------------------------------------------
609 int wxCmdLineParser::Parse(bool showUsage
)
611 bool maybeOption
= true; // can the following arg be an option?
612 bool ok
= true; // true until an error is detected
613 bool helpRequested
= false; // true if "-h" was given
614 bool hadRepeatableParam
= false; // true if found param with MULTIPLE flag
616 size_t currentParam
= 0; // the index in m_paramDesc
618 size_t countParam
= m_data
->m_paramDesc
.GetCount();
625 size_t count
= m_data
->m_arguments
.size();
626 for ( size_t n
= 1; ok
&& (n
< count
); n
++ ) // 0 is program name
628 arg
= m_data
->m_arguments
[n
];
630 // special case: "--" should be discarded and all following arguments
631 // should be considered as parameters, even if they start with '-' and
632 // not like options (this is POSIX-like)
633 if ( arg
== _T("--") )
640 // empty argument or just '-' is not an option but a parameter
641 if ( maybeOption
&& arg
.length() > 1 &&
642 // FIXME-UTF8: use wc_str() after removing ANSI build
643 wxStrchr(m_data
->m_switchChars
.c_str(), arg
[0u]) )
647 int optInd
= wxNOT_FOUND
; // init to suppress warnings
649 // an option or a switch: find whether it's a long or a short one
650 if ( arg
.length() >= 3 && arg
[0u] == _T('-') && arg
[1u] == _T('-') )
656 wxString::const_iterator p
= arg
.begin() + 2;
658 bool longOptionsEnabled
= AreLongOptionsEnabled();
660 name
= GetLongOptionName(p
, arg
.end());
662 if (longOptionsEnabled
)
664 optInd
= m_data
->FindOptionByLongName(name
);
665 if ( optInd
== wxNOT_FOUND
)
667 errorMsg
<< wxString::Format(_("Unknown long option '%s'"), name
.c_str())
673 optInd
= wxNOT_FOUND
; // Sanity check
675 // Print the argument including leading "--"
676 name
.Prepend( wxT("--") );
677 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
682 else // not a long option
686 // a short one: as they can be cumulated, we try to find the
687 // longest substring which is a valid option
688 wxString::const_iterator p
= arg
.begin() + 1;
690 name
= GetShortOptionName(p
, arg
.end());
692 size_t len
= name
.length();
697 // we couldn't find a valid option name in the
698 // beginning of this string
699 errorMsg
<< wxString::Format(_("Unknown option '%s'"), name
.c_str())
706 optInd
= m_data
->FindOption(name
.Left(len
));
708 // will try with one character less the next time
712 while ( optInd
== wxNOT_FOUND
);
714 len
++; // compensates extra len-- above
715 if ( (optInd
!= wxNOT_FOUND
) && (len
!= name
.length()) )
717 // first of all, the option name is only part of this
719 name
= name
.Left(len
);
721 // our option is only part of this argument, there is
722 // something else in it - it is either the value of this
723 // option or other switches if it is a switch
724 if ( m_data
->m_options
[(size_t)optInd
].kind
725 == wxCMD_LINE_SWITCH
)
727 // pretend that all the rest of the argument is the
728 // next argument, in fact
729 wxString arg2
= arg
[0u];
730 arg2
+= arg
.Mid(len
+ 1); // +1 for leading '-'
732 m_data
->m_arguments
.insert
733 (m_data
->m_arguments
.begin() + n
+ 1, arg2
);
736 //else: it's our value, we'll deal with it below
740 if ( optInd
== wxNOT_FOUND
)
744 continue; // will break, in fact
747 // look at what follows:
749 // +1 for leading '-'
750 wxString::const_iterator p
= arg
.begin() + 1 + name
.length();
751 wxString::const_iterator end
= arg
.end();
754 ++p
; // for another leading '-'
756 wxCmdLineOption
& opt
= m_data
->m_options
[(size_t)optInd
];
757 if ( opt
.kind
== wxCMD_LINE_SWITCH
)
759 // we must check that there is no value following the switch
760 if ( p
!= arg
.end() )
762 errorMsg
<< wxString::Format(_("Unexpected characters following option '%s'."), name
.c_str())
766 else // no value, as expected
768 // nothing more to do
771 if ( opt
.flags
& wxCMD_LINE_OPTION_HELP
)
773 helpRequested
= true;
775 // it's not an error, but we still stop here
780 else // it's an option. not a switch
782 switch ( p
== end
? '\0' : (*p
).GetValue() )
791 // the value is in the next argument
794 // ... but there is none
795 errorMsg
<< wxString::Format(_("Option '%s' requires a value."),
803 // ... take it from there
804 p
= m_data
->m_arguments
[n
].begin();
805 end
= m_data
->m_arguments
[n
].end();
810 // the value is right here: this may be legal or
811 // not depending on the option style
812 if ( opt
.flags
& wxCMD_LINE_NEEDS_SEPARATOR
)
814 errorMsg
<< wxString::Format(_("Separator expected after the option '%s'."),
824 wxString
value(p
, end
);
828 wxFAIL_MSG( _T("unknown option type") );
829 // still fall through
831 case wxCMD_LINE_VAL_STRING
:
832 opt
.SetStrVal(value
);
835 case wxCMD_LINE_VAL_NUMBER
:
838 if ( value
.ToLong(&val
) )
844 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
845 value
.c_str(), name
.c_str())
853 case wxCMD_LINE_VAL_DOUBLE
:
856 if ( value
.ToDouble(&val
) )
858 opt
.SetDoubleVal(val
);
862 errorMsg
<< wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
863 value
.c_str(), name
.c_str())
872 case wxCMD_LINE_VAL_DATE
:
875 const char *res
= dt
.ParseDate(value
);
878 errorMsg
<< wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
879 name
.c_str(), value
.c_str())
890 #endif // wxUSE_DATETIME
895 else // not an option, must be a parameter
897 if ( currentParam
< countParam
)
899 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
901 // TODO check the param type
903 m_data
->m_parameters
.push_back(arg
);
905 if ( !(param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) )
911 wxASSERT_MSG( currentParam
== countParam
- 1,
912 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
914 // remember that we did have this last repeatable parameter
915 hadRepeatableParam
= true;
920 errorMsg
<< wxString::Format(_("Unexpected parameter '%s'"), arg
.c_str())
928 // verify that all mandatory options were given
931 size_t countOpt
= m_data
->m_options
.GetCount();
932 for ( size_t n
= 0; ok
&& (n
< countOpt
); n
++ )
934 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
935 if ( (opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) && !opt
.HasValue() )
940 optName
= opt
.shortName
;
944 if ( AreLongOptionsEnabled() )
946 optName
.Printf( _("%s (or %s)"),
947 opt
.shortName
.c_str(),
948 opt
.longName
.c_str() );
952 optName
.Printf( wxT("%s"),
953 opt
.shortName
.c_str() );
957 errorMsg
<< wxString::Format(_("The value for the option '%s' must be specified."),
965 for ( ; ok
&& (currentParam
< countParam
); currentParam
++ )
967 wxCmdLineParam
& param
= m_data
->m_paramDesc
[currentParam
];
968 if ( (currentParam
== countParam
- 1) &&
969 (param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
) &&
972 // special case: currentParam wasn't incremented, but we did
973 // have it, so don't give error
977 if ( !(param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
) )
979 errorMsg
<< wxString::Format(_("The required parameter '%s' was not specified."),
980 param
.description
.c_str())
988 // if there was an error during parsing the command line, show this error
989 // and also the usage message if it had been requested
990 if ( !ok
&& (!errorMsg
.empty() || (helpRequested
&& showUsage
)) )
992 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
997 usage
= GetUsageString();
999 msgOut
->Printf( wxT("%s%s"), usage
.c_str(), errorMsg
.c_str() );
1003 wxFAIL_MSG( _T("no wxMessageOutput object?") );
1007 return ok
? 0 : helpRequested
? -1 : 1;
1010 // ----------------------------------------------------------------------------
1011 // give the usage message
1012 // ----------------------------------------------------------------------------
1014 void wxCmdLineParser::Usage() const
1016 wxMessageOutput
* msgOut
= wxMessageOutput::Get();
1019 msgOut
->Printf( wxT("%s"), GetUsageString().c_str() );
1023 wxFAIL_MSG( _T("no wxMessageOutput object?") );
1027 wxString
wxCmdLineParser::GetUsageString() const
1030 if ( m_data
->m_arguments
.empty() )
1033 appname
= wxTheApp
->GetAppName();
1037 appname
= wxFileName(m_data
->m_arguments
[0]).GetName();
1040 // we construct the brief cmd line desc on the fly, but not the detailed
1041 // help message below because we want to align the options descriptions
1042 // and for this we must first know the longest one of them
1044 wxArrayString namesOptions
, descOptions
;
1046 if ( !m_data
->m_logo
.empty() )
1048 usage
<< m_data
->m_logo
<< _T('\n');
1051 usage
<< wxString::Format(_("Usage: %s"), appname
.c_str());
1053 // the switch char is usually '-' but this can be changed with
1054 // SetSwitchChars() and then the first one of possible chars is used
1055 wxChar chSwitch
= !m_data
->m_switchChars
? _T('-')
1056 : m_data
->m_switchChars
[0u];
1058 bool areLongOptionsEnabled
= AreLongOptionsEnabled();
1059 size_t n
, count
= m_data
->m_options
.GetCount();
1060 for ( n
= 0; n
< count
; n
++ )
1062 wxCmdLineOption
& opt
= m_data
->m_options
[n
];
1065 if ( opt
.kind
!= wxCMD_LINE_USAGE_TEXT
)
1068 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1073 if ( !opt
.shortName
.empty() )
1075 usage
<< chSwitch
<< opt
.shortName
;
1077 else if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1079 usage
<< _T("--") << opt
.longName
;
1083 if (!opt
.longName
.empty())
1085 wxFAIL_MSG( wxT("option with only a long name while long ")
1086 wxT("options are disabled") );
1090 wxFAIL_MSG( _T("option without neither short nor long name") );
1094 if ( !opt
.shortName
.empty() )
1096 option
<< _T(" ") << chSwitch
<< opt
.shortName
;
1099 if ( areLongOptionsEnabled
&& !opt
.longName
.empty() )
1101 option
<< (option
.empty() ? _T(" ") : _T(", "))
1102 << _T("--") << opt
.longName
;
1105 if ( opt
.kind
!= wxCMD_LINE_SWITCH
)
1108 val
<< _T('<') << GetTypeName(opt
.type
) << _T('>');
1109 usage
<< _T(' ') << val
;
1110 option
<< (!opt
.longName
? _T(':') : _T('=')) << val
;
1113 if ( !(opt
.flags
& wxCMD_LINE_OPTION_MANDATORY
) )
1119 namesOptions
.push_back(option
);
1120 descOptions
.push_back(opt
.description
);
1123 count
= m_data
->m_paramDesc
.GetCount();
1124 for ( n
= 0; n
< count
; n
++ )
1126 wxCmdLineParam
& param
= m_data
->m_paramDesc
[n
];
1129 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1134 usage
<< param
.description
;
1136 if ( param
.flags
& wxCMD_LINE_PARAM_MULTIPLE
)
1141 if ( param
.flags
& wxCMD_LINE_PARAM_OPTIONAL
)
1149 // set to number of our own options, not counting the standard ones
1150 count
= namesOptions
.size();
1152 // get option names & descriptions for standard options, if any:
1153 wxAppTraits
*traits
= wxTheApp
? wxTheApp
->GetTraits() : NULL
;
1156 stdDesc
= traits
->GetStandardCmdLineOptions(namesOptions
, descOptions
);
1158 // now construct the detailed help message
1159 size_t len
, lenMax
= 0;
1160 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1162 len
= namesOptions
[n
].length();
1167 for ( n
= 0; n
< namesOptions
.size(); n
++ )
1170 usage
<< _T('\n') << stdDesc
;
1172 len
= namesOptions
[n
].length();
1173 // desc contains text if name is empty
1176 usage
<< descOptions
[n
] << _T('\n');
1180 usage
<< namesOptions
[n
]
1181 << wxString(_T(' '), lenMax
- len
) << _T('\t')
1190 // ----------------------------------------------------------------------------
1191 // private functions
1192 // ----------------------------------------------------------------------------
1194 static wxString
GetTypeName(wxCmdLineParamType type
)
1200 wxFAIL_MSG( _T("unknown option type") );
1201 // still fall through
1203 case wxCMD_LINE_VAL_STRING
:
1207 case wxCMD_LINE_VAL_NUMBER
:
1211 case wxCMD_LINE_VAL_DOUBLE
:
1215 case wxCMD_LINE_VAL_DATE
:
1224 Returns a string which is equal to the string pointed to by p, but up to the
1225 point where p contains an character that's not allowed.
1226 Allowable characters are letters and numbers, and characters pointed to by
1227 the parameter allowedChars.
1229 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1230 this function returns "abcde-".
1232 static wxString
GetOptionName(wxString::const_iterator p
,
1233 wxString::const_iterator end
,
1234 const wxChar
*allowedChars
)
1238 while ( p
!= end
&& (wxIsalnum(*p
) || wxStrchr(allowedChars
, *p
)) )
1246 // Besides alphanumeric characters, short and long options can
1247 // have other characters.
1249 // A short option additionally can have these
1250 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1252 // A long option can have the same characters as a short option and a '-'.
1253 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1254 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1256 static wxString
GetShortOptionName(wxString::const_iterator p
,
1257 wxString::const_iterator end
)
1259 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION
);
1262 static wxString
GetLongOptionName(wxString::const_iterator p
,
1263 wxString::const_iterator end
)
1265 return GetOptionName(p
, end
, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION
);
1268 #endif // wxUSE_CMDLINE_PARSER
1270 // ----------------------------------------------------------------------------
1272 // ----------------------------------------------------------------------------
1275 This function is mainly used under Windows (as under Unix we always get the
1276 command line arguments as argc/argv anyhow) and so it tries to follow
1277 Windows conventions for the command line handling, not Unix ones. For
1278 instance, backslash is not special except when it precedes double quote when
1284 wxCmdLineParser::ConvertStringToArgs(const wxString
& cmdline
,
1285 wxCmdLineSplitType type
)
1292 const wxString::const_iterator end
= cmdline
.end();
1293 wxString::const_iterator p
= cmdline
.begin();
1298 while ( p
!= end
&& (*p
== ' ' || *p
== '\t') )
1305 // parse this parameter
1306 bool lastBS
= false,
1307 isInsideQuotes
= false;
1308 wxChar chDelim
= '\0';
1309 for ( arg
.clear(); p
!= end
; ++p
)
1311 const wxChar ch
= *p
;
1313 if ( type
== wxCMD_LINE_SPLIT_DOS
)
1319 isInsideQuotes
= !isInsideQuotes
;
1321 // don't put quote in arg
1324 //else: quote has no special meaning but the backslash
1325 // still remains -- makes no sense but this is what
1328 // note that backslash does *not* quote the space, only quotes do
1329 else if ( !isInsideQuotes
&& (ch
== ' ' || ch
== '\t') )
1331 ++p
; // skip this space anyhow
1335 lastBS
= !lastBS
&& ch
== '\\';
1337 else // type == wxCMD_LINE_SPLIT_UNIX
1341 if ( isInsideQuotes
)
1343 if ( ch
== chDelim
)
1345 isInsideQuotes
= false;
1347 continue; // don't use the quote itself
1350 else // not in quotes and not escaped
1352 if ( ch
== '\'' || ch
== '"' )
1354 isInsideQuotes
= true;
1357 continue; // don't use the quote itself
1360 if ( ch
== ' ' || ch
== '\t' )
1362 ++p
; // skip this space anyhow
1367 lastBS
= ch
== '\\';
1371 else // escaped by backslash, just use as is
1380 args
.push_back(arg
);