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