]> git.saurik.com Git - wxWidgets.git/blob - src/common/cmdline.cpp
Remove all lines containing cvs/svn "$Id$" keyword.
[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
685 // empty argument or just '-' is not an option but a parameter
686 if ( maybeOption && arg.length() > 1 &&
687 // FIXME-UTF8: use wc_str() after removing ANSI build
688 wxStrchr(m_data->m_switchChars.c_str(), arg[0u]) )
689 {
690 bool isLong;
691 wxString name;
692 int optInd = wxNOT_FOUND; // init to suppress warnings
693
694 // an option or a switch: find whether it's a long or a short one
695 if ( arg.length() >= 3 && arg[0u] == wxT('-') && arg[1u] == wxT('-') )
696 {
697 // a long one
698 isLong = true;
699
700 // Skip leading "--"
701 wxString::const_iterator p = arg.begin() + 2;
702
703 bool longOptionsEnabled = AreLongOptionsEnabled();
704
705 name = GetLongOptionName(p, arg.end());
706
707 if (longOptionsEnabled)
708 {
709 wxString errorOpt;
710
711 optInd = m_data->FindOptionByLongName(name);
712 if ( optInd == wxNOT_FOUND )
713 {
714 // Check if this could be a negatable long option.
715 if ( name.Last() == '-' )
716 {
717 name.RemoveLast();
718
719 optInd = m_data->FindOptionByLongName(name);
720 if ( optInd != wxNOT_FOUND )
721 {
722 if ( !(m_data->m_options[optInd].flags &
723 wxCMD_LINE_SWITCH_NEGATABLE) )
724 {
725 errorOpt.Printf
726 (
727 _("Option '%s' can't be negated"),
728 name
729 );
730 optInd = wxNOT_FOUND;
731 }
732 }
733 }
734
735 if ( optInd == wxNOT_FOUND )
736 {
737 if ( errorOpt.empty() )
738 {
739 errorOpt.Printf
740 (
741 _("Unknown long option '%s'"),
742 name
743 );
744 }
745
746 errorMsg << errorOpt << wxT('\n');
747 }
748 }
749 }
750 else
751 {
752 optInd = wxNOT_FOUND; // Sanity check
753
754 // Print the argument including leading "--"
755 name.Prepend( wxT("--") );
756 errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str())
757 << wxT('\n');
758 }
759
760 }
761 else // not a long option
762 {
763 isLong = false;
764
765 // a short one: as they can be cumulated, we try to find the
766 // longest substring which is a valid option
767 wxString::const_iterator p = arg.begin() + 1;
768
769 name = GetShortOptionName(p, arg.end());
770
771 size_t len = name.length();
772 do
773 {
774 if ( len == 0 )
775 {
776 // we couldn't find a valid option name in the
777 // beginning of this string
778 errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str())
779 << wxT('\n');
780
781 break;
782 }
783 else
784 {
785 optInd = m_data->FindOption(name.Left(len));
786
787 // will try with one character less the next time
788 len--;
789 }
790 }
791 while ( optInd == wxNOT_FOUND );
792
793 len++; // compensates extra len-- above
794 if ( (optInd != wxNOT_FOUND) && (len != name.length()) )
795 {
796 // first of all, the option name is only part of this
797 // string
798 name = name.Left(len);
799
800 // our option is only part of this argument, there is
801 // something else in it - it is either the value of this
802 // option or other switches if it is a switch
803 if ( m_data->m_options[(size_t)optInd].kind
804 == wxCMD_LINE_SWITCH )
805 {
806 // if the switch is negatable and it is just followed
807 // by '-' the '-' is considered to be part of this
808 // switch
809 if ( (m_data->m_options[(size_t)optInd].flags &
810 wxCMD_LINE_SWITCH_NEGATABLE) &&
811 arg[len] == '-' )
812 ++len;
813
814 // pretend that all the rest of the argument is the
815 // next argument, in fact
816 wxString arg2 = arg[0u];
817 arg2 += arg.Mid(len + 1); // +1 for leading '-'
818
819 m_data->m_arguments.insert
820 (m_data->m_arguments.begin() + n + 1, arg2);
821 count++;
822
823 // only leave the part which wasn't extracted into the
824 // next argument in this one
825 arg = arg.Left(len + 1);
826 }
827 //else: it's our value, we'll deal with it below
828 }
829 }
830
831 if ( optInd == wxNOT_FOUND )
832 {
833 ok = false;
834
835 continue; // will break, in fact
836 }
837
838 // look at what follows:
839
840 // +1 for leading '-'
841 wxString::const_iterator p = arg.begin() + 1 + name.length();
842 wxString::const_iterator end = arg.end();
843
844 if ( isLong )
845 ++p; // for another leading '-'
846
847 wxCmdLineOption& opt = m_data->m_options[(size_t)optInd];
848 if ( opt.kind == wxCMD_LINE_SWITCH )
849 {
850 // we must check that there is no value following the switch
851 bool negated = (opt.flags & wxCMD_LINE_SWITCH_NEGATABLE) &&
852 p != arg.end() && *p == '-';
853
854 if ( !negated && p != arg.end() )
855 {
856 errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str())
857 << wxT('\n');
858 ok = false;
859 }
860 else // no value, as expected
861 {
862 // nothing more to do
863 opt.SetHasValue();
864 if ( negated )
865 opt.SetNegated();
866
867 if ( opt.flags & wxCMD_LINE_OPTION_HELP )
868 {
869 helpRequested = true;
870
871 // it's not an error, but we still stop here
872 ok = false;
873 }
874 }
875 }
876 else // it's an option. not a switch
877 {
878 switch ( p == end ? '\0' : (*p).GetValue() )
879 {
880 case '=':
881 case ':':
882 // the value follows
883 ++p;
884 break;
885
886 case '\0':
887 // the value is in the next argument
888 if ( ++n == count )
889 {
890 // ... but there is none
891 errorMsg << wxString::Format(_("Option '%s' requires a value."),
892 name.c_str())
893 << wxT('\n');
894
895 ok = false;
896 }
897 else
898 {
899 // ... take it from there
900 p = m_data->m_arguments[n].begin();
901 end = m_data->m_arguments[n].end();
902 }
903 break;
904
905 default:
906 // the value is right here: this may be legal or
907 // not depending on the option style
908 if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR )
909 {
910 errorMsg << wxString::Format(_("Separator expected after the option '%s'."),
911 name.c_str())
912 << wxT('\n');
913
914 ok = false;
915 }
916 }
917
918 if ( ok )
919 {
920 wxString value(p, end);
921 switch ( opt.type )
922 {
923 default:
924 wxFAIL_MSG( wxT("unknown option type") );
925 // still fall through
926
927 case wxCMD_LINE_VAL_STRING:
928 opt.SetStrVal(value);
929 break;
930
931 case wxCMD_LINE_VAL_NUMBER:
932 {
933 long val;
934 if ( value.ToLong(&val) )
935 {
936 opt.SetLongVal(val);
937 }
938 else
939 {
940 errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
941 value.c_str(), name.c_str())
942 << wxT('\n');
943
944 ok = false;
945 }
946 }
947 break;
948
949 case wxCMD_LINE_VAL_DOUBLE:
950 {
951 double val;
952 if ( value.ToDouble(&val) )
953 {
954 opt.SetDoubleVal(val);
955 }
956 else
957 {
958 errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
959 value.c_str(), name.c_str())
960 << wxT('\n');
961
962 ok = false;
963 }
964 }
965 break;
966
967 #if wxUSE_DATETIME
968 case wxCMD_LINE_VAL_DATE:
969 {
970 wxDateTime dt;
971 wxString::const_iterator endDate;
972 if ( !dt.ParseDate(value, &endDate) || endDate != value.end() )
973 {
974 errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
975 name.c_str(), value.c_str())
976 << wxT('\n');
977
978 ok = false;
979 }
980 else
981 {
982 opt.SetDateVal(dt);
983 }
984 }
985 break;
986 #endif // wxUSE_DATETIME
987 }
988 }
989 }
990 }
991 else // not an option, must be a parameter
992 {
993 if ( currentParam < countParam )
994 {
995 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
996
997 // TODO check the param type
998
999 m_data->m_parameters.push_back(arg);
1000
1001 if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
1002 {
1003 currentParam++;
1004 }
1005 else
1006 {
1007 wxASSERT_MSG( currentParam == countParam - 1,
1008 wxT("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
1009
1010 // remember that we did have this last repeatable parameter
1011 hadRepeatableParam = true;
1012 }
1013 }
1014 else
1015 {
1016 errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str())
1017 << wxT('\n');
1018
1019 ok = false;
1020 }
1021 }
1022 }
1023
1024 // verify that all mandatory options were given
1025 if ( ok )
1026 {
1027 size_t countOpt = m_data->m_options.GetCount();
1028 for ( size_t n = 0; ok && (n < countOpt); n++ )
1029 {
1030 wxCmdLineOption& opt = m_data->m_options[n];
1031 if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
1032 {
1033 wxString optName;
1034 if ( !opt.longName )
1035 {
1036 optName = opt.shortName;
1037 }
1038 else
1039 {
1040 if ( AreLongOptionsEnabled() )
1041 {
1042 optName.Printf( _("%s (or %s)"),
1043 opt.shortName.c_str(),
1044 opt.longName.c_str() );
1045 }
1046 else
1047 {
1048 optName.Printf( wxT("%s"),
1049 opt.shortName.c_str() );
1050 }
1051 }
1052
1053 errorMsg << wxString::Format(_("The value for the option '%s' must be specified."),
1054 optName.c_str())
1055 << wxT('\n');
1056
1057 ok = false;
1058 }
1059 }
1060
1061 for ( ; ok && (currentParam < countParam); currentParam++ )
1062 {
1063 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
1064 if ( (currentParam == countParam - 1) &&
1065 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
1066 hadRepeatableParam )
1067 {
1068 // special case: currentParam wasn't incremented, but we did
1069 // have it, so don't give error
1070 continue;
1071 }
1072
1073 if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
1074 {
1075 errorMsg << wxString::Format(_("The required parameter '%s' was not specified."),
1076 param.description.c_str())
1077 << wxT('\n');
1078
1079 ok = false;
1080 }
1081 }
1082 }
1083
1084 // if there was an error during parsing the command line, show this error
1085 // and also the usage message if it had been requested
1086 if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
1087 {
1088 wxMessageOutput* msgOut = wxMessageOutput::Get();
1089 if ( msgOut )
1090 {
1091 wxString usage;
1092 if ( showUsage )
1093 usage = GetUsageString();
1094
1095 msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() );
1096 }
1097 else
1098 {
1099 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1100 }
1101 }
1102
1103 return ok ? 0 : helpRequested ? -1 : 1;
1104 }
1105
1106 // ----------------------------------------------------------------------------
1107 // give the usage message
1108 // ----------------------------------------------------------------------------
1109
1110 void wxCmdLineParser::Usage() const
1111 {
1112 wxMessageOutput* msgOut = wxMessageOutput::Get();
1113 if ( msgOut )
1114 {
1115 msgOut->Printf( wxT("%s"), GetUsageString().c_str() );
1116 }
1117 else
1118 {
1119 wxFAIL_MSG( wxT("no wxMessageOutput object?") );
1120 }
1121 }
1122
1123 wxString wxCmdLineParser::GetUsageString() const
1124 {
1125 wxString appname;
1126 if ( m_data->m_arguments.empty() )
1127 {
1128 if ( wxTheApp )
1129 appname = wxTheApp->GetAppName();
1130 }
1131 else // use argv[0]
1132 {
1133 appname = wxFileName(m_data->m_arguments[0]).GetName();
1134 }
1135
1136 // we construct the brief cmd line desc on the fly, but not the detailed
1137 // help message below because we want to align the options descriptions
1138 // and for this we must first know the longest one of them
1139 wxString usage;
1140 wxArrayString namesOptions, descOptions;
1141
1142 if ( !m_data->m_logo.empty() )
1143 {
1144 usage << m_data->m_logo << wxT('\n');
1145 }
1146
1147 usage << wxString::Format(_("Usage: %s"), appname.c_str());
1148
1149 // the switch char is usually '-' but this can be changed with
1150 // SetSwitchChars() and then the first one of possible chars is used
1151 wxChar chSwitch = !m_data->m_switchChars ? wxT('-')
1152 : m_data->m_switchChars[0u];
1153
1154 bool areLongOptionsEnabled = AreLongOptionsEnabled();
1155 size_t n, count = m_data->m_options.GetCount();
1156 for ( n = 0; n < count; n++ )
1157 {
1158 wxCmdLineOption& opt = m_data->m_options[n];
1159 wxString option, negator;
1160
1161 if ( opt.kind != wxCMD_LINE_USAGE_TEXT )
1162 {
1163 usage << wxT(' ');
1164 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1165 {
1166 usage << wxT('[');
1167 }
1168
1169 if ( opt.flags & wxCMD_LINE_SWITCH_NEGATABLE )
1170 negator = wxT("[-]");
1171
1172 if ( !opt.shortName.empty() )
1173 {
1174 usage << chSwitch << opt.shortName << negator;
1175 }
1176 else if ( areLongOptionsEnabled && !opt.longName.empty() )
1177 {
1178 usage << wxT("--") << opt.longName << negator;
1179 }
1180 else
1181 {
1182 if (!opt.longName.empty())
1183 {
1184 wxFAIL_MSG( wxT("option with only a long name while long ")
1185 wxT("options are disabled") );
1186 }
1187 else
1188 {
1189 wxFAIL_MSG( wxT("option without neither short nor long name") );
1190 }
1191 }
1192
1193 if ( !opt.shortName.empty() )
1194 {
1195 option << wxT(" ") << chSwitch << opt.shortName;
1196 }
1197
1198 if ( areLongOptionsEnabled && !opt.longName.empty() )
1199 {
1200 option << (option.empty() ? wxT(" ") : wxT(", "))
1201 << wxT("--") << opt.longName;
1202 }
1203
1204 if ( opt.kind != wxCMD_LINE_SWITCH )
1205 {
1206 wxString val;
1207 val << wxT('<') << GetTypeName(opt.type) << wxT('>');
1208 usage << wxT(' ') << val;
1209 option << (!opt.longName ? wxT(':') : wxT('=')) << val;
1210 }
1211
1212 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1213 {
1214 usage << wxT(']');
1215 }
1216 }
1217
1218 namesOptions.push_back(option);
1219 descOptions.push_back(opt.description);
1220 }
1221
1222 count = m_data->m_paramDesc.GetCount();
1223 for ( n = 0; n < count; n++ )
1224 {
1225 wxCmdLineParam& param = m_data->m_paramDesc[n];
1226
1227 usage << wxT(' ');
1228 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1229 {
1230 usage << wxT('[');
1231 }
1232
1233 usage << param.description;
1234
1235 if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
1236 {
1237 usage << wxT("...");
1238 }
1239
1240 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1241 {
1242 usage << wxT(']');
1243 }
1244 }
1245
1246 usage << wxT('\n');
1247
1248 // set to number of our own options, not counting the standard ones
1249 count = namesOptions.size();
1250
1251 // get option names & descriptions for standard options, if any:
1252 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
1253 wxString stdDesc;
1254 if ( traits )
1255 stdDesc = traits->GetStandardCmdLineOptions(namesOptions, descOptions);
1256
1257 // now construct the detailed help message
1258 size_t len, lenMax = 0;
1259 for ( n = 0; n < namesOptions.size(); n++ )
1260 {
1261 len = namesOptions[n].length();
1262 if ( len > lenMax )
1263 lenMax = len;
1264 }
1265
1266 for ( n = 0; n < namesOptions.size(); n++ )
1267 {
1268 if ( n == count )
1269 usage << wxT('\n') << stdDesc;
1270
1271 len = namesOptions[n].length();
1272 // desc contains text if name is empty
1273 if (len == 0)
1274 {
1275 usage << descOptions[n] << wxT('\n');
1276 }
1277 else
1278 {
1279 usage << namesOptions[n]
1280 << wxString(wxT(' '), lenMax - len) << wxT('\t')
1281 << descOptions[n]
1282 << wxT('\n');
1283 }
1284 }
1285
1286 return usage;
1287 }
1288
1289 // ----------------------------------------------------------------------------
1290 // private functions
1291 // ----------------------------------------------------------------------------
1292
1293 static wxString GetTypeName(wxCmdLineParamType type)
1294 {
1295 wxString s;
1296 switch ( type )
1297 {
1298 default:
1299 wxFAIL_MSG( wxT("unknown option type") );
1300 // still fall through
1301
1302 case wxCMD_LINE_VAL_STRING:
1303 s = _("str");
1304 break;
1305
1306 case wxCMD_LINE_VAL_NUMBER:
1307 s = _("num");
1308 break;
1309
1310 case wxCMD_LINE_VAL_DOUBLE:
1311 s = _("double");
1312 break;
1313
1314 case wxCMD_LINE_VAL_DATE:
1315 s = _("date");
1316 break;
1317 }
1318
1319 return s;
1320 }
1321
1322 /*
1323 Returns a string which is equal to the string pointed to by p, but up to the
1324 point where p contains an character that's not allowed.
1325 Allowable characters are letters and numbers, and characters pointed to by
1326 the parameter allowedChars.
1327
1328 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1329 this function returns "abcde-".
1330 */
1331 static wxString GetOptionName(wxString::const_iterator p,
1332 wxString::const_iterator end,
1333 const wxChar *allowedChars)
1334 {
1335 wxString argName;
1336
1337 while ( p != end && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) )
1338 {
1339 argName += *p++;
1340 }
1341
1342 return argName;
1343 }
1344
1345 // Besides alphanumeric characters, short and long options can
1346 // have other characters.
1347
1348 // A short option additionally can have these
1349 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1350
1351 // A long option can have the same characters as a short option and a '-'.
1352 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1353 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1354
1355 static wxString GetShortOptionName(wxString::const_iterator p,
1356 wxString::const_iterator end)
1357 {
1358 return GetOptionName(p, end, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION);
1359 }
1360
1361 static wxString GetLongOptionName(wxString::const_iterator p,
1362 wxString::const_iterator end)
1363 {
1364 return GetOptionName(p, end, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION);
1365 }
1366
1367 #endif // wxUSE_CMDLINE_PARSER
1368
1369 // ----------------------------------------------------------------------------
1370 // global functions
1371 // ----------------------------------------------------------------------------
1372
1373 /*
1374 This function is mainly used under Windows (as under Unix we always get the
1375 command line arguments as argc/argv anyhow) and so it tries to follow
1376 Windows conventions for the command line handling, not Unix ones. For
1377 instance, backslash is not special except when it precedes double quote when
1378 it does quote it.
1379
1380 TODO: Rewrite this to follow the even more complicated rule used by Windows
1381 CommandLineToArgv():
1382
1383 * A string of backslashes not followed by a quotation mark has no special
1384 meaning.
1385 * An even number of backslashes followed by a quotation mark is treated as
1386 pairs of protected backslashes, followed by a word terminator.
1387 * An odd number of backslashes followed by a quotation mark is treated as
1388 pairs of protected backslashes, followed by a protected quotation mark.
1389
1390 See http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
1391
1392 It could also be useful to provide a converse function which is also
1393 non-trivial, see
1394
1395 http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
1396 */
1397
1398 /* static */
1399 wxArrayString
1400 wxCmdLineParser::ConvertStringToArgs(const wxString& cmdline,
1401 wxCmdLineSplitType type)
1402 {
1403 wxArrayString args;
1404
1405 wxString arg;
1406 arg.reserve(1024);
1407
1408 const wxString::const_iterator end = cmdline.end();
1409 wxString::const_iterator p = cmdline.begin();
1410
1411 for ( ;; )
1412 {
1413 // skip white space
1414 while ( p != end && (*p == ' ' || *p == '\t') )
1415 ++p;
1416
1417 // anything left?
1418 if ( p == end )
1419 break;
1420
1421 // parse this parameter
1422 bool lastBS = false,
1423 isInsideQuotes = false;
1424 wxChar chDelim = '\0';
1425 for ( arg.clear(); p != end; ++p )
1426 {
1427 const wxChar ch = *p;
1428
1429 if ( type == wxCMD_LINE_SPLIT_DOS )
1430 {
1431 if ( ch == '"' )
1432 {
1433 if ( !lastBS )
1434 {
1435 isInsideQuotes = !isInsideQuotes;
1436
1437 // don't put quote in arg
1438 continue;
1439 }
1440 //else: quote has no special meaning but the backslash
1441 // still remains -- makes no sense but this is what
1442 // Windows does
1443 }
1444 // note that backslash does *not* quote the space, only quotes do
1445 else if ( !isInsideQuotes && (ch == ' ' || ch == '\t') )
1446 {
1447 ++p; // skip this space anyhow
1448 break;
1449 }
1450
1451 lastBS = !lastBS && ch == '\\';
1452 }
1453 else // type == wxCMD_LINE_SPLIT_UNIX
1454 {
1455 if ( !lastBS )
1456 {
1457 if ( isInsideQuotes )
1458 {
1459 if ( ch == chDelim )
1460 {
1461 isInsideQuotes = false;
1462
1463 continue; // don't use the quote itself
1464 }
1465 }
1466 else // not in quotes and not escaped
1467 {
1468 if ( ch == '\'' || ch == '"' )
1469 {
1470 isInsideQuotes = true;
1471 chDelim = ch;
1472
1473 continue; // don't use the quote itself
1474 }
1475
1476 if ( ch == ' ' || ch == '\t' )
1477 {
1478 ++p; // skip this space anyhow
1479 break;
1480 }
1481 }
1482
1483 lastBS = ch == '\\';
1484 if ( lastBS )
1485 continue;
1486 }
1487 else // escaped by backslash, just use as is
1488 {
1489 lastBS = false;
1490 }
1491 }
1492
1493 arg += ch;
1494 }
1495
1496 args.push_back(arg);
1497 }
1498
1499 return args;
1500 }