#if wxUSE_CMDLINE_PARSER
#include <ctype.h>
+#include <locale.h> // 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
type = typ;
flags = fl;
- m_hasVal = false;
+ Reset();
}
// can't use union easily here, so just store all possible data fields, we
{ 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,
private:
bool m_hasVal;
+ bool m_isNegated;
double m_doubleVal;
long m_longVal;
#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);
}
}
// ----------------------------------------------------------------------------
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
{
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();
}
}
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
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];
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
}
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');
{
// nothing more to do
opt.SetHasValue();
+ if ( negated )
+ opt.SetNegated();
if ( opt.flags & wxCMD_LINE_OPTION_HELP )
{
case wxCMD_LINE_VAL_DATE:
{
wxDateTime dt;
- wxString::const_iterator end;
- if ( !dt.ParseDate(value, &end) || end != value.end() )
+ wxString::const_iterator endDate;
+ if ( !dt.ParseDate(value, &endDate) || endDate != value.end() )
{
errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
name.c_str(), value.c_str())
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 )
{
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
{