wxCmdLineOption(wxCmdLineEntryType k, const wxString& shrt, const wxString& lng, const wxString& desc, wxCmdLineParamType typ, int fl) { wxASSERT_MSG( !shrt.empty() || !lng.empty(), _T("option should have at least one name") ); wxASSERT_MSG ( GetShortOptionName(shrt).Len() == shrt.Len(), wxT("Short option contains invalid characters") ); wxASSERT_MSG ( GetLongOptionName(lng).Len() == lng.Len(), wxT("Long option contains invalid characters") ); kind = k; shortName = shrt; longName = lng; description = desc; type = typ; flags = fl; m_hasVal = false; }
wxCmdLineOption(wxCmdLineEntryType k, const wxString& shrt, const wxString& lng, const wxString& desc, wxCmdLineParamType typ, int fl) { // wxCMD_LINE_USAGE_TEXT uses only description, shortName and longName is empty if ( k != wxCMD_LINE_USAGE_TEXT ) { wxASSERT_MSG ( !shrt.empty() || !lng.empty(), wxT("option should have at least one name") ); wxASSERT_MSG ( GetShortOptionName(shrt.begin(), shrt.end()).Len() == shrt.Len(), wxT("Short option contains invalid characters") ); wxASSERT_MSG ( GetLongOptionName(lng.begin(), lng.end()).Len() == lng.Len(), wxT("Long option contains invalid characters") ); } kind = k; shortName = shrt; longName = lng; description = desc; type = typ; flags = fl; m_hasVal = false; m_isNegated = false; }
int wxCmdLineParser::Parse(bool showUsage) { bool maybeOption = true; // can the following arg be an option? bool ok = true; // true until an error is detected bool helpRequested = false; // true if "-h" was given bool hadRepeatableParam = false; // true if found param with MULTIPLE flag size_t currentParam = 0; // the index in m_paramDesc size_t countParam = m_data->m_paramDesc.GetCount(); wxString errorMsg; Reset(); // parse everything wxString arg; size_t count = m_data->m_arguments.size(); for ( size_t n = 1; ok && (n < count); n++ ) // 0 is program name { arg = m_data->m_arguments[n]; // special case: "--" should be discarded and all following arguments // should be considered as parameters, even if they start with '-' and // not like options (this is POSIX-like) if ( arg == wxT("--") ) { maybeOption = false; continue; } // empty argument or just '-' is not an option but a parameter if ( maybeOption && arg.length() > 1 && // FIXME-UTF8: use wc_str() after removing ANSI build wxStrchr(m_data->m_switchChars.c_str(), arg[0u]) ) { bool isLong; wxString name; int optInd = wxNOT_FOUND; // init to suppress warnings // an option or a switch: find whether it's a long or a short one if ( arg.length() >= 3 && arg[0u] == wxT('-') && arg[1u] == wxT('-') ) { // a long one isLong = true; // Skip leading "--" wxString::const_iterator p = arg.begin() + 2; bool longOptionsEnabled = AreLongOptionsEnabled(); name = GetLongOptionName(p, arg.end()); if (longOptionsEnabled) { optInd = m_data->FindOptionByLongName(name); if ( optInd == wxNOT_FOUND ) { errorMsg << wxString::Format(_("Unknown long option '%s'"), name.c_str()) << wxT('\n'); } } else { optInd = wxNOT_FOUND; // Sanity check // Print the argument including leading "--" name.Prepend( wxT("--") ); errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) << wxT('\n'); } } else // not a long option { isLong = false; // a short one: as they can be cumulated, we try to find the // longest substring which is a valid option wxString::const_iterator p = arg.begin() + 1; name = GetShortOptionName(p, arg.end()); size_t len = name.length(); do { if ( len == 0 ) { // we couldn't find a valid option name in the // beginning of this string errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) << wxT('\n'); break; } else { optInd = m_data->FindOption(name.Left(len)); // will try with one character less the next time len--; } } while ( optInd == wxNOT_FOUND ); len++; // compensates extra len-- above if ( (optInd != wxNOT_FOUND) && (len != name.length()) ) { // first of all, the option name is only part of this // string name = name.Left(len); // our option is only part of this argument, there is // something else in it - it is either the value of this // option or other switches if it is a switch if ( m_data->m_options[(size_t)optInd].kind == wxCMD_LINE_SWITCH ) { // pretend that all the rest of the argument is the // next argument, in fact wxString arg2 = arg[0u]; arg2 += arg.Mid(len + 1); // +1 for leading '-' 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 ( optInd == wxNOT_FOUND ) { ok = false; continue; // will break, in fact } // look at what follows: // +1 for leading '-' wxString::const_iterator p = arg.begin() + 1 + name.length(); wxString::const_iterator end = arg.end(); if ( isLong ) ++p; // for another leading '-' wxCmdLineOption& opt = m_data->m_options[(size_t)optInd]; if ( opt.kind == wxCMD_LINE_SWITCH ) { // we must check that there is no value following the switch if ( p != arg.end() ) { errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str()) << wxT('\n'); ok = false; } else // no value, as expected { // nothing more to do opt.SetHasValue(); if ( opt.flags & wxCMD_LINE_OPTION_HELP ) { helpRequested = true; // it's not an error, but we still stop here ok = false; } } } else // it's an option. not a switch { switch ( p == end ? '\0' : (*p).GetValue() ) { case '=': case ':': // the value follows ++p; break; case '\0': // the value is in the next argument if ( ++n == count ) { // ... but there is none errorMsg << wxString::Format(_("Option '%s' requires a value."), name.c_str()) << wxT('\n'); ok = false; } else { // ... take it from there p = m_data->m_arguments[n].begin(); end = m_data->m_arguments[n].end(); } break; default: // the value is right here: this may be legal or // not depending on the option style if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR ) { errorMsg << wxString::Format(_("Separator expected after the option '%s'."), name.c_str()) << wxT('\n'); ok = false; } } if ( ok ) { wxString value(p, end); switch ( opt.type ) { default: wxFAIL_MSG( wxT("unknown option type") ); // still fall through case wxCMD_LINE_VAL_STRING: opt.SetStrVal(value); break; case wxCMD_LINE_VAL_NUMBER: { long val; if ( value.ToLong(&val) ) { opt.SetLongVal(val); } else { errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."), value.c_str(), name.c_str()) << wxT('\n'); ok = false; } } break; case wxCMD_LINE_VAL_DOUBLE: { double val; if ( value.ToDouble(&val) ) { opt.SetDoubleVal(val); } else { errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."), value.c_str(), name.c_str()) << wxT('\n'); ok = false; } } break; #if wxUSE_DATETIME case wxCMD_LINE_VAL_DATE: { wxDateTime dt; wxString::const_iterator end; if ( !dt.ParseDate(value, &end) || end != value.end() ) { errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."), name.c_str(), value.c_str()) << wxT('\n'); ok = false; } else { opt.SetDateVal(dt); } } break; #endif // wxUSE_DATETIME } } } } else // not an option, must be a parameter { if ( currentParam < countParam ) { wxCmdLineParam& param = m_data->m_paramDesc[currentParam]; // TODO check the param type m_data->m_parameters.push_back(arg); if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) ) { currentParam++; } else { wxASSERT_MSG( currentParam == countParam - 1, wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") ); // remember that we did have this last repeatable parameter hadRepeatableParam = true; } } else { errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str()) << wxT('\n'); ok = false; } } } // verify that all mandatory options were given if ( ok ) { size_t countOpt = m_data->m_options.GetCount(); for ( size_t n = 0; ok && (n < countOpt); n++ ) { wxCmdLineOption& opt = m_data->m_options[n]; if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() ) { wxString optName; if ( !opt.longName ) { optName = opt.shortName; } else { if ( AreLongOptionsEnabled() ) { optName.Printf( _("%s (or %s)"), opt.shortName.c_str(), opt.longName.c_str() ); } else { optName.Printf( wxT("%s"), opt.shortName.c_str() ); } } errorMsg << wxString::Format(_("The value for the option '%s' must be specified."), optName.c_str()) << wxT('\n'); ok = false; } } for ( ; ok && (currentParam < countParam); currentParam++ ) { wxCmdLineParam& param = m_data->m_paramDesc[currentParam]; if ( (currentParam == countParam - 1) && (param.flags & wxCMD_LINE_PARAM_MULTIPLE) && hadRepeatableParam ) { // special case: currentParam wasn't incremented, but we did // have it, so don't give error continue; } if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) ) { errorMsg << wxString::Format(_("The required parameter '%s' was not specified."), param.description.c_str()) << wxT('\n'); ok = false; } } } // if there was an error during parsing the command line, show this error // and also the usage message if it had been requested if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) ) { wxMessageOutput* msgOut = wxMessageOutput::Get(); if ( msgOut ) { wxString usage; if ( showUsage ) usage = GetUsageString(); msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() ); } else { wxFAIL_MSG( wxT("no wxMessageOutput object?") ); } } return ok ? 0 : helpRequested ? -1 : 1; }