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