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