src/corelib/ncbiargs.cpp

Go to the documentation of this file.
00001 /*  $Id: ncbiargs.cpp 159911 2009-05-11 13:35:17Z gouriano $
00002  * ===========================================================================
00003  *
00004  *                            PUBLIC DOMAIN NOTICE
00005  *               National Center for Biotechnology Information
00006  *
00007  *  This software/database is a "United States Government Work" under the
00008  *  terms of the United States Copyright Act.  It was written as part of
00009  *  the author's official duties as a United States Government employee and
00010  *  thus cannot be copyrighted.  This software/database is freely available
00011  *  to the public for use. The National Library of Medicine and the U.S.
00012  *  Government have not placed any restriction on its use or reproduction.
00013  *
00014  *  Although all reasonable efforts have been taken to ensure the accuracy
00015  *  and reliability of the software and data, the NLM and the U.S.
00016  *  Government do not and cannot warrant the performance or results that
00017  *  may be obtained by using this software or data. The NLM and the U.S.
00018  *  Government disclaim all warranties, express or implied, including
00019  *  warranties of performance, merchantability or fitness for any particular
00020  *  purpose.
00021  *
00022  *  Please cite the author in any work or product based on this material.
00023  *
00024  * ===========================================================================
00025  *
00026  * Authors:  Denis Vakatov, Anton Butanayev
00027  *
00028  * File Description:
00029  *   Command-line arguments' processing:
00030  *      descriptions  -- CArgDescriptions,  CArgDesc
00031  *      parsed values -- CArgs,             CArgValue
00032  *      exceptions    -- CArgException, ARG_THROW()
00033  *      constraints   -- CArgAllow;  CArgAllow_{Strings,Integers,Int8s,Doubles}
00034  *
00035  */
00036 
00037 #include <ncbi_pch.hpp>
00038 #include <corelib/ncbiapp.hpp>
00039 #include <corelib/ncbiargs.hpp>
00040 #include <corelib/ncbienv.hpp>
00041 #include <corelib/error_codes.hpp>
00042 #include <algorithm>
00043 
00044 #if defined(NCBI_OS_MSWIN)
00045 #  include <corelib/ncbi_os_mswin.hpp>
00046 #  include <io.h> 
00047 #  include <fcntl.h> 
00048 #endif
00049 
00050 
00051 #define NCBI_USE_ERRCODE_X   Corelib_Config
00052 
00053 
00054 BEGIN_NCBI_SCOPE
00055 
00056 
00057 /////////////////////////////////////////////////////////////////////////////
00058 //  Include the private header
00059 //
00060 
00061 #define NCBIARGS__CPP
00062 #include "ncbiargs_p.hpp"
00063 
00064 
00065 
00066 /////////////////////////////////////////////////////////////////////////////
00067 //  Constants
00068 //
00069 
00070 static const char* s_AutoHelp     = "h";
00071 static const char* s_AutoHelpFull = "help";
00072 static const char* s_AutoHelpXml  = "xmlhelp";
00073 static const char* s_ExtraName    = "....";
00074 
00075 
00076 
00077 /////////////////////////////////////////////////////////////////////////////
00078 
00079 inline
00080 string s_ArgExptMsg(const string& name, const string& what, const string& attr)
00081 {
00082     return string("Argument \"") + (name.empty() ? s_ExtraName : name) +
00083         "\". " + what + (attr.empty() ? attr : ":  `" + attr + "'");
00084 }
00085 
00086 inline
00087 void s_WriteEscapedStr(CNcbiOstream& out, const char* s)
00088 {
00089     out << NStr::XmlEncode(s);
00090 }
00091 
00092 void s_WriteXmlLine(CNcbiOstream& out, const string& tag, const string& data)
00093 {
00094     CStringUTF8 u(data,eEncoding_Unknown);
00095     out << "<"  << tag << ">";
00096     s_WriteEscapedStr(out, u.c_str());
00097     out << "</" << tag << ">" << endl;
00098 }
00099 
00100 /////////////////////////////////////////////////////////////////////////////
00101 //  CArg_***::   classes representing various types of argument value
00102 //
00103 //    CArgValue
00104 //       CArg_NoValue        : CArgValue
00105 //       CArg_String         : CArgValue
00106 //          CArg_Int8        : CArg_String
00107 //             CArg_Integer  : CArg_Int8
00108 //          CArg_Double      : CArg_String
00109 //          CArg_Boolean     : CArg_String
00110 //          CArg_InputFile   : CArg_String
00111 //          CArg_OutputFile  : CArg_String
00112 //
00113 
00114 
00115 ///////////////////////////////////////////////////////
00116 //  CArgValue::
00117 
00118 CArgValue::CArgValue(const string& name)
00119     : m_Name(name)
00120 {
00121     if ( !CArgDescriptions::VerifyName(m_Name, true) ) {
00122         NCBI_THROW(CArgException,eInvalidArg,
00123             "Invalid argument name: " + m_Name);
00124     }
00125 }
00126 
00127 
00128 CArgValue::~CArgValue(void)
00129 {
00130     return;
00131 }
00132 
00133 
00134 const CArgValue::TStringArray& CArgValue::GetStringList() const
00135 {
00136     NCBI_THROW(CArgException, eInvalidArg,
00137         "Value lists not implemented for this argument: " + m_Name);
00138 }
00139 
00140 
00141 CArgValue::TStringArray& CArgValue::SetStringList()
00142 {
00143     NCBI_THROW(CArgException, eInvalidArg,
00144         "Value lists not implemented for this argument: " + m_Name);
00145 }
00146 
00147 
00148 //  Overload the comparison operator -- to handle "CRef<CArgValue>" elements
00149 //  in "CArgs::m_Args" stored as "set< CRef<CArgValue> >"
00150 //
00151 inline bool operator< (const CRef<CArgValue>& x, const CRef<CArgValue>& y)
00152 {
00153     return x->GetName() < y->GetName();
00154 }
00155 
00156 
00157 
00158 ///////////////////////////////////////////////////////
00159 //  CArg_NoValue::
00160 
00161 inline CArg_NoValue::CArg_NoValue(const string& name)
00162     : CArgValue(name)
00163 {
00164     return;
00165 }
00166 
00167 
00168 bool CArg_NoValue::HasValue(void) const
00169 {
00170     return false;
00171 }
00172 
00173 
00174 #define THROW_CArg_NoValue \
00175     NCBI_THROW(CArgException,eNoValue, s_ArgExptMsg(GetName(), \
00176         "Optional argument must have a default value", "NULL"));
00177 
00178 const string& CArg_NoValue::AsString    (void) const { THROW_CArg_NoValue; }
00179 Int8          CArg_NoValue::AsInt8      (void) const { THROW_CArg_NoValue; }
00180 int           CArg_NoValue::AsInteger   (void) const { THROW_CArg_NoValue; }
00181 double        CArg_NoValue::AsDouble    (void) const { THROW_CArg_NoValue; }
00182 bool          CArg_NoValue::AsBoolean   (void) const { THROW_CArg_NoValue; }
00183 CNcbiIstream& CArg_NoValue::AsInputFile (void) const { THROW_CArg_NoValue; }
00184 CNcbiOstream& CArg_NoValue::AsOutputFile(void) const { THROW_CArg_NoValue; }
00185 void          CArg_NoValue::CloseFile   (void) const { THROW_CArg_NoValue; }
00186 
00187 
00188 
00189 ///////////////////////////////////////////////////////
00190 //  CArg_String::
00191 
00192 inline CArg_String::CArg_String(const string& name, const string& value)
00193     : CArgValue(name)
00194 {
00195     m_StringList.push_back(value);
00196 }
00197 
00198 
00199 bool CArg_String::HasValue(void) const
00200 {
00201     return !m_StringList.empty();
00202 }
00203 
00204 
00205 const string& CArg_String::AsString(void) const
00206 {
00207     if (m_StringList.empty()) {
00208         return kEmptyStr;
00209     }
00210     return m_StringList[0];
00211 }
00212 
00213 
00214 const CArgValue::TStringArray& CArg_String::GetStringList() const
00215 {
00216     return m_StringList;
00217 }
00218 
00219 
00220 CArgValue::TStringArray& CArg_String::SetStringList()
00221 {
00222     return m_StringList;
00223 }
00224 
00225 
00226 Int8 CArg_String::AsInt8(void) const
00227 { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
00228     "Attempt to cast to a wrong (Int8) type", AsString()));}
00229 
00230 int CArg_String::AsInteger(void) const
00231 { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
00232     "Attempt to cast to a wrong (Integer) type", AsString()));}
00233 
00234 double CArg_String::AsDouble(void) const
00235 { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
00236     "Attempt to cast to a wrong (Double) type", AsString()));}
00237 
00238 bool CArg_String::AsBoolean(void) const
00239 { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
00240     "Attempt to cast to a wrong (Boolean) type", AsString()));}
00241 
00242 CNcbiIstream& CArg_String::AsInputFile(void) const
00243 { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
00244     "Attempt to cast to a wrong (InputFile) type", AsString()));}
00245 
00246 CNcbiOstream& CArg_String::AsOutputFile(void) const
00247 { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
00248     "Attempt to cast to a wrong (OutputFile) type", AsString()));}
00249 
00250 void CArg_String::CloseFile(void) const
00251 { NCBI_THROW(CArgException,eWrongCast,s_ArgExptMsg(GetName(),
00252     "Attempt to close an argument of non-file type", AsString()));}
00253 
00254 
00255 
00256 ///////////////////////////////////////////////////////
00257 //  CArg_Int8::
00258 
00259 inline CArg_Int8::CArg_Int8(const string& name, const string& value)
00260     : CArg_String(name, value)
00261 {
00262     try {
00263         m_Integer = NStr::StringToInt8(value);
00264     } catch (CException& e) {
00265         NCBI_RETHROW(e, CArgException, eConvert, s_ArgExptMsg(GetName(),
00266             "Argument cannot be converted", value));
00267     }
00268 }
00269 
00270 
00271 Int8 CArg_Int8::AsInt8(void) const
00272 {
00273     return m_Integer;
00274 }
00275 
00276 
00277 
00278 ///////////////////////////////////////////////////////
00279 //  CArg_Integer::
00280 
00281 inline CArg_Integer::CArg_Integer(const string& name, const string& value)
00282     : CArg_Int8(name, value)
00283 {
00284     if (m_Integer < kMin_Int  ||  kMin_Int > m_Integer) {
00285         NCBI_THROW(CArgException, eConvert, s_ArgExptMsg(GetName(),
00286             "Integer value is out of range", value));
00287     }
00288 }
00289 
00290 
00291 int CArg_Integer::AsInteger(void) const
00292 {
00293     return static_cast<int> (m_Integer);
00294 }
00295 
00296 
00297 
00298 ///////////////////////////////////////////////////////
00299 //  CArg_Double::
00300 
00301 inline CArg_Double::CArg_Double(const string& name, const string& value)
00302     : CArg_String(name, value)
00303 {
00304     try {
00305         m_Double = NStr::StringToDouble(value);
00306     } catch (CException& e) {
00307         NCBI_RETHROW(e,CArgException,eConvert,
00308             s_ArgExptMsg(GetName(),"Argument cannot be converted",value));
00309     }
00310 }
00311 
00312 
00313 double CArg_Double::AsDouble(void) const
00314 {
00315     return m_Double;
00316 }
00317 
00318 
00319 
00320 ///////////////////////////////////////////////////////
00321 //  CArg_Boolean::
00322 
00323 inline CArg_Boolean::CArg_Boolean(const string& name, bool value)
00324     : CArg_String(name, NStr::BoolToString(value))
00325 {
00326     m_Boolean = value;
00327 }
00328 
00329 
00330 inline CArg_Boolean::CArg_Boolean(const string& name, const string& value)
00331     : CArg_String(name, value)
00332 {
00333     try {
00334         m_Boolean = NStr::StringToBool(value);
00335     } catch (CException& e) {
00336         NCBI_RETHROW(e,CArgException,eConvert, s_ArgExptMsg(GetName(),
00337             "Argument cannot be converted",value));
00338     }
00339 }
00340 
00341 
00342 bool CArg_Boolean::AsBoolean(void) const
00343 {
00344     return m_Boolean;
00345 }
00346 
00347 
00348 
00349 ///////////////////////////////////////////////////////
00350 //  CArg_InputFile::
00351 
00352 void CArg_InputFile::x_Open(void) const
00353 {
00354     if ( m_InputFile )
00355         return;
00356 
00357     if (AsString() == "-") {
00358 #if defined(NCBI_OS_MSWIN)
00359         if ((m_OpenMode & IOS_BASE::binary) != 0)
00360             setmode(fileno(stdin), O_BINARY);
00361 #endif
00362         m_InputFile  = &cin;
00363         m_DeleteFlag = false;
00364     } else if ( !AsString().empty() ) {
00365         m_InputFile  = new CNcbiIfstream(AsString().c_str(),
00366                                          IOS_BASE::in | m_OpenMode);
00367         if (!m_InputFile  ||  !*m_InputFile) {
00368             delete m_InputFile;
00369             m_InputFile = 0;
00370         } else {
00371             m_DeleteFlag = true;
00372         }
00373     }
00374 
00375     if ( !m_InputFile ) {
00376         NCBI_THROW(CArgException,eNoFile, s_ArgExptMsg(GetName(),
00377             "File is not accessible",AsString()));
00378     }
00379 }
00380 
00381 
00382 CArg_InputFile::CArg_InputFile(const string& name, const string& value,
00383                                IOS_BASE::openmode openmode,
00384                                bool               delay_open)
00385 : CArg_String(name, value),
00386   m_OpenMode(openmode),
00387   m_InputFile(0),
00388   m_DeleteFlag(true)
00389 {
00390     if ( !delay_open )
00391         x_Open();
00392 }
00393 
00394 
00395 CArg_InputFile::~CArg_InputFile(void)
00396 {
00397     if (m_InputFile  &&  m_DeleteFlag)
00398         delete m_InputFile;
00399 }
00400 
00401 
00402 CNcbiIstream& CArg_InputFile::AsInputFile(void) const
00403 {
00404     x_Open();
00405     return *m_InputFile;
00406 }
00407 
00408 
00409 void CArg_InputFile::CloseFile(void) const
00410 {
00411     if ( !m_InputFile ) {
00412         ERR_POST_X(20, Warning
00413                        << s_ArgExptMsg(GetName(),
00414                                  "CArg_InputFile::CloseFile:  Unopened file",
00415                                  AsString()));
00416         return;
00417     }
00418 
00419     if ( m_DeleteFlag ) {
00420         delete m_InputFile;
00421         m_InputFile = 0;
00422     }
00423 }
00424 
00425 
00426 
00427 ///////////////////////////////////////////////////////
00428 //  CArg_OutputFile::
00429 
00430 void CArg_OutputFile::x_Open(void) const
00431 {
00432     if ( m_OutputFile )
00433         return;
00434 
00435     if (AsString() == "-") {
00436 #if defined(NCBI_OS_MSWIN)
00437         if ((m_OpenMode & IOS_BASE::binary) != 0)
00438             setmode(fileno(stdout), O_BINARY);
00439 #endif
00440         m_OutputFile = &cout;
00441         m_DeleteFlag = false;
00442     } else if ( !AsString().empty() ) {
00443         m_OutputFile = new CNcbiOfstream(AsString().c_str(),
00444                                          IOS_BASE::out | m_OpenMode);
00445         if (!m_OutputFile  ||  !*m_OutputFile) {
00446             delete m_OutputFile;
00447             m_OutputFile = 0;
00448         } else {
00449             m_DeleteFlag = true;
00450         }
00451     }
00452 
00453     if ( !m_OutputFile ) {
00454         NCBI_THROW(CArgException,eNoFile, s_ArgExptMsg(GetName(),
00455             "File is not accessible",AsString()));
00456     }
00457 }
00458 
00459 
00460 CArg_OutputFile::CArg_OutputFile(const string& name, const string& value,
00461                                  IOS_BASE::openmode openmode,
00462                                  bool               delay_open)
00463     : CArg_String(name, value),
00464       m_OpenMode(openmode),
00465       m_OutputFile(0),
00466       m_DeleteFlag(true)
00467 {
00468     if ( !delay_open )
00469         x_Open();
00470 }
00471 
00472 
00473 CArg_OutputFile::~CArg_OutputFile(void)
00474 {
00475     if (m_OutputFile  &&  m_DeleteFlag)
00476         delete m_OutputFile;
00477 }
00478 
00479 
00480 CNcbiOstream& CArg_OutputFile::AsOutputFile(void) const
00481 {
00482     x_Open();
00483     return *m_OutputFile;
00484 }
00485 
00486 
00487 void CArg_OutputFile::CloseFile(void) const
00488 {
00489     if ( !m_OutputFile ) {
00490         ERR_POST_X(21, Warning << s_ArgExptMsg( GetName(),
00491             "CArg_InputFile::CloseFile: File was not opened", AsString()));
00492         return;
00493     }
00494 
00495     if ( m_DeleteFlag ) {
00496         delete m_OutputFile;
00497         m_OutputFile = 0;
00498     }
00499 }
00500 
00501 
00502 /////////////////////////////////////////////////////////////////////////////
00503 //  Aux.functions to figure out various arg. features
00504 //
00505 //    s_IsPositional(arg)
00506 //    s_IsOptional(arg)
00507 //    s_IsFlag(arg)
00508 //
00509 
00510 class CArgDesc;
00511 
00512 inline bool s_IsKey(const CArgDesc& arg)
00513 {
00514     return (dynamic_cast<const CArgDescSynopsis*> (&arg) != 0);
00515 }
00516 
00517 
00518 inline bool s_IsPositional(const CArgDesc& arg)
00519 {
00520     return dynamic_cast<const CArgDesc_Pos*> (&arg) &&  !s_IsKey(arg);
00521 }
00522 
00523 
00524 inline bool s_IsOptional(const CArgDesc& arg)
00525 {
00526     return (dynamic_cast<const CArgDescOptional*> (&arg) != 0);
00527 }
00528 
00529 
00530 inline bool s_IsFlag(const CArgDesc& arg)
00531 {
00532     return (dynamic_cast<const CArgDesc_Flag*> (&arg) != 0);
00533 }
00534 
00535 
00536 inline bool s_IsAlias(const CArgDesc& arg)
00537 {
00538     return (dynamic_cast<const CArgDesc_Alias*> (&arg) != 0);
00539 }
00540 
00541 
00542 /////////////////////////////////////////////////////////////////////////////
00543 //  CArgDesc***::   abstract base classes for argument descriptions
00544 //
00545 //    CArgDesc
00546 //
00547 //    CArgDescMandatory  : CArgDesc
00548 //    CArgDescOptional   : virtual CArgDescMandatory
00549 //    CArgDescDefault    : virtual CArgDescOptional
00550 //
00551 //    CArgDescSynopsis
00552 //
00553 
00554 
00555 ///////////////////////////////////////////////////////
00556 //  CArgDesc::
00557 
00558 CArgDesc::CArgDesc(const string& name, const string& comment)
00559     : m_Name(name), m_Comment(comment)
00560 {
00561     if ( !CArgDescriptions::VerifyName(m_Name) ) {
00562         NCBI_THROW(CArgException,eInvalidArg,
00563             "Invalid argument name: " + m_Name);
00564     }
00565 }
00566 
00567 
00568 CArgDesc::~CArgDesc(void)
00569 {
00570     return;
00571 }
00572 
00573 
00574 void CArgDesc::VerifyDefault(void) const
00575 {
00576     return;
00577 }
00578 
00579 
00580 void CArgDesc::SetConstraint(CArgAllow*                          constraint,
00581                              CArgDescriptions::EConstraintNegate)
00582 {
00583     NCBI_THROW(CArgException, eConstraint, s_ArgExptMsg(GetName(),
00584         "No-value arguments may not be constrained",
00585         constraint ? constraint->GetUsage() : kEmptyStr));
00586 }
00587 
00588 
00589 const CArgAllow* CArgDesc::GetConstraint(void) const
00590 {
00591     return 0;
00592 }
00593 
00594 
00595 string CArgDesc::GetUsageConstraint(void) const
00596 {
00597     const CArgAllow* constraint = GetConstraint();
00598     if (!constraint)
00599         return kEmptyStr;
00600     string usage;
00601     if (IsConstraintInverted()) {
00602         usage = " NOT ";
00603     }
00604     usage += constraint->GetUsage();
00605     return usage;
00606 }
00607 
00608 
00609 //  Overload the comparison operator -- to handle "AutoPtr<CArgDesc>" elements
00610 //  in "CArgs::m_Args" stored as "set< AutoPtr<CArgDesc> >"
00611 //
00612 inline bool operator< (const AutoPtr<CArgDesc>& x, const AutoPtr<CArgDesc>& y)
00613 {
00614     return x->GetName() < y->GetName();
00615 }
00616 
00617 string CArgDesc::PrintXml(CNcbiOstream& out) const
00618 // note: I open 'role' tag, but do not close it here
00619 {
00620     string role;
00621     if (s_IsKey(*this)) {
00622         role = "key";
00623     } else if (s_IsPositional(*this)) {
00624         role = GetName().empty() ? "extra" : "positional";
00625     } else if (s_IsFlag(*this)) {
00626         role = "flag";
00627     } else {
00628         role = "UNKNOWN";
00629     }
00630 
00631 // name
00632     out << "<" << role << " name=\"";
00633     string name = CStringUTF8(GetName(),eEncoding_Unknown);
00634     s_WriteEscapedStr(out,name.c_str());
00635     out  << "\"";
00636 // type
00637     const CArgDescMandatory* am =
00638         dynamic_cast<const CArgDescMandatory*>(this);
00639     if (am) {
00640         out << " type=\"" << CArgDescriptions::GetTypeName(am->GetType()) << "\"";
00641     }
00642 // use (Flags are always optional)
00643     if (s_IsOptional(*this) || s_IsFlag(*this)) {
00644         out << " optional=\"true\"";
00645     }
00646     out << ">" << endl;
00647 
00648     s_WriteXmlLine(         out, "description", GetComment());
00649     size_t group = GetGroup();
00650     if (group != 0) {
00651         s_WriteXmlLine(     out, "group", NStr::UIntToString(group));
00652     }
00653     const CArgDescSynopsis* syn = 
00654         dynamic_cast<const CArgDescSynopsis*>(this);
00655     if (syn && !syn->GetSynopsis().empty()) {
00656         s_WriteXmlLine( out, "synopsis", syn->GetSynopsis());
00657     }
00658 
00659 // constraint
00660     string constraint = CStringUTF8(GetUsageConstraint(),eEncoding_Unknown);
00661     if (!constraint.empty()) {
00662         out << "<" << "constraint";
00663         if (IsConstraintInverted()) {
00664             out << " inverted=\"true\"";
00665         }
00666         out << ">" << endl;
00667         s_WriteXmlLine( out, "description", constraint.c_str());
00668         GetConstraint()->PrintUsageXml(out);
00669         out << "</" << "constraint" << ">" << endl;
00670     }
00671 
00672 // flags
00673     CArgDescriptions::TFlags flags = GetFlags();
00674     if (flags != 0) {
00675         out << "<" << "flags" << ">";
00676         if (flags & CArgDescriptions::fPreOpen) {
00677             out << "<" << "preOpen" << "/>";
00678         }
00679         if (flags & CArgDescriptions::fBinary) {
00680             out << "<" << "binary" << "/>";
00681         }
00682         if (flags & CArgDescriptions::fAppend) {
00683             out << "<" << "append" << "/>";
00684         }
00685         if (flags & CArgDescriptions::fAllowMultiple) {
00686             out << "<" << "allowMultiple" << "/>";
00687         }
00688         if (flags & CArgDescriptions::fIgnoreInvalidValue) {
00689             out << "<" << "ignoreInvalidValue" << "/>";
00690         }
00691         if (flags & CArgDescriptions::fWarnOnInvalidValue) {
00692             out << "<" << "warnOnInvalidValue" << "/>";
00693         }
00694         if (flags & CArgDescriptions::fOptionalSeparator) {
00695             out << "<" << "optionalSeparator" << "/>";
00696         }
00697         out << "</" << "flags" << ">" << endl;
00698     }
00699     const CArgDescDefault* def = dynamic_cast<const CArgDescDefault*>(this);
00700     if (def) {
00701         s_WriteXmlLine(     out, "default", def->GetDefaultValue());
00702     } else if (s_IsFlag(*this)) {
00703         const CArgDesc_Flag* fl = dynamic_cast<const CArgDesc_Flag*>(this);
00704         if (fl && !fl->GetSetValue()) {
00705             s_WriteXmlLine( out, "setvalue", "false");
00706         }
00707     }
00708     return role;
00709 }
00710 
00711 
00712 ///////////////////////////////////////////////////////
00713 //  CArgDescMandatory::
00714 
00715 CArgDescMandatory::CArgDescMandatory(const string&            name,
00716                                      const string&            comment,
00717                                      CArgDescriptions::EType  type,
00718                                      CArgDescriptions::TFlags flags)
00719     : CArgDesc(name, comment),
00720       m_Type(type), m_Flags(flags),
00721       m_NegateConstraint(CArgDescriptions::eConstraint)
00722 {
00723     // verify if "flags" "type" are matching
00724     switch ( type ) {
00725     case CArgDescriptions::eBoolean:
00726     case CArgDescriptions::eOutputFile:
00727         return;
00728     case CArgDescriptions::eInputFile:
00729         if((flags &
00730             (CArgDescriptions::fAllowMultiple | CArgDescriptions::fAppend)) == 0)
00731             return;
00732         break;
00733     case CArgDescriptions::k_EType_Size:
00734         _TROUBLE;
00735         NCBI_THROW(CArgException, eArgType, s_ArgExptMsg(GetName(),
00736             "Invalid argument type", "k_EType_Size"));
00737         /*NOTREACHED*/
00738         break;
00739     default:
00740         if ( (flags & CArgDescriptions::fFileFlags) == 0 )
00741             return;
00742     }
00743 
00744     NCBI_THROW(CArgException, eArgType,
00745                s_ArgExptMsg(GetName(),
00746                             "Argument type/flags mismatch",
00747                             string("(type=") +
00748                             CArgDescriptions::GetTypeName(type) +
00749                             ", flags=" + NStr::UIntToString(flags) + ")"));
00750 }
00751 
00752 
00753 CArgDescMandatory::~CArgDescMandatory(void)
00754 {
00755     return;
00756 }
00757 
00758 
00759 string CArgDescMandatory::GetUsageCommentAttr(void) const
00760 {
00761     // Print type name
00762     string str = CArgDescriptions::GetTypeName(GetType());
00763 
00764     // Print constraint info, if any
00765     string constr = GetUsageConstraint();
00766     if ( !constr.empty() ) {
00767         str += ", ";
00768         str += constr;
00769     }
00770     return str;
00771 }
00772 
00773 
00774 CArgValue* CArgDescMandatory::ProcessArgument(const string& value) const
00775 {
00776     // Process according to the argument type
00777     CRef<CArgValue> arg_value;
00778     switch ( GetType() ) {
00779     case CArgDescriptions::eString:
00780         arg_value = new CArg_String(GetName(), value);
00781         break;
00782     case CArgDescriptions::eBoolean:
00783         arg_value = new CArg_Boolean(GetName(), value);
00784         break;
00785     case CArgDescriptions::eInt8:
00786         arg_value = new CArg_Int8(GetName(), value);
00787         break;
00788     case CArgDescriptions::eInteger:
00789         arg_value = new CArg_Integer(GetName(), value);
00790         break;
00791     case CArgDescriptions::eDouble:
00792         arg_value = new CArg_Double(GetName(), value);
00793         break;
00794     case CArgDescriptions::eInputFile: {
00795         bool delay_open = (GetFlags() & CArgDescriptions::fPreOpen) == 0;
00796         IOS_BASE::openmode openmode = (IOS_BASE::openmode) 0;
00797         if (GetFlags() & CArgDescriptions::fBinary)
00798             openmode |= IOS_BASE::binary;
00799         arg_value = new CArg_InputFile(GetName(), value, openmode, delay_open);
00800         break;
00801     }
00802     case CArgDescriptions::eOutputFile: {
00803         bool delay_open = (GetFlags() & CArgDescriptions::fPreOpen) == 0;
00804         IOS_BASE::openmode openmode = (IOS_BASE::openmode) 0;
00805         if (GetFlags() & CArgDescriptions::fBinary)
00806             openmode |= IOS_BASE::binary;
00807         if (GetFlags() & CArgDescriptions::fAppend)
00808             openmode |= IOS_BASE::app;
00809         arg_value = new CArg_OutputFile(GetName(), value, openmode,delay_open);
00810         break;
00811     }
00812     case CArgDescriptions::k_EType_Size: {
00813         _TROUBLE;
00814         NCBI_THROW(CArgException, eArgType, s_ArgExptMsg(GetName(),
00815             "Unknown argument type", NStr::IntToString((int)GetType())));
00816     }
00817     } /* switch GetType() */
00818 
00819 
00820     // Check against additional (user-defined) constraints, if any imposed
00821     if ( m_Constraint ) {
00822         bool err = false;
00823         try {
00824             bool check = m_Constraint->Verify(value);
00825             if (m_NegateConstraint == CArgDescriptions::eConstraintInvert) {
00826                 err = check;
00827             } else {
00828                 err = !check;
00829             }
00830 
00831         } catch (...) {
00832             err = true;
00833         }
00834 
00835         if (err) {
00836             string err_msg;
00837             if (m_NegateConstraint == CArgDescriptions::eConstraintInvert) {
00838                 err_msg = "Illegal value, unexpected ";
00839             } else {
00840                 err_msg = "Illegal value, expected ";
00841             }
00842             NCBI_THROW(CArgException, eConstraint, s_ArgExptMsg(GetName(),
00843                        err_msg + m_Constraint->GetUsage(),value));
00844         }
00845     }
00846 
00847     return arg_value.Release();
00848 }
00849 
00850 
00851 CArgValue* CArgDescMandatory::ProcessDefault(void) const
00852 {
00853     NCBI_THROW(CArgException, eNoArg,
00854                s_ArgExptMsg(GetName(), "Mandatory value is missing",
00855                             GetUsageCommentAttr()));
00856 }
00857 
00858 
00859 void CArgDescMandatory::SetConstraint
00860 (CArgAllow*                          constraint,
00861  CArgDescriptions::EConstraintNegate negate)
00862 {
00863     m_Constraint       = constraint;
00864     m_NegateConstraint = negate;
00865 }
00866 
00867 
00868 const CArgAllow* CArgDescMandatory::GetConstraint(void) const
00869 {
00870     return m_Constraint;
00871 }
00872 
00873 
00874 bool CArgDescMandatory::IsConstraintInverted() const
00875 {
00876     return m_NegateConstraint == CArgDescriptions::eConstraintInvert;
00877 }
00878 
00879 
00880 ///////////////////////////////////////////////////////
00881 //  CArgDescOptional::
00882 
00883 
00884 CArgDescOptional::CArgDescOptional(const string&            name,
00885                                    const string&            comment,
00886                                    CArgDescriptions::EType  type,
00887                                    CArgDescriptions::TFlags flags)
00888     : CArgDescMandatory(name, comment, type, flags),
00889       m_Group(0)
00890 {
00891     return;
00892 }
00893 
00894 
00895 CArgDescOptional::~CArgDescOptional(void)
00896 {
00897     return;
00898 }
00899 
00900 
00901 CArgValue* CArgDescOptional::ProcessDefault(void) const
00902 {
00903     return new CArg_NoValue(GetName());
00904 }
00905 
00906 
00907 
00908 
00909 ///////////////////////////////////////////////////////
00910 //  CArgDescDefault::
00911 
00912 
00913 CArgDescDefault::CArgDescDefault(const string&            name,
00914                                  const string&            comment,
00915                                  CArgDescriptions::EType  type,
00916                                  CArgDescriptions::TFlags flags,
00917                                  const string&            default_value,
00918                                  const string&            env_var)
00919     : CArgDescMandatory(name, comment, type, flags),
00920       CArgDescOptional(name, comment, type, flags),
00921       m_DefaultValue(default_value), m_EnvVar(env_var)
00922 {
00923     return;
00924 }
00925 
00926 
00927 CArgDescDefault::~CArgDescDefault(void)
00928 {
00929     return;
00930 }
00931 
00932 const string& CArgDescDefault::GetDefaultValue(void) const
00933 {
00934     if (!m_EnvVar.empty() && CNcbiApplication::Instance()) {
00935         const string& value =
00936             CNcbiApplication::Instance()->GetEnvironment().Get(m_EnvVar);
00937         if (!value.empty()) {
00938             return value;
00939         }
00940     }
00941     return m_DefaultValue;
00942 }
00943 
00944 CArgValue* CArgDescDefault::ProcessDefault(void) const
00945 {
00946     return ProcessArgument(GetDefaultValue());
00947 }
00948 
00949 
00950 void CArgDescDefault::VerifyDefault(void) const
00951 {
00952     if (GetType() == CArgDescriptions::eInputFile  ||
00953         GetType() == CArgDescriptions::eOutputFile) {
00954         return;
00955     }
00956 
00957     // Process, then immediately delete
00958     CRef<CArgValue> arg_value(ProcessArgument(GetDefaultValue()));
00959 }
00960 
00961 
00962 ///////////////////////////////////////////////////////
00963 //  CArgDescSynopsis::
00964 
00965 
00966 CArgDescSynopsis::CArgDescSynopsis(const string& synopsis)
00967     : m_Synopsis(synopsis)
00968 {
00969     for (string::const_iterator it = m_Synopsis.begin();
00970          it != m_Synopsis.end();  ++it) {
00971         if (*it != '_'  &&  !isalnum((unsigned char)(*it))) {
00972             NCBI_THROW(CArgException,eSynopsis,
00973                 "Argument synopsis must be alphanumeric: "+ m_Synopsis);
00974         }
00975     }
00976 }
00977 
00978 
00979 
00980 /////////////////////////////////////////////////////////////////////////////
00981 //  CArgDesc_***::   classes for argument descriptions
00982 //    CArgDesc_Flag    : CArgDesc
00983 //
00984 //    CArgDesc_Key     : virtual CArgDescMandatory
00985 //    CArgDesc_KeyOpt  : CArgDesc_Key, virtual CArgDescOptional
00986 //    CArgDesc_KeyDef  : CArgDesc_Key, CArgDescDefault
00987 //
00988 //    CArgDesc_Pos     : virtual CArgDescMandatory
00989 //    CArgDesc_PosOpt  : CArgDesc_Pos, virtual CArgDescOptional
00990 //    CArgDesc_PosDef  : CArgDesc_Pos, CArgDescDefault
00991 //
00992 
00993 
00994 ///////////////////////////////////////////////////////
00995 //  CArgDesc_Flag::
00996 
00997 
00998 CArgDesc_Flag::CArgDesc_Flag(const string& name,
00999                              const string& comment,
01000                              bool  set_value)
01001     : CArgDesc(name, comment),
01002       m_Group(0),
01003       m_SetValue(set_value)
01004 {
01005     return;
01006 }
01007 
01008 
01009 CArgDesc_Flag::~CArgDesc_Flag(void)
01010 {
01011     return;
01012 }
01013 
01014 
01015 string CArgDesc_Flag::GetUsageSynopsis(bool /*name_only*/) const
01016 {
01017     return "-" + GetName();
01018 }
01019 
01020 
01021 string CArgDesc_Flag::GetUsageCommentAttr(void) const
01022 {
01023     return kEmptyStr;
01024 }
01025 
01026 
01027 CArgValue* CArgDesc_Flag::ProcessArgument(const string& /*value*/) const
01028 {
01029     if ( m_SetValue ) {
01030         return new CArg_Boolean(GetName(), true);
01031     } else {
01032         return new CArg_NoValue(GetName());
01033     }
01034 }
01035 
01036 
01037 CArgValue* CArgDesc_Flag::ProcessDefault(void) const
01038 {
01039     if ( m_SetValue ) {
01040         return new CArg_NoValue(GetName());
01041     } else {
01042         return new CArg_Boolean(GetName(), true);
01043     }
01044 }
01045 
01046 
01047 
01048 ///////////////////////////////////////////////////////
01049 //  CArgDesc_Pos::
01050 
01051 
01052 CArgDesc_Pos::CArgDesc_Pos(const string&            name,
01053                            const string&            comment,
01054                            CArgDescriptions::EType  type,
01055                            CArgDescriptions::TFlags flags)
01056     : CArgDescMandatory(name, comment, type, flags)
01057 {
01058     return;
01059 }
01060 
01061 
01062 CArgDesc_Pos::~CArgDesc_Pos(void)
01063 {
01064     return;
01065 }
01066 
01067 
01068 string CArgDesc_Pos::GetUsageSynopsis(bool /*name_only*/) const
01069 {
01070     return GetName().empty() ? s_ExtraName : GetName();
01071 }
01072 
01073 
01074 
01075 ///////////////////////////////////////////////////////
01076 //  CArgDesc_PosOpt::
01077 
01078 
01079 CArgDesc_PosOpt::CArgDesc_PosOpt(const string&            name,
01080                                  const string&            comment,
01081                                  CArgDescriptions::EType  type,
01082                                  CArgDescriptions::TFlags flags)
01083     : CArgDescMandatory (name, comment, type, flags),
01084       CArgDescOptional  (name, comment, type, flags),
01085       CArgDesc_Pos      (name, comment, type, flags)
01086 {
01087     return;
01088 }
01089 
01090 
01091 CArgDesc_PosOpt::~CArgDesc_PosOpt(void)
01092 {
01093     return;
01094 }
01095 
01096 
01097 
01098 ///////////////////////////////////////////////////////
01099 //  CArgDesc_PosDef::
01100 
01101 
01102 CArgDesc_PosDef::CArgDesc_PosDef(const string&            name,
01103                                  const string&            comment,
01104                                  CArgDescriptions::EType  type,
01105                                  CArgDescriptions::TFlags flags,
01106                                  const string&            default_value,
01107                                  const string&            env_var)
01108     : CArgDescMandatory (name, comment, type, flags),
01109       CArgDescOptional  (name, comment, type, flags),
01110       CArgDescDefault   (name, comment, type, flags, default_value, env_var),
01111       CArgDesc_PosOpt   (name, comment, type, flags)
01112 {
01113     return;
01114 }
01115 
01116 
01117 CArgDesc_PosDef::~CArgDesc_PosDef(void)
01118 {
01119     return;
01120 }
01121 
01122 
01123 
01124 ///////////////////////////////////////////////////////
01125 //  CArgDesc_Key::
01126 
01127 
01128 CArgDesc_Key::CArgDesc_Key(const string&            name,
01129                            const string&            comment,
01130                            CArgDescriptions::EType  type,
01131                            CArgDescriptions::TFlags flags,
01132                            const string&            synopsis)
01133     : CArgDescMandatory(name, comment, type, flags),
01134       CArgDesc_Pos     (name, comment, type, flags),
01135       CArgDescSynopsis(synopsis)
01136 {
01137     return;
01138 }
01139 
01140 
01141 CArgDesc_Key::~CArgDesc_Key(void)
01142 {
01143     return;
01144 }
01145 
01146 
01147 inline string s_KeyUsageSynopsis(const string& name, const string& synopsis,
01148                                  bool name_only)
01149 {
01150     if ( name_only ) {
01151         return '-' + name;
01152     } else {
01153         return '-' + name + ' ' + synopsis;
01154     }
01155 }
01156 
01157 
01158 string CArgDesc_Key::GetUsageSynopsis(bool name_only) const
01159 {
01160     return s_KeyUsageSynopsis(GetName(), GetSynopsis(), name_only);
01161 }
01162 
01163 
01164 
01165 ///////////////////////////////////////////////////////
01166 //  CArgDesc_KeyOpt::
01167 
01168 
01169 CArgDesc_KeyOpt::CArgDesc_KeyOpt(const string&            name,
01170                                  const string&            comment,
01171                                  CArgDescriptions::EType  type,
01172                                  CArgDescriptions::TFlags flags,
01173                                  const string&            synopsis)
01174     : CArgDescMandatory(name, comment, type, flags),
01175       CArgDescOptional (name, comment, type, flags),
01176       CArgDesc_PosOpt  (name, comment, type, flags),
01177       CArgDescSynopsis(synopsis)
01178 {
01179     return;
01180 }
01181 
01182 
01183 CArgDesc_KeyOpt::~CArgDesc_KeyOpt(void)
01184 {
01185     return;
01186 }
01187 
01188 
01189 string CArgDesc_KeyOpt::GetUsageSynopsis(bool name_only) const
01190 {
01191     return s_KeyUsageSynopsis(GetName(), GetSynopsis(), name_only);
01192 }
01193 
01194 
01195 
01196 ///////////////////////////////////////////////////////
01197 //  CArgDesc_KeyDef::
01198 
01199 
01200 CArgDesc_KeyDef::CArgDesc_KeyDef(const string&            name,
01201                                  const string&            comment,
01202                                  CArgDescriptions::EType  type,
01203                                  CArgDescriptions::TFlags flags,
01204                                  const string&            synopsis,
01205                                  const string&            default_value,
01206                                  const string&            env_var)
01207     : CArgDescMandatory(name, comment, type, flags),
01208       CArgDescOptional (name, comment, type, flags),
01209       CArgDesc_PosDef  (name, comment, type, flags, default_value, env_var),
01210       CArgDescSynopsis(synopsis)
01211 {
01212     return;
01213 }
01214 
01215 
01216 CArgDesc_KeyDef::~CArgDesc_KeyDef(void)
01217 {
01218     return;
01219 }
01220 
01221 
01222 string CArgDesc_KeyDef::GetUsageSynopsis(bool name_only) const
01223 {
01224     return s_KeyUsageSynopsis(GetName(), GetSynopsis(), name_only);
01225 }
01226 
01227 
01228 ///////////////////////////////////////////////////////
01229 //  CArgDesc_Alias::
01230 
01231 CArgDesc_Alias::CArgDesc_Alias(const string& alias,
01232                                const string& arg_name,
01233                                const string& comment)
01234     : CArgDesc(alias, comment),
01235       m_ArgName(arg_name),
01236       m_NegativeFlag(false)
01237 {
01238 }
01239 
01240 
01241 CArgDesc_Alias::~CArgDesc_Alias(void)
01242 {
01243 }
01244 
01245 
01246 const string& CArgDesc_Alias::GetAliasedName(void) const
01247 {
01248     return m_ArgName;
01249 }
01250 
01251 
01252 string CArgDesc_Alias::GetUsageSynopsis(bool /*name_only*/) const
01253 {
01254     return kEmptyStr;
01255 }
01256 
01257 
01258 string CArgDesc_Alias::GetUsageCommentAttr(void) const
01259 {
01260     return kEmptyStr;
01261 }
01262 
01263     
01264 CArgValue* CArgDesc_Alias::ProcessArgument(const string& /*value*/) const
01265 {
01266     return new CArg_NoValue(GetName());
01267 }
01268 
01269 
01270 CArgValue* CArgDesc_Alias::ProcessDefault(void) const
01271 {
01272     return new CArg_NoValue(GetName());
01273 }
01274 
01275 
01276 /////////////////////////////////////////////////////////////////////////////
01277 //  CArgs::
01278 //
01279 
01280 
01281 CArgs::CArgs(void)
01282 {
01283     m_nExtra = 0;
01284 }
01285 
01286 
01287 CArgs::~CArgs(void)
01288 {
01289     return;
01290 }
01291 
01292 
01293 static string s_ComposeNameExtra(size_t idx)
01294 {
01295     return '#' + NStr::UInt8ToString(idx);
01296 }
01297 
01298 
01299 inline bool s_IsArgNameChar(char c)
01300 {
01301     return isalnum(c)  ||  c == '_'  ||  c == '-';
01302 }
01303 
01304 
01305 CArgs::TArgsCI CArgs::x_Find(const string& name) const
01306 {
01307     CArgs::TArgsCI arg = m_Args.find(CRef<CArgValue> (new CArg_NoValue(name)));
01308     if (arg != m_Args.end() || name.empty() || name[0] == '-'  ||
01309         !s_IsArgNameChar(name[0])) {
01310         return arg;
01311     }
01312     return m_Args.find(CRef<CArgValue> (new CArg_NoValue("-" + name)));
01313 }
01314 
01315 CArgs::TArgsI CArgs::x_Find(const string& name)
01316 {
01317     CArgs::TArgsI arg = m_Args.find(CRef<CArgValue> (new CArg_NoValue(name)));
01318     if (arg != m_Args.end() || name.empty() || name[0] == '-'  ||
01319         !s_IsArgNameChar(name[0])) {
01320         return arg;
01321     }
01322     return m_Args.find(CRef<CArgValue> (new CArg_NoValue("-" + name)));
01323 }
01324 
01325 
01326 bool CArgs::Exist(const string& name) const
01327 {
01328     return (x_Find(name) != m_Args.end());
01329 }
01330 
01331 
01332 const CArgValue& CArgs::operator[] (const string& name) const
01333 {
01334     TArgsCI arg = x_Find(name);
01335     if (arg == m_Args.end()) {
01336         // Special diagnostics for "extra" args
01337         if (!name.empty()  &&  name[0] == '#') {
01338             size_t idx;
01339             try {
01340                 idx = NStr::StringToUInt(name.c_str() + 1);
01341             } catch (...) {
01342                 idx = kMax_UInt;
01343             }
01344             if (idx == kMax_UInt) {
01345                 NCBI_THROW(CArgException, eInvalidArg,
01346                            "Asked for an argument with invalid name: \"" +
01347                            name + "\"");
01348             }
01349             if (m_nExtra == 0) {
01350                 NCBI_THROW(CArgException, eInvalidArg,
01351                            "No \"extra\" (unnamed positional) arguments "
01352                            "provided, cannot Get: " + s_ComposeNameExtra(idx));
01353             }
01354             if (idx == 0  ||  idx >= m_nExtra) {
01355                 NCBI_THROW(CArgException, eInvalidArg,
01356                            "\"Extra\" (unnamed positional) arg is "
01357                            "out-of-range (#1.." + s_ComposeNameExtra(m_nExtra)
01358                            + "): " + s_ComposeNameExtra(idx));
01359             }
01360         }
01361 
01362         // Diagnostics for all other argument classes
01363         NCBI_THROW(CArgException, eInvalidArg,
01364                    "Unknown argument requested: \"" + name + "\"");
01365     }
01366 
01367     // Found arg with name "name"
01368     return **arg;
01369 }
01370 
01371 
01372 const CArgValue& CArgs::operator[] (size_t idx) const
01373 {
01374     return (*this)[s_ComposeNameExtra(idx)];
01375 }
01376 
01377 vector< CRef<CArgValue> > CArgs::GetAll(void) const
01378 {
01379     vector< CRef<CArgValue> > res;
01380     ITERATE( TArgs, a, m_Args) {
01381         if ((**a).HasValue()) {
01382             res.push_back( *a );
01383         }
01384     }
01385     return res;
01386 }
01387 
01388 
01389 string& CArgs::Print(string& str) const
01390 {
01391     for (TArgsCI arg = m_Args.begin();  arg != m_Args.end();  ++arg) {
01392         // Arg. name
01393         const string& arg_name = (*arg)->GetName();
01394         str += arg_name;
01395 
01396         // Arg. value, if any
01397         const CArgValue& arg_value = (*this)[arg_name];
01398         if ( arg_value ) {
01399             str += " = `";
01400             string tmp;
01401             try {
01402                 tmp = NStr::Join( arg_value.GetStringList(), " "); 
01403             } catch (...) {
01404                 tmp = arg_value.AsString();
01405             }
01406             str += tmp;
01407             str += "'\n";
01408         } else {
01409             str += ":  <not assigned>\n";
01410         }
01411     }
01412     return str;
01413 }
01414 
01415 
01416 void CArgs::Remove(const string& name)
01417 {
01418     CArgs::TArgsI it =  m_Args.find(CRef<CArgValue> (new CArg_NoValue(name)));
01419     m_Args.erase(it);
01420 }
01421 
01422 
01423 void CArgs::Reset(void)
01424 {
01425     m_nExtra = 0;
01426     m_Args.clear();
01427 }
01428 
01429 
01430 void CArgs::Add(CArgValue* arg, bool update, bool add_value)
01431 {
01432     // special case:  add an "extra" arg (generate virtual name for it)
01433     bool is_extra = false;
01434     if ( arg->GetName().empty() ) {
01435         arg->m_Name = s_ComposeNameExtra(m_nExtra + 1);
01436         is_extra = true;
01437     }
01438 
01439     // check-up
01440     _ASSERT(CArgDescriptions::VerifyName(arg->GetName(), true));
01441     CArgs::TArgsI arg_it = x_Find(arg->GetName());
01442     if ( arg_it !=  m_Args.end()) {
01443         if (update) {
01444             Remove(arg->GetName());
01445         } else {
01446             if (add_value) {
01447                 const string& v = arg->AsString();
01448                 CRef<CArgValue> av = *arg_it;
01449                 av->SetStringList().push_back(v);
01450             } else {
01451                 NCBI_THROW(CArgException,eSynopsis,
01452                    "Argument with this name is defined already: " 
01453                    + arg->GetName());
01454             }
01455         }
01456     }
01457 
01458     // add
01459     m_Args.insert(CRef<CArgValue>(arg));
01460 
01461     if ( is_extra ) {
01462         m_nExtra++;
01463     }
01464 }
01465 
01466 
01467 bool CArgs::IsEmpty(void) const
01468 {
01469     return m_Args.empty();
01470 }
01471 
01472 
01473 ///////////////////////////////////////////////////////
01474 //  CArgErrorHandler::
01475 
01476 CArgValue* CArgErrorHandler::HandleError(const CArgDesc& arg_desc,
01477                                          const string& value) const
01478 {
01479     if ((arg_desc.GetFlags() & CArgDescriptions::fIgnoreInvalidValue) == 0) {
01480         // Re-process invalid value to throw the same exception
01481         arg_desc.ProcessArgument(value);
01482         // Should never get past ProcessArgument()
01483     }
01484     if ((arg_desc.GetFlags() & CArgDescriptions::fWarnOnInvalidValue) == 0) {
01485         ERR_POST_X(22, Warning << "Invalid value " << value <<
01486             " for argument " << arg_desc.GetName() <<
01487             " - argument will be ignored.");
01488     }
01489     // return 0 to ignore the argument
01490     return 0;
01491 }
01492 
01493 
01494 ///////////////////////////////////////////////////////
01495 //  CArgDescriptions::
01496 //
01497 
01498 
01499 CArgDescriptions::CArgDescriptions(bool auto_help,
01500                                    CArgErrorHandler* err_handler)
01501     : m_ArgsType(eRegularArgs),
01502       m_nExtra(0),
01503       m_nExtraOpt(0),
01504       m_CurrentGroup(0),
01505       m_PositionalMode(ePositionalMode_Strict),
01506       m_AutoHelp(auto_help),
01507       m_UsageIfNoArgs(false),
01508       m_ErrorHandler(err_handler)
01509 {
01510     if ( !m_ErrorHandler ) {
01511         // Use default error handler
01512         m_ErrorHandler.Reset(new CArgErrorHandler);
01513     }
01514 
01515     SetUsageContext("NCBI_PROGRAM", kEmptyStr);
01516     m_ArgGroups.push_back(kEmptyStr); // create default group #0
01517     if ( m_AutoHelp ) {
01518         AddFlag(s_AutoHelp,
01519                 "Print USAGE and DESCRIPTION;  ignore other arguments");
01520     }
01521     AddFlag(s_AutoHelpFull,
01522             "Print USAGE, DESCRIPTION and ARGUMENTS description;  ignore other arguments");
01523     AddFlag(s_AutoHelpXml,
01524             "Print USAGE, DESCRIPTION and ARGUMENTS description in XML format;  ignore other arguments");
01525 }
01526 
01527 
01528 CArgDescriptions::~CArgDescriptions(void)
01529 {
01530     return;
01531 }
01532 
01533 
01534 void CArgDescriptions::SetArgsType(EArgSetType args_type)
01535 {
01536     m_ArgsType = args_type;
01537 
01538     // Run args check for a CGI application
01539     if (m_ArgsType == eCgiArgs) {
01540         // Must have no named positional arguments
01541         if ( !m_PosArgs.empty() ) {
01542             NCBI_THROW(CArgException, eInvalidArg,
01543                        "CGI application cannot have positional arguments, "
01544                        "name of the offending argument: '"
01545                        + *m_PosArgs.begin() + "'.");
01546         }
01547 
01548         // Must have no flag arguments
01549         ITERATE (TArgs, it, m_Args) {
01550             const CArgDesc& arg = **it;
01551             if ( s_IsFlag(arg) ) {
01552                 const string& name = arg.GetName();
01553 
01554                 if (name == s_AutoHelp ||
01555                     name == s_AutoHelpFull ||
01556                     name == s_AutoHelpXml)  // help
01557                     continue;
01558 
01559                 NCBI_THROW(CArgException, eInvalidArg,
01560                            "CGI application cannot have flag arguments, "
01561                            "name of the offending flag: '" + name + "'.");
01562             }
01563         }
01564 
01565         // Must have no unnamed positional arguments
01566         if (m_nExtra  ||  m_nExtraOpt) {
01567             NCBI_THROW(CArgException, eInvalidArg,
01568                        "CGI application cannot have unnamed positional "
01569                        "arguments.");
01570         }
01571     }
01572 }
01573 
01574 
01575 const char* CArgDescriptions::GetTypeName(EType type)
01576 {
01577     static const char* s_TypeName[k_EType_Size] = {
01578         "String",
01579         "Boolean",
01580         "Int8",
01581         "Integer",
01582         "Real",
01583         "File_In",
01584         "File_Out"
01585     };
01586 
01587     if (type == k_EType_Size) {
01588         _TROUBLE;
01589         NCBI_THROW(CArgException, eArgType,
01590                    "Invalid argument type: k_EType_Size");
01591     }
01592     return s_TypeName[(int) type];
01593 }
01594 
01595 
01596 void CArgDescriptions::AddKey
01597 (const string& name,
01598  const string& synopsis,
01599  const string& comment,
01600  EType         type,
01601  TFlags        flags)
01602 {
01603     auto_ptr<CArgDesc_Key> arg(new CArgDesc_Key(name,
01604         comment, type, flags, synopsis));
01605 
01606     x_AddDesc(*arg);
01607     arg.release();
01608 }
01609 
01610 
01611 void CArgDescriptions::AddOptionalKey
01612 (const string& name,
01613  const string& synopsis,
01614  const string& comment,
01615  EType         type,
01616  TFlags        flags)
01617 {
01618     auto_ptr<CArgDesc_KeyOpt> arg(new CArgDesc_KeyOpt(name,
01619         comment, type, flags, synopsis));
01620 
01621     x_AddDesc(*arg);
01622     arg.release();
01623 }
01624 
01625 
01626 void CArgDescriptions::AddDefaultKey
01627 (const string& name,
01628  const string& synopsis,
01629  const string& comment,
01630  EType         type,
01631  const string& default_value,
01632  TFlags        flags,
01633  const string& env_var)
01634 {
01635     auto_ptr<CArgDesc_KeyDef> arg(new CArgDesc_KeyDef(name,
01636         comment, type, flags, synopsis, default_value, env_var));
01637 
01638     x_AddDesc(*arg);
01639     arg.release();
01640 }
01641 
01642 
01643 void CArgDescriptions::AddFlag
01644 (const string& name,
01645  const string& comment,
01646  bool          set_value)
01647 {
01648     auto_ptr<CArgDesc_Flag> arg(new CArgDesc_Flag(name, comment, set_value));
01649 
01650     x_AddDesc(*arg);
01651     arg.release();
01652 }
01653 
01654 
01655 void CArgDescriptions::AddPositional
01656 (const string& name,
01657  const string& comment,
01658  EType         type,
01659  TFlags        flags)
01660 {
01661     auto_ptr<CArgDesc_Pos> arg(new CArgDesc_Pos(name, comment, type, flags));
01662 
01663     x_AddDesc(*arg);
01664     arg.release();
01665 }
01666 
01667 
01668 void CArgDescriptions::AddOptionalPositional
01669 (const string& name,
01670  const string& comment,
01671  EType         type,
01672  TFlags        flags)
01673 {
01674     auto_ptr<CArgDesc_PosOpt> arg
01675         (new CArgDesc_PosOpt(name, comment, type, flags));
01676 
01677     x_AddDesc(*arg);
01678     arg.release();
01679 }
01680 
01681 
01682 void CArgDescriptions::AddDefaultPositional
01683 (const string& name,
01684  const string& comment,
01685  EType         type,
01686  const string& default_value,
01687  TFlags        flags,
01688  const string& env_var)
01689 {
01690     auto_ptr<CArgDesc_PosDef> arg(new CArgDesc_PosDef(name,
01691         comment, type, flags, default_value, env_var));
01692 
01693     x_AddDesc(*arg);
01694     arg.release();
01695 }
01696 
01697 
01698 void CArgDescriptions::AddExtra
01699 (unsigned      n_mandatory,
01700  unsigned      n_optional,
01701  const string& comment,
01702  EType         type,
01703  TFlags        flags)
01704 {
01705     if (!n_mandatory  &&  !n_optional) {
01706         NCBI_THROW(CArgException,eSynopsis,
01707             "Number of extra arguments cannot be zero");
01708     }
01709     if (n_mandatory > 4096) {
01710         NCBI_THROW(CArgException,eSynopsis,
01711             "Number of mandatory extra arguments is too big");
01712     }
01713 
01714     m_nExtra    = n_mandatory;
01715     m_nExtraOpt = n_optional;
01716 
01717     auto_ptr<CArgDesc_Pos> arg
01718         (m_nExtra ?
01719          new CArgDesc_Pos   (kEmptyStr, comment, type, flags) :
01720          new CArgDesc_PosOpt(kEmptyStr, comment, type, flags));
01721 
01722     x_AddDesc(*arg);
01723     arg.release();
01724 }
01725 
01726 
01727 void CArgDescriptions::AddAlias(const string& alias,
01728                                 const string& arg_name)
01729 {
01730     auto_ptr<CArgDesc_Alias> arg(
01731         new CArgDesc_Alias(alias, arg_name, kEmptyStr));
01732 
01733     x_AddDesc(*arg);
01734     arg.release();
01735 }
01736 
01737 
01738 void CArgDescriptions::AddNegatedFlagAlias(const string& alias,
01739                                            const string& arg_name,
01740                                            const string& comment)
01741 {
01742     // Make sure arg_name describes a flag
01743     TArgsCI orig = x_Find(arg_name);
01744     if (orig == m_Args.end()  ||  !s_IsFlag(**orig)) {
01745         NCBI_THROW(CArgException, eArgType,
01746             "Attempt to negate a non-flag argument: "+ arg_name);
01747     }
01748 
01749     auto_ptr<CArgDesc_Alias> arg(new CArgDesc_Alias(alias, arg_name, comment));
01750     arg->SetNegativeFlag(true);
01751 
01752     x_AddDesc(*arg);
01753     arg.release();
01754 }
01755 
01756 
01757 void CArgDescriptions::SetConstraint(const string&      name, 
01758                                      CArgAllow*         constraint,
01759                                      EConstraintNegate  negate)
01760 {
01761     CRef<CArgAllow> safe_delete(constraint);
01762 
01763     TArgsI it = x_Find(name);
01764     if (it == m_Args.end()) {
01765         NCBI_THROW(CArgException, eConstraint,
01766             "Attempt to set constraint for undescribed argument: "+ name);
01767     }
01768     (*it)->SetConstraint(constraint, negate);
01769 }
01770 
01771 
01772 void CArgDescriptions::SetDependency(const string& arg1,
01773                                      EDependency   dep,
01774                                      const string& arg2)
01775 {
01776     m_Dependencies.insert(TDependencies::value_type(arg1,
01777         SArgDependency(arg2, dep)));
01778     if (dep == eExcludes) {
01779         // Exclusions must work in both directions
01780         m_Dependencies.insert(TDependencies::value_type(arg2,
01781             SArgDependency(arg1, dep)));
01782     }
01783 }
01784 
01785 
01786 void CArgDescriptions::SetCurrentGroup(const string& group)
01787 {
01788     m_CurrentGroup = x_GetGroupIndex(group);
01789     if (m_CurrentGroup >= m_ArgGroups.size()) {
01790         m_ArgGroups.push_back(group);
01791         m_CurrentGroup = m_ArgGroups.size() - 1;
01792     }
01793 }
01794 
01795 
01796 void CArgDescriptions::SetErrorHandler(const string&      name,
01797                                        CArgErrorHandler*  err_handler)
01798 {
01799     TArgsI it = x_Find(name);
01800     if (it == m_Args.end()) {
01801         NCBI_THROW(CArgException, eInvalidArg,
01802             "Attempt to set error handler for undescribed argument: "+ name);
01803     }
01804     (*it)->SetErrorHandler(err_handler);
01805 }
01806 
01807 
01808 bool CArgDescriptions::Exist(const string& name) const
01809 {
01810     return (x_Find(name) != m_Args.end());
01811 }
01812 
01813 
01814 void CArgDescriptions::Delete(const string& name)
01815 {
01816     {{ // ...from the list of all args
01817         TArgsI it = x_Find(name);
01818         if (it == m_Args.end()) {
01819             NCBI_THROW(CArgException,eSynopsis,
01820                 "Argument description is not found");
01821         }
01822         m_Args.erase(it);
01823 
01824         // take special care of the extra args
01825         if ( name.empty() ) {
01826             m_nExtra = 0;
01827             m_nExtraOpt = 0;
01828             return;
01829         }
01830     }}
01831 
01832     {{ // ...from the list of key/flag args
01833         TKeyFlagArgs::iterator it =
01834             find(m_KeyFlagArgs.begin(), m_KeyFlagArgs.end(), name);
01835         if (it != m_KeyFlagArgs.end()) {
01836             m_KeyFlagArgs.erase(it);
01837             _ASSERT(find(m_KeyFlagArgs.begin(), m_KeyFlagArgs.end(), name) ==
01838                          m_KeyFlagArgs.end());
01839             _ASSERT(find(m_PosArgs.begin(), m_PosArgs.end(), name) ==
01840                          m_PosArgs.end());
01841             return;
01842         }
01843     }}
01844 
01845     {{ // ...from the list of positional args' positions
01846         TPosArgs::iterator it =
01847             find(m_PosArgs.begin(), m_PosArgs.end(), name);
01848         _ASSERT (it != m_PosArgs.end());
01849         m_PosArgs.erase(it);
01850         _ASSERT(find(m_PosArgs.begin(), m_PosArgs.end(), name) ==
01851                      m_PosArgs.end());
01852     }}
01853 }
01854 
01855 
01856 // Fake class to hold only a name -- to find in "m_Args"
01857 class CArgDesc_NameOnly : public CArgDesc
01858 {
01859 public:
01860     CArgDesc_NameOnly(const string& name) :
01861         CArgDesc(name, kEmptyStr) {}
01862 private:
01863     virtual string GetUsageSynopsis(bool/*name_only*/) const{return kEmptyStr;}
01864     virtual string GetUsageCommentAttr(void) const {return kEmptyStr;}
01865     virtual CArgValue* ProcessArgument(const string&) const {return 0;}
01866     virtual CArgValue* ProcessDefault(void) const {return 0;}
01867 };
01868 
01869 CArgDescriptions::TArgsCI CArgDescriptions::x_Find(const string& name,
01870                                                    bool* negative) const
01871 {
01872     CArgDescriptions::TArgsCI arg =
01873         m_Args.find(AutoPtr<CArgDesc> (new CArgDesc_NameOnly(name)));
01874     if ( arg != m_Args.end() ) {
01875         const CArgDesc_Alias* al =
01876             dynamic_cast<const CArgDesc_Alias*>(arg->get());
01877         if ( al ) {
01878             if ( negative ) {
01879                 *negative = al->GetNegativeFlag();
01880             }
01881             return x_Find(al->GetAliasedName(), negative);
01882         }
01883     }
01884     return arg;
01885 }
01886 
01887 CArgDescriptions::TArgsI CArgDescriptions::x_Find(const string& name,
01888                                                    bool* negative)
01889 {
01890     CArgDescriptions::TArgsI arg =
01891         m_Args.find(AutoPtr<CArgDesc> (new CArgDesc_NameOnly(name)));
01892     if ( arg != m_Args.end() ) {
01893         const CArgDesc_Alias* al =
01894             dynamic_cast<const CArgDesc_Alias*>(arg->get());
01895         if ( al ) {
01896             if ( negative ) {
01897                 *negative = al->GetNegativeFlag();
01898             }
01899             return x_Find(al->GetAliasedName(), negative);
01900         }
01901     }
01902     return arg;
01903 }
01904 
01905 
01906 size_t CArgDescriptions::x_GetGroupIndex(const string& group) const
01907 {
01908     if ( group.empty() ) {
01909         return 0;
01910     }
01911     for (size_t i = 1; i < m_ArgGroups.size(); ++i) {
01912         if ( NStr::EqualNocase(m_ArgGroups[i], group) ) {
01913             return i;
01914         }
01915     }
01916     return m_ArgGroups.size();
01917 }
01918 
01919 
01920 void CArgDescriptions::x_PreCheck(void) const
01921 {
01922     // Check for the consistency of positional args
01923     if ( m_nExtra ) {
01924         for (TPosArgs::const_iterator name = m_PosArgs.begin();
01925              name != m_PosArgs.end();  ++name) {
01926             TArgsCI arg_it = x_Find(*name);
01927             _ASSERT(arg_it != m_Args.end());
01928             CArgDesc& arg = **arg_it;
01929 
01930             if (dynamic_cast<const CArgDesc_PosOpt*> (&arg)) {
01931                 NCBI_THROW(CArgException, eSynopsis,
01932                     "Having both optional named and required unnamed "
01933                     "positional arguments is prohibited");
01934             }
01935         }
01936     }
01937 
01938     // Check for the validity of default values.
01939     // Also check for conflict between no-separator and regular names
01940     for (TArgsCI it = m_Args.begin();  it != m_Args.end();  ++it) {
01941         CArgDesc& arg = **it;
01942 
01943         const string& name = arg.GetName();
01944         if (name.length() > 1  &&  m_NoSeparator.find(name[0]) != NPOS) {
01945             NCBI_THROW(CArgException, eInvalidArg,
01946                 string("'") + name[0] +
01947                 "' argument allowed to contain no separator conflicts with '" +
01948                 name + "' argument");
01949         }
01950 
01951         if (dynamic_cast<CArgDescDefault*> (&arg) == 0) {
01952             continue;
01953         }
01954 
01955         try {
01956             arg.VerifyDefault();
01957             continue;
01958         } catch (CException& e) {
01959             NCBI_RETHROW(e,CArgException,eConstraint,
01960                 "Invalid default argument value");
01961         } catch (exception& e) {
01962             NCBI_THROW(CArgException, eConstraint,
01963                 string("Invalid default value: ") + e.what());
01964         }
01965     }
01966 }
01967 
01968 
01969 CArgs* CArgDescriptions::CreateArgs(const CNcbiArguments& args) const
01970 {
01971     const_cast<CArgDescriptions&>(*this).SetCurrentGroup(kEmptyStr);
01972     return CreateArgs(args.Size(), args);
01973 }
01974 
01975 
01976 void CArgDescriptions::x_CheckAutoHelp(const string& arg) const
01977 {
01978 //    _ASSERT(m_AutoHelp);
01979     if (m_AutoHelp) {
01980         if (arg.compare(string("-") + s_AutoHelp) == 0) {
01981             NCBI_THROW(CArgHelpException,eHelp,kEmptyStr);
01982         }
01983     }
01984     if (arg.compare(string("-") + s_AutoHelpFull) == 0) {
01985         NCBI_THROW(CArgHelpException,eHelpFull,kEmptyStr);
01986     }
01987     if (arg.compare(string("-") + s_AutoHelpXml) == 0) {
01988         NCBI_THROW(CArgHelpException,eHelpXml,kEmptyStr);
01989     }
01990 }
01991 
01992 
01993 // (return TRUE if "arg2" was used)
01994 bool CArgDescriptions::x_CreateArg(const string& arg1,
01995                                    bool have_arg2, const string& arg2,
01996                                    unsigned* n_plain, CArgs& args) const
01997 {
01998     // Argument name
01999     string name;
02000 
02001     // Check if to start processing the args as positional
02002     if (*n_plain == kMax_UInt) {
02003         // Check for the "--" delimiter
02004         if (arg1.compare("--") == 0) {
02005             *n_plain = 0;  // pos.args started
02006             return false;
02007         }
02008         // Check if argument has not a key/flag syntax
02009         if ((arg1.length() > 1)  &&  arg1[0] == '-') {
02010             name = arg1.substr(1);
02011             // Check for '=' in the arg1
02012             size_t eq = name.find('=');
02013             if (eq != NPOS) {
02014                 name = name.substr(0, eq);
02015             }
02016             if (m_PositionalMode == ePositionalMode_Loose) {
02017                 // If not a valid key/flag, treat it as a positional value
02018                 if (!VerifyName(name)  ||  x_Find(name) == m_Args.end()) {
02019                     *n_plain = 0;  // pos.args started
02020                 }
02021             }
02022         } else {
02023             *n_plain = 0;  // pos.args started
02024         }
02025     }
02026 
02027     // Whether the value of "arg2" is used
02028     bool arg2_used = false;
02029 
02030     // Extract name of positional argument
02031     if (*n_plain != kMax_UInt) {
02032         if (*n_plain < m_PosArgs.size()) {
02033             name = m_PosArgs[*n_plain];  // named positional argument
02034         } else {
02035             name = kEmptyStr;  // unnamed (extra) positional argument
02036         }
02037         (*n_plain)++;
02038 
02039         // Check for too many positional arguments
02040         if (kMax_UInt - m_nExtraOpt > m_nExtra + m_PosArgs.size()  &&
02041             *n_plain > m_PosArgs.size() + m_nExtra + m_nExtraOpt) {
02042             NCBI_THROW(CArgException,eSynopsis,
02043                 "Too many positional arguments (" +
02044                 NStr::UIntToString(*n_plain) +
02045                 "), the offending value: "+ arg1);
02046         }
02047     }
02048 
02049     arg2_used = x_CreateArg(arg1, name, have_arg2, arg2, *n_plain, args);
02050 
02051     // Success (also indicate whether one or two "raw" args have been used)
02052     return arg2_used;
02053 }
02054 
02055 
02056 bool CArgDescriptions::x_CreateArg(const string& arg1,
02057                                    const string& name, 
02058                                    bool          have_arg2,
02059                                    const string& arg2,
02060                                    unsigned      n_plain,
02061                                    CArgs&        args,
02062                                    bool          update,
02063                                    CArgValue**   new_value) const
02064 {
02065     if (new_value)
02066         *new_value = 0;
02067 
02068     bool arg2_used = false;
02069     bool no_separator = false;
02070     bool eq_separator = false;
02071     bool negative = false;
02072 
02073     // Get arg. description
02074     TArgsCI it;
02075     try {
02076         it = x_Find(name, &negative);
02077     } catch (CArgException&) {
02078         // Suppress overzealous "invalid argument name" exceptions
02079         // in the no-separator case.
02080         if (m_NoSeparator.find(name[0]) != NPOS) {
02081             it = m_Args.end(); // avoid duplicating the logic below
02082         } else {
02083             throw;
02084         }
02085     }
02086     if (it == m_Args.end()  &&  m_NoSeparator.find(name[0]) != NPOS) {
02087         it = x_Find(name.substr(0, 1), &negative);
02088         _ASSERT(it != m_Args.end());
02089         no_separator = true;
02090     }
02091     if (it == m_Args.end()) {
02092         if ( name.empty() ) {
02093             NCBI_THROW(CArgException,eInvalidArg,
02094                     "Unexpected extra argument, at position # " +
02095                     NStr::UIntToString(n_plain));
02096         } else {
02097             NCBI_THROW(CArgException,eInvalidArg,
02098                     "Unknown argument: \"" + name + "\"");
02099         }
02100     }
02101     _ASSERT(*it);
02102 
02103     const CArgDesc& arg = **it;
02104 
02105     // Check value separated by '='
02106     string arg_val;
02107     if ( s_IsKey(arg) ) {
02108         eq_separator = arg1.length() > name.length()  &&
02109             (arg1[name.length() + 1] == '=');
02110         if ( !eq_separator ) {
02111             no_separator |= (arg.GetFlags() & fOptionalSeparator) != 0  &&
02112                 name.length() == 1  &&  arg1.length() > 2;
02113         }
02114     }
02115 
02116     // Get argument value
02117     const string* value = 0;
02118     if ( !eq_separator  &&  !no_separator ) {
02119         if ( s_IsKey(arg) ) {
02120             // <key> <value> arg  -- advance from the arg.name to the arg.value
02121             if ( !have_arg2  &&  !value ) {
02122 
02123                 // if update specified we try to add default value
02124                 //  (mandatory throws an exception out of the ProcessDefault())
02125                 if (update) {
02126                     CRef<CArgValue> arg_value(arg.ProcessDefault());
02127                     // Add the value to "args"
02128                     args.Add(arg_value, update);
02129                     return arg2_used;
02130                 }
02131 
02132                 NCBI_THROW(CArgException,eNoValue,s_ArgExptMsg(arg1,
02133                     "Value is missing", kEmptyStr));
02134             }
02135             value = &arg2;
02136             arg2_used = true;
02137         } else {
02138             value = &arg1;
02139         }
02140     }
02141     else {
02142         _ASSERT(s_IsKey(arg));
02143         if ( no_separator ) {
02144             arg_val = arg1.substr(2);
02145         }
02146         else {
02147             arg_val = arg1.substr(name.length() + 2);
02148         }
02149         value = &arg_val;
02150     }
02151 
02152     CArgValue* av = 0;
02153     try {
02154         // Process the "raw" argument value into "CArgValue"
02155         if ( negative  &&  s_IsFlag(arg) ) {
02156             // Negative flag - use default value rather than
02157             // normal one.
02158             av = arg.ProcessDefault();
02159         }
02160         else {
02161             av = arg.ProcessArgument(*value);
02162         }
02163     }
02164     catch (CArgException) {
02165         const CArgErrorHandler* err_handler = arg.GetErrorHandler();
02166         if ( !err_handler ) {
02167             err_handler = m_ErrorHandler.GetPointerOrNull();
02168         }
02169         _ASSERT(err_handler);
02170         av = err_handler->HandleError(arg, *value);
02171     }
02172 
02173     if ( !av ) {
02174         return arg2_used;
02175     }
02176     CRef<CArgValue> arg_value(av);
02177 
02178     if (new_value) {
02179         *new_value = av;
02180     }
02181 
02182     bool allow_multiple = false;
02183     const CArgDescMandatory* adm = 
02184         dynamic_cast<const CArgDescMandatory*>(&arg);
02185 
02186     if (adm) {
02187         allow_multiple = 
02188             (adm->GetFlags() & CArgDescriptions::fAllowMultiple) != 0;
02189     }
02190 
02191     // Add the argument value to "args"
02192     args.Add(arg_value, update, allow_multiple);
02193 
02194     return arg2_used;
02195 }
02196 
02197 
02198 bool CArgDescriptions::x_IsMultiArg(const string& name) const
02199 {
02200     TArgsCI it = x_Find(name);
02201     if (it == m_Args.end()) {
02202         return false;
02203     }
02204     const CArgDesc& arg = **it;
02205     const CArgDescMandatory* adm = 
02206         dynamic_cast<const CArgDescMandatory*>(&arg);
02207 
02208     if (!adm) {
02209         return false;
02210     }
02211     return (adm->GetFlags() & CArgDescriptions::fAllowMultiple) != 0;
02212 }
02213 
02214 
02215 void CArgDescriptions::x_PostCheck(CArgs&           args,
02216                                    unsigned int     n_plain,
02217                                    EPostCheckCaller caller)
02218     const
02219 {
02220     // If explicitly specified, printout usage and exit in case there
02221     // was no args passed to the application
02222     if (m_UsageIfNoArgs  &&  args.IsEmpty()) {
02223         NCBI_THROW(CArgHelpException, eHelp, kEmptyStr);
02224     }
02225 
02226     // Check dependencies, create set of exclusions
02227     set<string> exclude;
02228     set<string> require;
02229     ITERATE(TDependencies, dep, m_Dependencies) {
02230         // Skip missing and empty arguments
02231         if (!args.Exist(dep->first)  ||  !args[dep->first]) {
02232             continue;
02233         }
02234         switch ( dep->second.m_Dep ) {
02235         case eRequires:
02236             require.insert(dep->second.m_Arg);
02237             break;
02238         case eExcludes:
02239             // Excluded exists and is not empty?
02240             if (args.Exist(dep->second.m_Arg)  &&  args[dep->second.m_Arg]) {
02241                 NCBI_THROW(CArgException, eConstraint,
02242                     s_ArgExptMsg(dep->second.m_Arg,
02243                     "Conflict with argument", dep->first));
02244             }
02245             exclude.insert(dep->second.m_Arg);
02246             break;
02247         }
02248     }
02249 
02250     // Check if all mandatory unnamed positional arguments are provided
02251     if (m_PosArgs.size() <= n_plain  &&
02252         n_plain < m_PosArgs.size() + m_nExtra){
02253         NCBI_THROW(CArgException,eNoArg,
02254             "Too few (" + NStr::UIntToString(n_plain) +
02255             ") unnamed positional arguments. Must define at least " +
02256             NStr::UIntToString(m_nExtra));
02257     }
02258 
02259     // Compose an ordered list of args
02260     list<const CArgDesc*> def_args;
02261     ITERATE (TKeyFlagArgs, it, m_KeyFlagArgs) {
02262         const CArgDesc& arg = **x_Find(*it);
02263         def_args.push_back(&arg);
02264     }
02265     ITERATE (TPosArgs, it, m_PosArgs) {
02266         const CArgDesc& arg = **x_Find(*it);
02267         def_args.push_back(&arg);
02268     }
02269 
02270     // Set default values (if available) for the arguments not defined
02271     // in the command line.
02272     ITERATE (list<const CArgDesc*>, it, def_args) {
02273         const CArgDesc& arg = **it;
02274 
02275         // Nothing to do if defined in the command-line
02276         if ( args.Exist(arg.GetName()) ) {
02277             continue;
02278         }
02279 
02280         if (require.find(arg.GetName()) != require.end() ) {
02281             // Required argument must be present
02282             NCBI_THROW(CArgException, eConstraint,
02283                 s_ArgExptMsg(arg.GetName(),
02284                 "Explicit value required by dependencies", kEmptyStr));
02285         }
02286 
02287         if (exclude.find(arg.GetName()) != exclude.end()) {
02288             CRef<CArg_NoValue> arg_novalue(new CArg_NoValue(arg.GetName()));
02289             // Add the no-value argument to "args"
02290             args.Add(arg_novalue);
02291             continue;
02292         }
02293         // Use default argument value
02294         try {
02295             CRef<CArgValue> arg_value(arg.ProcessDefault());
02296             // Add the value to "args"
02297             args.Add(arg_value);
02298         } 
02299         catch (CArgException&) {
02300             // mandatory argument, for CGI can be taken not only from the
02301             // command line but also from the HTTP request
02302             if (GetArgsType() != eCgiArgs  ||  caller == eConvertKeys) {
02303                 throw;
02304             }
02305         }
02306     }
02307 }
02308 
02309 
02310 void CArgDescriptions::SetUsageContext
02311 (const string& usage_name,
02312  const string& usage_description,
02313  bool          usage_sort_args,
02314  SIZE_TYPE     usage_width)
02315 {
02316     m_UsageName        = usage_name;
02317     m_UsageDescription = usage_description;
02318     m_UsageSortArgs    = usage_sort_args;
02319 
02320     const SIZE_TYPE kMinUsageWidth = 30;
02321     if (usage_width < kMinUsageWidth) {
02322         usage_width = kMinUsageWidth;
02323         ERR_POST_X(23, Warning <<
02324                        "CArgDescriptions::SetUsageContext() -- usage_width=" <<
02325                        usage_width << " adjusted to " << kMinUsageWidth);
02326     }
02327     m_UsageWidth = usage_width;
02328 }
02329 
02330 
02331 bool CArgDescriptions::VerifyName(const string& name, bool extended)
02332 {
02333     if ( name.empty() )
02334         return true;
02335 
02336     string::const_iterator it = name.begin();
02337     if (extended  &&  *it == '#') {
02338         for (++it;  it != name.end();  ++it) {
02339             if ( !isdigit((unsigned char)(*it)) ) {
02340                 return false;
02341             }
02342         }
02343     } else {
02344         if (name[0] == '-') {
02345             // Prohibit names like '-' or '--foo'.
02346             // The second char must be present and may not be '-'.
02347             if (name.length() == 1  ||  name[1] == '-') {
02348                 return false;
02349             }
02350         }
02351         for ( ;  it != name.end();  ++it) {
02352             if ( !s_IsArgNameChar((unsigned char)(*it)) )
02353                 return false;
02354         }
02355     }
02356 
02357     return true;
02358 }
02359 
02360 
02361 void CArgDescriptions::x_AddDesc(CArgDesc& arg)
02362 {
02363     const string& name = arg.GetName();
02364 
02365     if ( Exist(name) ) {
02366         NCBI_THROW(CArgException,eSynopsis,
02367             "Argument with this name is already defined: " + name);
02368     }
02369 
02370     arg.SetGroup(m_CurrentGroup);
02371 
02372     if (s_IsKey(arg)  ||  s_IsFlag(arg)) {
02373         _ASSERT(find(m_KeyFlagArgs.begin(), m_KeyFlagArgs.end(), name)
02374                 == m_KeyFlagArgs.end());
02375         m_KeyFlagArgs.push_back(name);
02376     } else if ( !s_IsAlias(arg)  &&  !name.empty() ) {
02377         _ASSERT(find(m_PosArgs.begin(), m_PosArgs.end(), name)
02378                 == m_PosArgs.end());
02379         if ( s_IsOptional(arg) ) {
02380             m_PosArgs.push_back(name);
02381         } else {
02382             TPosArgs::iterator it;
02383             for (it = m_PosArgs.begin();  it != m_PosArgs.end();  ++it) {
02384                 if ( s_IsOptional(**x_Find(*it)) )
02385                     break;
02386             }
02387             m_PosArgs.insert(it, name);
02388         }
02389     }
02390     
02391     if ((arg.GetFlags() & fOptionalSeparator) != 0  &&
02392         name.length() == 1  &&
02393         s_IsKey(arg)) {
02394         m_NoSeparator += arg.GetName();
02395     }
02396 
02397     arg.SetErrorHandler(m_ErrorHandler.GetPointerOrNull());
02398     m_Args.insert(&arg);
02399 }
02400 
02401 
02402 void CArgDescriptions::PrintUsageIfNoArgs(bool do_print)
02403 {
02404     m_UsageIfNoArgs = do_print;
02405 }
02406 
02407 
02408 
02409 ///////////////////////////////////////////////////////
02410 //  CArgDescriptions::PrintUsage()
02411 
02412 
02413 static void s_PrintCommentBody(list<string>& arr, const string& s,
02414                                SIZE_TYPE width)
02415 {
02416     NStr::Wrap(s, width, arr, NStr::fWrap_Hyphenate, "   ");
02417 }
02418 
02419 
02420 void CArgDescriptions::x_PrintComment(list<string>&   arr,
02421                                       const CArgDesc& arg,
02422                                       SIZE_TYPE       width) const
02423 {
02424     string intro = ' ' + arg.GetUsageSynopsis(true/*name_only*/);
02425 
02426     // Print type (and value constraint, if any)
02427     string attr = arg.GetUsageCommentAttr();
02428     if ( !attr.empty() ) {
02429         attr = " <" + attr + '>';
02430     }
02431 
02432     // Add aliases for non-positional arguments
02433     list<string> negatives;
02434     if ( !s_IsPositional(arg) ) {
02435         ITERATE(CArgDescriptions::TArgs, it, m_Args) {
02436             const CArgDesc_Alias* alias =
02437                 dynamic_cast<const CArgDesc_Alias*>(it->get());
02438             if (!alias  ||  alias->GetAliasedName() != arg.GetName()) {
02439                 continue;
02440             }
02441             if ( alias->GetNegativeFlag() ) {
02442                 negatives.push_back(alias->GetName());
02443             }
02444             else {
02445                 intro += ", -" + alias->GetName();
02446             }
02447         }
02448     }
02449 
02450     intro += attr;
02451 
02452     // Wrap intro if necessary...
02453     {{
02454         SIZE_TYPE indent = intro.find(", ");
02455         if (indent == NPOS  ||  indent > width / 2) {
02456             indent = intro.find(" <");
02457             if (indent == NPOS  ||  indent > width / 2) {
02458                 indent = 0;
02459             }
02460         }
02461         NStr::Wrap(intro, width, arr, NStr::fWrap_Hyphenate,
02462                    string(indent + 2, ' '), kEmptyStr);
02463     }}
02464 
02465     // Print description
02466     s_PrintCommentBody(arr, arg.GetComment(), width);
02467 
02468     // Print default value, if any
02469     const CArgDescDefault* dflt = dynamic_cast<const CArgDescDefault*> (&arg);
02470     if ( dflt ) {
02471         s_PrintCommentBody
02472             (arr, "Default = `" + dflt->GetDefaultValue() + '\'', width);
02473     }
02474 
02475     // Print required/excluded args
02476     string require;
02477     string exclude;
02478     pair<TDependency_CI, TDependency_CI> dep_rg =
02479         m_Dependencies.equal_range(arg.GetName());
02480     for (TDependency_CI dep = dep_rg.first; dep != dep_rg.second; ++dep) {
02481         switch ( dep->second.m_Dep ) {
02482         case eRequires:
02483             if ( !require.empty() ) {
02484                 require += ", ";
02485             }
02486             require += dep->second.m_Arg;
02487             break;
02488         case eExcludes:
02489             if ( !exclude.empty() ) {
02490                 exclude += ", ";
02491             }
02492             exclude += dep->second.m_Arg;
02493             break;
02494         }
02495     }
02496     if ( !require.empty() ) {
02497         s_PrintCommentBody(arr, " * Requires:  " + require, width);
02498     }
02499     if ( !exclude.empty() ) {
02500         s_PrintCommentBody(arr, " * Incompatible with:  " + exclude, width);
02501     }
02502     if ( !negatives.empty() ) {
02503         string neg_info;
02504         ITERATE(list<string>, neg, negatives) {
02505             if ( !neg_info.empty() ) {
02506                 neg_info += ", ";
02507             }
02508             neg_info += *neg;
02509         }
02510         SIZE_TYPE indent = neg_info.find(", ");
02511         if (indent == NPOS  ||  indent > width / 2) {
02512             indent = 0;
02513         }
02514         neg_info = " -" + neg_info;
02515         NStr::Wrap(neg_info, width, arr, NStr::fWrap_Hyphenate,
02516                 string(indent + 2, ' '), kEmptyStr);
02517 
02518         // Print description
02519         string neg_comment = arg.GetComment();
02520         if ( neg_comment.empty() ) {
02521             neg_comment = "Negative for " + arg.GetName();
02522         }
02523         s_PrintCommentBody(arr, neg_comment, width);
02524     }
02525     if (s_IsFlag(arg)) {
02526         const CArgDesc_Flag* fl = dynamic_cast<const CArgDesc_Flag*>(&arg);
02527         if (fl && !fl->GetSetValue()) {
02528             s_PrintCommentBody(arr, "When the flag is present, its value is FALSE", width);
02529         }
02530     }
02531 }
02532 
02533 
02534 string& CArgDescriptions::PrintUsage(string& str, bool detailed) const
02535 {
02536     typedef list<const CArgDesc*> TList;
02537     typedef TList::iterator       TListI;
02538     typedef TList::const_iterator TListCI;
02539 
02540     TList args;
02541 
02542     args.push_front(0);
02543     TListI it_pos = args.begin();
02544 
02545     // Keys and Flags
02546     if ( m_UsageSortArgs ) {
02547         // Alphabetically ordered,
02548         // mandatory keys to go first, then flags, then optional keys
02549         TListI& it_opt_keys = it_pos;
02550         args.push_front(0);
02551         TListI it_flags = args.begin();
02552         args.push_front(0);
02553         TListI it_keys  = args.begin();
02554 
02555         for (TArgsCI it = m_Args.begin();  it != m_Args.end();  ++it) {
02556             const CArgDesc* arg = it->get();
02557 
02558             if (dynamic_cast<const CArgDesc_KeyOpt*> (arg)  ||
02559                 dynamic_cast<const CArgDesc_KeyDef*> (arg)) {
02560                 args.insert(it_opt_keys, arg);
02561             } else if (dynamic_cast<const CArgDesc_Key*> (arg)) {
02562                 args.insert(it_keys, arg);
02563             } else if (dynamic_cast<const CArgDesc_Flag*> (arg)) {
02564                 if (strcmp(s_AutoHelp,     (arg->GetName()).c_str()) == 0  ||
02565                     strcmp(s_AutoHelpFull, (arg->GetName()).c_str()) == 0)
02566                     args.push_front(arg);
02567                 else
02568                     args.insert(it_flags, arg);
02569             }
02570         }
02571         args.erase(it_keys);
02572         args.erase(it_flags);
02573     } else {
02574         // Unsorted, just the order they were described by user
02575         for (TKeyFlagArgs::const_iterator name = m_KeyFlagArgs.begin();
02576              name != m_KeyFlagArgs.end();  ++name) {
02577             TArgsCI it = x_Find(*name);
02578             _ASSERT(it != m_Args.end());
02579 
02580             args.insert(it_pos, it->get());
02581         }
02582     }
02583 
02584     // Positional
02585     for (TPosArgs::const_iterator name = m_PosArgs.begin();
02586          name != m_PosArgs.end();  ++name) {
02587         TArgsCI it = x_Find(*name);
02588         _ASSERT(it != m_Args.end());
02589         const CArgDesc* arg = it->get();
02590 
02591         // Mandatory args to go first, then go optional ones
02592         if (dynamic_cast<const CArgDesc_PosOpt*> (arg)) {
02593             args.push_back(arg);
02594         } else if (dynamic_cast<const CArgDesc_Pos*> (arg)) {
02595             args.insert(it_pos, arg);
02596         }
02597     }
02598     args.erase(it_pos);
02599 
02600     // Extra
02601     {{
02602         TArgsCI it = x_Find(kEmptyStr);
02603         if (it != m_Args.end()) {
02604             args.push_back(it->get());
02605         }
02606     }}
02607 
02608     // Do Printout
02609     TListCI      it;
02610     list<string> arr;
02611 
02612     // SYNOPSIS
02613     arr.push_back("USAGE");
02614 
02615     if (m_ArgsType == eCgiArgs) {
02616         list<string> syn;
02617         for (it = args.begin();  it != args.end();  ++it) {
02618             const CArgDescSynopsis* as = 
02619                 dynamic_cast<const CArgDescSynopsis*>(&**it);
02620 
02621             if (as) {
02622                 const string& name  = (*it)->GetName();
02623                 const string& synopsis  = as->GetSynopsis();
02624                 syn.push_back(name+"="+synopsis);
02625             }
02626         } // for
02627         NStr::WrapList(
02628             syn, m_UsageWidth, "&", arr, 0, "?", "  "+m_UsageName+"?");
02629 
02630     } else { // regular application
02631         list<string> syn;
02632         syn.push_back(m_UsageName);
02633         for (it = args.begin();  it != args.end();  ++it) {
02634             if ( s_IsOptional(**it) || s_IsFlag(**it) ) {
02635                 syn.push_back('[' + (*it)->GetUsageSynopsis() + ']');
02636             } else if ( s_IsPositional(**it) ) {
02637                 syn.push_back('<' + (*it)->GetUsageSynopsis() + '>');
02638             } else {
02639                 syn.push_back((*it)->GetUsageSynopsis());
02640             }
02641         } // for
02642         NStr::WrapList(syn, m_UsageWidth, " ", arr, 0, "    ", "  ");
02643     }
02644 
02645     // DESCRIPTION
02646     arr.push_back(kEmptyStr);
02647     if ( m_UsageDescription.empty() ) {
02648         arr.push_back("DESCRIPTION    -- none");
02649     } else {
02650         arr.push_back("DESCRIPTION");
02651         s_PrintCommentBody(arr, m_UsageDescription, m_UsageWidth);
02652     }
02653 
02654     // REQUIRED & OPTIONAL ARGUMENTS
02655     if (detailed) {
02656         list<string> req;
02657         list<string> opt;
02658         // Collect mandatory args
02659         for (it = args.begin();  it != args.end();  ++it) {
02660             if (s_IsOptional(**it)  ||  s_IsFlag(**it)) {
02661                 continue;
02662             }
02663             x_PrintComment(req, **it, m_UsageWidth);
02664         }
02665         // Collect optional args
02666         for (size_t grp = 0;  grp < m_ArgGroups.size();  ++grp) {
02667             list<string> grp_opt;
02668             bool group_not_empty = false;
02669             if ( !m_ArgGroups[grp].empty() ) {
02670                 NStr::Wrap(m_ArgGroups[grp], m_UsageWidth, grp_opt,
02671                     NStr::fWrap_Hyphenate, " *** ");
02672             }
02673             for (it = args.begin();  it != args.end();  ++it) {
02674                 if (!s_IsOptional(**it)  &&  !s_IsFlag(**it)) {
02675                     continue;
02676                 }
02677                 if ((*it)->GetGroup() == grp) {
02678                     x_PrintComment(grp_opt, **it, m_UsageWidth);
02679                     group_not_empty = true;
02680                 }
02681             }
02682             if ( group_not_empty ) {
02683                 opt.insert(opt.end(), grp_opt.begin(), grp_opt.end());
02684                 opt.push_back(kEmptyStr);
02685             }
02686         }
02687         if ( !req.empty() ) {
02688             arr.push_back(kEmptyStr);
02689             arr.push_back("REQUIRED ARGUMENTS");
02690             arr.splice(arr.end(), req);
02691         }
02692         if ( !m_nExtra  &&  !opt.empty() ) {
02693             arr.push_back(kEmptyStr);
02694             arr.push_back("OPTIONAL ARGUMENTS");
02695             arr.splice(arr.end(), opt);
02696         }
02697 
02698         // # of extra arguments
02699         if (m_nExtra  ||  (m_nExtraOpt != 0  &&  m_nExtraOpt != kMax_UInt)) {
02700             string str_extra = "NOTE:  Specify ";
02701             if ( m_nExtra ) {
02702                 str_extra += "at least ";
02703                 str_extra += NStr::UIntToString(m_nExtra);
02704                 if (m_nExtraOpt != kMax_UInt) {
02705                     str_extra += ", and ";
02706                 }
02707             }
02708             if (m_nExtraOpt != kMax_UInt) {
02709                 str_extra += "no more than ";
02710                 str_extra += NStr::UIntToString(m_nExtra + m_nExtraOpt);
02711             }
02712             str_extra += " arguments in \"....\"";
02713             s_PrintCommentBody(arr, str_extra, m_UsageWidth);
02714         }
02715         if ( m_nExtra  &&  !opt.empty() ) {
02716             arr.push_back(kEmptyStr);
02717             arr.push_back("OPTIONAL ARGUMENTS");
02718             arr.splice(arr.end(), opt);
02719         }
02720     } else {
02721         arr.push_back(kEmptyStr);
02722         arr.push_back("Use '-help' to print detailed descriptions of command line arguments");
02723     }
02724 
02725     str += NStr::Join(arr, "\n");
02726     str += "\n";
02727     return str;
02728 }
02729 
02730 void CArgDescriptions::PrintUsageXml(CNcbiOstream& out) const
02731 {
02732     out << "<" << "ncbi_application" << ">" << endl;
02733 
02734     out << "<" << "program" << " type=\"";
02735     if (m_ArgsType == eRegularArgs) {
02736         out << "regular";
02737     } else if (m_ArgsType == eCgiArgs) {
02738         out << "cgi";
02739     } else {
02740         out << "UNKNOWN";
02741     }
02742     out << "\"" << ">" << endl;    
02743     s_WriteXmlLine(out, "name", m_UsageName);
02744     s_WriteXmlLine(out, "version", 
02745         CNcbiApplication::Instance()->GetVersion().Print());
02746     s_WriteXmlLine(out, "description", m_UsageDescription);
02747     out << "</" << "program" << ">" << endl;
02748 
02749     out << "<" << "arguments";
02750     if (GetPositionalMode() == ePositionalMode_Loose) {
02751         out << " positional_mode=\"loose\"";
02752     }
02753     out << ">" << endl;
02754 
02755     string tag;
02756 // positional
02757     ITERATE(TPosArgs, p, m_PosArgs) {
02758         ITERATE (TArgs, a, m_Args) {
02759             if ((**a).GetName() == *p) {
02760                 tag = (*a)->PrintXml(out);
02761                 x_PrintAliasesAsXml(out, (*a)->GetName());
02762                 out << "</" << tag << ">" << endl;
02763             }
02764         }
02765     }
02766 // keys
02767     ITERATE (TArgs, a, m_Args) {
02768         if (s_IsKey(**a)) {
02769             tag = (*a)->PrintXml(out);
02770             x_PrintAliasesAsXml(out, (*a)->GetName());
02771             out << "</" << tag << ">" << endl;
02772         }
02773     }
02774 // flags
02775     ITERATE (TArgs, a, m_Args) {
02776         if (s_IsFlag(**a)) {
02777             tag = (*a)->PrintXml(out);
02778             x_PrintAliasesAsXml(out, (*a)->GetName());
02779             x_PrintAliasesAsXml(out, (*a)->GetName(), true);
02780             out << "</" << tag << ">" << endl;
02781         }
02782     }
02783 // extra positional
02784     ITERATE (TArgs, a, m_Args) {
02785         if (s_IsPositional(**a) && (**a).GetName().empty()) {
02786             tag = (*a)->PrintXml(out);
02787             s_WriteXmlLine(out, "min_occurs", NStr::UIntToString(m_nExtra));
02788             s_WriteXmlLine(out, "max_occurs", NStr::UIntToString(m_nExtraOpt));
02789             out << "</" << tag << ">" << endl;
02790         }
02791     }
02792     if (!m_Dependencies.empty()) {
02793         out << "<" << "dependencies" << ">" << endl;
02794         ITERATE(TDependencies, dep, m_Dependencies) {
02795             if (dep->second.m_Dep == eRequires) {
02796                 out << "<" << "first_requires_second" << ">" << endl;
02797                 s_WriteXmlLine(out, "arg1", dep->first);
02798                 s_WriteXmlLine(out, "arg2", dep->second.m_Arg);
02799                 out << "</" << "first_requires_second" << ">" << endl;
02800             }
02801         }
02802         ITERATE(TDependencies, dep, m_Dependencies) {
02803             if (dep->second.m_Dep == eExcludes) {
02804                 out << "<" << "first_excludes_second" << ">" << endl;
02805                 s_WriteXmlLine(out, "arg1", dep->first);
02806                 s_WriteXmlLine(out, "arg2", dep->second.m_Arg);
02807                 out << "</" << "first_excludes_second" << ">" << endl;
02808             }
02809         }
02810         out << "</" << "dependencies" << ">" << endl;
02811     }
02812 
02813 
02814 
02815     out << "</" << "arguments" << ">" << endl;
02816 
02817     out << "</" << "ncbi_application" << ">" << endl;
02818 }
02819 
02820 void CArgDescriptions::x_PrintAliasesAsXml( CNcbiOstream& out,
02821     const string& name, bool negated /* =false*/) const
02822 {
02823     ITERATE (TArgs, a, m_Args) {
02824         if (s_IsAlias(**a)) {
02825             const CArgDesc_Alias& alias =
02826                 dynamic_cast<const CArgDesc_Alias&>(**a);
02827             if (negated == alias.GetNegativeFlag()) {
02828                 string tag = negated ? "negated_alias" : "alias";
02829                 if (alias.GetAliasedName() == name) {
02830                     s_WriteXmlLine(out, tag, alias.GetName());
02831                 }
02832             }
02833         }
02834     }
02835 }
02836 
02837 
02838 ///////////////////////////////////////////////////////
02839 ///////////////////////////////////////////////////////
02840 // CArgAllow::
02841 //   CArgAllow_Symbols::
02842 //   CArgAllow_String::
02843 //   CArgAllow_Strings::
02844 //   CArgAllow_Int8s::
02845 //   CArgAllow_Integers::
02846 //   CArgAllow_Doubles::
02847 //
02848 
02849 
02850 ///////////////////////////////////////////////////////
02851 //  CArgAllow::
02852 //
02853 
02854 CArgAllow::~CArgAllow(void)
02855 {
02856     return;
02857 }
02858 
02859 void CArgAllow::PrintUsageXml(CNcbiOstream& ) const
02860 {
02861 }
02862 
02863 ///////////////////////////////////////////////////////
02864 //  s_IsSymbol() -- check if the symbol belongs to one of standard character
02865 //                  classes from <ctype.h>, or to user-defined symbol set
02866 //
02867 
02868 inline bool s_IsAllowedSymbol(unsigned char                   ch,
02869                               CArgAllow_Symbols::ESymbolClass symbol_class,
02870                               const string&                   symbol_set)
02871 {
02872     switch ( symbol_class ) {
02873     case CArgAllow_Symbols::eAlnum:   return isalnum(ch) != 0;
02874     case CArgAllow_Symbols::eAlpha:   return isalpha(ch) != 0;
02875     case CArgAllow_Symbols::eCntrl:   return iscntrl(ch) != 0;
02876     case CArgAllow_Symbols::eDigit:   return isdigit(ch) != 0;
02877     case CArgAllow_Symbols::eGraph:   return isgraph(ch) != 0;
02878     case CArgAllow_Symbols::eLower:   return islower(ch) != 0;
02879     case CArgAllow_Symbols::ePrint:   return isprint(ch) != 0;
02880     case CArgAllow_Symbols::ePunct:   return ispunct(ch) != 0;
02881     case CArgAllow_Symbols::eSpace:   return isspace(ch) != 0;
02882     case CArgAllow_Symbols::eUpper:   return isupper(ch) != 0;
02883     case CArgAllow_Symbols::eXdigit:  return isxdigit(ch) != 0;
02884     case CArgAllow_Symbols::eUser:
02885         return symbol_set.find_first_of(ch) != NPOS;
02886     }
02887     _TROUBLE;  return false;
02888 }
02889 
02890 
02891 static string s_GetUsageSymbol(CArgAllow_Symbols::ESymbolClass symbol_class,
02892                                const string&                   symbol_set)
02893 {
02894     switch ( symbol_class ) {
02895     case CArgAllow_Symbols::eAlnum:   return "alphanumeric";
02896     case CArgAllow_Symbols::eAlpha:   return "alphabetic";
02897     case CArgAllow_Symbols::eCntrl:   return "control symbol";
02898     case CArgAllow_Symbols::eDigit:   return "decimal";
02899     case CArgAllow_Symbols::eGraph:   return "graphical symbol";
02900     case CArgAllow_Symbols::eLower:   return "lower case";
02901     case CArgAllow_Symbols::ePrint:   return "printable";
02902     case CArgAllow_Symbols::ePunct:   return "punctuation";
02903     case CArgAllow_Symbols::eSpace:   return "space";
02904     case CArgAllow_Symbols::eUpper:   return "upper case";
02905     case CArgAllow_Symbols::eXdigit:  return "hexadecimal";
02906     case CArgAllow_Symbols::eUser:
02907         return "'" + NStr::PrintableString(symbol_set) + "'";
02908     }
02909     _TROUBLE;  return kEmptyStr;
02910 }
02911 
02912 static string s_GetSymbolClass(CArgAllow_Symbols::ESymbolClass symbol_class)
02913 {
02914     switch ( symbol_class ) {
02915     case CArgAllow_Symbols::eAlnum:   return "Alnum";
02916     case CArgAllow_Symbols::eAlpha:   return "Alpha";
02917     case CArgAllow_Symbols::eCntrl:   return "Cntrl";
02918     case CArgAllow_Symbols::eDigit:   return "Digit";
02919     case CArgAllow_Symbols::eGraph:   return "Graph";
02920     case CArgAllow_Symbols::eLower:   return "Lower";
02921     case CArgAllow_Symbols::ePrint:   return "Print";
02922     case CArgAllow_Symbols::ePunct:   return "Punct";
02923     case CArgAllow_Symbols::eSpace:   return "Space";
02924     case CArgAllow_Symbols::eUpper:   return "Upper";
02925     case CArgAllow_Symbols::eXdigit:  return "Xdigit";
02926     case CArgAllow_Symbols::eUser:    return "User";
02927     }
02928     _TROUBLE;  return kEmptyStr;
02929 }
02930 
02931 
02932 
02933 ///////////////////////////////////////////////////////
02934 //  CArgAllow_Symbols::
02935 //
02936 
02937 CArgAllow_Symbols::CArgAllow_Symbols(ESymbolClass symbol_class)
02938     : CArgAllow(),
02939       m_SymbolClass(symbol_class)
02940 {
02941     return;
02942 }
02943 
02944 
02945 CArgAllow_Symbols::CArgAllow_Symbols(const string& symbol_set)
02946     : CArgAllow(),
02947       m_SymbolClass(eUser), m_SymbolSet(symbol_set)
02948 {
02949     return;
02950 }
02951 
02952 
02953 bool CArgAllow_Symbols::Verify(const string& value) const
02954 {
02955     if (value.length() != 1)
02956         return false;
02957 
02958     return s_IsAllowedSymbol(value[0], m_SymbolClass, m_SymbolSet);
02959 }
02960 
02961 
02962 string CArgAllow_Symbols::GetUsage(void) const
02963 {
02964     return "one symbol: " + s_GetUsageSymbol(m_SymbolClass, m_SymbolSet);
02965 }
02966 
02967 void CArgAllow_Symbols::PrintUsageXml(CNcbiOstream& out) const
02968 {
02969     out << "<" << "Symbols" << ">" << endl;
02970     if (m_SymbolClass != eUser) {
02971         s_WriteXmlLine( out, "type", s_GetSymbolClass(m_SymbolClass).c_str());
02972     } else {
02973         ITERATE( string, p, m_SymbolSet) {
02974             string c;
02975             s_WriteXmlLine( out, "value", c.append(1,*p).c_str());
02976         }
02977     }
02978     out << "</" << "Symbols" << ">" << endl;
02979 }
02980 
02981 CArgAllow_Symbols::~CArgAllow_Symbols(void)
02982 {
02983     return;
02984 }
02985 
02986 
02987 
02988 ///////////////////////////////////////////////////////
02989 //  CArgAllow_String::
02990 //
02991 
02992 CArgAllow_String::CArgAllow_String(ESymbolClass symbol_class)
02993     : CArgAllow_Symbols(symbol_class)
02994 {
02995     return;
02996 }
02997 
02998 
02999 CArgAllow_String::CArgAllow_String(const string& symbol_set)
03000     : CArgAllow_Symbols(symbol_set)
03001 {
03002     return;
03003 }
03004 
03005 
03006 bool CArgAllow_String::Verify(const string& value) const
03007 {
03008     for (string::const_iterator it = value.begin();  it != value.end(); ++it) {
03009         if ( !s_IsAllowedSymbol(*it, m_SymbolClass, m_SymbolSet) )
03010             return false;
03011     }
03012     return true;
03013 }
03014 
03015 
03016 string CArgAllow_String::GetUsage(void) const
03017 {
03018     return "to contain only symbols: " +
03019         s_GetUsageSymbol(m_SymbolClass, m_SymbolSet);
03020 }
03021 
03022 
03023 void CArgAllow_String::PrintUsageXml(CNcbiOstream& out) const
03024 {
03025     out << "<" << "String" << ">" << endl;
03026     if (m_SymbolClass != eUser) {
03027         s_WriteXmlLine( out, "type", s_GetSymbolClass(m_SymbolClass).c_str());
03028     } else {
03029         s_WriteXmlLine( out, "charset", m_SymbolSet.c_str());
03030     }
03031     out << "</" << "String" << ">" << endl;
03032 }
03033 
03034 
03035 
03036 ///////////////////////////////////////////////////////
03037 //  CArgAllow_Strings::
03038 //
03039 
03040 CArgAllow_Strings::CArgAllow_Strings(NStr::ECase use_case)
03041     : CArgAllow(),
03042       m_Strings(PNocase_Conditional(use_case))
03043 {
03044     return;
03045 }
03046 
03047 
03048 CArgAllow_Strings* CArgAllow_Strings::Allow(const string& value)
03049 {
03050     m_Strings.insert(value);
03051     return this;
03052 }
03053 
03054 
03055 bool CArgAllow_Strings::Verify(const string& value) const
03056 {
03057     TStrings::const_iterator it = m_Strings.find(value);
03058     return it != m_Strings.end();
03059 }
03060 
03061 
03062 string 
03063 CArgAllow_Strings::GetUsage(void) const
03064 {
03065     if ( m_Strings.empty() ) {
03066         return "ERROR:  Constraint with no values allowed(?!)";
03067     }
03068 
03069     string str;
03070     TStrings::const_iterator it = m_Strings.begin();
03071     for (;;) {
03072         str += "`";
03073         str += *it;
03074 
03075         ++it;
03076         if (it == m_Strings.end()) {
03077             str += "'";
03078             if ( m_Strings.key_comp()("a", "A") ) {
03079                 str += "  {case insensitive}";
03080             }
03081             break;
03082         }
03083         str += "', ";
03084     }
03085     return str;
03086 }
03087 
03088 
03089 void CArgAllow_Strings::PrintUsageXml(CNcbiOstream& out) const
03090 {
03091     out << "<" << "Strings";
03092     out << " case_sensitive=\"";
03093     if ( m_Strings.key_comp()("a", "A") ) {
03094         out << "false";
03095     } else {
03096         out << "true";
03097     }
03098     out << "\">" << endl;
03099     ITERATE( TStrings, p, m_Strings) {
03100         s_WriteXmlLine( out, "value", (*p).c_str());
03101     }
03102     out << "</" << "Strings" << ">" << endl;
03103 }
03104 
03105 
03106 CArgAllow_Strings::~CArgAllow_Strings(void)
03107 {
03108     return;
03109 }
03110 
03111 
03112 
03113 ///////////////////////////////////////////////////////
03114 //  CArgAllow_Int8s::
03115 //
03116 
03117 CArgAllow_Int8s::CArgAllow_Int8s(Int8 x_min, Int8 x_max)
03118     : CArgAllow()
03119 {
03120     if (x_min <= x_max) {
03121         m_Min = x_min;
03122         m_Max = x_max;
03123     } else {
03124         m_Min = x_max;
03125         m_Max = x_min;
03126     }
03127 }
03128 
03129 
03130 bool CArgAllow_Int8s::Verify(const string& value) const
03131 {
03132     Int8 val = NStr::StringToInt8(value);
03133     return (m_Min <= val  &&  val <= m_Max);
03134 }
03135 
03136 
03137 string CArgAllow_Int8s::GetUsage(void) const
03138 {
03139     return NStr::Int8ToString(m_Min) + ".." + NStr::Int8ToString(m_Max);
03140 }
03141 
03142 
03143 void CArgAllow_Int8s::PrintUsageXml(CNcbiOstream& out) const
03144 {
03145     string tag("Int8s");
03146     if (dynamic_cast<const CArgAllow_Integers*>(this) != 0) {
03147         tag = "Integers";
03148     }
03149     out << "<" << tag << ">" << endl;
03150     s_WriteXmlLine( out, "min", NStr::Int8ToString(m_Min).c_str());
03151     s_WriteXmlLine( out, "max", NStr::Int8ToString(m_Max).c_str());
03152     out << "</" << tag << ">" << endl;
03153 }
03154 
03155 
03156 
03157 ///////////////////////////////////////////////////////
03158 //  CArgAllow_Integers::
03159 //
03160 
03161 CArgAllow_Integers::CArgAllow_Integers(int x_min, int x_max)
03162     : CArgAllow_Int8s(x_min, x_max)
03163 {
03164 }
03165 
03166 
03167 
03168 ///////////////////////////////////////////////////////
03169 //  CArgAllow_Doubles::
03170 //
03171 
03172 CArgAllow_Doubles::CArgAllow_Doubles(double x_min, double x_max)
03173     : CArgAllow()
03174 {
03175     if (x_min <= x_max) {
03176         m_Min = x_min;
03177         m_Max = x_max;
03178     } else {
03179         m_Min = x_max;
03180         m_Max = x_min;
03181     }
03182 }
03183 
03184 
03185 bool CArgAllow_Doubles::Verify(const string& value) const
03186 {
03187     double val = NStr::StringToDouble(value);
03188     return (m_Min <= val  &&  val <= m_Max);
03189 }
03190 
03191 
03192 string CArgAllow_Doubles::GetUsage(void) const
03193 {
03194     return NStr::DoubleToString(m_Min) + ".." + NStr::DoubleToString(m_Max);
03195 }
03196 
03197 
03198 void CArgAllow_Doubles::PrintUsageXml(CNcbiOstream& out) const
03199 {
03200     out << "<" << "Doubles" << ">" << endl;
03201     s_WriteXmlLine( out, "min", NStr::DoubleToString(m_Min).c_str());
03202     s_WriteXmlLine( out, "max", NStr::DoubleToString(m_Max).c_str());
03203     out << "</" << "Doubles" << ">" << endl;
03204 }
03205 
03206 const char* CArgException::GetErrCodeString(void) const
03207 {
03208     switch (GetErrCode()) {
03209     case eInvalidArg: return "eInvalidArg";
03210     case eNoValue:    return "eNoValue";
03211     case eWrongCast:  return "eWrongCast";
03212     case eConvert:    return "eConvert";
03213     case eNoFile:     return "eNoFile";
03214     case eConstraint: return "eConstraint";
03215     case eArgType:    return "eArgType";
03216     case eNoArg:      return "eNoArg";
03217     case eSynopsis:   return "eSynopsis";
03218     default:    return CException::GetErrCodeString();
03219     }
03220 }
03221 
03222 const char* CArgHelpException::GetErrCodeString(void) const
03223 {
03224     switch (GetErrCode()) {
03225     case eHelp:     return "eHelp";
03226     case eHelpFull: return "eHelpFull";
03227     case eHelpXml:  return "eHelpXml";
03228     default:    return CException::GetErrCodeString();
03229     }
03230 }
03231 
03232 
03233 END_NCBI_SCOPE
03234 
03235 

Generated on Sun Dec 6 22:22:29 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Mon Dec 07 16:20:56 2009 by modify_doxy.py rev. 173732