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