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