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