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