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