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