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