blob: 3a0cea08129d7943fac9b68ec4f627c14904fe4a [file] [log] [blame]
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright
ownership. The ASF licenses this file to you under the Apache
License, Version 2.0 (the License); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
Copyright 1999-2007 Rogue Wave Software, Inc.
-->
<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>Apache C++ Standard Library 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>