ncbiargs.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:61k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbiargs.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:08:48  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.48
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbiargs.cpp,v 1000.1 2004/06/01 19:08:48 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Authors:  Denis Vakatov, Anton Butanayev
  35.  *
  36.  * File Description:
  37.  *   Command-line arguments' processing:
  38.  *      descriptions  -- CArgDescriptions,  CArgDesc
  39.  *      parsed values -- CArgs,             CArgValue
  40.  *      exceptions    -- CArgException, ARG_THROW()
  41.  *      constraints   -- CArgAllow;  CArgAllow_{Strings,Integers,Doubles}
  42.  *
  43.  */
  44. #include <ncbi_pch.hpp>
  45. #include <corelib/ncbiargs.hpp>
  46. #include <corelib/ncbienv.hpp>
  47. #include <algorithm>
  48. BEGIN_NCBI_SCOPE
  49. /////////////////////////////////////////////////////////////////////////////
  50. /////////////////////////////////////////////////////////////////////////////
  51. //  Include the private header
  52. //
  53. #define NCBIARGS__CPP
  54. #include "ncbiargs_p.hpp"
  55. /////////////////////////////////////////////////////////////////////////////
  56. /////////////////////////////////////////////////////////////////////////////
  57. //  Constants
  58. //
  59. static const string s_AutoHelp("h");
  60. static const string s_ExtraName("....");
  61. /////////////////////////////////////////////////////////////////////////////
  62. string s_ArgExptMsg(const string& name, const string& what, const string& attr)
  63. {
  64.     return string("Argument "") + (name.empty() ? s_ExtraName : name) +
  65.         "". " + what + ":  `" + attr + "'";
  66. }
  67. /////////////////////////////////////////////////////////////////////////////
  68. /////////////////////////////////////////////////////////////////////////////
  69. //  CArg_***::   classes representing various types of argument value
  70. //
  71. //    CArgValue
  72. //
  73. //       CArg_NoValue     : CArgValue
  74. //
  75. //       CArg_String      : CArgValue
  76. //          CArg_Integer     : CArg_String
  77. //          CArg_Double      : CArg_String
  78. //          CArg_Boolean     : CArg_String
  79. //          CArg_InputFile   : CArg_String
  80. //          CArg_OutputFile  : CArg_String
  81. //    
  82. ///////////////////////////////////////////////////////
  83. //  CArgValue::
  84. CArgValue::CArgValue(const string& name)
  85.     : m_Name(name)
  86. {
  87.     if ( !CArgDescriptions::VerifyName(m_Name, true) ) {
  88.         NCBI_THROW(CArgException,eInvalidArg,
  89.             "Invalid argument name: " + m_Name);
  90.     }
  91. }
  92. CArgValue::~CArgValue(void)
  93. {
  94.     return;
  95. }
  96. ///////////////////////////////////////////////////////
  97. //  Overload the comparison operator -- to handle "CRef<CArgValue>" elements
  98. //  in "CArgs::m_Args" stored as "set< CRef<CArgValue> >"
  99. //
  100. inline bool operator< (const CRef<CArgValue>& x, const CRef<CArgValue>& y)
  101. {
  102.     return x->GetName() < y->GetName();
  103. }
  104. ///////////////////////////////////////////////////////
  105. //  CArg_NoValue::
  106. inline CArg_NoValue::CArg_NoValue(const string& name)
  107.     : CArgValue(name)
  108. {
  109.     return;
  110. }
  111. bool CArg_NoValue::HasValue(void) const
  112. {
  113.     return false;
  114. }
  115. #define THROW_CArg_NoValue 
  116.     NCBI_THROW(CArgException,eNoValue, s_ArgExptMsg(GetName(), 
  117.         "Optional argument must have a default value", "NULL"));
  118. const string& CArg_NoValue::AsString    (void) const { THROW_CArg_NoValue; }
  119. int           CArg_NoValue::AsInteger   (void) const { THROW_CArg_NoValue; }
  120. double        CArg_NoValue::AsDouble    (void) const { THROW_CArg_NoValue; }
  121. bool          CArg_NoValue::AsBoolean   (void) const { THROW_CArg_NoValue; }
  122. CNcbiIstream& CArg_NoValue::AsInputFile (void) const { THROW_CArg_NoValue; }
  123. CNcbiOstream& CArg_NoValue::AsOutputFile(void) const { THROW_CArg_NoValue; }
  124. void          CArg_NoValue::CloseFile   (void) const { THROW_CArg_NoValue; }
  125. ///////////////////////////////////////////////////////
  126. //  CArg_String::
  127. inline CArg_String::CArg_String(const string& name, const string& value)
  128.     : CArgValue(name),
  129.       m_String(value)
  130. {
  131.     return;
  132. }
  133. bool CArg_String::HasValue(void) const
  134. {
  135.     return true;
  136. }
  137. const string& CArg_String::AsString(void) const
  138. {
  139.     return m_String;
  140. }
  141. int CArg_String::AsInteger(void) const
  142. { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
  143.     "Attempt to cast to a wrong (Integer) type", AsString()));}
  144. double CArg_String::AsDouble(void) const
  145. { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
  146.     "Attempt to cast to a wrong (Double) type", AsString()));}
  147. bool CArg_String::AsBoolean(void) const
  148. { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
  149.     "Attempt to cast to a wrong (Boolean) type", AsString()));}
  150. CNcbiIstream& CArg_String::AsInputFile(void) const
  151. { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
  152.     "Attempt to cast to a wrong (InputFile) type", AsString()));}
  153. CNcbiOstream& CArg_String::AsOutputFile(void) const
  154. { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
  155.     "Attempt to cast to a wrong (OutputFile) type", AsString()));}
  156. void CArg_String::CloseFile(void) const
  157. { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
  158.     "Attempt to close an argument of non-file type", AsString()));}
  159. ///////////////////////////////////////////////////////
  160. //  CArg_Integer::
  161. inline CArg_Integer::CArg_Integer(const string& name, const string& value)
  162.     : CArg_String(name, value)
  163. {
  164.     try {
  165.         m_Integer = NStr::StringToInt(value);
  166.     } catch (CException& e) {
  167.         NCBI_RETHROW(e,CArgException,eConvert, s_ArgExptMsg(GetName(),
  168.             "Argument cannot be converted",value));
  169.     }
  170. }
  171. int CArg_Integer::AsInteger(void) const
  172. {
  173.     return m_Integer;
  174. }
  175. ///////////////////////////////////////////////////////
  176. //  CArg_Double::
  177. inline CArg_Double::CArg_Double(const string& name, const string& value)
  178.     : CArg_String(name, value)
  179. {
  180.     try {
  181.         m_Double = NStr::StringToDouble(value);
  182.     } catch (CException& e) {
  183.         NCBI_RETHROW(e,CArgException,eConvert,
  184.             s_ArgExptMsg(GetName(),"Argument cannot be converted",value));
  185.     }
  186. }
  187. double CArg_Double::AsDouble(void) const
  188. {
  189.     return m_Double;
  190. }
  191. ///////////////////////////////////////////////////////
  192. //  CArg_Boolean::
  193. inline CArg_Boolean::CArg_Boolean(const string& name, bool value)
  194.     : CArg_String(name, NStr::BoolToString(value))
  195. {
  196.     m_Boolean = value;
  197. }
  198. inline CArg_Boolean::CArg_Boolean(const string& name, const string& value)
  199.     : CArg_String(name, value)
  200. {
  201.     try {
  202.         m_Boolean = NStr::StringToBool(value);
  203.     } catch (CException& e) {
  204.         NCBI_RETHROW(e,CArgException,eConvert, s_ArgExptMsg(GetName(),
  205.             "Argument cannot be converted",value));
  206.     }
  207. }
  208. bool CArg_Boolean::AsBoolean(void) const
  209. {
  210.     return m_Boolean;
  211. }
  212. ///////////////////////////////////////////////////////
  213. //  CArg_InputFile::
  214. void CArg_InputFile::x_Open(void) const
  215. {
  216.     if ( m_InputFile )
  217.         return;
  218.     if (AsString() == "-") {
  219.         m_InputFile  = &cin;
  220.         m_DeleteFlag = false;
  221.     } else if ( !AsString().empty() ) {
  222.         m_InputFile  = new CNcbiIfstream(AsString().c_str(),
  223.                                          IOS_BASE::in | m_OpenMode);
  224.         if (!m_InputFile  ||  !*m_InputFile) {
  225.             delete m_InputFile;
  226.             m_InputFile = 0;
  227.         } else {
  228.             m_DeleteFlag = true;
  229.         }
  230.     }
  231.     if ( !m_InputFile ) {
  232.         NCBI_THROW(CArgException,eNoFile, s_ArgExptMsg(GetName(),
  233.             "File is not accessible",AsString()));
  234.     }
  235. }
  236. CArg_InputFile::CArg_InputFile(const string& name, const string& value,
  237.                                IOS_BASE::openmode openmode,
  238.                                bool               delay_open)
  239. : CArg_String(name, value),
  240.   m_OpenMode(openmode),
  241.   m_InputFile(0),
  242.   m_DeleteFlag(true)
  243. {
  244.     if ( !delay_open )
  245.         x_Open();
  246. }
  247. CArg_InputFile::~CArg_InputFile(void)
  248. {
  249.     if (m_InputFile  &&  m_DeleteFlag)
  250.         delete m_InputFile;
  251. }
  252. CNcbiIstream& CArg_InputFile::AsInputFile(void) const
  253. {
  254.     x_Open();
  255.     return *m_InputFile;
  256. }
  257. void CArg_InputFile::CloseFile(void) const
  258. {
  259.     if ( !m_InputFile ) {
  260.         ERR_POST(Warning << s_ArgExptMsg( GetName(),
  261.             "CArg_InputFile::CloseFile: File was not opened", AsString()));
  262. /*
  263.                  CArgException(GetName(),
  264.                                "CArg_InputFile::CloseFile -- file not opened",
  265.                                AsString()).what());
  266. */
  267.         return;
  268.     }
  269.     if ( m_DeleteFlag ) {
  270.         delete m_InputFile;
  271.         m_InputFile = 0;
  272.     }
  273. }
  274. ///////////////////////////////////////////////////////
  275. //  CArg_OutputFile::
  276. void CArg_OutputFile::x_Open(void) const
  277. {
  278.     if ( m_OutputFile )
  279.         return;
  280.     if (AsString() == "-") {
  281.         m_OutputFile = &cout;
  282.         m_DeleteFlag = false;
  283.     } else if ( !AsString().empty() ) {
  284.         m_OutputFile = new CNcbiOfstream(AsString().c_str(),
  285.                                          IOS_BASE::out | m_OpenMode);
  286.         if (!m_OutputFile  ||  !*m_OutputFile) {
  287.             delete m_OutputFile;
  288.             m_OutputFile = 0;
  289.         } else {
  290.             m_DeleteFlag = true;
  291.         }
  292.     }
  293.     if ( !m_OutputFile ) {
  294.         NCBI_THROW(CArgException,eNoFile, s_ArgExptMsg(GetName(),
  295.             "File is not accessible",AsString()));
  296.     }
  297. }
  298. CArg_OutputFile::CArg_OutputFile(const string& name, const string& value,
  299.                                  IOS_BASE::openmode openmode,
  300.                                  bool               delay_open)
  301.     : CArg_String(name, value),
  302.       m_OpenMode(openmode),
  303.       m_OutputFile(0),
  304.       m_DeleteFlag(true)
  305. {
  306.     if ( !delay_open )
  307.         x_Open();
  308. }
  309. CArg_OutputFile::~CArg_OutputFile(void)
  310. {
  311.     if (m_OutputFile  &&  m_DeleteFlag)
  312.         delete m_OutputFile;
  313. }
  314. CNcbiOstream& CArg_OutputFile::AsOutputFile(void) const
  315. {
  316.     x_Open();
  317.     return *m_OutputFile;
  318. }
  319. void CArg_OutputFile::CloseFile(void) const
  320. {
  321.     if ( !m_OutputFile ) {
  322.         ERR_POST(Warning << s_ArgExptMsg( GetName(),
  323.             "CArg_InputFile::CloseFile: File was not opened", AsString()));
  324.         return;
  325.     }
  326.     if ( m_DeleteFlag ) {
  327.         delete m_OutputFile;
  328.         m_OutputFile = 0;
  329.     }
  330. }
  331. /////////////////////////////////////////////////////////////////////////////
  332. /////////////////////////////////////////////////////////////////////////////
  333. //  CArgDesc***::   abstract base classes for argument descriptions
  334. //
  335. //    CArgDesc
  336. //
  337. //    CArgDescMandatory  : CArgDesc
  338. //    CArgDescOptional   : virtual CArgDescMandatory
  339. //    CArgDescDefault    : virtual CArgDescOptional
  340. //
  341. //    CArgDescSynopsis
  342. //
  343. ///////////////////////////////////////////////////////
  344. //  CArgDesc::
  345. CArgDesc::CArgDesc(const string& name, const string& comment)
  346.     : m_Name(name), m_Comment(comment)
  347. {
  348.     if ( !CArgDescriptions::VerifyName(m_Name) ) {
  349.         NCBI_THROW(CArgException,eInvalidArg,
  350.             "Invalid argument name: " + m_Name);
  351.     }
  352. }
  353. CArgDesc::~CArgDesc(void)
  354. {
  355.     return;
  356. }
  357. void CArgDesc::VerifyDefault(void) const
  358. {
  359.     return;
  360. }
  361. void CArgDesc::SetConstraint(CArgAllow* constraint)
  362. {
  363.     NCBI_THROW(CArgException, eConstraint, s_ArgExptMsg(GetName(),
  364.         "No-value arguments may not be constrained",
  365.         constraint ? constraint->GetUsage() : kEmptyStr));
  366. }
  367. const CArgAllow* CArgDesc::GetConstraint(void) const
  368. {
  369.     return 0;
  370. }
  371. string CArgDesc::GetUsageConstraint(void) const
  372. {
  373.     const CArgAllow* constraint = GetConstraint();
  374.     return constraint ? constraint->GetUsage() : kEmptyStr;
  375. }
  376. ///////////////////////////////////////////////////////
  377. //  Overload the comparison operator -- to handle "AutoPtr<CArgDesc>" elements
  378. //  in "CArgs::m_Args" stored as "set< AutoPtr<CArgDesc> >"
  379. //
  380. inline bool operator< (const AutoPtr<CArgDesc>& x, const AutoPtr<CArgDesc>& y)
  381. {
  382.     return x->GetName() < y->GetName();
  383. }
  384. ///////////////////////////////////////////////////////
  385. //  CArgDescMandatory::
  386. CArgDescMandatory::CArgDescMandatory(const string&            name,
  387.                                      const string&            comment,
  388.                                      CArgDescriptions::EType  type,
  389.                                      CArgDescriptions::TFlags flags)
  390.     : CArgDesc(name, comment),
  391.       m_Type(type), m_Flags(flags)
  392. {
  393.     // verify if "flags" "type" are matching
  394.     switch ( type ) {
  395.     case CArgDescriptions::eBoolean:
  396.     case CArgDescriptions::eOutputFile:
  397.         return;
  398.     case CArgDescriptions::eInputFile:
  399.         if((flags &
  400.             ~(CArgDescriptions::fPreOpen | CArgDescriptions::fBinary)) == 0)
  401.             return;
  402.     case CArgDescriptions::k_EType_Size:
  403.         _TROUBLE;
  404.         NCBI_THROW(CArgException, eArgType, s_ArgExptMsg(GetName(),
  405.             "Invalid argument type", "k_EType_Size"));
  406.     default:
  407.         if (flags == 0)
  408.             return;
  409.     }
  410.     NCBI_THROW(CArgException, eArgType, s_ArgExptMsg(GetName(),
  411.         "Argument type/flags mismatch",
  412.         "(type=" + CArgDescriptions::GetTypeName(type) +
  413.         ", flags=" + NStr::UIntToString(flags) + ")"));
  414.         
  415. }
  416. CArgDescMandatory::~CArgDescMandatory(void)
  417. {
  418.     return;
  419. }
  420. string CArgDescMandatory::GetUsageCommentAttr(void) const
  421. {
  422.     // Print type name
  423.     string str = CArgDescriptions::GetTypeName(GetType());
  424.     // Print constraint info, if any
  425.     string constr = GetUsageConstraint();
  426.     if ( !constr.empty() ) {
  427.         str += ", ";
  428.         str += constr;
  429.     }
  430.     return str;
  431. }
  432. CArgValue* CArgDescMandatory::ProcessArgument(const string& value) const
  433. {
  434.     // Process according to the argument type
  435.     CRef<CArgValue> arg_value;
  436.     switch ( GetType() ) {
  437.     case CArgDescriptions::eString:
  438.         arg_value = new CArg_String(GetName(), value);
  439.         break;
  440.     case CArgDescriptions::eBoolean:
  441.         arg_value = new CArg_Boolean(GetName(), value);
  442.         break;
  443.     case CArgDescriptions::eInteger:
  444.         arg_value = new CArg_Integer(GetName(), value);
  445.         break;
  446.     case CArgDescriptions::eDouble:
  447.         arg_value = new CArg_Double(GetName(), value);
  448.         break;
  449.     case CArgDescriptions::eInputFile: {
  450.         bool delay_open = (GetFlags() & CArgDescriptions::fPreOpen) == 0;
  451.         IOS_BASE::openmode openmode = (IOS_BASE::openmode) 0;
  452.         if (GetFlags() & CArgDescriptions::fBinary)
  453.             openmode |= IOS_BASE::binary;
  454.         arg_value = new CArg_InputFile(GetName(), value, openmode, delay_open);
  455.         break;
  456.     }
  457.     case CArgDescriptions::eOutputFile: {
  458.         bool delay_open = (GetFlags() & CArgDescriptions::fPreOpen) == 0;
  459.         IOS_BASE::openmode openmode = (IOS_BASE::openmode) 0;
  460.         if (GetFlags() & CArgDescriptions::fBinary)
  461.             openmode |= IOS_BASE::binary;
  462.         if (GetFlags() & CArgDescriptions::fAppend)
  463.             openmode |= IOS_BASE::app;
  464.         arg_value = new CArg_OutputFile(GetName(), value, openmode,delay_open);
  465.         break;
  466.     }
  467.     case CArgDescriptions::k_EType_Size: {
  468.         _TROUBLE;
  469.         NCBI_THROW(CArgException, eArgType, s_ArgExptMsg(GetName(),
  470.             "Unknown argument type", NStr::IntToString((int)GetType())));
  471.     }
  472.     } /* switch GetType() */
  473.     // Check against additional (user-defined) constraints, if any imposed
  474.     if ( m_Constraint ) {
  475.         bool err = false;
  476.         try {
  477.             if ( !m_Constraint->Verify(value) )
  478.                 err = true;
  479.         } catch (...) {
  480.             err = true;
  481.         }
  482.         if ( err ) {
  483.             NCBI_THROW(CArgException, eConstraint, s_ArgExptMsg(GetName(),
  484.                 "Illegal value, expected " + m_Constraint->GetUsage(),value));
  485.         }
  486.     }
  487.     return arg_value.Release();
  488. }
  489. CArgValue* CArgDescMandatory::ProcessDefault(void) const
  490. {
  491.     NCBI_THROW(CArgException, eNoArg, s_ArgExptMsg(GetName(),
  492.         "Required argument missing", GetUsageCommentAttr()));
  493. }
  494. void CArgDescMandatory::SetConstraint(CArgAllow* constraint)
  495. {
  496.     m_Constraint = constraint;
  497. }
  498. const CArgAllow* CArgDescMandatory::GetConstraint(void) const
  499. {
  500.     return m_Constraint;
  501. }
  502. ///////////////////////////////////////////////////////
  503. //  CArgDescOptional::
  504. CArgDescOptional::CArgDescOptional(const string& name, const string& comment,
  505.                                    CArgDescriptions::EType  type,
  506.                                    CArgDescriptions::TFlags flags)
  507.     : CArgDescMandatory(name, comment, type, flags)
  508. {
  509.     return;
  510. }
  511. CArgDescOptional::~CArgDescOptional(void)
  512. {
  513.     return;
  514. }
  515. CArgValue* CArgDescOptional::ProcessDefault(void) const
  516. {
  517.     return new CArg_NoValue(GetName());
  518. }
  519. ///////////////////////////////////////////////////////
  520. //  CArgDescDefault::
  521. CArgDescDefault::CArgDescDefault(const string& name, const string& comment,
  522.                                  CArgDescriptions::EType  type,
  523.                                  CArgDescriptions::TFlags flags,
  524.                                  const string&            default_value)
  525.     : CArgDescMandatory(name, comment, type, flags),
  526.       CArgDescOptional(name, comment, type, flags),
  527.       m_DefaultValue(default_value)
  528. {
  529.     return;
  530. }
  531. CArgDescDefault::~CArgDescDefault(void)
  532. {
  533.     return;
  534. }
  535. CArgValue* CArgDescDefault::ProcessDefault(void) const
  536. {
  537.     return ProcessArgument(GetDefaultValue());
  538. }
  539. void CArgDescDefault::VerifyDefault(void) const
  540. {
  541.     if (GetType() == CArgDescriptions::eInputFile  ||
  542.         GetType() == CArgDescriptions::eOutputFile) {
  543.         return;
  544.     }
  545.     // Process, then immediately delete
  546.     CRef<CArgValue> arg_value(ProcessArgument(GetDefaultValue()));
  547. }
  548. ///////////////////////////////////////////////////////
  549. //  CArgDescSynopsis::
  550. CArgDescSynopsis::CArgDescSynopsis(const string& synopsis)
  551.     : m_Synopsis(synopsis)
  552. {
  553.     for (string::const_iterator it = m_Synopsis.begin();
  554.          it != m_Synopsis.end();  ++it) {
  555.         if (*it != '_'  &&  !isalnum(*it)) {
  556.             NCBI_THROW(CArgException,eSynopsis,
  557.                 "Argument synopsis must be alphanumeric: "+ m_Synopsis);
  558.         }
  559.     }
  560. }
  561. /////////////////////////////////////////////////////////////////////////////
  562. /////////////////////////////////////////////////////////////////////////////
  563. //  CArgDesc_***::   classes for argument descriptions
  564. //    CArgDesc_Flag    : CArgDesc
  565. //
  566. //    CArgDesc_Key     : virtual CArgDescMandatory
  567. //    CArgDesc_KeyOpt  : CArgDesc_Key, virtual CArgDescOptional
  568. //    CArgDesc_KeyDef  : CArgDesc_Key, CArgDescDefault
  569. //
  570. //    CArgDesc_Pos     : virtual CArgDescMandatory
  571. //    CArgDesc_PosOpt  : CArgDesc_Pos, virtual CArgDescOptional
  572. //    CArgDesc_PosDef  : CArgDesc_Pos, CArgDescDefault
  573. //
  574. ///////////////////////////////////////////////////////
  575. //  CArgDesc_Flag::
  576. CArgDesc_Flag::CArgDesc_Flag(const string& name, const string& comment,
  577.                              bool set_value)
  578.     : CArgDesc(name, comment),
  579.       m_SetValue(set_value)
  580. {
  581.     return;
  582. }
  583. CArgDesc_Flag::~CArgDesc_Flag(void)
  584. {
  585.     return;
  586. }
  587. string CArgDesc_Flag::GetUsageSynopsis(bool /*name_only*/) const
  588. {
  589.     return "-" + GetName();
  590. }
  591. string CArgDesc_Flag::GetUsageCommentAttr(void) const
  592. {
  593.     return kEmptyStr;
  594. }
  595. CArgValue* CArgDesc_Flag::ProcessArgument(const string& /*value*/) const
  596. {
  597.     if ( m_SetValue ) {
  598.         return new CArg_Boolean(GetName(), true);
  599.     } else {
  600.         return new CArg_NoValue(GetName());
  601.     }
  602. }
  603. CArgValue* CArgDesc_Flag::ProcessDefault(void) const
  604. {
  605.     if ( m_SetValue ) {
  606.         return new CArg_NoValue(GetName());
  607.     } else {
  608.         return new CArg_Boolean(GetName(), true);
  609.     }
  610. }
  611. ///////////////////////////////////////////////////////
  612. //  CArgDesc_Pos::
  613. CArgDesc_Pos::CArgDesc_Pos(const string&            name,
  614.                            const string&            comment,
  615.                            CArgDescriptions::EType  type,
  616.                            CArgDescriptions::TFlags flags)
  617.     : CArgDescMandatory(name, comment, type, flags)
  618. {
  619.     return;
  620. }
  621. CArgDesc_Pos::~CArgDesc_Pos(void)
  622. {
  623.     return;
  624. }
  625. string CArgDesc_Pos::GetUsageSynopsis(bool /*name_only*/) const
  626. {
  627.     return GetName().empty() ? s_ExtraName : GetName();
  628. }
  629. ///////////////////////////////////////////////////////
  630. //  CArgDesc_PosOpt::
  631. CArgDesc_PosOpt::CArgDesc_PosOpt(const string&            name,
  632.                                  const string&            comment,
  633.                                  CArgDescriptions::EType  type,
  634.                                  CArgDescriptions::TFlags flags)
  635.     : CArgDescMandatory (name, comment, type, flags),
  636.       CArgDescOptional  (name, comment, type, flags),
  637.       CArgDesc_Pos      (name, comment, type, flags)
  638. {
  639.     return;
  640. }
  641. CArgDesc_PosOpt::~CArgDesc_PosOpt(void)
  642. {
  643.     return;
  644. }
  645. ///////////////////////////////////////////////////////
  646. //  CArgDesc_PosDef::
  647. CArgDesc_PosDef::CArgDesc_PosDef(const string&            name,
  648.                                  const string&            comment,
  649.                                  CArgDescriptions::EType  type,
  650.                                  CArgDescriptions::TFlags flags,
  651.                                  const string&            default_value)
  652.     : CArgDescMandatory (name, comment, type, flags),
  653.       CArgDescOptional  (name, comment, type, flags),
  654.       CArgDescDefault   (name, comment, type, flags, default_value),
  655.       CArgDesc_PosOpt   (name, comment, type, flags)
  656. {
  657.     return;
  658. }
  659. CArgDesc_PosDef::~CArgDesc_PosDef(void)
  660. {
  661.     return;
  662. }
  663. ///////////////////////////////////////////////////////
  664. //  CArgDesc_Key::
  665. CArgDesc_Key::CArgDesc_Key(const string&            name,
  666.                            const string&            comment,
  667.                            CArgDescriptions::EType  type,
  668.                            CArgDescriptions::TFlags flags,
  669.                            const string&            synopsis)
  670.     : CArgDescMandatory(name, comment, type, flags),
  671.       CArgDesc_Pos     (name, comment, type, flags),
  672.       CArgDescSynopsis(synopsis)
  673. {
  674.     return;
  675. }
  676. CArgDesc_Key::~CArgDesc_Key(void)
  677. {
  678.     return;
  679. }
  680. inline string s_KeyUsageSynopsis(const string& name, const string& synopsis,
  681.                                  bool name_only)
  682. {
  683.     if ( name_only ) {
  684.         return '-' + name;
  685.     } else {
  686.         return '-' + name + ' ' + synopsis;
  687.     }
  688. }
  689. string CArgDesc_Key::GetUsageSynopsis(bool name_only) const
  690. {
  691.     return s_KeyUsageSynopsis(GetName(), GetSynopsis(), name_only);
  692. }
  693. ///////////////////////////////////////////////////////
  694. //  CArgDesc_KeyOpt::
  695. CArgDesc_KeyOpt::CArgDesc_KeyOpt(const string&            name,
  696.                                  const string&            comment,
  697.                                  CArgDescriptions::EType  type,
  698.                                  CArgDescriptions::TFlags flags,
  699.                                  const string&            synopsis)
  700.     : CArgDescMandatory(name, comment, type, flags),
  701.       CArgDescOptional (name, comment, type, flags),
  702.       CArgDesc_PosOpt  (name, comment, type, flags),
  703.       CArgDescSynopsis(synopsis)
  704. {
  705.     return;
  706. }
  707. CArgDesc_KeyOpt::~CArgDesc_KeyOpt(void)
  708. {
  709.     return;
  710. }
  711. string CArgDesc_KeyOpt::GetUsageSynopsis(bool name_only) const
  712. {
  713.     return s_KeyUsageSynopsis(GetName(), GetSynopsis(), name_only);
  714. }
  715. ///////////////////////////////////////////////////////
  716. //  CArgDesc_KeyDef::
  717. CArgDesc_KeyDef::CArgDesc_KeyDef(const string&            name,
  718.                                  const string&            comment,
  719.                                  CArgDescriptions::EType  type,
  720.                                  CArgDescriptions::TFlags flags,
  721.                                  const string&            synopsis,
  722.                                  const string&            default_value)
  723.     : CArgDescMandatory(name, comment, type, flags),
  724.       CArgDescOptional (name, comment, type, flags),
  725.       CArgDesc_PosDef  (name, comment, type, flags, default_value),
  726.       CArgDescSynopsis(synopsis)
  727. {
  728.     return;
  729. }
  730. CArgDesc_KeyDef::~CArgDesc_KeyDef(void)
  731. {
  732.     return;
  733. }
  734. string CArgDesc_KeyDef::GetUsageSynopsis(bool name_only) const
  735. {
  736.     return s_KeyUsageSynopsis(GetName(), GetSynopsis(), name_only);
  737. }
  738. /////////////////////////////////////////////////////////////////////////////
  739. /////////////////////////////////////////////////////////////////////////////
  740. //  Aux.functions to figure out various arg. features
  741. //
  742. //    s_IsPositional(arg)
  743. //    s_IsOptional(arg)
  744. //    s_IsFlag(arg)
  745. //
  746. inline bool s_IsKey(const CArgDesc& arg)
  747. {
  748.     return (dynamic_cast<const CArgDescSynopsis*> (&arg) != 0);
  749. }
  750. inline bool s_IsPositional(const CArgDesc& arg)
  751. {
  752.     return dynamic_cast<const CArgDesc_Pos*> (&arg) &&  !s_IsKey(arg);
  753. }
  754. inline bool s_IsOptional(const CArgDesc& arg)
  755. {
  756.     return (dynamic_cast<const CArgDescOptional*> (&arg) != 0);
  757. }
  758. inline bool s_IsFlag(const CArgDesc& arg)
  759. {
  760.     return (dynamic_cast<const CArgDesc_Flag*> (&arg) != 0);
  761. }
  762. /////////////////////////////////////////////////////////////////////////////
  763. /////////////////////////////////////////////////////////////////////////////
  764. //  CArgs::
  765. //
  766. CArgs::CArgs(void)
  767. {
  768.     m_nExtra = 0;
  769. }
  770. CArgs::~CArgs(void)
  771. {
  772.     return;
  773. }
  774. static string s_ComposeNameExtra(size_t idx)
  775. {
  776.     return '#' + NStr::UIntToString(idx);
  777. }
  778. CArgs::TArgsCI CArgs::x_Find(const string& name) const
  779. {
  780.     return m_Args.find(CRef<CArgValue> (new CArg_NoValue(name)));
  781. }
  782. bool CArgs::Exist(const string& name) const
  783. {
  784.     return (x_Find(name) != m_Args.end());
  785. }
  786. const CArgValue& CArgs::operator[] (const string& name) const
  787. {
  788.     TArgsCI arg = x_Find(name);
  789.     if (arg == m_Args.end()) {
  790.         // Special diagnostics for "extra" args
  791.         if (!name.empty()  &&  name[0] == '#') {
  792.             size_t idx;
  793.             try {
  794.                 idx = NStr::StringToUInt(name.c_str() + 1);
  795.             } catch (...) {
  796.                 idx = kMax_UInt;
  797.             }
  798.             if (idx == kMax_UInt) {
  799.                 NCBI_THROW(CArgException,eInvalidArg,
  800.                     "Argument of invalid name requested: "+ name);
  801.             }
  802.             if (m_nExtra == 0) {
  803.                 NCBI_THROW(CArgException,eInvalidArg,
  804.                     "No "extra" (unnamed positional) arguments "
  805.                     "provided, cannot Get: "+ s_ComposeNameExtra(idx));
  806.             }
  807.             if (idx == 0  ||  idx >= m_nExtra) {
  808.                 NCBI_THROW(CArgException,eInvalidArg,
  809.                     ""Extra" (unnamed positional) arg is "
  810.                     "out-of-range (#1..#" + NStr::UIntToString(m_nExtra)
  811.                     + "): "+ s_ComposeNameExtra(idx));
  812.             }
  813.         }
  814.         // Diagnostics for all other argument classes
  815.         NCBI_THROW(CArgException,eInvalidArg,
  816.             "Undescribed argument requested: "+ name);
  817.     }
  818.     // Found arg with name "name"
  819.     return **arg;
  820. }
  821. const CArgValue& CArgs::operator[] (size_t idx) const
  822. {
  823.     return (*this)[s_ComposeNameExtra(idx)];
  824. }
  825. string& CArgs::Print(string& str) const
  826. {
  827.     for (TArgsCI arg = m_Args.begin();  arg != m_Args.end();  ++arg) {
  828.         // Arg. name
  829.         const string& arg_name = (*arg)->GetName();
  830.         str += arg_name;
  831.         // Arg. value, if any
  832.         const CArgValue& arg_value = (*this)[arg_name];
  833.         if ( arg_value ) {
  834.             str += " = `";
  835.             str += arg_value.AsString();
  836.             str += "'n";
  837.         } else {
  838.             str += ":  <not assigned>n";
  839.         }
  840.     }
  841.     return str;
  842. }
  843. void CArgs::Add(CArgValue* arg)
  844. {
  845.     // special case:  add an "extra" arg (generate virtual name for it)
  846.     bool is_extra = false;
  847.     if ( arg->GetName().empty() ) {
  848.         arg->m_Name = s_ComposeNameExtra(m_nExtra + 1);
  849.         is_extra = true;
  850.     }
  851.     // check-up
  852.     _ASSERT(CArgDescriptions::VerifyName(arg->GetName(), true));
  853.     if ( Exist(arg->GetName()) ) {
  854.         NCBI_THROW(CArgException,eSynopsis,
  855.             "Argument with this name is defined already: " + arg->GetName());
  856.     }
  857.     // add
  858.     m_Args.insert(CRef<CArgValue>(arg));
  859.     if ( is_extra ) {
  860.         m_nExtra++;
  861.     }
  862. }
  863. bool CArgs::IsEmpty(void) const
  864. {
  865.     return m_Args.empty();
  866. }
  867. ///////////////////////////////////////////////////////
  868. ///////////////////////////////////////////////////////
  869. //  CArgDescriptions::
  870. //
  871. CArgDescriptions::CArgDescriptions(bool auto_help)
  872.     : m_nExtra(0),
  873.       m_nExtraOpt(0),
  874.       m_AutoHelp(auto_help),
  875.       m_UsageIfNoArgs(false)
  876. {
  877.     SetUsageContext("NCBI_PROGRAM", kEmptyStr);
  878.     if ( m_AutoHelp ) {
  879.         AddFlag(s_AutoHelp,
  880.                 "Print this USAGE message;  ignore other arguments");
  881.     }
  882. }
  883. CArgDescriptions::~CArgDescriptions(void)
  884. {
  885.     return;
  886. }
  887. const string& CArgDescriptions::GetTypeName(EType type)
  888. {
  889.     static const string s_TypeName[k_EType_Size] = {
  890.         "String",
  891.         "Boolean",
  892.         "Integer",
  893.         "Real",
  894.         "File_In",
  895.         "File_Out"
  896.     };
  897.     if (type == k_EType_Size) {
  898.         _TROUBLE;
  899.         NCBI_THROW(CArgException, eArgType,
  900.             "Invalid argument type: k_EType_Size");
  901.     }
  902.     return s_TypeName[(int) type];
  903. }
  904. void CArgDescriptions::AddKey
  905. (const string& name,
  906.  const string& synopsis,
  907.  const string& comment,
  908.  EType         type,
  909.  TFlags        flags)
  910. {
  911.     auto_ptr<CArgDesc_Key> arg
  912.         (new CArgDesc_Key(name, comment, type, flags, synopsis));
  913.     x_AddDesc(*arg);
  914.     arg.release();
  915. }
  916. void CArgDescriptions::AddOptionalKey
  917. (const string& name,
  918.  const string& synopsis,
  919.  const string& comment,
  920.  EType         type,
  921.  TFlags        flags)
  922. {
  923.     auto_ptr<CArgDesc_KeyOpt> arg
  924.         (new CArgDesc_KeyOpt(name, comment, type, flags, synopsis));
  925.     x_AddDesc(*arg);
  926.     arg.release();
  927. }
  928. void CArgDescriptions::AddDefaultKey
  929. (const string& name,
  930.  const string& synopsis,
  931.  const string& comment,
  932.  EType         type,
  933.  const string& default_value,
  934.  TFlags        flags)
  935. {
  936.     auto_ptr<CArgDesc_KeyDef> arg
  937.         (new CArgDesc_KeyDef(name, comment, type, flags, synopsis,
  938.                              default_value));
  939.     x_AddDesc(*arg);
  940.     arg.release();
  941. }
  942. void CArgDescriptions::AddFlag
  943. (const string& name,
  944.  const string& comment,
  945.  bool          set_value)
  946. {
  947.     auto_ptr<CArgDesc_Flag> arg
  948.         (new CArgDesc_Flag(name, comment, set_value));
  949.     x_AddDesc(*arg);
  950.     arg.release();
  951. }
  952. void CArgDescriptions::AddPositional
  953. (const string& name,
  954.  const string& comment,
  955.  EType         type,
  956.  TFlags        flags)
  957. {
  958.     auto_ptr<CArgDesc_Pos> arg
  959.         (new CArgDesc_Pos(name, comment, type, flags));
  960.     x_AddDesc(*arg);
  961.     arg.release();
  962. }
  963. void CArgDescriptions::AddOptionalPositional
  964. (const string& name,
  965.  const string& comment,
  966.  EType         type,
  967.  TFlags        flags)
  968. {
  969.     auto_ptr<CArgDesc_PosOpt> arg
  970.         (new CArgDesc_PosOpt(name, comment, type, flags));
  971.     x_AddDesc(*arg);
  972.     arg.release();
  973. }
  974. void CArgDescriptions::AddDefaultPositional
  975. (const string& name,
  976.  const string& comment,
  977.  EType         type,
  978.  const string& default_value,
  979.  TFlags        flags)
  980. {
  981.     auto_ptr<CArgDesc_PosDef> arg
  982.         (new CArgDesc_PosDef(name, comment, type, flags, default_value));
  983.     x_AddDesc(*arg);
  984.     arg.release();
  985. }
  986. void CArgDescriptions::AddExtra
  987. (unsigned      n_mandatory,
  988.  unsigned      n_optional,
  989.  const string& comment,
  990.  EType         type,
  991.  TFlags        flags)
  992. {
  993.     if (!n_mandatory  &&  !n_optional) {
  994.         NCBI_THROW(CArgException,eSynopsis,
  995.             "Number of extra arguments cannot be zero");
  996.     }
  997.     if (n_mandatory > 4096) {
  998.         NCBI_THROW(CArgException,eSynopsis,
  999.             "Number of mandatory extra arguments is too big");
  1000.     }
  1001.     m_nExtra    = n_mandatory;
  1002.     m_nExtraOpt = n_optional;
  1003.     auto_ptr<CArgDesc_Pos> arg
  1004.         (m_nExtra ?
  1005.          new CArgDesc_Pos   (kEmptyStr, comment, type, flags) :
  1006.          new CArgDesc_PosOpt(kEmptyStr, comment, type, flags));
  1007.     x_AddDesc(*arg);
  1008.     arg.release();
  1009. }
  1010. void CArgDescriptions::SetConstraint(const string& name, CArgAllow* constraint)
  1011. {
  1012.     CRef<CArgAllow> safe_delete(constraint);
  1013.     TArgsI it = x_Find(name);
  1014.     if (it == m_Args.end()) {
  1015.         NCBI_THROW(CArgException, eConstraint, 
  1016.             "Attempt to set constraint for undescribed argument: "+ name);
  1017.     }
  1018.     (*it)->SetConstraint(constraint);
  1019. }
  1020. bool CArgDescriptions::Exist(const string& name) const
  1021. {
  1022.     return (x_Find(name) != m_Args.end());
  1023. }
  1024. void CArgDescriptions::Delete(const string& name)
  1025. {
  1026.     {{ // ...from the list of all args
  1027.         TArgsI it = x_Find(name);
  1028.         if (it == m_Args.end()) {
  1029.             NCBI_THROW(CArgException,eSynopsis,
  1030.                 "Argument description is not found");
  1031.         }
  1032.         m_Args.erase(it);
  1033.         // take special care of the extra args
  1034.         if ( name.empty() ) {
  1035.             m_nExtra = 0;
  1036.             m_nExtraOpt = 0;
  1037.             return;
  1038.         }
  1039.     }}
  1040.     {{ // ...from the list of key/flag args
  1041.         TKeyFlagArgs::iterator it =
  1042.             find(m_KeyFlagArgs.begin(), m_KeyFlagArgs.end(), name);
  1043.         if (it != m_KeyFlagArgs.end()) {
  1044.             m_KeyFlagArgs.erase(it);
  1045.             _ASSERT(find(m_KeyFlagArgs.begin(), m_KeyFlagArgs.end(), name) ==
  1046.                          m_KeyFlagArgs.end());
  1047.             _ASSERT(find(m_PosArgs.begin(), m_PosArgs.end(), name) ==
  1048.                          m_PosArgs.end());
  1049.             return;
  1050.         }
  1051.     }}
  1052.     {{ // ...from the list of positional args' positions
  1053.         TPosArgs::iterator it =
  1054.             find(m_PosArgs.begin(), m_PosArgs.end(), name);
  1055.         _ASSERT (it != m_PosArgs.end());
  1056.         m_PosArgs.erase(it);
  1057.         _ASSERT(find(m_PosArgs.begin(), m_PosArgs.end(), name) ==
  1058.                      m_PosArgs.end());
  1059.     }}
  1060. }
  1061. // Fake class to hold only a name -- to find in "m_Args"
  1062. class CArgDesc_NameOnly : public CArgDesc
  1063. {
  1064. public:
  1065.     CArgDesc_NameOnly(const string& name) :
  1066.         CArgDesc(name, kEmptyStr) {}
  1067. private:
  1068.     virtual string GetUsageSynopsis(bool/*name_only*/) const{return kEmptyStr;}
  1069.     virtual string GetUsageCommentAttr(void) const {return kEmptyStr;}
  1070.     virtual CArgValue* ProcessArgument(const string&) const {return 0;}
  1071.     virtual CArgValue* ProcessDefault(void) const {return 0;}
  1072. };
  1073. CArgDescriptions::TArgsCI CArgDescriptions::x_Find(const string& name) const
  1074. {
  1075.     return m_Args.find(AutoPtr<CArgDesc> (new CArgDesc_NameOnly(name)));
  1076. }
  1077. CArgDescriptions::TArgsI CArgDescriptions::x_Find(const string& name)
  1078. {
  1079.     return m_Args.find(AutoPtr<CArgDesc> (new CArgDesc_NameOnly(name)));
  1080. }
  1081. void CArgDescriptions::x_PreCheck(void) const
  1082. {
  1083.     // Check for the consistency of positional args
  1084.     if ( m_nExtra ) {
  1085.         for (TPosArgs::const_iterator name = m_PosArgs.begin();
  1086.              name != m_PosArgs.end();  ++name) {
  1087.             TArgsCI arg_it = x_Find(*name);
  1088.             _ASSERT(arg_it != m_Args.end());
  1089.             CArgDesc& arg = **arg_it;
  1090.             if (dynamic_cast<const CArgDesc_PosOpt*> (&arg)) {
  1091.                 NCBI_THROW(CArgException, eSynopsis,
  1092.                     "Having both optional named and required unnamed "
  1093.                     "positional arguments is prohibited");
  1094.             }
  1095.         }
  1096.     }
  1097.     // Check for the validity of default values
  1098.     for (TArgsCI it = m_Args.begin();  it != m_Args.end();  ++it) {
  1099.         CArgDesc& arg = **it;
  1100.         if (dynamic_cast<CArgDescDefault*> (&arg) == 0) {
  1101.             continue;
  1102.         }
  1103.         try {
  1104.             arg.VerifyDefault();
  1105.             continue;
  1106.         } catch (CException& e) {
  1107.             NCBI_RETHROW(e,CArgException,eConstraint,
  1108.                 "Invalid default argument value");
  1109.         } catch (exception& e) {
  1110.             NCBI_THROW(CArgException, eConstraint,
  1111.                 string("Invalid default value: ") + e.what());
  1112.         }
  1113.     }
  1114. }
  1115. CArgs* CArgDescriptions::CreateArgs(const CNcbiArguments& args) const
  1116. {
  1117.     return CreateArgs(args.Size(), args);
  1118. }
  1119. void CArgDescriptions::x_CheckAutoHelp(const string& arg) const
  1120. {
  1121.     _ASSERT(m_AutoHelp);
  1122.     if (arg.compare('-' + s_AutoHelp) == 0) {
  1123.         NCBI_THROW(CArgHelpException,eHelp,kEmptyStr);
  1124.     }
  1125. }
  1126. // (return TRUE if "arg2" was used)
  1127. bool CArgDescriptions::x_CreateArg
  1128. (const string& arg1,
  1129.  bool have_arg2, const string& arg2,
  1130.  unsigned* n_plain, CArgs& args)
  1131.     const
  1132. {
  1133.     // Argument name
  1134.     string name;
  1135.     // Check if to start processing the args as positional
  1136.     if (*n_plain == kMax_UInt) {
  1137.         // Check for the "--" delimiter
  1138.         if (arg1.compare("--") == 0) {
  1139.             *n_plain = 0;  // pos.args started
  1140.             return false;
  1141.         }
  1142.         // Check if argument has not a key/flag syntax
  1143.         if ((arg1.length() > 1)  &&  arg1[0] == '-') {
  1144.             // Extract name of flag or key
  1145.             name = arg1.substr(1);
  1146.             if ( !VerifyName(name) ) {
  1147.                 *n_plain = 0;  // pos.args started
  1148.             }
  1149.         } else {
  1150.             *n_plain = 0;  // pos.args started
  1151.         }
  1152.     }
  1153.     // Whether the value of "arg2" is used
  1154.     bool arg2_used = false;
  1155.     // Extract name of positional argument
  1156.     if (*n_plain != kMax_UInt) {
  1157.         if (*n_plain < m_PosArgs.size()) {
  1158.             name = m_PosArgs[*n_plain];  // named positional argument
  1159.         } else {
  1160.             name = kEmptyStr;  // unnamed (extra) positional argument
  1161.         }
  1162.         (*n_plain)++;
  1163.         // Check for too many positional arguments
  1164.         if (kMax_UInt - m_nExtraOpt > m_nExtra + m_PosArgs.size()  &&
  1165.             *n_plain > m_PosArgs.size() + m_nExtra + m_nExtraOpt) {
  1166.             NCBI_THROW(CArgException,eSynopsis,
  1167.                 "Too many positional arguments (" +
  1168.                 NStr::UIntToString(*n_plain) +
  1169.                 "), the offending value: "+ arg1);
  1170.         }
  1171.     }
  1172.     // Get arg. description
  1173.     TArgsCI it = x_Find(name);
  1174.     if (it == m_Args.end()) {
  1175.         if ( name.empty() ) {
  1176.             NCBI_THROW(CArgException,eInvalidArg,
  1177.                 "Unexpected extra argument, at position # " +
  1178.                 NStr::UIntToString(*n_plain));
  1179.         } else {
  1180.             NCBI_THROW(CArgException,eInvalidArg,
  1181.                 "Unknown argument: "+ name);
  1182.         }
  1183.     }
  1184.     _ASSERT(*it);
  1185.     const CArgDesc& arg = **it;
  1186.     // Get argument value
  1187.     const string* value;
  1188.     if ( s_IsKey(arg) ) {
  1189.         // <key> <value> arg  -- advance from the arg.name to the arg.value
  1190.         if ( !have_arg2 ) {
  1191.             NCBI_THROW(CArgException,eNoValue,s_ArgExptMsg(arg1,
  1192.                 "Value is missing", kEmptyStr));
  1193.         }
  1194.         value = &arg2;
  1195.         arg2_used = true;
  1196.     } else {
  1197.         value = &arg1;
  1198.     }
  1199.     // Process the "raw" argument value into "CArgValue"
  1200.     CRef<CArgValue> arg_value(arg.ProcessArgument(*value));
  1201.     // Add the argument value to "args"
  1202.     args.Add(arg_value);
  1203.     // Success (also indicate whether one or two "raw" args have been used)
  1204.     return arg2_used;
  1205. }
  1206. void CArgDescriptions::x_PostCheck(CArgs& args, unsigned n_plain) const
  1207. {
  1208.     // If explicitly specified, printout usage and exit in case there
  1209.     // was no args passed to the application
  1210.     if (m_UsageIfNoArgs  &&  args.IsEmpty()) {
  1211.         NCBI_THROW(CArgHelpException, eHelp, kEmptyStr);
  1212.     }
  1213.     // Check if all mandatory unnamed positional arguments are provided
  1214.     if (m_PosArgs.size() <= n_plain  &&  
  1215.         n_plain < m_PosArgs.size() + m_nExtra){
  1216.         NCBI_THROW(CArgException,eNoArg,
  1217.             "Too few (" + NStr::UIntToString(n_plain) +
  1218.             ") unnamed positional arguments. Must define at least " +
  1219.             NStr::UIntToString(m_nExtra));
  1220.     }
  1221.     // Compose an ordered list of args
  1222.     list<const CArgDesc*> def_args;
  1223.     ITERATE (TKeyFlagArgs, it, m_KeyFlagArgs) {
  1224.         const CArgDesc& arg = **x_Find(*it);
  1225.         def_args.push_back(&arg);
  1226.     }
  1227.     ITERATE (TPosArgs, it, m_PosArgs) {
  1228.         const CArgDesc& arg = **x_Find(*it);
  1229.         def_args.push_back(&arg);
  1230.     }
  1231.     // Set default values (if available) for the arguments not defined
  1232.     // in the command line.
  1233.     ITERATE (list<const CArgDesc*>, it, def_args) {
  1234.         const CArgDesc& arg = **it;
  1235.         // Nothing to do if defined in the command-line
  1236.         if ( args.Exist(arg.GetName()) ) {
  1237.             continue;
  1238.         }
  1239.         // Use default argument value
  1240.         CRef<CArgValue> arg_value(arg.ProcessDefault());
  1241.         // Add the value to "args"
  1242.         args.Add(arg_value);
  1243.     }
  1244. }
  1245. void CArgDescriptions::SetUsageContext
  1246. (const string& usage_name,
  1247.  const string& usage_description,
  1248.  bool          usage_sort_args,
  1249.  SIZE_TYPE     usage_width)
  1250. {
  1251.     m_UsageName        = usage_name;
  1252.     m_UsageDescription = usage_description;
  1253.     m_UsageSortArgs    = usage_sort_args;
  1254.     const SIZE_TYPE kMinUsageWidth = 30;
  1255.     if (usage_width < kMinUsageWidth) {
  1256.         usage_width = kMinUsageWidth;
  1257.         ERR_POST(Warning <<
  1258.                  "CArgDescriptions::SetUsageContext() -- usage_width=" <<
  1259.                  usage_width << " adjusted to " << kMinUsageWidth);
  1260.     }
  1261.     m_UsageWidth = usage_width;
  1262. }
  1263. bool CArgDescriptions::VerifyName(const string& name, bool extended)
  1264. {
  1265.     if ( name.empty() )
  1266.         return true;
  1267.     string::const_iterator it = name.begin();
  1268.     if (extended  &&  *it == '#') {
  1269.         for (++it;  it != name.end();  ++it) {
  1270.             if ( !isdigit(*it) ) {
  1271.                 return false;
  1272.             }
  1273.         }
  1274.     } else {
  1275.         for ( ;  it != name.end();  ++it) {
  1276.             if (!isalnum(*it)  &&  *it != '_')
  1277.                 return false;
  1278.         }
  1279.     }
  1280.     return true;
  1281. }
  1282. void CArgDescriptions::x_AddDesc(CArgDesc& arg)
  1283. {
  1284.     const string& name = arg.GetName();
  1285.     if ( Exist(name) ) {
  1286.         NCBI_THROW(CArgException,eSynopsis,
  1287.             "Argument with this name is already defined: " + name);
  1288.     }
  1289.     if (s_IsKey(arg)  ||  s_IsFlag(arg)) {
  1290.         _ASSERT(find(m_KeyFlagArgs.begin(), m_KeyFlagArgs.end(), name)
  1291.                 == m_KeyFlagArgs.end());
  1292.         m_KeyFlagArgs.push_back(name);
  1293.     } else if ( !name.empty() ) {
  1294.         _ASSERT(find(m_PosArgs.begin(), m_PosArgs.end(), name)
  1295.                 == m_PosArgs.end());
  1296.         if ( s_IsOptional(arg) ) {
  1297.             m_PosArgs.push_back(name);
  1298.         } else {
  1299.             TPosArgs::iterator it;
  1300.             for (it = m_PosArgs.begin();  it != m_PosArgs.end();  ++it) {
  1301.                 if ( s_IsOptional(**x_Find(*it)) )
  1302.                     break;
  1303.             }
  1304.             m_PosArgs.insert(it, name);
  1305.         }
  1306.     }
  1307.     m_Args.insert(&arg);
  1308. }
  1309. void CArgDescriptions::PrintUsageIfNoArgs(bool do_print)
  1310. {
  1311.     m_UsageIfNoArgs = do_print;
  1312. }
  1313. ///////////////////////////////////////////////////////
  1314. //  CArgDescriptions::PrintUsage()
  1315. static void s_PrintCommentBody(list<string>& arr, const string& s,
  1316.                                SIZE_TYPE width)
  1317. {
  1318.     NStr::Wrap(s, width, arr, NStr::fWrap_Hyphenate, "   ");
  1319. }
  1320. static void s_PrintComment(list<string>& arr, const CArgDesc& arg,
  1321.                            SIZE_TYPE width)
  1322. {
  1323.     string intro = ' ' + arg.GetUsageSynopsis(true/*name_only*/);
  1324.     // Print type (and value constraint, if any)
  1325.     string attr = arg.GetUsageCommentAttr();
  1326.     if ( !attr.empty() ) {
  1327.         intro += " <";
  1328.         intro += attr;
  1329.         intro += '>';
  1330.     }
  1331.     // Wrap intro if necessary...
  1332.     {{
  1333.         SIZE_TYPE indent = intro.find(", ");
  1334.         if (indent == NPOS  ||  indent > width / 2) {
  1335.             indent = intro.find(" <");
  1336.             if (indent == NPOS  ||  indent > width / 2) {
  1337.                 indent = 0;
  1338.             }
  1339.         }
  1340.         NStr::Wrap(intro, width, arr, NStr::fWrap_Hyphenate,
  1341.                    string(indent + 2, ' '), kEmptyStr);
  1342.     }}
  1343.     // Print description
  1344.     s_PrintCommentBody(arr, arg.GetComment(), width);
  1345.     // Print default value, if any
  1346.     const CArgDescDefault* dflt = dynamic_cast<const CArgDescDefault*> (&arg);
  1347.     if ( dflt ) {
  1348.         s_PrintCommentBody
  1349.             (arr, "Default = `" + dflt->GetDefaultValue() + ''', width);
  1350.     }
  1351. }
  1352. string& CArgDescriptions::PrintUsage(string& str) const
  1353. {
  1354.     typedef list<const CArgDesc*> TList;
  1355.     typedef TList::iterator       TListI;
  1356.     typedef TList::const_iterator TListCI;
  1357.     TList args;
  1358.     args.push_front(0);
  1359.     TListI it_pos = args.begin();
  1360.     // Keys and Flags
  1361.     if ( m_UsageSortArgs ) {
  1362.         // Alphabetically ordered,
  1363.         // mandatory keys to go first, then flags, then optional keys
  1364.         TListI& it_opt_keys = it_pos; 
  1365.         args.push_front(0);
  1366.         TListI it_flags = args.begin();
  1367.         args.push_front(0);
  1368.         TListI it_keys  = args.begin();
  1369.         for (TArgsCI it = m_Args.begin();  it != m_Args.end();  ++it) {
  1370.             const CArgDesc* arg = it->get();
  1371.             if (dynamic_cast<const CArgDesc_KeyOpt*> (arg)  ||
  1372.                 dynamic_cast<const CArgDesc_KeyDef*> (arg)) {
  1373.                 args.insert(it_opt_keys, arg);
  1374.             } else if (dynamic_cast<const CArgDesc_Key*> (arg)) {
  1375.                 args.insert(it_keys, arg);
  1376.             } else if (dynamic_cast<const CArgDesc_Flag*> (arg)) {
  1377.                 if (s_AutoHelp.compare(arg->GetName()) == 0)
  1378.                     args.push_front(arg);
  1379.                 else
  1380.                     args.insert(it_flags, arg);
  1381.             }
  1382.         }
  1383.         args.erase(it_keys);
  1384.         args.erase(it_flags);
  1385.     } else {
  1386.         // Unsorted, just the order they were described by user
  1387.         for (TKeyFlagArgs::const_iterator name = m_KeyFlagArgs.begin();
  1388.              name != m_KeyFlagArgs.end();  ++name) {
  1389.             TArgsCI it = x_Find(*name);
  1390.             _ASSERT(it != m_Args.end());
  1391.             args.insert(it_pos, it->get());
  1392.         }
  1393.     }
  1394.     // Positional
  1395.     for (TPosArgs::const_iterator name = m_PosArgs.begin();
  1396.          name != m_PosArgs.end();  ++name) {
  1397.         TArgsCI it = x_Find(*name);
  1398.         _ASSERT(it != m_Args.end());
  1399.         const CArgDesc* arg = it->get();
  1400.         // Mandatory args to go first, then go optional ones
  1401.         if (dynamic_cast<const CArgDesc_PosOpt*> (arg)) {
  1402.             args.push_back(arg);
  1403.         } else if (dynamic_cast<const CArgDesc_Pos*> (arg)) {
  1404.             args.insert(it_pos, arg);
  1405.         }
  1406.     }
  1407.     args.erase(it_pos);
  1408.     // Extra
  1409.     {{
  1410.         TArgsCI it = x_Find(kEmptyStr);
  1411.         if (it != m_Args.end()) {
  1412.             args.push_back(it->get());
  1413.         }
  1414.     }}
  1415.     // Do Printout
  1416.     TListCI      it;
  1417.     list<string> arr;
  1418.     // SYNOPSIS
  1419.     arr.push_back("USAGE");
  1420.     {{
  1421.         list<string> syn;
  1422.         syn.push_back(m_UsageName);
  1423.         for (it = args.begin();  it != args.end();  ++it) {
  1424.             if ( s_IsOptional(**it) || s_IsFlag(**it) ) {
  1425.                 syn.push_back('[' + (*it)->GetUsageSynopsis() + ']');
  1426.             } else if ( s_IsPositional(**it) ) {
  1427.                 syn.push_back('<' + (*it)->GetUsageSynopsis() + '>');
  1428.             } else {
  1429.                 syn.push_back((*it)->GetUsageSynopsis());
  1430.             }
  1431.         }
  1432.         NStr::WrapList(syn, m_UsageWidth, " ", arr, 0, "    ", "  ");
  1433.     }}
  1434.     // DESCRIPTION
  1435.     arr.push_back(kEmptyStr);
  1436.     if ( m_UsageDescription.empty() ) {
  1437.         arr.push_back("DESCRIPTION    -- none");
  1438.     } else {
  1439.         arr.push_back("DESCRIPTION");
  1440.         s_PrintCommentBody(arr, m_UsageDescription, m_UsageWidth);
  1441.     }
  1442.     // REQUIRED & OPTIONAL ARGUMENTS
  1443.     list<string> req;
  1444.     list<string> opt;
  1445.     for (it = args.begin();  it != args.end();  ++it) {
  1446.         s_PrintComment((s_IsOptional(**it) || s_IsFlag(**it)) ? opt : req,
  1447.                        **it, m_UsageWidth);
  1448.     }
  1449.     if ( !req.empty() ) {
  1450.         arr.push_back(kEmptyStr);
  1451.         arr.push_back("REQUIRED ARGUMENTS");
  1452.         arr.splice(arr.end(), req);
  1453.     }
  1454.     if ( !m_nExtra  &&  !opt.empty() ) {
  1455.         arr.push_back(kEmptyStr);
  1456.         arr.push_back("OPTIONAL ARGUMENTS");
  1457.         arr.splice(arr.end(), opt);
  1458.     }
  1459.     // # of extra arguments
  1460.     if (m_nExtra  ||  (m_nExtraOpt != 0  &&  m_nExtraOpt != kMax_UInt)) {
  1461.         string str_extra = "NOTE:  Specify ";
  1462.         if ( m_nExtra ) {
  1463.             str_extra += "at least ";
  1464.             str_extra += NStr::UIntToString(m_nExtra);
  1465.             if (m_nExtraOpt != kMax_UInt) {
  1466.                 str_extra += ", and ";
  1467.             }
  1468.         }
  1469.         if (m_nExtraOpt != kMax_UInt) {
  1470.             str_extra += "no more than ";
  1471.             str_extra += NStr::UIntToString(m_nExtra + m_nExtraOpt);
  1472.         }
  1473.         str_extra += " arguments in "...."";
  1474.         s_PrintCommentBody(arr, str_extra, m_UsageWidth);
  1475.     }
  1476.     if ( m_nExtra  &&  !opt.empty() ) {
  1477.         arr.push_back(kEmptyStr);
  1478.         arr.push_back("OPTIONAL ARGUMENTS");
  1479.         arr.splice(arr.end(), opt);
  1480.     }
  1481.     str += NStr::Join(arr, "n");
  1482.     str += "n";
  1483.     return str;
  1484. }
  1485. ///////////////////////////////////////////////////////
  1486. ///////////////////////////////////////////////////////
  1487. // CArgAllow::
  1488. //   CArgAllow_Symbols::
  1489. //   CArgAllow_String::
  1490. //   CArgAllow_Strings::
  1491. //   CArgAllow_Integers::
  1492. //   CArgAllow_Doubles::
  1493. //
  1494. ///////////////////////////////////////////////////////
  1495. //  CArgAllow::
  1496. //
  1497. CArgAllow::~CArgAllow(void)
  1498. {
  1499.     return;
  1500. }
  1501. ///////////////////////////////////////////////////////
  1502. //  s_IsSymbol() -- check if the symbol belongs to one of standard character
  1503. //                  classes from <ctype.h>, or to user-defined symbol set
  1504. //
  1505. inline bool s_IsAllowedSymbol(unsigned char                   ch,
  1506.                               CArgAllow_Symbols::ESymbolClass symbol_class,
  1507.                               const string&                   symbol_set)
  1508. {
  1509.     switch ( symbol_class ) {
  1510.     case CArgAllow_Symbols::eAlnum:   return isalnum(ch) != 0;
  1511.     case CArgAllow_Symbols::eAlpha:   return isalpha(ch) != 0;
  1512.     case CArgAllow_Symbols::eCntrl:   return iscntrl(ch) != 0;
  1513.     case CArgAllow_Symbols::eDigit:   return isdigit(ch) != 0;
  1514.     case CArgAllow_Symbols::eGraph:   return isgraph(ch) != 0;
  1515.     case CArgAllow_Symbols::eLower:   return islower(ch) != 0;
  1516.     case CArgAllow_Symbols::ePrint:   return isprint(ch) != 0;
  1517.     case CArgAllow_Symbols::ePunct:   return ispunct(ch) != 0;
  1518.     case CArgAllow_Symbols::eSpace:   return isspace(ch) != 0;
  1519.     case CArgAllow_Symbols::eUpper:   return isupper(ch) != 0;
  1520.     case CArgAllow_Symbols::eXdigit:  return isxdigit(ch) != 0;
  1521.     case CArgAllow_Symbols::eUser:
  1522.         return symbol_set.find_first_of(ch) != NPOS;
  1523.     }
  1524.     _TROUBLE;  return false;
  1525. }
  1526. static string s_GetUsageSymbol(CArgAllow_Symbols::ESymbolClass symbol_class,
  1527.                                const string&                   symbol_set)
  1528. {
  1529.     switch ( symbol_class ) {
  1530.     case CArgAllow_Symbols::eAlnum:   return "alphanumeric";
  1531.     case CArgAllow_Symbols::eAlpha:   return "alphabetic";
  1532.     case CArgAllow_Symbols::eCntrl:   return "control symbol";
  1533.     case CArgAllow_Symbols::eDigit:   return "decimal";
  1534.     case CArgAllow_Symbols::eGraph:   return "graphical symbol";
  1535.     case CArgAllow_Symbols::eLower:   return "lower case";
  1536.     case CArgAllow_Symbols::ePrint:   return "printable";
  1537.     case CArgAllow_Symbols::ePunct:   return "punctuation";
  1538.     case CArgAllow_Symbols::eSpace:   return "space";
  1539.     case CArgAllow_Symbols::eUpper:   return "upper case";
  1540.     case CArgAllow_Symbols::eXdigit:  return "hexadecimal";
  1541.     case CArgAllow_Symbols::eUser:
  1542.         return "'" + NStr::PrintableString(symbol_set) + "'";
  1543.     }
  1544.     _TROUBLE;  return kEmptyStr;
  1545. }
  1546. ///////////////////////////////////////////////////////
  1547. //  CArgAllow_Symbols::
  1548. //
  1549. CArgAllow_Symbols::CArgAllow_Symbols(ESymbolClass symbol_class)
  1550.     : CArgAllow(),
  1551.       m_SymbolClass(symbol_class)
  1552. {
  1553.     return;
  1554. }
  1555. CArgAllow_Symbols::CArgAllow_Symbols(const string& symbol_set)
  1556.     : CArgAllow(),
  1557.       m_SymbolClass(eUser), m_SymbolSet(symbol_set)
  1558. {
  1559.     return;
  1560. }
  1561. bool CArgAllow_Symbols::Verify(const string& value) const
  1562. {
  1563.     if (value.length() != 1)
  1564.         return false;
  1565.     return s_IsAllowedSymbol(value[0], m_SymbolClass, m_SymbolSet);
  1566. }
  1567. string CArgAllow_Symbols::GetUsage(void) const
  1568. {
  1569.     return "one symbol: " + s_GetUsageSymbol(m_SymbolClass, m_SymbolSet);
  1570. }
  1571. CArgAllow_Symbols::~CArgAllow_Symbols(void)
  1572. {
  1573.     return;
  1574. }
  1575. ///////////////////////////////////////////////////////
  1576. //  CArgAllow_String::
  1577. //
  1578. CArgAllow_String::CArgAllow_String(ESymbolClass symbol_class)
  1579.     : CArgAllow_Symbols(symbol_class)
  1580. {
  1581.     return;
  1582. }
  1583. CArgAllow_String::CArgAllow_String(const string& symbol_set)
  1584.     : CArgAllow_Symbols(symbol_set)
  1585. {
  1586.     return;
  1587. }
  1588. bool CArgAllow_String::Verify(const string& value) const
  1589. {
  1590.     for (string::const_iterator it = value.begin();  it != value.end(); ++it) {
  1591.         if ( !s_IsAllowedSymbol(*it, m_SymbolClass, m_SymbolSet) )
  1592.             return false;
  1593.     }
  1594.     return true;
  1595. }
  1596. string CArgAllow_String::GetUsage(void) const
  1597. {
  1598.     return "to contain only symbols: " +
  1599.         s_GetUsageSymbol(m_SymbolClass, m_SymbolSet);
  1600. }
  1601. ///////////////////////////////////////////////////////
  1602. //  CArgAllow_Strings::
  1603. //
  1604. CArgAllow_Strings::CArgAllow_Strings(void)
  1605.     : CArgAllow()
  1606. {
  1607.     return;
  1608. }
  1609. CArgAllow_Strings* CArgAllow_Strings::Allow(const string& value)
  1610. {
  1611.     m_Strings.insert(value);
  1612.     return this;
  1613. }
  1614. bool CArgAllow_Strings::Verify(const string& value) const
  1615. {
  1616.     return (m_Strings.find(value) != m_Strings.end());
  1617. }
  1618. string CArgAllow_Strings::GetUsage(void) const
  1619. {
  1620.     if ( m_Strings.empty() ) {
  1621.         return "ERROR:  Constraint with no values allowed(?!)";
  1622.     }
  1623.     string str;
  1624.     set<string>::const_iterator it = m_Strings.begin();
  1625.     for (;;) {
  1626.         str += "`";
  1627.         str += *it;
  1628.         ++it;
  1629.         if (it == m_Strings.end()) {
  1630.             str += "'";
  1631.             break;
  1632.         }
  1633.         str += "', ";
  1634.     }
  1635.     return str;
  1636. }
  1637. CArgAllow_Strings::~CArgAllow_Strings(void)
  1638. {
  1639.     return;
  1640. }
  1641. ///////////////////////////////////////////////////////
  1642. //  CArgAllow_Integers::
  1643. //
  1644. CArgAllow_Integers::CArgAllow_Integers(int x_min, int x_max)
  1645.     : CArgAllow()
  1646. {
  1647.     if (x_min <= x_max) {
  1648.         m_Min = x_min;
  1649.         m_Max = x_max;
  1650.     } else {
  1651.         m_Min = x_max;
  1652.         m_Max = x_min;
  1653.     }
  1654. }
  1655. bool CArgAllow_Integers::Verify(const string& value) const
  1656. {
  1657.     int val = NStr::StringToInt(value);
  1658.     return (m_Min <= val  &&  val <= m_Max);
  1659. }
  1660. string CArgAllow_Integers::GetUsage(void) const
  1661. {
  1662.     return NStr::IntToString(m_Min) + ".." + NStr::IntToString(m_Max);
  1663. }
  1664. ///////////////////////////////////////////////////////
  1665. //  CArgAllow_Doubles::
  1666. //
  1667. CArgAllow_Doubles::CArgAllow_Doubles(double x_min, double x_max)
  1668.     : CArgAllow()
  1669. {
  1670.     if (x_min <= x_max) {
  1671.         m_Min = x_min;
  1672.         m_Max = x_max;
  1673.     } else {
  1674.         m_Min = x_max;
  1675.         m_Max = x_min;
  1676.     }
  1677. }
  1678. bool CArgAllow_Doubles::Verify(const string& value) const
  1679. {
  1680.     double val = NStr::StringToDouble(value);
  1681.     return (m_Min <= val  &&  val <= m_Max);
  1682. }
  1683. string CArgAllow_Doubles::GetUsage(void) const
  1684. {
  1685.     return NStr::DoubleToString(m_Min) + ".." + NStr::DoubleToString(m_Max);
  1686. }
  1687. END_NCBI_SCOPE
  1688. /*
  1689.  * ===========================================================================
  1690.  * $Log: ncbiargs.cpp,v $
  1691.  * Revision 1000.1  2004/06/01 19:08:48  gouriano
  1692.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.48
  1693.  *
  1694.  * Revision 1.48  2004/05/14 13:59:26  gorelenk
  1695.  * Added include of ncbi_pch.hpp
  1696.  *
  1697.  * Revision 1.47  2003/09/16 19:51:36  rsmith
  1698.  * move CreateArgs definition to avoid new Codewarrior compiler bug.
  1699.  *
  1700.  * Revision 1.46  2003/05/28 18:01:58  kuznets
  1701.  * Changed program help (usage section). Now prints flags as optional argument in []
  1702.  *
  1703.  * Revision 1.45  2003/05/16 16:00:41  vakatov
  1704.  * + CArgs::IsEmpty()
  1705.  * + CArgDescriptions::PrintUsageIfNoArgs()
  1706.  *
  1707.  * Revision 1.44  2003/03/10 18:57:07  kuznets
  1708.  * iterate->ITERATE
  1709.  *
  1710.  * Revision 1.43  2003/02/10 18:07:07  kuznets
  1711.  * Fixed problem with mandatory extra args
  1712.  *
  1713.  * Revision 1.42  2002/11/04 21:29:04  grichenk
  1714.  * Fixed usage of const CRef<> and CRef<> constructor
  1715.  *
  1716.  * Revision 1.41  2002/10/03 14:44:34  ucko
  1717.  * Tweak the interfaces to NStr::Wrap* to avoid publicly depending on
  1718.  * kEmptyStr, removing the need for fWrap_UsePrefix1 in the process; also
  1719.  * drop fWrap_FavorPunct, as WrapList should be a better choice for such
  1720.  * situations.
  1721.  *
  1722.  * Revision 1.40  2002/10/02 20:16:46  ucko
  1723.  * Take advantage of the new wrapping-related code in NStr:: when
  1724.  * formatting usage messages.
  1725.  * Move the note about "...." up if there are required extra arguments.
  1726.  *
  1727.  * Revision 1.39  2002/08/08 18:37:32  gouriano
  1728.  * corrected CArgDescriptions::Delete
  1729.  *
  1730.  * Revision 1.38  2002/07/15 18:17:23  gouriano
  1731.  * renamed CNcbiException and its descendents
  1732.  *
  1733.  * Revision 1.37  2002/07/11 14:18:25  gouriano
  1734.  * exceptions replaced by CNcbiException-type ones
  1735.  *
  1736.  * Revision 1.36  2002/06/13 20:41:57  ucko
  1737.  * Improve usage formatting for long choice lists.
  1738.  *
  1739.  * Revision 1.35  2002/04/24 04:02:45  vakatov
  1740.  * Do not use #NO_INCLASS_TMPL anymore -- apparently all modern
  1741.  * compilers seem to be supporting in-class template methods.
  1742.  *
  1743.  * Revision 1.34  2002/04/11 21:08:01  ivanov
  1744.  * CVS log moved to end of the file
  1745.  *
  1746.  * Revision 1.33  2001/07/24 23:33:14  vakatov
  1747.  * Use _DEBUG_ARG() to get rid of the compiler warnings in Release mode
  1748.  *
  1749.  * Revision 1.32  2001/03/16 16:40:18  vakatov
  1750.  * Moved <corelib/ncbi_limits.h> to the header
  1751.  *
  1752.  * Revision 1.31  2001/01/22 23:07:14  vakatov
  1753.  * CArgValue::AsInteger() to return "int" (rather than "long")
  1754.  *
  1755.  * Revision 1.30  2001/01/03 17:45:35  vakatov
  1756.  * + <ncbi_limits.h>
  1757.  *
  1758.  * Revision 1.29  2000/12/24 00:13:00  vakatov
  1759.  * Radically revamped NCBIARGS.
  1760.  * Introduced optional key and posit. args without default value.
  1761.  * Added new arg.value constraint classes.
  1762.  * Passed flags to be detected by HasValue() rather than AsBoolean.
  1763.  * Simplified constraints on the number of mandatory and optional extra args.
  1764.  * Improved USAGE info and diagnostic messages. Etc...
  1765.  *
  1766.  * Revision 1.26  2000/11/29 00:18:13  vakatov
  1767.  * s_ProcessArgument() -- avoid nested quotes in the exception message
  1768.  *
  1769.  * Revision 1.25  2000/11/29 00:07:28  vakatov
  1770.  * Flag and key args not to be sorted in alphabetical order by default; see
  1771.  * "usage_sort_args" in SetUsageContext().
  1772.  *
  1773.  * Revision 1.24  2000/11/24 23:28:33  vakatov
  1774.  * CArgValue::  added CloseFile()
  1775.  * CArgValue::  get rid of "change_mode" feature in AsInput/OutputFile()
  1776.  *
  1777.  * Revision 1.23  2000/11/22 22:04:31  vakatov
  1778.  * Added special flag "-h" and special exception CArgHelpException to
  1779.  * force USAGE printout in a standard manner
  1780.  *
  1781.  * Revision 1.22  2000/11/17 22:04:30  vakatov
  1782.  * CArgDescriptions::  Switch the order of optional args in methods
  1783.  * AddOptionalKey() and AddPlain(). Also, enforce the default value to
  1784.  * match arg. description (and constraints, if any) at all times.
  1785.  *
  1786.  * Revision 1.21  2000/11/13 20:31:07  vakatov
  1787.  * Wrote new test, fixed multiple bugs, ugly "features", and the USAGE.
  1788.  *
  1789.  * Revision 1.20  2000/11/09 21:02:58  vakatov
  1790.  * USAGE to show default value for optional arguments
  1791.  *
  1792.  * Revision 1.19  2000/11/08 17:48:37  butanaev
  1793.  * There was no minus in optional key synopsis, fixed.
  1794.  *
  1795.  * Revision 1.18  2000/11/01 20:37:15  vasilche
  1796.  * Fixed detection of heap objects.
  1797.  * Removed ECanDelete enum and related constructors.
  1798.  * Disabled sync_with_stdio ad the beginning of AppMain.
  1799.  *
  1800.  * Revision 1.17  2000/10/30 22:26:29  vakatov
  1801.  * Get rid of "s_IsAvailableExtra()" -- not used anymore
  1802.  *
  1803.  * Revision 1.16  2000/10/20 22:33:37  vakatov
  1804.  * CArgAllow_Integers, CArgAllow_Doubles:  swap min/max, if necessary
  1805.  *
  1806.  * Revision 1.15  2000/10/20 22:23:28  vakatov
  1807.  * CArgAllow_Strings customization;  MSVC++ fixes;  better diagnostic messages
  1808.  *
  1809.  * Revision 1.14  2000/10/20 20:25:55  vakatov
  1810.  * Redesigned/reimplemented the user-defined arg.value constraints
  1811.  * mechanism (CArgAllow-related classes and methods). +Generic clean-up.
  1812.  *
  1813.  * Revision 1.13  2000/10/13 16:26:30  vasilche
  1814.  * Added heuristic for detection of CObject allocation in heap.
  1815.  *
  1816.  * Revision 1.12  2000/10/11 21:03:49  vakatov
  1817.  * Cleanup to avoid 64-bit to 32-bit values truncation, etc.
  1818.  * (reported by Forte6 Patch 109490-01)
  1819.  *
  1820.  * Revision 1.11  2000/10/06 21:56:45  butanaev
  1821.  * Added Allow() function. Added classes CArgAllowValue, CArgAllowIntInterval.
  1822.  *
  1823.  * Revision 1.10  2000/09/29 17:10:54  butanaev
  1824.  * Got rid of IsDefaultValue(), added IsProvided().
  1825.  *
  1826.  * Revision 1.9  2000/09/28 21:00:14  butanaev
  1827.  * fPreOpen with opposite meaning took over fDelayOpen.
  1828.  * IsDefaultValue() added which returns true if no
  1829.  * value for an optional argument was provided in cmd. line.
  1830.  *
  1831.  *
  1832.  * Revision 1.7  2000/09/28 19:38:00  butanaev
  1833.  * stdin and stdout now referenced as '-' Example: ./test_ncbiargs -if - -of -
  1834.  *
  1835.  * Revision 1.6  2000/09/22 21:25:59  butanaev
  1836.  * Fixed bug in handling default arg values.
  1837.  *
  1838.  * Revision 1.5  2000/09/19 21:19:58  butanaev
  1839.  * Added possibility to change file open mode on the fly
  1840.  *
  1841.  * Revision 1.4  2000/09/18 19:39:02  vasilche
  1842.  * Added CreateArgs() from CNcbiArguments.
  1843.  *
  1844.  * Revision 1.3  2000/09/12 15:00:30  butanaev
  1845.  * Fixed bug with stdin, stdout caused compilation errors on IRIX.
  1846.  *
  1847.  * Revision 1.2  2000/09/06 18:56:04  butanaev
  1848.  * Added stdin, stdout support. Fixed bug in PrintOut.
  1849.  *
  1850.  * Revision 1.1  2000/08/31 23:54:49  vakatov
  1851.  * Initial revision
  1852.  *
  1853.  * ===========================================================================
  1854.  */