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