Ejemplo n.º 1
0
wxString wxCmdLineParser::GetUsageString() const
{
    wxString appname;
    if ( m_data->m_arguments.empty() )
    {
        if ( wxTheApp )
            appname = wxTheApp->GetAppName();
    }
    else // use argv[0]
    {
        appname = wxFileName(m_data->m_arguments[0]).GetName();
    }

    // we construct the brief cmd line desc on the fly, but not the detailed
    // help message below because we want to align the options descriptions
    // and for this we must first know the longest one of them
    wxString usage;
    wxArrayString namesOptions, descOptions;

    if ( !m_data->m_logo.empty() )
    {
        usage << m_data->m_logo << wxT('\n');
    }

    usage << wxString::Format(_("Usage: %s"), appname.c_str());

    // the switch char is usually '-' but this can be changed with
    // SetSwitchChars() and then the first one of possible chars is used
    wxChar chSwitch = !m_data->m_switchChars ? wxT('-')
                                             : m_data->m_switchChars[0u];

    bool areLongOptionsEnabled = AreLongOptionsEnabled();
    size_t n, count = m_data->m_options.GetCount();
    for ( n = 0; n < count; n++ )
    {
        wxCmdLineOption& opt = m_data->m_options[n];
        wxString option;

        if ( opt.kind != wxCMD_LINE_USAGE_TEXT )
        {
            usage << wxT(' ');
            if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
            {
                usage << wxT('[');
            }

            if ( !opt.shortName.empty() )
            {
                usage << chSwitch << opt.shortName;
            }
            else if ( areLongOptionsEnabled && !opt.longName.empty() )
            {
                usage << wxT("--") << opt.longName;
            }
            else
            {
                if (!opt.longName.empty())
                {
                    wxFAIL_MSG( wxT("option with only a long name while long ")
                                wxT("options are disabled") );
                }
                else
                {
                    wxFAIL_MSG( wxT("option without neither short nor long name") );
                }
            }

            if ( !opt.shortName.empty() )
            {
                option << wxT("  ") << chSwitch << opt.shortName;
            }

            if ( areLongOptionsEnabled && !opt.longName.empty() )
            {
                option << (option.empty() ? wxT("  ") : wxT(", "))
                       << wxT("--") << opt.longName;
            }

            if ( opt.kind != wxCMD_LINE_SWITCH )
            {
                wxString val;
                val << wxT('<') << GetTypeName(opt.type) << wxT('>');
                usage << wxT(' ') << val;
                option << (!opt.longName ? wxT(':') : wxT('=')) << val;
            }

            if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
            {
                usage << wxT(']');
            }
        }

        namesOptions.push_back(option);
        descOptions.push_back(opt.description);
    }

    count = m_data->m_paramDesc.GetCount();
    for ( n = 0; n < count; n++ )
    {
        wxCmdLineParam& param = m_data->m_paramDesc[n];

        usage << wxT(' ');
        if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
        {
            usage << wxT('[');
        }

        usage << param.description;

        if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
        {
            usage << wxT("...");
        }

        if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
        {
            usage << wxT(']');
        }
    }

    usage << wxT('\n');

    // set to number of our own options, not counting the standard ones
    count = namesOptions.size();

    // get option names & descriptions for standard options, if any:
    wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
    wxString stdDesc;
    if ( traits )
        stdDesc = traits->GetStandardCmdLineOptions(namesOptions, descOptions);

    // now construct the detailed help message
    size_t len, lenMax = 0;
    for ( n = 0; n < namesOptions.size(); n++ )
    {
        len = namesOptions[n].length();
        if ( len > lenMax )
            lenMax = len;
    }

    for ( n = 0; n < namesOptions.size(); n++ )
    {
        if ( n == count )
            usage << wxT('\n') << stdDesc;

        len = namesOptions[n].length();
        // desc contains text if name is empty
        if (len == 0)
        {
            usage << descOptions[n] << wxT('\n');
        }
        else
        {
            usage << namesOptions[n]
                  << wxString(wxT(' '), lenMax - len) << wxT('\t')
                  << descOptions[n]
                  << wxT('\n');
        }
    }

    return usage;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
wxString wxCmdLineParser::GetUsageString()
{
    wxString appname = wxTheApp->GetAppName();
    if ( !appname )
    {
        wxCHECK_MSG( m_data->m_arguments.size() != 0, wxEmptyString,
                     _T("no program name") );

        appname = wxFileNameFromPath(m_data->m_arguments[0]);
        wxStripExtension(appname);
    }

    // we construct the brief cmd line desc on the fly, but not the detailed
    // help message below because we want to align the options descriptions
    // and for this we must first know the longest one of them
    wxString usage;
    wxArrayString namesOptions, descOptions;

    if ( !m_data->m_logo.empty() )
    {
        usage << m_data->m_logo << _T('\n');
    }

    usage << wxString::Format(_("Usage: %s"), appname.c_str());

    // the switch char is usually '-' but this can be changed with
    // SetSwitchChars() and then the first one of possible chars is used
    wxChar chSwitch = !m_data->m_switchChars ? _T('-')
                                             : m_data->m_switchChars[0u];

    bool areLongOptionsEnabled = AreLongOptionsEnabled();
    size_t n, count = m_data->m_options.GetCount();
    for ( n = 0; n < count; n++ )
    {
        wxCmdLineOption& opt = m_data->m_options[n];

        usage << _T(' ');
        if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
        {
            usage << _T('[');
        }

        if ( !opt.shortName.empty() )
        {
            usage << chSwitch << opt.shortName;
        }
        else if ( areLongOptionsEnabled && !opt.longName.empty() )
        {
            usage << _T("--") << opt.longName;
        }
        else
        {
            if (!opt.longName.empty())
            {
                wxFAIL_MSG( wxT("option with only a long name while long ")
                    wxT("options are disabled") );
            }
            else
            {
                wxFAIL_MSG( _T("option without neither short nor long name") );
            }
        }

        wxString option;

        if ( !opt.shortName.empty() )
        {
            option << _T("  ") << chSwitch << opt.shortName;
        }

        if ( areLongOptionsEnabled && !opt.longName.empty() )
        {
            option << (option.empty() ? _T("  ") : _T(", "))
                   << _T("--") << opt.longName;
        }

        if ( opt.kind != wxCMD_LINE_SWITCH )
        {
            wxString val;
            val << _T('<') << GetTypeName(opt.type) << _T('>');
            usage << _T(' ') << val;
            option << (!opt.longName ? _T(':') : _T('=')) << val;
        }

        if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
        {
            usage << _T(']');
        }

        namesOptions.push_back(option);
        descOptions.push_back(opt.description);
    }

    count = m_data->m_paramDesc.GetCount();
    for ( n = 0; n < count; n++ )
    {
        wxCmdLineParam& param = m_data->m_paramDesc[n];

        usage << _T(' ');
        if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
        {
            usage << _T('[');
        }

        usage << param.description;

        if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
        {
            usage << _T("...");
        }

        if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
        {
            usage << _T(']');
        }
    }

    usage << _T('\n');

    // now construct the detailed help message
    size_t len, lenMax = 0;
    count = namesOptions.size();
    for ( n = 0; n < count; n++ )
    {
        len = namesOptions[n].length();
        if ( len > lenMax )
            lenMax = len;
    }

    for ( n = 0; n < count; n++ )
    {
        len = namesOptions[n].length();
        usage << namesOptions[n]
              << wxString(_T(' '), lenMax - len) << _T('\t')
              << descOptions[n]
              << _T('\n');
    }

    return usage;
}