]> git.saurik.com Git - wxWidgets.git/blame - src/common/cmdline.cpp
Only account for WM frame extents in tlw size if WM supports _NET_FRAME_EXTENTS....
[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;
86501081
VS
809 // FIXME-UTF8: ParseDate API will need changes
810 const wxChar *res = dt.ParseDate(value.c_str());
9f83044f
VZ
811 if ( !res || *res )
812 {
74698d3a 813 errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
abce4ee6
VZ
814 name.c_str(), value.c_str())
815 << _T('\n');
9f83044f 816
36ebb50a 817 ok = false;
9f83044f
VZ
818 }
819 else
820 {
821 opt.SetDateVal(dt);
822 }
823 }
824 break;
e2b87f38 825#endif // wxUSE_DATETIME
9f83044f
VZ
826 }
827 }
828 }
829 }
abce4ee6 830 else // not an option, must be a parameter
9f83044f 831 {
9f83044f
VZ
832 if ( currentParam < countParam )
833 {
834 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
835
836 // TODO check the param type
837
df5168c4 838 m_data->m_parameters.push_back(arg);
9f83044f
VZ
839
840 if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
841 {
842 currentParam++;
843 }
844 else
845 {
846 wxASSERT_MSG( currentParam == countParam - 1,
fbdcff4a 847 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
9f83044f
VZ
848
849 // remember that we did have this last repeatable parameter
36ebb50a 850 hadRepeatableParam = true;
9f83044f
VZ
851 }
852 }
853 else
854 {
abce4ee6
VZ
855 errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str())
856 << _T('\n');
9f83044f 857
36ebb50a 858 ok = false;
9f83044f
VZ
859 }
860 }
861 }
862
863 // verify that all mandatory options were given
864 if ( ok )
865 {
866 size_t countOpt = m_data->m_options.GetCount();
867 for ( size_t n = 0; ok && (n < countOpt); n++ )
868 {
869 wxCmdLineOption& opt = m_data->m_options[n];
870 if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
871 {
872 wxString optName;
873 if ( !opt.longName )
874 {
875 optName = opt.shortName;
876 }
877 else
878 {
33293a32
VZ
879 if ( AreLongOptionsEnabled() )
880 {
881 optName.Printf( _("%s (or %s)"),
882 opt.shortName.c_str(),
883 opt.longName.c_str() );
884 }
885 else
886 {
887 optName.Printf( wxT("%s"),
888 opt.shortName.c_str() );
889 }
9f83044f
VZ
890 }
891
74698d3a 892 errorMsg << wxString::Format(_("The value for the option '%s' must be specified."),
abce4ee6
VZ
893 optName.c_str())
894 << _T('\n');
9f83044f 895
36ebb50a 896 ok = false;
9f83044f
VZ
897 }
898 }
899
900 for ( ; ok && (currentParam < countParam); currentParam++ )
901 {
902 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
903 if ( (currentParam == countParam - 1) &&
904 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
905 hadRepeatableParam )
906 {
907 // special case: currentParam wasn't incremented, but we did
908 // have it, so don't give error
909 continue;
910 }
911
912 if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
913 {
74698d3a 914 errorMsg << wxString::Format(_("The required parameter '%s' was not specified."),
abce4ee6
VZ
915 param.description.c_str())
916 << _T('\n');
9f83044f 917
36ebb50a 918 ok = false;
9f83044f
VZ
919 }
920 }
921 }
922
e9c54ec3
VZ
923 // if there was an error during parsing the command line, show this error
924 // and also the usage message if it had been requested
925 if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
9f83044f 926 {
74698d3a 927 wxMessageOutput* msgOut = wxMessageOutput::Get();
74698d3a 928 if ( msgOut )
e9c54ec3
VZ
929 {
930 wxString usage;
931 if ( showUsage )
932 usage = GetUsageString();
933
74698d3a 934 msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() );
e9c54ec3
VZ
935 }
936 else
937 {
938 wxFAIL_MSG( _T("no wxMessageOutput object?") );
939 }
9f83044f
VZ
940 }
941
942 return ok ? 0 : helpRequested ? -1 : 1;
943}
944
945// ----------------------------------------------------------------------------
946// give the usage message
947// ----------------------------------------------------------------------------
948
949void wxCmdLineParser::Usage()
74698d3a 950{
74698d3a
MB
951 wxMessageOutput* msgOut = wxMessageOutput::Get();
952 if ( msgOut )
e9c54ec3
VZ
953 {
954 msgOut->Printf( wxT("%s"), GetUsageString().c_str() );
955 }
956 else
957 {
958 wxFAIL_MSG( _T("no wxMessageOutput object?") );
959 }
74698d3a
MB
960}
961
962wxString wxCmdLineParser::GetUsageString()
9f83044f 963{
a2ec9439
VZ
964 wxString appname;
965 if ( m_data->m_arguments.empty() )
2822ee33 966 {
a2ec9439
VZ
967 if ( wxTheApp )
968 appname = wxTheApp->GetAppName();
969 }
970 else // use argv[0]
971 {
972 appname = wxFileName(m_data->m_arguments[0]).GetName();
2822ee33
VZ
973 }
974
f6bcfd97
BP
975 // we construct the brief cmd line desc on the fly, but not the detailed
976 // help message below because we want to align the options descriptions
977 // and for this we must first know the longest one of them
74698d3a 978 wxString usage;
f6bcfd97 979 wxArrayString namesOptions, descOptions;
74698d3a 980
e9c54ec3 981 if ( !m_data->m_logo.empty() )
74698d3a
MB
982 {
983 usage << m_data->m_logo << _T('\n');
984 }
985
986 usage << wxString::Format(_("Usage: %s"), appname.c_str());
9f83044f 987
f6bcfd97
BP
988 // the switch char is usually '-' but this can be changed with
989 // SetSwitchChars() and then the first one of possible chars is used
990 wxChar chSwitch = !m_data->m_switchChars ? _T('-')
991 : m_data->m_switchChars[0u];
992
250b589f 993 bool areLongOptionsEnabled = AreLongOptionsEnabled();
9f83044f
VZ
994 size_t n, count = m_data->m_options.GetCount();
995 for ( n = 0; n < count; n++ )
996 {
997 wxCmdLineOption& opt = m_data->m_options[n];
998
74698d3a 999 usage << _T(' ');
9f83044f
VZ
1000 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1001 {
74698d3a 1002 usage << _T('[');
9f83044f
VZ
1003 }
1004
be03c0ec
VZ
1005 if ( !opt.shortName.empty() )
1006 {
74698d3a 1007 usage << chSwitch << opt.shortName;
be03c0ec 1008 }
250b589f 1009 else if ( areLongOptionsEnabled && !opt.longName.empty() )
be03c0ec 1010 {
74698d3a 1011 usage << _T("--") << opt.longName;
be03c0ec
VZ
1012 }
1013 else
1014 {
250b589f
JS
1015 if (!opt.longName.empty())
1016 {
1017 wxFAIL_MSG( wxT("option with only a long name while long ")
abce4ee6 1018 wxT("options are disabled") );
250b589f
JS
1019 }
1020 else
1021 {
1022 wxFAIL_MSG( _T("option without neither short nor long name") );
1023 }
be03c0ec 1024 }
f6bcfd97
BP
1025
1026 wxString option;
be03c0ec
VZ
1027
1028 if ( !opt.shortName.empty() )
1029 {
1030 option << _T(" ") << chSwitch << opt.shortName;
1031 }
1032
250b589f 1033 if ( areLongOptionsEnabled && !opt.longName.empty() )
9f83044f 1034 {
be03c0ec
VZ
1035 option << (option.empty() ? _T(" ") : _T(", "))
1036 << _T("--") << opt.longName;
9f83044f
VZ
1037 }
1038
1039 if ( opt.kind != wxCMD_LINE_SWITCH )
1040 {
1041 wxString val;
1042 val << _T('<') << GetTypeName(opt.type) << _T('>');
74698d3a 1043 usage << _T(' ') << val;
f6bcfd97 1044 option << (!opt.longName ? _T(':') : _T('=')) << val;
9f83044f
VZ
1045 }
1046
1047 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1048 {
74698d3a 1049 usage << _T(']');
9f83044f
VZ
1050 }
1051
df5168c4
MB
1052 namesOptions.push_back(option);
1053 descOptions.push_back(opt.description);
9f83044f
VZ
1054 }
1055
1056 count = m_data->m_paramDesc.GetCount();
1057 for ( n = 0; n < count; n++ )
1058 {
1059 wxCmdLineParam& param = m_data->m_paramDesc[n];
1060
74698d3a 1061 usage << _T(' ');
9f83044f
VZ
1062 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1063 {
74698d3a 1064 usage << _T('[');
9f83044f
VZ
1065 }
1066
74698d3a 1067 usage << param.description;
9f83044f
VZ
1068
1069 if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
1070 {
74698d3a 1071 usage << _T("...");
9f83044f
VZ
1072 }
1073
1074 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1075 {
74698d3a 1076 usage << _T(']');
9f83044f
VZ
1077 }
1078 }
1079
74698d3a 1080 usage << _T('\n');
f6bcfd97 1081
d3a0a0ee
VZ
1082 // set to number of our own options, not counting the standard ones
1083 count = namesOptions.size();
1084
1085 // get option names & descriptions for standard options, if any:
1086 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
1087 wxString stdDesc;
1088 if ( traits )
1089 stdDesc = traits->GetStandardCmdLineOptions(namesOptions, descOptions);
1090
f6bcfd97
BP
1091 // now construct the detailed help message
1092 size_t len, lenMax = 0;
d3a0a0ee 1093 for ( n = 0; n < namesOptions.size(); n++ )
f6bcfd97
BP
1094 {
1095 len = namesOptions[n].length();
1096 if ( len > lenMax )
1097 lenMax = len;
1098 }
1099
d3a0a0ee 1100 for ( n = 0; n < namesOptions.size(); n++ )
f6bcfd97 1101 {
d3a0a0ee
VZ
1102 if ( n == count )
1103 usage << _T('\n') << stdDesc;
1104
f6bcfd97 1105 len = namesOptions[n].length();
74698d3a
MB
1106 usage << namesOptions[n]
1107 << wxString(_T(' '), lenMax - len) << _T('\t')
1108 << descOptions[n]
1109 << _T('\n');
f6bcfd97
BP
1110 }
1111
74698d3a 1112 return usage;
9f83044f
VZ
1113}
1114
1115// ----------------------------------------------------------------------------
31f6de22 1116// private functions
9f83044f
VZ
1117// ----------------------------------------------------------------------------
1118
1119static wxString GetTypeName(wxCmdLineParamType type)
1120{
1121 wxString s;
1122 switch ( type )
1123 {
1124 default:
1125 wxFAIL_MSG( _T("unknown option type") );
1126 // still fall through
1127
e9c54ec3
VZ
1128 case wxCMD_LINE_VAL_STRING:
1129 s = _("str");
1130 break;
1131
1132 case wxCMD_LINE_VAL_NUMBER:
1133 s = _("num");
1134 break;
1135
1136 case wxCMD_LINE_VAL_DATE:
1137 s = _("date");
1138 break;
9f83044f
VZ
1139 }
1140
1141 return s;
1142}
1e6feb95 1143
250b589f
JS
1144/*
1145Returns a string which is equal to the string pointed to by p, but up to the
1146point where p contains an character that's not allowed.
1147Allowable characters are letters and numbers, and characters pointed to by
1148the parameter allowedChars.
1149
1150For example, if p points to "abcde-@-_", and allowedChars is "-_",
1151this function returns "abcde-".
1152*/
86501081
VS
1153static wxString GetOptionName(wxString::const_iterator p,
1154 wxString::const_iterator end,
1155 const wxChar *allowedChars)
250b589f
JS
1156{
1157 wxString argName;
1158
86501081 1159 while ( p != end && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) )
250b589f
JS
1160 {
1161 argName += *p++;
1162 }
1163
1164 return argName;
1165}
1166
1167// Besides alphanumeric characters, short and long options can
1168// have other characters.
1169
1170// A short option additionally can have these
1171#define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1172
1173// A long option can have the same characters as a short option and a '-'.
1174#define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1175 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1176
86501081
VS
1177static wxString GetShortOptionName(wxString::const_iterator p,
1178 wxString::const_iterator end)
250b589f 1179{
86501081 1180 return GetOptionName(p, end, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION);
250b589f
JS
1181}
1182
86501081
VS
1183static wxString GetLongOptionName(wxString::const_iterator p,
1184 wxString::const_iterator end)
250b589f 1185{
86501081 1186 return GetOptionName(p, end, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION);
250b589f
JS
1187}
1188
1e6feb95 1189#endif // wxUSE_CMDLINE_PARSER
31f6de22
VZ
1190
1191// ----------------------------------------------------------------------------
1192// global functions
1193// ----------------------------------------------------------------------------
1194
217f9d07
VZ
1195/*
1196 This function is mainly used under Windows (as under Unix we always get the
7a1f9c09
VZ
1197 command line arguments as argc/argv anyhow) and so it tries to follow
1198 Windows conventions for the command line handling, not Unix ones. For
1199 instance, backslash is not special except when it precedes double quote when
1200 it does quote it.
217f9d07
VZ
1201 */
1202
31f6de22 1203/* static */
86501081 1204wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxString& cmdline)
31f6de22
VZ
1205{
1206 wxArrayString args;
1207
1208 wxString arg;
1209 arg.reserve(1024);
1210
7a1f9c09 1211 bool isInsideQuotes = false;
86501081
VS
1212
1213 wxString::const_iterator p = cmdline.begin();
1214
31f6de22
VZ
1215 for ( ;; )
1216 {
1217 // skip white space
86501081
VS
1218 while ( p != cmdline.end() && (*p == _T(' ') || *p == _T('\t')) )
1219 ++p;
31f6de22
VZ
1220
1221 // anything left?
86501081 1222 if ( p == cmdline.end() )
31f6de22
VZ
1223 break;
1224
1225 // parse this parameter
7a1f9c09
VZ
1226 bool endParam = false;
1227 bool lastBS = false;
1228 for ( arg.clear(); !endParam; p++ )
31f6de22 1229 {
86501081 1230 switch ( (*p).GetValue() )
31f6de22 1231 {
93b79b6b 1232 case _T('"'):
7a1f9c09 1233 if ( !lastBS )
31f6de22 1234 {
31f6de22 1235 isInsideQuotes = !isInsideQuotes;
31f6de22 1236
7a1f9c09
VZ
1237 // don't put quote in arg
1238 continue;
1239 }
1240 //else: quote has no special meaning but the backslash
1241 // still remains -- makes no sense but this is what
1242 // Windows does
31f6de22
VZ
1243 break;
1244
1245 case _T(' '):
1246 case _T('\t'):
7a1f9c09 1247 // backslash does *not* quote the space, only quotes do
217f9d07 1248 if ( isInsideQuotes )
31f6de22 1249 {
7a1f9c09 1250 // skip assignment below
31f6de22
VZ
1251 break;
1252 }
7a1f9c09 1253 // fall through
31f6de22
VZ
1254
1255 case _T('\0'):
36ebb50a 1256 endParam = true;
93b79b6b 1257
36ebb50a
VZ
1258 break;
1259 }
1260
1261 if ( endParam )
1262 {
1263 break;
31f6de22
VZ
1264 }
1265
7a1f9c09 1266 lastBS = *p == _T('\\');
31f6de22 1267
7a1f9c09 1268 arg += *p;
31f6de22
VZ
1269 }
1270
df5168c4 1271 args.push_back(arg);
31f6de22
VZ
1272 }
1273
1274 return args;
1275}