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