1///////////////////////////////////////////////////////////////////////////////
2// Name:        src/common/cmdline.cpp
3// Purpose:     wxCmdLineParser implementation
4// Author:      Vadim Zeitlin
5// Modified by:
6// Created:     05.01.00
7// RCS-ID:      $Id: cmdline.cpp 66920 2011-02-16 22:00:30Z JS $
8// Copyright:   (c) 2000 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence:     wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24    #pragma hdrstop
25#endif
26
27#ifndef WX_PRECOMP
28    #include "wx/dynarray.h"
29    #include "wx/string.h"
30    #include "wx/log.h"
31    #include "wx/intl.h"
32    #include "wx/app.h"
33#endif //WX_PRECOMP
34
35#include "wx/cmdline.h"
36
37#if wxUSE_CMDLINE_PARSER
38
39#include <ctype.h>
40
41#include "wx/datetime.h"
42#include "wx/msgout.h"
43#include "wx/filename.h"
44
45// ----------------------------------------------------------------------------
46// private functions
47// ----------------------------------------------------------------------------
48
49static wxString GetTypeName(wxCmdLineParamType type);
50
51static wxString GetOptionName(const wxChar *p, const wxChar *allowedChars);
52
53static wxString GetShortOptionName(const wxChar *p);
54
55static wxString GetLongOptionName(const wxChar *p);
56
57// ----------------------------------------------------------------------------
58// private structs
59// ----------------------------------------------------------------------------
60
61// an internal representation of an option
62struct wxCmdLineOption
63{
64    wxCmdLineOption(wxCmdLineEntryType k,
65                    const wxString& shrt,
66                    const wxString& lng,
67                    const wxString& desc,
68                    wxCmdLineParamType typ,
69                    int fl)
70    {
71        wxASSERT_MSG( !shrt.empty() || !lng.empty(),
72                      _T("option should have at least one name") );
73
74        wxASSERT_MSG
75            (
76                GetShortOptionName(shrt).Len() == shrt.Len(),
77                wxT("Short option contains invalid characters")
78            );
79
80        wxASSERT_MSG
81            (
82                GetLongOptionName(lng).Len() == lng.Len(),
83                wxT("Long option contains invalid characters")
84            );
85
86
87        kind = k;
88
89        shortName = shrt;
90        longName = lng;
91        description = desc;
92
93        type = typ;
94        flags = fl;
95
96        m_hasVal = false;
97    }
98
99    // can't use union easily here, so just store all possible data fields, we
100    // don't waste much (might still use union later if the number of supported
101    // types increases, so always use the accessor functions and don't access
102    // the fields directly!)
103
104    void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const
105    {
106        wxASSERT_MSG( type == typ, _T("type mismatch in wxCmdLineOption") );
107    }
108
109    long GetLongVal() const
110        { Check(wxCMD_LINE_VAL_NUMBER); return m_longVal; }
111    const wxString& GetStrVal() const
112        { Check(wxCMD_LINE_VAL_STRING); return m_strVal;  }
113#if wxUSE_DATETIME
114    const wxDateTime& GetDateVal() const
115        { Check(wxCMD_LINE_VAL_DATE);   return m_dateVal; }
116#endif // wxUSE_DATETIME
117
118    void SetLongVal(long val)
119        { Check(wxCMD_LINE_VAL_NUMBER); m_longVal = val; m_hasVal = true; }
120    void SetStrVal(const wxString& val)
121        { Check(wxCMD_LINE_VAL_STRING); m_strVal = val; m_hasVal = true; }
122#if wxUSE_DATETIME
123    void SetDateVal(const wxDateTime& val)
124        { Check(wxCMD_LINE_VAL_DATE); m_dateVal = val; m_hasVal = true; }
125#endif // wxUSE_DATETIME
126
127    void SetHasValue(bool hasValue = true) { m_hasVal = hasValue; }
128    bool HasValue() const { return m_hasVal; }
129
130public:
131    wxCmdLineEntryType kind;
132    wxString shortName,
133             longName,
134             description;
135    wxCmdLineParamType type;
136    int flags;
137
138private:
139    bool m_hasVal;
140
141    long m_longVal;
142    wxString m_strVal;
143#if wxUSE_DATETIME
144    wxDateTime m_dateVal;
145#endif // wxUSE_DATETIME
146};
147
148struct wxCmdLineParam
149{
150    wxCmdLineParam(const wxString& desc,
151                   wxCmdLineParamType typ,
152                   int fl)
153        : description(desc)
154    {
155        type = typ;
156        flags = fl;
157    }
158
159    wxString description;
160    wxCmdLineParamType type;
161    int flags;
162};
163
164WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions);
165WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams);
166
167#include "wx/arrimpl.cpp"
168
169WX_DEFINE_OBJARRAY(wxArrayOptions)
170WX_DEFINE_OBJARRAY(wxArrayParams)
171
172// the parser internal state
173struct wxCmdLineParserData
174{
175    // options
176    wxString m_switchChars;     // characters which may start an option
177    bool m_enableLongOptions;   // true if long options are enabled
178    wxString m_logo;            // some extra text to show in Usage()
179
180    // cmd line data
181    wxArrayString m_arguments;  // == argv, argc == m_arguments.GetCount()
182    wxArrayOptions m_options;   // all possible options and switchrs
183    wxArrayParams m_paramDesc;  // description of all possible params
184    wxArrayString m_parameters; // all params found
185
186    // methods
187    wxCmdLineParserData();
188    void SetArguments(int argc, char **argv);
189#if wxUSE_UNICODE
190    void SetArguments(int argc, wxChar **argv);
191#endif // wxUSE_UNICODE
192    void SetArguments(const wxString& cmdline);
193
194    int FindOption(const wxString& name);
195    int FindOptionByLongName(const wxString& name);
196};
197
198// ============================================================================
199// implementation
200// ============================================================================
201
202// ----------------------------------------------------------------------------
203// wxCmdLineParserData
204// ----------------------------------------------------------------------------
205
206wxCmdLineParserData::wxCmdLineParserData()
207{
208    m_enableLongOptions = true;
209#ifdef __UNIX_LIKE__
210    m_switchChars = _T("-");
211#else // !Unix
212    m_switchChars = _T("/-");
213#endif
214}
215
216void wxCmdLineParserData::SetArguments(int argc, char **argv)
217{
218    m_arguments.clear();
219
220    for ( int n = 0; n < argc; n++ )
221    {
222        m_arguments.push_back(wxString::FromAscii(argv[n]));
223    }
224}
225
226#if wxUSE_UNICODE
227
228void wxCmdLineParserData::SetArguments(int argc, wxChar **argv)
229{
230    m_arguments.clear();
231
232    for ( int n = 0; n < argc; n++ )
233    {
234        m_arguments.push_back(argv[n]);
235    }
236}
237
238#endif // wxUSE_UNICODE
239
240void wxCmdLineParserData::SetArguments(const wxString& cmdLine)
241{
242    m_arguments.clear();
243
244    if(wxTheApp && wxTheApp->argc > 0)
245        m_arguments.push_back(wxTheApp->argv[0]);
246    else
247        m_arguments.push_back(wxEmptyString);
248
249    wxArrayString args = wxCmdLineParser::ConvertStringToArgs(cmdLine);
250
251    WX_APPEND_ARRAY(m_arguments, args);
252}
253
254int wxCmdLineParserData::FindOption(const wxString& name)
255{
256    if ( !name.empty() )
257    {
258        size_t count = m_options.GetCount();
259        for ( size_t n = 0; n < count; n++ )
260        {
261            if ( m_options[n].shortName == name )
262            {
263                // found
264                return n;
265            }
266        }
267    }
268
269    return wxNOT_FOUND;
270}
271
272int wxCmdLineParserData::FindOptionByLongName(const wxString& name)
273{
274    size_t count = m_options.GetCount();
275    for ( size_t n = 0; n < count; n++ )
276    {
277        if ( m_options[n].longName == name )
278        {
279            // found
280            return n;
281        }
282    }
283
284    return wxNOT_FOUND;
285}
286
287// ----------------------------------------------------------------------------
288// construction and destruction
289// ----------------------------------------------------------------------------
290
291void wxCmdLineParser::Init()
292{
293    m_data = new wxCmdLineParserData;
294}
295
296void wxCmdLineParser::SetCmdLine(int argc, char **argv)
297{
298    m_data->SetArguments(argc, argv);
299}
300
301#if wxUSE_UNICODE
302
303void wxCmdLineParser::SetCmdLine(int argc, wxChar **argv)
304{
305    m_data->SetArguments(argc, argv);
306}
307
308#endif // wxUSE_UNICODE
309
310void wxCmdLineParser::SetCmdLine(const wxString& cmdline)
311{
312    m_data->SetArguments(cmdline);
313}
314
315wxCmdLineParser::~wxCmdLineParser()
316{
317    delete m_data;
318}
319
320// ----------------------------------------------------------------------------
321// options
322// ----------------------------------------------------------------------------
323
324void wxCmdLineParser::SetSwitchChars(const wxString& switchChars)
325{
326    m_data->m_switchChars = switchChars;
327}
328
329void wxCmdLineParser::EnableLongOptions(bool enable)
330{
331    m_data->m_enableLongOptions = enable;
332}
333
334bool wxCmdLineParser::AreLongOptionsEnabled()
335{
336    return m_data->m_enableLongOptions;
337}
338
339void wxCmdLineParser::SetLogo(const wxString& logo)
340{
341    m_data->m_logo = logo;
342}
343
344// ----------------------------------------------------------------------------
345// command line construction
346// ----------------------------------------------------------------------------
347
348void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc *desc)
349{
350    for ( ;; desc++ )
351    {
352        switch ( desc->kind )
353        {
354            case wxCMD_LINE_SWITCH:
355                AddSwitch(desc->shortName, desc->longName, desc->description,
356                          desc->flags);
357                break;
358
359            case wxCMD_LINE_OPTION:
360                AddOption(desc->shortName, desc->longName, desc->description,
361                          desc->type, desc->flags);
362                break;
363
364            case wxCMD_LINE_PARAM:
365                AddParam(desc->description, desc->type, desc->flags);
366                break;
367
368            default:
369                wxFAIL_MSG( _T("unknown command line entry type") );
370                // still fall through
371
372            case wxCMD_LINE_NONE:
373                return;
374        }
375    }
376}
377
378void wxCmdLineParser::AddSwitch(const wxString& shortName,
379                                const wxString& longName,
380                                const wxString& desc,
381                                int flags)
382{
383    wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND,
384                  _T("duplicate switch") );
385
386    wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_SWITCH,
387                                                  shortName, longName, desc,
388                                                  wxCMD_LINE_VAL_NONE, flags);
389
390    m_data->m_options.Add(option);
391}
392
393void wxCmdLineParser::AddOption(const wxString& shortName,
394                                const wxString& longName,
395                                const wxString& desc,
396                                wxCmdLineParamType type,
397                                int flags)
398{
399    wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND,
400                  _T("duplicate option") );
401
402    wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_OPTION,
403                                                  shortName, longName, desc,
404                                                  type, flags);
405
406    m_data->m_options.Add(option);
407}
408
409void wxCmdLineParser::AddParam(const wxString& desc,
410                               wxCmdLineParamType type,
411                               int flags)
412{
413    // do some consistency checks: a required parameter can't follow an
414    // optional one and nothing should follow a parameter with MULTIPLE flag
415#ifdef __WXDEBUG__
416    if ( !m_data->m_paramDesc.IsEmpty() )
417    {
418        wxCmdLineParam& param = m_data->m_paramDesc.Last();
419
420        wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE),
421                      _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
422
423        if ( !(flags & wxCMD_LINE_PARAM_OPTIONAL) )
424        {
425            wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL),
426                          _T("a required parameter can't follow an optional one") );
427        }
428    }
429#endif // Debug
430
431    wxCmdLineParam *param = new wxCmdLineParam(desc, type, flags);
432
433    m_data->m_paramDesc.Add(param);
434}
435
436// ----------------------------------------------------------------------------
437// access to parse command line
438// ----------------------------------------------------------------------------
439
440bool wxCmdLineParser::Found(const wxString& name) const
441{
442    int i = m_data->FindOption(name);
443    if ( i == wxNOT_FOUND )
444        i = m_data->FindOptionByLongName(name);
445
446    wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown switch") );
447
448    wxCmdLineOption& opt = m_data->m_options[(size_t)i];
449    if ( !opt.HasValue() )
450        return false;
451
452    return true;
453}
454
455bool wxCmdLineParser::Found(const wxString& name, wxString *value) const
456{
457    int i = m_data->FindOption(name);
458    if ( i == wxNOT_FOUND )
459        i = m_data->FindOptionByLongName(name);
460
461    wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") );
462
463    wxCmdLineOption& opt = m_data->m_options[(size_t)i];
464    if ( !opt.HasValue() )
465        return false;
466
467    wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") );
468
469    *value = opt.GetStrVal();
470
471    return true;
472}
473
474bool wxCmdLineParser::Found(const wxString& name, long *value) const
475{
476    int i = m_data->FindOption(name);
477    if ( i == wxNOT_FOUND )
478        i = m_data->FindOptionByLongName(name);
479
480    wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") );
481
482    wxCmdLineOption& opt = m_data->m_options[(size_t)i];
483    if ( !opt.HasValue() )
484        return false;
485
486    wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") );
487
488    *value = opt.GetLongVal();
489
490    return true;
491}
492
493#if wxUSE_DATETIME
494bool wxCmdLineParser::Found(const wxString& name, wxDateTime *value) const
495{
496    int i = m_data->FindOption(name);
497    if ( i == wxNOT_FOUND )
498        i = m_data->FindOptionByLongName(name);
499
500    wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") );
501
502    wxCmdLineOption& opt = m_data->m_options[(size_t)i];
503    if ( !opt.HasValue() )
504        return false;
505
506    wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") );
507
508    *value = opt.GetDateVal();
509
510    return true;
511}
512#endif // wxUSE_DATETIME
513
514size_t wxCmdLineParser::GetParamCount() const
515{
516    return m_data->m_parameters.size();
517}
518
519wxString wxCmdLineParser::GetParam(size_t n) const
520{
521    wxCHECK_MSG( n < GetParamCount(), wxEmptyString, _T("invalid param index") );
522
523    return m_data->m_parameters[n];
524}
525
526// Resets switches and options
527void wxCmdLineParser::Reset()
528{
529    for ( size_t i = 0; i < m_data->m_options.Count(); i++ )
530    {
531        wxCmdLineOption& opt = m_data->m_options[i];
532        opt.SetHasValue(false);
533    }
534}
535
536
537// ----------------------------------------------------------------------------
538// the real work is done here
539// ----------------------------------------------------------------------------
540
541int wxCmdLineParser::Parse(bool showUsage)
542{
543    bool maybeOption = true;    // can the following arg be an option?
544    bool ok = true;             // true until an error is detected
545    bool helpRequested = false; // true if "-h" was given
546    bool hadRepeatableParam = false; // true if found param with MULTIPLE flag
547
548    size_t currentParam = 0;    // the index in m_paramDesc
549
550    size_t countParam = m_data->m_paramDesc.GetCount();
551    wxString errorMsg;
552
553    Reset();
554
555    // parse everything
556    wxString arg;
557    size_t count = m_data->m_arguments.size();
558    for ( size_t n = 1; ok && (n < count); n++ )    // 0 is program name
559    {
560        arg = m_data->m_arguments[n];
561
562        // special case: "--" should be discarded and all following arguments
563        // should be considered as parameters, even if they start with '-' and
564        // not like options (this is POSIX-like)
565        if ( arg == _T("--") )
566        {
567            maybeOption = false;
568
569            continue;
570        }
571
572        // empty argument or just '-' is not an option but a parameter
573        if ( maybeOption && arg.length() > 1 &&
574                wxStrchr(m_data->m_switchChars, arg[0u]) )
575        {
576            bool isLong;
577            wxString name;
578            int optInd = wxNOT_FOUND;   // init to suppress warnings
579
580            // an option or a switch: find whether it's a long or a short one
581            if ( arg[0u] == _T('-') && arg[1u] == _T('-') )
582            {
583                // a long one
584                isLong = true;
585
586                // Skip leading "--"
587                const wxChar *p = arg.c_str() + 2;
588
589                bool longOptionsEnabled = AreLongOptionsEnabled();
590
591                name = GetLongOptionName(p);
592
593                if (longOptionsEnabled)
594                {
595                    optInd = m_data->FindOptionByLongName(name);
596                    if ( optInd == wxNOT_FOUND )
597                    {
598                        errorMsg << wxString::Format(_("Unknown long option '%s'"), name.c_str())
599                                 << _T('\n');
600                    }
601                }
602                else
603                {
604                    optInd = wxNOT_FOUND; // Sanity check
605
606                    // Print the argument including leading "--"
607                    name.Prepend( wxT("--") );
608                    errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str())
609                             << _T('\n');
610                }
611
612            }
613            else // not a long option
614            {
615                isLong = false;
616
617                // a short one: as they can be cumulated, we try to find the
618                // longest substring which is a valid option
619                const wxChar *p = arg.c_str() + 1;
620
621                name = GetShortOptionName(p);
622
623                size_t len = name.length();
624                do
625                {
626                    if ( len == 0 )
627                    {
628                        // we couldn't find a valid option name in the
629                        // beginning of this string
630                        errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str())
631                                 << _T('\n');
632
633                        break;
634                    }
635                    else
636                    {
637                        optInd = m_data->FindOption(name.Left(len));
638
639                        // will try with one character less the next time
640                        len--;
641                    }
642                }
643                while ( optInd == wxNOT_FOUND );
644
645                len++;  // compensates extra len-- above
646                if ( (optInd != wxNOT_FOUND) && (len != name.length()) )
647                {
648                    // first of all, the option name is only part of this
649                    // string
650                    name = name.Left(len);
651
652                    // our option is only part of this argument, there is
653                    // something else in it - it is either the value of this
654                    // option or other switches if it is a switch
655                    if ( m_data->m_options[(size_t)optInd].kind
656                            == wxCMD_LINE_SWITCH )
657                    {
658                        // pretend that all the rest of the argument is the
659                        // next argument, in fact
660                        wxString arg2 = arg[0u];
661                        arg2 += arg.Mid(len + 1); // +1 for leading '-'
662
663                        m_data->m_arguments.insert
664                            (m_data->m_arguments.begin() + n + 1, arg2);
665                        count++;
666                    }
667                    //else: it's our value, we'll deal with it below
668                }
669            }
670
671            if ( optInd == wxNOT_FOUND )
672            {
673                ok = false;
674
675                continue;   // will break, in fact
676            }
677
678            // look at what follows:
679
680            // +1 for leading '-'
681            const wxChar *p = arg.c_str() + 1 + name.length();
682            if ( isLong )
683                p++;    // for another leading '-'
684
685            wxCmdLineOption& opt = m_data->m_options[(size_t)optInd];
686            if ( opt.kind == wxCMD_LINE_SWITCH )
687            {
688                // we must check that there is no value following the switch
689                if ( *p != _T('\0') )
690                {
691                    errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str())
692                             << _T('\n');
693                    ok = false;
694                }
695                else // no value, as expected
696                {
697                    // nothing more to do
698                    opt.SetHasValue();
699
700                    if ( opt.flags & wxCMD_LINE_OPTION_HELP )
701                    {
702                        helpRequested = true;
703
704                        // it's not an error, but we still stop here
705                        ok = false;
706                    }
707                }
708            }
709            else // it's an option. not a switch
710            {
711                // get the value
712                if ( isLong )
713                {
714                    if ( *p++ != _T('=') )
715                    {
716                        errorMsg << wxString::Format(_("Option '%s' requires a value, '=' expected."), name.c_str())
717                                 << _T('\n');
718
719                        ok = false;
720                    }
721                }
722                else // short option
723                {
724                    switch ( *p )
725                    {
726                        case _T('='):
727                        case _T(':'):
728                            // the value follows
729                            p++;
730                            break;
731
732                        case 0:
733                            // the value is in the next argument
734                            if ( ++n == count )
735                            {
736                                // ... but there is none
737                                errorMsg << wxString::Format(_("Option '%s' requires a value."),
738                                                             name.c_str())
739                                         << _T('\n');
740
741                                ok = false;
742                            }
743                            else
744                            {
745                                // ... take it from there
746                                p = m_data->m_arguments[n].c_str();
747                            }
748                            break;
749
750                        default:
751                            // the value is right here: this may be legal or
752                            // not depending on the option style
753                            if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR )
754                            {
755                                errorMsg << wxString::Format(_("Separator expected after the option '%s'."),
756                                                             name.c_str())
757                                        << _T('\n');
758
759                                ok = false;
760                            }
761                    }
762                }
763
764                if ( ok )
765                {
766                    wxString value = p;
767                    switch ( opt.type )
768                    {
769                        default:
770                            wxFAIL_MSG( _T("unknown option type") );
771                            // still fall through
772
773                        case wxCMD_LINE_VAL_STRING:
774                            opt.SetStrVal(value);
775                            break;
776
777                        case wxCMD_LINE_VAL_NUMBER:
778                            {
779                                long val;
780                                if ( value.ToLong(&val) )
781                                {
782                                    opt.SetLongVal(val);
783                                }
784                                else
785                                {
786                                    errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
787                                                                 value.c_str(), name.c_str())
788                                             << _T('\n');
789
790                                    ok = false;
791                                }
792                            }
793                            break;
794
795#if wxUSE_DATETIME
796                        case wxCMD_LINE_VAL_DATE:
797                            {
798                                wxDateTime dt;
799                                const wxChar *res = dt.ParseDate(value);
800                                if ( !res || *res )
801                                {
802                                    errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
803                                                                 name.c_str(), value.c_str())
804                                             << _T('\n');
805
806                                    ok = false;
807                                }
808                                else
809                                {
810                                    opt.SetDateVal(dt);
811                                }
812                            }
813                            break;
814#endif // wxUSE_DATETIME
815                    }
816                }
817            }
818        }
819        else // not an option, must be a parameter
820        {
821            if ( currentParam < countParam )
822            {
823                wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
824
825                // TODO check the param type
826
827                m_data->m_parameters.push_back(arg);
828
829                if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
830                {
831                    currentParam++;
832                }
833                else
834                {
835                    wxASSERT_MSG( currentParam == countParam - 1,
836                                  _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
837
838                    // remember that we did have this last repeatable parameter
839                    hadRepeatableParam = true;
840                }
841            }
842            else
843            {
844                errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str())
845                         << _T('\n');
846
847                ok = false;
848            }
849        }
850    }
851
852    // verify that all mandatory options were given
853    if ( ok )
854    {
855        size_t countOpt = m_data->m_options.GetCount();
856        for ( size_t n = 0; ok && (n < countOpt); n++ )
857        {
858            wxCmdLineOption& opt = m_data->m_options[n];
859            if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
860            {
861                wxString optName;
862                if ( !opt.longName )
863                {
864                    optName = opt.shortName;
865                }
866                else
867                {
868                    if ( AreLongOptionsEnabled() )
869                    {
870                        optName.Printf( _("%s (or %s)"),
871                                        opt.shortName.c_str(),
872                                        opt.longName.c_str() );
873                    }
874                    else
875                    {
876                        optName.Printf( wxT("%s"),
877                                        opt.shortName.c_str() );
878                    }
879                }
880
881                errorMsg << wxString::Format(_("The value for the option '%s' must be specified."),
882                                             optName.c_str())
883                         << _T('\n');
884
885                ok = false;
886            }
887        }
888
889        for ( ; ok && (currentParam < countParam); currentParam++ )
890        {
891            wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
892            if ( (currentParam == countParam - 1) &&
893                 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
894                 hadRepeatableParam )
895            {
896                // special case: currentParam wasn't incremented, but we did
897                // have it, so don't give error
898                continue;
899            }
900
901            if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
902            {
903                errorMsg << wxString::Format(_("The required parameter '%s' was not specified."),
904                                             param.description.c_str())
905                         << _T('\n');
906
907                ok = false;
908            }
909        }
910    }
911
912    // if there was an error during parsing the command line, show this error
913    // and also the usage message if it had been requested
914    if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
915    {
916        wxMessageOutput* msgOut = wxMessageOutput::Get();
917        if ( msgOut )
918        {
919            wxString usage;
920            if ( showUsage )
921                usage = GetUsageString();
922
923            msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() );
924        }
925        else
926        {
927            wxFAIL_MSG( _T("no wxMessageOutput object?") );
928        }
929    }
930
931    return ok ? 0 : helpRequested ? -1 : 1;
932}
933
934// ----------------------------------------------------------------------------
935// give the usage message
936// ----------------------------------------------------------------------------
937
938void wxCmdLineParser::Usage()
939{
940    wxMessageOutput* msgOut = wxMessageOutput::Get();
941    if ( msgOut )
942    {
943        msgOut->Printf( wxT("%s"), GetUsageString().c_str() );
944    }
945    else
946    {
947        wxFAIL_MSG( _T("no wxMessageOutput object?") );
948    }
949}
950
951wxString wxCmdLineParser::GetUsageString()
952{
953    wxString appname;
954    if ( wxTheApp )
955    {
956        appname = wxFileName(wxTheApp->argv[0]).GetFullName();
957    }
958    else if (!m_data->m_arguments.empty() )
959    {
960        appname = wxFileName(m_data->m_arguments[0]).GetFullName();
961    }
962
963    // we construct the brief cmd line desc on the fly, but not the detailed
964    // help message below because we want to align the options descriptions
965    // and for this we must first know the longest one of them
966    wxString usage;
967    wxArrayString namesOptions, descOptions;
968
969    if ( !m_data->m_logo.empty() )
970    {
971        usage << m_data->m_logo << _T('\n');
972    }
973
974    usage << wxString::Format(_("Usage: %s"), appname.c_str());
975
976    // the switch char is usually '-' but this can be changed with
977    // SetSwitchChars() and then the first one of possible chars is used
978    wxChar chSwitch = !m_data->m_switchChars ? _T('-')
979                                             : m_data->m_switchChars[0u];
980
981    bool areLongOptionsEnabled = AreLongOptionsEnabled();
982    size_t n, count = m_data->m_options.GetCount();
983    for ( n = 0; n < count; n++ )
984    {
985        wxCmdLineOption& opt = m_data->m_options[n];
986
987        usage << _T(' ');
988        if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
989        {
990            usage << _T('[');
991        }
992
993        if ( !opt.shortName.empty() )
994        {
995            usage << chSwitch << opt.shortName;
996        }
997        else if ( areLongOptionsEnabled && !opt.longName.empty() )
998        {
999            usage << _T("--") << opt.longName;
1000        }
1001        else
1002        {
1003            if (!opt.longName.empty())
1004            {
1005                wxFAIL_MSG( wxT("option with only a long name while long ")
1006                            wxT("options are disabled") );
1007            }
1008            else
1009            {
1010                wxFAIL_MSG( _T("option without neither short nor long name") );
1011            }
1012        }
1013
1014        wxString option;
1015
1016        if ( !opt.shortName.empty() )
1017        {
1018            option << _T("  ") << chSwitch << opt.shortName;
1019        }
1020
1021        if ( areLongOptionsEnabled && !opt.longName.empty() )
1022        {
1023            option << (option.empty() ? _T("  ") : _T(", "))
1024                   << _T("--") << opt.longName;
1025        }
1026
1027        if ( opt.kind != wxCMD_LINE_SWITCH )
1028        {
1029            wxString val;
1030            val << _T('<') << GetTypeName(opt.type) << _T('>');
1031            usage << _T(' ') << val;
1032            option << (!opt.longName ? _T(':') : _T('=')) << val;
1033        }
1034
1035        if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1036        {
1037            usage << _T(']');
1038        }
1039
1040        namesOptions.push_back(option);
1041        descOptions.push_back(opt.description);
1042    }
1043
1044    count = m_data->m_paramDesc.GetCount();
1045    for ( n = 0; n < count; n++ )
1046    {
1047        wxCmdLineParam& param = m_data->m_paramDesc[n];
1048
1049        usage << _T(' ');
1050        if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1051        {
1052            usage << _T('[');
1053        }
1054
1055        usage << param.description;
1056
1057        if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
1058        {
1059            usage << _T("...");
1060        }
1061
1062        if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1063        {
1064            usage << _T(']');
1065        }
1066    }
1067
1068    usage << _T('\n');
1069
1070    // now construct the detailed help message
1071    size_t len, lenMax = 0;
1072    count = namesOptions.size();
1073    for ( n = 0; n < count; n++ )
1074    {
1075        len = namesOptions[n].length();
1076        if ( len > lenMax )
1077            lenMax = len;
1078    }
1079
1080    for ( n = 0; n < count; n++ )
1081    {
1082        len = namesOptions[n].length();
1083        usage << namesOptions[n]
1084              << wxString(_T(' '), lenMax - len) << _T('\t')
1085              << descOptions[n]
1086              << _T('\n');
1087    }
1088
1089    return usage;
1090}
1091
1092// ----------------------------------------------------------------------------
1093// private functions
1094// ----------------------------------------------------------------------------
1095
1096static wxString GetTypeName(wxCmdLineParamType type)
1097{
1098    wxString s;
1099    switch ( type )
1100    {
1101        default:
1102            wxFAIL_MSG( _T("unknown option type") );
1103            // still fall through
1104
1105        case wxCMD_LINE_VAL_STRING:
1106            s = _("str");
1107            break;
1108
1109        case wxCMD_LINE_VAL_NUMBER:
1110            s = _("num");
1111            break;
1112
1113        case wxCMD_LINE_VAL_DATE:
1114            s = _("date");
1115            break;
1116    }
1117
1118    return s;
1119}
1120
1121/*
1122Returns a string which is equal to the string pointed to by p, but up to the
1123point where p contains an character that's not allowed.
1124Allowable characters are letters and numbers, and characters pointed to by
1125the parameter allowedChars.
1126
1127For example, if p points to "abcde-@-_", and allowedChars is "-_",
1128this function returns "abcde-".
1129*/
1130static wxString GetOptionName(const wxChar *p,
1131    const wxChar *allowedChars)
1132{
1133    wxString argName;
1134
1135    while ( *p && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) )
1136    {
1137        argName += *p++;
1138    }
1139
1140    return argName;
1141}
1142
1143// Besides alphanumeric characters, short and long options can
1144// have other characters.
1145
1146// A short option additionally can have these
1147#define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1148
1149// A long option can have the same characters as a short option and a '-'.
1150#define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1151    wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1152
1153static wxString GetShortOptionName(const wxChar *p)
1154{
1155    return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION);
1156}
1157
1158static wxString GetLongOptionName(const wxChar *p)
1159{
1160    return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION);
1161}
1162
1163#endif // wxUSE_CMDLINE_PARSER
1164
1165// ----------------------------------------------------------------------------
1166// global functions
1167// ----------------------------------------------------------------------------
1168
1169/*
1170   This function is mainly used under Windows (as under Unix we always get the
1171   command line arguments as argc/argv anyhow) and so it tries to follow
1172   Windows conventions for the command line handling, not Unix ones. For
1173   instance, backslash is not special except when it precedes double quote when
1174   it does quote it.
1175 */
1176
1177/* static */
1178wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxChar *p)
1179{
1180    wxArrayString args;
1181
1182    wxString arg;
1183    arg.reserve(1024);
1184
1185    bool isInsideQuotes = false;
1186    for ( ;; )
1187    {
1188        // skip white space
1189        while ( *p == _T(' ') || *p == _T('\t') )
1190            p++;
1191
1192        // anything left?
1193        if ( *p == _T('\0') )
1194            break;
1195
1196        // parse this parameter
1197        bool endParam = false;
1198        bool lastBS = false;
1199        for ( arg.clear(); !endParam; p++ )
1200        {
1201            switch ( *p )
1202            {
1203                case _T('"'):
1204                    if ( !lastBS )
1205                    {
1206                        isInsideQuotes = !isInsideQuotes;
1207
1208                        // don't put quote in arg
1209                        continue;
1210                    }
1211                    //else: quote has no special meaning but the backslash
1212                    //      still remains -- makes no sense but this is what
1213                    //      Windows does
1214                    break;
1215
1216                case _T(' '):
1217                case _T('\t'):
1218                    // backslash does *not* quote the space, only quotes do
1219                    if ( isInsideQuotes )
1220                    {
1221                        // skip assignment below
1222                        break;
1223                    }
1224                    // fall through
1225
1226                case _T('\0'):
1227                    endParam = true;
1228
1229                    break;
1230            }
1231
1232            if ( endParam )
1233            {
1234                break;
1235            }
1236
1237            lastBS = !lastBS && *p == _T('\\');
1238
1239            arg += *p;
1240        }
1241
1242        args.push_back(arg);
1243    }
1244
1245    return args;
1246}
1247