<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> <html> <head> <meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"> <title>Libstdc++-porting-howto</title> <meta name="generator" content="DocBook XSL Stylesheets V1.48"> </head> <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="article"> <div class="titlepage"> <div><h1 class="title"> <a name="libstdc++-porting-howto"></a>Libstdc++-porting-howto</h1></div> <div><h3 class="author">Felix Natter</h3></div> <div><div class="legalnotice"> <p class="legalnotice-title"><b>Legal Notice</b></p> <p> This document can be distributed under the FDL (<a href="http://www.gnu.org" target="_top">www.gnu.org</a>) </p> </div></div> <div><p class="pubdate">Tue Jun 5 20:07:49 2001</p></div> <div><div class="revhistory"><table border="1" width="100%" summary="Revision history"> <tr><th align="left" valign="top" colspan="3"><b>Revision History</b></th></tr> <tr> <td align="left">Revision 0.5</td> <td align="left">Thu Jun 1 13:06:50 2000</td> <td align="left">fnatter</td> </tr> <tr><td align="left" colspan="3">First docbook-version.</td></tr> <tr> <td align="left">Revision 0.8</td> <td align="left">Sun Jul 30 20:28:40 2000</td> <td align="left">fnatter</td> </tr> <tr><td align="left" colspan="3">First released version using docbook-xml + second upload to libstdc++-page. </td></tr> <tr> <td align="left">Revision 0.9</td> <td align="left">Wed Sep 6 02:59:32 2000</td> <td align="left">fnatter</td> </tr> <tr><td align="left" colspan="3">5 new sections.</td></tr> <tr> <td align="left">Revision 0.9.1</td> <td align="left">Sat Sep 23 14:20:15 2000</td> <td align="left">fnatter</td> </tr> <tr><td align="left" colspan="3">added information about why file-descriptors are not in the standard</td></tr> <tr> <td align="left">Revision 0.9.2</td> <td align="left">Tue Jun 5 20:07:49 2001</td> <td align="left">fnatter</td> </tr> <tr><td align="left" colspan="3"> a fix, added hint on increased portability of C-shadow-headers, added autoconf-test HAVE_CONTAINER_AT </td></tr> <tr> <td align="left">Revision 0.9.3</td> <td align="left">Fri Jun 29 16:15:56 2001</td> <td align="left">fnatter</td> </tr> <tr><td align="left" colspan="3"> changed signature of nonstandard filebuf-constructor and update the section on filebuf::attach to point to ../ext/howto.html, added link to ../21/strings/howto.html in sec-stringstream, changed <link>-tags to have content (so that these links work), replace "user-space" by "global namespace" add note about gcc 3.0 and shadow-headers add section about ostream::form and istream::scan sec-vector-at: remove hint to modify headers fix spelling error in sec-stringstream </td></tr> <tr> <td align="left">Revision 0.9.4</td> <td align="left">Mon Nov 5 17:01:04 2001</td> <td align="left">fnatter</td> </tr> <tr><td align="left" colspan="3"> rewrite section 1.1.3 because of gnu.gcc.help-post by Juergen Heinzl </td></tr> </table></div></div> <div><div class="abstract"> <p><b>Abstract</b></p> <p> Some notes on porting applications from libstdc++-2.90 (or earlier versions) to libstdc++-v3. Not speaking in terms of the GNU libstdc++ implementations, this means porting from earlier versions of the C++-Standard to ISO 14882. </p> </div></div> <hr> </div> <div class="toc"> <p><b>Table of Contents</b></p> <dl> <dt>1. <a href="#sec-nsstd">Namespace std::</a> </dt> <dd><dl> <dt>1.1.1. <a href="#sec-gtkmm-hack">Using namespace composition if the project uses a separate namespace</a> </dt> <dt>1.1.2. <a href="#sec-emptyns">Defining an empty namespace std</a> </dt> <dt>1.1.3. <a href="#sec-avoidfqn">Avoid to use fully qualified names (i.e. std::string)</a> </dt> <dt>1.1.4. <a href="#sec-osprojects">How some open-source-projects deal with this</a> </dt> </dl></dd> <dt>2. <a href="#sec-nocreate">there is no ios::nocreate/ios::noreplace in ISO 14882</a> </dt> <dt>3. <a href="#sec-stream::attach">stream::attach(int fd) is not in the standard any more</a> </dt> <dt>4. <a href="#sec-headers">The new headers</a> </dt> <dd><dl> <dt>4.4.1. <a href="#sec-cheaders">New headers replacing C-headers</a> </dt> <dt>4.4.2. <a href="#sec-fstream-header"> <fstream> does not define std::cout, std::cin etc.</a> </dt> </dl></dd> <dt>5. <a href="#sec-iterators">Iterators</a> </dt> <dt>6. <a href="#sec-macros"> Libc-macros (i.e. isspace from <cctype>)</a> </dt> <dt>7. <a href="#sec-stream-state">State of streams</a> </dt> <dt>8. <a href="#sec-vector-at">vector::at is missing (i.e. gcc 2.95.x)</a> </dt> <dt>9. <a href="#sec-eof">Using std::char_traits<char>::eof()</a> </dt> <dt>10. <a href="#sec-string-clear">Using string::clear()/string::erase()</a> </dt> <dt>11. <a href="#sec-scan-form">GNU Extensions ostream::form and istream::scan</a> </dt> <dt>12. <a href="#sec-stringstream">Using stringstreams</a> </dt> <dt>13. <a href="#sec-about">About...</a> </dt> </dl> </div> <p> In the following, when I say portable, I will refer to "portable among ISO 14882-implementations". On the other hand, if I say "backportable" or "conservative", I am talking about "compiles with older libstdc++-implementations". </p> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-nsstd"></a>Namespace std::</h2></div></div> <p> The latest C++-standard (ISO-14882) requires that the standard C++-library is defined in namespace std::. Thus, in order to use classes from the standard C++-library, you can do one of three things: <div class="itemizedlist"><ul type="disc"> <li><p>wrap your code in <b>namespace std { ... }</b> => This is not an option because only symbols from the standard c++-library are defined in namespace std::. </p></li> <li><p>put a kind of <span class="emphasis"><i>using-declaration</i></span> in your source (either <b>using namespace std;</b> or i.e. <b>using std::string;</b>) => works well for source-files, but cannot be used in header-files. </p></li> <li><p>use a <span class="emphasis"><i>fully qualified name</i></span> for each libstdc++-symbol (i.e. <b>std::string</b>, <b>std::cout</b>) => can always be used </p></li> </ul></div> </p> <p> Because there are many compilers which still use an implementation that does not have the standard C++-library in namespace <b>std::</b>, some care is required to support these as well. </p> <p> Namespace back-portability-issues are generally not a problem with g++, because versions of g++ that do not have libstdc++ in <b>std::</b> use <b>-fno-honor-std</b> (ignore <b>std::</b>, <b>:: = std::</b>) by default. That is, the responsibility for enabling or disabling <b>std::</b> is on the user; the maintainer does not have to care about it. This probably applies to some other compilers as well. </p> <p> The following sections list some possible solutions to support compilers that cannot ignore std::. </p> <div class="section"> <div class="titlepage"><div><h3 class="title"> <a name="sec-gtkmm-hack"></a>Using <span class="emphasis"><i>namespace composition</i></span> if the project uses a separate namespace</h3></div></div> <p> <a href="http://gtkmm.sourceforge.net" target="_top">Gtk--</a> defines most of its classes in namespace Gtk::. Thus, it was possible to adapt Gtk-- to namespace std:: by using a C++-feature called <span class="emphasis"><i>namespace composition</i></span>. This is what happens if you put a <span class="emphasis"><i>using</i></span>-declaration into a namespace-definition: the imported symbol(s) gets imported into the currently active namespace(s). For example: <pre class="programlisting"> namespace Gtk { using std::string; class Window { ... } } </pre> In this example, <b>std::string</b> gets imported into namespace Gtk::. The result is that you don't have to use <b>std::string</b> in this header, but still <b>std::string</b> does not get imported into the global namespace (::) unless the user does <b>using namespace Gtk;</b> (which is not recommended practice for Gtk--, so it is not a problem). Additionally, the <b>using</b>-declarations are wrapped in macros that are set based on autoconf-tests to either "" or i.e. <b>using std::string;</b> (depending on whether the system has libstdc++ in <b>std::</b> or not). (ideas from <tt><<a href="mailto:llewelly@dbritsch.dsl.xmission.com">llewelly@dbritsch.dsl.xmission.com</a>></tt>, Karl Nelson <tt><<a href="mailto:kenelson@ece.ucdavis.edu">kenelson@ece.ucdavis.edu</a>></tt>) </p> </div> <div class="section"> <div class="titlepage"><div><h3 class="title"> <a name="sec-emptyns"></a>Defining an empty namespace std</h3></div></div> <p> By defining an (empty) namespace <b>std::</b> before using it, you avoid getting errors on systems where no part of the library is in namespace std: <pre class="programlisting"> namespace std { } using namespace std; </pre> </p> </div> <div class="section"> <div class="titlepage"><div><h3 class="title"> <a name="sec-avoidfqn"></a>Avoid to use fully qualified names (i.e. std::string)</h3></div></div> <p> If some compilers complain about <b>using std::string;</b>, and if the "hack" for gtk-- mentioned above does not work, then I see two solutions: <div class="itemizedlist"><ul type="disc"> <li><p> Define <b>std::</b> as a macro if the compiler doesn't know about <b>std::</b>. <pre class="programlisting"> #ifdef OLD_COMPILER #define std #endif </pre> (thanks to Juergen Heinzl who posted this solution on gnu.gcc.help) </p></li> <li><p> Define a macro NS_STD, which is defined to either "" or "std" based on an autoconf-test. Then you should be able to use <b>NS_STD::string</b>, which will evaluate to <b>::string</b> ("string in the global namespace") on systems that do not put string in std::. (This is untested) </p></li> </ul></div> </p> </div> <div class="section"> <div class="titlepage"><div><h3 class="title"> <a name="sec-osprojects"></a>How some open-source-projects deal with this</h3></div></div> <p> This information was gathered around May 2000. It may not be correct by the time you read this. </p> <div class="table"> <p><b>Table 1. Namespace std:: in Open-Source programs</b></p> <table summary="Namespace std:: in Open-Source programs" border="1"> <colgroup> <col> <col> </colgroup> <tbody> <tr> <td><a href="http://www.clanlib.org" target="_top">clanlib</a></td> <td>usual</td> </tr> <tr> <td><a href="http://pingus.seul.org" target="_top">pingus</a></td> <td>usual</td> </tr> <tr> <td><a href="http://www.mozilla.org" target="_top">mozilla</a></td> <td>usual</td> </tr> <tr> <td><a href="http://www.mnemonic.org" target="_top">mnemonic</a></td> <td>none</td> </tr> <tr> <td><a href="http://libsigc.sourceforge.net" target="_top"> libsigc++</a></td> <td>conservative-impl</td> </tr> </tbody> </table> </div> <div class="table"> <p><b>Table 2. Notations for categories</b></p> <table summary="Notations for categories" border="1"> <colgroup> <col> <col> </colgroup> <tbody> <tr> <td>usual</td> <td>mostly fully qualified names and some using-declarations (but not in headers)</td> </tr> <tr> <td>none</td> <td>no namespace std at all</td> </tr> <tr> <td>conservative-impl</td> <td>wrap all namespace-handling in macros to support compilers without namespace-support (no libstdc++ used in headers)</td> </tr> </tbody> </table> </div> <p> As you can see, this currently lacks an example of a project which uses libstdc++-symbols in headers in a back-portable way (except for Gtk--: see the <a href="#sec-gtkmm-hack" title="Using namespace composition if the project uses a separate namespace">section on the gtkmm-hack</a>). </p> </div> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-nocreate"></a>there is no ios::nocreate/ios::noreplace in ISO 14882</h2></div></div> <p> I have seen <b>ios::nocreate</b> being used for input-streams, most probably because the author thought it would be more correct to specify nocreate "explicitly". So you can simply leave it out for input-streams. </p> <p> For output streams, "nocreate" is probably the default, unless you specify <b>std::ios::trunc</b> ? To be safe, you can open the file for reading, check if it has been opened, and then decide whether you want to create/replace or not. To my knowledge, even older implementations support <b>app</b>, <b>ate</b> and <b>trunc</b> (except for <b>app</b> ?). </p> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-stream::attach"></a><b>stream::attach(int fd)</b> is not in the standard any more</h2></div></div> <p> Phil Edwards <tt><<a href="mailto:pedwards@disaster.jaj.com">pedwards@disaster.jaj.com</a>></tt> writes: It was considered and rejected. Not all environments use file descriptors. Of those that do, not all of them use integers to represent them. </p> <p> When using libstdc++-v3, you can use <div class="funcsynopsis"> <pre class="funcsynopsisinfo"> #include <fstream> </pre> <p><code><code class="funcdef"> <b class="fsfunc">basic_filebuf<...>::basic_filebuf<...> </b> </code>(<var class="pdparam">file</var>, <var class="pdparam">mode</var>, <var class="pdparam">size</var>);<br>__c_file_type* <var class="pdparam">file</var>;<br>ios_base::open_mode <var class="pdparam">mode</var>;<br>int <var class="pdparam">size</var>;</code></p> </div> but the the signature of this constructor has changed often, and it might change again. For the current state of this, check <a href="../ext/howto.html" target="_top">the howto for extensions</a>. </p> <p> For a portable solution (among systems which use filedescriptors), you need to implement a subclass of <b>std::streambuf</b> (or <b>std::basic_streambuf<..></b>) which opens a file given a descriptor, and then pass an instance of this to the stream-constructor. For an example of this, refer to <a href="http://www.josuttis.com/cppcode/fdstream.html" target="_top">fdstream example</a> by Nicolai Josuttis. </p> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-headers"></a>The new headers</h2></div></div> <p> All new headers can be seen in this <a href="headers_cc.txt" target="_top"> source-code</a>. </p> <p> The old C++-headers (iostream.h etc.) are available, but gcc generates a warning that you are using deprecated headers. </p> <div class="section"> <div class="titlepage"><div><h3 class="title"> <a name="sec-cheaders"></a>New headers replacing C-headers</h3></div></div> <p> You should not use the C-headers (except for system-level headers) from C++ programs. Instead, you should use a set of headers that are named by prepending 'c' and, as usual, omitting the extension (.h). For example, instead of using <tt><math.h></tt>, you should use <tt><cmath></tt>. In some cases this has the advantage that the C++-header is more standardized than the C-header (i.e. <tt><ctime></tt> (almost) corresponds to either <tt><time.h></tt> or <tt><sys/time.h></tt>). The standard specifies that if you include the C-style header (<tt><math.h></tt> in this case), the symbols will be available both in the global namespace and in namespace <b>std::</b> (but libstdc++ does not yet have fully compliant headers) On the other hand, if you include only the new header (i.e. <tt><cmath></tt>), the symbols will only be defined in namespace <b>std::</b> (and macros will be converted to inline-functions). </p> <p> For more information on this, and for information on how the GNU C++ implementation might reuse ("shadow") the C library-functions, have a look at <a href="http://www.cantrip.org/cheaders.html" target="_top"> www.cantrip.org</a>. </p> </div> <div class="section"> <div class="titlepage"><div><h3 class="title"> <a name="sec-fstream-header"></a> <tt><fstream></tt> does not define <b>std::cout</b>, <b>std::cin</b> etc.</h3></div></div> <p> In earlier versions of the standard, <tt><fstream.h></tt>, <tt><ostream.h></tt> and <tt><istream.h></tt> used to define <b>cout</b>, <b>cin</b> and so on. Because of the templatized iostreams in libstdc++-v3, you need to include <tt><iostream></tt> explicitly to define these. </p> </div> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-iterators"></a>Iterators</h2></div></div> <p> The following are not proper uses of iterators, but may be working fixes for existing uses of iterators. <div class="itemizedlist"><ul type="disc"> <li><p>you cannot do <b>ostream::operator<<(iterator)</b> to print the address of the iterator => use <b>operator<< &*iterator</b> instead ? </p></li> <li><p>you cannot clear an iterator's reference (<b>iterator = 0</b>) => use <b>iterator = iterator_type();</b> ? </p></li> <li><p> <b>if (iterator)</b> won't work any more => use <b>if (iterator != iterator_type())</b> ?</p></li> </ul></div> </p> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-macros"></a> Libc-macros (i.e. <b>isspace</b> from <tt><cctype></tt>)</h2></div></div> <p> Glibc 2.0.x and 2.1.x define the <tt><ctype.h></tt> -functionality as macros (isspace, isalpha etc.). Libstdc++-v3 "shadows" these macros as described in the <a href="#sec-cheaders" title="New headers replacing C-headers">section about c-headers</a>. </p> <p> Older implementations of libstdc++ (g++-2 for egcs 1.x and g++-3 for gcc 2.95.x), however, keep these functions as macros, and so it is not back-portable to use fully qualified names. For example: <pre class="programlisting"> #include <cctype> int main() { std::isspace('X'); } </pre> will result in something like this (unless using g++-v3): <pre class="programlisting"> std:: (__ctype_b[(int) ( ( 'X' ) )] & (unsigned short int) _ISspace ) ; </pre> </p> <p> One solution I can think of is to test for -v3 using autoconf-macros, and define macros for each of the C-functions (maybe that is possible with one "wrapper" macro as well ?). </p> <p> Another solution which would fix g++ is to tell the user to modify a header-file so that g++-2 (egcs 1.x) and g++-3 (gcc 2.95.x) define a macro which tells <tt><ctype.h></tt> to define functions instead of macros: <pre class="programlisting"> // This keeps isalnum, et al from being propagated as macros. #if __linux__ #define __NO_CTYPE 1 #endif [ now include <ctype.h> ] </pre> </p> <p> Another problem arises if you put a <b>using namespace std;</b> declaration at the top, and include <tt><ctype.h></tt>. This will result in ambiguities between the definitions in the global namespace (<tt><ctype.h></tt>) and the definitions in namespace <b>std::</b> (<b><cctype></b>). </p> <p> The solution to this problem was posted to the libstdc++-v3 mailing-list: Benjamin Kosnik <tt><<a href="mailto:bkoz@redhat.com">bkoz@redhat.com</a>></tt> writes: ‘ --enable-cshadow-headers is currently broken. As a result, shadow headers are not being searched.... ’ This is now outdated, but gcc 3.0 still does not have fully compliant "shadow headers". </p> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-stream-state"></a>State of streams</h2></div></div> <p> At least some older implementations don't have <b>std::ios_base</b>, so you should use <b>std::ios::badbit</b>, <b>std::ios::failbit</b> and <b>std::ios::eofbit</b> and <b>std::ios::goodbit</b>. </p> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-vector-at"></a>vector::at is missing (i.e. gcc 2.95.x)</h2></div></div> <p> One solution is to add an autoconf-test for this: <pre class="programlisting"> AC_MSG_CHECKING(for container::at) AC_TRY_COMPILE( [ #include <vector> #include <deque> #include <string> using namespace std; ], [ deque<int> test_deque(3); test_deque.at(2); vector<int> test_vector(2); test_vector.at(1); string test_string("test_string"); test_string.at(3); ], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_CONTAINER_AT)], [AC_MSG_RESULT(no)]) </pre> If you are using other (non-GNU) compilers it might be a good idea to check for <b>string::at</b> separately. </p> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-eof"></a>Using std::char_traits<char>::eof()</h2></div></div> <p> <pre class="programlisting"> #ifdef HAVE_CHAR_TRAITS #define CPP_EOF std::char_traits<char>::eof() #else #define CPP_EOF EOF #endif </pre> </p> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-string-clear"></a>Using string::clear()/string::erase()</h2></div></div> <p> There are two functions for deleting the contents of a string: <b>clear</b> and <b>erase</b> (the latter returns the string). <pre class="programlisting"> void clear() { _M_mutate(0, this->size(), 0); } </pre> <pre class="programlisting"> basic_string& erase(size_type __pos = 0, size_type __n = npos) { return this->replace(_M_check(__pos), _M_fold(__pos, __n), _M_data(), _M_data()); } </pre> The implementation of <b>erase</b> seems to be more complicated (from libstdc++-v3), but <b>clear</b> is not implemented in gcc 2.95.x's libstdc++, so you should use <b>erase</b> (which is probably faster than <b>operator=(charT*)</b>). </p> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-scan-form"></a>GNU Extensions ostream::form and istream::scan</h2></div></div> <p> These are not supported any more - use <a href="#sec-stringstream" title="Using stringstreams"> stringstreams</a> instead. </p> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-stringstream"></a>Using stringstreams</h2></div></div> <p> Libstdc++-v3 provides the new <b>i/ostringstream</b>-classes, (<tt><sstream></tt>), but for compatibility with older implementations you still have to use <b>i/ostrstream</b> (<tt><strstream></tt>): <pre class="programlisting"> #ifdef HAVE_SSTREAM #include <sstream> #else #include <strstream> #endif </pre> <div class="itemizedlist"><ul type="disc"> <li><p> <b>strstream</b> is considered to be deprecated </p></li> <li><p> <b>strstream</b> is limited to <b>char</b> </p></li> <li><p> with <b>ostringstream</b> you don't have to take care of terminating the string or freeing its memory </p></li> <li><p> <b>istringstream</b> can be re-filled (clear(); str(input);) </p></li> </ul></div> </p> <p> You can then use output-stringstreams like this: <pre class="programlisting"> #ifdef HAVE_SSTREAM std::ostringstream oss; #else std::ostrstream oss; #endif oss << "Name=" << m_name << ", number=" << m_number << std::endl; ... #ifndef HAVE_SSTREAM oss << std::ends; // terminate the char*-string #endif // str() returns char* for ostrstream and a string for ostringstream // this also causes ostrstream to think that the buffer's memory // is yours m_label.set_text(oss.str()); #ifndef HAVE_SSTREAM // let the ostrstream take care of freeing the memory oss.freeze(false); #endif </pre> </p> <p> Input-stringstreams can be used similarly: <pre class="programlisting"> std::string input; ... #ifdef HAVE_SSTREAM std::istringstream iss(input); #else std::istrstream iss(input.c_str()); #endif int i; iss >> i; </pre> One (the only?) restriction is that an istrstream cannot be re-filled: <pre class="programlisting"> std::istringstream iss(numerator); iss >> m_num; // this is not possible with istrstream iss.clear(); iss.str(denominator); iss >> m_den; </pre> If you don't care about speed, you can put these conversions in a template-function: <pre class="programlisting"> template <class X> void fromString(const string& input, X& any) { #ifdef HAVE_SSTREAM std::istringstream iss(input); #else std::istrstream iss(input.c_str()); #endif X temp; iss >> temp; if (iss.fail()) throw runtime_error(..) any = temp; } </pre> Another example of using stringstreams is in <a href="../21_strings/howto.html" target="_top">this howto</a>. </p> <p> I have read the Josuttis book on Standard C++, so some information comes from there. Additionally, there is information in "info iostream", which covers the old implementation that gcc 2.95.x uses. </p> </div> <div class="section"> <div class="titlepage"><div><h2 class="title" style="clear: both"> <a name="sec-about"></a>About...</h2></div></div> <p> Please send any experience, additions, corrections or questions to <a href="mailto:fnatter@gmx.net" target="_top">fnatter@gmx.net</a> or for discussion to the libstdc++-v3-mailing-list. </p> </div> </div></body> </html>