// This is part of the iostream library, providing input/output for C++. // Copyright (C) 1991 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. #ifdef __GNUG__ #pragma implementation #endif #define _STREAM_COMPAT #include "ioprivat.h" #include #include /* Needed for sprintf */ #include #include "floatio.h" #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ //#define isspace(ch) ((ch)==' ' || (ch)=='\t' || (ch)=='\n') extern streambuf not_open_filebuf; istream::istream() : ios(¬_open_filebuf) { _flags |= ios::dont_close; _gcount = 0; _tie = NULL; } istream::istream(streambuf *sb, ostream* tied) : ios(sb) { _flags |= ios::dont_close; _gcount = 0; _tie = tied; } istream::~istream() { if (!(_flags & (unsigned int)ios::dont_close)) delete _strbuf; _flags |= ios::dont_close; _strbuf = ¬_open_filebuf; } int skip_ws(streambuf* sb) { int ch; for (;;) { ch = sb->sbumpc(); if (ch == EOF || !isspace(ch)) return ch; } } istream& istream::get(char& c) { if (ipfx1()) { int ch = _strbuf->sbumpc(); if (ch == EOF) set(ios::eofbit|ios::failbit); else c = (char)ch; } return *this; } istream& istream::get(unsigned char& c) { if (ipfx1()) { int ch = _strbuf->sbumpc(); if (ch == EOF) set(ios::eofbit|ios::failbit); else c = (unsigned char)ch; } return *this; } istream& istream::ignore(int n=1, int delim = EOF) { if (ipfx1()) { register streambuf* sb = _strbuf; for (;;) { // Could skip multiple chars at a time if egptr() > gptr(), // if delim==EOF. FIXME! #if 0 if (n != MAXINT) // FIXME #endif if (--n < 0) break; int ch = sb->sbumpc(); if (ch == EOF) { set(ios::eofbit|ios::failbit); break; } else if (ch == delim) break; } } return *this; } istream& istream::read(char *s, size_t n) { if (ipfx1()) { if (_strbuf->sgetn(s, n) != n) set(ios::failbit); } return *this; } istream& istream::seekg(streampos pos) { pos = _strbuf->seekpos(pos, ios::in); if (pos == streampos(EOF)) set(ios::badbit); return *this; } istream& istream::seekg(streamoff off, _seek_dir dir) { streampos pos = _strbuf->seekoff(off, dir, ios::in); if (pos == streampos(EOF)) set(ios::badbit); return *this; } streampos istream::tellg() { streampos pos = _strbuf->seekoff(0, ios::cur, ios::in); if (pos == streampos(EOF)) set(ios::badbit); return pos; } istream& operator>>(istream& is, char& c) { if (is.ipfx0()) { int ch = is._strbuf->sbumpc(); if (ch == EOF) is.set(ios::eofbit|ios::failbit); else c = (char)ch; } return is; } istream& operator>>(istream& is, unsigned char& c) { if (is.ipfx0()) { int ch = is._strbuf->sbumpc(); if (ch == EOF) is.set(ios::eofbit|ios::failbit); else c = (unsigned char)ch; } return is; } istream& operator>>(istream& is, char* ptr) { if (is.ipfx0()) { register streambuf* sb = is._strbuf; int ch = sb->sbumpc(); if (ch == EOF) is.set(ios::eofbit|ios::failbit); else { int w = is.width(0); *ptr++ = ch; for (;;) { ch = sb->sbumpc(); if (ch == EOF) { is.set(ios::eofbit); break; } else if (isspace(ch)) { sb->sputbackc(ch); break; } else if (w == 1) { is.set(ios::failbit); sb->sputbackc(ch); break; } else *ptr++ = ch; w--; } } } *ptr = '\0'; return is; } static int read_int(istream& stream, unsigned long& val, int& neg) { if (!stream.ipfx0()) return 0; register streambuf* sb = stream.rdbuf(); int base = 10; int ndigits = 0; register int ch = skip_ws(sb);; if (ch == EOF) goto eof_fail; neg = 0; if (ch == '+') { ch = skip_ws(sb); } else if (ch == '-') { neg = 1; ch = skip_ws(sb); } if (ch == EOF) goto eof_fail; if (!(stream.flags() & (ios::hex|ios::dec|ios::oct))) { if (ch == '0') { ch = sb->sbumpc(); if (ch == EOF) { stream.set(ios::eofbit); val = 0; return 1; } if (ch == 'x' || ch == 'X') { base = 16; ch = sb->sbumpc(); if (ch == EOF) goto eof_fail; } else { sb->sputbackc(ch); base = 8; ch = '0'; } } } else if (stream.flags() & ios::hex) base = 16; else if (stream.flags() & ios::oct) base = 8; val = 0; for (;;) { if (ch == EOF) { stream.set(ios::eofbit); break; } int digit; if (ch >= '0' && ch <= '9') digit = ch - '0'; else if (ch >= 'A' && ch <= 'F') digit = ch - 'A' + 10; else if (ch >= 'a' && ch <= 'f') digit = ch - 'a' + 10; else digit = 999; if (digit >= base) if (ndigits == 0) goto fail; else { sb->sputbackc(ch); return 1; } ndigits++; val = base * val + digit; ch = sb->sbumpc(); } return 1; fail: stream.set(ios::failbit); return 0; eof_fail: stream.set(ios::failbit|ios::eofbit); return 0; } #define READ_INT(TYPE) \ istream& operator>>(istream& is, TYPE& i)\ {\ unsigned long val; int neg;\ if (read_int(is, val, neg)) {\ if (neg) val = -val;\ i = (TYPE)val;\ }\ return is;\ } READ_INT(short) READ_INT(unsigned short) READ_INT(int) READ_INT(unsigned int) READ_INT(long) READ_INT(unsigned long) istream& operator>>(istream& is, double& x) { if (is.ipfx0()) { double* ptr = &x; is.rdbuf()->vscan("%lg", (_G_va_list)&ptr); } return is; } istream& operator>>(istream& is, float& x) { if (is.ipfx0()) { float* ptr = &x; is.rdbuf()->vscan("%g", (_G_va_list)&ptr); } return is; } ostream& operator<<(ostream& os, char c) { if (os.opfx()) { int w = os.width(0); char fill_char = os.fill(); register int padding = w > 0 ? w - 1 : 0; register streambuf *sb = os._strbuf; if (!(os.flags() & ios::left)) // Default adjustment. while (--padding >= 0) sb->sputc(fill_char); sb->sputc(c); if (os.flags() & ios::left) // Left adjustment. while (--padding >= 0) sb->sputc(fill_char); os.osfx(); } return os; } void write_int(ostream& stream, unsigned long val, int neg) { char buf[10 + sizeof(unsigned long) * 3]; char *show_base = ""; int show_base_len = 0; if ((stream.flags() & (ios::oct|ios::hex)) == 0) // Decimal sprintf(buf, "%lu", val); else if (stream.flags() & ios::oct) { // Oct sprintf(buf, "%lo", val); if (stream.flags() && ios::showbase) show_base = "0", show_base_len = 1; } else if (stream.flags() & ios::uppercase) {// Hex sprintf(buf, "%lX", val); if (stream.flags() && ios::showbase) show_base = "0X", show_base_len = 2; } else { // Hex sprintf(buf, "%lx", val); if (stream.flags() && ios::showbase) show_base = "0x", show_base_len = 2; } int buf_len = strlen(buf); int w = stream.width(0); int show_pos = 0; int i; // Calculate padding. int len = buf_len; if (neg) len++; else if (val != 0 && (stream.flags() & ios::showpos)) len++, show_pos=1; len += show_base_len; int padding = len > w ? 0 : w - len; // Do actual output. register streambuf* sbuf = stream.rdbuf(); unsigned long pad_kind = stream.flags() & (ios::left|ios::right|ios::internal); char fill_char = stream.fill(); if (pad_kind != (unsigned long)ios::left // Default (right) adjustment. && pad_kind != (unsigned long)ios::internal) for (i = padding; --i >= 0; ) sbuf->sputc(fill_char); if (neg) sbuf->sputc('-'); else if (show_pos) sbuf->sputc('+'); if (show_base_len) sbuf->sputn(show_base, show_base_len); if (pad_kind == (unsigned long)ios::internal) for (i = padding; --i >= 0; ) sbuf->sputc(fill_char); sbuf->sputn(buf, buf_len); if (pad_kind == (unsigned long)ios::left) // Left adjustment. for (i = padding; --i >= 0; ) sbuf->sputc(fill_char); stream.osfx(); } ostream& operator<<(ostream& os, int n) { if (os.opfx()) { int neg = 0; if (n < 0 && (os.flags() & (ios::oct|ios::hex)) == 0) n = -n, neg = 1; write_int(os, n, neg); } return os; } ostream& operator<<(ostream& os, long n) { if (os.opfx()) { int neg = 0; if (n < 0 && (os.flags() & (ios::oct|ios::hex)) == 0) n = -n, neg = 1; write_int(os, n, neg); } return os; } ostream& operator<<(ostream& os, unsigned int n) { if (os.opfx()) write_int(os, n, 0); return os; } ostream& operator<<(ostream& os, unsigned long n) { if (os.opfx()) write_int(os, n, 0); return os; } ostream& operator<<(ostream& os, float n) { return os << (double)n; } ostream& operator<<(ostream& os, double n) { if (os.opfx()) { // 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). char negative; char buf[BUF]; int format_char; int sign = '\0'; #if 0 if (os.flags() ios::showpos) sign = '+'; #endif if (os.flags() & ios::fixed) format_char = 'f'; else if (os.flags() & ios::scientific) format_char = os.flags() & ios::uppercase ? 'E' : 'e'; else format_char = os.flags() & ios::uppercase ? 'G' : 'g'; int fpprec = 0; // 'Extra' (suppressed) floating precision. int prec = os.precision(); if (prec < 0) prec = 6; // default. else if (prec > MAXFRACT) { if (os.flags() & (ios::fixed|ios::scientific) & ios::showpos) fpprec = prec - MAXFRACT; prec = MAXFRACT; } // Do actual conversion. char *cp = buf; *cp = 0; int size = __cvt_double(n, os.precision(), os.flags() & ios::showpoint ? 0x80 : 0, &negative, format_char, cp, buf + sizeof(buf)); if (negative) sign = '-'; if (*cp == 0) cp++; // Calculate padding. int fieldsize = size + fpprec; if (sign) fieldsize++; int padding = 0; int w = os.width(0); if (fieldsize < w) padding = w - fieldsize; // Do actual output. register streambuf* sbuf = os.rdbuf(); register i; char fill_char = os.fill(); unsigned long pad_kind = os.flags() & (ios::left|ios::right|ios::internal); if (pad_kind != (unsigned long)ios::left // Default (right) adjust. && pad_kind != (unsigned long)ios::internal) for (i = padding; --i >= 0; ) sbuf->sputc(fill_char); if (sign) sbuf->sputc(sign); if (pad_kind == (unsigned long)ios::internal) for (i = padding; --i >= 0; ) sbuf->sputc(fill_char); // Emit the actual concented field, followed by extra zeros. sbuf->sputn(cp, size); for (i = fpprec; --i >= 0; ) sbuf->sputc('0'); if (pad_kind == (unsigned long)ios::left) // Left adjustment for (i = padding; --i >= 0; ) sbuf->sputc(fill_char); os.osfx(); } return os; } ostream& operator<<(ostream& stream, const char *s) { if (stream.opfx()) { size_t len = strlen(s); int w = stream.width(0); char fill_char = stream.fill(); register streambuf *sbuf = stream.rdbuf(); register int padding = w > len ? w - len : 0; if (!(stream.flags() & ios::left)) // Default adjustment. while (--padding >= 0) sbuf->sputc(fill_char); sbuf->sputn(s, len); if (stream.flags() & ios::left) // Left adjustment. while (--padding >= 0) sbuf->sputc(fill_char); stream.osfx(); } return stream; } ostream& operator<<(ostream& os, void *p) { if (os.opfx()) { void *px = p; os._strbuf->vform("0x%x", (_G_va_list)&px); os.osfx(); } return os; } ostream& operator<<(ostream& os, register streambuf* sbuf) { if (os.opfx()) { register streambuf* outbuf = os.rdbuf(); // FIXME: Should optimize! for (;;) { register int ch = sbuf->sbumpc(); if (ch == EOF) break; outbuf->sputc(ch); } os.osfx(); } return os; } ostream::ostream() : ios(¬_open_filebuf) { _flags |= ios::dont_close; _tie = NULL; } ostream::ostream(streambuf* sb, ostream* tied) : ios(sb) { _flags |= ios::dont_close; _tie = tied; } ostream::~ostream() { if (!(_flags & (unsigned int)ios::dont_close)) delete _strbuf; _flags |= ios::dont_close; _strbuf = ¬_open_filebuf; } ostream& ostream::seekp(streampos pos) { pos = _strbuf->seekpos(pos, ios::out); if (pos == streampos(EOF)) set(ios::badbit); return *this; } ostream& ostream::seekp(streamoff off, _seek_dir dir) { streampos pos = _strbuf->seekoff(off, dir, ios::out); if (pos == streampos(EOF)) set(ios::badbit); return *this; } streampos ostream::tellp() { streampos pos = _strbuf->seekoff(0, ios::cur, ios::out); if (pos == streampos(EOF)) set(ios::badbit); return pos; } ostream& ostream::form(const char *format ...) { va_list ap; va_start(ap, format); _strbuf->vform(format, (_G_va_list)ap); va_end(ap); return *this; } ostream& ostream::vform(const char *format, _G_va_list args) { _strbuf->vform(format, args); return *this; } ostream& ostream::flush() { if (_strbuf->sync()) set(ios::badbit); return *this; } ostream& flush(ostream& outs) { outs.rdbuf()->overflow(EOF); return outs; } istream& ws(istream& ins) { if (ins.ipfx1()) for (;;) { int ch = ins._strbuf->sbumpc(); if (ch == EOF) { ins.set(ios::eofbit); break; } if (!isspace(ch)) { ins._strbuf->sputbackc(ch); break; } } return ins; } ostream& ends(ostream& outs) { outs.put(0); return outs; } ostream& endl(ostream& outs) { return flush(outs.put('\n')); } ostream& ostream::write(const char *s, size_t n) { if (opfx()) { if (_strbuf->sputn(s, n) != n) set(ios::failbit); } return *this; } void ostream::do_osfx() { if (flags() & ios::unitbuf) flush(); if (flags() & ios::stdio) { fflush(stdout); fflush(stderr); } } const unsigned long ios::basefield = ios::hex|ios::oct|ios::dec; const unsigned long ios::floatfield = ios::scientific|ios::fixed; const unsigned long ios::adjustfield = ios::left|ios::right|ios::internal; iostream::iostream() : ios(¬_open_filebuf) { _flags |= ios::dont_close; _gcount = 0; _tie = NULL; } iostream::iostream(streambuf* sb, ostream* tied) : ios(sb) { _flags |= ios::dont_close; _tie = tied; } iostream::~iostream() { if (!(_flags & (unsigned int)ios::dont_close)) delete _strbuf; _flags |= ios::dont_close; _strbuf = ¬_open_filebuf; } ostream& iostream::form(const char *format ...) // Copy of ostream::form. { va_list ap; va_start(ap, format); _strbuf->vform(format, (_G_va_list)ap); va_end(ap); return *(ostream*)this; } // NOTE: extension for compatibility with old libg++. // Not really compatible with fistream::close(). #ifdef _STREAM_COMPAT void ios::close() { if (!(_flags & (unsigned int)ios::dont_close)) delete _strbuf; else if (_strbuf->_flags & _S_IS_FILEBUF) ((struct filebuf*)_strbuf)->close(); else if (_strbuf != ¬_open_filebuf) _strbuf->sync(); _flags |= ios::dont_close; _strbuf = ¬_open_filebuf; } int istream::skip(int i) { int old = (_flags & ios::skipws) != 0; if (i) _flags |= ios::skipws; else _flags &= ~ios::skipws; return old; } #endif