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