cppannotations/annotations/yo/concrete/fistream.yo

70 lines
4 KiB
Text

Usually when extracting information from tt(istream) objects oprshift(), the
standard extraction operator is perfectly suited for the task as in most
cases the extracted fields are white-space (or otherwise clearly) separated
from each other. But this does not hold true in all situations. For example,
when a web-form is posted to some processing script or program, the receiving
program may receive the form field's values as em(url-encoded)
characters: letters and digits are sent unaltered, blanks are sent as tt(+)
characters, and all other characters start with tt(%) followed by the
character's
i(ascii-value) represented by its two digit hexadecimal value.
When decoding url-encoded information, simple hexadecimal extraction won't
work, as that extracts as many hexadecimal characters as available,
instead of just two. Since the letters tt(a-f`) and tt(0-9) are legal
hexadecimal characters, a text like tt(My name is `Ed'), url-encoded as
verb(
My+name+is+%60Ed%27
)
results in the extraction of the hexadecimal values tt(60ed) and tt(27),
instead of tt(60) and tt(27). The name tt(Ed) disappears from view, which is
clearly not what we want.
In this case, having seen the tt(%), we could extract 2 characters, put
them in an ti(istringstream) object, and extract the hexadecimal value from
the tt(istringstream) object. A bit cumbersome, but doable. Other approaches
are possible as well.
The class ti(Fistream) for em(fixed-sized field istream) defines
an tt(istream) class supporting both fixed-sized field extractions and
blank-delimited extractions (as well as unformatted tt(read) calls). The
class may be initialized as a emi(wrapper) around an existing tt(istream), or
it can be initialized using the name of an existing file. The class is derived
from tt(istream), allowing all extractions and operations supported by
tt(istream)s in general. tt(Fistream) defines the following data members:
itemization(
itt(d_filebuf): a filebuffer used when tt(Fistream) reads its information
from a named (existing) file. Since the filebuffer is only needed in
that case, and since it must be allocated dynamically, it is defined
as a tt(unique_ptr<filebuf>) object.
itt(d_streambuf): a pointer to tt(Fistream)'s tt(streambuf). It points
to tt(d_filebuf) when tt(Fistream) opens a file by name. When an
existing tt(istream) is used to construct an tt(Fistream), it
points to the existing tt(istream)'s tt(streambuf).
itt(d_iss): an tt(istringstream) object used for the fixed field
extractions.
itt(d_width): a tt(size_t) indicating the width of the field to
extract. If 0 no fixed field extractions is used, but
information is extracted from the tt(istream) base class object
using standard extractions.
)
Here is the initial section of tt(Fistream)'s class interface:
verbinclude(//INITIAL examples/fistream/fistream.h)
As stated, tt(Fistream) objects can be constructed from either a
filename or an existing tt(istream) object. The class interface therefore
declares two constructors:
verbinclude(//CONS examples/fistream/fistream.h)
When an tt(Fistream) object is constructed using an existing tt(istream)
object, the tt(Fistream)'s tt(istream) part simply uses the tt(stream)'s
tt(streambuf) object:
verbinclude(//CONS1 examples/fistream/fistream.cc)
When an tt(fstream) object is constructed using a filename, the
tt(istream) base initializer is given a new tt(filebuf) object to be used as
its tt(streambuf). Since the class's data members are not initialized before
the class's base class has been constructed, tt(d_filebuf) can only be
initialized thereafter. By then, the tt(filebuf) is only available as
tt(rdbuf), returning a tt(streambuf). However, as it is actually a
tt(filebuf), a tt(static_cast) is used to cast the tt(streambuf) pointer
returned by tt(rdbuf) to tt(a filebuf *), so tt(d_filebuf) can be initialized:
verbinclude(//CONS2 examples/fistream/fistream.cc)