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