]> git.saurik.com Git - wxWidgets.git/blob - src/common/cmdline.cpp
Hopefully fixed library names generated by wx-config for OS/2's PM port.
[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 licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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 #include "wx/msgout.h"
48
49 // ----------------------------------------------------------------------------
50 // private functions
51 // ----------------------------------------------------------------------------
52
53 static wxString GetTypeName(wxCmdLineParamType type);
54
55 static wxString GetOptionName(const wxChar *p, const wxChar *allowedChars);
56
57 static wxString GetShortOptionName(const wxChar *p);
58
59 static wxString GetLongOptionName(const wxChar *p);
60
61 // ----------------------------------------------------------------------------
62 // private structs
63 // ----------------------------------------------------------------------------
64
65 // an internal representation of an option
66 struct wxCmdLineOption
67 {
68 wxCmdLineOption(wxCmdLineEntryType k,
69 const wxString& shrt,
70 const wxString& lng,
71 const wxString& desc,
72 wxCmdLineParamType typ,
73 int fl)
74 {
75 wxASSERT_MSG( !shrt.empty() || !lng.empty(),
76 _T("option should have at least one name") );
77
78 wxASSERT_MSG
79 (
80 GetShortOptionName(shrt).Len() == shrt.Len(),
81 wxT("Short option contains invalid characters")
82 );
83
84 wxASSERT_MSG
85 (
86 GetLongOptionName(lng).Len() == lng.Len(),
87 wxT("Long option contains invalid characters")
88 );
89
90
91 kind = k;
92
93 shortName = shrt;
94 longName = lng;
95 description = desc;
96
97 type = typ;
98 flags = fl;
99
100 m_hasVal = false;
101 }
102
103 // can't use union easily here, so just store all possible data fields, we
104 // don't waste much (might still use union later if the number of supported
105 // types increases, so always use the accessor functions and don't access
106 // the fields directly!)
107
108 void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const
109 {
110 wxASSERT_MSG( type == typ, _T("type mismatch in wxCmdLineOption") );
111 }
112
113 long GetLongVal() const
114 { Check(wxCMD_LINE_VAL_NUMBER); return m_longVal; }
115 const wxString& GetStrVal() const
116 { Check(wxCMD_LINE_VAL_STRING); return m_strVal; }
117 #if wxUSE_DATETIME
118 const wxDateTime& GetDateVal() const
119 { Check(wxCMD_LINE_VAL_DATE); return m_dateVal; }
120 #endif // wxUSE_DATETIME
121
122 void SetLongVal(long val)
123 { Check(wxCMD_LINE_VAL_NUMBER); m_longVal = val; m_hasVal = true; }
124 void SetStrVal(const wxString& val)
125 { Check(wxCMD_LINE_VAL_STRING); m_strVal = val; m_hasVal = true; }
126 #if wxUSE_DATETIME
127 void SetDateVal(const wxDateTime val)
128 { Check(wxCMD_LINE_VAL_DATE); m_dateVal = val; m_hasVal = true; }
129 #endif // wxUSE_DATETIME
130
131 void SetHasValue(bool hasValue = true) { m_hasVal = hasValue; }
132 bool HasValue() const { return m_hasVal; }
133
134 public:
135 wxCmdLineEntryType kind;
136 wxString shortName,
137 longName,
138 description;
139 wxCmdLineParamType type;
140 int flags;
141
142 private:
143 bool m_hasVal;
144
145 long m_longVal;
146 wxString m_strVal;
147 #if wxUSE_DATETIME
148 wxDateTime m_dateVal;
149 #endif // wxUSE_DATETIME
150 };
151
152 struct wxCmdLineParam
153 {
154 wxCmdLineParam(const wxString& desc,
155 wxCmdLineParamType typ,
156 int fl)
157 : description(desc)
158 {
159 type = typ;
160 flags = fl;
161 }
162
163 wxString description;
164 wxCmdLineParamType type;
165 int flags;
166 };
167
168 WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions);
169 WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams);
170
171 #include "wx/arrimpl.cpp"
172
173 WX_DEFINE_OBJARRAY(wxArrayOptions);
174 WX_DEFINE_OBJARRAY(wxArrayParams);
175
176 // the parser internal state
177 struct wxCmdLineParserData
178 {
179 // options
180 wxString m_switchChars; // characters which may start an option
181 bool m_enableLongOptions; // true if long options are enabled
182 wxString m_logo; // some extra text to show in Usage()
183
184 // cmd line data
185 wxArrayString m_arguments; // == argv, argc == m_arguments.GetCount()
186 wxArrayOptions m_options; // all possible options and switchrs
187 wxArrayParams m_paramDesc; // description of all possible params
188 wxArrayString m_parameters; // all params found
189
190 // methods
191 wxCmdLineParserData();
192 void SetArguments(int argc, char **argv);
193 #if wxUSE_UNICODE
194 void SetArguments(int argc, wxChar **argv);
195 #endif // wxUSE_UNICODE
196 void SetArguments(const wxString& cmdline);
197
198 int FindOption(const wxString& name);
199 int FindOptionByLongName(const wxString& name);
200 };
201
202 // ============================================================================
203 // implementation
204 // ============================================================================
205
206 // ----------------------------------------------------------------------------
207 // wxCmdLineParserData
208 // ----------------------------------------------------------------------------
209
210 wxCmdLineParserData::wxCmdLineParserData()
211 {
212 m_enableLongOptions = true;
213 #ifdef __UNIX_LIKE__
214 m_switchChars = _T("-");
215 #else // !Unix
216 m_switchChars = _T("/-");
217 #endif
218 }
219
220 void wxCmdLineParserData::SetArguments(int argc, char **argv)
221 {
222 m_arguments.clear();
223
224 for ( int n = 0; n < argc; n++ )
225 {
226 m_arguments.push_back(wxString::FromAscii(argv[n]));
227 }
228 }
229
230 #if wxUSE_UNICODE
231
232 void wxCmdLineParserData::SetArguments(int argc, wxChar **argv)
233 {
234 m_arguments.clear();
235
236 for ( int n = 0; n < argc; n++ )
237 {
238 m_arguments.push_back(argv[n]);
239 }
240 }
241
242 #endif // wxUSE_UNICODE
243
244 void wxCmdLineParserData::SetArguments(const wxString& cmdLine)
245 {
246 m_arguments.clear();
247
248 m_arguments.push_back(wxTheApp->GetAppName());
249
250 wxArrayString args = wxCmdLineParser::ConvertStringToArgs(cmdLine);
251
252 WX_APPEND_ARRAY(m_arguments, args);
253 }
254
255 int wxCmdLineParserData::FindOption(const wxString& name)
256 {
257 if ( !name.empty() )
258 {
259 size_t count = m_options.GetCount();
260 for ( size_t n = 0; n < count; n++ )
261 {
262 if ( m_options[n].shortName == name )
263 {
264 // found
265 return n;
266 }
267 }
268 }
269
270 return wxNOT_FOUND;
271 }
272
273 int wxCmdLineParserData::FindOptionByLongName(const wxString& name)
274 {
275 size_t count = m_options.GetCount();
276 for ( size_t n = 0; n < count; n++ )
277 {
278 if ( m_options[n].longName == name )
279 {
280 // found
281 return n;
282 }
283 }
284
285 return wxNOT_FOUND;
286 }
287
288 // ----------------------------------------------------------------------------
289 // construction and destruction
290 // ----------------------------------------------------------------------------
291
292 void wxCmdLineParser::Init()
293 {
294 m_data = new wxCmdLineParserData;
295 }
296
297 void wxCmdLineParser::SetCmdLine(int argc, char **argv)
298 {
299 m_data->SetArguments(argc, argv);
300 }
301
302 #if wxUSE_UNICODE
303
304 void wxCmdLineParser::SetCmdLine(int argc, wxChar **argv)
305 {
306 m_data->SetArguments(argc, argv);
307 }
308
309 #endif // wxUSE_UNICODE
310
311 void wxCmdLineParser::SetCmdLine(const wxString& cmdline)
312 {
313 m_data->SetArguments(cmdline);
314 }
315
316 wxCmdLineParser::~wxCmdLineParser()
317 {
318 delete m_data;
319 }
320
321 // ----------------------------------------------------------------------------
322 // options
323 // ----------------------------------------------------------------------------
324
325 void wxCmdLineParser::SetSwitchChars(const wxString& switchChars)
326 {
327 m_data->m_switchChars = switchChars;
328 }
329
330 void wxCmdLineParser::EnableLongOptions(bool enable)
331 {
332 m_data->m_enableLongOptions = enable;
333 }
334
335 bool wxCmdLineParser::AreLongOptionsEnabled()
336 {
337 return m_data->m_enableLongOptions;
338 }
339
340 void wxCmdLineParser::SetLogo(const wxString& logo)
341 {
342 m_data->m_logo = logo;
343 }
344
345 // ----------------------------------------------------------------------------
346 // command line construction
347 // ----------------------------------------------------------------------------
348
349 void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc *desc)
350 {
351 for ( ;; desc++ )
352 {
353 switch ( desc->kind )
354 {
355 case wxCMD_LINE_SWITCH:
356 AddSwitch(desc->shortName, desc->longName, desc->description,
357 desc->flags);
358 break;
359
360 case wxCMD_LINE_OPTION:
361 AddOption(desc->shortName, desc->longName, desc->description,
362 desc->type, desc->flags);
363 break;
364
365 case wxCMD_LINE_PARAM:
366 AddParam(desc->description, desc->type, desc->flags);
367 break;
368
369 default:
370 wxFAIL_MSG( _T("unknown command line entry type") );
371 // still fall through
372
373 case wxCMD_LINE_NONE:
374 return;
375 }
376 }
377 }
378
379 void wxCmdLineParser::AddSwitch(const wxString& shortName,
380 const wxString& longName,
381 const wxString& desc,
382 int flags)
383 {
384 wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND,
385 _T("duplicate switch") );
386
387 wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_SWITCH,
388 shortName, longName, desc,
389 wxCMD_LINE_VAL_NONE, flags);
390
391 m_data->m_options.Add(option);
392 }
393
394 void wxCmdLineParser::AddOption(const wxString& shortName,
395 const wxString& longName,
396 const wxString& desc,
397 wxCmdLineParamType type,
398 int flags)
399 {
400 wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND,
401 _T("duplicate option") );
402
403 wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_OPTION,
404 shortName, longName, desc,
405 type, flags);
406
407 m_data->m_options.Add(option);
408 }
409
410 void wxCmdLineParser::AddParam(const wxString& desc,
411 wxCmdLineParamType type,
412 int flags)
413 {
414 // do some consistency checks: a required parameter can't follow an
415 // optional one and nothing should follow a parameter with MULTIPLE flag
416 #ifdef __WXDEBUG__
417 if ( !m_data->m_paramDesc.IsEmpty() )
418 {
419 wxCmdLineParam& param = m_data->m_paramDesc.Last();
420
421 wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE),
422 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") );
423
424 if ( !(flags & wxCMD_LINE_PARAM_OPTIONAL) )
425 {
426 wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL),
427 _T("a required parameter can't follow an optional one") );
428 }
429 }
430 #endif // Debug
431
432 wxCmdLineParam *param = new wxCmdLineParam(desc, type, flags);
433
434 m_data->m_paramDesc.Add(param);
435 }
436
437 // ----------------------------------------------------------------------------
438 // access to parse command line
439 // ----------------------------------------------------------------------------
440
441 bool wxCmdLineParser::Found(const wxString& name) const
442 {
443 int i = m_data->FindOption(name);
444 if ( i == wxNOT_FOUND )
445 i = m_data->FindOptionByLongName(name);
446
447 wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown switch") );
448
449 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
450 if ( !opt.HasValue() )
451 return false;
452
453 return true;
454 }
455
456 bool wxCmdLineParser::Found(const wxString& name, wxString *value) const
457 {
458 int i = m_data->FindOption(name);
459 if ( i == wxNOT_FOUND )
460 i = m_data->FindOptionByLongName(name);
461
462 wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") );
463
464 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
465 if ( !opt.HasValue() )
466 return false;
467
468 wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") );
469
470 *value = opt.GetStrVal();
471
472 return true;
473 }
474
475 bool wxCmdLineParser::Found(const wxString& name, long *value) const
476 {
477 int i = m_data->FindOption(name);
478 if ( i == wxNOT_FOUND )
479 i = m_data->FindOptionByLongName(name);
480
481 wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") );
482
483 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
484 if ( !opt.HasValue() )
485 return false;
486
487 wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") );
488
489 *value = opt.GetLongVal();
490
491 return true;
492 }
493
494 #if wxUSE_DATETIME
495 bool wxCmdLineParser::Found(const wxString& name, wxDateTime *value) const
496 {
497 int i = m_data->FindOption(name);
498 if ( i == wxNOT_FOUND )
499 i = m_data->FindOptionByLongName(name);
500
501 wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") );
502
503 wxCmdLineOption& opt = m_data->m_options[(size_t)i];
504 if ( !opt.HasValue() )
505 return false;
506
507 wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") );
508
509 *value = opt.GetDateVal();
510
511 return true;
512 }
513 #endif // wxUSE_DATETIME
514
515 size_t wxCmdLineParser::GetParamCount() const
516 {
517 return m_data->m_parameters.size();
518 }
519
520 wxString wxCmdLineParser::GetParam(size_t n) const
521 {
522 wxCHECK_MSG( n < GetParamCount(), wxEmptyString, _T("invalid param index") );
523
524 return m_data->m_parameters[n];
525 }
526
527 // Resets switches and options
528 void wxCmdLineParser::Reset()
529 {
530 for ( size_t i = 0; i < m_data->m_options.Count(); i++ )
531 {
532 wxCmdLineOption& opt = m_data->m_options[i];
533 opt.SetHasValue(false);
534 }
535 }
536
537
538 // ----------------------------------------------------------------------------
539 // the real work is done here
540 // ----------------------------------------------------------------------------
541
542 int wxCmdLineParser::Parse(bool showUsage)
543 {
544 bool maybeOption = true; // can the following arg be an option?
545 bool ok = true; // true until an error is detected
546 bool helpRequested = false; // true if "-h" was given
547 bool hadRepeatableParam = false; // true if found param with MULTIPLE flag
548
549 size_t currentParam = 0; // the index in m_paramDesc
550
551 size_t countParam = m_data->m_paramDesc.GetCount();
552 wxString errorMsg;
553
554 Reset();
555
556 // parse everything
557 wxString arg;
558 size_t count = m_data->m_arguments.size();
559 for ( size_t n = 1; ok && (n < count); n++ ) // 0 is program name
560 {
561 arg = m_data->m_arguments[n];
562
563 // special case: "--" should be discarded and all following arguments
564 // should be considered as parameters, even if they start with '-' and
565 // not like options (this is POSIX-like)
566 if ( arg == _T("--") )
567 {
568 maybeOption = false;
569
570 continue;
571 }
572
573 // empty argument or just '-' is not an option but a parameter
574 if ( maybeOption && arg.length() > 1 &&
575 wxStrchr(m_data->m_switchChars, arg[0u]) )
576 {
577 bool isLong;
578 wxString name;
579 int optInd = wxNOT_FOUND; // init to suppress warnings
580
581 // an option or a switch: find whether it's a long or a short one
582 if ( arg[0u] == _T('-') && arg[1u] == _T('-') )
583 {
584 // a long one
585 isLong = true;
586
587 // Skip leading "--"
588 const wxChar *p = arg.c_str() + 2;
589
590 bool longOptionsEnabled = AreLongOptionsEnabled();
591
592 name = GetLongOptionName(p);
593
594 if (longOptionsEnabled)
595 {
596 optInd = m_data->FindOptionByLongName(name);
597 if ( optInd == wxNOT_FOUND )
598 {
599 errorMsg << wxString::Format(_("Unknown long option '%s'"), name.c_str()) << wxT("\n");
600 }
601 }
602 else
603 {
604 optInd = wxNOT_FOUND; // Sanity check
605
606 // Print the argument including leading "--"
607 name.Prepend( wxT("--") );
608 errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) << wxT("\n");
609 }
610
611 }
612 else
613 {
614 isLong = false;
615
616 // a short one: as they can be cumulated, we try to find the
617 // longest substring which is a valid option
618 const wxChar *p = arg.c_str() + 1;
619
620 name = GetShortOptionName(p);
621
622 size_t len = name.length();
623 do
624 {
625 if ( len == 0 )
626 {
627 // we couldn't find a valid option name in the
628 // beginning of this string
629 errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) << wxT("\n");
630
631 break;
632 }
633 else
634 {
635 optInd = m_data->FindOption(name.Left(len));
636
637 // will try with one character less the next time
638 len--;
639 }
640 }
641 while ( optInd == wxNOT_FOUND );
642
643 len++; // compensates extra len-- above
644 if ( (optInd != wxNOT_FOUND) && (len != name.length()) )
645 {
646 // first of all, the option name is only part of this
647 // string
648 name = name.Left(len);
649
650 // our option is only part of this argument, there is
651 // something else in it - it is either the value of this
652 // option or other switches if it is a switch
653 if ( m_data->m_options[(size_t)optInd].kind
654 == wxCMD_LINE_SWITCH )
655 {
656 // pretend that all the rest of the argument is the
657 // next argument, in fact
658 wxString arg2 = arg[0u];
659 arg2 += arg.Mid(len + 1); // +1 for leading '-'
660
661 m_data->m_arguments.insert
662 (m_data->m_arguments.begin() + n + 1, arg2);
663 count++;
664 }
665 //else: it's our value, we'll deal with it below
666 }
667 }
668
669 if ( optInd == wxNOT_FOUND )
670 {
671 ok = false;
672
673 continue; // will break, in fact
674 }
675
676 wxCmdLineOption& opt = m_data->m_options[(size_t)optInd];
677 if ( opt.kind == wxCMD_LINE_SWITCH )
678 {
679 // nothing more to do
680 opt.SetHasValue();
681
682 if ( opt.flags & wxCMD_LINE_OPTION_HELP )
683 {
684 helpRequested = true;
685
686 // it's not an error, but we still stop here
687 ok = false;
688 }
689 }
690 else
691 {
692 // get the value
693
694 // +1 for leading '-'
695 const wxChar *p = arg.c_str() + 1 + name.length();
696 if ( isLong )
697 {
698 p++; // for another leading '-'
699
700 if ( *p++ != _T('=') )
701 {
702 errorMsg << wxString::Format(_("Option '%s' requires a value, '=' expected."), name.c_str()) << wxT("\n");
703
704 ok = false;
705 }
706 }
707 else
708 {
709 switch ( *p )
710 {
711 case _T('='):
712 case _T(':'):
713 // the value follows
714 p++;
715 break;
716
717 case 0:
718 // the value is in the next argument
719 if ( ++n == count )
720 {
721 // ... but there is none
722 errorMsg << wxString::Format(_("Option '%s' requires a value."),
723 name.c_str()) << wxT("\n");
724
725 ok = false;
726 }
727 else
728 {
729 // ... take it from there
730 p = m_data->m_arguments[n].c_str();
731 }
732 break;
733
734 default:
735 // the value is right here: this may be legal or
736 // not depending on the option style
737 if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR )
738 {
739 errorMsg << wxString::Format(_("Separator expected after the option '%s'."),
740 name.c_str()) << wxT("\n");
741
742 ok = false;
743 }
744 }
745 }
746
747 if ( ok )
748 {
749 wxString value = p;
750 switch ( opt.type )
751 {
752 default:
753 wxFAIL_MSG( _T("unknown option type") );
754 // still fall through
755
756 case wxCMD_LINE_VAL_STRING:
757 opt.SetStrVal(value);
758 break;
759
760 case wxCMD_LINE_VAL_NUMBER:
761 {
762 long val;
763 if ( value.ToLong(&val) )
764 {
765 opt.SetLongVal(val);
766 }
767 else
768 {
769 errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."),
770 value.c_str(), name.c_str()) << wxT("\n");
771
772 ok = false;
773 }
774 }
775 break;
776
777 #if wxUSE_DATETIME
778 case wxCMD_LINE_VAL_DATE:
779 {
780 wxDateTime dt;
781 const wxChar *res = dt.ParseDate(value);
782 if ( !res || *res )
783 {
784 errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."),
785 name.c_str(), value.c_str()) << wxT("\n");
786
787 ok = false;
788 }
789 else
790 {
791 opt.SetDateVal(dt);
792 }
793 }
794 break;
795 #endif // wxUSE_DATETIME
796 }
797 }
798 }
799 }
800 else
801 {
802 // a parameter
803 if ( currentParam < countParam )
804 {
805 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
806
807 // TODO check the param type
808
809 m_data->m_parameters.push_back(arg);
810
811 if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) )
812 {
813 currentParam++;
814 }
815 else
816 {
817 wxASSERT_MSG( currentParam == countParam - 1,
818 _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") );
819
820 // remember that we did have this last repeatable parameter
821 hadRepeatableParam = true;
822 }
823 }
824 else
825 {
826 errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str()) << wxT("\n");
827
828 ok = false;
829 }
830 }
831 }
832
833 // verify that all mandatory options were given
834 if ( ok )
835 {
836 size_t countOpt = m_data->m_options.GetCount();
837 for ( size_t n = 0; ok && (n < countOpt); n++ )
838 {
839 wxCmdLineOption& opt = m_data->m_options[n];
840 if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() )
841 {
842 wxString optName;
843 if ( !opt.longName )
844 {
845 optName = opt.shortName;
846 }
847 else
848 {
849 if ( AreLongOptionsEnabled() )
850 {
851 optName.Printf( _("%s (or %s)"),
852 opt.shortName.c_str(),
853 opt.longName.c_str() );
854 }
855 else
856 {
857 optName.Printf( wxT("%s"),
858 opt.shortName.c_str() );
859 }
860 }
861
862 errorMsg << wxString::Format(_("The value for the option '%s' must be specified."),
863 optName.c_str()) << wxT("\n");
864
865 ok = false;
866 }
867 }
868
869 for ( ; ok && (currentParam < countParam); currentParam++ )
870 {
871 wxCmdLineParam& param = m_data->m_paramDesc[currentParam];
872 if ( (currentParam == countParam - 1) &&
873 (param.flags & wxCMD_LINE_PARAM_MULTIPLE) &&
874 hadRepeatableParam )
875 {
876 // special case: currentParam wasn't incremented, but we did
877 // have it, so don't give error
878 continue;
879 }
880
881 if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) )
882 {
883 errorMsg << wxString::Format(_("The required parameter '%s' was not specified."),
884 param.description.c_str()) << wxT("\n");
885
886 ok = false;
887 }
888 }
889 }
890
891 // if there was an error during parsing the command line, show this error
892 // and also the usage message if it had been requested
893 if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
894 {
895 wxMessageOutput* msgOut = wxMessageOutput::Get();
896 if ( msgOut )
897 {
898 wxString usage;
899 if ( showUsage )
900 usage = GetUsageString();
901
902 msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() );
903 }
904 else
905 {
906 wxFAIL_MSG( _T("no wxMessageOutput object?") );
907 }
908 }
909
910 return ok ? 0 : helpRequested ? -1 : 1;
911 }
912
913 // ----------------------------------------------------------------------------
914 // give the usage message
915 // ----------------------------------------------------------------------------
916
917 void wxCmdLineParser::Usage()
918 {
919 wxMessageOutput* msgOut = wxMessageOutput::Get();
920 if ( msgOut )
921 {
922 msgOut->Printf( wxT("%s"), GetUsageString().c_str() );
923 }
924 else
925 {
926 wxFAIL_MSG( _T("no wxMessageOutput object?") );
927 }
928 }
929
930 wxString wxCmdLineParser::GetUsageString()
931 {
932 wxString appname = wxTheApp->GetAppName();
933 if ( !appname )
934 {
935 wxCHECK_MSG( m_data->m_arguments.size() != 0, wxEmptyString,
936 _T("no program name") );
937
938 appname = wxFileNameFromPath(m_data->m_arguments[0]);
939 wxStripExtension(appname);
940 }
941
942 // we construct the brief cmd line desc on the fly, but not the detailed
943 // help message below because we want to align the options descriptions
944 // and for this we must first know the longest one of them
945 wxString usage;
946 wxArrayString namesOptions, descOptions;
947
948 if ( !m_data->m_logo.empty() )
949 {
950 usage << m_data->m_logo << _T('\n');
951 }
952
953 usage << wxString::Format(_("Usage: %s"), appname.c_str());
954
955 // the switch char is usually '-' but this can be changed with
956 // SetSwitchChars() and then the first one of possible chars is used
957 wxChar chSwitch = !m_data->m_switchChars ? _T('-')
958 : m_data->m_switchChars[0u];
959
960 bool areLongOptionsEnabled = AreLongOptionsEnabled();
961 size_t n, count = m_data->m_options.GetCount();
962 for ( n = 0; n < count; n++ )
963 {
964 wxCmdLineOption& opt = m_data->m_options[n];
965
966 usage << _T(' ');
967 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
968 {
969 usage << _T('[');
970 }
971
972 if ( !opt.shortName.empty() )
973 {
974 usage << chSwitch << opt.shortName;
975 }
976 else if ( areLongOptionsEnabled && !opt.longName.empty() )
977 {
978 usage << _T("--") << opt.longName;
979 }
980 else
981 {
982 if (!opt.longName.empty())
983 {
984 wxFAIL_MSG( wxT("option with only a long name while long ")
985 wxT("options are disabled") );
986 }
987 else
988 {
989 wxFAIL_MSG( _T("option without neither short nor long name") );
990 }
991 }
992
993 wxString option;
994
995 if ( !opt.shortName.empty() )
996 {
997 option << _T(" ") << chSwitch << opt.shortName;
998 }
999
1000 if ( areLongOptionsEnabled && !opt.longName.empty() )
1001 {
1002 option << (option.empty() ? _T(" ") : _T(", "))
1003 << _T("--") << opt.longName;
1004 }
1005
1006 if ( opt.kind != wxCMD_LINE_SWITCH )
1007 {
1008 wxString val;
1009 val << _T('<') << GetTypeName(opt.type) << _T('>');
1010 usage << _T(' ') << val;
1011 option << (!opt.longName ? _T(':') : _T('=')) << val;
1012 }
1013
1014 if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) )
1015 {
1016 usage << _T(']');
1017 }
1018
1019 namesOptions.push_back(option);
1020 descOptions.push_back(opt.description);
1021 }
1022
1023 count = m_data->m_paramDesc.GetCount();
1024 for ( n = 0; n < count; n++ )
1025 {
1026 wxCmdLineParam& param = m_data->m_paramDesc[n];
1027
1028 usage << _T(' ');
1029 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1030 {
1031 usage << _T('[');
1032 }
1033
1034 usage << param.description;
1035
1036 if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE )
1037 {
1038 usage << _T("...");
1039 }
1040
1041 if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL )
1042 {
1043 usage << _T(']');
1044 }
1045 }
1046
1047 usage << _T('\n');
1048
1049 // now construct the detailed help message
1050 size_t len, lenMax = 0;
1051 count = namesOptions.size();
1052 for ( n = 0; n < count; n++ )
1053 {
1054 len = namesOptions[n].length();
1055 if ( len > lenMax )
1056 lenMax = len;
1057 }
1058
1059 for ( n = 0; n < count; n++ )
1060 {
1061 len = namesOptions[n].length();
1062 usage << namesOptions[n]
1063 << wxString(_T(' '), lenMax - len) << _T('\t')
1064 << descOptions[n]
1065 << _T('\n');
1066 }
1067
1068 return usage;
1069 }
1070
1071 // ----------------------------------------------------------------------------
1072 // private functions
1073 // ----------------------------------------------------------------------------
1074
1075 static wxString GetTypeName(wxCmdLineParamType type)
1076 {
1077 wxString s;
1078 switch ( type )
1079 {
1080 default:
1081 wxFAIL_MSG( _T("unknown option type") );
1082 // still fall through
1083
1084 case wxCMD_LINE_VAL_STRING:
1085 s = _("str");
1086 break;
1087
1088 case wxCMD_LINE_VAL_NUMBER:
1089 s = _("num");
1090 break;
1091
1092 case wxCMD_LINE_VAL_DATE:
1093 s = _("date");
1094 break;
1095 }
1096
1097 return s;
1098 }
1099
1100 /*
1101 Returns a string which is equal to the string pointed to by p, but up to the
1102 point where p contains an character that's not allowed.
1103 Allowable characters are letters and numbers, and characters pointed to by
1104 the parameter allowedChars.
1105
1106 For example, if p points to "abcde-@-_", and allowedChars is "-_",
1107 this function returns "abcde-".
1108 */
1109 static wxString GetOptionName(const wxChar *p,
1110 const wxChar *allowedChars)
1111 {
1112 wxString argName;
1113
1114 while ( *p && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) )
1115 {
1116 argName += *p++;
1117 }
1118
1119 return argName;
1120 }
1121
1122 // Besides alphanumeric characters, short and long options can
1123 // have other characters.
1124
1125 // A short option additionally can have these
1126 #define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?")
1127
1128 // A long option can have the same characters as a short option and a '-'.
1129 #define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \
1130 wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-")
1131
1132 static wxString GetShortOptionName(const wxChar *p)
1133 {
1134 return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION);
1135 }
1136
1137 static wxString GetLongOptionName(const wxChar *p)
1138 {
1139 return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION);
1140 }
1141
1142 #endif // wxUSE_CMDLINE_PARSER
1143
1144 // ----------------------------------------------------------------------------
1145 // global functions
1146 // ----------------------------------------------------------------------------
1147
1148 /*
1149 This function is mainly used under Windows (as under Unix we always get the
1150 command line arguments as argc/argv anyhow) and so it tries to follow
1151 Windows conventions for the command line handling, not Unix ones. For
1152 instance, backslash is not special except when it precedes double quote when
1153 it does quote it.
1154 */
1155
1156 /* static */
1157 wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxChar *p)
1158 {
1159 wxArrayString args;
1160
1161 wxString arg;
1162 arg.reserve(1024);
1163
1164 bool isInsideQuotes = false;
1165 for ( ;; )
1166 {
1167 // skip white space
1168 while ( *p == _T(' ') || *p == _T('\t') )
1169 p++;
1170
1171 // anything left?
1172 if ( *p == _T('\0') )
1173 break;
1174
1175 // parse this parameter
1176 bool endParam = false;
1177 bool lastBS = false;
1178 for ( arg.clear(); !endParam; p++ )
1179 {
1180 switch ( *p )
1181 {
1182 case _T('"'):
1183 if ( !lastBS )
1184 {
1185 isInsideQuotes = !isInsideQuotes;
1186
1187 // don't put quote in arg
1188 continue;
1189 }
1190 //else: quote has no special meaning but the backslash
1191 // still remains -- makes no sense but this is what
1192 // Windows does
1193 break;
1194
1195 case _T(' '):
1196 case _T('\t'):
1197 // backslash does *not* quote the space, only quotes do
1198 if ( isInsideQuotes )
1199 {
1200 // skip assignment below
1201 break;
1202 }
1203 // fall through
1204
1205 case _T('\0'):
1206 endParam = true;
1207
1208 break;
1209 }
1210
1211 if ( endParam )
1212 {
1213 break;
1214 }
1215
1216 lastBS = *p == _T('\\');
1217
1218 arg += *p;
1219 }
1220
1221 args.push_back(arg);
1222 }
1223
1224 return args;
1225 }
1226