// This is part of the iostream library, providing input/output for C++.
// Copyright (C) 1991, 1992 Per Bothner.
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <stdio.h> /* Needed for sprintf */
#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
//#define isspace(ch) ((ch)==' ' || (ch)=='\t' || (ch)=='\n')
istream::istream(streambuf *sb, ostream* tied) : ios(sb, tied)
_flags |= ios::dont_close;
int skip_ws(streambuf* sb)
if (ch == EOF || !isspace(ch))
istream& istream::get(char& c)
int ch = _strbuf->sbumpc();
set(ios::eofbit|ios::failbit);
if (_tie && rdbuf()->in_avail() == 0)
int ch = _strbuf->sgetc();
istream& istream::ignore(int n /* = 1 */, int delim /* = EOF */)
register streambuf* sb = _strbuf;
if (n != MAXINT) // FIXME
set(ios::eofbit|ios::failbit);
istream& istream::read(char *s, int n)
_gcount = _strbuf->sgetn(s, n);
istream& istream::seekg(streampos pos)
pos = _strbuf->seekpos(pos, ios::in);
if (pos == streampos(EOF))
istream& istream::seekg(streamoff off, _seek_dir dir)
streampos pos = _strbuf->seekoff(off, dir, ios::in);
if (pos == streampos(EOF))
streampos istream::tellg()
streampos pos = _strbuf->seekoff(0, ios::cur, ios::in);
if (pos == streampos(EOF))
istream& istream::scan(const char *format ...)
_strbuf->vscan(format, ap, this);
istream& istream::vscan(const char *format, _G_va_list args)
_strbuf->vscan(format, args, this);
istream& istream::operator>>(char& c)
int ch = _strbuf->sbumpc();
set(ios::eofbit|ios::failbit);
istream& istream::operator>>(char* ptr)
register streambuf* sb = _strbuf;
set(p == ptr ? (ios::eofbit|ios::failbit) : (ios::eofbit));
#define LONGEST long long
static int read_int(istream& stream, unsigned LONGEST& val, int& neg)
register streambuf* sb = stream.rdbuf();
register int ch = skip_ws(sb);
if (ch == EOF) goto eof_fail;
if (!(stream.flags() & ios::basefield)) {
if (ch == 'x' || ch == 'X') {
if (ch == EOF) goto eof_fail;
else if ((stream.flags() & ios::basefield) == ios::hex)
else if ((stream.flags() & ios::basefield) == ios::oct)
if (ch >= '0' && ch <= '9')
else if (ch >= 'A' && ch <= 'F')
else if (ch >= 'a' && ch <= 'f')
val = base * val + digit;
stream.set(ios::failbit);
stream.set(ios::failbit|ios::eofbit);
istream& istream::operator>>(TYPE& i)\
unsigned LONGEST val; int neg;\
if (read_int(*this, val, neg)) {\
READ_INT(unsigned long long)
istream& istream::operator>>(double& x)
istream& istream::operator>>(float& x)
istream& istream::operator>>(register streambuf* sbuf)
register streambuf* inbuf = rdbuf();
// FIXME: Should optimize!
register int ch = inbuf->sbumpc();
if (sbuf->sputc(ch) == EOF) {
ostream& ostream::operator<<(char c)
// This is what the cfront implementation does.
// This is what cfront documentation and current ANSI drafts say.
register int padding = w > 0 ? w - 1 : 0;
register streambuf *sb = _strbuf;
if (!(flags() & ios::left)) // Default adjustment.
while (--padding >= 0) sb->sputc(fill_char);
if (flags() & ios::left) // Left adjustment.
while (--padding >= 0) sb->sputc(fill_char);
If SIGN<0, val is the absolute value of a negative number.
If SIGN>0, val is a signed non-negative number.
If SIGN==0, val is unsigned. */
static void write_int(ostream& stream, unsigned LONGEST val, int sign)
#define WRITE_BUF_SIZE (10 + sizeof(unsigned LONGEST) * 3)
char buf[WRITE_BUF_SIZE];
register char *buf_ptr = buf+WRITE_BUF_SIZE; // End of buf.
int show_pos = 0; // If 1, print a '+'.
// Now do the actual conversion, placing the result at the *end* of buf.
// Note that we use separate code for decimal, octal, and hex,
// so we can divide by optimizable constants.
if ((stream.flags() & ios::basefield) == ios::oct) { // Octal
*--buf_ptr = (val & 7) + '0';
if ((stream.flags() & ios::showbase) && (val != 0))
else if ((stream.flags() & ios::basefield) == ios::hex) { // Hex
char *xdigs = (stream.flags() & ios::uppercase) ? "0123456789ABCDEF0X"
*--buf_ptr = xdigs[val & 15];
if ((stream.flags() & ios::showbase) && (val != 0)) {
show_base = xdigs + 16; // Either "0X" or "0x".
// Optimization: Only use long long when we need to.
*--buf_ptr = (val % 10) + '0';
// Use more efficient (int) arithmetic for the rest.
register unsigned int ival = (unsigned int)val;
register unsigned LONGEST ival = val;
*--buf_ptr = (ival % 10) + '0';
if (sign > 0 && (stream.flags() & ios::showpos))
int buf_len = buf+WRITE_BUF_SIZE - buf_ptr;
int len = buf_len+show_pos;
int padding = len > w ? 0 : w - len;
register streambuf* sbuf = stream.rdbuf();
stream.flags() & (ios::left|ios::right|ios::internal);
char fill_char = stream.fill();
&& pad_kind != (ios::fmtflags)ios::left
&& pad_kind != (ios::fmtflags)ios::internal) // Default (right) adjust.
sbuf->padn(fill_char, padding);
if (sign < 0) sbuf->sputc('-');
else if (show_pos) sbuf->sputc('+');
sbuf->sputn(show_base, show_base_len);
if (pad_kind == (ios::fmtflags)ios::internal && padding > 0)
sbuf->padn(fill_char, padding);
sbuf->sputn(buf_ptr, buf_len);
if (pad_kind == (ios::fmtflags)ios::left && padding > 0) // Left adjustment
sbuf->padn(fill_char, padding);
ostream& ostream::operator<<(int n)
if (n < 0 && (flags() & (ios::oct|ios::hex)) == 0)
write_int(*this, n, sign);
ostream& ostream::operator<<(unsigned int n)
ostream& ostream::operator<<(long n)
if (n < 0 && (flags() & (ios::oct|ios::hex)) == 0)
write_int(*this, n, sign);
ostream& ostream::operator<<(unsigned long n)
ostream& ostream::operator<<(long long n)
if (n < 0 && (flags() & (ios::oct|ios::hex)) == 0)
write_int(*this, n, sign);
ostream& ostream::operator<<(unsigned long long n)
ostream& ostream::operator<<(double n)
// Uses __cvt_double (renamed from static cvt), in Chris Torek's
// stdio implementation. The setup code uses the same logic
// as in __vsbprintf.C (also based on Torek's code).
if (flags() ios::showpos) sign = '+';
if ((flags() & ios::floatfield) == ios::fixed)
else if ((flags() & ios::floatfield) == ios::scientific)
format_char = flags() & ios::uppercase ? 'E' : 'e';
format_char = flags() & ios::uppercase ? 'G' : 'g';
int fpprec = 0; // 'Extra' (suppressed) floating precision.
if (flags() & (ios::fixed|ios::scientific) & ios::showpos)
fpprec = prec - MAXFRACT;
else if (prec <= 0 && !(flags() & ios::fixed))
if (__outfloat(n, rdbuf(), format_char, width(0),
prec, flags(), 0, fill()) < 0)
set(ios::badbit|ios::failbit); // ??
int size = __cvt_double(n, prec,
flags() & ios::showpoint ? 0x80 : 0,
format_char, cp, buf + sizeof(buf));
if (negative) sign = '-';
int fieldsize = size + fpprec;
register streambuf* sbuf = rdbuf();
flags() & (ios::left|ios::right|ios::internal);
if (pad_kind != (ios::fmtflags)ios::left // Default (right) adjust.
&& pad_kind != (ios::fmtflags)ios::internal)
for (i = padding; --i >= 0; ) sbuf->sputc(fill_char);
if (pad_kind == (ios::fmtflags)ios::internal)
for (i = padding; --i >= 0; ) sbuf->sputc(fill_char);
// Emit the actual concented field, followed by extra zeros.
for (i = fpprec; --i >= 0; ) sbuf->sputc('0');
if (pad_kind == (ios::fmtflags)ios::left) // Left adjustment
for (i = padding; --i >= 0; ) sbuf->sputc(fill_char);
ostream& ostream::operator<<(const char *s)
register streambuf *sbuf = rdbuf();
register int padding = w > len ? w - len : 0;
if (!(flags() & ios::left)) // Default adjustment.
while (--padding >= 0) sbuf->sputc(fill_char);
if (flags() & ios::left) // Left adjustment.
while (--padding >= 0) sbuf->sputc(fill_char);
ostream& ostream::operator<<(const void *p)
ostream& ostream::operator<<(register streambuf* sbuf)
register streambuf* outbuf = rdbuf();
// FIXME: Should optimize!
register int ch = sbuf->sbumpc();
if (outbuf->sputc(ch) == EOF) {
ostream::ostream(streambuf* sb, ostream* tied) : ios(sb, tied)
_flags |= ios::dont_close;
ostream& ostream::seekp(streampos pos)
pos = _strbuf->seekpos(pos, ios::out);
if (pos == streampos(EOF))
ostream& ostream::seekp(streamoff off, _seek_dir dir)
streampos pos = _strbuf->seekoff(off, dir, ios::out);
if (pos == streampos(EOF))
streampos ostream::tellp()
streampos pos = _strbuf->seekoff(0, ios::cur, ios::out);
if (pos == streampos(EOF))
ostream& ostream::form(const char *format ...)
_strbuf->vform(format, ap);
ostream& ostream::vform(const char *format, _G_va_list args)
_strbuf->vform(format, args);
ostream& ostream::flush()
ostream& flush(ostream& outs)
istream& ws(istream& ins)
int ch = skip_ws(ins._strbuf);
ins._strbuf->sputbackc(ch);
// Skip white-space. Return 0 on failure (EOF), or 1 on success.
// Differs from ws() manipulator in that failbit is set on EOF.
// Called by ipfx() and ipfx0() if needed.
int ch = skip_ws(_strbuf);
set(ios::eofbit|ios::failbit);
ostream& ends(ostream& outs)
ostream& endl(ostream& outs)
return flush(outs.put('\n'));
ostream& ostream::write(const char *s, int n)
if (_strbuf->sputn(s, n) != n)
if (flags() & ios::unitbuf)
if (flags() & ios::stdio) {
iostream::iostream(streambuf* sb, ostream* tied) : ios(sb, tied)
_flags |= ios::dont_close;
// NOTE: extension for compatibility with old libg++.
// Not really compatible with fistream::close().
if (!(_flags & (unsigned int)ios::dont_close))
else if (_strbuf->_flags & _S_IS_FILEBUF)
((struct filebuf*)_strbuf)->close();
else if (_strbuf != NULL)
_flags |= ios::dont_close;
int old = (_flags & ios::skipws) != 0;