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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbireg.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:09:18  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.39
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbireg.cpp,v 1000.1 2004/06/01 19:09:18 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Denis Vakatov
  35.  *
  36.  * File Description:
  37.  *   Handle info in the NCBI configuration file(s):
  38.  *      read and parse config. file
  39.  *      search, edit, etc. in the retrieved configuration info
  40.  *      dump info back to config. file
  41.  *
  42.  */
  43. #include <ncbi_pch.hpp>
  44. #include <corelib/ncbireg.hpp>
  45. #include <corelib/ncbimtx.hpp>
  46. // Platform-specific EndOfLine
  47. #if   defined(NCBI_OS_MAC)
  48. const char s_Endl[] = "r";
  49. #elif defined(NCBI_OS_MSWIN)
  50. const char s_Endl[] = "rn";
  51. #else /* assume UNIX-like EOLs */
  52. const char s_Endl[] = "n";
  53. #endif
  54. BEGIN_NCBI_SCOPE
  55. #define CHECK_FLAGS(func_name, flags, allowed_flags)  do { 
  56.     if (flags & ~((TFlags)(allowed_flags))) 
  57.         _TRACE("CNcbiRegistry::" func_name "(): extra flags passed: " 
  58.                << setiosflags(IOS_BASE::hex) << flags); 
  59.     flags = flags & (TFlags)(allowed_flags); 
  60. } while (0)
  61. /* Valid symbols for a section/entry name
  62.  */
  63. inline bool s_IsNameSectionSymbol(char ch)
  64. {
  65.     return (isalnum(ch)  ||  ch == '_'  ||  ch == '-'  ||  ch == '.');
  66. }
  67. /* Check if "str" consists of alphanumeric and '_' only
  68.  */
  69. static bool s_IsNameSection(const string& str)
  70. {
  71.     if ( str.empty() )
  72.         return false;
  73.     ITERATE (string, it, str) {
  74.         if ( !s_IsNameSectionSymbol(*it) )
  75.             return false;
  76.     }
  77.     return true;
  78. }
  79. /* Convert "comment" from plain text to comment
  80.  */
  81. static const string s_ConvertComment(const string& comment,
  82.                                      bool is_file_comment = false)
  83. {
  84.     if ( !comment.length() )
  85.         return kEmptyStr;
  86.     string x_comment;
  87.     const char c_comment = is_file_comment ? '#' : ';';
  88.     SIZE_TYPE endl_pos = 0;
  89.     for (SIZE_TYPE beg = 0;  beg < comment.length();
  90.          beg = endl_pos + 1) {
  91.         SIZE_TYPE pos = comment.find_first_not_of(" t", beg);
  92.         endl_pos = comment.find_first_of("n", beg);
  93.         if (endl_pos == NPOS) {
  94.             endl_pos = comment.length();
  95.         }
  96.         if (((pos != NPOS  &&  comment[pos] != c_comment) ||
  97.              (pos == NPOS  &&  endl_pos == comment.length())) &&
  98.             (is_file_comment  ||  beg != endl_pos) ) {
  99.             x_comment += c_comment;
  100.         }
  101.         x_comment.append(comment, beg, endl_pos - beg);
  102.         x_comment += 'n';
  103.     }
  104.     return x_comment;
  105. }
  106. /* Dump the comment to stream "os"
  107.  */
  108. static bool s_WriteComment(CNcbiOstream& os, const string& comment)
  109. {
  110.     if (!comment.length())
  111.         return true;
  112.     if (strcmp(s_Endl, "n") == 0) {
  113.         os << comment;
  114.     } else {
  115.         ITERATE(string, i, comment) {
  116.             if (*i == 'n') {
  117.                 os << s_Endl;
  118.             } else {
  119.                 os << *i;
  120.             }
  121.         }
  122.     }
  123.     return os.good();
  124. }
  125. // Protective mutex for registry Get() and Set() functions
  126. DEFINE_STATIC_FAST_MUTEX(s_RegMutex);
  127. CNcbiRegistry::CNcbiRegistry(void)
  128.     : m_Modified(false), m_Written(false)
  129. {
  130.     return;
  131. }
  132. CNcbiRegistry::~CNcbiRegistry(void)
  133. {
  134.     return;
  135. }
  136. CNcbiRegistry::CNcbiRegistry(CNcbiIstream& is, TFlags flags)
  137.     : m_Modified(false), m_Written(false)
  138. {
  139.     CHECK_FLAGS("CNcbiRegistry", flags, eTransient);
  140.     Read(is, flags);
  141. }
  142. bool CNcbiRegistry::Empty(void) const {
  143.     return m_Registry.empty();
  144. }
  145. bool CNcbiRegistry::Modified(void) const
  146. {
  147.     return m_Modified;
  148. }
  149. /* Read data to reqistry from stream
  150.  */
  151. void CNcbiRegistry::Read(CNcbiIstream& is, TFlags flags)
  152. {
  153.     CHECK_FLAGS("Read", flags, eTransient | eNoOverride);
  154.     // If to consider this read to be (unconditionally) non-modifying
  155.     bool non_modifying = !m_Modified  &&  !m_Written  &&  x_IsAllTransient();
  156.     // Adjust flags for Set()
  157.     if (flags & eTransient) {
  158.         flags &= ~((TFlags) eTransient);
  159.     } else {
  160.         flags |= ePersistent;
  161.     }
  162.     string    str;          // the line being parsed
  163.     SIZE_TYPE line;         // # of the line being parsed
  164.     string    section;      // current section name
  165.     string    comment;      // current comment
  166.     for (line = 1;  NcbiGetlineEOL(is, str);  line++) {
  167.         SIZE_TYPE len = str.length();
  168.         SIZE_TYPE beg;
  169.         for (beg = 0;  beg < len  &&  isspace(str[beg]);  beg++)
  170.             continue;
  171.         if (beg == len) {
  172.             comment += str;
  173.             comment += 'n';
  174.             continue;
  175.         }
  176.         switch ( str[beg] ) {
  177.         case '#':  { // file comment
  178.             m_Comment += str;
  179.             m_Comment += 'n';
  180.             break;
  181.         }
  182.         case ';':  { // comment
  183.             comment += str;
  184.             comment += 'n';
  185.             break;
  186.         }
  187.         case '[':  { // section name
  188.             beg++;
  189.             SIZE_TYPE end = str.find_first_of(']');
  190.             if (end == NPOS)
  191.                 NCBI_THROW2(CRegistryException, eSection,
  192.                             "Invalid registry section(']' is missing): `"
  193.                             + str + "'", line);
  194.             while ( isspace(str[beg]) )
  195.                 beg++;
  196.             if (str[beg] == ']') {
  197.                 NCBI_THROW2(CRegistryException, eSection,
  198.                             "Unnamed registry section: `" + str + "'", line);
  199.             }
  200.             for (end = beg;  s_IsNameSectionSymbol(str[end]);  end++)
  201.                 continue;
  202.             section = str.substr(beg, end - beg);
  203.             // an extra validity check
  204.             while ( isspace(str[end]) )
  205.                 end++;
  206.             _ASSERT( end <= str.find_first_of(']', 0) );
  207.             if (str[end] != ']')
  208.                 NCBI_THROW2(CRegistryException, eSection,
  209.                             "Invalid registry section name: `"
  210.                             + str + "'", line);
  211.             // add section comment
  212.             if ( !comment.empty() ) {
  213.                 _ASSERT( s_IsNameSection(section) );
  214.                 // create section if it not exist
  215.                 m_Registry.insert(TRegistry::value_type(section,
  216.                                                         TRegSection()));
  217.                 SetComment(GetComment(section) + comment, section);
  218.                 comment.erase();
  219.             }
  220.             break;
  221.         }
  222.         default:  { // regular entry
  223.             if (!s_IsNameSectionSymbol(str[beg])  ||
  224.                 str.find_first_of('=') == NPOS)
  225.                 NCBI_THROW2(CRegistryException, eEntry,
  226.                             "Invalid registry entry format: '" + str + "'",
  227.                             line);
  228.             // name
  229.             SIZE_TYPE mid;
  230.             for (mid = beg;  s_IsNameSectionSymbol(str[mid]);  mid++)
  231.                 continue;
  232.             string name = str.substr(beg, mid - beg);
  233.             // '=' and surrounding spaces
  234.             while ( isspace(str[mid]) )
  235.                 mid++;
  236.             if (str[mid] != '=')
  237.                 NCBI_THROW2(CRegistryException, eEntry,
  238.                             "Invalid registry entry name: '" + str + "'",
  239.                             line);
  240.             for (mid++;  mid < len  &&  isspace(str[mid]);  mid++)
  241.                 continue;
  242.             _ASSERT( mid <= len );
  243.             // ? empty value
  244.             if (mid == len) {
  245.                 if ( !(flags & eNoOverride) ) {
  246.                     Set(section, name, kEmptyStr, flags, comment);
  247.                     comment.erase();
  248.                 }
  249.                 break;
  250.             }
  251.             // value
  252.             string value;
  253.             beg = mid;
  254.             if (str[beg] == '"')
  255.                 beg++;
  256.             bool read_next_line;
  257.             do {
  258.                 read_next_line = false;
  259.                 // strip trailing spaces, check for an empty string
  260.                 if ( str.empty() )
  261.                     break;
  262.                 SIZE_TYPE end;
  263.                 for (end = str.length() - 1;
  264.                      end > beg  &&  isspace(str[end]);  end--)
  265.                     continue;
  266.                 if (end < beg  ||  isspace(str[end]) )
  267.                     break;
  268.                 // un-escape the value
  269.                 for (SIZE_TYPE i = beg;  i <= end;  i++) {
  270.                     if (str[i] == '"') {
  271.                         if (i != end) {
  272.                             NCBI_THROW2(CRegistryException, eValue,
  273.                                         "Single(unescaped) '"' in the middle "
  274.                                         "of registry value: '" + str + "'",
  275.                                         line);
  276.                         }
  277.                         break;
  278.                     }
  279.                     if (str[i] != '\') {
  280.                         value += str[i];
  281.                         continue;
  282.                     }
  283.                     // process back-slash
  284.                     if (i == end) {
  285.                         value += 'n';
  286.                         beg = 0;
  287.                         read_next_line = true;
  288.                         line++;
  289.                     } else if (str[i+1] == 'r') {
  290.                         value += 'r';
  291.                         i++;
  292.                     } else if (str[i+1] == '\') {
  293.                         value += '\';
  294.                         i++;
  295.                     } else if (str[i+1] == '"') {
  296.                         value += '"';
  297.                         i++;
  298.                     } else {
  299.                         NCBI_THROW2(CRegistryException, eValue,
  300.                                     "Badly placed '\' in the registry "
  301.                                     "value: '" + str + "'", line);
  302.                     }
  303.                 }
  304.             } while (read_next_line  &&  NcbiGetlineEOL(is, str));
  305.             Set(section, name, value, flags, comment);
  306.             comment.erase();
  307.         }
  308.         }
  309.     }
  310.     if ( !is.eof() ) {
  311.         NCBI_THROW2(CRegistryException, eErr,
  312.                     "Error in reading the registry: '" + str + "'", line);
  313.     }
  314.     if ( non_modifying ) {
  315.         m_Modified = false;
  316.     }
  317. }
  318. /* Write data from reqistry to stream
  319.  */
  320. bool CNcbiRegistry::Write(CNcbiOstream& os)
  321.     const
  322. {
  323.     CFastMutexGuard LOCK(s_RegMutex);
  324.     // write file comment
  325.     if ( !s_WriteComment(os, m_Comment) )
  326.         return false;
  327.     // write data
  328.     ITERATE (TRegistry, section, m_Registry) {
  329.         //
  330.         const TRegSection& reg_section = section->second;
  331.         _ASSERT( !reg_section.empty() );
  332.         // write section comment, if any
  333.         TRegSection::const_iterator comm_entry = reg_section.find(kEmptyStr);
  334.         if (comm_entry != reg_section.end()  &&
  335.             !s_WriteComment(os, comm_entry->second.comment) ) {
  336.             return false;
  337.         }
  338.         // write section header
  339.         os << '[' << section->first << ']' << s_Endl;
  340.         if ( !os )
  341.             return false;
  342.         // write section entries
  343.         ITERATE (TRegSection, entry, reg_section) {
  344.             // if this entry is actually a section comment, then skip it
  345.             if (entry == comm_entry)
  346.                 continue;
  347.             // dump only persistent entries
  348.             if ( entry->second.persistent.empty() )
  349.                 continue;
  350.             // write entry comment
  351.             if ( !s_WriteComment(os, entry->second.comment) )
  352.                 return false;
  353.             // write next entry;  escape all back-slash and new-line symbols;
  354.             // add "\i" to the beginning/end of the string if it has
  355.             // spaces there
  356.             os << entry->first << " = ";
  357.             const char* cs = entry->second.persistent.c_str();
  358.             if (isspace(*cs)  &&  *cs != 'n')
  359.                 os << '"';
  360.             for ( ;  *cs;  cs++) {
  361.                 switch ( *cs ) {
  362.                 case 'n':
  363.                     os << '\' << s_Endl;  break;
  364.                 case 'r':
  365.                     os << "\r";  break;
  366.                 case '\':
  367.                     os << "\\";  break;
  368.                 case '"':
  369.                     os << "\"";  break;
  370.                 default:
  371.                     os << *cs;
  372.                 }
  373.             }
  374.             cs--;
  375.             if (isspace(*cs)  &&  *cs != 'n')
  376.                 os << '"';
  377.             os << s_Endl;
  378.             if ( !os )
  379.                 return false;
  380.         }
  381.     }
  382.     m_Modified = false;
  383.     m_Written  = true;
  384.     return true;
  385. }
  386. void CNcbiRegistry::Clear(void)
  387. {
  388.     m_Modified = (m_Modified  ||  !x_IsAllTransient());
  389.     m_Comment.erase();
  390.     m_Registry.clear();
  391. }
  392. const string& CNcbiRegistry::Get(const string& section, const string& name,
  393.                                  TFlags flags)
  394.     const
  395. {
  396.     CHECK_FLAGS("Get", flags, ePersistent);
  397.     // Truncate marginal spaces of "section" and "name"
  398.     // Make sure they aren't empty and consist of alpanum and '_' only
  399.     string x_section = NStr::TruncateSpaces(section);
  400.     if ( !s_IsNameSection(x_section) ) {
  401.         _TRACE("CNcbiRegistry::Get():  bad or empty section name: " + section);
  402.         return kEmptyStr;
  403.     }
  404.     string x_name = NStr::TruncateSpaces(name);
  405.     if ( !s_IsNameSection(x_name) ) {
  406.         _TRACE("CNcbiRegistry::Get():  bad or empty entry name: " + name);
  407.         return kEmptyStr;
  408.     }
  409.     CFastMutexGuard LOCK(s_RegMutex);
  410.     // find section
  411.     TRegistry::const_iterator find_section = m_Registry.find(x_section);
  412.     if (find_section == m_Registry.end())
  413.         return kEmptyStr;
  414.     // find entry in the section
  415.     const TRegSection& reg_section = find_section->second;
  416.     _ASSERT( !reg_section.empty() );
  417.     TRegSection::const_iterator find_entry = reg_section.find(x_name);
  418.     if (find_entry == reg_section.end())
  419.         return kEmptyStr;
  420.     // ok -- found the requested entry
  421.     const TRegEntry& entry = find_entry->second;
  422.     _ASSERT( !entry.persistent.empty()  ||  !entry.transient.empty() );
  423.     return ((flags & ePersistent) == 0  &&  !entry.transient.empty()) ?
  424.         entry.transient : entry.persistent;
  425. }
  426. const string CNcbiRegistry::GetString
  427. (const string& section,
  428.  const string& name,
  429.  const string& default_value,
  430.  TFlags        flags)
  431.     const
  432. {
  433.     const string& value = Get(section, name, flags);
  434.     return value.empty() ? default_value : value;
  435. }
  436. int CNcbiRegistry::GetInt
  437. (const string& section,
  438.  const string& name,
  439.  int           default_value,
  440.  TFlags        flags,
  441.  EErrAction    err_action)
  442.     const
  443. {
  444.     const string& value = Get(section, name, flags);
  445.     if ( value.empty() )
  446.         return default_value;
  447.     try {
  448.         return NStr::StringToInt(value);
  449.     } catch (CStringException& ex) {
  450.         if (err_action == eReturn) 
  451.             return default_value;
  452.         string msg = "CNcbiRegistry::GetInt()";
  453.         msg += " Reg entry:" + section + ":" + name;
  454.         if (err_action == eThrow)
  455.             NCBI_RETHROW_SAME(ex, msg);
  456.         if (err_action == eErrPost)
  457.             ERR_POST(ex.what() << msg);
  458.         return default_value;
  459.     }
  460. }
  461. bool CNcbiRegistry::GetBool
  462. (const string& section,
  463.  const string& name,
  464.  bool          default_value,
  465.  TFlags        flags,
  466.  EErrAction    err_action)
  467.     const
  468. {
  469.     const string& value = Get(section, name, flags);
  470.     if ( value.empty() )
  471.         return default_value;
  472.     try {
  473.         return NStr::StringToBool(value);
  474.     } catch (CStringException& ex) {
  475.         if (err_action == eReturn) 
  476.             return default_value;
  477.         string msg = "CNcbiRegistry::GetBool()";
  478.         msg += " Reg entry:" + section + ":" + name;
  479.         if (err_action == eThrow)
  480.             NCBI_RETHROW_SAME(ex, msg);
  481.         if (err_action == eErrPost)
  482.             ERR_POST(ex.what() << msg);
  483.         return default_value;
  484.     }
  485. }
  486. double CNcbiRegistry::GetDouble
  487. (const string& section,
  488.  const string& name,
  489.  double        default_value,
  490.  TFlags        flags,
  491.  EErrAction    err_action)
  492.     const
  493. {
  494.     const string& value = Get(section, name, flags);
  495.     if ( value.empty() )
  496.         return default_value;
  497.     try {
  498.         return NStr::StringToDouble(value);
  499.     } catch (CStringException& ex) {
  500.         if (err_action == eReturn) 
  501.             return default_value;
  502.         string msg = "CNcbiRegistry::GetDouble()";
  503.         msg += " Reg entry:" + section + ":" + name;
  504.         if (err_action == eThrow)
  505.             NCBI_RETHROW_SAME(ex, msg);
  506.         if (err_action == eErrPost)
  507.             ERR_POST(ex.what() << msg);
  508.         return default_value;
  509.     }
  510. }
  511. bool CNcbiRegistry::Set(const string& section, const string& name,
  512.                         const string& value, TFlags flags,
  513.                         const string& comment)
  514. {
  515.     CHECK_FLAGS("Set", flags, ePersistent | eNoOverride | eTruncate);
  516.     // Truncate marginal spaces of "section" and "name"
  517.     // Make sure they aren't empty and consist of alpanum and '_' only
  518.     string x_section = NStr::TruncateSpaces(section);
  519.     if ( !s_IsNameSection(x_section) ) {
  520.         _TRACE("CNcbiRegistry::Set():  bad or empty section name: " + section);
  521.         return false;
  522.     }
  523.     string x_name = NStr::TruncateSpaces(name);
  524.     // is the entry name valid ?
  525.     if ( !s_IsNameSection(x_name) ) {
  526.         _TRACE("CNcbiRegistry::Set():  bad or empty entry name: " + name);
  527.         return false;
  528.     }
  529.     // MT-protect everything down the function code
  530.     CFastMutexGuard LOCK(s_RegMutex);
  531.     // find section
  532.     TRegistry::iterator find_section = m_Registry.find(x_section);
  533.     if (find_section == m_Registry.end()) {
  534.         if ( value.empty() )  // the "unset" case
  535.             return false;
  536.         // new section, new entry
  537.         x_SetValue(m_Registry[x_section][x_name], value, flags, comment);
  538.         return true;
  539.     }
  540.     // find entry within the found section
  541.     TRegSection& reg_section = find_section->second;
  542.     _ASSERT( !reg_section.empty() );
  543.     TRegSection::iterator find_entry = reg_section.find(x_name);
  544.     if (find_entry == reg_section.end()) {
  545.         if ( value.empty() )  // the "unset" case
  546.             return false;
  547.         // new entry
  548.         x_SetValue(reg_section[x_name], value, flags, comment);
  549.         return true;
  550.     }
  551.     // modifying an existing entry...
  552.     if (flags & eNoOverride)
  553.         return false;  // cannot override
  554.     TRegEntry& entry = find_entry->second;
  555.     // check if it tries to unset an already unset value
  556.     bool transient = (flags & ePersistent) == 0;
  557.     if (value.empty()  &&
  558.         (( transient  &&  entry.transient.empty())  ||
  559.          (!transient  &&  entry.persistent.empty())))
  560.         return false;
  561.     // modify an existing entry
  562.     x_SetValue(entry, value, flags, comment);
  563.     // unset(remove) the entry, if empty
  564.     if (entry.persistent.empty()  &&  entry.transient.empty()) {
  565.         reg_section.erase(find_entry);
  566.         // remove the section, if empty
  567.         if (reg_section.empty() ) {
  568.             m_Registry.erase(find_section);
  569.         }
  570.     }
  571.     return true;
  572. }
  573. bool CNcbiRegistry::SetComment(const string& comment, const string& section,
  574.                                const string& name)
  575. {
  576.     CFastMutexGuard LOCK(s_RegMutex);
  577.     // If "section" is empty string, then set as the registry comment
  578.     string x_section = NStr::TruncateSpaces(section);
  579.     if (x_section == kEmptyStr) {
  580.         m_Comment = s_ConvertComment(comment, true);
  581.         m_Modified = true;
  582.         return true;
  583.     }
  584.     // Find section
  585.     TRegistry::iterator find_section = m_Registry.find(x_section);
  586.     if (find_section == m_Registry.end()) {
  587.         return false;
  588.     }
  589.     TRegSection& reg_section = find_section->second;
  590.     string x_name    = NStr::TruncateSpaces(name);
  591.     string x_comment = s_ConvertComment(comment);
  592.     // If "name" is empty string, then set as the "section" comment
  593.     if (name == kEmptyStr) {
  594.         TRegSection::iterator comm_entry = reg_section.find(kEmptyStr);
  595.         if (comm_entry != reg_section.end()) {
  596.             // replace old comment
  597.             comm_entry->second.comment = x_comment;
  598.             m_Modified = true;
  599.         } else {
  600.             // new comment
  601.             x_SetValue(m_Registry[x_section][kEmptyStr],
  602.                        kEmptyStr, ePersistent, x_comment);
  603.         }
  604.         return true;
  605.     }
  606.     // This is an entry comment
  607.     _ASSERT( !reg_section.empty() );
  608.     TRegSection::iterator find_entry = reg_section.find(x_name);
  609.     if (find_entry == reg_section.end())
  610.         return false;
  611.     // (Re)set entry comment
  612.     find_entry->second.comment = x_comment;
  613.     m_Modified = true;
  614.     return true;
  615. }
  616. const string& CNcbiRegistry::GetComment(const string& section,
  617.                                         const string& name)
  618.     const
  619. {
  620.     CFastMutexGuard LOCK(s_RegMutex);
  621.     // If "section" is empty string, then get the registry's comment.
  622.     string x_section = NStr::TruncateSpaces(section);
  623.     if (x_section == kEmptyStr) {
  624.         return m_Comment;
  625.     }
  626.     // Find section
  627.     TRegistry::const_iterator find_section = m_Registry.find(x_section);
  628.     if (find_section == m_Registry.end()) {
  629.         return kEmptyStr;
  630.     }
  631.     const TRegSection& reg_section = find_section->second;
  632.     // If "name" is empty string, then get "section"'s comment.
  633.     string x_name = NStr::TruncateSpaces(name);
  634.     if (x_name == kEmptyStr) {
  635.         TRegSection::const_iterator comm_entry = reg_section.find(kEmptyStr);
  636.         if (comm_entry == reg_section.end()) {
  637.             return kEmptyStr;
  638.         }
  639.         return comm_entry->second.comment;
  640.     }
  641.     // Get "section:entry"'s comment
  642.     _ASSERT( !reg_section.empty() );
  643.     TRegSection::const_iterator find_entry = reg_section.find(x_name);
  644.     if (find_entry == reg_section.end()) {
  645.         return kEmptyStr;
  646.     }
  647.     return find_entry->second.comment;
  648. }
  649. void CNcbiRegistry::EnumerateSections(list<string>* sections)
  650.     const
  651. {
  652.     CFastMutexGuard LOCK(s_RegMutex);
  653.     sections->clear();
  654.     ITERATE (TRegistry, section, m_Registry) {
  655.         sections->push_back(section->first);
  656.     }
  657. }
  658. void CNcbiRegistry::EnumerateEntries(const string& section,
  659.                                      list<string>* entries)
  660.     const
  661. {
  662.     CFastMutexGuard LOCK(s_RegMutex);
  663.     entries->clear();
  664.     // find section
  665.     TRegistry::const_iterator find_section = m_Registry.find(section);
  666.     if (find_section == m_Registry.end())
  667.         return;
  668.     const TRegSection& reg_section = find_section->second;
  669.     _ASSERT( !reg_section.empty() );
  670.     // enumerate through the entries in the found section
  671.     ITERATE (TRegSection, entry, reg_section) {
  672.         if ( entry->first.empty() )
  673.             continue;  // skip section comment
  674.         entries->push_back(entry->first);
  675.     }
  676. }
  677. bool CNcbiRegistry::x_IsAllTransient(void)
  678.     const
  679. {
  680.     if ( !m_Comment.empty() ) {
  681.         return false;
  682.     }
  683.     ITERATE (TRegistry, section, m_Registry) {
  684.         ITERATE (TRegSection, entry, section->second) {
  685.             if (section->first.empty()  || !entry->second.persistent.empty()) {
  686.                 return false;  // section comment or non-transient entry
  687.             }
  688.         }
  689.     }
  690.     return true;
  691. }
  692. void CNcbiRegistry::x_SetValue(TRegEntry& entry, const string& value,
  693.                                TFlags flags, const string& comment)
  694. {
  695.     bool persistent = (flags & ePersistent) != 0;
  696.     if ( persistent ) {
  697.         m_Modified = true;
  698.     }
  699.     if ( !comment.empty() ) {
  700.         entry.comment = s_ConvertComment(comment);
  701.     }
  702.     string* to = persistent ? &entry.persistent : &entry.transient;
  703.     if ((flags & eTruncate) == 0  ||  value.empty()) {
  704.         *to = value;
  705.         return;
  706.     }
  707.     SIZE_TYPE beg;
  708.     for (beg = 0;
  709.          beg < value.length()  &&  isspace(value[beg])  &&  value[beg] != 'n';
  710.          beg++)
  711.         continue;
  712.     if (beg == value.length()) {
  713.         to->erase();
  714.         return;
  715.     }
  716.     SIZE_TYPE end;
  717.     for (end = value.length() - 1;
  718.          isspace(value[end])  &&  value[end] != 'n';
  719.          end--)
  720.         continue;
  721.     _ASSERT(beg <= end);
  722.     *to = value.substr(beg, end - beg + 1);
  723. }
  724. END_NCBI_SCOPE
  725. /*
  726.  * ===========================================================================
  727.  * $Log: ncbireg.cpp,v $
  728.  * Revision 1000.1  2004/06/01 19:09:18  gouriano
  729.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.39
  730.  *
  731.  * Revision 1.39  2004/05/14 13:59:27  gorelenk
  732.  * Added include of ncbi_pch.hpp
  733.  *
  734.  * Revision 1.38  2003/10/20 21:55:12  vakatov
  735.  * CNcbiRegistry::GetComment() -- make it "const"
  736.  *
  737.  * Revision 1.37  2003/06/26 18:54:48  rsmith
  738.  * fix bug where comments multiplied blank lines after them.
  739.  *
  740.  * Revision 1.36  2003/06/25 20:05:57  rsmith
  741.  * Fix small bugs setting comments
  742.  *
  743.  * Revision 1.35  2003/05/08 13:47:16  ivanov
  744.  * Fixed Read() for right handle entry names with leading spaces
  745.  *
  746.  * Revision 1.34  2003/04/07 19:40:36  ivanov
  747.  * Rollback to R1.32
  748.  *
  749.  * Revision 1.33  2003/04/07 16:08:29  ivanov
  750.  * Added more thread-safety to CNcbiRegistry:: methods -- mutex protection.
  751.  * Get() and GetComment() returns "string", not "string&".
  752.  *
  753.  * Revision 1.32  2003/03/10 18:57:08  kuznets
  754.  * iterate->ITERATE
  755.  *
  756.  * Revision 1.31  2003/02/28 19:24:51  vakatov
  757.  * Get rid of redundant "const" in the return type of GetInt/Bool/Double()
  758.  *
  759.  * Revision 1.30  2003/02/24 19:56:05  gouriano
  760.  * use template-based exceptions instead of errno and parse exceptions
  761.  *
  762.  * Revision 1.29  2003/01/17 20:45:39  kuznets
  763.  * Minor code cleanup~
  764.  *
  765.  * Revision 1.28  2003/01/17 20:27:30  kuznets
  766.  * CNcbiRegistry added ErrPost error action
  767.  *
  768.  * Revision 1.27  2003/01/17 17:31:07  vakatov
  769.  * CNcbiRegistry::GetString() to return "string", not "string&" -- for safety
  770.  *
  771.  * Revision 1.26  2002/12/30 23:23:07  vakatov
  772.  * + GetString(), GetInt(), GetBool(), GetDouble() -- with defaults,
  773.  * conversions and error handling control (to extend Get()'s functionality).
  774.  *
  775.  * Revision 1.25  2002/09/19 20:05:43  vasilche
  776.  * Safe initialization of static mutexes
  777.  *
  778.  * Revision 1.24  2002/08/01 18:43:57  ivanov
  779.  * Using NcbiGetlineEOL() instead s_NcbiGetline()
  780.  *
  781.  * Revision 1.23  2002/07/11 14:18:27  gouriano
  782.  * exceptions replaced by CNcbiException-type ones
  783.  *
  784.  * Revision 1.22  2002/04/11 21:08:03  ivanov
  785.  * CVS log moved to end of the file
  786.  *
  787.  * Revision 1.21  2001/10/29 18:55:08  ivanov
  788.  * Fixed adding blank lines at write registry file
  789.  *
  790.  * Revision 1.20  2001/09/11 00:52:51  vakatov
  791.  * Fixes to R1.17 - R1.19:
  792.  *   Renamed HasChanged() to Modified(), get rid of bugs, refined and
  793.  *   extended its functionality.
  794.  *   Made Write() be "const" again.
  795.  *   Prevent section comment from inadvertently concatenating with the
  796.  *   section name (without a new-line between them).
  797.  *   Other fixes and refinements.
  798.  *
  799.  * Revision 1.19  2001/09/10 16:34:35  ivanov
  800.  * Added method HasChanged()
  801.  *
  802.  * Revision 1.18  2001/06/26 15:20:22  ivanov
  803.  * Fixed small bug in s_ConvertComment().
  804.  * Changed method of check and create new section in Read().
  805.  *
  806.  * Revision 1.17  2001/06/22 21:49:47  ivanov
  807.  * Added (with Denis Vakatov) ability for read/write the registry file
  808.  * with comments. Also added functions GetComment() and SetComment().
  809.  *
  810.  * Revision 1.16  2001/05/17 15:04:59  lavr
  811.  * Typos corrected
  812.  *
  813.  * Revision 1.15  2001/04/09 17:39:45  grichenk
  814.  * CNcbiRegistry::Get() return type reverted to "const string&"
  815.  *
  816.  * Revision 1.14  2001/04/06 15:46:30  grichenk
  817.  * Added thread-safety to CNcbiRegistry:: methods
  818.  *
  819.  * Revision 1.13  2001/01/30 22:13:28  vakatov
  820.  * Write() -- use "s_Endl" instead of "NcbiEndl"
  821.  *
  822.  * Revision 1.12  2001/01/30 00:41:58  vakatov
  823.  * Read/Write -- serialize 'r' as "\r"
  824.  *
  825.  * Revision 1.11  2000/03/30 21:06:35  kans
  826.  * bad end of line detected on Mac
  827.  *
  828.  * Revision 1.10  1999/11/18 20:14:15  vakatov
  829.  * Get rid of some CodeWarrior(MAC) C++ compilation warnings
  830.  *
  831.  * Revision 1.9  1999/09/02 21:52:14  vakatov
  832.  * CNcbiRegistry::Read() -- fixed to accept if underscore is the 1st
  833.  * symbol in the section/entry name;
  834.  * Allow '-' and '.' in the section/entry name
  835.  *
  836.  * Revision 1.8  1999/08/30 16:00:41  vakatov
  837.  * CNcbiRegistry:: Get()/Set() -- force the "name" and "section" to
  838.  * consist of alphanumeric and '_' only;  ignore leading and trailing
  839.  * spaces
  840.  *
  841.  * Revision 1.7  1999/07/06 15:26:35  vakatov
  842.  * CNcbiRegistry::
  843.  *   - allow multi-line values
  844.  *   - allow values starting and ending with space symbols
  845.  *   - introduced EFlags/TFlags for optional parameters in the class
  846.  *     member functions -- rather than former numerous boolean parameters
  847.  *
  848.  * Revision 1.6  1998/12/28 17:56:37  vakatov
  849.  * New CVS and development tree structure for the NCBI C++ projects
  850.  *
  851.  * Revision 1.5  1998/12/10 22:59:47  vakatov
  852.  * CNcbiRegistry:: API is ready(and by-and-large tested)
  853.  * ===========================================================================
  854.  */