home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / cmdline.cpp < prev    next >
C/C++ Source or Header  |  2002-11-04  |  39KB  |  1,235 lines

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