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