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