]> git.saurik.com Git - wxWidgets.git/blame - src/common/cmdline.cpp
added test for writing empty value to the config
[wxWidgets.git] / src / common / cmdline.cpp
CommitLineData
9f83044f
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: common/cmdline.cpp
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>
9// Licence: wxWindows license
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "cmdline.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
1e6feb95
VZ
31#if wxUSE_CMDLINE_PARSER
32
9f83044f
VZ
33#ifndef WX_PRECOMP
34 #include "wx/string.h"
35 #include "wx/log.h"
36 #include "wx/intl.h"
2822ee33 37 #include "wx/app.h"
9f83044f 38 #include "wx/dynarray.h"
2822ee33 39 #include "wx/filefn.h"
9f83044f
VZ
40#endif //WX_PRECOMP
41
ff0ea71c
GT
42#include <ctype.h>
43
9f83044f
VZ
44#include "wx/datetime.h"
45#include "wx/cmdline.h"
46
47// ----------------------------------------------------------------------------
48// private functions
49// ----------------------------------------------------------------------------
50
51static wxString GetTypeName(wxCmdLineParamType type);
52
53// ----------------------------------------------------------------------------
54// private classes
55// ----------------------------------------------------------------------------
56
57// an internal representation of an option
58struct wxCmdLineOption
59{
60 wxCmdLineOption(wxCmdLineEntryType k,
61 const wxString& shrt,
62 const wxString& lng,
63 const wxString& desc,
64 wxCmdLineParamType typ,
65 int fl)
66 {
bf188f1a
VZ
67 wxASSERT_MSG( !shrt.empty() || !lng.empty(),
68 _T("option should have at least one name") );
69
9f83044f
VZ
70 kind = k;
71
72 shortName = shrt;
73 longName = lng;
74 description = desc;
75
76 type = typ;
77 flags = fl;
78
79 m_hasVal = FALSE;
80 }
81
82 // can't use union easily here, so just store all possible data fields, we
83 // don't waste much (might still use union later if the number of supported
84 // types increases, so always use the accessor functions and don't access
85 // the fields directly!)
86
6f2a55e3 87 void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const
9f83044f
VZ
88 {
89 wxASSERT_MSG( type == typ, _T("type mismatch in wxCmdLineOption") );
90 }
91
92 long GetLongVal() const
93 { Check(wxCMD_LINE_VAL_NUMBER); return m_longVal; }
94 const wxString& GetStrVal() const
95 { Check(wxCMD_LINE_VAL_STRING); return m_strVal; }
96 const wxDateTime& GetDateVal() const
97 { Check(wxCMD_LINE_VAL_DATE); return m_dateVal; }
98
99 void SetLongVal(long val)
100 { Check(wxCMD_LINE_VAL_NUMBER); m_longVal = val; m_hasVal = TRUE; }
101 void SetStrVal(const wxString& val)
102 { Check(wxCMD_LINE_VAL_STRING); m_strVal = val; m_hasVal = TRUE; }
103 void SetDateVal(const wxDateTime val)
104 { Check(wxCMD_LINE_VAL_DATE); m_dateVal = val; m_hasVal = TRUE; }
105
07d09af8 106 void SetHasValue(bool hasValue = TRUE) { m_hasVal = hasValue; }
9f83044f
VZ
107 bool HasValue() const { return m_hasVal; }
108
109public:
110 wxCmdLineEntryType kind;
111 wxString shortName, longName, description;
112 wxCmdLineParamType type;
113 int flags;
114
115private:
116 bool m_hasVal;
117
118 long m_longVal;
119 wxString m_strVal;
120 wxDateTime m_dateVal;
121};
122
123struct wxCmdLineParam
124{
125 wxCmdLineParam(const wxString& desc,
126 wxCmdLineParamType typ,
127 int fl)
128 : description(desc)
129 {
130 type = typ;
131 flags = fl;
132 }
133
134 wxString description;
135 wxCmdLineParamType type;
136 int flags;
137};
138
139WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions);
140WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams);
141
142#include "wx/arrimpl.cpp"
143
144WX_DEFINE_OBJARRAY(wxArrayOptions);
145WX_DEFINE_OBJARRAY(wxArrayParams);
146
147// the parser internal state
148struct wxCmdLineParserData
149{
150 // options
151 wxString m_switchChars; // characters which may start an option
9f83044f 152 bool m_enableLongOptions; // TRUE if long options are enabled
e612f101 153 wxString m_logo; // some extra text to show in Usage()
9f83044f
VZ
154
155 // cmd line data
156 wxArrayString m_arguments; // == argv, argc == m_arguments.GetCount()
157 wxArrayOptions m_options; // all possible options and switchrs
158 wxArrayParams m_paramDesc; // description of all possible params
159 wxArrayString m_parameters; // all params found
160
161 // methods
162 wxCmdLineParserData();
55b2b0d8 163 void SetArguments(int argc, wxChar **argv);
9f83044f
VZ
164 void SetArguments(const wxString& cmdline);
165
166 int FindOption(const wxString& name);
167 int FindOptionByLongName(const wxString& name);
168};
169
170// ============================================================================
171// implementation
172// ============================================================================
173
174// ----------------------------------------------------------------------------
175// wxCmdLineParserData
176// ----------------------------------------------------------------------------
177
178wxCmdLineParserData::wxCmdLineParserData()
179{
180 m_enableLongOptions = TRUE;
181#ifdef __UNIX_LIKE__
182 m_switchChars = _T("-");
183#else // !Unix
184 m_switchChars = _T("/-");
185#endif
186}
187
55b2b0d8 188void wxCmdLineParserData::SetArguments(int argc, wxChar **argv)
9f83044f
VZ
189{
190 m_arguments.Empty();
191
192 for ( int n = 0; n < argc; n++ )
193 {
194 m_arguments.Add(argv[n]);
195 }
196}
197
97d59046 198void wxCmdLineParserData::SetArguments(const wxString& cmdLine)
9f83044f 199{
97d59046
JS
200 m_arguments.Empty();
201
202 m_arguments.Add(wxTheApp->GetAppName());
203
204 // Break up string
205 // Treat strings enclosed in double-quotes as single arguments
206 int i = 0;
207 int len = cmdLine.Length();
208 while (i < len)
209 {
210 // Skip whitespace
211 while ((i < len) && wxIsspace(cmdLine.GetChar(i)))
212 i ++;
9f83044f 213
97d59046
JS
214 if (i < len)
215 {
216 if (cmdLine.GetChar(i) == wxT('"')) // We found the start of a string
217 {
218 i ++;
219 int first = i;
220 while ((i < len) && (cmdLine.GetChar(i) != wxT('"')))
221 i ++;
222
223 wxString arg(cmdLine.Mid(first, (i - first)));
224
225 m_arguments.Add(arg);
226
227 if (i < len)
228 i ++; // Skip past 2nd quote
229 }
230 else // Unquoted argument
231 {
232 int first = i;
233 while ((i < len) && !wxIsspace(cmdLine.GetChar(i)))
234 i ++;
235
236 wxString arg(cmdLine.Mid(first, (i - first)));
237
238 m_arguments.Add(arg);
239 }
240 }
241 }
9f83044f
VZ
242}
243
244int wxCmdLineParserData::FindOption(const wxString& name)
245{
bf188f1a 246 if ( !name.empty() )
9f83044f 247 {
bf188f1a
VZ
248 size_t count = m_options.GetCount();
249 for ( size_t n = 0; n < count; n++ )
9f83044f 250 {
bf188f1a
VZ
251 if ( m_options[n].shortName == name )
252 {
253 // found
254 return n;
255 }
9f83044f
VZ
256 }
257 }
258
259 return wxNOT_FOUND;
260}
261
262int wxCmdLineParserData::FindOptionByLongName(const wxString& name)
263{
264 size_t count = m_options.GetCount();
265 for ( size_t n = 0; n < count; n++ )
266 {
267 if ( m_options[n].longName == name )
268 {
269 // found
270 return n;
271 }
272 }
273
274 return wxNOT_FOUND;
275}
276
277// ----------------------------------------------------------------------------
278// construction and destruction
279// ----------------------------------------------------------------------------
280
281void wxCmdLineParser::Init()
282{
283 m_data = new wxCmdLineParserData;
284}
285
55b2b0d8 286void wxCmdLineParser::SetCmdLine(int argc, wxChar **argv)
9f83044f
VZ
287{
288 m_data->SetArguments(argc, argv);
289}
290
291void wxCmdLineParser::SetCmdLine(const wxString& cmdline)
292{
293 m_data->SetArguments(cmdline);
294}
295
296wxCmdLineParser::~wxCmdLineParser()
297{
298 delete m_data;
299}
300
301// ----------------------------------------------------------------------------
302// options
303// ----------------------------------------------------------------------------
304
305void wxCmdLineParser::SetSwitchChars(const wxString& switchChars)
306{
307 m_data->m_switchChars = switchChars;
308}
309
310void wxCmdLineParser::EnableLongOptions(bool enable)
311{
312 m_data->m_enableLongOptions = enable;
313}
314
e612f101
VZ
315void wxCmdLineParser::SetLogo(const wxString& logo)
316{
317 m_data->m_logo = logo;
318}
319
9f83044f
VZ
320// ----------------------------------------------------------------------------
321// command line construction
322// ----------------------------------------------------------------------------
323
324void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc *desc)
325{
326 for ( ;; desc++ )
327 {
328 switch ( desc->kind )
329 {
330 case wxCMD_LINE_SWITCH:
e612f101
VZ
331 AddSwitch(desc->shortName, desc->longName, desc->description,
332 desc->flags);
9f83044f
VZ
333 break;
334
335 case wxCMD_LINE_OPTION:
336 AddOption(desc->shortName, desc->longName, desc->description,
337 desc->type, desc->flags);
338 break;
339
340 case wxCMD_LINE_PARAM:
341 AddParam(desc->description, desc->type, desc->flags);
342 break;
343
344 default:
345 wxFAIL_MSG( _T("unknown command line entry type") );
346 // still fall through
347
348 case wxCMD_LINE_NONE:
349 return;
350 }
351 }
352}
353
354void wxCmdLineParser::AddSwitch(const wxString& shortName,
355 const wxString& longName,
356 const wxString& desc,
357 int flags)
358{
359 wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND,
360 _T("duplicate switch") );
361
362 wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_SWITCH,
363 shortName, longName, desc,
364 wxCMD_LINE_VAL_NONE, flags);
365
366 m_data->m_options.Add(option);
367}
368
369void wxCmdLineParser::AddOption(const wxString& shortName,
370 const wxString& longName,
371 const wxString& desc,
372 wxCmdLineParamType type,
373 int flags)
374{
375 wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND,
376 _T("duplicate option") );
377
378 wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_OPTION,
379 shortName, longName, desc,
380 type, flags);
381
382 m_data->m_options.Add(option);
383}
384
385void wxCmdLineParser::AddParam(const wxString& desc,
386 wxCmdLineParamType type,
387 int flags)
388{
389 // do some consistency checks: a required parameter can't follow an
390 // optional one and nothing should follow a parameter with MULTIPLE flag
391#ifdef __WXDEBUG__
392 if ( !m_data->m_paramDesc.IsEmpty() )
393 {
394 wxCmdLineParam& param = m_data->m_paramDesc.Last();
395
396 wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE),
fbdcff4a 397 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
9f83044f
VZ
398
399 if ( !(flags & wxCMD_LINE_PARAM_OPTIONAL) )
400 {
401 wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL),
fbdcff4a 402 _T("a required parameter can't follow an optional one") );
9f83044f
VZ
403 }
404 }
405#endif // Debug
406
407 wxCmdLineParam *param = new wxCmdLineParam(desc, type, flags);
408
409 m_data->m_paramDesc.Add(param);
410}
411
412// ----------------------------------------------------------------------------
413// access to parse command line
414// ----------------------------------------------------------------------------
415
416bool wxCmdLineParser::Found(const wxString& name) const
417{
418 int i = m_data->FindOption(name);
bf188f1a
VZ
419 if ( i == wxNOT_FOUND )
420 i = m_data->FindOptionByLongName(name);
421
9f83044f
VZ
422 wxCHECK_MSG( i != wxNOT_FOUND, FALSE, _T("unknown switch") );
423
424 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
425 if ( !opt.HasValue() )
426 return FALSE;
427
428 return TRUE;
429}
430
431bool wxCmdLineParser::Found(const wxString& name, wxString *value) const
432{
433 int i = m_data->FindOption(name);
bf188f1a
VZ
434 if ( i == wxNOT_FOUND )
435 i = m_data->FindOptionByLongName(name);
436
9f83044f
VZ
437 wxCHECK_MSG( i != wxNOT_FOUND, FALSE, _T("unknown option") );
438
439 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
440 if ( !opt.HasValue() )
441 return FALSE;
442
443 wxCHECK_MSG( value, FALSE, _T("NULL pointer in wxCmdLineOption::Found") );
444
445 *value = opt.GetStrVal();
446
447 return TRUE;
448}
449
450bool wxCmdLineParser::Found(const wxString& name, long *value) const
451{
452 int i = m_data->FindOption(name);
bf188f1a
VZ
453 if ( i == wxNOT_FOUND )
454 i = m_data->FindOptionByLongName(name);
455
9f83044f
VZ
456 wxCHECK_MSG( i != wxNOT_FOUND, FALSE, _T("unknown option") );
457
458 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
459 if ( !opt.HasValue() )
460 return FALSE;
461
462 wxCHECK_MSG( value, FALSE, _T("NULL pointer in wxCmdLineOption::Found") );
463
464 *value = opt.GetLongVal();
465
466 return TRUE;
467}
468
469bool wxCmdLineParser::Found(const wxString& name, wxDateTime *value) const
470{
471 int i = m_data->FindOption(name);
bf188f1a
VZ
472 if ( i == wxNOT_FOUND )
473 i = m_data->FindOptionByLongName(name);
474
9f83044f
VZ
475 wxCHECK_MSG( i != wxNOT_FOUND, FALSE, _T("unknown option") );
476
477 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
478 if ( !opt.HasValue() )
479 return FALSE;
480
481 wxCHECK_MSG( value, FALSE, _T("NULL pointer in wxCmdLineOption::Found") );
482
483 *value = opt.GetDateVal();
484
485 return TRUE;
486}
487
488size_t wxCmdLineParser::GetParamCount() const
489{
490 return m_data->m_parameters.GetCount();
491}
492
493wxString wxCmdLineParser::GetParam(size_t n) const
494{
495 return m_data->m_parameters[n];
496}
497
07d09af8
JS
498// Resets switches and options
499void wxCmdLineParser::Reset()
500{
3f2bcf34
VZ
501 for ( size_t i = 0; i < m_data->m_options.Count(); i++ )
502 {
503 wxCmdLineOption& opt = m_data->m_options[i];
504 opt.SetHasValue(FALSE);
505 }
07d09af8
JS
506}
507
508
9f83044f
VZ
509// ----------------------------------------------------------------------------
510// the real work is done here
511// ----------------------------------------------------------------------------
512
513int wxCmdLineParser::Parse()
514{
515 bool maybeOption = TRUE; // can the following arg be an option?
516 bool ok = TRUE; // TRUE until an error is detected
517 bool helpRequested = FALSE; // TRUE if "-h" was given
518 bool hadRepeatableParam = FALSE; // TRUE if found param with MULTIPLE flag
519
520 size_t currentParam = 0; // the index in m_paramDesc
521
522 size_t countParam = m_data->m_paramDesc.GetCount();
523
3f2bcf34 524 Reset();
07d09af8 525
9f83044f
VZ
526 // parse everything
527 wxString arg;
528 size_t count = m_data->m_arguments.GetCount();
529 for ( size_t n = 1; ok && (n < count); n++ ) // 0 is program name
530 {
531 arg = m_data->m_arguments[n];
532
533 // special case: "--" should be discarded and all following arguments
534 // should be considered as parameters, even if they start with '-' and
535 // not like options (this is POSIX-like)
536 if ( arg == _T("--") )
537 {
538 maybeOption = FALSE;
539
540 continue;
541 }
542
543 // empty argument or just '-' is not an option but a parameter
544 if ( maybeOption && arg.length() > 1 &&
545 wxStrchr(m_data->m_switchChars, arg[0u]) )
546 {
547 bool isLong;
548 wxString name;
549 int optInd = wxNOT_FOUND; // init to suppress warnings
550
551 // an option or a switch: find whether it's a long or a short one
552 if ( m_data->m_enableLongOptions &&
553 arg[0u] == _T('-') && arg[1u] == _T('-') )
554 {
555 // a long one
556 isLong = TRUE;
557
558 const wxChar *p = arg.c_str() + 2;
f6bcfd97 559 while ( wxIsalnum(*p) || (*p == _T('_')) || (*p == _T('-')) )
9f83044f
VZ
560 {
561 name += *p++;
562 }
563
564 optInd = m_data->FindOptionByLongName(name);
565 if ( optInd == wxNOT_FOUND )
566 {
567 wxLogError(_("Unknown long option '%s'"), name.c_str());
568 }
569 }
570 else
571 {
572 isLong = FALSE;
573
574 // a short one: as they can be cumulated, we try to find the
575 // longest substring which is a valid option
576 const wxChar *p = arg.c_str() + 1;
f6bcfd97 577 while ( wxIsalnum(*p) || (*p == _T('_')) )
9f83044f
VZ
578 {
579 name += *p++;
580 }
581
582 size_t len = name.length();
583 do
584 {
585 if ( len == 0 )
586 {
587 // we couldn't find a valid option name in the
588 // beginning of this string
589 wxLogError(_("Unknown option '%s'"), name.c_str());
590
591 break;
592 }
593 else
594 {
595 optInd = m_data->FindOption(name.Left(len));
596
597 // will try with one character less the next time
598 len--;
599 }
600 }
601 while ( optInd == wxNOT_FOUND );
602
2822ee33 603 len++; // compensates extra len-- above
4f40f5e3 604 if ( (optInd != wxNOT_FOUND) && (len != name.length()) )
9f83044f 605 {
2822ee33
VZ
606 // first of all, the option name is only part of this
607 // string
608 name = name.Left(len);
609
9f83044f
VZ
610 // our option is only part of this argument, there is
611 // something else in it - it is either the value of this
612 // option or other switches if it is a switch
613 if ( m_data->m_options[(size_t)optInd].kind
614 == wxCMD_LINE_SWITCH )
615 {
616 // pretend that all the rest of the argument is the
617 // next argument, in fact
618 wxString arg2 = arg[0u];
2822ee33 619 arg2 += arg.Mid(len + 1); // +1 for leading '-'
9f83044f
VZ
620
621 m_data->m_arguments.Insert(arg2, n + 1);
4f40f5e3 622 count++;
9f83044f
VZ
623 }
624 //else: it's our value, we'll deal with it below
625 }
626 }
627
628 if ( optInd == wxNOT_FOUND )
629 {
630 ok = FALSE;
631
632 continue; // will break, in fact
633 }
634
635 wxCmdLineOption& opt = m_data->m_options[(size_t)optInd];
636 if ( opt.kind == wxCMD_LINE_SWITCH )
637 {
638 // nothing more to do
639 opt.SetHasValue();
640
641 if ( opt.flags & wxCMD_LINE_OPTION_HELP )
642 {
643 helpRequested = TRUE;
644
645 // it's not an error, but we still stop here
646 ok = FALSE;
647 }
648 }
649 else
650 {
651 // get the value
652
653 // +1 for leading '-'
654 const wxChar *p = arg.c_str() + 1 + name.length();
655 if ( isLong )
656 {
657 p++; // for another leading '-'
658
659 if ( *p++ != _T('=') )
660 {
fbdcff4a 661 wxLogError(_("Option '%s' requires a value, '=' expected."), name.c_str());
9f83044f
VZ
662
663 ok = FALSE;
664 }
665 }
666 else
667 {
668 switch ( *p )
669 {
f6bcfd97 670 case _T('='):
9f83044f
VZ
671 case _T(':'):
672 // the value follows
673 p++;
674 break;
675
676 case 0:
677 // the value is in the next argument
678 if ( ++n == count )
679 {
680 // ... but there is none
681 wxLogError(_("Option '%s' requires a value."),
682 name.c_str());
683
684 ok = FALSE;
685 }
686 else
687 {
688 // ... take it from there
689 p = m_data->m_arguments[n].c_str();
690 }
691 break;
692
693 default:
f6bcfd97
BP
694 // the value is right here: this may be legal or
695 // not depending on the option style
696 if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR )
697 {
698 wxLogError(_("Separator expected after the option '%s'."),
699 name.c_str());
700
701 ok = FALSE;
702 }
9f83044f
VZ
703 }
704 }
705
706 if ( ok )
707 {
708 wxString value = p;
709 switch ( opt.type )
710 {
711 default:
712 wxFAIL_MSG( _T("unknown option type") );
713 // still fall through
714
715 case wxCMD_LINE_VAL_STRING:
716 opt.SetStrVal(value);
717 break;
718
719 case wxCMD_LINE_VAL_NUMBER:
720 {
721 long val;
722 if ( value.ToLong(&val) )
723 {
724 opt.SetLongVal(val);
725 }
726 else
727 {
fbdcff4a 728 wxLogError(_("'%s' is not a correct numeric value for option '%s'."),
9f83044f
VZ
729 value.c_str(), name.c_str());
730
731 ok = FALSE;
732 }
733 }
734 break;
735
736 case wxCMD_LINE_VAL_DATE:
737 {
738 wxDateTime dt;
739 const wxChar *res = dt.ParseDate(value);
740 if ( !res || *res )
741 {
fbdcff4a 742 wxLogError(_("Option '%s': '%s' cannot be converted to a date."),
9f83044f
VZ
743 name.c_str(), value.c_str());
744
745 ok = FALSE;
746 }
747 else
748 {
749 opt.SetDateVal(dt);
750 }
751 }
752 break;
753 }
754 }
755 }
756 }
757 else
758 {
759 // a parameter
760 if ( currentParam < countParam )
761 {
762 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
763
764 // TODO check the param type
765
766 m_data->m_parameters.Add(arg);
767
768 if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
769 {
770 currentParam++;
771 }
772 else
773 {
774 wxASSERT_MSG( currentParam == countParam - 1,
fbdcff4a 775 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
9f83044f
VZ
776
777 // remember that we did have this last repeatable parameter
778 hadRepeatableParam = TRUE;
779 }
780 }
781 else
782 {
783 wxLogError(_("Unexpected parameter '%s'"), arg.c_str());
784
785 ok = FALSE;
786 }
787 }
788 }
789
790 // verify that all mandatory options were given
791 if ( ok )
792 {
793 size_t countOpt = m_data->m_options.GetCount();
794 for ( size_t n = 0; ok && (n < countOpt); n++ )
795 {
796 wxCmdLineOption& opt = m_data->m_options[n];
797 if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
798 {
799 wxString optName;
800 if ( !opt.longName )
801 {
802 optName = opt.shortName;
803 }
804 else
805 {
806 optName.Printf(_("%s (or %s)"),
807 opt.shortName.c_str(),
808 opt.longName.c_str());
809 }
810
811 wxLogError(_("The value for the option '%s' must be specified."),
812 optName.c_str());
813
814 ok = FALSE;
815 }
816 }
817
818 for ( ; ok && (currentParam < countParam); currentParam++ )
819 {
820 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
821 if ( (currentParam == countParam - 1) &&
822 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
823 hadRepeatableParam )
824 {
825 // special case: currentParam wasn't incremented, but we did
826 // have it, so don't give error
827 continue;
828 }
829
830 if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
831 {
832 wxLogError(_("The required parameter '%s' was not specified."),
833 param.description.c_str());
834
835 ok = FALSE;
836 }
837 }
838 }
839
840 if ( !ok )
841 {
842 Usage();
843 }
844
845 return ok ? 0 : helpRequested ? -1 : 1;
846}
847
848// ----------------------------------------------------------------------------
849// give the usage message
850// ----------------------------------------------------------------------------
851
852void wxCmdLineParser::Usage()
853{
2822ee33
VZ
854 wxString appname = wxTheApp->GetAppName();
855 if ( !appname )
856 {
857 wxCHECK_RET( !m_data->m_arguments.IsEmpty(), _T("no program name") );
858
859 appname = wxFileNameFromPath(m_data->m_arguments[0]);
860 wxStripExtension(appname);
861 }
862
f6bcfd97
BP
863 // we construct the brief cmd line desc on the fly, but not the detailed
864 // help message below because we want to align the options descriptions
865 // and for this we must first know the longest one of them
866 wxString brief;
867 wxArrayString namesOptions, descOptions;
2822ee33 868 brief.Printf(_("Usage: %s"), appname.c_str());
9f83044f 869
f6bcfd97
BP
870 // the switch char is usually '-' but this can be changed with
871 // SetSwitchChars() and then the first one of possible chars is used
872 wxChar chSwitch = !m_data->m_switchChars ? _T('-')
873 : m_data->m_switchChars[0u];
874
9f83044f
VZ
875 size_t n, count = m_data->m_options.GetCount();
876 for ( n = 0; n < count; n++ )
877 {
878 wxCmdLineOption& opt = m_data->m_options[n];
879
880 brief << _T(' ');
881 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
882 {
883 brief << _T('[');
884 }
885
f6bcfd97
BP
886 brief << chSwitch << opt.shortName;
887
888 wxString option;
889 option << _T(" ") << chSwitch << opt.shortName;
9f83044f
VZ
890 if ( !!opt.longName )
891 {
f6bcfd97 892 option << _T(" --") << opt.longName;
9f83044f
VZ
893 }
894
895 if ( opt.kind != wxCMD_LINE_SWITCH )
896 {
897 wxString val;
898 val << _T('<') << GetTypeName(opt.type) << _T('>');
899 brief << _T(' ') << val;
f6bcfd97 900 option << (!opt.longName ? _T(':') : _T('=')) << val;
9f83044f
VZ
901 }
902
903 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
904 {
905 brief << _T(']');
906 }
907
f6bcfd97
BP
908 namesOptions.Add(option);
909 descOptions.Add(opt.description);
9f83044f
VZ
910 }
911
912 count = m_data->m_paramDesc.GetCount();
913 for ( n = 0; n < count; n++ )
914 {
915 wxCmdLineParam& param = m_data->m_paramDesc[n];
916
917 brief << _T(' ');
918 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
919 {
920 brief << _T('[');
921 }
922
923 brief << param.description;
924
925 if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
926 {
927 brief << _T("...");
928 }
929
930 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
931 {
932 brief << _T(']');
933 }
934 }
935
e612f101
VZ
936 if ( !!m_data->m_logo )
937 {
938 wxLogMessage(m_data->m_logo);
939 }
940
9f83044f 941 wxLogMessage(brief);
f6bcfd97
BP
942
943 // now construct the detailed help message
944 size_t len, lenMax = 0;
945 count = namesOptions.GetCount();
946 for ( n = 0; n < count; n++ )
947 {
948 len = namesOptions[n].length();
949 if ( len > lenMax )
950 lenMax = len;
951 }
952
953 wxString detailed;
954 for ( n = 0; n < count; n++ )
955 {
956 len = namesOptions[n].length();
957 detailed << namesOptions[n]
958 << wxString(_T(' '), lenMax - len) << _T('\t')
959 << descOptions[n]
960 << _T('\n');
961 }
962
9f83044f
VZ
963 wxLogMessage(detailed);
964}
965
966// ----------------------------------------------------------------------------
967// global functions
968// ----------------------------------------------------------------------------
969
970static wxString GetTypeName(wxCmdLineParamType type)
971{
972 wxString s;
973 switch ( type )
974 {
975 default:
976 wxFAIL_MSG( _T("unknown option type") );
977 // still fall through
978
979 case wxCMD_LINE_VAL_STRING: s = _("str"); break;
980 case wxCMD_LINE_VAL_NUMBER: s = _("num"); break;
981 case wxCMD_LINE_VAL_DATE: s = _("date"); break;
982 }
983
984 return s;
985}
1e6feb95
VZ
986
987#endif // wxUSE_CMDLINE_PARSER