X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9a83f860948059b0273b5cc6d9e43fadad3ebfca..41fec01fa9e009d84fe353aa494725328d850af1:/src/common/cmdline.cpp diff --git a/src/common/cmdline.cpp b/src/common/cmdline.cpp index e8058e2979..2952c2d6ae 100644 --- a/src/common/cmdline.cpp +++ b/src/common/cmdline.cpp @@ -37,11 +37,13 @@ #if wxUSE_CMDLINE_PARSER #include +#include // for LC_ALL #include "wx/datetime.h" #include "wx/msgout.h" #include "wx/filename.h" #include "wx/apptrait.h" +#include "wx/scopeguard.h" // ---------------------------------------------------------------------------- // private functions @@ -104,7 +106,7 @@ struct wxCmdLineOption type = typ; flags = fl; - m_hasVal = false; + Reset(); } // can't use union easily here, so just store all possible data fields, we @@ -139,9 +141,19 @@ struct wxCmdLineOption { Check(wxCMD_LINE_VAL_DATE); m_dateVal = val; m_hasVal = true; } #endif // wxUSE_DATETIME - void SetHasValue(bool hasValue = true) { m_hasVal = hasValue; } + void SetHasValue() { m_hasVal = true; } bool HasValue() const { return m_hasVal; } + void SetNegated() { m_isNegated = true; } + bool IsNegated() const { return m_isNegated; } + + // Reset to the initial state, called before parsing another command line. + void Reset() + { + m_hasVal = + m_isNegated = false; + } + public: wxCmdLineEntryType kind; wxString shortName, @@ -152,6 +164,7 @@ public: private: bool m_hasVal; + bool m_isNegated; double m_doubleVal; long m_longVal; @@ -230,13 +243,45 @@ wxCmdLineParserData::wxCmdLineParserData() #endif } +namespace +{ + +// Small helper function setting locale for all categories. +// +// We define it because wxSetlocale() can't be easily used with wxScopeGuard as +// it has several overloads -- while this one can. +inline char *SetAllLocaleFacets(const char *loc) +{ + return wxSetlocale(LC_ALL, loc); +} + +} // private namespace + void wxCmdLineParserData::SetArguments(int argc, char **argv) { m_arguments.clear(); + // Command-line arguments are supposed to be in the user locale encoding + // (what else?) but wxLocale probably wasn't initialized yet as we're + // called early during the program startup and so our locale might not have + // been set from the environment yet. To work around this problem we + // temporarily change the locale here. The only drawback is that changing + // the locale is thread-unsafe but precisely because we're called so early + // it's hopefully safe to assume that no other threads had been created yet. + char * const locOld = SetAllLocaleFacets(""); + wxON_BLOCK_EXIT1( SetAllLocaleFacets, locOld ); + for ( int n = 0; n < argc; n++ ) { - m_arguments.push_back(wxString::FromAscii(argv[n])); + // try to interpret the string as being in the current locale + wxString arg(argv[n]); + + // but just in case we guessed wrongly and the conversion failed, do + // try to salvage at least something + if ( arg.empty() && argv[n][0] != '\0' ) + arg = wxString(argv[n], wxConvISO8859_1); + + m_arguments.push_back(arg); } } @@ -484,18 +529,23 @@ void wxCmdLineParser::AddUsageText(const wxString& text) // ---------------------------------------------------------------------------- bool wxCmdLineParser::Found(const wxString& name) const +{ + return FoundSwitch(name) != wxCMD_SWITCH_NOT_FOUND; +} + +wxCmdLineSwitchState wxCmdLineParser::FoundSwitch(const wxString& name) const { int i = m_data->FindOption(name); if ( i == wxNOT_FOUND ) i = m_data->FindOptionByLongName(name); - wxCHECK_MSG( i != wxNOT_FOUND, false, wxT("unknown switch") ); + wxCHECK_MSG( i != wxNOT_FOUND, wxCMD_SWITCH_NOT_FOUND, wxT("unknown switch") ); wxCmdLineOption& opt = m_data->m_options[(size_t)i]; if ( !opt.HasValue() ) - return false; + return wxCMD_SWITCH_NOT_FOUND; - return true; + return opt.IsNegated() ? wxCMD_SWITCH_OFF : wxCMD_SWITCH_ON; } bool wxCmdLineParser::Found(const wxString& name, wxString *value) const @@ -593,8 +643,7 @@ void wxCmdLineParser::Reset() { for ( size_t i = 0; i < m_data->m_options.GetCount(); i++ ) { - wxCmdLineOption& opt = m_data->m_options[i]; - opt.SetHasValue(false); + m_data->m_options[i].Reset(); } } @@ -658,11 +707,45 @@ int wxCmdLineParser::Parse(bool showUsage) if (longOptionsEnabled) { + wxString errorOpt; + optInd = m_data->FindOptionByLongName(name); if ( optInd == wxNOT_FOUND ) { - errorMsg << wxString::Format(_("Unknown long option '%s'"), name.c_str()) - << wxT('\n'); + // Check if this could be a negatable long option. + if ( name.Last() == '-' ) + { + name.RemoveLast(); + + optInd = m_data->FindOptionByLongName(name); + if ( optInd != wxNOT_FOUND ) + { + if ( !(m_data->m_options[optInd].flags & + wxCMD_LINE_SWITCH_NEGATABLE) ) + { + errorOpt.Printf + ( + _("Option '%s' can't be negated"), + name + ); + optInd = wxNOT_FOUND; + } + } + } + + if ( optInd == wxNOT_FOUND ) + { + if ( errorOpt.empty() ) + { + errorOpt.Printf + ( + _("Unknown long option '%s'"), + name + ); + } + + errorMsg << errorOpt << wxT('\n'); + } } } else @@ -721,6 +804,14 @@ int wxCmdLineParser::Parse(bool showUsage) if ( m_data->m_options[(size_t)optInd].kind == wxCMD_LINE_SWITCH ) { + // if the switch is negatable and it is just followed + // by '-' the '-' is considered to be part of this + // switch + if ( (m_data->m_options[(size_t)optInd].flags & + wxCMD_LINE_SWITCH_NEGATABLE) && + arg[len] == '-' ) + ++len; + // pretend that all the rest of the argument is the // next argument, in fact wxString arg2 = arg[0u]; @@ -729,6 +820,10 @@ int wxCmdLineParser::Parse(bool showUsage) m_data->m_arguments.insert (m_data->m_arguments.begin() + n + 1, arg2); count++; + + // only leave the part which wasn't extracted into the + // next argument in this one + arg = arg.Left(len + 1); } //else: it's our value, we'll deal with it below } @@ -754,7 +849,10 @@ int wxCmdLineParser::Parse(bool showUsage) if ( opt.kind == wxCMD_LINE_SWITCH ) { // we must check that there is no value following the switch - if ( p != arg.end() ) + bool negated = (opt.flags & wxCMD_LINE_SWITCH_NEGATABLE) && + p != arg.end() && *p == '-'; + + if ( !negated && p != arg.end() ) { errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str()) << wxT('\n'); @@ -764,6 +862,8 @@ int wxCmdLineParser::Parse(bool showUsage) { // nothing more to do opt.SetHasValue(); + if ( negated ) + opt.SetNegated(); if ( opt.flags & wxCMD_LINE_OPTION_HELP ) { @@ -1057,7 +1157,7 @@ wxString wxCmdLineParser::GetUsageString() const for ( n = 0; n < count; n++ ) { wxCmdLineOption& opt = m_data->m_options[n]; - wxString option; + wxString option, negator; if ( opt.kind != wxCMD_LINE_USAGE_TEXT ) { @@ -1067,13 +1167,16 @@ wxString wxCmdLineParser::GetUsageString() const usage << wxT('['); } + if ( opt.flags & wxCMD_LINE_SWITCH_NEGATABLE ) + negator = wxT("[-]"); + if ( !opt.shortName.empty() ) { - usage << chSwitch << opt.shortName; + usage << chSwitch << opt.shortName << negator; } else if ( areLongOptionsEnabled && !opt.longName.empty() ) { - usage << wxT("--") << opt.longName; + usage << wxT("--") << opt.longName << negator; } else {