]> git.saurik.com Git - wxWidgets.git/blob - src/common/cmdline.cpp
30bf7f09d6e50d1db4b6b8a767d3e475592c0649
[wxWidgets.git] / src / common / cmdline.cpp
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
50 static wxString GetTypeName(wxCmdLineParamType type);
51
52 static wxString GetOptionName(const wxChar *p, const wxChar *allowedChars);
53
54 static wxString GetShortOptionName(const wxChar *p);
55
56 static wxString GetLongOptionName(const wxChar *p);
57
58 // ----------------------------------------------------------------------------
59 // private structs
60 // ----------------------------------------------------------------------------
61
62 // an internal representation of an option
63 struct wxCmdLineOption
64 {
65 wxCmdLineOption(wxCmdLineEntryType k,
66 const wxString& shrt,
67 const wxString& lng,
68 const wxString& desc,
69 wxCmdLineParamType typ,
70 int fl)
71 {
72 wxASSERT_MSG( !shrt.empty() || !lng.empty(),
73 _T("option should have at least one name") );
74
75 wxASSERT_MSG
76 (
77 GetShortOptionName(shrt).Len() == shrt.Len(),
78 wxT("Short option contains invalid characters")
79 );
80
81 wxASSERT_MSG
82 (
83 GetLongOptionName(lng).Len() == lng.Len(),
84 wxT("Long option contains invalid characters")
85 );
86
87
88 kind = k;
89
90 shortName = shrt;
91 longName = lng;
92 description = desc;
93
94 type = typ;
95 flags = fl;
96
97 m_hasVal = false;
98 }
99
100 // can't use union easily here, so just store all possible data fields, we
101 // don't waste much (might still use union later if the number of supported
102 // types increases, so always use the accessor functions and don't access
103 // the fields directly!)
104
105 void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const
106 {
107 wxASSERT_MSG( type == typ, _T("type mismatch in wxCmdLineOption") );
108 }
109
110 long GetLongVal() const
111 { Check(wxCMD_LINE_VAL_NUMBER); return m_longVal; }
112 const wxString& GetStrVal() const
113 { Check(wxCMD_LINE_VAL_STRING); return m_strVal; }
114 #if wxUSE_DATETIME
115 const wxDateTime& GetDateVal() const
116 { Check(wxCMD_LINE_VAL_DATE); return m_dateVal; }
117 #endif // wxUSE_DATETIME
118
119 void SetLongVal(long val)
120 { Check(wxCMD_LINE_VAL_NUMBER); m_longVal = val; m_hasVal = true; }
121 void SetStrVal(const wxString& val)
122 { Check(wxCMD_LINE_VAL_STRING); m_strVal = val; m_hasVal = true; }
123 #if wxUSE_DATETIME
124 void SetDateVal(const wxDateTime& val)
125 { Check(wxCMD_LINE_VAL_DATE); m_dateVal = val; m_hasVal = true; }
126 #endif // wxUSE_DATETIME
127
128 void SetHasValue(bool hasValue = true) { m_hasVal = hasValue; }
129 bool HasValue() const { return m_hasVal; }
130
131 public:
132 wxCmdLineEntryType kind;
133 wxString shortName,
134 longName,
135 description;
136 wxCmdLineParamType type;
137 int flags;
138
139 private:
140 bool m_hasVal;
141
142 long m_longVal;
143 wxString m_strVal;
144 #if wxUSE_DATETIME
145 wxDateTime m_dateVal;
146 #endif // wxUSE_DATETIME
147 };
148
149 struct wxCmdLineParam
150 {
151 wxCmdLineParam(const wxString& desc,
152 wxCmdLineParamType typ,
153 int fl)
154 : description(desc)
155 {
156 type = typ;
157 flags = fl;
158 }
159
160 wxString description;
161 wxCmdLineParamType type;
162 int flags;
163 };
164
165 WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions);
166 WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams);
167
168 #include "wx/arrimpl.cpp"
169
170 WX_DEFINE_OBJARRAY(wxArrayOptions)
171 WX_DEFINE_OBJARRAY(wxArrayParams)
172
173 // the parser internal state
174 struct wxCmdLineParserData
175 {
176 // options
177 wxString m_switchChars; // characters which may start an option
178 bool m_enableLongOptions; // true if long options are enabled
179 wxString m_logo; // some extra text to show in Usage()
180
181 // cmd line data
182 wxArrayString m_arguments; // == argv, argc == m_arguments.GetCount()
183 wxArrayOptions m_options; // all possible options and switches
184 wxArrayParams m_paramDesc; // description of all possible params
185 wxArrayString m_parameters; // all params found
186
187 // methods
188 wxCmdLineParserData();
189 void SetArguments(int argc, char **argv);
190 #if wxUSE_UNICODE
191 void SetArguments(int argc, wxChar **argv);
192 #endif // wxUSE_UNICODE
193 void SetArguments(const wxString& cmdline);
194
195 int FindOption(const wxString& name);
196 int FindOptionByLongName(const wxString& name);
197 };
198
199 // ============================================================================
200 // implementation
201 // ============================================================================
202
203 // ----------------------------------------------------------------------------
204 // wxCmdLineParserData
205 // ----------------------------------------------------------------------------
206
207 wxCmdLineParserData::wxCmdLineParserData()
208 {
209 m_enableLongOptions = true;
210 #ifdef __UNIX_LIKE__
211 m_switchChars = _T("-");
212 #else // !Unix
213 m_switchChars = _T("/-");
214 #endif
215 }
216
217 void wxCmdLineParserData::SetArguments(int argc, char **argv)
218 {
219 m_arguments.clear();
220
221 for ( int n = 0; n < argc; n++ )
222 {
223 m_arguments.push_back(wxString::FromAscii(argv[n]));
224 }
225 }
226
227 #if wxUSE_UNICODE
228
229 void wxCmdLineParserData::SetArguments(int argc, wxChar **argv)
230 {
231 m_arguments.clear();
232
233 for ( int n = 0; n < argc; n++ )
234 {
235 m_arguments.push_back(argv[n]);
236 }
237 }
238
239 #endif // wxUSE_UNICODE
240
241 void wxCmdLineParserData::SetArguments(const wxString& cmdLine)
242 {
243 m_arguments.clear();
244
245 if(wxTheApp && wxTheApp->argc > 0)
246 m_arguments.push_back(wxTheApp->argv[0]);
247 else
248 m_arguments.push_back(wxEmptyString);
249
250 wxArrayString args = wxCmdLineParser::ConvertStringToArgs(cmdLine);
251
252 WX_APPEND_ARRAY(m_arguments, args);
253 }
254
255 int 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
273 int 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
292 void wxCmdLineParser::Init()
293 {
294 m_data = new wxCmdLineParserData;
295 }
296
297 void wxCmdLineParser::SetCmdLine(int argc, char **argv)
298 {
299 m_data->SetArguments(argc, argv);
300 }
301
302 #if wxUSE_UNICODE
303
304 void wxCmdLineParser::SetCmdLine(int argc, wxChar **argv)
305 {
306 m_data->SetArguments(argc, argv);
307 }
308
309 #endif // wxUSE_UNICODE
310
311 void wxCmdLineParser::SetCmdLine(const wxString& cmdline)
312 {
313 m_data->SetArguments(cmdline);
314 }
315
316 wxCmdLineParser::~wxCmdLineParser()
317 {
318 delete m_data;
319 }
320
321 // ----------------------------------------------------------------------------
322 // options
323 // ----------------------------------------------------------------------------
324
325 void wxCmdLineParser::SetSwitchChars(const wxString& switchChars)
326 {
327 m_data->m_switchChars = switchChars;
328 }
329
330 void wxCmdLineParser::EnableLongOptions(bool enable)
331 {
332 m_data->m_enableLongOptions = enable;
333 }
334
335 bool wxCmdLineParser::AreLongOptionsEnabled()
336 {
337 return m_data->m_enableLongOptions;
338 }
339
340 void wxCmdLineParser::SetLogo(const wxString& logo)
341 {
342 m_data->m_logo = logo;
343 }
344
345 // ----------------------------------------------------------------------------
346 // command line construction
347 // ----------------------------------------------------------------------------
348
349 void 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
379 void 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
394 void 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
410 void 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
441 bool 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
456 bool 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
475 bool 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
495 bool 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
515 size_t wxCmdLineParser::GetParamCount() const
516 {
517 return m_data->m_parameters.size();
518 }
519
520 wxString 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
528 void wxCmdLineParser::Reset()
529 {
530 for ( size_t i = 0; i < m_data->m_options.GetCount(); 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
542 int 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())
600 << _T('\n');
601 }
602 }
603 else
604 {
605 optInd = wxNOT_FOUND; // Sanity check
606
607 // Print the argument including leading "--"
608 name.Prepend( wxT("--") );
609 errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str())
610 << _T('\n');
611 }
612
613 }
614 else // not a long option
615 {
616 isLong = false;
617
618 // a short one: as they can be cumulated, we try to find the
619 // longest substring which is a valid option
620 const wxChar *p = arg.c_str() + 1;
621
622 name = GetShortOptionName(p);
623
624 size_t len = name.length();
625 do
626 {
627 if ( len == 0 )
628 {
629 // we couldn't find a valid option name in the
630 // beginning of this string
631 errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str())
632 << _T('\n');
633
634 break;
635 }
636 else
637 {
638 optInd = m_data->FindOption(name.Left(len));
639
640 // will try with one character less the next time
641 len--;
642 }
643 }
644 while ( optInd == wxNOT_FOUND );
645
646 len++; // compensates extra len-- above
647 if ( (optInd != wxNOT_FOUND) && (len != name.length()) )
648 {
649 // first of all, the option name is only part of this
650 // string
651 name = name.Left(len);
652
653 // our option is only part of this argument, there is
654 // something else in it - it is either the value of this
655 // option or other switches if it is a switch
656 if ( m_data->m_options[(size_t)optInd].kind
657 == wxCMD_LINE_SWITCH )
658 {
659 // pretend that all the rest of the argument is the
660 // next argument, in fact
661 wxString arg2 = arg[0u];
662 arg2 += arg.Mid(len + 1); // +1 for leading '-'
663
664 m_data->m_arguments.insert
665 (m_data->m_arguments.begin() + n + 1, arg2);
666 count++;
667 }
668 //else: it's our value, we'll deal with it below
669 }
670 }
671
672 if ( optInd == wxNOT_FOUND )
673 {
674 ok = false;
675
676 continue; // will break, in fact
677 }
678
679 // look at what follows:
680
681 // +1 for leading '-'
682 const wxChar *p = arg.c_str() + 1 + name.length();
683 if ( isLong )
684 p++; // for another leading '-'
685
686 wxCmdLineOption& opt = m_data->m_options[(size_t)optInd];
687 if ( opt.kind == wxCMD_LINE_SWITCH )
688 {
689 // we must check that there is no value following the switch
690 if ( *p != _T('\0') )
691 {
692 errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str())
693 << _T('\n');
694 ok = false;
695 }
696 else // no value, as expected
697 {
698 // nothing more to do
699 opt.SetHasValue();
700
701 if ( opt.flags & wxCMD_LINE_OPTION_HELP )
702 {
703 helpRequested = true;
704
705 // it's not an error, but we still stop here
706 ok = false;
707 }
708 }
709 }
710 else // it's an option. not a switch
711 {
712 // get the value
713 if ( isLong )
714 {
715 if ( *p++ != _T('=') )
716 {
717 errorMsg << wxString::Format(_("Option '%s' requires a value, '=' expected."), name.c_str())
718 << _T('\n');
719
720 ok = false;
721 }
722 }
723 else // short option
724 {
725 switch ( *p )
726 {
727 case _T('='):
728 case _T(':'):
729 // the value follows
730 p++;
731 break;
732
733 case 0:
734 // the value is in the next argument
735 if ( ++n == count )
736 {
737 // ... but there is none
738 errorMsg << wxString::Format(_("Option '%s' requires a value."),
739 name.c_str())
740 << _T('\n');
741
742 ok = false;
743 }
744 else
745 {
746 // ... take it from there
747 p = m_data->m_arguments[n].c_str();
748 }
749 break;
750
751 default:
752 // the value is right here: this may be legal or
753 // not depending on the option style
754 if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR )
755 {
756 errorMsg << wxString::Format(_("Separator expected after the option '%s'."),
757 name.c_str())
758 << _T('\n');
759
760 ok = false;
761 }
762 }
763 }
764
765 if ( ok )
766 {
767 wxString value = p;
768 switch ( opt.type )
769 {
770 default:
771 wxFAIL_MSG( _T("unknown option type") );
772 // still fall through
773
774 case wxCMD_LINE_VAL_STRING:
775 opt.SetStrVal(value);
776 break;
777
778 case wxCMD_LINE_VAL_NUMBER:
779 {
780 long val;
781 if ( value.ToLong(&val) )
782 {
783 opt.SetLongVal(val);
784 }
785 else
786 {
787 errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
788 value.c_str(), name.c_str())
789 << _T('\n');
790
791 ok = false;
792 }
793 }
794 break;
795
796 #if wxUSE_DATETIME
797 case wxCMD_LINE_VAL_DATE:
798 {
799 wxDateTime dt;
800 const wxChar *res = dt.ParseDate(value);
801 if ( !res || *res )
802 {
803 errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
804 name.c_str(), value.c_str())
805 << _T('\n');
806
807 ok = false;
808 }
809 else
810 {
811 opt.SetDateVal(dt);
812 }
813 }
814 break;
815 #endif // wxUSE_DATETIME
816 }
817 }
818 }
819 }
820 else // not an option, must be a parameter
821 {
822 if ( currentParam < countParam )
823 {
824 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
825
826 // TODO check the param type
827
828 m_data->m_parameters.push_back(arg);
829
830 if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
831 {
832 currentParam++;
833 }
834 else
835 {
836 wxASSERT_MSG( currentParam == countParam - 1,
837 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
838
839 // remember that we did have this last repeatable parameter
840 hadRepeatableParam = true;
841 }
842 }
843 else
844 {
845 errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str())
846 << _T('\n');
847
848 ok = false;
849 }
850 }
851 }
852
853 // verify that all mandatory options were given
854 if ( ok )
855 {
856 size_t countOpt = m_data->m_options.GetCount();
857 for ( size_t n = 0; ok && (n < countOpt); n++ )
858 {
859 wxCmdLineOption& opt = m_data->m_options[n];
860 if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
861 {
862 wxString optName;
863 if ( !opt.longName )
864 {
865 optName = opt.shortName;
866 }
867 else
868 {
869 if ( AreLongOptionsEnabled() )
870 {
871 optName.Printf( _("%s (or %s)"),
872 opt.shortName.c_str(),
873 opt.longName.c_str() );
874 }
875 else
876 {
877 optName.Printf( wxT("%s"),
878 opt.shortName.c_str() );
879 }
880 }
881
882 errorMsg << wxString::Format(_("The value for the option '%s' must be specified."),
883 optName.c_str())
884 << _T('\n');
885
886 ok = false;
887 }
888 }
889
890 for ( ; ok && (currentParam < countParam); currentParam++ )
891 {
892 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
893 if ( (currentParam == countParam - 1) &&
894 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
895 hadRepeatableParam )
896 {
897 // special case: currentParam wasn't incremented, but we did
898 // have it, so don't give error
899 continue;
900 }
901
902 if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
903 {
904 errorMsg << wxString::Format(_("The required parameter '%s' was not specified."),
905 param.description.c_str())
906 << _T('\n');
907
908 ok = false;
909 }
910 }
911 }
912
913 // if there was an error during parsing the command line, show this error
914 // and also the usage message if it had been requested
915 if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
916 {
917 wxMessageOutput* msgOut = wxMessageOutput::Get();
918 if ( msgOut )
919 {
920 wxString usage;
921 if ( showUsage )
922 usage = GetUsageString();
923
924 msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() );
925 }
926 else
927 {
928 wxFAIL_MSG( _T("no wxMessageOutput object?") );
929 }
930 }
931
932 return ok ? 0 : helpRequested ? -1 : 1;
933 }
934
935 // ----------------------------------------------------------------------------
936 // give the usage message
937 // ----------------------------------------------------------------------------
938
939 void wxCmdLineParser::Usage()
940 {
941 wxMessageOutput* msgOut = wxMessageOutput::Get();
942 if ( msgOut )
943 {
944 msgOut->Printf( wxT("%s"), GetUsageString().c_str() );
945 }
946 else
947 {
948 wxFAIL_MSG( _T("no wxMessageOutput object?") );
949 }
950 }
951
952 wxString wxCmdLineParser::GetUsageString()
953 {
954 wxString appname;
955 if ( m_data->m_arguments.empty() )
956 {
957 if ( wxTheApp )
958 appname = wxTheApp->GetAppName();
959 }
960 else // use argv[0]
961 {
962 appname = wxFileName(m_data->m_arguments[0]).GetName();
963 }
964
965 // we construct the brief cmd line desc on the fly, but not the detailed
966 // help message below because we want to align the options descriptions
967 // and for this we must first know the longest one of them
968 wxString usage;
969 wxArrayString namesOptions, descOptions;
970
971 if ( !m_data->m_logo.empty() )
972 {
973 usage << m_data->m_logo << _T('\n');
974 }
975
976 usage << wxString::Format(_("Usage: %s"), appname.c_str());
977
978 // the switch char is usually '-' but this can be changed with
979 // SetSwitchChars() and then the first one of possible chars is used
980 wxChar chSwitch = !m_data->m_switchChars ? _T('-')
981 : m_data->m_switchChars[0u];
982
983 bool areLongOptionsEnabled = AreLongOptionsEnabled();
984 size_t n, count = m_data->m_options.GetCount();
985 for ( n = 0; n < count; n++ )
986 {
987 wxCmdLineOption& opt = m_data->m_options[n];
988
989 usage << _T(' ');
990 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
991 {
992 usage << _T('[');
993 }
994
995 if ( !opt.shortName.empty() )
996 {
997 usage << chSwitch << opt.shortName;
998 }
999 else if ( areLongOptionsEnabled && !opt.longName.empty() )
1000 {
1001 usage << _T("--") << opt.longName;
1002 }
1003 else
1004 {
1005 if (!opt.longName.empty())
1006 {
1007 wxFAIL_MSG( wxT("option with only a long name while long ")
1008 wxT("options are disabled") );
1009 }
1010 else
1011 {
1012 wxFAIL_MSG( _T("option without neither short nor long name") );
1013 }
1014 }
1015
1016 wxString option;
1017
1018 if ( !opt.shortName.empty() )
1019 {
1020 option << _T(" ") << chSwitch << opt.shortName;
1021 }
1022
1023 if ( areLongOptionsEnabled && !opt.longName.empty() )
1024 {
1025 option << (option.empty() ? _T(" ") : _T(", "))
1026 << _T("--") << opt.longName;
1027 }
1028
1029 if ( opt.kind != wxCMD_LINE_SWITCH )
1030 {
1031 wxString val;
1032 val << _T('<') << GetTypeName(opt.type) << _T('>');
1033 usage << _T(' ') << val;
1034 option << (!opt.longName ? _T(':') : _T('=')) << val;
1035 }
1036
1037 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1038 {
1039 usage << _T(']');
1040 }
1041
1042 namesOptions.push_back(option);
1043 descOptions.push_back(opt.description);
1044 }
1045
1046 count = m_data->m_paramDesc.GetCount();
1047 for ( n = 0; n < count; n++ )
1048 {
1049 wxCmdLineParam& param = m_data->m_paramDesc[n];
1050
1051 usage << _T(' ');
1052 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1053 {
1054 usage << _T('[');
1055 }
1056
1057 usage << param.description;
1058
1059 if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
1060 {
1061 usage << _T("...");
1062 }
1063
1064 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1065 {
1066 usage << _T(']');
1067 }
1068 }
1069
1070 usage << _T('\n');
1071
1072 // set to number of our own options, not counting the standard ones
1073 count = namesOptions.size();
1074
1075 // get option names & descriptions for standard options, if any:
1076 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
1077 wxString stdDesc;
1078 if ( traits )
1079 stdDesc = traits->GetStandardCmdLineOptions(namesOptions, descOptions);
1080
1081 // now construct the detailed help message
1082 size_t len, lenMax = 0;
1083 for ( n = 0; n < namesOptions.size(); n++ )
1084 {
1085 len = namesOptions[n].length();
1086 if ( len > lenMax )
1087 lenMax = len;
1088 }
1089
1090 for ( n = 0; n < namesOptions.size(); n++ )
1091 {
1092 if ( n == count )
1093 usage << _T('\n') << stdDesc;
1094
1095 len = namesOptions[n].length();
1096 usage << namesOptions[n]
1097 << wxString(_T(' '), lenMax - len) << _T('\t')
1098 << descOptions[n]
1099 << _T('\n');
1100 }
1101
1102 return usage;
1103 }
1104
1105 // ----------------------------------------------------------------------------
1106 // private functions
1107 // ----------------------------------------------------------------------------
1108
1109 static wxString GetTypeName(wxCmdLineParamType type)
1110 {
1111 wxString s;
1112 switch ( type )
1113 {
1114 default:
1115 wxFAIL_MSG( _T("unknown option type") );
1116 // still fall through
1117
1118 case wxCMD_LINE_VAL_STRING:
1119 s = _("str");
1120 break;
1121
1122 case wxCMD_LINE_VAL_NUMBER:
1123 s = _("num");
1124 break;
1125
1126 case wxCMD_LINE_VAL_DATE:
1127 s = _("date");
1128 break;
1129 }
1130
1131 return s;
1132 }
1133
1134 /*
1135 Returns a string which is equal to the string pointed to by p, but up to the
1136 point where p contains an character that's not allowed.
1137 Allowable characters are letters and numbers, and characters pointed to by
1138 the parameter allowedChars.
1139
1140 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1141 this function returns "abcde-".
1142 */
1143 static wxString GetOptionName(const wxChar *p,
1144 const wxChar *allowedChars)
1145 {
1146 wxString argName;
1147
1148 while ( *p && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) )
1149 {
1150 argName += *p++;
1151 }
1152
1153 return argName;
1154 }
1155
1156 // Besides alphanumeric characters, short and long options can
1157 // have other characters.
1158
1159 // A short option additionally can have these
1160 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1161
1162 // A long option can have the same characters as a short option and a '-'.
1163 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1164 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1165
1166 static wxString GetShortOptionName(const wxChar *p)
1167 {
1168 return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION);
1169 }
1170
1171 static wxString GetLongOptionName(const wxChar *p)
1172 {
1173 return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION);
1174 }
1175
1176 #endif // wxUSE_CMDLINE_PARSER
1177
1178 // ----------------------------------------------------------------------------
1179 // global functions
1180 // ----------------------------------------------------------------------------
1181
1182 /*
1183 This function is mainly used under Windows (as under Unix we always get the
1184 command line arguments as argc/argv anyhow) and so it tries to follow
1185 Windows conventions for the command line handling, not Unix ones. For
1186 instance, backslash is not special except when it precedes double quote when
1187 it does quote it.
1188 */
1189
1190 /* static */
1191 wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxChar *p)
1192 {
1193 wxArrayString args;
1194
1195 wxString arg;
1196 arg.reserve(1024);
1197
1198 bool isInsideQuotes = false;
1199 for ( ;; )
1200 {
1201 // skip white space
1202 while ( *p == _T(' ') || *p == _T('\t') )
1203 p++;
1204
1205 // anything left?
1206 if ( *p == _T('\0') )
1207 break;
1208
1209 // parse this parameter
1210 bool endParam = false;
1211 bool lastBS = false;
1212 for ( arg.clear(); !endParam; p++ )
1213 {
1214 switch ( *p )
1215 {
1216 case _T('"'):
1217 if ( !lastBS )
1218 {
1219 isInsideQuotes = !isInsideQuotes;
1220
1221 // don't put quote in arg
1222 continue;
1223 }
1224 //else: quote has no special meaning but the backslash
1225 // still remains -- makes no sense but this is what
1226 // Windows does
1227 break;
1228
1229 case _T(' '):
1230 case _T('\t'):
1231 // backslash does *not* quote the space, only quotes do
1232 if ( isInsideQuotes )
1233 {
1234 // skip assignment below
1235 break;
1236 }
1237 // fall through
1238
1239 case _T('\0'):
1240 endParam = true;
1241
1242 break;
1243 }
1244
1245 if ( endParam )
1246 {
1247 break;
1248 }
1249
1250 lastBS = *p == _T('\\');
1251
1252 arg += *p;
1253 }
1254
1255 args.push_back(arg);
1256 }
1257
1258 return args;
1259 }