]> git.saurik.com Git - wxWidgets.git/blob - src/common/cmdline.cpp
Some wxUniv compile fixes
[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 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
84 void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const
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
103 void SetHasValue(bool hasValue = TRUE) { m_hasVal = hasValue; }
104 bool HasValue() const { return m_hasVal; }
105
106 public:
107 wxCmdLineEntryType kind;
108 wxString shortName, longName, description;
109 wxCmdLineParamType type;
110 int flags;
111
112 private:
113 bool m_hasVal;
114
115 long m_longVal;
116 wxString m_strVal;
117 wxDateTime m_dateVal;
118 };
119
120 struct 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
136 WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions);
137 WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams);
138
139 #include "wx/arrimpl.cpp"
140
141 WX_DEFINE_OBJARRAY(wxArrayOptions);
142 WX_DEFINE_OBJARRAY(wxArrayParams);
143
144 // the parser internal state
145 struct wxCmdLineParserData
146 {
147 // options
148 wxString m_switchChars; // characters which may start an option
149 bool m_enableLongOptions; // TRUE if long options are enabled
150 wxString m_logo; // some extra text to show in Usage()
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
175 wxCmdLineParserData::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
185 void 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
195 void wxCmdLineParserData::SetArguments(const wxString& cmdLine)
196 {
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 ++;
210
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 }
239 }
240
241 int 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
256 int 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
275 void wxCmdLineParser::Init()
276 {
277 m_data = new wxCmdLineParserData;
278 }
279
280 void wxCmdLineParser::SetCmdLine(int argc, char **argv)
281 {
282 m_data->SetArguments(argc, argv);
283 }
284
285 void wxCmdLineParser::SetCmdLine(const wxString& cmdline)
286 {
287 m_data->SetArguments(cmdline);
288 }
289
290 wxCmdLineParser::~wxCmdLineParser()
291 {
292 delete m_data;
293 }
294
295 // ----------------------------------------------------------------------------
296 // options
297 // ----------------------------------------------------------------------------
298
299 void wxCmdLineParser::SetSwitchChars(const wxString& switchChars)
300 {
301 m_data->m_switchChars = switchChars;
302 }
303
304 void wxCmdLineParser::EnableLongOptions(bool enable)
305 {
306 m_data->m_enableLongOptions = enable;
307 }
308
309 void wxCmdLineParser::SetLogo(const wxString& logo)
310 {
311 m_data->m_logo = logo;
312 }
313
314 // ----------------------------------------------------------------------------
315 // command line construction
316 // ----------------------------------------------------------------------------
317
318 void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc *desc)
319 {
320 for ( ;; desc++ )
321 {
322 switch ( desc->kind )
323 {
324 case wxCMD_LINE_SWITCH:
325 AddSwitch(desc->shortName, desc->longName, desc->description,
326 desc->flags);
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
348 void 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
363 void 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
379 void 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),
391 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
392
393 if ( !(flags & wxCMD_LINE_PARAM_OPTIONAL) )
394 {
395 wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL),
396 _T("a required parameter can't follow an optional one") );
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
410 bool 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
422 bool 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
438 bool 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
454 bool 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
470 size_t wxCmdLineParser::GetParamCount() const
471 {
472 return m_data->m_parameters.GetCount();
473 }
474
475 wxString wxCmdLineParser::GetParam(size_t n) const
476 {
477 return m_data->m_parameters[n];
478 }
479
480 // Resets switches and options
481 void wxCmdLineParser::Reset()
482 {
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 }
488 }
489
490
491 // ----------------------------------------------------------------------------
492 // the real work is done here
493 // ----------------------------------------------------------------------------
494
495 int 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
506 Reset();
507
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;
541 while ( wxIsalnum(*p) || (*p == _T('_')) || (*p == _T('-')) )
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;
559 while ( wxIsalnum(*p) || (*p == _T('_')) )
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
585 len++; // compensates extra len-- above
586 if ( (optInd != wxNOT_FOUND) && (len != name.length()) )
587 {
588 // first of all, the option name is only part of this
589 // string
590 name = name.Left(len);
591
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];
601 arg2 += arg.Mid(len + 1); // +1 for leading '-'
602
603 m_data->m_arguments.Insert(arg2, n + 1);
604 count++;
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 {
643 wxLogError(_("Option '%s' requires a value, '=' expected."), name.c_str());
644
645 ok = FALSE;
646 }
647 }
648 else
649 {
650 switch ( *p )
651 {
652 case _T('='):
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:
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 }
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 {
710 wxLogError(_("'%s' is not a correct numeric value for option '%s'."),
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 {
724 wxLogError(_("Option '%s': '%s' cannot be converted to a date."),
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,
757 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
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
834 void wxCmdLineParser::Usage()
835 {
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
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;
850 brief.Printf(_("Usage: %s"), appname.c_str());
851
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
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
868 brief << chSwitch << opt.shortName;
869
870 wxString option;
871 option << _T(" ") << chSwitch << opt.shortName;
872 if ( !!opt.longName )
873 {
874 option << _T(" --") << opt.longName;
875 }
876
877 if ( opt.kind != wxCMD_LINE_SWITCH )
878 {
879 wxString val;
880 val << _T('<') << GetTypeName(opt.type) << _T('>');
881 brief << _T(' ') << val;
882 option << (!opt.longName ? _T(':') : _T('=')) << val;
883 }
884
885 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
886 {
887 brief << _T(']');
888 }
889
890 namesOptions.Add(option);
891 descOptions.Add(opt.description);
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
918 if ( !!m_data->m_logo )
919 {
920 wxLogMessage(m_data->m_logo);
921 }
922
923 wxLogMessage(brief);
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
945 wxLogMessage(detailed);
946 }
947
948 // ----------------------------------------------------------------------------
949 // global functions
950 // ----------------------------------------------------------------------------
951
952 static 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 }
968
969 #endif // wxUSE_CMDLINE_PARSER