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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: fileutil.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:43:09  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.28
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: fileutil.cpp,v 1000.1 2004/06/01 19:43:09 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: Eugene Vasilchenko
  35. *
  36. * File Description:
  37. *   Some file utilities functions/classes.
  38. */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbistre.hpp>
  41. #include <corelib/ncbiutil.hpp>
  42. #include <corelib/ncbifile.hpp>
  43. #include <serial/datatool/fileutil.hpp>
  44. #include <serial/datatool/srcutil.hpp>
  45. #include <set>
  46. BEGIN_NCBI_SCOPE
  47. static const int BUFFER_SIZE = 4096;
  48. SourceFile::SourceFile(const string& name, bool binary)
  49.     : m_StreamPtr(0), m_Open(false)
  50. {
  51.     if ( name == "stdin" || name == "-" ) {
  52.         m_StreamPtr = &NcbiCin;
  53.     }
  54.     else {
  55.         if ( !x_Open(name, binary) )
  56.             ERR_POST(Fatal << "cannot open file " << name);
  57.     }
  58. }
  59. SourceFile::SourceFile(const string& name, const list<string>& dirs,
  60.                        bool binary)
  61. {
  62.     if ( name == "stdin" || name == "-" ) {
  63.         m_StreamPtr = &NcbiCin;
  64.     } else if ( !x_Open(name, binary) ) {
  65.         ITERATE(list<string>, dir, dirs) {
  66.             if ( x_Open(Path(*dir, name), binary) ) {
  67.                 return;
  68.             }
  69.         }
  70.         ERR_POST(Fatal << "cannot open file " << name);
  71.     }
  72. }
  73. SourceFile::~SourceFile(void)
  74. {
  75.     if ( m_Open ) {
  76.         delete m_StreamPtr;
  77.         m_StreamPtr = 0;
  78.         m_Open = false;
  79.     }
  80. }
  81. SourceFile::EType SourceFile::GetType(void) const
  82. {
  83.     CDirEntry entry(m_Name);
  84.     string ext(entry.GetExt());
  85.     if (NStr::CompareNocase(ext,".asn") == 0) {
  86.         return eASN;
  87.     } else if (NStr::CompareNocase(ext,".dtd") == 0) {
  88.         return eDTD;
  89.     }
  90.     return eUnknown;
  91. }
  92. bool SourceFile::x_Open(const string& name, bool binary)
  93. {
  94.     m_Name = name;
  95.     m_StreamPtr = new CNcbiIfstream(name.c_str(),
  96.                                     binary?
  97.                                         IOS_BASE::in | IOS_BASE::binary:
  98.                                         IOS_BASE::in);
  99.     m_Open = m_StreamPtr->good();
  100.     if ( !m_Open ) {
  101.         delete m_StreamPtr;
  102.         m_StreamPtr = 0;
  103.     }
  104.     return m_Open;
  105. }
  106. DestinationFile::DestinationFile(const string& name, bool binary)
  107. {
  108.     if ( name == "stdout" || name == "-" ) {
  109.         m_StreamPtr = &NcbiCout;
  110.         m_Open = false;
  111.     }
  112.     else {
  113.         m_StreamPtr = new CNcbiOfstream(name.c_str(),
  114.                                         binary?
  115.                                             IOS_BASE::out | IOS_BASE::binary:
  116.                                             IOS_BASE::out);
  117.         if ( !*m_StreamPtr ) {
  118.             delete m_StreamPtr;
  119.             m_StreamPtr = 0;
  120.             ERR_POST(Fatal << "cannot open file " << name);
  121.         }
  122.         m_Open = true;
  123.     }
  124. }
  125. DestinationFile::~DestinationFile(void)
  126. {
  127.     if ( m_Open ) {
  128.         delete m_StreamPtr;
  129.     }
  130. }
  131. // default parameters
  132. #undef DIR_SEPARATOR_CHAR
  133. #undef DIR_SEPARATOR_CHAR2
  134. #undef DISK_SEPARATOR_CHAR
  135. #undef ALL_SEPARATOR_CHARS
  136. #define PARENT_DIR ".."
  137. #ifdef NCBI_OS_MSWIN
  138. #  define DIR_SEPARATOR_CHAR '\'
  139. #  define DIR_SEPARATOR_CHAR2 '/'
  140. #  define DISK_SEPARATOR_CHAR ':'
  141. #  define ALL_SEPARATOR_CHARS ":/\"
  142. #endif
  143. #ifdef NCBI_OS_MAC
  144. #  define DIR_SEPARATOR_CHAR ':'
  145. #  undef PARENT_DIR
  146. #endif
  147. #ifndef DIR_SEPARATOR_CHAR
  148. #  define DIR_SEPARATOR_CHAR '/'
  149. #endif
  150. #ifndef ALL_SEPARATOR_CHARS
  151. #  define ALL_SEPARATOR_CHARS DIR_SEPARATOR_CHAR
  152. #endif
  153. inline
  154. bool IsDiskSeparator(char c)
  155. {
  156. #ifdef DISK_SEPARATOR_CHAR
  157.     if ( c == DISK_SEPARATOR_CHAR )
  158.         return true;
  159. #endif
  160.     return false;
  161. }
  162. inline
  163. bool IsDirSeparator(char c)
  164. {
  165. #ifdef DISK_SEPARATOR_CHAR
  166.     if ( c == DISK_SEPARATOR_CHAR )
  167.         return true;
  168. #endif
  169. #ifdef DIR_SEPARATOR_CHAR2
  170.     if ( c == DIR_SEPARATOR_CHAR2 )
  171.         return true;
  172. #endif
  173.     return c == DIR_SEPARATOR_CHAR;
  174. }
  175. bool IsLocalPath(const string& path)
  176. {
  177.     // determine if path is local to current directory
  178.     // exclude pathes like:
  179.     // "../xxx" everywhere
  180.     // "xxx/../yyy" everywhere
  181.     // "/xxx/yyy"  on unix
  182.     // "d:xxx" on windows
  183.     // "HD:folder" on Mac
  184.     if ( path.empty() )
  185.         return false;
  186. #ifdef NCBI_OS_MAC
  187.     if (path.find(DIR_SEPARATOR_CHAR) != NPOS  &&
  188.         path[0] != DIR_SEPARATOR_CHAR)
  189.         return false;
  190. #else
  191.     if ( IsDirSeparator(path[0]) )
  192.         return false;
  193. #endif
  194.     SIZE_TYPE pos;
  195. #ifdef PARENT_DIR
  196.     SIZE_TYPE parentDirLength = strlen(PARENT_DIR);
  197.     pos = 0;
  198.     while ( (pos = path.find(PARENT_DIR, pos)) != NPOS ) {
  199.         if ( pos == 0 || IsDirSeparator(path[pos - 1]) )
  200.             return false;
  201.         SIZE_TYPE end = pos + parentDirLength;
  202.         if ( end == path.size() || IsDirSeparator(path[end]) )
  203.             return false;
  204.         pos = end + 1;
  205.     }
  206. #endif
  207. #ifdef DISK_SEPARATOR_CHAR
  208.     if ( path.find(DISK_SEPARATOR_CHAR) != NPOS )
  209.         return false;
  210. #endif
  211.     return true;
  212. }
  213. string Path(const string& dir, const string& file)
  214. {
  215.     if ( dir.empty() )
  216.         return file;
  217.     char lastChar = dir[dir.size() - 1];
  218.     if ( file.empty() )
  219.         _TRACE("Path("" << dir << "", "" << file << "")");
  220.     // Avoid duplicate dir separators
  221.     if ( IsDirSeparator(lastChar) ) {
  222.         if ( IsDirSeparator(file[0]) )
  223.             return dir.substr(0, dir.size()-1) + file;
  224.     }
  225.     else {
  226.         if ( !IsDirSeparator(file[0]) )
  227.             return dir + DIR_SEPARATOR_CHAR + file;
  228.     }
  229.     return dir + file;
  230. }
  231. string BaseName(const string& path)
  232. {
  233.     SIZE_TYPE dirEnd = path.find_last_of(ALL_SEPARATOR_CHARS);
  234.     string name;
  235.     if ( dirEnd != NPOS )
  236.         name = path.substr(dirEnd + 1);
  237.     else
  238.         name = path;
  239.     SIZE_TYPE extStart = name.rfind('.');
  240.     if ( extStart != NPOS )
  241.         name = name.substr(0, extStart);
  242.     return name;
  243. }
  244. string DirName(const string& path)
  245. {
  246.     SIZE_TYPE dirEnd = path.find_last_of(ALL_SEPARATOR_CHARS);
  247.     if ( dirEnd != NPOS ) {
  248.         if ( dirEnd == 0 /* "/" root directory */ ||
  249.              IsDiskSeparator(path[dirEnd]) /* disk separator */ ) 
  250.             ++dirEnd; // include separator
  251.         return path.substr(0, dirEnd);
  252.     }
  253.     else {
  254.         return NcbiEmptyString;
  255.     }
  256. }
  257. string GetStdPath(const string& path)
  258. {
  259.     string stdpath = path;
  260. #ifdef NCBI_OS_MAC
  261.     // Exlude leading ':' on Mac
  262.     if ( IsDirSeparator(stdpath[0]) ) {
  263.         stdpath = path.substr(1);
  264.     }
  265.     else {
  266.         // FIXME:  How do we translate an absolute pathname?
  267.     }
  268. #endif
  269.     // Replace each native separator character with the 'standard' one.
  270.     SIZE_TYPE ibeg = NStr::StartsWith(path, "http://", NStr::eNocase) ? 7 : 0;
  271.     for (SIZE_TYPE i=ibeg ; i < stdpath.size(); i++) {
  272.         if ( IsDirSeparator(stdpath[i]) )
  273.             stdpath[i] = '/';
  274.     }
  275.     string tmp = NStr::Replace(stdpath,"//","/",ibeg);
  276.     stdpath = NStr::Replace(tmp,"/./","/",ibeg);
  277.     return stdpath;
  278. }
  279. class SSubString
  280. {
  281. public:
  282.     SSubString(const string& value, size_t order)
  283.         : value(value), order(order)
  284.         {
  285.         }
  286.     struct ByOrder {
  287.         bool operator()(const SSubString& s1, const SSubString& s2) const
  288.             {
  289.                 return s1.order < s2.order;
  290.             }
  291.     };
  292.     struct ByLength {
  293.         bool operator()(const SSubString& s1, const SSubString& s2) const
  294.             {
  295.                 if ( s1.value.size() > s2.value.size() )
  296.                     return true;
  297.                 if ( s1.value.size() < s2.value.size() )
  298.                     return false;
  299.                 return s1.order < s2.order;
  300.             }
  301.     };
  302.     string value;
  303.     size_t order;
  304. };
  305. string MakeFileName(const string& fname, size_t addLength)
  306. {
  307.     string name = Identifier(fname);
  308.     size_t fullLength = name.size() + addLength;
  309.     if ( fullLength <= MAX_FILE_NAME_LENGTH )
  310.         return name;
  311.     size_t remove = fullLength - MAX_FILE_NAME_LENGTH;
  312.     // we'll have to truncate very long filename
  313.     _TRACE("MakeFileName(""<<fname<<"", "<<addLength<<") remove="<<remove);
  314.     // 1st step: parse name dividing by '_' sorting elements by their size
  315.     SIZE_TYPE removable = 0; // removable part of string
  316.     typedef set<SSubString, SSubString::ByLength> TByLength;
  317.     TByLength byLength;
  318.     {
  319.         SIZE_TYPE curr = 0; // current element position in string
  320.         size_t order = 0; // current element order
  321.         for (;;) {
  322.             SIZE_TYPE und = name.find('_', curr);
  323.             if ( und == NPOS ) {
  324.                 // end of string
  325.                 break;
  326.             }
  327.             _TRACE("MakeFileName: ""<<name.substr(curr, und - curr)<<""");
  328.             removable += (und - curr);
  329.             byLength.insert(SSubString(name.substr(curr, und - curr), order));
  330.             curr = und + 1;
  331.             ++order;
  332.         }
  333.         _TRACE("MakeFileName: ""<<name.substr(curr)<<""");
  334.         removable += name.size() - curr;
  335.         byLength.insert(SSubString(name.substr(curr), order));
  336.     }
  337.     _TRACE("MakeFileName: removable="<<removable);
  338.     // if removable part of string too small...
  339.     if ( removable - remove < size_t(MAX_FILE_NAME_LENGTH - addLength) / 2 ) {
  340.         // we'll do plain truncate
  341.         _TRACE("MakeFileName: return ""<<name.substr(0, MAX_FILE_NAME_LENGTH - addLength)<<""");
  342.         return name.substr(0, MAX_FILE_NAME_LENGTH - addLength);
  343.     }
  344.     
  345.     // 2nd step: shorten elementes beginning with longest
  346.     while ( remove > 0 ) {
  347.         // extract most long element
  348.         SSubString s = *byLength.begin();
  349.         _TRACE("MakeFileName: shorten ""<<s.value<<""");
  350.         byLength.erase(byLength.begin());
  351.         // shorten it by one symbol
  352.         s.value = s.value.substr(0, s.value.size() - 1);
  353.         // insert it back
  354.         byLength.insert(s);
  355.         // decrement progress counter
  356.         remove--;
  357.     }
  358.     // 3rd step: reorder elements by their relative order in original string
  359.     typedef set<SSubString, SSubString::ByOrder> TByOrder;
  360.     TByOrder byOrder;
  361.     {
  362.         ITERATE ( TByLength, i, byLength ) {
  363.             byOrder.insert(*i);
  364.         }
  365.     }
  366.     // 4th step: join elements in resulting string
  367.     name.erase();
  368.     {
  369.         ITERATE ( TByOrder, i, byOrder ) {
  370.             if ( !name.empty() )
  371.                 name += '_';
  372.             name += i->value;
  373.         }
  374.     }
  375.     _TRACE("MakeFileName: return ""<<name<<""");
  376.     return name;
  377. }
  378. CDelayedOfstream::CDelayedOfstream(const string& fileName)
  379. {
  380.     open(fileName);
  381. }
  382. CDelayedOfstream::~CDelayedOfstream(void)
  383. {
  384.     close();
  385. }
  386. void CDelayedOfstream::open(const string& fileName)
  387. {
  388.     close();
  389.     clear();
  390.     seekp(0, IOS_BASE::beg);
  391.     clear(); // eof set?
  392.     m_FileName = fileName;
  393.     m_Istream.reset(new CNcbiIfstream(fileName.c_str()));
  394.     if ( !*m_Istream ) {
  395.         _TRACE("cannot open " << m_FileName);
  396.         m_Istream.reset(0);
  397.         m_Ostream.reset(new CNcbiOfstream(fileName.c_str()));
  398.         if ( !*m_Ostream ) {
  399.             _TRACE("cannot create " << m_FileName);
  400.             setstate(m_Ostream->rdstate());
  401.             m_Ostream.reset(0);
  402.             m_FileName.erase();
  403.         }
  404.     }
  405. }
  406. void CDelayedOfstream::close(void)
  407. {
  408.     if ( !is_open() )
  409.         return;
  410.     if ( !equals() ) {
  411.         if ( !rewrite() )
  412.             setstate(m_Ostream->rdstate());
  413.         m_Ostream.reset(0);
  414.     }
  415.     m_Istream.reset(0);
  416.     m_FileName.erase();
  417. }
  418. bool CDelayedOfstream::equals(void)
  419. {
  420.     if ( !m_Istream.get() )
  421.         return false;
  422.     streamsize count = pcount();
  423.     const char* ptr = str();
  424.     freeze(false);
  425.     while ( count > 0 ) {
  426.         char buffer[BUFFER_SIZE];
  427.         streamsize c = count;
  428.         if ( c > BUFFER_SIZE )
  429.             c = BUFFER_SIZE;
  430.         if ( !m_Istream->read(buffer, c) ) {
  431.             _TRACE("read fault " << m_FileName <<
  432.                    " need: " << c << " was: " << m_Istream->gcount());
  433.             return false;
  434.         }
  435.         if ( memcmp(buffer, ptr, c) != 0 ) {
  436.             _TRACE("file differs " << m_FileName);
  437.             return false;
  438.         }
  439.         ptr += c;
  440.         count -= c;
  441.     }
  442.     if ( m_Istream->get() != -1 ) {
  443.         _TRACE("file too long " << m_FileName);
  444.         return false;
  445.     }
  446.     return true;
  447. }
  448. bool CDelayedOfstream::rewrite(void)
  449. {
  450.     if ( !m_Ostream.get() ) {
  451.         m_Ostream.reset(new CNcbiOfstream(m_FileName.c_str()));
  452.         if ( !*m_Ostream ) {
  453.             _TRACE("rewrite fault " << m_FileName);
  454.             return false;
  455.         }
  456.     }
  457.     streamsize count = pcount();
  458.     const char* ptr = str();
  459.     freeze(false);
  460.     if ( !m_Ostream->write(ptr, count) ) {
  461.         _TRACE("write fault " << m_FileName);
  462.         return false;
  463.     }
  464.     m_Ostream->close();
  465.     if ( !*m_Ostream ) {
  466.         _TRACE("close fault " << m_FileName);
  467.         return false;
  468.     }
  469.     return true;
  470. }
  471. bool Empty(const CNcbiOstrstream& src)
  472. {
  473.     return const_cast<CNcbiOstrstream&>(src).pcount() == 0;
  474. }
  475. CNcbiOstream& Write(CNcbiOstream& out, const CNcbiOstrstream& src)
  476. {
  477.     CNcbiOstrstream& source = const_cast<CNcbiOstrstream&>(src);
  478.     size_t size = source.pcount();
  479.     if ( size != 0 ) {
  480.         out.write(source.str(), size);
  481.         source.freeze(false);
  482.     }
  483.     return out;
  484. }
  485. CNcbiOstream& WriteTabbed(CNcbiOstream& out, const CNcbiOstrstream& code,
  486.                           const char* tab)
  487. {
  488.     CNcbiOstrstream& source = const_cast<CNcbiOstrstream&>(code);
  489.     size_t size = source.pcount();
  490.     if ( size != 0 ) {
  491.         if ( !tab )
  492.             tab = "    ";
  493.         const char* ptr = source.str();
  494.         source.freeze(false);
  495.         while ( size > 0 ) {
  496.             out << tab;
  497.             const char* endl =
  498.                 reinterpret_cast<const char*>(memchr(ptr, 'n', size));
  499.             if ( !endl ) { // no more 'n'
  500.                 out.write(ptr, size) << 'n';
  501.                 break;
  502.             }
  503.             ++endl; // skip 'n'
  504.             size_t lineSize = endl - ptr;
  505.             out.write(ptr, lineSize);
  506.             ptr = endl;
  507.             size -= lineSize;
  508.         }
  509.     }
  510.     return out;
  511. }
  512. END_NCBI_SCOPE
  513. /*
  514. *
  515. * ---------------------------------------------------------------------------
  516. * $Log: fileutil.cpp,v $
  517. * Revision 1000.1  2004/06/01 19:43:09  gouriano
  518. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.28
  519. *
  520. * Revision 1.28  2004/05/17 21:03:14  gorelenk
  521. * Added include of PCH ncbi_pch.hpp
  522. *
  523. * Revision 1.27  2004/04/29 20:12:36  gouriano
  524. * GetStdPath tweaked
  525. *
  526. * Revision 1.26  2003/03/11 20:06:47  kuznets
  527. * iterate -> ITERATE
  528. *
  529. * Revision 1.25  2002/10/15 13:54:58  gouriano
  530. * addded "GetType" method - module file type by extension
  531. *
  532. * Revision 1.24  2002/08/06 17:03:49  ucko
  533. * Let -opm take a comma-delimited list; move relevant CVS logs to end.
  534. *
  535. * Revision 1.23  2001/09/19 19:03:59  ucko
  536. * Use SIZE_TYPE to index strings.
  537. *
  538. * Revision 1.22  2001/08/31 20:05:46  ucko
  539. * Fix ICC build.
  540. *
  541. * Revision 1.21  2001/08/16 13:19:26  grichenk
  542. * Removed extra-defines for MAC, rearranged code for MAC paths
  543. *
  544. * Revision 1.20  2001/08/15 20:26:32  juran
  545. * Correctly assemble Mac pathnames.  (Omit duplicate ':'.)
  546. * IsLocalPath(): A Mac pathname beginning with ':' is relative.
  547. * GetStdPath(): Convert native pathnames to unix-style.
  548. *
  549. * Revision 1.19  2001/05/17 15:07:12  lavr
  550. * Typos corrected
  551. *
  552. * Revision 1.18  2001/02/02 20:50:35  vasilche
  553. * Fixed defines on Mac
  554. *
  555. * Revision 1.17  2001/02/02 16:20:00  vasilche
  556. * Fixed file path processing on Mac
  557. *
  558. * Revision 1.16  2000/11/29 17:42:44  vasilche
  559. * Added CComment class for storing/printing ASN.1/XML module comments.
  560. * Added srcutil.hpp file to reduce file dependency.
  561. *
  562. * Revision 1.15  2000/11/20 17:26:32  vasilche
  563. * Fixed warnings on 64 bit platforms.
  564. * Updated names of config variables.
  565. *
  566. * Revision 1.14  2000/11/15 20:34:54  vasilche
  567. * Added user comments to ENUMERATED types.
  568. * Added storing of user comments to ASN.1 module definition.
  569. *
  570. * Revision 1.13  2000/11/14 21:41:24  vasilche
  571. * Added preserving of ASN.1 definition comments.
  572. *
  573. * Revision 1.12  2000/08/25 15:59:22  vasilche
  574. * Renamed directory tool -> datatool.
  575. *
  576. * Revision 1.11  2000/04/10 20:01:31  vakatov
  577. * Typo fixed
  578. *
  579. * Revision 1.10  2000/04/10 19:34:02  vakatov
  580. * Get rid of a minor compiler warning
  581. *
  582. * Revision 1.9  2000/04/07 19:26:27  vasilche
  583. * Added namespace support to datatool.
  584. * By default with argument -oR datatool will generate objects in namespace
  585. * NCBI_NS_NCBI::objects (aka ncbi::objects).
  586. * Datatool's classes also moved to NCBI namespace.
  587. *
  588. * Revision 1.8  2000/03/29 15:52:27  vasilche
  589. * Generated files names limited to 31 symbols due to limitations of Mac.
  590. * Removed unions with only one member.
  591. *
  592. * Revision 1.7  2000/02/01 21:47:59  vasilche
  593. * Added CGeneratedChoiceTypeInfo for generated choice classes.
  594. * Removed CMemberInfo subclasses.
  595. * Added support for DEFAULT/OPTIONAL members.
  596. * Changed class generation.
  597. * Moved datatool headers to include/internal/serial/tool.
  598. *
  599. * Revision 1.6  2000/01/05 19:34:53  vasilche
  600. * Fixed warning on MS VC
  601. *
  602. * Revision 1.5  1999/12/30 21:33:39  vasilche
  603. * Changed arguments - more structured.
  604. * Added intelligence in detection of source directories.
  605. *
  606. * Revision 1.4  1999/12/28 18:55:57  vasilche
  607. * Reduced size of compiled object files:
  608. * 1. avoid inline or implicit virtual methods (especially destructors).
  609. * 2. avoid std::string's methods usage in inline methods.
  610. * 3. avoid string literals ("xxx") in inline methods.
  611. *
  612. * Revision 1.3  1999/12/21 17:44:18  vasilche
  613. * Fixed compilation on SunPro C++
  614. *
  615. * Revision 1.2  1999/12/21 17:18:34  vasilche
  616. * Added CDelayedFostream class which rewrites file only if contents is changed.
  617. *
  618. * Revision 1.1  1999/12/20 21:00:17  vasilche
  619. * Added generation of sources in different directories.
  620. *
  621. * ===========================================================================
  622. */