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