added cmd line parsing support to wxApp and --theme option to wxUniv
[wxWidgets.git] / src / common / cmdline.cpp
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
31 #if wxUSE_CMDLINE_PARSER
32
33 #ifndef WX_PRECOMP
34 #include "wx/string.h"
35 #include "wx/log.h"
36 #include "wx/intl.h"
37 #include "wx/app.h"
38 #include "wx/dynarray.h"
39 #include "wx/filefn.h"
40 #endif //WX_PRECOMP
41
42 #include <ctype.h>
43
44 #include "wx/datetime.h"
45 #include "wx/cmdline.h"
46
47 // ----------------------------------------------------------------------------
48 // private functions
49 // ----------------------------------------------------------------------------
50
51 static wxString GetTypeName(wxCmdLineParamType type);
52
53 // ----------------------------------------------------------------------------
54 // private classes
55 // ----------------------------------------------------------------------------
56
57 // an internal representation of an option
58 struct 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 wxASSERT_MSG( !shrt.empty() || !lng.empty(),
68 _T("option should have at least one name") );
69
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
87 void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const
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
106 void SetHasValue(bool hasValue = TRUE) { m_hasVal = hasValue; }
107 bool HasValue() const { return m_hasVal; }
108
109 public:
110 wxCmdLineEntryType kind;
111 wxString shortName, longName, description;
112 wxCmdLineParamType type;
113 int flags;
114
115 private:
116 bool m_hasVal;
117
118 long m_longVal;
119 wxString m_strVal;
120 wxDateTime m_dateVal;
121 };
122
123 struct 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
139 WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions);
140 WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams);
141
142 #include "wx/arrimpl.cpp"
143
144 WX_DEFINE_OBJARRAY(wxArrayOptions);
145 WX_DEFINE_OBJARRAY(wxArrayParams);
146
147 // the parser internal state
148 struct wxCmdLineParserData
149 {
150 // options
151 wxString m_switchChars; // characters which may start an option
152 bool m_enableLongOptions; // TRUE if long options are enabled
153 wxString m_logo; // some extra text to show in Usage()
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();
163 void SetArguments(int argc, char **argv);
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
178 wxCmdLineParserData::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
188 void wxCmdLineParserData::SetArguments(int argc, char **argv)
189 {
190 m_arguments.Empty();
191
192 for ( int n = 0; n < argc; n++ )
193 {
194 m_arguments.Add(argv[n]);
195 }
196 }
197
198 void wxCmdLineParserData::SetArguments(const wxString& cmdLine)
199 {
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 ++;
213
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 }
242 }
243
244 int wxCmdLineParserData::FindOption(const wxString& name)
245 {
246 if ( !name.empty() )
247 {
248 size_t count = m_options.GetCount();
249 for ( size_t n = 0; n < count; n++ )
250 {
251 if ( m_options[n].shortName == name )
252 {
253 // found
254 return n;
255 }
256 }
257 }
258
259 return wxNOT_FOUND;
260 }
261
262 int 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
281 void wxCmdLineParser::Init()
282 {
283 m_data = new wxCmdLineParserData;
284 }
285
286 void wxCmdLineParser::SetCmdLine(int argc, char **argv)
287 {
288 m_data->SetArguments(argc, argv);
289 }
290
291 void wxCmdLineParser::SetCmdLine(const wxString& cmdline)
292 {
293 m_data->SetArguments(cmdline);
294 }
295
296 wxCmdLineParser::~wxCmdLineParser()
297 {
298 delete m_data;
299 }
300
301 // ----------------------------------------------------------------------------
302 // options
303 // ----------------------------------------------------------------------------
304
305 void wxCmdLineParser::SetSwitchChars(const wxString& switchChars)
306 {
307 m_data->m_switchChars = switchChars;
308 }
309
310 void wxCmdLineParser::EnableLongOptions(bool enable)
311 {
312 m_data->m_enableLongOptions = enable;
313 }
314
315 void wxCmdLineParser::SetLogo(const wxString& logo)
316 {
317 m_data->m_logo = logo;
318 }
319
320 // ----------------------------------------------------------------------------
321 // command line construction
322 // ----------------------------------------------------------------------------
323
324 void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc *desc)
325 {
326 for ( ;; desc++ )
327 {
328 switch ( desc->kind )
329 {
330 case wxCMD_LINE_SWITCH:
331 AddSwitch(desc->shortName, desc->longName, desc->description,
332 desc->flags);
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
354 void 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
369 void 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
385 void 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),
397 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
398
399 if ( !(flags & wxCMD_LINE_PARAM_OPTIONAL) )
400 {
401 wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL),
402 _T("a required parameter can't follow an optional one") );
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
416 bool wxCmdLineParser::Found(const wxString& name) const
417 {
418 int i = m_data->FindOption(name);
419 if ( i == wxNOT_FOUND )
420 i = m_data->FindOptionByLongName(name);
421
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
431 bool wxCmdLineParser::Found(const wxString& name, wxString *value) const
432 {
433 int i = m_data->FindOption(name);
434 if ( i == wxNOT_FOUND )
435 i = m_data->FindOptionByLongName(name);
436
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
450 bool wxCmdLineParser::Found(const wxString& name, long *value) const
451 {
452 int i = m_data->FindOption(name);
453 if ( i == wxNOT_FOUND )
454 i = m_data->FindOptionByLongName(name);
455
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
469 bool wxCmdLineParser::Found(const wxString& name, wxDateTime *value) const
470 {
471 int i = m_data->FindOption(name);
472 if ( i == wxNOT_FOUND )
473 i = m_data->FindOptionByLongName(name);
474
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
488 size_t wxCmdLineParser::GetParamCount() const
489 {
490 return m_data->m_parameters.GetCount();
491 }
492
493 wxString wxCmdLineParser::GetParam(size_t n) const
494 {
495 return m_data->m_parameters[n];
496 }
497
498 // Resets switches and options
499 void wxCmdLineParser::Reset()
500 {
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 }
506 }
507
508
509 // ----------------------------------------------------------------------------
510 // the real work is done here
511 // ----------------------------------------------------------------------------
512
513 int 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
524 Reset();
525
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;
559 while ( wxIsalnum(*p) || (*p == _T('_')) || (*p == _T('-')) )
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;
577 while ( wxIsalnum(*p) || (*p == _T('_')) )
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
603 len++; // compensates extra len-- above
604 if ( (optInd != wxNOT_FOUND) && (len != name.length()) )
605 {
606 // first of all, the option name is only part of this
607 // string
608 name = name.Left(len);
609
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];
619 arg2 += arg.Mid(len + 1); // +1 for leading '-'
620
621 m_data->m_arguments.Insert(arg2, n + 1);
622 count++;
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 {
661 wxLogError(_("Option '%s' requires a value, '=' expected."), name.c_str());
662
663 ok = FALSE;
664 }
665 }
666 else
667 {
668 switch ( *p )
669 {
670 case _T('='):
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:
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 }
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 {
728 wxLogError(_("'%s' is not a correct numeric value for option '%s'."),
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 {
742 wxLogError(_("Option '%s': '%s' cannot be converted to a date."),
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,
775 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
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
852 void wxCmdLineParser::Usage()
853 {
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
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;
868 brief.Printf(_("Usage: %s"), appname.c_str());
869
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
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
886 brief << chSwitch << opt.shortName;
887
888 wxString option;
889 option << _T(" ") << chSwitch << opt.shortName;
890 if ( !!opt.longName )
891 {
892 option << _T(" --") << opt.longName;
893 }
894
895 if ( opt.kind != wxCMD_LINE_SWITCH )
896 {
897 wxString val;
898 val << _T('<') << GetTypeName(opt.type) << _T('>');
899 brief << _T(' ') << val;
900 option << (!opt.longName ? _T(':') : _T('=')) << val;
901 }
902
903 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
904 {
905 brief << _T(']');
906 }
907
908 namesOptions.Add(option);
909 descOptions.Add(opt.description);
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
936 if ( !!m_data->m_logo )
937 {
938 wxLogMessage(m_data->m_logo);
939 }
940
941 wxLogMessage(brief);
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
963 wxLogMessage(detailed);
964 }
965
966 // ----------------------------------------------------------------------------
967 // global functions
968 // ----------------------------------------------------------------------------
969
970 static 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 }
986
987 #endif // wxUSE_CMDLINE_PARSER