00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
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
00059
00060
00061 #define NCBIARGS__CPP
00062 #include "ncbiargs_p.hpp"
00063
00064
00065
00066
00067
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
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
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
00149
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
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
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
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
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
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
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
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
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
00504
00505
00506
00507
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
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
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
00610
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
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
00632 out << "<" << role << " name=\"";
00633 string name = CStringUTF8(GetName(),eEncoding_Unknown);
00634 s_WriteEscapedStr(out,name.c_str());
00635 out << "\"";
00636
00637 const CArgDescMandatory* am =
00638 dynamic_cast<const CArgDescMandatory*>(this);
00639 if (am) {
00640 out << " type=\"" << CArgDescriptions::GetTypeName(am->GetType()) << "\"";
00641 }
00642
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
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
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
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
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
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
00762 string str = CArgDescriptions::GetTypeName(GetType());
00763
00764
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
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 }
00818
00819
00820
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
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
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
00958 CRef<CArgValue> arg_value(ProcessArgument(GetDefaultValue()));
00959 }
00960
00961
00962
00963
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
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
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 ) 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& ) 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
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 ) const
01069 {
01070 return GetName().empty() ? s_ExtraName : GetName();
01071 }
01072
01073
01074
01075
01076
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
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
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
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
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
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 ) 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& ) 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
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
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
01363 NCBI_THROW(CArgException, eInvalidArg,
01364 "Unknown argument requested: \"" + name + "\"");
01365 }
01366
01367
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
01393 const string& arg_name = (*arg)->GetName();
01394 str += arg_name;
01395
01396
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
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
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
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
01475
01476 CArgValue* CArgErrorHandler::HandleError(const CArgDesc& arg_desc,
01477 const string& value) const
01478 {
01479 if ((arg_desc.GetFlags() & CArgDescriptions::fIgnoreInvalidValue) == 0) {
01480
01481 arg_desc.ProcessArgument(value);
01482
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
01490 return 0;
01491 }
01492
01493
01494
01495
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
01512 m_ErrorHandler.Reset(new CArgErrorHandler);
01513 }
01514
01515 SetUsageContext("NCBI_PROGRAM", kEmptyStr);
01516 m_ArgGroups.push_back(kEmptyStr);
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
01539 if (m_ArgsType == eCgiArgs) {
01540
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
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)
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
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
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
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 {{
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
01825 if ( name.empty() ) {
01826 m_nExtra = 0;
01827 m_nExtraOpt = 0;
01828 return;
01829 }
01830 }}
01831
01832 {{
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 {{
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
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) 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
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
01939
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
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
01994 bool CArgDescriptions::x_CreateArg(const string& arg1,
01995 bool have_arg2, const string& arg2,
01996 unsigned* n_plain, CArgs& args) const
01997 {
01998
01999 string name;
02000
02001
02002 if (*n_plain == kMax_UInt) {
02003
02004 if (arg1.compare("--") == 0) {
02005 *n_plain = 0;
02006 return false;
02007 }
02008
02009 if ((arg1.length() > 1) && arg1[0] == '-') {
02010 name = arg1.substr(1);
02011
02012 size_t eq = name.find('=');
02013 if (eq != NPOS) {
02014 name = name.substr(0, eq);
02015 }
02016 if (m_PositionalMode == ePositionalMode_Loose) {
02017
02018 if (!VerifyName(name) || x_Find(name) == m_Args.end()) {
02019 *n_plain = 0;
02020 }
02021 }
02022 } else {
02023 *n_plain = 0;
02024 }
02025 }
02026
02027
02028 bool arg2_used = false;
02029
02030
02031 if (*n_plain != kMax_UInt) {
02032 if (*n_plain < m_PosArgs.size()) {
02033 name = m_PosArgs[*n_plain];
02034 } else {
02035 name = kEmptyStr;
02036 }
02037 (*n_plain)++;
02038
02039
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
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
02074 TArgsCI it;
02075 try {
02076 it = x_Find(name, &negative);
02077 } catch (CArgException&) {
02078
02079
02080 if (m_NoSeparator.find(name[0]) != NPOS) {
02081 it = m_Args.end();
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
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
02117 const string* value = 0;
02118 if ( !eq_separator && !no_separator ) {
02119 if ( s_IsKey(arg) ) {
02120
02121 if ( !have_arg2 && !value ) {
02122
02123
02124
02125 if (update) {
02126 CRef<CArgValue> arg_value(arg.ProcessDefault());
02127
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
02155 if ( negative && s_IsFlag(arg) ) {
02156
02157
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
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
02221
02222 if (m_UsageIfNoArgs && args.IsEmpty()) {
02223 NCBI_THROW(CArgHelpException, eHelp, kEmptyStr);
02224 }
02225
02226
02227 set<string> exclude;
02228 set<string> require;
02229 ITERATE(TDependencies, dep, m_Dependencies) {
02230
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
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
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
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
02271
02272 ITERATE (list<const CArgDesc*>, it, def_args) {
02273 const CArgDesc& arg = **it;
02274
02275
02276 if ( args.Exist(arg.GetName()) ) {
02277 continue;
02278 }
02279
02280 if (require.find(arg.GetName()) != require.end() ) {
02281
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
02290 args.Add(arg_novalue);
02291 continue;
02292 }
02293
02294 try {
02295 CRef<CArgValue> arg_value(arg.ProcessDefault());
02296
02297 args.Add(arg_value);
02298 }
02299 catch (CArgException&) {
02300
02301
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
02346
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
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);
02425
02426
02427 string attr = arg.GetUsageCommentAttr();
02428 if ( !attr.empty() ) {
02429 attr = " <" + attr + '>';
02430 }
02431
02432
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
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
02466 s_PrintCommentBody(arr, arg.GetComment(), width);
02467
02468
02469 const CArgDescDefault* dflt = dynamic_cast<const CArgDescDefault*> (&arg);
02470 if ( dflt ) {
02471 s_PrintCommentBody
02472 (arr, "Default = `" + dflt->GetDefaultValue() + '\'', width);
02473 }
02474
02475
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
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
02546 if ( m_UsageSortArgs ) {
02547
02548
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
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
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
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
02601 {{
02602 TArgsCI it = x_Find(kEmptyStr);
02603 if (it != m_Args.end()) {
02604 args.push_back(it->get());
02605 }
02606 }}
02607
02608
02609 TListCI it;
02610 list<string> arr;
02611
02612
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 }
02627 NStr::WrapList(
02628 syn, m_UsageWidth, "&", arr, 0, "?", " "+m_UsageName+"?");
02629
02630 } else {
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 }
02642 NStr::WrapList(syn, m_UsageWidth, " ", arr, 0, " ", " ");
02643 }
02644
02645
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
02655 if (detailed) {
02656 list<string> req;
02657 list<string> opt;
02658
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
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
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
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
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
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
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 ) 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
02841
02842
02843
02844
02845
02846
02847
02848
02849
02850
02851
02852
02853
02854 CArgAllow::~CArgAllow(void)
02855 {
02856 return;
02857 }
02858
02859 void CArgAllow::PrintUsageXml(CNcbiOstream& ) const
02860 {
02861 }
02862
02863
02864
02865
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
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
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
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
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
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
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