📄 ncbireg.cpp
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbireg.cpp,v $ * PRODUCTION Revision 1000.1 2004/06/01 19:09:18 gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.39 * PRODUCTION * =========================================================================== *//* $Id: ncbireg.cpp,v 1000.1 2004/06/01 19:09:18 gouriano Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: Denis Vakatov * * File Description: * Handle info in the NCBI configuration file(s): * read and parse config. file * search, edit, etc. in the retrieved configuration info * dump info back to config. file * */#include <ncbi_pch.hpp>#include <corelib/ncbireg.hpp>#include <corelib/ncbimtx.hpp>// Platform-specific EndOfLine#if defined(NCBI_OS_MAC)const char s_Endl[] = "\r";#elif defined(NCBI_OS_MSWIN)const char s_Endl[] = "\r\n";#else /* assume UNIX-like EOLs */const char s_Endl[] = "\n";#endifBEGIN_NCBI_SCOPE#define CHECK_FLAGS(func_name, flags, allowed_flags) do { \ if (flags & ~((TFlags)(allowed_flags))) \ _TRACE("CNcbiRegistry::" func_name "(): extra flags passed: " \ << setiosflags(IOS_BASE::hex) << flags); \ flags = flags & (TFlags)(allowed_flags); \} while (0)/* Valid symbols for a section/entry name */inline bool s_IsNameSectionSymbol(char ch){ return (isalnum(ch) || ch == '_' || ch == '-' || ch == '.');}/* Check if "str" consists of alphanumeric and '_' only */static bool s_IsNameSection(const string& str){ if ( str.empty() ) return false; ITERATE (string, it, str) { if ( !s_IsNameSectionSymbol(*it) ) return false; } return true;}/* Convert "comment" from plain text to comment */static const string s_ConvertComment(const string& comment, bool is_file_comment = false){ if ( !comment.length() ) return kEmptyStr; string x_comment; const char c_comment = is_file_comment ? '#' : ';'; SIZE_TYPE endl_pos = 0; for (SIZE_TYPE beg = 0; beg < comment.length(); beg = endl_pos + 1) { SIZE_TYPE pos = comment.find_first_not_of(" \t", beg); endl_pos = comment.find_first_of("\n", beg); if (endl_pos == NPOS) { endl_pos = comment.length(); } if (((pos != NPOS && comment[pos] != c_comment) || (pos == NPOS && endl_pos == comment.length())) && (is_file_comment || beg != endl_pos) ) { x_comment += c_comment; } x_comment.append(comment, beg, endl_pos - beg); x_comment += '\n'; } return x_comment;}/* Dump the comment to stream "os" */static bool s_WriteComment(CNcbiOstream& os, const string& comment){ if (!comment.length()) return true; if (strcmp(s_Endl, "\n") == 0) { os << comment; } else { ITERATE(string, i, comment) { if (*i == '\n') { os << s_Endl; } else { os << *i; } } } return os.good();}// Protective mutex for registry Get() and Set() functionsDEFINE_STATIC_FAST_MUTEX(s_RegMutex);CNcbiRegistry::CNcbiRegistry(void) : m_Modified(false), m_Written(false){ return;}CNcbiRegistry::~CNcbiRegistry(void){ return;}CNcbiRegistry::CNcbiRegistry(CNcbiIstream& is, TFlags flags) : m_Modified(false), m_Written(false){ CHECK_FLAGS("CNcbiRegistry", flags, eTransient); Read(is, flags);}bool CNcbiRegistry::Empty(void) const { return m_Registry.empty();}bool CNcbiRegistry::Modified(void) const{ return m_Modified;}/* Read data to reqistry from stream */void CNcbiRegistry::Read(CNcbiIstream& is, TFlags flags){ CHECK_FLAGS("Read", flags, eTransient | eNoOverride); // If to consider this read to be (unconditionally) non-modifying bool non_modifying = !m_Modified && !m_Written && x_IsAllTransient(); // Adjust flags for Set() if (flags & eTransient) { flags &= ~((TFlags) eTransient); } else { flags |= ePersistent; } string str; // the line being parsed SIZE_TYPE line; // # of the line being parsed string section; // current section name string comment; // current comment for (line = 1; NcbiGetlineEOL(is, str); line++) { SIZE_TYPE len = str.length(); SIZE_TYPE beg; for (beg = 0; beg < len && isspace(str[beg]); beg++) continue; if (beg == len) { comment += str; comment += '\n'; continue; } switch ( str[beg] ) { case '#': { // file comment m_Comment += str; m_Comment += '\n'; break; } case ';': { // comment comment += str; comment += '\n'; break; } case '[': { // section name beg++; SIZE_TYPE end = str.find_first_of(']'); if (end == NPOS) NCBI_THROW2(CRegistryException, eSection, "Invalid registry section(']' is missing): `" + str + "'", line); while ( isspace(str[beg]) ) beg++; if (str[beg] == ']') { NCBI_THROW2(CRegistryException, eSection, "Unnamed registry section: `" + str + "'", line); } for (end = beg; s_IsNameSectionSymbol(str[end]); end++) continue; section = str.substr(beg, end - beg); // an extra validity check while ( isspace(str[end]) ) end++; _ASSERT( end <= str.find_first_of(']', 0) ); if (str[end] != ']') NCBI_THROW2(CRegistryException, eSection, "Invalid registry section name: `" + str + "'", line); // add section comment if ( !comment.empty() ) { _ASSERT( s_IsNameSection(section) ); // create section if it not exist m_Registry.insert(TRegistry::value_type(section, TRegSection())); SetComment(GetComment(section) + comment, section); comment.erase(); } break; } default: { // regular entry if (!s_IsNameSectionSymbol(str[beg]) || str.find_first_of('=') == NPOS) NCBI_THROW2(CRegistryException, eEntry, "Invalid registry entry format: '" + str + "'", line); // name SIZE_TYPE mid; for (mid = beg; s_IsNameSectionSymbol(str[mid]); mid++) continue; string name = str.substr(beg, mid - beg); // '=' and surrounding spaces while ( isspace(str[mid]) ) mid++; if (str[mid] != '=') NCBI_THROW2(CRegistryException, eEntry, "Invalid registry entry name: '" + str + "'", line); for (mid++; mid < len && isspace(str[mid]); mid++) continue; _ASSERT( mid <= len ); // ? empty value if (mid == len) { if ( !(flags & eNoOverride) ) { Set(section, name, kEmptyStr, flags, comment); comment.erase(); } break; } // value string value; beg = mid; if (str[beg] == '"') beg++; bool read_next_line; do { read_next_line = false; // strip trailing spaces, check for an empty string if ( str.empty() ) break; SIZE_TYPE end; for (end = str.length() - 1; end > beg && isspace(str[end]); end--) continue; if (end < beg || isspace(str[end]) ) break; // un-escape the value for (SIZE_TYPE i = beg; i <= end; i++) { if (str[i] == '"') { if (i != end) { NCBI_THROW2(CRegistryException, eValue, "Single(unescaped) '\"' in the middle " "of registry value: '" + str + "'", line); } break; } if (str[i] != '\\') { value += str[i]; continue; } // process back-slash if (i == end) { value += '\n'; beg = 0; read_next_line = true; line++; } else if (str[i+1] == 'r') { value += '\r'; i++; } else if (str[i+1] == '\\') { value += '\\'; i++; } else if (str[i+1] == '"') { value += '"'; i++; } else { NCBI_THROW2(CRegistryException, eValue, "Badly placed '\\' in the registry " "value: '" + str + "'", line); } } } while (read_next_line && NcbiGetlineEOL(is, str)); Set(section, name, value, flags, comment); comment.erase(); } } } if ( !is.eof() ) { NCBI_THROW2(CRegistryException, eErr, "Error in reading the registry: '" + str + "'", line); } if ( non_modifying ) { m_Modified = false; }}/* Write data from reqistry to stream */bool CNcbiRegistry::Write(CNcbiOstream& os) const{ CFastMutexGuard LOCK(s_RegMutex); // write file comment if ( !s_WriteComment(os, m_Comment) ) return false; // write data ITERATE (TRegistry, section, m_Registry) { // const TRegSection& reg_section = section->second; _ASSERT( !reg_section.empty() ); // write section comment, if any TRegSection::const_iterator comm_entry = reg_section.find(kEmptyStr); if (comm_entry != reg_section.end() && !s_WriteComment(os, comm_entry->second.comment) ) { return false; } // write section header os << '[' << section->first << ']' << s_Endl; if ( !os ) return false; // write section entries ITERATE (TRegSection, entry, reg_section) { // if this entry is actually a section comment, then skip it if (entry == comm_entry) continue; // dump only persistent entries if ( entry->second.persistent.empty() ) continue; // write entry comment if ( !s_WriteComment(os, entry->second.comment) ) return false; // write next entry; escape all back-slash and new-line symbols; // add "\\i" to the beginning/end of the string if it has // spaces there os << entry->first << " = "; const char* cs = entry->second.persistent.c_str(); if (isspace(*cs) && *cs != '\n') os << '"'; for ( ; *cs; cs++) { switch ( *cs ) { case '\n': os << '\\' << s_Endl; break; case '\r': os << "\\r"; break; case '\\': os << "\\\\"; break; case '"': os << "\\\""; break; default: os << *cs; } } cs--; if (isspace(*cs) && *cs != '\n') os << '"'; os << s_Endl; if ( !os ) return false; } } m_Modified = false; m_Written = true; return true;}void CNcbiRegistry::Clear(void){ m_Modified = (m_Modified || !x_IsAllTransient()); m_Comment.erase(); m_Registry.clear();}const string& CNcbiRegistry::Get(const string& section, const string& name, TFlags flags) const{ CHECK_FLAGS("Get", flags, ePersistent); // Truncate marginal spaces of "section" and "name" // Make sure they aren't empty and consist of alpanum and '_' only string x_section = NStr::TruncateSpaces(section); if ( !s_IsNameSection(x_section) ) { _TRACE("CNcbiRegistry::Get(): bad or empty section name: " + section); return kEmptyStr; } string x_name = NStr::TruncateSpaces(name); if ( !s_IsNameSection(x_name) ) { _TRACE("CNcbiRegistry::Get(): bad or empty entry name: " + name); return kEmptyStr; } CFastMutexGuard LOCK(s_RegMutex); // find section TRegistry::const_iterator find_section = m_Registry.find(x_section); if (find_section == m_Registry.end()) return kEmptyStr; // find entry in the section const TRegSection& reg_section = find_section->second; _ASSERT( !reg_section.empty() ); TRegSection::const_iterator find_entry = reg_section.find(x_name); if (find_entry == reg_section.end()) return kEmptyStr; // ok -- found the requested entry const TRegEntry& entry = find_entry->second; _ASSERT( !entry.persistent.empty() || !entry.transient.empty() ); return ((flags & ePersistent) == 0 && !entry.transient.empty()) ? entry.transient : entry.persistent;}const string CNcbiRegistry::GetString(const string& section,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -