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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: page.cpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 19:15:52  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.44
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: page.cpp,v 1000.4 2004/06/01 19:15:52 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:  Lewis Geer
  35.  *
  36.  */
  37. #include <ncbi_pch.hpp>
  38. #include <html/components.hpp>
  39. #include <html/page.hpp>
  40. #include <html/jsmenu.hpp>
  41. #include <corelib/ncbiutil.hpp>
  42. #include <errno.h>
  43. BEGIN_NCBI_SCOPE
  44. // The buffer size for reading from stream.
  45. const SIZE_TYPE kBufferSize = 4096;
  46. extern const char* kTagStart;
  47. extern const char* kTagEnd;
  48. extern const char* kTagStartEnd;
  49.  
  50. // CHTMLBasicPage
  51. CHTMLBasicPage::CHTMLBasicPage(void)
  52.     : CParent("basicpage"),
  53.       m_CgiApplication(0),
  54.       m_Style(0)
  55. {
  56.     return;
  57. }
  58. CHTMLBasicPage::CHTMLBasicPage(CCgiApplication* application, int style)
  59.     : m_CgiApplication(application),
  60.       m_Style(style),
  61.       m_PrintMode(eHTML)
  62. {
  63.     return;
  64. }
  65. CHTMLBasicPage::~CHTMLBasicPage(void)
  66. {
  67.     // BW_02:  the following does not compile on MSVC++ 6.0 SP3:
  68.     // DeleteElements(m_TagMap);
  69.     for (TTagMap::iterator i = m_TagMap.begin();  i != m_TagMap.end();  ++i) {
  70.         delete i->second;
  71.     }
  72. }
  73. void CHTMLBasicPage::SetApplication(CCgiApplication* App)
  74. {
  75.     m_CgiApplication = App;
  76. }
  77. void CHTMLBasicPage::SetStyle(int style)
  78. {
  79.     m_Style = style;
  80. }
  81. CNCBINode* CHTMLBasicPage::MapTag(const string& name)
  82. {
  83.     map<string, BaseTagMapper*>::iterator i = m_TagMap.find(name);
  84.     if ( i != m_TagMap.end() ) {
  85.         return (i->second)->MapTag(this, name);
  86.     }
  87.     return CParent::MapTag(name);
  88. }
  89. void CHTMLBasicPage::AddTagMap(const string& name, CNCBINode* node)
  90. {
  91.     AddTagMap(name, CreateTagMapper(node));
  92. }
  93. void CHTMLBasicPage::AddTagMap(const string& name, BaseTagMapper* mapper)
  94. {
  95.     delete m_TagMap[name];
  96.     m_TagMap[name] = mapper;
  97. }
  98. // CHTMLPage
  99. CHTMLPage::CHTMLPage(const string& title)
  100.     : m_Title(title)
  101. {
  102.     Init();
  103. }
  104. CHTMLPage::CHTMLPage(const string& title, const string& template_file)
  105.     : m_Title(title)
  106. {
  107.     Init();
  108.     SetTemplateFile(template_file);
  109. }
  110. CHTMLPage::CHTMLPage(const string& title, istream& template_stream)
  111.     : m_Title(title)
  112. {
  113.     Init();
  114.     SetTemplateStream(template_stream);
  115. }
  116. CHTMLPage::CHTMLPage(const string& /*title*/,
  117.                      const void* template_buffer, SIZE_TYPE size)
  118. {
  119.     Init();
  120.     SetTemplateBuffer(template_buffer, size);
  121. }
  122. CHTMLPage::CHTMLPage(CCgiApplication* application, int style,
  123.                      const string& title, const string& template_file)
  124.     : CParent(application, style),
  125.       m_Title(title)
  126. {
  127.     Init();
  128.     SetTemplateFile(template_file);
  129. }
  130. void CHTMLPage::Init(void)
  131. {
  132.     // Generate internal page name
  133.     GeneratePageInternalName();
  134.     // Template sources
  135.     m_TemplateFile   = kEmptyStr;
  136.     m_TemplateStream = 0;
  137.     m_TemplateBuffer = 0;
  138.     m_TemplateSize   = 0;
  139.     
  140.     m_UsePopupMenus  = false;
  141.     AddTagMap("TITLE", CreateTagMapper(this, &CHTMLPage::CreateTitle));
  142.     AddTagMap("VIEW",  CreateTagMapper(this, &CHTMLPage::CreateView));
  143. }
  144. void CHTMLPage::CreateSubNodes(void)
  145. {
  146.     if (m_UsePopupMenus) {
  147.         AppendChild(CreateTemplate());
  148.     }
  149.     // Otherwise, done while printing to avoid latency on large files
  150. }
  151. CNCBINode* CHTMLPage::CreateTitle(void) 
  152. {
  153.     if ( GetStyle() & fNoTITLE )
  154.         return 0;
  155.     return new CHTMLText(m_Title);
  156. }
  157. CNCBINode* CHTMLPage::CreateView(void) 
  158. {
  159.     return 0;
  160. }
  161. void CHTMLPage::EnablePopupMenu(CHTMLPopupMenu::EType type,
  162.                                  const string& menu_script_url,
  163.                                  bool use_dynamic_menu)
  164. {
  165.     SPopupMenuInfo info(menu_script_url, use_dynamic_menu);
  166.     m_PopupMenus[type] = info;
  167. }
  168. static bool s_CheckUsePopupMenus(const CNCBINode* node,
  169.                                  CHTMLPopupMenu::EType type)
  170. {
  171.     if ( !node  ||  !node->HaveChildren() ) {
  172.         return false;
  173.     }
  174.     ITERATE ( CNCBINode::TChildren, i, node->Children() ) {
  175.         const CNCBINode* cnode = node->Node(i);
  176.         if ( dynamic_cast<const CHTMLPopupMenu*>(cnode) ) {
  177.             const CHTMLPopupMenu* menu
  178.                 = dynamic_cast<const CHTMLPopupMenu*>(cnode);
  179.             if ( menu->GetType() == type )
  180.                 return true;
  181.         }
  182.         if ( cnode->HaveChildren()  &&  s_CheckUsePopupMenus(cnode, type)) {
  183.             return true;
  184.         }
  185.     }
  186.     return false;
  187. }
  188. void CHTMLPage::AddTagMap(const string& name, CNCBINode* node)
  189. {
  190.     CParent::AddTagMap(name, node);
  191.     for (int t = CHTMLPopupMenu::ePMFirst; t <= CHTMLPopupMenu::ePMLast; t++ )
  192.     {
  193.         CHTMLPopupMenu::EType type = (CHTMLPopupMenu::EType)t;
  194.         if ( m_PopupMenus.find(type) == m_PopupMenus.end() ) {
  195.             if ( s_CheckUsePopupMenus(node, type) ) {
  196.                 EnablePopupMenu(type);
  197.                 m_UsePopupMenus = true;
  198.             }
  199.         } else {
  200.             m_UsePopupMenus = true;
  201.         }
  202.     }
  203. }
  204. void CHTMLPage::AddTagMap(const string& name, BaseTagMapper* mapper)
  205. {
  206.     CParent::AddTagMap(name,mapper);
  207. }
  208. CNcbiOstream& CHTMLPage::PrintChildren(CNcbiOstream& out, TMode mode)
  209. {
  210.     if (HaveChildren()) {
  211.         return CParent::PrintChildren(out, mode);
  212.     } else {
  213.         m_PrintMode = mode;
  214.         AppendChild(CreateTemplate(&out, mode));
  215.         return out;
  216.     }
  217. }
  218. CNCBINode* CHTMLPage::CreateTemplate(CNcbiOstream* out, CNCBINode::TMode mode)
  219. {
  220.     // Get template stream
  221.     if ( !m_TemplateFile.empty() ) {
  222.         CNcbiIfstream is(m_TemplateFile.c_str());
  223.         return x_CreateTemplate(is, out, mode);
  224.     } else if ( m_TemplateStream ) {
  225.         return x_CreateTemplate(*m_TemplateStream, out, mode);
  226.     } else if ( m_TemplateBuffer ) {
  227.         CNcbiIstrstream is((char*)m_TemplateBuffer, m_TemplateSize);
  228.         return x_CreateTemplate(is, out, mode);
  229.     } else {
  230.         return new CHTMLText(kEmptyStr);
  231.     }
  232. }
  233. CNCBINode* CHTMLPage::x_CreateTemplate(CNcbiIstream& is, CNcbiOstream* out,
  234.                                        CNCBINode::TMode mode)
  235. {
  236.     string str;
  237.     char   buf[kBufferSize];
  238.     if ( !is.good() ) {
  239.         NCBI_THROW(CHTMLException, eTemplateAccess,
  240.                    "CHTMLPage::CreateTemplate(): failed to open template");
  241.     }
  242.     // Special case: stream large templates on the first pass
  243.     // to reduce latency.
  244.     if (out  &&  !m_UsePopupMenus) {
  245.         auto_ptr<CNCBINode> node(new CNCBINode);
  246.         while (is) {
  247.             is.read(buf, sizeof(buf));
  248.             str.append(buf, is.gcount());
  249.             SIZE_TYPE pos = str.rfind('n');
  250.             if (pos != NPOS) {
  251.                 ++pos;
  252.                 CHTMLText* child = new CHTMLText(str.substr(0, pos));
  253.                 child->Print(*out, mode);
  254.                 node->AppendChild(child);
  255.                 str.erase(0, pos);
  256.             }
  257.         }
  258.         if ( !str.empty() ) {
  259.             CHTMLText* child = new CHTMLText(str);
  260.             child->Print(*out, mode);
  261.             node->AppendChild(child);
  262.         }
  263.         if ( !is.eof() ) {
  264.             NCBI_THROW(CHTMLException, eTemplateAccess,
  265.                        "CHTMLPage::CreateTemplate(): error reading template");
  266.         }
  267.         
  268.         return node.release();
  269.     }
  270.     if ( m_TemplateSize ) {
  271.         str.reserve(m_TemplateSize);
  272.     }
  273.     while ( is ) {
  274.         is.read(buf, sizeof(buf));
  275.         if (m_TemplateSize == 0  &&  is.gcount() > 0
  276.             &&  str.size() == str.capacity()) {
  277.             // We don't know how big str will need to be, so we grow it
  278.             // exponentially.
  279.             str.reserve(str.size() +
  280.                         max((SIZE_TYPE)is.gcount(), str.size() / 2));
  281.         }
  282.         str.append(buf, is.gcount());
  283.     }
  284.     if ( !is.eof() ) {
  285.         NCBI_THROW(CHTMLException, eTemplateAccess,
  286.                    "CHTMLPage::CreateTemplate(): error reading template");
  287.     }
  288.     // Insert code in end of <HEAD> and <BODY> blocks for support popup menus
  289.     if ( m_UsePopupMenus ) {
  290.         // a "do ... while (false)" lets us avoid a goto
  291.         do {
  292.             // Search </HEAD> tag
  293.             SIZE_TYPE pos = NStr::FindNoCase(str, "/head");
  294.             if ( pos == NPOS) {
  295.                 break;
  296.             }
  297.             pos = str.rfind("<", pos);
  298.             if ( pos == NPOS) {
  299.                 break;
  300.             }
  301.             // Insert code for load popup menu library
  302.             for (int t = CHTMLPopupMenu::ePMFirst;
  303.                  t <= CHTMLPopupMenu::ePMLast; t++ ) 
  304.             {
  305.                 CHTMLPopupMenu::EType type = (CHTMLPopupMenu::EType)t;
  306.                 TPopupMenus::const_iterator info = m_PopupMenus.find(type);
  307.                 if ( info != m_PopupMenus.end() ) {
  308.                     string script
  309.                         = CHTMLPopupMenu::GetCodeHead(type,info->second.m_Url);
  310.                     str.insert(pos, script);
  311.                     pos += script.length();
  312.                 }
  313.             }
  314.             // Search </BODY> tag
  315.             pos = NStr::FindNoCase(str, "/body", 0, NPOS, NStr::eLast);
  316.             if ( pos == NPOS) {
  317.                 break;
  318.             }
  319.             pos = str.rfind("<", pos);
  320.             if ( pos == NPOS) {
  321.                 break;
  322.             }
  323.             // Insert code for init popup menus
  324.             for (int t = CHTMLPopupMenu::ePMFirst;
  325.                  t <= CHTMLPopupMenu::ePMLast; t++ ) {
  326.                 CHTMLPopupMenu::EType type = (CHTMLPopupMenu::EType)t;
  327.                 TPopupMenus::const_iterator info = m_PopupMenus.find(type);
  328.                 if ( info != m_PopupMenus.end() ) {
  329.                     string script = CHTMLPopupMenu::GetCodeBody(type,
  330.                         info->second.m_UseDynamicMenu);
  331.                     str.insert(pos, script);
  332.                 }
  333.             }
  334.         }
  335.         while (false);
  336.     }
  337.     {{
  338.         auto_ptr<CHTMLText> node(new CHTMLText(str));
  339.         if (out) {
  340.             node->Print(*out, mode);
  341.         }
  342.         return node.release();
  343.     }}
  344. }
  345. void CHTMLPage::SetTemplateFile(const string& template_file)
  346. {
  347.     m_TemplateFile   = template_file;
  348.     m_TemplateStream = 0;
  349.     m_TemplateBuffer = 0;
  350.     GeneratePageInternalName(template_file);
  351.     {{
  352.         Int8 size = CFile(template_file).GetLength();
  353.         if (size <= 0) {
  354.             m_TemplateSize = 0;
  355.         } else if (size >= numeric_limits<size_t>::max()) {
  356.             NCBI_THROW(CHTMLException, eTemplateTooBig,
  357.                        "CHTMLPage: input template " + template_file
  358.                        + " too big to handle");
  359.         } else {
  360.             m_TemplateSize = (SIZE_TYPE)size;
  361.         }
  362.     }}
  363. }
  364. void CHTMLPage::LoadTemplateLibFile(const string& template_file)
  365. {
  366.     Int8 size = CFile(template_file).GetLength();
  367.     if (size <= 0) {
  368.         return;
  369.     } else if (size >= numeric_limits<size_t>::max()) {
  370.         NCBI_THROW(CHTMLException, eTemplateTooBig,
  371.                    "CHTMLPage: input template " + template_file
  372.                    + " too big to handle");
  373.     }
  374.     CNcbiIfstream is(template_file.c_str());
  375.     x_LoadTemplateLib(is, (SIZE_TYPE)size);
  376. }
  377. static SIZE_TYPE s_Find(const string& s, const char* target,
  378.                         SIZE_TYPE start = 0)
  379. {
  380.     // Return s.find(target);
  381.     // Some implementations of string::find call memcmp at every
  382.     // possible position, which is way too slow.
  383.     if ( start >= s.size() ) {
  384.         return NPOS;
  385.     }
  386.     const char* cstr = s.c_str();
  387.     const char* p    = strstr(cstr + start, target);
  388.     return p ? p - cstr : NPOS;
  389. }
  390. void CHTMLPage::x_LoadTemplateLib(CNcbiIstream& is, SIZE_TYPE size)
  391. {
  392.     string str("n");
  393.     char   buf[kBufferSize];
  394.     // Load template in memory all-in-all
  395.     if ( size ) {
  396.         str.reserve(size);
  397.     }
  398.     while (is) {
  399.         is.read(buf, sizeof(buf));
  400.         if (size == 0  &&  is.gcount() > 0
  401.             &&  str.size() == str.capacity()) {
  402.             // We don't know how big str will need to be, so we grow it
  403.             // exponentially.
  404.             str.reserve(str.size() + max((SIZE_TYPE)is.gcount(),
  405.                         str.size() / 2));
  406.         }
  407.         str.append(buf, is.gcount());
  408.     }
  409.     if ( !is.eof() ) {
  410.         NCBI_THROW(CHTMLException, eTemplateAccess,
  411.                    "CHTMLPage::x_LoadTemplate(): error reading template");
  412.     }
  413.     // Parse template
  414.     const string kTagStartBOL(string("n") + kTagStart); 
  415.     SIZE_TYPE ts_size  = kTagStartBOL.length();
  416.     SIZE_TYPE te_size  = strlen(kTagEnd);
  417.     SIZE_TYPE tse_size = strlen(kTagStartEnd);
  418.     SIZE_TYPE tag_start = s_Find(str, kTagStartBOL.c_str());
  419.     while ( tag_start != NPOS ) {
  420.         // Get name
  421.         string name;
  422.         SIZE_TYPE name_start = tag_start + ts_size;
  423.         SIZE_TYPE name_end   = s_Find(str, kTagEnd, name_start);
  424.         if ( name_end == NPOS ) {
  425.             // Tag not closed
  426.             NCBI_THROW(CHTMLException, eTextUnclosedTag,
  427.                 "opening tag "" + name + "" not closed, " 
  428.                 "stream pos = " + NStr::IntToString(tag_start));
  429.         }
  430.         if (name_end != name_start) {
  431.             // Tag found
  432.             name = str.substr(name_start, name_end - name_start);
  433.         }
  434.         SIZE_TYPE tag_end = name_end + te_size;
  435.         // Find close tags for "name"
  436.         string close_str = kTagStartEnd;
  437.         if ( !name.empty() ) {
  438.             close_str += name + kTagEnd;
  439.         }
  440.         SIZE_TYPE last = s_Find(str, close_str.c_str(), tag_end);
  441.         if ( last == NPOS ) {
  442.             // Tag not closed
  443.             NCBI_THROW(CHTMLException, eTextUnclosedTag,
  444.                 "closing tag "" + name + "" not closed, " 
  445.                 "stream pos = " + NStr::IntToString(tag_end));
  446.         }
  447.         if ( name.empty() ) {
  448.             tag_start = s_Find(str, kTagStartBOL.c_str(), last + tse_size);
  449.             continue;
  450.         }
  451.         // Is it a multi-line template? Remove redundand line breaks.
  452.         SIZE_TYPE pos = str.find_first_not_of(" ", tag_end);
  453.         if (pos != NPOS  &&  str[pos] == 'n') {
  454.             tag_end = pos + 1;
  455.         }
  456.         pos = str.find_first_not_of(" ", last - 1);
  457.         if (pos != NPOS  &&  str[pos] == 'n') {
  458.             last = pos;
  459.         }
  460.         // Get sub-template
  461.         string subtemplate = str.substr(tag_end, last - tag_end);
  462.         // Add sub-template resolver
  463.         AddTagMap(name, CreateTagMapper(new CHTMLText(subtemplate)));
  464.         // Find next
  465.         tag_start = s_Find(str, kTagStartBOL.c_str(),
  466.                            last + te_size + name_end - name_start + tse_size);
  467.     }
  468. }
  469.     
  470. END_NCBI_SCOPE
  471. /*
  472.  * ===========================================================================
  473.  * $Log: page.cpp,v $
  474.  * Revision 1000.4  2004/06/01 19:15:52  gouriano
  475.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.44
  476.  *
  477.  * Revision 1.44  2004/05/17 20:59:50  gorelenk
  478.  * Added include of PCH ncbi_pch.hpp
  479.  *
  480.  * Revision 1.43  2004/02/04 17:15:22  ivanov
  481.  * Added debug function GeneratePageInternalName()
  482.  *
  483.  * Revision 1.42  2004/02/03 19:45:14  ivanov
  484.  * Binded dummy names for the unnamed nodes
  485.  *
  486.  * Revision 1.41  2004/02/02 14:27:49  ivanov
  487.  * Added HTML template support
  488.  *
  489.  * Revision 1.40  2003/12/02 14:26:35  ivanov
  490.  * Removed obsolete functions GetCodeBodyTag[Handler|Action]().
  491.  *
  492.  * Revision 1.39  2003/11/03 17:03:08  ivanov
  493.  * Some formal code rearrangement. Move log to end.
  494.  *
  495.  * Revision 1.38  2003/07/08 17:13:53  gouriano
  496.  * changed thrown exceptions to CException-derived ones
  497.  *
  498.  * Revision 1.37  2003/05/15 13:07:32  ucko
  499.  * Fix a more serious (and correctly diagnosed ;-)) logic error: include
  500.  * the last line of streamed templates that don't end in newlines.
  501.  *
  502.  * Revision 1.36  2003/05/15 13:00:24  ucko
  503.  * When breaking large templates into chunks, be sure to include the
  504.  * relevant newline in each chunk to avoid accidentally repeating it if a
  505.  * really long line follows.
  506.  *
  507.  * Revision 1.35  2003/05/15 00:07:05  ucko
  508.  * x_CreateTemplate: don't assume out implies !m_UsePopupMenus
  509.  *
  510.  * Revision 1.34  2003/05/14 21:54:27  ucko
  511.  * Adjust interface to allow automatic streaming of large templates when
  512.  * not using JavaScript menus.
  513.  * Other performance improvements -- in particular, use NStr::FindNoCase
  514.  * instead of making a lowercase copy of the template.
  515.  *
  516.  * Revision 1.33  2003/05/13 15:44:41  ucko
  517.  * Make reading large templates more efficient.
  518.  *
  519.  * Revision 1.32  2003/03/11 15:28:57  kuznets
  520.  * iterate -> ITERATE
  521.  *
  522.  * Revision 1.31  2002/12/09 22:11:59  ivanov
  523.  * Added support for Sergey Kurdin's popup menu
  524.  *
  525.  * Revision 1.30  2002/09/16 22:24:52  vakatov
  526.  * Formal fix to get rid of an "unused func arg" warning
  527.  *
  528.  * Revision 1.29  2002/09/11 16:09:27  dicuccio
  529.  * fixed memory leak in CreateTemplate(): added x_CreateTemplate() to get
  530.  * around heap allocation of stream.
  531.  * moved cvs log to the bottom of the page.
  532.  *
  533.  * Revision 1.28  2002/08/09 21:12:02  ivanov
  534.  * Added stuff to read template from a stream and string
  535.  *
  536.  * Revision 1.27  2002/02/23 04:08:25  vakatov
  537.  * Commented out "// template struct TagMapper<CHTMLPage>;" to see if it's
  538.  * still needed for any compiler
  539.  *
  540.  * Revision 1.26  2002/02/13 20:16:45  ivanov
  541.  * Added support of dynamic popup menus. Changed EnablePopupMenu().
  542.  *
  543.  * Revision 1.25  2001/08/14 16:56:42  ivanov
  544.  * Added support for work HTML templates with JavaScript popup menu.
  545.  * Renamed type Flags -> ETypes. Moved all code from "page.inl" to header file.
  546.  *
  547.  * Revision 1.24  2000/03/31 17:08:43  kans
  548.  * cast ifstr.rdstate() to int
  549.  *
  550.  * Revision 1.23  1999/10/28 13:40:36  vasilche
  551.  * Added reference counters to CNCBINode.
  552.  *
  553.  * Revision 1.22  1999/09/27 16:17:18  vasilche
  554.  * Fixed several incompatibilities with Windows
  555.  *
  556.  * Revision 1.21  1999/09/23 15:51:42  vakatov
  557.  * Added <unistd.h> for the getcwd() proto
  558.  *
  559.  * Revision 1.20  1999/09/17 14:16:09  sandomir
  560.  * tmp diagnostics to find error
  561.  *
  562.  * Revision 1.19  1999/09/15 15:04:47  sandomir
  563.  * minor memory leak in tag mapping
  564.  *
  565.  * Revision 1.18  1999/07/19 21:05:02  pubmed
  566.  * minor change in CHTMLPage::CreateTemplate() - show file name
  567.  *
  568.  * Revision 1.17  1999/05/28 20:43:10  vakatov
  569.  * ::~CHTMLBasicPage(): MSVC++ 6.0 SP3 cant compile:  DeleteElements(m_TagMap);
  570.  *
  571.  * Revision 1.16  1999/05/28 16:32:16  vasilche
  572.  * Fixed memory leak in page tag mappers.
  573.  *
  574.  * Revision 1.15  1999/05/27 21:46:25  vakatov
  575.  * CHTMLPage::CreateTemplate():  throw exception if cannot open or read
  576.  * the page template file specified by user
  577.  *
  578.  * Revision 1.14  1999/04/28 16:52:45  vasilche
  579.  * Restored optimized code for reading from file.
  580.  *
  581.  * Revision 1.13  1999/04/27 16:48:44  vakatov
  582.  * Rollback of the buggy "optimization" in CHTMLPage::CreateTemplate()
  583.  *
  584.  * Revision 1.12  1999/04/26 21:59:31  vakatov
  585.  * Cleaned and ported to build with MSVC++ 6.0 compiler
  586.  *
  587.  * Revision 1.11  1999/04/19 16:51:36  vasilche
  588.  * Fixed error with member pointers detected by GCC.
  589.  *
  590.  * Revision 1.10  1999/04/15 22:10:43  vakatov
  591.  * Fixed "class TagMapper<>" to "struct ..."
  592.  *
  593.  * Revision 1.9  1998/12/28 23:29:10  vakatov
  594.  * New CVS and development tree structure for the NCBI C++ projects
  595.  *
  596.  * Revision 1.8  1998/12/28 21:48:17  vasilche
  597.  * Made Lewis's 'tool' compilable
  598.  *
  599.  * Revision 1.7  1998/12/28 16:48:09  vasilche
  600.  * Removed creation of QueryBox in CHTMLPage::CreateView()
  601.  * CQueryBox extends from CHTML_form
  602.  * CButtonList, CPageList, CPagerBox, CSmallPagerBox extend from CNCBINode.
  603.  *
  604.  * Revision 1.6  1998/12/22 16:39:15  vasilche
  605.  * Added ReadyTagMapper to map tags to precreated nodes.
  606.  *
  607.  * Revision 1.3  1998/12/01 19:10:39  lewisg
  608.  * uses CCgiApplication and new page factory
  609.  *
  610.  * ===========================================================================
  611.  */