blob: 53e4253f3698044d55200c1cc7464d098b133af7 [file] [log] [blame]
<HTML>
<HEAD>
<TITLE>Another Look at the Date Format String</TITLE>
<LINK REL=StyleSheet HREF="../rw.css" TYPE="text/css" TITLE="Apache stdcxx Stylesheet"></HEAD>
<BODY BGCOLOR=#FFFFFF>
<A HREF="36-2.html"><IMG SRC="images/bprev.gif" WIDTH=20 HEIGHT=21 ALT="Previous file" BORDER=O></A><A HREF="noframes.html"><IMG SRC="images/btop.gif" WIDTH=56 HEIGHT=21 ALT="Top of Document" BORDER=O></A><A HREF="booktoc.html"><IMG SRC="images/btoc.gif" WIDTH=56 HEIGHT=21 ALT="Contents" BORDER=O></A><A HREF="tindex.html"><IMG SRC="images/bindex.gif" WIDTH=56 HEIGHT=21 ALT="Index page" BORDER=O></A><A HREF="36-4.html"><IMG SRC="images/bnext.gif" WIDTH=25 HEIGHT=21 ALT="Next file" BORDER=O></A><DIV CLASS="DOCUMENTNAME"><B>Apache C++ Standard Library User's Guide</B></DIV>
<H2>36.3 Another Look at the Date Format String</H2>
<A NAME="idx891"><!></A>
<P>We would like to store the date format string in the iostream storage through <SAMP>std::ios_base::iword()</SAMP> and <SAMP>std::ios_base::pword()</SAMP>. In this way, the input and output operations for <SAMP>date</SAMP> objects can access the format string for parsing and formatting. Format parameters are often set with manipulators (see <A HREF="28-3.html#2832">Section&nbsp;28.3.2</A>), so we should add a manipulator that sets the date format string. It could be used like this:</P>
<UL><PRE>
date today;
std::ofstream ostr;
// ...
ostr &lt;&lt; setfmt("%D") &lt;&lt; today;
</PRE></UL>
<A NAME="idx892"><!></A>
<P>Here is a suggested implementation for such a manipulator (note that the name of the base class is implementation-defined):</P>
<UL><PRE>
class setfmt : public <I>smanip</I>&lt;const char*&gt;
{
public:
setfmt(const char* fmt)
: <I>smanip</I>&lt;const char*&gt;(setfmt_,fmt) {}
private:
static const int datfmtIdx; //1
static std::ios_base&amp; setfmt_(std::ios_base&amp; str,
const char* fmt)
{
str.pword(datfmtIdx) = const_cast&lt;char*&gt; (fmt); //2
return str;
}
template&lt;class charT, class Traits&gt;
friend std::basic_ostream&lt;charT, Traits&gt;&amp; //3
operator&lt;&lt;(basic_ostream&lt;charT, Traits&gt;&amp; os,
const date&amp; dat);
};
const int setfmt::datfmtIdx = std::ios_base::xalloc(); //4
</PRE></UL>
<A NAME="idx893"><!></A>
<P>The technique applied to implement the manipulator is described in detail in Example 2 of <A HREF="33-3.html">Section&nbsp;33.3</A>, so we won't repeat it here. But regarding this manipulator and the private use of iostream storage, there are other interesting details:</P>
<TABLE CELLPADDING="3">
<TR VALIGN="top"><TD><SAMP>//1</SAMP></TD><TD>The manipulator class owns the index of the element in the iostream storage where we want to store the format string. It is initialized in <SAMP>//4</SAMP> by a call to <SAMP>xalloc()</SAMP>.
<TR VALIGN="top"><TD><SAMP>//2</SAMP></TD><TD>The manipulator accesses the array <SAMP>pword()</SAMP> using the index <SAMP>datfmtIdx</SAMP>, and stores the pointer to the date format string. [For brevity, error handling is omitted in the example. If allocation fails, then <SAMP>std::ios_base::badbit</SAMP> is set.] Note that the reference returned by <SAMP>pword()</SAMP> is only used for <I>storing</I> the pointer to the date format string. Generally, you should never store a reference returned by <SAMP>iword()</SAMP> or <SAMP>pword()</SAMP> in order to access the stored data through this reference later on. This is because these references can become invalid once the array is reallocated or copied. (See the <A HREF="../stdlibref/noframes.html"><I>C++ Standard Library Module Reference Guide</I></A> for more details.)
<TR VALIGN="top"><TD><SAMP>//3</SAMP></TD><TD>The inserter for <SAMP>date</SAMP> objects needs to access the index into the array of pointers, so that it can read the format string and use it. Therefore, the inserter must be declared as a friend. In principle, the extractor must be a friend, too; however, the standard C++ locale falls short of supporting the use of format strings like the ones used by the standard C function <SAMP>strptime()</SAMP>. Hence, the implementation of a date extractor that supports date format strings would be a lot more complicated than the implementation for the inserter, which can use the stream's locale. We have omitted the extractor for the sake of brevity.
<TR VALIGN="top"><TD><SAMP>//4</SAMP></TD><TD>Initializes the index of elements in istream storage where the format string is kept.
</TABLE>
<A NAME="idx894"><!></A>
<P>The inserter for <SAMP>date</SAMP> objects given below is almost identical to the one we described in <A HREF="32-5.html#3251">Section&nbsp;32.5.1</A>:</P>
<UL><PRE>
template&lt;class charT, class Traits&gt;
std::basic_ostream&lt;charT, Traits&gt; &amp;
operator &lt;&lt; (std::basic_ostream&lt;charT, Traits &gt;&amp; os,
const date&amp; dat)
{
std::ios_base::iostate err = 0;
charT* fmt = 0;
try {
typename std::basic_ostream&lt;charT, Traits&gt;::sentry opfx(os);
if(opfx)
{
char* patt = static_cast&lt;char*&gt;
(os.pword(setfmt.datfmtIdx); //1
std::size_t len = std::strlen(patt);
fmt = new charT[len];
std::use_facet&lt;std::ctype&lt;charT&gt; &gt;(os.getloc()).
widen(patt, patt+len, fmt);
if (std::use_facet&lt;std::time_put&lt;charT,
std::ostreambuf_iterator&lt;charT,Traits&gt; &gt; &gt;
(os.getloc())
.put(os,os,os.fill(),&amp;dat.tm_date,fmt,fmt+len) //2
.failed()
)
err = std::ios_base::badbit;
os.width(0);
}
}
catch(...)
{
delete [] fmt;
bool flag = false;
try {
os.setstate(std::ios_base::failbit);
}
catch(std::ios_base::failure) {
flag = true;
}
if (flag)
throw;
}
delete [] fmt;
if ( err )
os.setstate(err);
return os;
}
</PRE></UL>
<P>The only change from the previous inserter is that the format string here is read from the iostream storage (in statement <SAMP>//1</SAMP>) instead of being the fixed string <SAMP>"%x"</SAMP>. The format string is then provided to the locale's time formatting facet (in statement <SAMP>//2</SAMP>).</P>
<BR>
<HR>
<A HREF="36-2.html"><IMG SRC="images/bprev.gif" WIDTH=20 HEIGHT=21 ALT="Previous file" BORDER=O></A><A HREF="noframes.html"><IMG SRC="images/btop.gif" WIDTH=56 HEIGHT=21 ALT="Top of Document" BORDER=O></A><A HREF="booktoc.html"><IMG SRC="images/btoc.gif" WIDTH=56 HEIGHT=21 ALT="Contents" BORDER=O></A><A HREF="tindex.html"><IMG SRC="images/bindex.gif" WIDTH=56 HEIGHT=21 ALT="Index page" BORDER=O></A><A HREF="36-4.html"><IMG SRC="images/bnext.gif" WIDTH=20 HEIGHT=21 ALT="Next file" BORDER=O></A>
<!-- Google Analytics tracking code -->
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-1775151-1";
urchinTracker();
</script>
<!-- end of Google Analytics tracking code -->
</BODY>
</HTML>