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