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