]> git.saurik.com Git - wxWidgets.git/blob - src/common/cmdline.cpp
extending implementation
[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.Count(); 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()) << wxT("\n");
599 }
600 }
601 else
602 {
603 optInd = wxNOT_FOUND; // Sanity check
604
605 // Print the argument including leading "--"
606 name.Prepend( wxT("--") );
607 errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) << wxT("\n");
608 }
609
610 }
611 else
612 {
613 isLong = false;
614
615 // a short one: as they can be cumulated, we try to find the
616 // longest substring which is a valid option
617 const wxChar *p = arg.c_str() + 1;
618
619 name = GetShortOptionName(p);
620
621 size_t len = name.length();
622 do
623 {
624 if ( len == 0 )
625 {
626 // we couldn't find a valid option name in the
627 // beginning of this string
628 errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) << wxT("\n");
629
630 break;
631 }
632 else
633 {
634 optInd = m_data->FindOption(name.Left(len));
635
636 // will try with one character less the next time
637 len--;
638 }
639 }
640 while ( optInd == wxNOT_FOUND );
641
642 len++; // compensates extra len-- above
643 if ( (optInd != wxNOT_FOUND) && (len != name.length()) )
644 {
645 // first of all, the option name is only part of this
646 // string
647 name = name.Left(len);
648
649 // our option is only part of this argument, there is
650 // something else in it - it is either the value of this
651 // option or other switches if it is a switch
652 if ( m_data->m_options[(size_t)optInd].kind
653 == wxCMD_LINE_SWITCH )
654 {
655 // pretend that all the rest of the argument is the
656 // next argument, in fact
657 wxString arg2 = arg[0u];
658 arg2 += arg.Mid(len + 1); // +1 for leading '-'
659
660 m_data->m_arguments.insert
661 (m_data->m_arguments.begin() + n + 1, arg2);
662 count++;
663 }
664 //else: it's our value, we'll deal with it below
665 }
666 }
667
668 if ( optInd == wxNOT_FOUND )
669 {
670 ok = false;
671
672 continue; // will break, in fact
673 }
674
675 wxCmdLineOption& opt = m_data->m_options[(size_t)optInd];
676 if ( opt.kind == wxCMD_LINE_SWITCH )
677 {
678 // nothing more to do
679 opt.SetHasValue();
680
681 if ( opt.flags & wxCMD_LINE_OPTION_HELP )
682 {
683 helpRequested = true;
684
685 // it's not an error, but we still stop here
686 ok = false;
687 }
688 }
689 else
690 {
691 // get the value
692
693 // +1 for leading '-'
694 const wxChar *p = arg.c_str() + 1 + name.length();
695 if ( isLong )
696 {
697 p++; // for another leading '-'
698
699 if ( *p++ != _T('=') )
700 {
701 errorMsg << wxString::Format(_("Option '%s' requires a value, '=' expected."), name.c_str()) << wxT("\n");
702
703 ok = false;
704 }
705 }
706 else
707 {
708 switch ( *p )
709 {
710 case _T('='):
711 case _T(':'):
712 // the value follows
713 p++;
714 break;
715
716 case 0:
717 // the value is in the next argument
718 if ( ++n == count )
719 {
720 // ... but there is none
721 errorMsg << wxString::Format(_("Option '%s' requires a value."),
722 name.c_str()) << wxT("\n");
723
724 ok = false;
725 }
726 else
727 {
728 // ... take it from there
729 p = m_data->m_arguments[n].c_str();
730 }
731 break;
732
733 default:
734 // the value is right here: this may be legal or
735 // not depending on the option style
736 if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR )
737 {
738 errorMsg << wxString::Format(_("Separator expected after the option '%s'."),
739 name.c_str()) << wxT("\n");
740
741 ok = false;
742 }
743 }
744 }
745
746 if ( ok )
747 {
748 wxString value = p;
749 switch ( opt.type )
750 {
751 default:
752 wxFAIL_MSG( _T("unknown option type") );
753 // still fall through
754
755 case wxCMD_LINE_VAL_STRING:
756 opt.SetStrVal(value);
757 break;
758
759 case wxCMD_LINE_VAL_NUMBER:
760 {
761 long val;
762 if ( value.ToLong(&val) )
763 {
764 opt.SetLongVal(val);
765 }
766 else
767 {
768 errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
769 value.c_str(), name.c_str()) << wxT("\n");
770
771 ok = false;
772 }
773 }
774 break;
775
776 #if wxUSE_DATETIME
777 case wxCMD_LINE_VAL_DATE:
778 {
779 wxDateTime dt;
780 const wxChar *res = dt.ParseDate(value);
781 if ( !res || *res )
782 {
783 errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
784 name.c_str(), value.c_str()) << wxT("\n");
785
786 ok = false;
787 }
788 else
789 {
790 opt.SetDateVal(dt);
791 }
792 }
793 break;
794 #endif // wxUSE_DATETIME
795 }
796 }
797 }
798 }
799 else
800 {
801 // a parameter
802 if ( currentParam < countParam )
803 {
804 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
805
806 // TODO check the param type
807
808 m_data->m_parameters.push_back(arg);
809
810 if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
811 {
812 currentParam++;
813 }
814 else
815 {
816 wxASSERT_MSG( currentParam == countParam - 1,
817 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
818
819 // remember that we did have this last repeatable parameter
820 hadRepeatableParam = true;
821 }
822 }
823 else
824 {
825 errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str()) << wxT("\n");
826
827 ok = false;
828 }
829 }
830 }
831
832 // verify that all mandatory options were given
833 if ( ok )
834 {
835 size_t countOpt = m_data->m_options.GetCount();
836 for ( size_t n = 0; ok && (n < countOpt); n++ )
837 {
838 wxCmdLineOption& opt = m_data->m_options[n];
839 if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
840 {
841 wxString optName;
842 if ( !opt.longName )
843 {
844 optName = opt.shortName;
845 }
846 else
847 {
848 if ( AreLongOptionsEnabled() )
849 {
850 optName.Printf( _("%s (or %s)"),
851 opt.shortName.c_str(),
852 opt.longName.c_str() );
853 }
854 else
855 {
856 optName.Printf( wxT("%s"),
857 opt.shortName.c_str() );
858 }
859 }
860
861 errorMsg << wxString::Format(_("The value for the option '%s' must be specified."),
862 optName.c_str()) << wxT("\n");
863
864 ok = false;
865 }
866 }
867
868 for ( ; ok && (currentParam < countParam); currentParam++ )
869 {
870 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
871 if ( (currentParam == countParam - 1) &&
872 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
873 hadRepeatableParam )
874 {
875 // special case: currentParam wasn't incremented, but we did
876 // have it, so don't give error
877 continue;
878 }
879
880 if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
881 {
882 errorMsg << wxString::Format(_("The required parameter '%s' was not specified."),
883 param.description.c_str()) << wxT("\n");
884
885 ok = false;
886 }
887 }
888 }
889
890 // if there was an error during parsing the command line, show this error
891 // and also the usage message if it had been requested
892 if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
893 {
894 wxMessageOutput* msgOut = wxMessageOutput::Get();
895 if ( msgOut )
896 {
897 wxString usage;
898 if ( showUsage )
899 usage = GetUsageString();
900
901 msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() );
902 }
903 else
904 {
905 wxFAIL_MSG( _T("no wxMessageOutput object?") );
906 }
907 }
908
909 return ok ? 0 : helpRequested ? -1 : 1;
910 }
911
912 // ----------------------------------------------------------------------------
913 // give the usage message
914 // ----------------------------------------------------------------------------
915
916 void wxCmdLineParser::Usage()
917 {
918 wxMessageOutput* msgOut = wxMessageOutput::Get();
919 if ( msgOut )
920 {
921 msgOut->Printf( wxT("%s"), GetUsageString().c_str() );
922 }
923 else
924 {
925 wxFAIL_MSG( _T("no wxMessageOutput object?") );
926 }
927 }
928
929 wxString wxCmdLineParser::GetUsageString()
930 {
931 wxString appname;
932 if ( m_data->m_arguments.empty() )
933 {
934 if ( wxTheApp )
935 appname = wxTheApp->GetAppName();
936 }
937 else // use argv[0]
938 {
939 appname = wxFileName(m_data->m_arguments[0]).GetName();
940 }
941
942 // we construct the brief cmd line desc on the fly, but not the detailed
943 // help message below because we want to align the options descriptions
944 // and for this we must first know the longest one of them
945 wxString usage;
946 wxArrayString namesOptions, descOptions;
947
948 if ( !m_data->m_logo.empty() )
949 {
950 usage << m_data->m_logo << _T('\n');
951 }
952
953 usage << wxString::Format(_("Usage: %s"), appname.c_str());
954
955 // the switch char is usually '-' but this can be changed with
956 // SetSwitchChars() and then the first one of possible chars is used
957 wxChar chSwitch = !m_data->m_switchChars ? _T('-')
958 : m_data->m_switchChars[0u];
959
960 bool areLongOptionsEnabled = AreLongOptionsEnabled();
961 size_t n, count = m_data->m_options.GetCount();
962 for ( n = 0; n < count; n++ )
963 {
964 wxCmdLineOption& opt = m_data->m_options[n];
965
966 usage << _T(' ');
967 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
968 {
969 usage << _T('[');
970 }
971
972 if ( !opt.shortName.empty() )
973 {
974 usage << chSwitch << opt.shortName;
975 }
976 else if ( areLongOptionsEnabled && !opt.longName.empty() )
977 {
978 usage << _T("--") << opt.longName;
979 }
980 else
981 {
982 if (!opt.longName.empty())
983 {
984 wxFAIL_MSG( wxT("option with only a long name while long ")
985 wxT("options are disabled") );
986 }
987 else
988 {
989 wxFAIL_MSG( _T("option without neither short nor long name") );
990 }
991 }
992
993 wxString option;
994
995 if ( !opt.shortName.empty() )
996 {
997 option << _T(" ") << chSwitch << opt.shortName;
998 }
999
1000 if ( areLongOptionsEnabled && !opt.longName.empty() )
1001 {
1002 option << (option.empty() ? _T(" ") : _T(", "))
1003 << _T("--") << opt.longName;
1004 }
1005
1006 if ( opt.kind != wxCMD_LINE_SWITCH )
1007 {
1008 wxString val;
1009 val << _T('<') << GetTypeName(opt.type) << _T('>');
1010 usage << _T(' ') << val;
1011 option << (!opt.longName ? _T(':') : _T('=')) << val;
1012 }
1013
1014 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1015 {
1016 usage << _T(']');
1017 }
1018
1019 namesOptions.push_back(option);
1020 descOptions.push_back(opt.description);
1021 }
1022
1023 count = m_data->m_paramDesc.GetCount();
1024 for ( n = 0; n < count; n++ )
1025 {
1026 wxCmdLineParam& param = m_data->m_paramDesc[n];
1027
1028 usage << _T(' ');
1029 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1030 {
1031 usage << _T('[');
1032 }
1033
1034 usage << param.description;
1035
1036 if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
1037 {
1038 usage << _T("...");
1039 }
1040
1041 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1042 {
1043 usage << _T(']');
1044 }
1045 }
1046
1047 usage << _T('\n');
1048
1049 // now construct the detailed help message
1050 size_t len, lenMax = 0;
1051 count = namesOptions.size();
1052 for ( n = 0; n < count; n++ )
1053 {
1054 len = namesOptions[n].length();
1055 if ( len > lenMax )
1056 lenMax = len;
1057 }
1058
1059 for ( n = 0; n < count; n++ )
1060 {
1061 len = namesOptions[n].length();
1062 usage << namesOptions[n]
1063 << wxString(_T(' '), lenMax - len) << _T('\t')
1064 << descOptions[n]
1065 << _T('\n');
1066 }
1067
1068 return usage;
1069 }
1070
1071 // ----------------------------------------------------------------------------
1072 // private functions
1073 // ----------------------------------------------------------------------------
1074
1075 static wxString GetTypeName(wxCmdLineParamType type)
1076 {
1077 wxString s;
1078 switch ( type )
1079 {
1080 default:
1081 wxFAIL_MSG( _T("unknown option type") );
1082 // still fall through
1083
1084 case wxCMD_LINE_VAL_STRING:
1085 s = _("str");
1086 break;
1087
1088 case wxCMD_LINE_VAL_NUMBER:
1089 s = _("num");
1090 break;
1091
1092 case wxCMD_LINE_VAL_DATE:
1093 s = _("date");
1094 break;
1095 }
1096
1097 return s;
1098 }
1099
1100 /*
1101 Returns a string which is equal to the string pointed to by p, but up to the
1102 point where p contains an character that's not allowed.
1103 Allowable characters are letters and numbers, and characters pointed to by
1104 the parameter allowedChars.
1105
1106 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1107 this function returns "abcde-".
1108 */
1109 static wxString GetOptionName(const wxChar *p,
1110 const wxChar *allowedChars)
1111 {
1112 wxString argName;
1113
1114 while ( *p && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) )
1115 {
1116 argName += *p++;
1117 }
1118
1119 return argName;
1120 }
1121
1122 // Besides alphanumeric characters, short and long options can
1123 // have other characters.
1124
1125 // A short option additionally can have these
1126 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1127
1128 // A long option can have the same characters as a short option and a '-'.
1129 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1130 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1131
1132 static wxString GetShortOptionName(const wxChar *p)
1133 {
1134 return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION);
1135 }
1136
1137 static wxString GetLongOptionName(const wxChar *p)
1138 {
1139 return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION);
1140 }
1141
1142 #endif // wxUSE_CMDLINE_PARSER
1143
1144 // ----------------------------------------------------------------------------
1145 // global functions
1146 // ----------------------------------------------------------------------------
1147
1148 /*
1149 This function is mainly used under Windows (as under Unix we always get the
1150 command line arguments as argc/argv anyhow) and so it tries to follow
1151 Windows conventions for the command line handling, not Unix ones. For
1152 instance, backslash is not special except when it precedes double quote when
1153 it does quote it.
1154 */
1155
1156 /* static */
1157 wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxChar *p)
1158 {
1159 wxArrayString args;
1160
1161 wxString arg;
1162 arg.reserve(1024);
1163
1164 bool isInsideQuotes = false;
1165 for ( ;; )
1166 {
1167 // skip white space
1168 while ( *p == _T(' ') || *p == _T('\t') )
1169 p++;
1170
1171 // anything left?
1172 if ( *p == _T('\0') )
1173 break;
1174
1175 // parse this parameter
1176 bool endParam = false;
1177 bool lastBS = false;
1178 for ( arg.clear(); !endParam; p++ )
1179 {
1180 switch ( *p )
1181 {
1182 case _T('"'):
1183 if ( !lastBS )
1184 {
1185 isInsideQuotes = !isInsideQuotes;
1186
1187 // don't put quote in arg
1188 continue;
1189 }
1190 //else: quote has no special meaning but the backslash
1191 // still remains -- makes no sense but this is what
1192 // Windows does
1193 break;
1194
1195 case _T(' '):
1196 case _T('\t'):
1197 // backslash does *not* quote the space, only quotes do
1198 if ( isInsideQuotes )
1199 {
1200 // skip assignment below
1201 break;
1202 }
1203 // fall through
1204
1205 case _T('\0'):
1206 endParam = true;
1207
1208 break;
1209 }
1210
1211 if ( endParam )
1212 {
1213 break;
1214 }
1215
1216 lastBS = *p == _T('\\');
1217
1218 arg += *p;
1219 }
1220
1221 args.push_back(arg);
1222 }
1223
1224 return args;
1225 }