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