]> git.saurik.com Git - wxWidgets.git/blob - src/common/cmdline.cpp
simplified and cleaned up wxGTK's focus handling
[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 const char *res = dt.ParseDate(value);
810 if ( !res || *res )
811 {
812 errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
813 name.c_str(), value.c_str())
814 << _T('\n');
815
816 ok = false;
817 }
818 else
819 {
820 opt.SetDateVal(dt);
821 }
822 }
823 break;
824 #endif // wxUSE_DATETIME
825 }
826 }
827 }
828 }
829 else // not an option, must be a parameter
830 {
831 if ( currentParam < countParam )
832 {
833 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
834
835 // TODO check the param type
836
837 m_data->m_parameters.push_back(arg);
838
839 if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
840 {
841 currentParam++;
842 }
843 else
844 {
845 wxASSERT_MSG( currentParam == countParam - 1,
846 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
847
848 // remember that we did have this last repeatable parameter
849 hadRepeatableParam = true;
850 }
851 }
852 else
853 {
854 errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str())
855 << _T('\n');
856
857 ok = false;
858 }
859 }
860 }
861
862 // verify that all mandatory options were given
863 if ( ok )
864 {
865 size_t countOpt = m_data->m_options.GetCount();
866 for ( size_t n = 0; ok && (n < countOpt); n++ )
867 {
868 wxCmdLineOption& opt = m_data->m_options[n];
869 if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
870 {
871 wxString optName;
872 if ( !opt.longName )
873 {
874 optName = opt.shortName;
875 }
876 else
877 {
878 if ( AreLongOptionsEnabled() )
879 {
880 optName.Printf( _("%s (or %s)"),
881 opt.shortName.c_str(),
882 opt.longName.c_str() );
883 }
884 else
885 {
886 optName.Printf( wxT("%s"),
887 opt.shortName.c_str() );
888 }
889 }
890
891 errorMsg << wxString::Format(_("The value for the option '%s' must be specified."),
892 optName.c_str())
893 << _T('\n');
894
895 ok = false;
896 }
897 }
898
899 for ( ; ok && (currentParam < countParam); currentParam++ )
900 {
901 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
902 if ( (currentParam == countParam - 1) &&
903 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
904 hadRepeatableParam )
905 {
906 // special case: currentParam wasn't incremented, but we did
907 // have it, so don't give error
908 continue;
909 }
910
911 if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
912 {
913 errorMsg << wxString::Format(_("The required parameter '%s' was not specified."),
914 param.description.c_str())
915 << _T('\n');
916
917 ok = false;
918 }
919 }
920 }
921
922 // if there was an error during parsing the command line, show this error
923 // and also the usage message if it had been requested
924 if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
925 {
926 wxMessageOutput* msgOut = wxMessageOutput::Get();
927 if ( msgOut )
928 {
929 wxString usage;
930 if ( showUsage )
931 usage = GetUsageString();
932
933 msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() );
934 }
935 else
936 {
937 wxFAIL_MSG( _T("no wxMessageOutput object?") );
938 }
939 }
940
941 return ok ? 0 : helpRequested ? -1 : 1;
942 }
943
944 // ----------------------------------------------------------------------------
945 // give the usage message
946 // ----------------------------------------------------------------------------
947
948 void wxCmdLineParser::Usage()
949 {
950 wxMessageOutput* msgOut = wxMessageOutput::Get();
951 if ( msgOut )
952 {
953 msgOut->Printf( wxT("%s"), GetUsageString().c_str() );
954 }
955 else
956 {
957 wxFAIL_MSG( _T("no wxMessageOutput object?") );
958 }
959 }
960
961 wxString wxCmdLineParser::GetUsageString()
962 {
963 wxString appname;
964 if ( m_data->m_arguments.empty() )
965 {
966 if ( wxTheApp )
967 appname = wxTheApp->GetAppName();
968 }
969 else // use argv[0]
970 {
971 appname = wxFileName(m_data->m_arguments[0]).GetName();
972 }
973
974 // we construct the brief cmd line desc on the fly, but not the detailed
975 // help message below because we want to align the options descriptions
976 // and for this we must first know the longest one of them
977 wxString usage;
978 wxArrayString namesOptions, descOptions;
979
980 if ( !m_data->m_logo.empty() )
981 {
982 usage << m_data->m_logo << _T('\n');
983 }
984
985 usage << wxString::Format(_("Usage: %s"), appname.c_str());
986
987 // the switch char is usually '-' but this can be changed with
988 // SetSwitchChars() and then the first one of possible chars is used
989 wxChar chSwitch = !m_data->m_switchChars ? _T('-')
990 : m_data->m_switchChars[0u];
991
992 bool areLongOptionsEnabled = AreLongOptionsEnabled();
993 size_t n, count = m_data->m_options.GetCount();
994 for ( n = 0; n < count; n++ )
995 {
996 wxCmdLineOption& opt = m_data->m_options[n];
997
998 usage << _T(' ');
999 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1000 {
1001 usage << _T('[');
1002 }
1003
1004 if ( !opt.shortName.empty() )
1005 {
1006 usage << chSwitch << opt.shortName;
1007 }
1008 else if ( areLongOptionsEnabled && !opt.longName.empty() )
1009 {
1010 usage << _T("--") << opt.longName;
1011 }
1012 else
1013 {
1014 if (!opt.longName.empty())
1015 {
1016 wxFAIL_MSG( wxT("option with only a long name while long ")
1017 wxT("options are disabled") );
1018 }
1019 else
1020 {
1021 wxFAIL_MSG( _T("option without neither short nor long name") );
1022 }
1023 }
1024
1025 wxString option;
1026
1027 if ( !opt.shortName.empty() )
1028 {
1029 option << _T(" ") << chSwitch << opt.shortName;
1030 }
1031
1032 if ( areLongOptionsEnabled && !opt.longName.empty() )
1033 {
1034 option << (option.empty() ? _T(" ") : _T(", "))
1035 << _T("--") << opt.longName;
1036 }
1037
1038 if ( opt.kind != wxCMD_LINE_SWITCH )
1039 {
1040 wxString val;
1041 val << _T('<') << GetTypeName(opt.type) << _T('>');
1042 usage << _T(' ') << val;
1043 option << (!opt.longName ? _T(':') : _T('=')) << val;
1044 }
1045
1046 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1047 {
1048 usage << _T(']');
1049 }
1050
1051 namesOptions.push_back(option);
1052 descOptions.push_back(opt.description);
1053 }
1054
1055 count = m_data->m_paramDesc.GetCount();
1056 for ( n = 0; n < count; n++ )
1057 {
1058 wxCmdLineParam& param = m_data->m_paramDesc[n];
1059
1060 usage << _T(' ');
1061 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1062 {
1063 usage << _T('[');
1064 }
1065
1066 usage << param.description;
1067
1068 if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
1069 {
1070 usage << _T("...");
1071 }
1072
1073 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1074 {
1075 usage << _T(']');
1076 }
1077 }
1078
1079 usage << _T('\n');
1080
1081 // set to number of our own options, not counting the standard ones
1082 count = namesOptions.size();
1083
1084 // get option names & descriptions for standard options, if any:
1085 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
1086 wxString stdDesc;
1087 if ( traits )
1088 stdDesc = traits->GetStandardCmdLineOptions(namesOptions, descOptions);
1089
1090 // now construct the detailed help message
1091 size_t len, lenMax = 0;
1092 for ( n = 0; n < namesOptions.size(); n++ )
1093 {
1094 len = namesOptions[n].length();
1095 if ( len > lenMax )
1096 lenMax = len;
1097 }
1098
1099 for ( n = 0; n < namesOptions.size(); n++ )
1100 {
1101 if ( n == count )
1102 usage << _T('\n') << stdDesc;
1103
1104 len = namesOptions[n].length();
1105 usage << namesOptions[n]
1106 << wxString(_T(' '), lenMax - len) << _T('\t')
1107 << descOptions[n]
1108 << _T('\n');
1109 }
1110
1111 return usage;
1112 }
1113
1114 // ----------------------------------------------------------------------------
1115 // private functions
1116 // ----------------------------------------------------------------------------
1117
1118 static wxString GetTypeName(wxCmdLineParamType type)
1119 {
1120 wxString s;
1121 switch ( type )
1122 {
1123 default:
1124 wxFAIL_MSG( _T("unknown option type") );
1125 // still fall through
1126
1127 case wxCMD_LINE_VAL_STRING:
1128 s = _("str");
1129 break;
1130
1131 case wxCMD_LINE_VAL_NUMBER:
1132 s = _("num");
1133 break;
1134
1135 case wxCMD_LINE_VAL_DATE:
1136 s = _("date");
1137 break;
1138 }
1139
1140 return s;
1141 }
1142
1143 /*
1144 Returns a string which is equal to the string pointed to by p, but up to the
1145 point where p contains an character that's not allowed.
1146 Allowable characters are letters and numbers, and characters pointed to by
1147 the parameter allowedChars.
1148
1149 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1150 this function returns "abcde-".
1151 */
1152 static wxString GetOptionName(wxString::const_iterator p,
1153 wxString::const_iterator end,
1154 const wxChar *allowedChars)
1155 {
1156 wxString argName;
1157
1158 while ( p != end && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) )
1159 {
1160 argName += *p++;
1161 }
1162
1163 return argName;
1164 }
1165
1166 // Besides alphanumeric characters, short and long options can
1167 // have other characters.
1168
1169 // A short option additionally can have these
1170 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1171
1172 // A long option can have the same characters as a short option and a '-'.
1173 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1174 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1175
1176 static wxString GetShortOptionName(wxString::const_iterator p,
1177 wxString::const_iterator end)
1178 {
1179 return GetOptionName(p, end, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION);
1180 }
1181
1182 static wxString GetLongOptionName(wxString::const_iterator p,
1183 wxString::const_iterator end)
1184 {
1185 return GetOptionName(p, end, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION);
1186 }
1187
1188 #endif // wxUSE_CMDLINE_PARSER
1189
1190 // ----------------------------------------------------------------------------
1191 // global functions
1192 // ----------------------------------------------------------------------------
1193
1194 /*
1195 This function is mainly used under Windows (as under Unix we always get the
1196 command line arguments as argc/argv anyhow) and so it tries to follow
1197 Windows conventions for the command line handling, not Unix ones. For
1198 instance, backslash is not special except when it precedes double quote when
1199 it does quote it.
1200 */
1201
1202 /* static */
1203 wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxString& cmdline)
1204 {
1205 wxArrayString args;
1206
1207 wxString arg;
1208 arg.reserve(1024);
1209
1210 bool isInsideQuotes = false;
1211
1212 wxString::const_iterator p = cmdline.begin();
1213
1214 for ( ;; )
1215 {
1216 // skip white space
1217 while ( p != cmdline.end() && (*p == _T(' ') || *p == _T('\t')) )
1218 ++p;
1219
1220 // anything left?
1221 if ( p == cmdline.end() )
1222 break;
1223
1224 // parse this parameter
1225 bool endParam = false;
1226 bool lastBS = false;
1227 for ( arg.clear(); !endParam; p++ )
1228 {
1229 switch ( (*p).GetValue() )
1230 {
1231 case _T('"'):
1232 if ( !lastBS )
1233 {
1234 isInsideQuotes = !isInsideQuotes;
1235
1236 // don't put quote in arg
1237 continue;
1238 }
1239 //else: quote has no special meaning but the backslash
1240 // still remains -- makes no sense but this is what
1241 // Windows does
1242 break;
1243
1244 case _T(' '):
1245 case _T('\t'):
1246 // backslash does *not* quote the space, only quotes do
1247 if ( isInsideQuotes )
1248 {
1249 // skip assignment below
1250 break;
1251 }
1252 // fall through
1253
1254 case _T('\0'):
1255 endParam = true;
1256
1257 break;
1258 }
1259
1260 if ( endParam )
1261 {
1262 break;
1263 }
1264
1265 lastBS = *p == _T('\\');
1266
1267 arg += *p;
1268 }
1269
1270 args.push_back(arg);
1271 }
1272
1273 return args;
1274 }