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