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