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