📄 ncbiargs.cpp
字号:
virtual string GetUsageCommentAttr(void) const {return kEmptyStr;} virtual CArgValue* ProcessArgument(const string&) const {return 0;} virtual CArgValue* ProcessDefault(void) const {return 0;}};CArgDescriptions::TArgsCI CArgDescriptions::x_Find(const string& name) const{ return m_Args.find(AutoPtr<CArgDesc> (new CArgDesc_NameOnly(name)));}CArgDescriptions::TArgsI CArgDescriptions::x_Find(const string& name){ return m_Args.find(AutoPtr<CArgDesc> (new CArgDesc_NameOnly(name)));}void CArgDescriptions::x_PreCheck(void) const{ // Check for the consistency of positional args if ( m_nExtra ) { for (TPosArgs::const_iterator name = m_PosArgs.begin(); name != m_PosArgs.end(); ++name) { TArgsCI arg_it = x_Find(*name); _ASSERT(arg_it != m_Args.end()); CArgDesc& arg = **arg_it; if (dynamic_cast<const CArgDesc_PosOpt*> (&arg)) { NCBI_THROW(CArgException, eSynopsis, "Having both optional named and required unnamed " "positional arguments is prohibited"); } } } // Check for the validity of default values for (TArgsCI it = m_Args.begin(); it != m_Args.end(); ++it) { CArgDesc& arg = **it; if (dynamic_cast<CArgDescDefault*> (&arg) == 0) { continue; } try { arg.VerifyDefault(); continue; } catch (CException& e) { NCBI_RETHROW(e,CArgException,eConstraint, "Invalid default argument value"); } catch (exception& e) { NCBI_THROW(CArgException, eConstraint, string("Invalid default value: ") + e.what()); } }}CArgs* CArgDescriptions::CreateArgs(const CNcbiArguments& args) const{ return CreateArgs(args.Size(), args);}void CArgDescriptions::x_CheckAutoHelp(const string& arg) const{ _ASSERT(m_AutoHelp); if (arg.compare('-' + s_AutoHelp) == 0) { NCBI_THROW(CArgHelpException,eHelp,kEmptyStr); }}// (return TRUE if "arg2" was used)bool CArgDescriptions::x_CreateArg(const string& arg1, bool have_arg2, const string& arg2, unsigned* n_plain, CArgs& args) const{ // Argument name string name; // Check if to start processing the args as positional if (*n_plain == kMax_UInt) { // Check for the "--" delimiter if (arg1.compare("--") == 0) { *n_plain = 0; // pos.args started return false; } // Check if argument has not a key/flag syntax if ((arg1.length() > 1) && arg1[0] == '-') { // Extract name of flag or key name = arg1.substr(1); if ( !VerifyName(name) ) { *n_plain = 0; // pos.args started } } else { *n_plain = 0; // pos.args started } } // Whether the value of "arg2" is used bool arg2_used = false; // Extract name of positional argument if (*n_plain != kMax_UInt) { if (*n_plain < m_PosArgs.size()) { name = m_PosArgs[*n_plain]; // named positional argument } else { name = kEmptyStr; // unnamed (extra) positional argument } (*n_plain)++; // Check for too many positional arguments if (kMax_UInt - m_nExtraOpt > m_nExtra + m_PosArgs.size() && *n_plain > m_PosArgs.size() + m_nExtra + m_nExtraOpt) { NCBI_THROW(CArgException,eSynopsis, "Too many positional arguments (" + NStr::UIntToString(*n_plain) + "), the offending value: "+ arg1); } } // Get arg. description TArgsCI it = x_Find(name); if (it == m_Args.end()) { if ( name.empty() ) { NCBI_THROW(CArgException,eInvalidArg, "Unexpected extra argument, at position # " + NStr::UIntToString(*n_plain)); } else { NCBI_THROW(CArgException,eInvalidArg, "Unknown argument: "+ name); } } _ASSERT(*it); const CArgDesc& arg = **it; // Get argument value const string* value; if ( s_IsKey(arg) ) { // <key> <value> arg -- advance from the arg.name to the arg.value if ( !have_arg2 ) { NCBI_THROW(CArgException,eNoValue,s_ArgExptMsg(arg1, "Value is missing", kEmptyStr)); } value = &arg2; arg2_used = true; } else { value = &arg1; } // Process the "raw" argument value into "CArgValue" CRef<CArgValue> arg_value(arg.ProcessArgument(*value)); // Add the argument value to "args" args.Add(arg_value); // Success (also indicate whether one or two "raw" args have been used) return arg2_used;}void CArgDescriptions::x_PostCheck(CArgs& args, unsigned n_plain) const{ // If explicitly specified, printout usage and exit in case there // was no args passed to the application if (m_UsageIfNoArgs && args.IsEmpty()) { NCBI_THROW(CArgHelpException, eHelp, kEmptyStr); } // Check if all mandatory unnamed positional arguments are provided if (m_PosArgs.size() <= n_plain && n_plain < m_PosArgs.size() + m_nExtra){ NCBI_THROW(CArgException,eNoArg, "Too few (" + NStr::UIntToString(n_plain) + ") unnamed positional arguments. Must define at least " + NStr::UIntToString(m_nExtra)); } // Compose an ordered list of args list<const CArgDesc*> def_args; ITERATE (TKeyFlagArgs, it, m_KeyFlagArgs) { const CArgDesc& arg = **x_Find(*it); def_args.push_back(&arg); } ITERATE (TPosArgs, it, m_PosArgs) { const CArgDesc& arg = **x_Find(*it); def_args.push_back(&arg); } // Set default values (if available) for the arguments not defined // in the command line. ITERATE (list<const CArgDesc*>, it, def_args) { const CArgDesc& arg = **it; // Nothing to do if defined in the command-line if ( args.Exist(arg.GetName()) ) { continue; } // Use default argument value CRef<CArgValue> arg_value(arg.ProcessDefault()); // Add the value to "args" args.Add(arg_value); }}void CArgDescriptions::SetUsageContext(const string& usage_name, const string& usage_description, bool usage_sort_args, SIZE_TYPE usage_width){ m_UsageName = usage_name; m_UsageDescription = usage_description; m_UsageSortArgs = usage_sort_args; const SIZE_TYPE kMinUsageWidth = 30; if (usage_width < kMinUsageWidth) { usage_width = kMinUsageWidth; ERR_POST(Warning << "CArgDescriptions::SetUsageContext() -- usage_width=" << usage_width << " adjusted to " << kMinUsageWidth); } m_UsageWidth = usage_width;}bool CArgDescriptions::VerifyName(const string& name, bool extended){ if ( name.empty() ) return true; string::const_iterator it = name.begin(); if (extended && *it == '#') { for (++it; it != name.end(); ++it) { if ( !isdigit(*it) ) { return false; } } } else { for ( ; it != name.end(); ++it) { if (!isalnum(*it) && *it != '_') return false; } } return true;}void CArgDescriptions::x_AddDesc(CArgDesc& arg){ const string& name = arg.GetName(); if ( Exist(name) ) { NCBI_THROW(CArgException,eSynopsis, "Argument with this name is already defined: " + name); } if (s_IsKey(arg) || s_IsFlag(arg)) { _ASSERT(find(m_KeyFlagArgs.begin(), m_KeyFlagArgs.end(), name) == m_KeyFlagArgs.end()); m_KeyFlagArgs.push_back(name); } else if ( !name.empty() ) { _ASSERT(find(m_PosArgs.begin(), m_PosArgs.end(), name) == m_PosArgs.end()); if ( s_IsOptional(arg) ) { m_PosArgs.push_back(name); } else { TPosArgs::iterator it; for (it = m_PosArgs.begin(); it != m_PosArgs.end(); ++it) { if ( s_IsOptional(**x_Find(*it)) ) break; } m_PosArgs.insert(it, name); } } m_Args.insert(&arg);}void CArgDescriptions::PrintUsageIfNoArgs(bool do_print){ m_UsageIfNoArgs = do_print;}///////////////////////////////////////////////////////// CArgDescriptions::PrintUsage()static void s_PrintCommentBody(list<string>& arr, const string& s, SIZE_TYPE width){ NStr::Wrap(s, width, arr, NStr::fWrap_Hyphenate, " ");}static void s_PrintComment(list<string>& arr, const CArgDesc& arg, SIZE_TYPE width){ string intro = ' ' + arg.GetUsageSynopsis(true/*name_only*/); // Print type (and value constraint, if any) string attr = arg.GetUsageCommentAttr(); if ( !attr.empty() ) { intro += " <"; intro += attr; intro += '>'; } // Wrap intro if necessary... {{ SIZE_TYPE indent = intro.find(", "); if (indent == NPOS || indent > width / 2) { indent = intro.find(" <"); if (indent == NPOS || indent > width / 2) { indent = 0; } } NStr::Wrap(intro, width, arr, NStr::fWrap_Hyphenate, string(indent + 2, ' '), kEmptyStr); }} // Print description s_PrintCommentBody(arr, arg.GetComment(), width); // Print default value, if any const CArgDescDefault* dflt = dynamic_cast<const CArgDescDefault*> (&arg); if ( dflt ) { s_PrintCommentBody (arr, "Default = `" + dflt->GetDefaultValue() + '\'', width); }}string& CArgDescriptions::PrintUsage(string& str) const{ typedef list<const CArgDesc*> TList; typedef TList::iterator TListI; typedef TList::const_iterator TListCI; TList args; args.push_front(0); TListI it_pos = args.begin(); // Keys and Flags if ( m_UsageSortArgs ) { // Alphabetically ordered, // mandatory keys to go first, then flags, then optional keys TListI& it_opt_keys = it_pos; args.push_front(0); TListI it_flags = args.begin(); args.push_front(0); TListI it_keys = args.begin(); for (TArgsCI it = m_Args.begin(); it != m_Args.end(); ++it) { const CArgDesc* arg = it->get(); if (dynamic_cast<const CArgDesc_KeyOpt*> (arg) || dynamic_cast<const CArgDesc_KeyDef*> (arg)) { args.insert(it_opt_keys, arg); } else if (dynamic_cast<const CArgDesc_Key*> (arg)) { args.insert(it_keys, arg); } else if (dynamic_cast<const CArgDesc_Flag*> (arg)) { if (s_AutoHelp.compare(arg->GetName()) == 0) args.push_front(arg); else args.insert(it_flags, arg); } } args.erase(it_keys); args.erase(it_flags); } else { // Unsorted, just the order they were described by user for (TKeyFlagArgs::const_iterator name = m_KeyFlagArgs.begin(); name != m_KeyFlagArgs.end(); ++name) { TArgsCI it = x_Find(*name); _ASSERT(it != m_Args.end()); args.insert(it_pos, it->get()); } } // Positional for (TPosArgs::const_iterator name = m_PosArgs.begin(); name != m_PosArgs.end(); ++name) { TArgsCI it = x_Find(*name); _ASSERT(it != m_Args.end()); const CArgDesc* arg = it->get(); // Mandatory args to go first, then go optional ones if (dynamic_cast<const CArgDesc_PosOpt*> (arg)) { args.push_back(arg); } else if (dynamic_cast<const CArgDesc_Pos*> (arg)) { args.insert(it_pos, arg); } } args.erase(it_pos); // Extra {{ TArgsCI it = x_Find(kEmptyStr); if (it != m_Args.end()) { args.push_back(it->get()); } }} // Do Printout TListCI it; list<string> arr; // SYNOPSIS arr.push_back("USAGE"); {{ list<string> syn; syn.push_back(m_UsageName); for (it = args.begin(); it != args.end(); ++it) { if ( s_IsOptional(**it) || s_IsFlag(**it) ) { syn.push_back('[' + (*it)->GetUsageSynopsis() + ']'); } else if ( s_IsPositional(**it) ) { syn.push_back('<' + (*it)->GetUsageSynopsis() + '>'); } else { syn.push_back((*it)->GetUsageSynopsis()); } } NStr::WrapList(syn, m_UsageWidth, " ", arr, 0, " ", " "); }} // DESCRIPTION arr.push_back(kEmptyStr); if ( m_UsageDescription.empty() ) { arr.push_back("DESCRIPTION -- none"); } else { arr.push_back("DESCRIPTION"); s_PrintCommentBody(arr, m_UsageDescription, m_UsageWidth); } // REQUIRED & OPTIONAL ARGUMENTS list<string> req; list<string> opt; for (it = args.begin(); it != args.end(); ++it) { s_PrintComment((s_IsOptional(**it) || s_IsFlag(**it)) ? opt : req, **it, m_UsageWidth); } if ( !req.empty() ) { arr.push_back(kEmptyStr); arr.push_back("REQUIRED ARGUMENTS"); arr.splice(arr.end(), req); } if ( !m_nExtra && !opt.empty() ) { arr.push_back(kEmptyStr); arr.push_back("OPTIONAL ARGUMENTS"); arr.splice(arr.end(), opt); } // # of extra arguments if (m_nExtra || (m_nExtraOpt != 0 && m_nExtraOpt != kMax_UInt)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -