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