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