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