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