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