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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: generate.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:43:12  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.59
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: generate.cpp,v 1000.1 2004/06/01 19:43:12 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. *   Main generator: collects all types, classes and files.
  38. */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbistd.hpp>
  41. #include <corelib/ncbifile.hpp>
  42. #include <algorithm>
  43. #include <typeinfo>
  44. #include <serial/datatool/moduleset.hpp>
  45. #include <serial/datatool/module.hpp>
  46. #include <serial/datatool/type.hpp>
  47. #include <serial/datatool/statictype.hpp>
  48. #include <serial/datatool/reftype.hpp>
  49. #include <serial/datatool/unitype.hpp>
  50. #include <serial/datatool/enumtype.hpp>
  51. #include <serial/datatool/blocktype.hpp>
  52. #include <serial/datatool/choicetype.hpp>
  53. #include <serial/datatool/filecode.hpp>
  54. #include <serial/datatool/generate.hpp>
  55. #include <serial/datatool/exceptions.hpp>
  56. #include <serial/datatool/fileutil.hpp>
  57. #include <serial/datatool/rpcgen.hpp>
  58. #include <serial/datatool/code.hpp>
  59. BEGIN_NCBI_SCOPE
  60. CCodeGenerator::CCodeGenerator(void)
  61.     : m_ExcludeRecursion(false), m_FileNamePrefixSource(eFileName_FromNone)
  62. {
  63.     m_MainFiles.SetModuleContainer(this);
  64.     m_ImportFiles.SetModuleContainer(this); 
  65.     m_UseQuotedForm = false;
  66.     m_CreateCvsignore = false;
  67. }
  68. CCodeGenerator::~CCodeGenerator(void)
  69. {
  70. }
  71. const CNcbiRegistry& CCodeGenerator::GetConfig(void) const
  72. {
  73.     return m_Config;
  74. }
  75. string CCodeGenerator::GetFileNamePrefix(void) const
  76. {
  77.     return m_FileNamePrefix;
  78. }
  79. void CCodeGenerator::UseQuotedForm(bool use)
  80. {
  81.     m_UseQuotedForm = use;
  82. }
  83. void CCodeGenerator::CreateCvsignore(bool create)
  84. {
  85.     m_CreateCvsignore = create;
  86. }
  87. void CCodeGenerator::SetFileNamePrefix(const string& prefix)
  88. {
  89.     m_FileNamePrefix = prefix;
  90. }
  91. EFileNamePrefixSource CCodeGenerator::GetFileNamePrefixSource(void) const
  92. {
  93.     return m_FileNamePrefixSource;
  94. }
  95. void CCodeGenerator::SetFileNamePrefixSource(EFileNamePrefixSource source)
  96. {
  97.     m_FileNamePrefixSource =
  98.         EFileNamePrefixSource(m_FileNamePrefixSource | source);
  99. }
  100. CDataType* CCodeGenerator::InternalResolve(const string& module,
  101.                                            const string& name) const
  102. {
  103.     return ExternalResolve(module, name);
  104. }
  105. const CNamespace& CCodeGenerator::GetNamespace(void) const
  106. {
  107.     return m_DefaultNamespace;
  108. }
  109. void CCodeGenerator::SetDefaultNamespace(const string& ns)
  110. {
  111.     m_DefaultNamespace = ns;
  112. }
  113. void CCodeGenerator::LoadConfig(CNcbiIstream& in)
  114. {
  115.     m_Config.Read(in);
  116. }
  117. void CCodeGenerator::LoadConfig(const string& fileName,
  118.     bool ignoreAbsense, bool warningAbsense)
  119. {
  120.     m_DefFile.erase();
  121.     // load descriptions from registry file
  122.     if ( fileName == "stdin" || fileName == "-" ) {
  123.         LoadConfig(NcbiCin);
  124.     }
  125.     else {
  126.         CNcbiIfstream in(fileName.c_str());
  127.         if ( !in ) {
  128.             if ( ignoreAbsense ) {
  129.                 return;
  130.             } else if (warningAbsense) {
  131.                 ERR_POST(Warning << "cannot open file " << fileName);
  132.             } else {
  133.                 ERR_POST(Fatal << "cannot open file " << fileName);
  134.             }
  135.         }
  136.         else {
  137.             m_DefFile = fileName;
  138.             LoadConfig(in);
  139.         }
  140.     }
  141. }
  142. void CCodeGenerator::AddConfigLine(const string& line)
  143. {
  144.     SIZE_TYPE bra = line.find('[');
  145.     SIZE_TYPE ket = line.find(']');
  146.     SIZE_TYPE eq = line.find('=', ket + 1);
  147.     if ( bra != 0 || ket == NPOS || eq == NPOS )
  148.         ERR_POST(Fatal << "bad config line: " << line);
  149.     
  150.     m_Config.Set(line.substr(bra + 1, ket - bra - 1),
  151.                  line.substr(ket + 1, eq - ket - 1),
  152.                  line.substr(eq + 1));
  153. }
  154. CDataType* CCodeGenerator::ExternalResolve(const string& module,
  155.                                            const string& name,
  156.                                            bool exported) const
  157. {
  158.     string loc("CCodeGenerator::ExternalResolve: failed");
  159.     try {
  160.         return m_MainFiles.ExternalResolve(module, name, exported);
  161.     }
  162.     catch ( CAmbiguiousTypes& exc) {
  163.         _TRACE(exc.what());
  164.         NCBI_RETHROW_SAME(exc,loc);
  165.     }
  166.     catch ( CNotFoundException& _DEBUG_ARG(exc)) {
  167.         _TRACE(exc.what());
  168.         return m_ImportFiles.ExternalResolve(module, name, exported);
  169.     }
  170.     return NULL;  // Eliminate "return value expected" warning
  171. }
  172. CDataType* CCodeGenerator::ResolveInAnyModule(const string& name,
  173.                                               bool exported) const
  174. {
  175.     string loc("CCodeGenerator::ResolveInAnyModule: failed");
  176.     try {
  177.         return m_MainFiles.ResolveInAnyModule(name, exported);
  178.     }
  179.     catch ( CAmbiguiousTypes& exc) {
  180.         _TRACE(exc.what());
  181.         NCBI_RETHROW_SAME(exc,loc);
  182.     }
  183.     catch ( CNotFoundException& _DEBUG_ARG(exc)) {
  184.         _TRACE(exc.what());
  185.         return m_ImportFiles.ResolveInAnyModule(name, exported);
  186.     }
  187.     return NULL;  // Eliminate "return value expected" warning
  188. }
  189. CDataType* CCodeGenerator::ResolveMain(const string& fullName) const
  190. {
  191.     SIZE_TYPE dot = fullName.find('.');
  192.     if ( dot != NPOS ) {
  193.         // module specified
  194.         return m_MainFiles.ExternalResolve(fullName.substr(0, dot),
  195.                                            fullName.substr(dot + 1),
  196.                                            true);
  197.     }
  198.     else {
  199.         // module not specified - we'll scan all modules for type
  200.         return m_MainFiles.ResolveInAnyModule(fullName, true);
  201.     }
  202. }
  203. const string& CCodeGenerator::ResolveFileName(const string& name) const
  204. {
  205.     TOutputFiles::const_iterator i = m_Files.find(name);
  206.     if (i != m_Files.end()) {
  207.         return i->second->GetFileBaseName();
  208.     }
  209.     return name;
  210. }
  211. void CCodeGenerator::IncludeAllMainTypes(void)
  212. {
  213.     ITERATE ( CFileSet::TModuleSets, msi, m_MainFiles.GetModuleSets() ) {
  214.         ITERATE ( CFileModules::TModules, mi, (*msi)->GetModules() ) {
  215.             const CDataTypeModule* module = mi->get();
  216.             ITERATE ( CDataTypeModule::TDefinitions, ti,
  217.                       module->GetDefinitions() ) {
  218.                 const string& name = ti->first;
  219.                 const CDataType* type = ti->second.get();
  220.                 if ( !name.empty() && !type->Skipped() ) {
  221.                     m_GenerateTypes.insert(module->GetName() + '.' + name);
  222.                 }
  223.             }
  224.         }
  225.     }
  226. }
  227. void CCodeGenerator::GetTypes(TTypeNames& typeSet, const string& types)
  228. {
  229.     SIZE_TYPE pos = 0;
  230.     SIZE_TYPE next = types.find(',');
  231.     while ( next != NPOS ) {
  232.         typeSet.insert(types.substr(pos, next - pos));
  233.         pos = next + 1;
  234.         next = types.find(',', pos);
  235.     }
  236.     typeSet.insert(types.substr(pos));
  237. }
  238. bool CCodeGenerator::Check(void) const
  239. {
  240.     return m_MainFiles.CheckNames() && m_ImportFiles.CheckNames() &&
  241.         m_MainFiles.Check();
  242. }
  243. void CCodeGenerator::ExcludeTypes(const string& typeList)
  244. {
  245.     TTypeNames typeNames;
  246.     GetTypes(typeNames, typeList);
  247.     ITERATE ( TTypeNames, i, typeNames ) {
  248.         m_Config.Set(*i, "_class", "-");
  249.         m_GenerateTypes.erase(*i);
  250.     }
  251. }
  252. void CCodeGenerator::IncludeTypes(const string& typeList)
  253. {
  254.     GetTypes(m_GenerateTypes, typeList);
  255. }
  256. struct string_nocase_less
  257. {
  258.     bool operator()(const string& s1, const string& s2) const
  259.     {
  260.         return (NStr::CompareNocase(s1, s2) < 0);
  261.     }
  262. };
  263. void CCodeGenerator::GenerateCode(void)
  264. {
  265.     // collect types
  266.     ITERATE ( TTypeNames, ti, m_GenerateTypes ) {
  267.         CollectTypes(ResolveMain(*ti), eRoot);
  268.     }
  269.     {
  270.         set<string,string_nocase_less> names;
  271.         ITERATE ( TOutputFiles, filei, m_Files ) {
  272.             CFileCode* code = filei->second.get();
  273.             string fname;
  274.             for ( fname = code->GetFileBaseName();
  275.                   names.find(fname) != names.end();) {
  276.                 fname = code->ChangeFileBaseName();
  277.             }
  278.             names.insert(fname);
  279.         }
  280.     }
  281.     // generate output files
  282.     string outdir_cpp, outdir_hpp;
  283.     list<string> listGenerated, listUntouched;
  284.     map<string,string> module_names;
  285.     ITERATE ( TOutputFiles, filei, m_Files ) {
  286.         CFileCode* code = filei->second.get();
  287.         code->GetModuleNames( module_names);
  288.         code->UseQuotedForm(m_UseQuotedForm);
  289.         code->GenerateCode();
  290.         string fileName;
  291.         code->GenerateHPP(m_HPPDir, fileName);
  292.         if (outdir_hpp.empty()) {
  293.             CDirEntry entry(fileName);
  294.             outdir_hpp = entry.GetDir();
  295.         }
  296.         code->GenerateCPP(m_CPPDir, fileName);
  297.         if (outdir_cpp.empty()) {
  298.             CDirEntry entry(fileName);
  299.             outdir_cpp = entry.GetDir();
  300.         }
  301.         if (code->GenerateUserHPP(m_HPPDir, fileName)) {
  302.             listGenerated.push_back( fileName);
  303.         } else {
  304.             listUntouched.push_back( fileName);
  305.         }
  306.         if (code->GenerateUserCPP(m_CPPDir, fileName)) {
  307.             listGenerated.push_back( fileName);
  308.         } else {
  309.             listUntouched.push_back( fileName);
  310.         }
  311.     }
  312.     // generate Doxygen group description
  313.     if (CClassCode::GetDoxygenComments() && !module_names.empty()) {
  314.         string ingroup_name =
  315.             m_DoxygenIngroup.empty() ? "DatatoolGeneratedClasses" : m_DoxygenIngroup;
  316.         CDirEntry entry(GetMainModules().GetModuleSets().front()->GetSourceFileName());
  317.         string fileName =
  318.             Path(m_HPPDir, Path(m_FileNamePrefix, entry.GetBase() + "_doxygen.h"));
  319.         CNcbiOfstream doxyfile(fileName.c_str());
  320.         if ( doxyfile.is_open() ) {
  321.             CFileCode::WriteCopyrightHeader( doxyfile);
  322.             doxyfile <<
  323.                 " *  File Description:n"
  324.                 " *    This file was generated by application DATATOOLn"
  325.                 " *    It contains comment blocks for DOXYGEN metamodulesn"
  326.                 " *n"
  327.                 " * ===========================================================================n"
  328.                 " */n";
  329.             if (CClassCode::GetDoxygenGroup().empty()) {
  330.                 map<string,string>::iterator i;
  331.                 for (i = module_names.begin(); i != module_names.end(); ++i) {
  332.                     doxyfile << "nn/** @defgroup dataspec_" << i->first << " ";
  333.                     if (m_DoxygenGroupDescription.empty()) {
  334.                         doxyfile << "Code generated by DATATOOL from "
  335.                             << i->second << " (module '" << i->first << "')";
  336.                     } else {
  337.                         doxyfile << m_DoxygenGroupDescription;
  338.                     }
  339.                     doxyfile << "n *  @ingroup " << ingroup_name << "n */nn";
  340.                 }
  341.             } else {
  342.                 doxyfile << "nn/** @defgroup ";
  343.                 doxyfile << CClassCode::GetDoxygenGroup() << " ";
  344.                 if (m_DoxygenGroupDescription.empty()) {
  345.                     doxyfile << "Code generated by DATATOOL";
  346.                 } else {
  347.                     doxyfile << m_DoxygenGroupDescription;
  348.                 }
  349.                 doxyfile << "n *  @ingroup " << ingroup_name << "n */nn";
  350.             }
  351.         }
  352.     }
  353.     if ( !m_FileListFileName.empty() ) {
  354.         string fileName(Path(m_CPPDir,Path(m_FileNamePrefix,m_FileListFileName)));
  355.         CNcbiOfstream fileList(fileName.c_str());
  356.         if ( !fileList ) {
  357.             ERR_POST(Fatal <<
  358.                      "cannot create file list file: " << m_FileListFileName);
  359.         }
  360.         
  361.         fileList << "GENFILES =";
  362.         {
  363.             ITERATE ( TOutputFiles, filei, m_Files ) {
  364.                 fileList << ' ' << filei->second->GetFileBaseName();
  365.             }
  366.         }
  367.         fileList << "n";
  368.         fileList << "GENFILES_LOCAL =";
  369.         {
  370.             ITERATE ( TOutputFiles, filei, m_Files ) {
  371.                 fileList << ' ' << BaseName(
  372.                     filei->second->GetFileBaseName());
  373.             }
  374.         }
  375.         fileList << "n";
  376.         
  377.         // generation report
  378.         for (int  user=0;  user<2; ++user)  {
  379.         for (int local=0; local<2; ++local) {
  380.         for (int   cpp=0;   cpp<2; ++cpp)   {
  381.             fileList << (user ? "SKIPPED" : "GENERATED") << "_"
  382.                 << (cpp ? "CPP" : "HPP") << (local ? "_LOCAL" : "") << " =";
  383.             list<string> *lst = (user ? &listUntouched : &listGenerated);
  384.             for (list<string>::iterator i=lst->begin();
  385.                 i != lst->end(); ++i) {
  386.                 CDirEntry entry(*i);
  387.                 bool is_cpp = (NStr::CompareNocase(entry.GetExt(),".cpp")==0);
  388.                 if ((is_cpp && cpp) || (!is_cpp && !cpp)) {
  389.                     fileList << ' ';
  390.                     if (local) {
  391.                         fileList << entry.GetBase();
  392.                     } else {
  393.                         string pp = entry.GetPath();
  394.                         size_t found;
  395.                         if (is_cpp) {
  396.                             if (!m_CPPDir.empty() &&
  397.                                 (found = pp.find(m_CPPDir)) == 0) {
  398.                                 pp.erase(0,m_CPPDir.length()+1);
  399.                             }
  400.                         } else {
  401.                             if (!m_HPPDir.empty() &&
  402.                                 (found = pp.find(m_HPPDir)) == 0) {
  403.                                 pp.erase(0,m_HPPDir.length()+1);
  404.                             }
  405.                         }
  406.                         CDirEntry ent(CDirEntry::ConvertToOSPath(pp));
  407.                         fileList << ent.GetDir() << ent.GetBase();
  408.                     }
  409.                 }
  410.             }
  411.             fileList << endl;
  412.         }
  413.         }
  414.         }
  415.     }
  416.     if ( !m_CombiningFileName.empty() ) {
  417.         // write combined files *__.cpp and *___.cpp
  418.         for ( int i = 0; i < 2; ++i ) {
  419.             const char* suffix = i? "_.cpp": ".cpp";
  420.             string fileName = m_CombiningFileName + "__" + suffix;
  421.             fileName = Path(m_CPPDir,Path(m_FileNamePrefix,fileName));
  422.             CDelayedOfstream out(fileName);
  423.             if ( !out )
  424.                 ERR_POST(Fatal << "Cannot create file: "<<fileName);
  425.             
  426.             if (!CFileCode::GetPchHeader().empty()) {
  427.                 out <<
  428.                     "#include <" << CFileCode::GetPchHeader() << ">n";
  429.             }
  430.             ITERATE ( TOutputFiles, filei, m_Files ) {
  431.                 out << "#include ""<<BaseName(
  432.                     filei->second->GetFileBaseName())<<
  433.                     suffix<<""n";
  434.             }
  435.             out.close();
  436.             if ( !out )
  437.                 ERR_POST(Fatal << "Error writing file "<<fileName);
  438.         }
  439.         // write combined *__.hpp file
  440.         const char* suffix = ".hpp";
  441.         // save to the includes directory
  442.         string fileName = Path(m_HPPDir,
  443.                                Path(m_FileNamePrefix,
  444.                                     m_CombiningFileName + "__" + suffix));
  445.         CDelayedOfstream out(fileName);
  446.         if ( !out )
  447.             ERR_POST(Fatal << "Cannot create file: " << fileName);
  448.         ITERATE ( TOutputFiles, filei, m_Files ) {
  449.             out << "#include " << (m_UseQuotedForm ? '"' : '<') << GetStdPath(
  450.                 Path(m_FileNamePrefix, BaseName(
  451.                     filei->second->GetFileBaseName())) + suffix) <<
  452.                 (m_UseQuotedForm ? '"' : '>') << "n";
  453.         }
  454.         out.close();
  455.         if ( !out )
  456.             ERR_POST(Fatal << "Error writing file " << fileName);
  457.     }
  458.     if (m_CreateCvsignore) {
  459.         string ignoreName(".cvsignore");
  460.         string extraName(".cvsignore.extra");
  461.         for (int i=0; i<2; ++i) {
  462.             bool is_cpp = (i==0);
  463.             bool different_dirs = (outdir_cpp != outdir_hpp);
  464.             string out_dir(is_cpp ? outdir_cpp : outdir_hpp);
  465.             string ignorePath(Path(out_dir,ignoreName));
  466.             // ios::out should be redundant, but some compilers
  467.             // (GCC 2.9x, for one) seem to need it. :-/
  468.             CNcbiOfstream ignoreFile(ignorePath.c_str(),
  469.                 ios::out | ((different_dirs || is_cpp) ? ios::trunc : ios::app));
  470.             if (ignoreFile.is_open()) {
  471.                 if (different_dirs || is_cpp) {
  472.                     ignoreFile << ignoreName << endl;
  473.                 }
  474. // .cvsignore.extra
  475.                 if (different_dirs || is_cpp) {
  476.                     string extraPath(Path(out_dir,extraName));
  477.                     CNcbiIfstream extraFile(extraPath.c_str());
  478.                     if (extraFile.is_open()) {
  479.                         char buf[256];
  480.                         while (extraFile.good()) {
  481.                             extraFile.getline(buf, sizeof(buf));
  482.                             string sbuf(NStr::TruncateSpaces(buf));
  483.                             if (!sbuf.empty()) {
  484.                                 ignoreFile << sbuf << endl;
  485.                             }
  486.                         }
  487.                     }
  488.                 }
  489. // base classes (always generated)
  490.                 ITERATE ( TOutputFiles, filei, m_Files ) {
  491.                     ignoreFile
  492.                         << BaseName(filei->second->GetFileBaseName())
  493.                         << "_." << (is_cpp ? "cpp" : "hpp") << endl;
  494.                 }
  495. // user classes
  496.                 for (list<string>::iterator it = listGenerated.begin();
  497.                     it != listGenerated.end(); ++it) {
  498.                     CDirEntry entry(*it);
  499.                     if (is_cpp == (NStr::CompareNocase(entry.GetExt(),".cpp")==0)) {
  500.                         ignoreFile << entry.GetName() << endl;
  501.                     }
  502.                 }
  503. // combining files
  504.                 if ( !m_CombiningFileName.empty() ) {
  505.                     if (is_cpp) {
  506.                         ignoreFile << m_CombiningFileName << "__" << "_.cpp" << endl;
  507.                         ignoreFile << m_CombiningFileName << "__" << ".cpp" << endl;
  508.                     } else {
  509.                         ignoreFile << m_CombiningFileName << "__" << ".hpp" << endl;
  510.                     }
  511.                 }
  512. // doxygen header
  513.                 if ( !is_cpp  &&  CClassCode::GetDoxygenComments()
  514.                      &&  !module_names.empty() ) {
  515.                     CDirEntry entry(GetMainModules().GetModuleSets().front()
  516.                                     ->GetSourceFileName());
  517.                     ignoreFile << entry.GetBase() << "_doxygen.h" << endl;
  518.                 }
  519. // file list
  520.                 if ( is_cpp && !m_FileListFileName.empty() ) {
  521.                     CDirEntry entry(Path(m_FileNamePrefix,m_FileListFileName));
  522.                     ignoreFile << entry.GetName() << endl;
  523.                 }
  524.             }
  525.         }
  526.     }
  527.     GenerateClientCode();
  528. }
  529. void CCodeGenerator::GenerateClientCode(void)
  530. {
  531.     string clients = m_Config.Get("-", "clients");
  532.     if (clients.empty()) {
  533.         // // for compatibility with older specifications
  534.         // GenerateClientCode("client", false);
  535.     } else {
  536.         // explicit name; must be enabled
  537.         list<string> l;
  538.         // if multiple items, may have whitespace, commas, or both...
  539.         NStr::Split(clients, ", t", l);
  540.         ITERATE (list<string>, it, l) {
  541.             if ( !it->empty() ) {
  542.                 GenerateClientCode(*it, true);
  543.             }
  544.         }
  545.     }
  546. }
  547. void CCodeGenerator::GenerateClientCode(const string& name, bool mandatory)
  548. {
  549.     string class_name = m_Config.Get(name, "class");
  550.     if (class_name.empty()) {
  551.         if (mandatory) {
  552.             ERR_POST(Fatal << "No configuration for mandatory client " + name);
  553.         }
  554.         return; // not configured
  555.     }
  556.     CFileCode code(this,Path(m_FileNamePrefix, name));
  557.     code.UseQuotedForm(m_UseQuotedForm);
  558.     code.AddType(new CClientPseudoDataType(*this, name, class_name));
  559.     code.GenerateCode();
  560.     string filename;
  561.     code.GenerateHPP(m_HPPDir, filename);
  562.     code.GenerateCPP(m_CPPDir, filename);
  563.     code.GenerateUserHPP(m_HPPDir, filename);
  564.     code.GenerateUserCPP(m_CPPDir, filename);
  565. }
  566. bool CCodeGenerator::AddType(const CDataType* type)
  567. {
  568.     string fileName = type->FileName();
  569.     AutoPtr<CFileCode>& file = m_Files[fileName];
  570.     if ( !file )
  571.         file = new CFileCode(this,fileName);
  572.     return file->AddType(type);
  573. }
  574. bool CCodeGenerator::Imported(const CDataType* type) const
  575. {
  576.     try {
  577.         m_MainFiles.ExternalResolve(type->GetModule()->GetName(),
  578.                                     type->IdName(),
  579.                                     true);
  580.         return false;
  581.     }
  582.     catch ( CNotFoundException& /* ignored */) {
  583.     }
  584.     return true;
  585. }
  586. void CCodeGenerator::CollectTypes(const CDataType* type, EContext /*context*/)
  587. {
  588.     if ( type->GetParentType() == 0 ) {
  589.         if ( !AddType(type) )
  590.             return;
  591.     }
  592.     if ( m_ExcludeRecursion )
  593.         return;
  594.     const CUniSequenceDataType* array =
  595.         dynamic_cast<const CUniSequenceDataType*>(type);
  596.     if ( array != 0 ) {
  597.         // we should add element type
  598.         CollectTypes(array->GetElementType(), eElement);
  599.         return;
  600.     }
  601.     const CReferenceDataType* user =
  602.         dynamic_cast<const CReferenceDataType*>(type);
  603.     if ( user != 0 ) {
  604.         // reference to another type
  605.         const CDataType* resolved;
  606.         try {
  607.             resolved = user->Resolve();
  608.         }
  609.         catch ( CNotFoundException& exc) {
  610.             ERR_POST(Warning <<
  611.                      "Skipping type: " << user->GetUserTypeName() <<
  612.                      ": " << exc.what());
  613.             return;
  614.         }
  615.         if ( resolved->Skipped() ) {
  616.             ERR_POST(Warning << "Skipping type: " << user->GetUserTypeName());
  617.             return;
  618.         }
  619.         if ( !Imported(resolved) ) {
  620.             CollectTypes(resolved, eReference);
  621.         }
  622.         return;
  623.     }
  624.     const CDataMemberContainerType* cont =
  625.         dynamic_cast<const CDataMemberContainerType*>(type);
  626.     if ( cont != 0 ) {
  627.         // collect member's types
  628.         ITERATE ( CDataMemberContainerType::TMembers, mi,
  629.                   cont->GetMembers() ) {
  630.             const CDataType* memberType = mi->get()->GetType();
  631.             CollectTypes(memberType, eMember);
  632.         }
  633.         return;
  634.     }
  635. }
  636. #if 0
  637. void CCodeGenerator::CollectTypes(const CDataType* type, EContext context)
  638. {
  639.     const CUniSequenceDataType* array =
  640.         dynamic_cast<const CUniSequenceDataType*>(type);
  641.     if ( array != 0 ) {
  642.         // SET OF or SEQUENCE OF
  643.         if ( type->GetParentType() == 0 || context == eChoice ) {
  644.             if ( !AddType(type) )
  645.                 return;
  646.         }
  647.         if ( m_ExcludeRecursion )
  648.             return;
  649.         // we should add element type
  650.         CollectTypes(array->GetElementType(), eElement);
  651.         return;
  652.     }
  653.     const CReferenceDataType* user =
  654.         dynamic_cast<const CReferenceDataType*>(type);
  655.     if ( user != 0 ) {
  656.         // reference to another type
  657.         const CDataType* resolved;
  658.         try {
  659.             resolved = user->Resolve();
  660.         }
  661.         catch ( CNotFoundException& exc) {
  662.             ERR_POST(Warning <<
  663.                      "Skipping type: " << user->GetUserTypeName() <<
  664.                      ": " << exc.what());
  665.             return;
  666.         }
  667.         if ( resolved->Skipped() ) {
  668.             ERR_POST(Warning << "Skipping type: " << user->GetUserTypeName());
  669.             return;
  670.         }
  671.         if ( context == eChoice ) {
  672.             // in choice
  673.             if ( resolved->InheritFromType() != user->GetParentType() ||
  674.                  dynamic_cast<const CEnumDataType*>(resolved) != 0 ) {
  675.                 // add intermediate class
  676.                 AddType(user);
  677.             }
  678.         }
  679.         else if ( type->GetParentType() == 0 ) {
  680.             // alias declaration
  681.             // generate empty class
  682.             AddType(user);
  683.         }
  684.         if ( !Imported(resolved) ) {
  685.             CollectTypes(resolved, eReference);
  686.         }
  687.         return;
  688.     }
  689.     if ( dynamic_cast<const CStaticDataType*>(type) != 0 ) {
  690.         // STD type
  691.         if ( type->GetParentType() == 0 || context == eChoice ) {
  692.             AddType(type);
  693.         }
  694.         return;
  695.     }
  696.     if ( dynamic_cast<const CEnumDataType*>(type) != 0 ) {
  697.         // ENUMERATED type
  698.         if ( type->GetParentType() == 0 || context == eChoice ) {
  699.             AddType(type);
  700.         }
  701.         return;
  702.     }
  703.     if ( type->GetParentType() == 0 || context == eChoice ) {
  704.         if ( type->Skipped() ) {
  705.             ERR_POST(Warning << "Skipping type: " << type->IdName());
  706.             return;
  707.         }
  708.     }
  709.     
  710.     const CChoiceDataType* choice =
  711.         dynamic_cast<const CChoiceDataType*>(type);
  712.     if ( choice != 0 ) {
  713.         if ( !AddType(type) )
  714.             return;
  715.         if ( m_ExcludeRecursion )
  716.             return;
  717.         // collect member's types
  718.         ITERATE ( CDataMemberContainerType::TMembers, mi,
  719.                   choice->GetMembers() ) {
  720.             const CDataType* memberType = mi->get()->GetType();
  721.             CollectTypes(memberType, eMember); // eChoice
  722.         }
  723.     }
  724.     const CDataMemberContainerType* cont =
  725.         dynamic_cast<const CDataMemberContainerType*>(type);
  726.     if ( cont != 0 ) {
  727.         if ( !AddType(type) )
  728.             return;
  729.         if ( m_ExcludeRecursion )
  730.             return;
  731.         // collect member's types
  732.         ITERATE ( CDataMemberContainerType::TMembers, mi,
  733.                   cont->GetMembers() ) {
  734.             const CDataType* memberType = mi->get()->GetType();
  735.             CollectTypes(memberType, eMember);
  736.         }
  737.         return;
  738.     }
  739.     if ( !AddType(type) )
  740.         return;
  741. }
  742. #endif
  743. END_NCBI_SCOPE
  744. /*
  745. * ===========================================================================
  746. *
  747. * $Log: generate.cpp,v $
  748. * Revision 1000.1  2004/06/01 19:43:12  gouriano
  749. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.59
  750. *
  751. * Revision 1.59  2004/05/19 15:46:19  gouriano
  752. * Add precompiled header into combining files as well
  753. *
  754. * Revision 1.58  2004/05/17 21:03:14  gorelenk
  755. * Added include of PCH ncbi_pch.hpp
  756. *
  757. * Revision 1.57  2004/05/13 15:49:49  ucko
  758. * When generating doxygen headers, list them in .cvsignore.
  759. *
  760. * Revision 1.56  2004/05/03 19:31:03  gouriano
  761. * Made generation of DOXYGEN-style comments optional
  762. *
  763. * Revision 1.55  2004/04/30 02:05:05  ucko
  764. * Make ingroup_name a full-fledged string rather than a reference,
  765. * since it may be initialized by a temporary and should never be big
  766. * enough for copying to be an issue.
  767. *
  768. * Revision 1.54  2004/04/29 20:11:39  gouriano
  769. * Generate DOXYGEN-style comments in C++ headers
  770. *
  771. * Revision 1.53  2003/06/16 19:03:03  ucko
  772. * Explicitly turn on ios::out when opening ignoreFile; needed with GCC 2.9x.
  773. *
  774. * Revision 1.52  2003/05/29 17:25:34  gouriano
  775. * added possibility of generation .cvsignore file
  776. *
  777. * Revision 1.51  2003/04/18 20:40:17  ucko
  778. * Oops, s/iterate/ITERATE/ in my latest change.
  779. *
  780. * Revision 1.50  2003/04/08 20:40:08  ucko
  781. * Get client name(s) from [-]clients rather than hardcoding "client"
  782. *
  783. * Revision 1.49  2003/03/11 20:06:47  kuznets
  784. * iterate -> ITERATE
  785. *
  786. * Revision 1.48  2003/03/10 18:55:18  gouriano
  787. * use new structured exceptions (based on CException)
  788. *
  789. * Revision 1.47  2003/02/24 21:57:46  gouriano
  790. * added odw flag - to issue a warning about missing DEF file
  791. *
  792. * Revision 1.46  2002/12/17 19:03:26  gouriano
  793. * corrected ResolveFileName for external definitions
  794. *
  795. * Revision 1.45  2002/12/17 16:22:47  gouriano
  796. * separated class name from the name of the file in which it will be written
  797. *
  798. * Revision 1.44  2002/11/13 00:46:07  ucko
  799. * Add RPC client generator; CVS logs to end in generate.?pp
  800. *
  801. * Revision 1.43  2002/10/22 15:06:13  gouriano
  802. * added possibillity to use quoted syntax form for generated include files
  803. *
  804. * Revision 1.42  2002/10/01 17:04:31  gouriano
  805. * corrections to eliminate redundant info in the generation report
  806. *
  807. * Revision 1.41  2002/10/01 14:20:30  gouriano
  808. * added more generation report data
  809. *
  810. * Revision 1.40  2002/09/30 19:16:10  gouriano
  811. * changed location of "*.files" and "combining" files to CPP dir
  812. *
  813. * Revision 1.39  2001/12/07 18:56:51  grichenk
  814. * Paths in "#include"-s made system-independent
  815. *
  816. * Revision 1.38  2001/12/03 14:50:27  juran
  817. * Eliminate "return value expected" warning.
  818. *
  819. * Revision 1.37  2001/10/22 15:18:19  grichenk
  820. * Fixed combined HPP generation.
  821. *
  822. * Revision 1.36  2001/10/18 20:10:34  grichenk
  823. * Save combining header on -oc
  824. *
  825. * Revision 1.35  2001/08/31 20:05:46  ucko
  826. * Fix ICC build.
  827. *
  828. * Revision 1.34  2000/11/27 18:19:48  vasilche
  829. * Datatool now conforms CNcbiApplication requirements.
  830. *
  831. * Revision 1.33  2000/08/25 15:59:22  vasilche
  832. * Renamed directory tool -> datatool.
  833. *
  834. * Revision 1.32  2000/06/16 16:31:39  vasilche
  835. * Changed implementation of choices and classes info to allow use of the same classes in generated and user written classes.
  836. *
  837. * Revision 1.31  2000/05/24 20:57:14  vasilche
  838. * Use new macro _DEBUG_ARG to avoid warning about unused argument.
  839. *
  840. * Revision 1.30  2000/05/24 20:09:28  vasilche
  841. * Implemented DTD generation.
  842. *
  843. * Revision 1.29  2000/04/10 19:33:22  vakatov
  844. * Get rid of a minor compiler warning
  845. *
  846. * Revision 1.28  2000/04/07 19:26:27  vasilche
  847. * Added namespace support to datatool.
  848. * By default with argument -oR datatool will generate objects in namespace
  849. * NCBI_NS_NCBI::objects (aka ncbi::objects).
  850. * Datatool's classes also moved to NCBI namespace.
  851. *
  852. * Revision 1.27  2000/03/07 14:06:32  vasilche
  853. * Added generation of reference counted objects.
  854. *
  855. * Revision 1.26  2000/02/01 21:48:00  vasilche
  856. * Added CGeneratedChoiceTypeInfo for generated choice classes.
  857. * Removed CMemberInfo subclasses.
  858. * Added support for DEFAULT/OPTIONAL members.
  859. * Changed class generation.
  860. * Moved datatool headers to include/internal/serial/tool.
  861. *
  862. * Revision 1.25  2000/01/06 16:13:18  vasilche
  863. * Fail of file generation now fatal.
  864. *
  865. * Revision 1.24  1999/12/28 18:55:57  vasilche
  866. * Reduced size of compiled object files:
  867. * 1. avoid inline or implicit virtual methods (especially destructors).
  868. * 2. avoid std::string's methods usage in inline methods.
  869. * 3. avoid string literals ("xxx") in inline methods.
  870. *
  871. * Revision 1.23  1999/12/21 17:18:34  vasilche
  872. * Added CDelayedFostream class which rewrites file only if contents is changed.
  873. *
  874. * Revision 1.22  1999/12/20 21:00:18  vasilche
  875. * Added generation of sources in different directories.
  876. *
  877. * Revision 1.21  1999/12/17 19:05:19  vasilche
  878. * Simplified generation of GetTypeInfo methods.
  879. *
  880. * Revision 1.20  1999/12/09 20:01:23  vasilche
  881. * Fixed bug with missed internal classes.
  882. *
  883. * Revision 1.19  1999/12/03 21:42:12  vasilche
  884. * Fixed conflict of enums in choices.
  885. *
  886. * Revision 1.18  1999/12/01 17:36:25  vasilche
  887. * Fixed CHOICE processing.
  888. *
  889. * Revision 1.17  1999/11/15 19:36:15  vasilche
  890. * Fixed warnings on GCC
  891. *
  892. * ===========================================================================
  893. */