diff options
Diffstat (limited to 'gnu/lib/libg++/iostream')
39 files changed, 10666 insertions, 0 deletions
diff --git a/gnu/lib/libg++/iostream/PlotFile.C b/gnu/lib/libg++/iostream/PlotFile.C new file mode 100644 index 00000000000..306ba5e9026 --- /dev/null +++ b/gnu/lib/libg++/iostream/PlotFile.C @@ -0,0 +1,130 @@ +// This may look like C code, but it is really -*- C++ -*- +/* +Copyright (C) 1988, 1992 Free Software Foundation + written by Doug Lea (dl@rocky.oswego.edu) + converted to use iostream library by Per Bothner (bothner@cygnus.com) + +This file is part of GNU CC. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY. No author or distributor +accepts responsibility to anyone for the consequences of using it +or for whether it serves any particular purpose or works at all, +unless he says so in writing. Refer to the GNU CC General Public +License for full details. + +Everyone is granted permission to copy, modify and redistribute +GNU CC, but only under the conditions described in the +GNU CC General Public License. A copy of this license is +supposed to have been given to you along with GNU CC so you +can know your rights and responsibilities. It should be in a +file named COPYING. Among other things, the copyright notice +and this notice must be preserved on all copies. +*/ + +#ifdef __GNUG__ +#pragma implementation +#endif +#include <PlotFile.h> + +/* + PlotFile implementation module +*/ + + +PlotFile& PlotFile:: cmd(char c) +{ + ofstream::put(c); + return *this; +} + +PlotFile& PlotFile:: operator<<(const int x) +{ +#if defined(convex) + ofstream::put((char)(x>>8)); + ofstream::put((char)(x&0377)); +#else + ofstream::put((char)(x&0377)); + ofstream::put((char)(x>>8)); +#endif + return *this; +} + +PlotFile& PlotFile:: operator<<(const char *s) +{ + *(ofstream*)this << s; + return *this; +} + + +PlotFile& PlotFile:: arc(const int xi, const int yi, + const int x0, const int y0, + const int x1, const int y1) +{ + return cmd('a') << xi << yi << x0 << y0 << x1 << y1; +} + + +PlotFile& PlotFile:: box(const int x0, const int y0, + const int x1, const int y1) +{ + line(x0, y0, x0, y1); + line(x0, y1, x1, y1); + line(x1, y1, x1, y0); + return line(x1, y0, x0, y0); +} + +PlotFile& PlotFile:: circle(const int x, const int y, const int r) +{ + return cmd('c') << x << y << r; +} + +PlotFile& PlotFile:: cont(const int xi, const int yi) +{ + return cmd('n') << xi << yi; +} + +PlotFile& PlotFile:: dot(const int xi, const int yi, const int dx, + int n, const int* pat) +{ + cmd('d') << xi << yi << dx << n; + while (n-- > 0) *this << *pat++; + return *this; +} + +PlotFile& PlotFile:: erase() +{ + return cmd('e'); +} + +PlotFile& PlotFile:: label(const char* s) +{ + return cmd('t') << s << "\n"; +} + +PlotFile& PlotFile:: line(const int x0, const int y0, + const int x1, const int y1) +{ + return cmd('l') << x0 << y0 << x1 << y1; +} + +PlotFile& PlotFile:: linemod(const char* s) +{ + return cmd('f') << s << "\n"; +} + +PlotFile& PlotFile:: move(const int xi, const int yi) +{ + return cmd('m') << xi << yi; +} + +PlotFile& PlotFile:: point(const int xi, const int yi) +{ + return cmd('p') << xi << yi; +} + +PlotFile& PlotFile:: space(const int x0, const int y0, + const int x1, const int y1) +{ + return cmd('s') << x0 << y0 << x1 << y1; +} diff --git a/gnu/lib/libg++/iostream/PlotFile.h b/gnu/lib/libg++/iostream/PlotFile.h new file mode 100644 index 00000000000..5a85a5cd2cc --- /dev/null +++ b/gnu/lib/libg++/iostream/PlotFile.h @@ -0,0 +1,120 @@ +// This may look like C code, but it is really -*- C++ -*- +/* +Copyright (C) 1988, 1992 Free Software Foundation + written by Doug Lea (dl@rocky.oswego.edu) + converted to use iostream library by Per Bothner (bothner@cygnus.com) + +This file is part of GNU CC. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY. No author or distributor +accepts responsibility to anyone for the consequences of using it +or for whether it serves any particular purpose or works at all, +unless he says so in writing. Refer to the GNU CC General Public +License for full details. + +Everyone is granted permission to copy, modify and redistribute +GNU CC, but only under the conditions described in the +GNU CC General Public License. A copy of this license is +supposed to have been given to you along with GNU CC so you +can know your rights and responsibilities. It should be in a +file named COPYING. Among other things, the copyright notice +and this notice must be preserved on all copies. + + $Id: PlotFile.h,v 1.1 1995/10/18 08:38:11 deraadt Exp $ +*/ + +/* + a very simple implementation of a class to output unix "plot" + format plotter files. See corresponding unix man pages for + more details. +*/ + +#ifndef _PlotFile_h +#ifdef __GNUG__ +#pragma interface +#endif +#define _PlotFile_h + +#include <fstream.h> + +/* + Some plot libraries have the `box' command to draw boxes. Some don't. + `box' is included here via moves & lines to allow both possiblilties. +*/ + + +class PlotFile : public ofstream +{ +protected: + PlotFile& cmd(char c); + PlotFile& operator << (const int x); + PlotFile& operator << (const char *s); + +public: + + PlotFile() : ofstream() { } + PlotFile(int fd) : ofstream(fd) { } + PlotFile(const char *name, int mode=ios::out, int prot=0664) + : ofstream(name, mode, prot) { } + +// PlotFile& remove() { ofstream::remove(); return *this; } + +// int filedesc() { return ofstream::filedesc(); } +// const char* name() { return File::name(); } +// void setname(const char* newname) { File::setname(newname); } +// int iocount() { return File::iocount(); } + + PlotFile& arc(const int xi, const int yi, + const int x0, const int y0, + const int x1, const int y1); + PlotFile& box(const int x0, const int y0, + const int x1, const int y1); + PlotFile& circle(const int x, const int y, const int r); + PlotFile& cont(const int xi, const int yi); + PlotFile& dot(const int xi, const int yi, const int dx, + int n, const int* pat); + PlotFile& erase(); + PlotFile& label(const char* s); + PlotFile& line(const int x0, const int y0, + const int x1, const int y1); + PlotFile& linemod(const char* s); + PlotFile& move(const int xi, const int yi); + PlotFile& point(const int xi, const int yi); + PlotFile& space(const int x0, const int y0, + const int x1, const int y1); +}; +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gnu/lib/libg++/iostream/SFile.C b/gnu/lib/libg++/iostream/SFile.C new file mode 100644 index 00000000000..9221bb34f7b --- /dev/null +++ b/gnu/lib/libg++/iostream/SFile.C @@ -0,0 +1,58 @@ +/* +Copyright (C) 1988 Free Software Foundation + written by Doug Lea (dl@rocky.oswego.edu) + +This file is part of the GNU C++ Library. 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, 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifdef __GNUG__ +#pragma implementation +#endif +#include <SFile.h> + +SFile::SFile(const char *filename, int size, int mode, int prot) +: fstream(filename, mode, prot) +{ + sz = size; +} + +SFile::SFile(int fd, int size) +: fstream(fd) +{ + sz = size; +} + +void SFile::open(const char *name, int size, int mode, int prot) +{ + fstream::open(name, mode, prot); + sz = size; +} + +SFile& SFile::get(void* x) +{ + read(x, sz); + return *this; +} + +SFile& SFile::put(void* x) +{ + write(x, sz); + return *this; +} + +SFile& SFile::operator[](long i) +{ + if (rdbuf()->seekoff(i * sz, ios::beg) == EOF) + set(ios::badbit); + return *this; +} diff --git a/gnu/lib/libg++/iostream/SFile.h b/gnu/lib/libg++/iostream/SFile.h new file mode 100644 index 00000000000..d7b75225272 --- /dev/null +++ b/gnu/lib/libg++/iostream/SFile.h @@ -0,0 +1,48 @@ +// This may look like C code, but it is really -*- C++ -*- +/* +Copyright (C) 1988, 1992 Free Software Foundation + written by Doug Lea (dl@rocky.oswego.edu) + +This file is part of the GNU C++ Library. 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, 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: SFile.h,v 1.1 1995/10/18 08:38:12 deraadt Exp $ +*/ + +#ifndef _SFile_h +#ifdef __GNUG__ +#pragma interface +#endif +#define _SFile_h 1 + +#include <fstream.h> + +class SFile: public fstream +{ + protected: + int sz; // unit size for structured binary IO + +public: + SFile() : fstream() { } + SFile(int fd, int size); + SFile(const char *name, int size, int mode, int prot=0664); + void open(const char *name, int size, int mode, int prot=0664); + + int size() { return sz; } + int setsize(int s) { int old = sz; sz = s; return old; } + + SFile& get(void* x); + SFile& put(void* x); + SFile& operator[](long i); +}; + +#endif diff --git a/gnu/lib/libg++/iostream/editbuf.C b/gnu/lib/libg++/iostream/editbuf.C new file mode 100644 index 00000000000..3d99e8442d1 --- /dev/null +++ b/gnu/lib/libg++/iostream/editbuf.C @@ -0,0 +1,707 @@ +// 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 +#include "ioprivate.h" +#include "editbuf.h" +#include <stddef.h> + +/* NOTE: Some of the code here is taken from GNU emacs */ +/* Hence this file falls under the GNU License! */ + +// Invariants for edit_streambuf: +// An edit_streambuf is associated with a specific edit_string, +// which again is a sub-string of a specific edit_buffer. +// An edit_streambuf is always in either get mode or put mode, never both. +// In get mode, gptr() is the current position, +// and pbase(), pptr(), and epptr() are all NULL. +// In put mode, pptr() is the current position, +// and eback(), gptr(), and egptr() are all NULL. +// Any edit_streambuf that is actively doing insertion (as opposed to +// replacing) // must have its pptr() pointing to the start of the gap. +// Only one edit_streambuf can be actively inserting into a specific +// edit_buffer; the edit_buffer's _writer field points to that edit_streambuf. +// That edit_streambuf "owns" the gap, and the actual start of the +// gap is the pptr() of the edit_streambuf; the edit_buffer::_gap_start pointer +// will only be updated on an edit_streambuf::overflow(). + +int edit_streambuf::truncate() +{ + str->buffer->delete_range(str->buffer->tell((buf_char*)pptr()), + str->buffer->tell(str->end)); + return 0; +} + +#ifdef OLD_STDIO +inline void disconnect_gap_from_file(edit_buffer* buffer, FILE* fp) +{ + if (buffer->gap_start_ptr != &fp->__bufp) + return; + buffer->gap_start_normal = fp->__bufp; + buffer->gap_start_ptr = &buffer->gap_start_normal; +} +#endif + +void edit_streambuf::flush_to_buffer(edit_buffer* buffer) +{ + if (pptr() > buffer->_gap_start && pptr() < buffer->gap_end()) + buffer->_gap_start = pptr(); +} + +void edit_streambuf::disconnect_gap_from_file(edit_buffer* buffer) +{ + if (buffer->_writer != this) return; + flush_to_buffer(buffer); + setp(pptr(),pptr()); + buffer->_writer = NULL; +} + +buf_index edit_buffer::tell(buf_char *ptr) +{ + if (ptr <= gap_start()) + return ptr - data; + else + return ptr - gap_end() + size1(); +} + +#if 0 +buf_index buf_cookie::tell() +{ + return str->buffer->tell(file->__bufp); +} +#endif + +buf_index edit_buffer::tell(edit_mark*mark) +{ + return tell(data + mark->index_in_buffer(this)); +} + +// adjust the position of the gap + +void edit_buffer::move_gap(buf_offset pos) +{ + if (pos < size1()) + gap_left (pos); + else if (pos > size1()) + gap_right (pos); +} + +void edit_buffer::gap_left (int pos) +{ + register buf_char *to, *from; + register int i; + int new_s1; + + i = size1(); + from = gap_start(); + to = from + gap_size(); + new_s1 = size1(); + + /* Now copy the characters. To move the gap down, + copy characters up. */ + + for (;;) + { + /* I gets number of characters left to copy. */ + i = new_s1 - pos; + if (i == 0) + break; +#if 0 + /* If a quit is requested, stop copying now. + Change POS to be where we have actually moved the gap to. */ + if (QUITP) + { + pos = new_s1; + break; + } +#endif + /* Move at most 32000 chars before checking again for a quit. */ + if (i > 32000) + i = 32000; + new_s1 -= i; + while (--i >= 0) + *--to = *--from; + } + + /* Adjust markers, and buffer data structure, to put the gap at POS. + POS is where the loop above stopped, which may be what was specified + or may be where a quit was detected. */ + adjust_markers (pos << 1, size1() << 1, gap_size(), data); +#ifndef OLD_STDIO + _gap_start = data + pos; +#else + if (gap_start_ptr == &gap_start_normal) + gap_start_normal = data + pos; +#endif + __gap_end_pos = to - data; +/* QUIT;*/ +} + +void edit_buffer::gap_right (int pos) +{ + register buf_char *to, *from; + register int i; + int new_s1; + + i = size1(); + to = gap_start(); + from = i + gap_end(); + new_s1 = i; + + /* Now copy the characters. To move the gap up, + copy characters down. */ + + while (1) + { + /* I gets number of characters left to copy. */ + i = pos - new_s1; + if (i == 0) + break; +#if 0 + /* If a quit is requested, stop copying now. + Change POS to be where we have actually moved the gap to. */ + if (QUITP) + { + pos = new_s1; + break; + } +#endif + /* Move at most 32000 chars before checking again for a quit. */ + if (i > 32000) + i = 32000; + new_s1 += i; + while (--i >= 0) + *to++ = *from++; + } + + adjust_markers ((size1() + gap_size()) << 1, (pos + gap_size()) << 1, + - gap_size(), data); +#ifndef OLD_STDIO + _gap_start = data+pos; +#else + if (gap_start_ptr == &gap_start_normal) + gap_start_normal = data + pos; +#endif + __gap_end_pos = from - data; +/* QUIT;*/ +} + +/* make sure that the gap in the current buffer is at least k + characters wide */ + +void edit_buffer::make_gap(buf_offset k) +{ + register buf_char *p1, *p2, *lim; + buf_char *old_data = data; + int s1 = size1(); + + if (gap_size() >= k) + return; + + /* Get more than just enough */ + if (buf_size > 1000) k += 2000; + else k += /*200;*/ 20; // for testing! + + p1 = (buf_char *) realloc (data, s1 + size2() + k); + if (p1 == 0) + abort(); /*memory_full ();*/ + + k -= gap_size(); /* Amount of increase. */ + + /* Record new location of text */ + data = p1; + + /* Transfer the new free space from the end to the gap + by shifting the second segment upward */ + p2 = data + buf_size; + p1 = p2 + k; + lim = p2 - size2(); + while (lim < p2) + *--p1 = *--p2; + + /* Finish updating text location data */ + __gap_end_pos += k; + +#ifndef OLD_STDIO + _gap_start = data + s1; +#else + if (gap_start_ptr == &gap_start_normal) + gap_start_normal = data + s1; +#endif + + /* adjust markers */ + adjust_markers (s1 << 1, (buf_size << 1) + 1, k, old_data); + buf_size += k; +} + +/* Add `amount' to the position of every marker in the current buffer + whose current position is between `from' (exclusive) and `to' (inclusive). + Also, any markers past the outside of that interval, in the direction + of adjustment, are first moved back to the near end of the interval + and then adjusted by `amount'. */ + +void edit_buffer::adjust_markers(register mark_pointer low, + register mark_pointer high, + int amount, buf_char *old_data) +{ + register struct edit_mark *m; + register mark_pointer mpos; + /* convert to mark_pointer */ + amount <<= 1; + + if (_writer) + _writer->disconnect_gap_from_file(this); + + for (m = mark_list(); m != NULL; m = m->chain) + { + mpos = m->_pos; + if (amount > 0) + { + if (mpos > high && mpos < high + amount) + mpos = high + amount; + } + else + { + if (mpos > low + amount && mpos <= low) + mpos = low + amount; + } + if (mpos > low && mpos <= high) + mpos += amount; + m->_pos = mpos; + } + + // Now adjust files + edit_streambuf *file; + + for (file = files; file != NULL; file = file->next) { + mpos = file->current() - old_data; + if (amount > 0) + { + if (mpos > high && mpos < high + amount) + mpos = high + amount; + } + else + { + if (mpos > low + amount && mpos <= low) + mpos = low + amount; + } + if (mpos > low && mpos <= high) + mpos += amount; + char* new_pos = data + mpos; + file->set_current(new_pos, file->is_reading()); + } +} + +#if 0 +stdio_ + __off == index at start of buffer (need only be valid after seek ? ) + __buf == + +if read/read_delete/overwrite mode: + __endp <= min(*gap_start_ptr, edit_string->end->ptr(buffer)) + +if inserting: + must have *gap_start_ptr == __bufp && *gap_start_ptr+gap == __endp + file->edit_string->end->ptr(buffer) == *gap_start_ptr+end +if write_mode: + if before gap +#endif + +int edit_streambuf::underflow() +{ + if (!(_mode & ios::in)) + return EOF; + struct edit_buffer *buffer = str->buffer; + if (!is_reading()) { // Must switch from put to get mode. + disconnect_gap_from_file(buffer); + set_current(pptr(), 1); + } + buf_char *str_end = str->end->ptr(buffer); + retry: + if (gptr() < egptr()) { + return *gptr(); + } + if ((buf_char*)gptr() == str_end) + return EOF; + if (str_end <= buffer->gap_start()) { + setg(eback(), gptr(), str_end); + goto retry; + } + if (gptr() < buffer->gap_start()) { + setg(eback(), gptr(), buffer->gap_start()); + goto retry; + } + if (gptr() == buffer->gap_start()) { + disconnect_gap_from_file(buffer); +// fp->__offset += fp->__bufp - fp->__buffer; + setg(buffer->gap_end(), buffer->gap_end(), str_end); + } + else + setg(eback(), gptr(), str_end); + goto retry; +} + +int edit_streambuf::overflow(int ch) +{ + if (_mode == ios::in) + return EOF; + struct edit_buffer *buffer = str->buffer; + flush_to_buffer(buffer); + if (ch == EOF) + return 0; + if (is_reading()) { // Must switch from get to put mode. + set_current(gptr(), 0); + } + buf_char *str_end = str->end->ptr(buffer); + retry: + if (pptr() < epptr()) { + *pptr() = ch; + pbump(1); + return (unsigned char)ch; + } + if ((buf_char*)pptr() == str_end || inserting()) { + /* insert instead */ + if (buffer->_writer) + buffer->_writer->flush_to_buffer(); // Redundant? + buffer->_writer = NULL; + if (pptr() >= buffer->gap_end()) + buffer->move_gap(pptr() - buffer->gap_size()); + else + buffer->move_gap(pptr()); + buffer->make_gap(1); + setp(buffer->gap_start(), buffer->gap_end()); + buffer->_writer = this; + *pptr() = ch; + pbump(1); + return (unsigned char)ch; + } + if (str_end <= buffer->gap_start()) { + // Entire string is left of gap. + setp(pptr(), str_end); + } + else if (pptr() < buffer->gap_start()) { + // Current pos is left of gap. + setp(pptr(), buffer->gap_start()); + goto retry; + } + else if (pptr() == buffer->gap_start()) { + // Current pos is at start of gap; move to end of gap. +// disconnect_gap_from_file(buffer); + setp(buffer->gap_end(), str_end); +// __offset += __bufp - __buffer; + } + else { + // Otherwise, current pos is right of gap. + setp(pptr(), str_end); + } + goto retry; +} + +void edit_streambuf::set_current(char *new_pos, int reading) +{ + if (reading) { + setg(new_pos, new_pos, new_pos); + setp(NULL, NULL); + } + else { + setg(NULL, NULL, NULL); + setp(new_pos, new_pos); + } +} + +// Called by fseek(fp, pos, whence) if fp is bound to a edit_buffer. + +streampos edit_streambuf::seekoff(streamoff offset, _seek_dir dir, + int mode /* =ios::in|ios::out*/) +{ + struct edit_buffer *buffer = str->buffer; + disconnect_gap_from_file(buffer); + buf_index cur_pos = buffer->tell((buf_char*)current());; + buf_index start_pos = buffer->tell(str->start); + buf_index end_pos = buffer->tell(str->end); + switch (dir) { + case ios::beg: + offset += start_pos; + break; + case ios::cur: + offset += cur_pos; + break; + case ios::end: + offset += end_pos; + break; + } + if (offset < start_pos || offset > end_pos) + return EOF; + buf_char *new_pos = buffer->data + offset; + buf_char* gap_start = buffer->gap_start(); + if (new_pos > gap_start) { + buf_char* gap_end = buffer->gap_end(); + new_pos += gap_end - gap_start; + if (new_pos >= buffer->data + buffer->buf_size) abort(); // Paranoia. + } + set_current(new_pos, is_reading()); + return EOF; +} + +#if 0 +int buf_seek(void *arg_cookie, fpos_t * pos, int whence) +{ + struct buf_cookie *cookie = arg_cookie; + FILE *file = cookie->file; + struct edit_buffer *buffer = cookie->str->buffer; + buf_char *str_start = cookie->str->start->ptr(buffer); + disconnect_gap_from_file(buffer, cookie->file); + fpos_t cur_pos, new_pos; + if (file->__bufp <= *buffer->gap_start_ptr + || str_start >= buffer->__gap_end) + cur_pos = str_start - file->__bufp; + else + cur_pos = + (*buffer->gap_start_ptr - str_start) + (file->__bufp - __gap_end); + end_pos = ...; + switch (whence) { + case SEEK_SET: + new_pos = *pos; + break; + case SEEK_CUR: + new_pos = cur_pos + *pos; + break; + case SEEK_END: + new_pos = end_pos + *pos; + break; + } + if (new_pos > end_pos) { + seek to end_pos; + insert_nulls(new_pos - end_pos); + return; + } + if (str_start + new_pos <= *gap_start_ptr &* *gap_start_ptr < end) { + __buffer = str_start; + __off = 0; + __bufp = str_start + new_pos; + file->__get_limit = + *buffer->gap_start_ptr; /* what if gap_start_ptr == &bufp ??? */ + } else if () { + + } + *pos = new_pos; +} +#endif + +/* Delete characters from `from' up to (but not incl) `to' */ + +void edit_buffer::delete_range (buf_index from, buf_index to) +{ + register int numdel; + + if ((numdel = to - from) <= 0) + return; + + /* Make sure the gap is somewhere in or next to what we are deleting */ + if (from > size1()) + gap_right (from); + if (to < size1()) + gap_left (to); + + /* Relocate all markers pointing into the new, larger gap + to point at the end of the text before the gap. */ + adjust_markers ((to + gap_size()) << 1, (to + gap_size()) << 1, + - numdel - gap_size(), data); + + __gap_end_pos = to + gap_size(); + _gap_start = data + from; +} + +void edit_buffer::delete_range(struct edit_mark *start, struct edit_mark *end) +{ + delete_range(tell(start), tell(end)); +} + +void buf_delete_chars(struct edit_buffer *buf, struct edit_mark *mark, size_t count) +{ + abort(); +} + +edit_streambuf::edit_streambuf(edit_string* bstr, int mode) +{ + _mode = mode; + str = bstr; + edit_buffer* buffer = bstr->buffer; + next = buffer->files; + buffer->files = this; + char* buf_ptr = bstr->start->ptr(buffer); + _inserting = 0; +// setb(buf_ptr, buf_ptr, 0); + set_current(buf_ptr, !(mode & ios::out+ios::trunc+ios::app)); + if (_mode & ios::trunc) + truncate(); + if (_mode & ios::ate) + seekoff(0, ios::end); +} + +// Called by fclose(fp) if fp is bound to a edit_buffer. + +#if 0 +static int buf_close(void *arg) +{ + register struct buf_cookie *cookie = arg; + struct edit_buffer *buffer = cookie->str->buffer; + struct buf_cookie **ptr; + for (ptr = &buffer->files; *ptr != cookie; ptr = &(*ptr)->next) ; + *ptr = cookie->next; + disconnect_gap_from_file(buffer, cookie->file); + free (cookie); + return 0; +} +#endif + +edit_streambuf::~edit_streambuf() +{ + if (_mode == ios::out) + truncate(); + // Unlink this from list of files associated with bstr->buffer. + edit_streambuf **ptr = &str->buffer->files; + for (; *ptr != this; ptr = &(*ptr)->next) { } + *ptr = next; + + disconnect_gap_from_file(str->buffer); +} + +edit_buffer::edit_buffer() +{ + buf_size = /*200;*/ 15; /* for testing! */ + data = (buf_char*)malloc(buf_size); + files = NULL; +#ifndef OLD_STDIO + _gap_start = data; + _writer = NULL; +#else + gap_start_normal = data; + gap_start_ptr = &gap_start_normal; +#endif + __gap_end_pos = buf_size; + start_mark.chain = &end_mark; + start_mark._pos = 0; + end_mark.chain = NULL; + end_mark._pos = 2 * buf_size + 1; +} + +// Allocate a new mark, which is adjusted by 'delta' bytes from 'this'. +// Restrict new mark to lie within 'str'. + +edit_mark::edit_mark(struct edit_string *str, long delta) +{ + struct edit_buffer *buf = str->buffer; + chain = buf->start_mark.chain; + buf->start_mark.chain = this; + mark_pointer size1 = buf->size1() << 1; + int gap_size = buf->gap_size() << 1; + delta <<= 1; + + // check if new and old marks are opposite sides of gap + if (_pos <= size1 && _pos + delta > size1) + delta += gap_size; + else if (_pos >= size1 + gap_size && _pos + delta < size1 + gap_size) + delta -= gap_size; + + _pos = _pos + delta; + if (_pos < str->start->_pos & ~1) + _pos = (str->start->_pos & ~ 1) + (_pos & 1); + else if (_pos >= str->end->_pos) + _pos = (str->end->_pos & ~ 1) + (_pos & 1); +} + +// A (slow) way to find the buffer a mark belongs to. + +edit_buffer * edit_mark::buffer() +{ + struct edit_mark *mark; + for (mark = this; mark->chain != NULL; mark = mark->chain) ; + // Assume that the last mark on the chain is the end_mark. + return (edit_buffer *)((char*)mark - offsetof(edit_buffer, end_mark)); +} + +edit_mark::~edit_mark() +{ + // Must unlink mark from chain of owning buffer + struct edit_buffer *buf = buffer(); + if (this == &buf->start_mark || this == &buf->end_mark) abort(); + edit_mark **ptr; + for (ptr = &buf->start_mark.chain; *ptr != this; ptr = &(*ptr)->chain) ; + *ptr = this->chain; +} + +int edit_string::length() const +{ + ptrdiff_t delta = end->ptr(buffer) - start->ptr(buffer); + if (end->ptr(buffer) <= buffer->gap_start() || + start->ptr(buffer) >= buffer->gap_end()) + return delta; + return delta - buffer->gap_size(); +} + +buf_char * edit_string::copy_bytes(int *lenp) const +{ + char *new_str; + int len1, len2; + buf_char *start1, *start2; + start1 = start->ptr(buffer); + if (end->ptr(buffer) <= buffer->gap_start() + || start->ptr(buffer) >= buffer->gap_end()) { + len1 = end->ptr(buffer) - start1; + len2 = 0; + start2 = NULL; // To avoid a warning from g++. + } + else { + len1 = buffer->gap_start() - start1; + start2 = buffer->gap_end(); + len2 = end->ptr(buffer) - start2; + } + new_str = (char*)malloc(len1 + len2 + 1); + memcpy(new_str, start1, len1); + if (len2 > 0) memcpy(new_str + len1, start2, len2); + new_str[len1+len2] = '\0'; + *lenp = len1+len2; + return new_str; +} + +// Replace the buf_chars in 'this' with ones from 'src'. +// Equivalent to deleting this, then inserting src, except tries +// to leave marks in place: Marks whose offset from the start +// of 'this' is less than 'src->length()' will still have the +// same offset in 'this' when done. + +void edit_string::assign(struct edit_string *src) +{ + edit_streambuf dst_file(this, ios::out); + if (buffer == src->buffer /*&& ???*/) { /* overly conservative */ + int src_len; + buf_char *new_str; + new_str = src->copy_bytes(&src_len); + dst_file.sputn(new_str, src_len); + free (new_str); + } else { + edit_streambuf src_file(src, ios::in); + for ( ; ; ) { + int ch = src_file.sbumpc(); + if (ch == EOF) break; + dst_file.sputc(ch); + } + } +} diff --git a/gnu/lib/libg++/iostream/editbuf.h b/gnu/lib/libg++/iostream/editbuf.h new file mode 100644 index 00000000000..6562d73702e --- /dev/null +++ b/gnu/lib/libg++/iostream/editbuf.h @@ -0,0 +1,175 @@ +// 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. +// +// 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. +// +// $Id: editbuf.h,v 1.1 1995/10/18 08:38:12 deraadt Exp $ + +#ifndef _EDITBUF_H +#define _EDITBUF_H +#ifdef __GNUG__ +#pragma interface +#endif +#include <stdio.h> +#include <fstream.h> + +typedef unsigned long mark_pointer; +// At some point, it might be nice to parameterize this code +// in terms of buf_char. +typedef /*unsigned*/ char buf_char; + +// Logical pos from start of buffer (does not count gap). +typedef long buf_index; + +// Pos from start of buffer, possibly including gap_size. +typedef long buf_offset; + +#if 0 +struct buf_cookie { + FILE *file; + struct edit_string *str; + struct buf_cookie *next; + buf_index tell(); +}; +#endif + +struct edit_buffer; +struct edit_mark; + +// A edit_string is defined as the region between the 'start' and 'end' marks. +// Normally (always?) 'start->insert_before()' should be false, +// and 'end->insert_before()' should be true. + +struct edit_string { + struct edit_buffer *buffer; // buffer that 'start' and 'end' belong to + struct edit_mark *start, *end; + int length() const; // count of buf_chars currently in string + edit_string(struct edit_buffer *b, + struct edit_mark *ms, struct edit_mark *me) + { buffer = b; start = ms; end = me; } +/* Make a fresh, contiguous copy of the data in STR. + Assign length of STR to *LENP. + (Output has extra NUL at out[*LENP].) */ + buf_char *copy_bytes(int *lenp) const; +// FILE *open_file(char *mode); + void assign(struct edit_string *src); // copy bytes from src to this +}; + +struct edit_streambuf : public streambuf { + friend edit_buffer; + edit_string *str; + edit_streambuf* next; // Chain of edit_streambuf's for a edit_buffer. + short _mode; + edit_streambuf(edit_string* bstr, int mode); + ~edit_streambuf(); + virtual int underflow(); + virtual int overflow(int c = EOF); + virtual streampos seekoff(streamoff, _seek_dir, int mode=ios::in|ios::out); + void flush_to_buffer(); + void flush_to_buffer(edit_buffer* buffer); + int _inserting; + int inserting() { return _inserting; } + void inserting(int i) { _inserting = i; } +// int delete_chars(int count, char* cut_buf); Not implemented. + int truncate(); + int is_reading() { return gptr() != NULL; } + buf_char* current() { return is_reading() ? gptr() : pptr(); } + void set_current(char *p, int is_reading); + protected: + void disconnect_gap_from_file(edit_buffer* buffer); +}; + +// A 'edit_mark' indicates a position in a buffer. +// It is "attached" the text (rather than the offset). +// There are two kinds of mark, which have different behavior +// when text is inserted at the mark: +// If 'insert_before()' is true the mark will be adjusted to be +// *after* the new text. + +struct edit_mark { + struct edit_mark *chain; + mark_pointer _pos; + inline int insert_before() { return _pos & 1; } + inline unsigned long index_in_buffer(struct edit_buffer *buffer) + { return _pos >> 1; } + inline buf_char *ptr(struct edit_buffer *buf); + buf_index tell(); + edit_mark() { } + edit_mark(struct edit_string *str, long delta); + edit_buffer *buffer(); + ~edit_mark(); +}; + +// A 'edit_buffer' consists of a sequence of buf_chars (the data), +// a list of edit_marks pointing into the data, and a list of FILEs +// also pointing into the data. +// A 'edit_buffer' coerced to a edit_string is the string of +// all the buf_chars in the buffer. + +// This implementation uses a conventional buffer gap (as in Emacs). +// The gap start is defined by de-referencing a (buf_char**). +// This is because sometimes a FILE is inserting into the buffer, +// so rather than having each putc adjust the gap, we use indirection +// to have the gap be defined as the write pointer of the FILE. +// (This assumes that putc adjusts a pointer (as in GNU's libc), not an index.) + +struct edit_buffer { + buf_char *data; /* == emacs buffer_text.p1+1 */ + buf_char *_gap_start; + edit_streambuf* _writer; // If non-NULL, currently writing stream + inline buf_char *gap_start() + { return _writer ? _writer->pptr() : _gap_start; } + buf_offset __gap_end_pos; // size of part 1 + size of gap + /* int gap; implicit: buf_size - size1 - size2 */ + int buf_size; + struct edit_streambuf *files; + struct edit_mark start_mark; + struct edit_mark end_mark; + edit_buffer(); + inline buf_offset gap_end_pos() { return __gap_end_pos; } + inline struct edit_mark *start_marker() { return &start_mark; } + inline struct edit_mark *end_marker() { return &end_mark; } +/* these should be protected, ultimately */ + buf_index tell(edit_mark*); + buf_index tell(buf_char*); + inline buf_char *gap_end() { return data + gap_end_pos(); } + inline int gap_size() { return gap_end() - gap_start(); } + inline int size1() { return gap_start() - data; } + inline int size2() { return buf_size - gap_end_pos(); } + inline struct edit_mark * mark_list() { return &start_mark; } + void make_gap (buf_offset); + void move_gap (buf_offset pos); + void move_gap (buf_char *pos) { move_gap(pos - data); } + void gap_left (int pos); + void gap_right (int pos); + void adjust_markers(mark_pointer low, mark_pointer high, + int amount, buf_char *old_data); + void delete_range(buf_index from, buf_index to); + void delete_range(struct edit_mark *start, struct edit_mark *end); +}; + +extern buf_char * bstr_copy(struct edit_string *str, int *lenp); + +// Convert a edit_mark to a (buf_char*) + +inline buf_char *edit_mark::ptr(struct edit_buffer *buf) + { return buf->data + index_in_buffer(buf); } + +inline void edit_streambuf::flush_to_buffer() +{ + edit_buffer* buffer = str->buffer; + if (buffer->_writer == this) flush_to_buffer(buffer); +} +#endif /* !_EDITBUF_H*/ + diff --git a/gnu/lib/libg++/iostream/filebuf.C b/gnu/lib/libg++/iostream/filebuf.C new file mode 100644 index 00000000000..4d49d7f0e60 --- /dev/null +++ b/gnu/lib/libg++/iostream/filebuf.C @@ -0,0 +1,580 @@ +// 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 "ioprivate.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +// An fstream can be in at most one of put mode, get mode, or putback mode. +// Putback mode is a variant of get mode. + +// In a filebuf, there is only one current position, instead of two +// separate get and put pointers. In get mode, the current posistion +// is that of gptr(); in put mode that of pptr(). + +// The position in the buffer that corresponds to the position +// in external file system is file_ptr(). +// This is normally egptr(), except in putback mode, when it is _save_egptr. +// If the field _fb._offset is >= 0, it gives the offset in +// the file as a whole corresponding to eGptr(). (???) + +// PUT MODE: +// If a filebuf is in put mode, pbase() is non-NULL and equal to base(). +// Also, epptr() == ebuf(). +// Also, eback() == gptr() && gptr() == egptr(). +// The un-flushed character are those between pbase() and pptr(). +// GET MODE: +// If a filebuf is in get or putback mode, eback() != egptr(). +// In get mode, the unread characters are between gptr() and egptr(). +// The OS file position corresponds to that of egptr(). +// PUTBACK MODE: +// Putback mode is used to remember "excess" characters that have +// been sputbackc'd in a separate putback buffer. +// In putback mode, the get buffer points to the special putback buffer. +// The unread characters are the characters between gptr() and egptr() +// in the putback buffer, as well as the area between save_gptr() +// and save_egptr(), which point into the original reserve buffer. +// (The pointers save_gptr() and save_egptr() are the values +// of gptr() and egptr() at the time putback mode was entered.) +// The OS position corresponds to that of save_egptr(). +// +// LINE BUFFERED OUTPUT: +// During line buffered output, pbase()==base() && epptr()==base(). +// However, ptr() may be anywhere between base() and ebuf(). +// This forces a call to filebuf::overflow(int C) on every put. +// If there is more space in the buffer, and C is not a '\n', +// then C is inserted, and pptr() incremented. +// +// UNBUFFERED STREAMS: +// If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer. + +#define CLOSED_FILEBUF_FLAGS \ + (_S_IS_FILEBUF+_S_NO_READS+_S_NO_WRITES+_S_TIED_PUT_GET) + +void filebuf::init() +{ + _fb._offset = 0; + + _link_in(); + _fb._fileno = -1; +} + +filebuf::filebuf() : backupbuf(CLOSED_FILEBUF_FLAGS) +{ + init(); +} + +filebuf::filebuf(int fd) : backupbuf(CLOSED_FILEBUF_FLAGS) +{ + init(); + attach(fd); +} + +filebuf::filebuf(int fd, char* p, int len) : backupbuf(CLOSED_FILEBUF_FLAGS) +{ + init(); + attach(fd); + setbuf(p, len); +} + +filebuf::~filebuf() +{ + if (!(xflags() & _S_DELETE_DONT_CLOSE)) + close(); + + _un_link(); +} + +filebuf* filebuf::open(const char *filename, ios::openmode mode, int prot) +{ + if (is_open()) + return NULL; + int posix_mode; + int read_write; + if (mode & ios::app) + mode |= ios::out; + if ((mode & (ios::in|ios::out)) == (ios::in|ios::out)) { + posix_mode = O_RDWR; + read_write = 0; + } + else if (mode & ios::out) + posix_mode = O_WRONLY, read_write = _S_NO_READS; + else if (mode & (int)ios::in) + posix_mode = O_RDONLY, read_write = _S_NO_WRITES; + else + posix_mode = 0, read_write = _S_NO_READS+_S_NO_WRITES; + if ((mode & (int)ios::trunc) || mode == (int)ios::out) + posix_mode |= O_TRUNC; + if (mode & ios::app) + posix_mode |= O_APPEND, read_write |= _S_IS_APPENDING; + if (!(mode & (int)ios::nocreate) && mode != ios::in) + posix_mode |= O_CREAT; + if (mode & (int)ios::noreplace) + posix_mode |= O_EXCL; + int fd = ::open(filename, posix_mode, prot); + if (fd < 0) + return NULL; + _fb._fileno = fd; + xsetflags(read_write, _S_NO_READS+_S_NO_WRITES+_S_IS_APPENDING); + if (mode & (ios::ate|ios::app)) { + if (seekoff(0, ios::end) == EOF) + return NULL; + } + _link_in(); + return this; +} + +filebuf* filebuf::open(const char *filename, const char *mode) +{ + if (is_open()) + return NULL; + int oflags = 0, omode; + int read_write; + int oprot = 0666; + switch (*mode++) { + case 'r': + omode = O_RDONLY; + read_write = _S_NO_WRITES; + break; + case 'w': + omode = O_WRONLY; + oflags = O_CREAT|O_TRUNC; + read_write = _S_NO_READS; + break; + case 'a': + omode = O_WRONLY; + oflags = O_CREAT|O_APPEND; + read_write = _S_NO_READS|_S_IS_APPENDING; + break; + default: + errno = EINVAL; + return NULL; + } + if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+')) { + omode = O_RDWR; + read_write &= _S_IS_APPENDING; + } + int fdesc = ::open(filename, omode|oflags, oprot); + if (fdesc < 0) + return NULL; + _fb._fileno = fdesc; + xsetflags(read_write, _S_NO_READS+_S_NO_WRITES+_S_IS_APPENDING); + if (read_write & _S_IS_APPENDING) + if (seekoff(0, ios::end) == EOF) + return NULL; + _link_in(); + return this; +} + +filebuf* filebuf::attach(int fd) +{ + if (is_open()) + return NULL; + _fb._fileno = fd; + xsetflags(0, _S_NO_READS+_S_NO_WRITES); + return this; +} + +streambuf* filebuf::setbuf(char* p, int len) +{ + if (streambuf::setbuf(p, len) == NULL) + return NULL; + setp(_base, _base); + setg(_base, _base, _base); + return this; +} + +int filebuf::overflow(int c) +{ + if (xflags() & _S_NO_WRITES) // SET ERROR + return EOF; + // Allocate a buffer if needed. + if (base() == NULL) { + doallocbuf(); + if (xflags() & _S_LINE_BUF+_S_UNBUFFERED) setp(_base, _base); + else setp(_base, _ebuf); + setg(_base, _base, _base); + _flags |= _S_CURRENTLY_PUTTING; + } + // If currently reading, switch to writing. + else if ((_flags & _S_CURRENTLY_PUTTING) == 0) { + if (xflags() & _S_LINE_BUF+_S_UNBUFFERED) setp(gptr(), gptr()); + else setp(gptr(), ebuf()); + setg(egptr(), egptr(), egptr()); + _flags |= _S_CURRENTLY_PUTTING; + } + if (c == EOF) + return do_flush(); + if (pptr() == ebuf() ) // Buffer is really full + if (do_flush() == EOF) + return EOF; + xput_char(c); + if (unbuffered() || (linebuffered() && c == '\n')) + if (do_flush() == EOF) + return EOF; + return (unsigned char)c; +} + +int filebuf::underflow() +{ +#if 0 + /* SysV does not make this test; take it out for compatibility */ + if (fp->_flags & __SEOF) + return (EOF); +#endif + + if (xflags() & _S_NO_READS) + return EOF; + if (gptr() < egptr()) + return *(unsigned char*)gptr(); + allocbuf(); + + // FIXME This can/should be moved to __streambuf ?? + if ((xflags() & _S_LINE_BUF) || unbuffered()) { + // Flush all line buffered files before reading. + streambuf::flush_all_linebuffered(); + } + + switch_to_get_mode(); + + _G_ssize_t count = sys_read(base(), ebuf() - base()); + if (count <= 0) { + if (count == 0) + xsetflags(_S_EOF_SEEN); + else + xsetflags(_S_ERR_SEEN), count = 0; + } + setg(base(), base(), base() + count); + setp(base(), base()); + if (count == 0) + return EOF; + if (_fb._offset >= 0) + _fb._offset += count; + return *(unsigned char*)gptr(); +} + +int filebuf::do_write(const char *data, int to_do) +{ + if (to_do == 0) + return 0; + if (xflags() & _S_IS_APPENDING) { + // On a system without a proper O_APPEND implementation, + // you would need to sys_seek(0, ios::end) here, but is + // is not needed nor desirable for Unix- or Posix-like systems. + // Instead, just indicate that offset (before and after) is + // unpredictable. + _fb._offset = -1; + } + else if (egptr() != pbase()) { + long new_pos = sys_seek(pbase()-egptr(), ios::cur); + if (new_pos == -1) + return EOF; + _fb._offset = new_pos; + } + _G_ssize_t count = sys_write(data, to_do); + if (_cur_column) + _cur_column = __adjust_column(_cur_column - 1, data, to_do) + 1; + setg(base(), base(), base()); + if (xflags() & _S_LINE_BUF+_S_UNBUFFERED) setp(base(), base()); + else setp(base(), ebuf()); + return count != to_do ? EOF : 0; +} + +int filebuf::sync() +{ +// char* ptr = cur_ptr(); + if (pptr() > pbase()) + if (do_flush()) return EOF; + if (gptr() != egptr()) { + streampos delta = gptr() - egptr(); + if (in_backup()) + delta -= eGptr() - Gbase(); + _G_fpos_t new_pos = sys_seek(delta, ios::cur); + if (new_pos == EOF) + return EOF; + _fb._offset = new_pos; + setg(eback(), gptr(), gptr()); + } + // FIXME: Cleanup - can this be shared? +// setg(base(), ptr, ptr); + return 0; +} + +streampos filebuf::seekoff(streamoff offset, _seek_dir dir, int mode) +{ + streampos result, new_offset, delta; + _G_ssize_t count; + + if (mode == 0) // Don't move any pointers. + dir = ios::cur, offset = 0; + + // Flush unwritten characters. + // (This may do an unneeded write if we seek within the buffer. + // But to be able to switch to reading, we would need to set + // egptr to ptr. That can't be done in the current design, + // which assumes file_ptr() is eGptr. Anyway, since we probably + // end up flushing when we close(), it doesn't make much difference.) + if (pptr() > pbase() || put_mode()) + if (switch_to_get_mode()) return EOF; + + if (base() == NULL) { + doallocbuf(); + setp(base(), base()); + setg(base(), base(), base()); + } + switch (dir) { + case ios::cur: + if (_fb._offset < 0) { + _fb._offset = sys_seek(0, ios::cur); + if (_fb._offset < 0) + return EOF; + } + // Make offset absolute, assuming current pointer is file_ptr(). + offset += _fb._offset; + + offset -= _egptr - _gptr; + if (in_backup()) + offset -= _other_egptr - _other_gbase; + dir = ios::beg; + break; + case ios::beg: + break; + case ios::end: + struct stat st; + if (sys_stat(&st) == 0 && S_ISREG(st.st_mode)) { + offset += st.st_size; + dir = ios::beg; + } + else + goto dumb; + } + // At this point, dir==ios::beg. + + // If destination is within current buffer, optimize: + if (_fb._offset >= 0 && _eback != NULL) { + // Offset relative to start of main get area. + _G_fpos_t rel_offset = offset - _fb._offset + + (eGptr()-Gbase()); + if (rel_offset >= 0) { + if (in_backup()) + switch_to_main_get_area(); + if (rel_offset <= _egptr - _eback) { + setg(base(), base() + rel_offset, egptr()); + setp(base(), base()); + return offset; + } + // If we have streammarkers, seek forward by reading ahead. + if (have_markers()) { + int to_skip = rel_offset - (_gptr - _eback); + if (ignore(to_skip) != to_skip) + goto dumb; + return offset; + } + } + if (rel_offset < 0 && rel_offset >= Bbase() - Bptr()) { + if (!in_backup()) + switch_to_backup_area(); + gbump(_egptr + rel_offset - gptr()); + return offset; + } + } + + unsave_markers(); + + // Try to seek to a block boundary, to improve kernel page management. + new_offset = offset & ~(ebuf() - base() - 1); + delta = offset - new_offset; + if (delta > ebuf() - base()) { + new_offset = offset; + delta = 0; + } + result = sys_seek(new_offset, ios::beg); + if (result < 0) + return EOF; + if (delta == 0) + count = 0; + else { + count = sys_read(base(), ebuf()-base()); + if (count < delta) { + // We weren't allowed to read, but try to seek the remainder. + offset = count == EOF ? delta : delta-count; + dir = ios::cur; + goto dumb; + } + } + setg(base(), base()+delta, base()+count); + setp(base(), base()); + _fb._offset = result + count; + xflags(xflags() & ~ _S_EOF_SEEN); + return offset; + dumb: + unsave_markers(); + result = sys_seek(offset, dir); + if (result != EOF) { + xflags(xflags() & ~_S_EOF_SEEN); + } + _fb._offset = result; + setg(base(), base(), base()); + setp(base(), base()); + return result; +} + +filebuf* filebuf::close() +{ + if (!is_open()) + return NULL; + + // This flushes as well as switching mode. + if (pptr() > pbase() || put_mode()) + if (switch_to_get_mode()) return NULL; + + unsave_markers(); + + int status = sys_close(); + + // Free buffer. + setb(NULL, NULL, 0); + setg(NULL, NULL, NULL); + setp(NULL, NULL); + + _un_link(); + _flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS; + _fb._fileno = EOF; + _fb._offset = 0; + + return status < 0 ? NULL : this; +} + +_G_ssize_t filebuf::sys_read(char* buf, size_t size) +{ + for (;;) { + _G_ssize_t count = ::read(_fb._fileno, buf, size); + if (count != -1 || errno != EINTR) + return count; + } +} + +_G_fpos_t filebuf::sys_seek(_G_fpos_t offset, _seek_dir dir) +{ + return ::lseek(fd(), offset, (int)dir); +} + +_G_ssize_t filebuf::sys_write(const void *buf, long n) +{ + long to_do = n; + while (to_do > 0) { + _G_ssize_t count = ::write(fd(), buf, to_do); + if (count == EOF) { + if (errno == EINTR) + continue; + else { + _flags |= _S_ERR_SEEN; + break; + } + } + to_do -= count; + buf = (void*)((char*)buf + count); + } + n -= to_do; + if (_fb._offset >= 0) + _fb._offset += n; + return n; +} + +int filebuf::sys_stat(void* st) +{ + return ::_fstat(fd(), (struct stat*)st); +} + +int filebuf::sys_close() +{ + return ::close(fd()); +} + +int filebuf::xsputn(const char *s, int n) +{ + if (n <= 0) + return 0; + // This is an optimized implementation. + // If the amount to be written straddles a block boundary + // (or the filebuf is unbuffered), use sys_write directly. + + int to_do = n; + int must_flush = 0; + // First figure out how much space is available in the buffer. + int count = _epptr - _pptr; // Space available. + if (linebuffered() && (_flags & _S_CURRENTLY_PUTTING)) { + count =_ebuf - _pptr; + if (count >= n) { + for (register const char *p = s + n; p > s; ) { + if (*--p == '\n') { + count = p - s + 1; + must_flush = 1; + break; + } + } + } + } + // Then fill the buffer. + if (count > 0) { + if (count > to_do) + count = to_do; + if (count > 20) { + memcpy(pptr(), s, count); + s += count; + } + else { + register char *p = pptr();; + for (register int i = count; --i >= 0; ) *p++ = *s++; + } + pbump(count); + to_do -= count; + } + if (to_do + must_flush > 0) { + // Next flush the (full) buffer. + if (__overflow(this, EOF) == EOF) + return n - to_do; + + // Try to maintain alignment: write a whole number of blocks. + // dont_write is what gets left over. + int block_size = _ebuf - _base; + int dont_write = block_size >= 128 ? to_do % block_size : 0; + + _G_ssize_t count = to_do - dont_write; + if (do_write(s, count) == EOF) + return n - to_do; + to_do = dont_write; + + // Now write out the remainder. Normally, this will fit in the + // buffer, but it's somewhat messier for line-buffered files, + // so we let streambuf::sputn handle the general case. + if (dont_write) + to_do -= streambuf::sputn(s+count, dont_write); + } + return n - to_do; +} + +int filebuf::xsgetn(char *s, int n) +{ + // FIXME: OPTIMIZE THIS (specifically, when unbuffered()). + return streambuf::xsgetn(s, n); +} + +// Non-ANSI AT&T-ism: Default open protection. +const int filebuf::openprot = 0644; diff --git a/gnu/lib/libg++/iostream/floatconv.C b/gnu/lib/libg++/iostream/floatconv.C new file mode 100644 index 00000000000..fb70052c035 --- /dev/null +++ b/gnu/lib/libg++/iostream/floatconv.C @@ -0,0 +1,2416 @@ +#include <ioprivate.h> +#ifdef USE_DTOA +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991 by AT&T. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* Some cleaning up by Per Bothner, bothner@cygnus.com, 1992, 1993. */ + +/* Please send bug reports to + David M. Gay + AT&T Bell Laboratories, Room 2C-463 + 600 Mountain Avenue + Murray Hill, NJ 07974-2070 + U.S.A. + dmg@research.att.com or research!dmg + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_8087 for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_MC68k for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define Sudden_Underflow for IEEE-format machines without gradual + * underflow (i.e., that flush to zero on underflow). + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic. + * #define Unsigned_Shifts if >> does treats its left operand as unsigned. + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define Just_16 to store 16 bits per 32-bit long when doing high-precision + * integer arithmetic. Whether this speeds things up or slows things + * down depends on the machine and the number being converted. + * #define KR_headers for old-style C function headers. + */ + +#ifdef DEBUG +#include <stdio.h> +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#include <stdlib.h> +#include <string.h> +#define CONST const + +#include <errno.h> +#include <float.h> +#ifndef __MATH_H__ +#include <math.h> +#endif + +#ifdef Unsigned_Shifts +#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000; +#else +#define Sign_Extend(a,b) /*no-op*/ +#endif + +#if defined(__i386__) +#define IEEE_8087 +#endif + +#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 + +#if FLT_RADIX==16 +#define IBM +#elif DBL_MANT_DIG==56 +#define VAX +#elif DBL_MANT_DIG==53 && DBL_MAX_10_EXP==308 +#define IEEE_Unknown +#else +Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. +#endif +#endif + +#ifdef IEEE_8087 +#define HIWORD 1 +#define LOWORD 0 +#define TEST_ENDIANNESS /* nothing */ +#elif defined(IEEE_MC68k) +#define HIWORD 0 +#define LOWORD 1 +#define TEST_ENDIANNESS /* nothing */ +#else +static int HIWORD = -1, LOWORD; +static void test_endianness() +{ + union doubleword { + double d; + unsigned long u[2]; + } dw; + dw.d = 10; + if (dw.u[0] != 0) /* big-endian */ + HIWORD=0, LOWORD=1; + else + HIWORD=1, LOWORD=0; +} +#define TEST_ENDIANNESS if (HIWORD<0) test_endianness(); +#endif +#define word0(x) ((unsigned long *)&x)[HIWORD] +#define word1(x) ((unsigned long *)&x)[LOWORD] + +/* The following definition of Storeinc is appropriate for MIPS processors. */ +#if defined(IEEE_8087) + defined(VAX) +#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ +((unsigned short *)a)[0] = (unsigned short)c, a++) +#elif defined(IEEE_MC68k) +#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ +((unsigned short *)a)[1] = (unsigned short)c, a++) +#else +#define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_Unknown) +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Bias 1023 +#define IEEE_Arith +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#define Infinite(x) (word0(x) == 0x7ff00000) /* sufficient test for here */ +#else +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Bias 65 +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Bias 129 +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif +#endif + +#ifndef IEEE_Arith +#define ROUND_BIASED +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) a = rnd_prod(a, b) +#define rounded_quotient(a,b) a = rnd_quot(a, b) +extern double rnd_prod(double, double), rnd_quot(double, double); +#else +#define rounded_product(a,b) a *= b +#define rounded_quotient(a,b) a /= b +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Just_16 +/* When Pack_32 is not defined, we store 16 bits per 32-bit long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per long. + */ +#ifndef Pack_32 +#define Pack_32 +#endif +#endif + +#define Kmax 15 + +extern "C" double _Xstrtod(const char *s00, char **se); +extern "C" char *dtoa(double d, int mode, int ndigits, + int *decpt, int *sign, char **rve); + +struct Bigint { + /* Note: Order of fields is significant: Cfr. Bcopy macro. */ + struct Bigint *next; + int k; /* Parameter given to Balloc(k) */ + int maxwds; /* Allocated space: equals 1<<k. */ + int sign; + int wds; /* Current length. */ + unsigned long x[1]; /* Actually: x[maxwds] */ +}; + + typedef struct Bigint Bigint; + + static Bigint *freelist[Kmax+1]; + +/* Allocate a Bigint with '1<<k' big digits. */ + + static Bigint * +Balloc +#ifdef KR_headers + (k) int k; +#else + (int k) +#endif +{ + int x; + Bigint *rv; + + if (rv = freelist[k]) { + freelist[k] = rv->next; + } + else { + x = 1 << k; + rv = (Bigint *)malloc(sizeof(Bigint) + (x-1)*sizeof(long)); + rv->k = k; + rv->maxwds = x; + } + rv->sign = rv->wds = 0; + return rv; + } + + static void +Bfree +#ifdef KR_headers + (v) Bigint *v; +#else + (Bigint *v) +#endif +{ + if (v) { + v->next = freelist[v->k]; + freelist[v->k] = v; + } + } + +#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ +y->wds*sizeof(long) + 2*sizeof(int)) + +/* Return b*m+a. b is modified. */ + + static Bigint * +multadd +#ifdef KR_headers + (b, m, a) Bigint *b; int m, a; +#else + (Bigint *b, int m, int a) +#endif +{ + int i, wds; + unsigned long *x, y; +#ifdef Pack_32 + unsigned long xi, z; +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + do { +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + a; + z = (xi >> 16) * m + (y >> 16); + a = (int)(z >> 16); + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + a; + a = (int)(y >> 16); + *x++ = y & 0xffff; +#endif + } + while(++i < wds); + if (a) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = a; + b->wds = wds; + } + return b; + } + + static Bigint * +s2b +#ifdef KR_headers + (s, nd0, nd, y9) CONST char *s; int nd0, nd; unsigned long y9; +#else + (CONST char *s, int nd0, int nd, unsigned long y9) +#endif +{ + Bigint *b; + int i, k; + long x, y; + + x = (nd + 8) / 9; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(k); + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(k+1); + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do b = multadd(b, 10, *s++ - '0'); + while(++i < nd0); + s++; + } + else + s += 10; + for(; i < nd; i++) + b = multadd(b, 10, *s++ - '0'); + return b; + } + + static int +hi0bits +#ifdef KR_headers + (x) register unsigned long x; +#else + (register unsigned long x) +#endif +{ + register int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; + } + + static int +lo0bits +#ifdef KR_headers + (y) unsigned long *y; +#else + (unsigned long *y) +#endif +{ + register int k; + register unsigned long x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x & 1) + return 32; + } + *y = x; + return k; + } + + static Bigint * +i2b +#ifdef KR_headers + (i) int i; +#else + (int i) +#endif +{ + Bigint *b; + + b = Balloc(1); + b->x[0] = i; + b->wds = 1; + return b; + } + + static Bigint * +mult +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int k, wa, wb, wc; + unsigned long carry, y, z; + unsigned long *x, *xa, *xae, *xb, *xbe, *xc, *xc0; +#ifdef Pack_32 + unsigned long z2; +#endif + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + for(x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef Pack_32 + for(; xb < xbe; xb++, xc0++) { + if (y = *xb & 0xffff) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } + while(x < xae); + *xc = carry; + } + if (y = *xb >> 16) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } + while(x < xae); + *xc = z2; + } + } +#else + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } + while(x < xae); + *xc = carry; + } + } +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; + } + + static Bigint *p5s; + +/* Returns b*(5**k). b is modified. */ + + static Bigint * +pow5mult +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + Bigint *b1, *p5, *p51; + int i; + static int p05[3] = { 5, 25, 125 }; + + if (i = k & 3) + b = multadd(b, p05[i-1], 0); + + if (!(k >>= 2)) + return b; + if (!(p5 = p5s)) { + /* first time */ + p5 = p5s = i2b(625); + p5->next = 0; + } + for(;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + } + if (!(k >>= 1)) + break; + if (!(p51 = p5->next)) { + p51 = p5->next = mult(p5,p5); + p51->next = 0; + } + p5 = p51; + } + return b; + } + + static Bigint * +lshift +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + int i, k1, n, n1; + Bigint *b1; + unsigned long *x, *x1, *xe, z; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for(i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + x1 = b1->x; + for(i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#endif + else do + *x1++ = *x++; + while(x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; + } + + static int +cmp +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + unsigned long *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for(;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; + } + + static Bigint * +diff +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int i, wa, wb; + long borrow, y; /* We need signed shifts here. */ + unsigned long *xa, *xae, *xb, *xbe, *xc; +#ifdef Pack_32 + long z; +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + z = (*xa++ >> 16) - (*xb++ >> 16) + borrow; + borrow = z >> 16; + Sign_Extend(borrow, z); + Storeinc(xc, z, y); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + z = (*xa++ >> 16) + borrow; + borrow = z >> 16; + Sign_Extend(borrow, z); + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + *xc++ = y & 0xffff; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + *xc++ = y & 0xffff; + } +#endif + while(!*--xc) + wa--; + c->wds = wa; + return c; + } + + static double +ulp +#ifdef KR_headers + (x) double x; +#else + (double x) +#endif +{ + register long L; + double a; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + word0(a) = L; + word1(a) = 0; +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(a) = 0x80000 >> L; + word1(a) = 0; + } + else { + word0(a) = 0; + L -= Exp_shift; + word1(a) = L >= 31 ? 1 : 1 << 31 - L; + } + } +#endif + return a; + } + + static double +b2d +#ifdef KR_headers + (a, e) Bigint *a; int *e; +#else + (Bigint *a, int *e) +#endif +{ + unsigned long *xa, *xa0, w, y, z; + int k; + double d; +#ifdef VAX + unsigned long d0, d1; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + d0 = Exp_1 | y >> Ebits - k; + w = xa > xa0 ? *--xa : 0; + d1 = y << (32-Ebits) + k | w >> Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + d0 = Exp_1 | y << k | z >> 32 - k; + y = xa > xa0 ? *--xa : 0; + d1 = z << k | y >> 32 - k; + } + else { + d0 = Exp_1 | y; + d1 = z; + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; + y = xa > xa0 ? *--xa : 0; + d1 = w << k + 16 | y << k; +#endif + ret_d: +#ifdef VAX + word0(d) = d0 >> 16 | d0 << 16; + word1(d) = d1 >> 16 | d1 << 16; +#else +#undef d0 +#undef d1 +#endif + return d; + } + + static Bigint * +d2b +#ifdef KR_headers + (d, e, bits) double d; int *e, *bits; +#else + (double d, int *e, int *bits) +#endif +{ + Bigint *b; + int de, i, k; + unsigned long *x, y, z; +#ifdef VAX + unsigned long d0, d1; + d0 = word0(d) >> 16 | word0(d) << 16; + d1 = word1(d) >> 16 | word1(d) << 16; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + +#ifdef Pack_32 + b = Balloc(1); +#else + b = Balloc(2); +#endif + x = b->x; + + z = d0 & Frac_mask; + d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ + + de = (int)(d0 >> Exp_shift); /* The exponent part of d. */ + + /* Put back the suppressed high-order bit, if normalized. */ +#ifndef IBM +#ifndef Sudden_Underflow + if (de) +#endif + z |= Exp_msk1; +#endif + +#ifdef Pack_32 + if (y = d1) { + if (k = lo0bits(&y)) { + x[0] = y | z << 32 - k; + z >>= k; + } + else + x[0] = y; + i = b->wds = (x[1] = z) ? 2 : 1; + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + x[0] = z; + i = b->wds = 1; + k += 32; + } +#else + if (y = d1) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while(!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; + } +#undef d0 +#undef d1 + + static double +ratio +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + double da, db; + int k, ka, kb; + + da = b2d(a, &ka); + db = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + word0(da) += (k >> 2)*Exp_msk1; + if (k &= 3) + da *= 1 << k; + } + else { + k = -k; + word0(db) += (k >> 2)*Exp_msk1; + if (k &= 3) + db *= 1 << k; + } +#else + if (k > 0) + word0(da) += k*Exp_msk1; + else { + k = -k; + word0(db) += k*Exp_msk1; + } +#endif + return da / db; + } + + static double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif + }; + + static double +#ifdef IEEE_Arith +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; +#define n_bigtens 5 +#else +#ifdef IBM +bigtens[] = { 1e16, 1e32, 1e64 }; +static double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +bigtens[] = { 1e16, 1e32 }; +static double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + + double +_Xstrtod +#ifdef KR_headers + (s00, se) CONST char *s00; char **se; +#else + (CONST char *s00, char **se) +#endif +{ + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + CONST char *s, *s0, *s1; + double aadj, aadj1, adj, rv, rv0; + long L; + unsigned long y, z; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; + TEST_ENDIANNESS; + sign = nz0 = nz = 0; + rv = 0.; + for(s = s00;;s++) switch(*s) { + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) + goto break2; + /* no break */ + case 0: + goto ret; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; + } + break2: + if (*s == '0') { + nz0 = 1; + while(*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < 16) + z = 10*z + c - '0'; + nd0 = nd; + if (c == '.') { + c = *++s; + if (!nd) { + for(; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for(; c >= '0' && c <= '9'; c = *++s) { + have_dig: + nz++; + if (c -= '0') { + nf += nz; + for(i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 1) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 1) + z = 10*z + c; + nz = 0; + } + } + } + dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + s = s00; + goto ret; + } + s00 = s; + esign = 0; + switch(c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while(c == '0') + c = *++s; + if (c > '0' && c <= '9') { + e = c - '0'; + s1 = s; + while((c = *++s) >= '0' && c <= '9') + e = 10*e + c - '0'; + if (s - s1 > 8) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 9999999; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) + s = s00; + goto ret; + } + e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + rv = y; + if (k > 9) + rv = tens[k - 9] * rv + z; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT + && FLT_ROUNDS == 1 +#endif + ) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else + /* rv = */ rounded_product(rv, tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ + e -= i; + rv *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ + vax_ovfl_check: + word0(rv) -= P*Exp_msk1; + /* rv = */ rounded_product(rv, tens[e]); + if ((word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + word0(rv) += P*Exp_msk1; +#else + /* rv = */ rounded_product(rv, tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { + /* rv = */ rounded_quotient(rv, tens[-e]); + goto ret; + } +#endif + } + e1 += nd - k; + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if (i = e1 & 15) + rv *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { + ovfl: + errno = ERANGE; +#ifndef HUGE_VAL +#define HUGE_VAL 1.7976931348623157E+308 +#endif + rv = HUGE_VAL; + goto ret; + } + if (e1 >>= 4) { + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + rv *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(rv) -= P*Exp_msk1; + rv *= bigtens[j]; + if ((z = word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(rv) = Big0; + word1(rv) = Big1; + } + else + word0(rv) += P*Exp_msk1; + } + + } + } + else if (e1 < 0) { + e1 = -e1; + if (i = e1 & 15) + rv /= tens[i]; + if (e1 &= ~15) { + e1 >>= 4; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + rv *= tinytens[j]; + /* The last multiplication could underflow. */ + rv0 = rv; + rv *= tinytens[j]; + if (!rv) { + rv = 2.*rv0; + rv *= tinytens[j]; + if (!rv) { + undfl: + rv = 0.; + errno = ERANGE; + goto ret; + } + word0(rv) = Tiny0; + word1(rv) = Tiny1; + /* The refinement below will clean + * this approximation up. + */ + } + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bd0 = s2b(s0, nd0, nd, y); + + for(;;) { + bd = Balloc(bd0->k); + Bcopy(bd, bd0); + bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else + i = bbe + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j = bbe + (P-Emin); + else + j = P + 1 - bbbits; +#endif + bb2 += j; + bd2 += j; + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + } + if (bb2 > 0) + bb = lshift(bb, bb2); + if (bd5 > 0) + bd = pow5mult(bd, bd5); + if (bd2 > 0) + bd = lshift(bd, bd2); + if (bs2 > 0) + bs = lshift(bs, bs2); + delta = diff(bb, bd); + dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask) + break; + delta = lshift(delta,Log2P); + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (dsign) { + if ((word0(rv) & Bndry_mask1) == Bndry_mask1 + && word1(rv) == 0xffffffff) { + /*boundary case -- increment exponent*/ + word0(rv) = (word0(rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ; + word1(rv) = 0; + break; + } + } + else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { + drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow + L = word0(rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else + if (L <= Exp_msk1) +#endif + goto undfl; + L -= Exp_msk1; +#else + L = (word0(rv) & Exp_mask) - Exp_msk1; +#endif + word0(rv) = L | Bndry_mask1; + word1(rv) = 0xffffffff; +#ifdef IBM + goto cont; +#else + break; +#endif + } +#ifndef ROUND_BIASED + if (!(word1(rv) & LSB)) + break; +#endif + if (dsign) + rv += ulp(rv); +#ifndef ROUND_BIASED + else { + rv -= ulp(rv); +#ifndef Sudden_Underflow + if (!rv) + goto undfl; +#endif + } +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (dsign) + aadj = aadj1 = 1.; + else if (word1(rv) || word0(rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (word1(rv) == Tiny1 && !word0(rv)) + goto undfl; +#endif + aadj = 1.; + aadj1 = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + aadj1 = -aadj; + } + } + else { + aadj *= 0.5; + aadj1 = dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch(FLT_ROUNDS) { + case 2: /* towards +infinity */ + aadj1 -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + aadj1 += 0.5; + } +#else + if (FLT_ROUNDS == 0) + aadj1 += 0.5; +#endif + } + y = word0(rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + rv0 = rv; + word0(rv) -= P*Exp_msk1; + adj = aadj1 * ulp(rv); + rv += adj; + if ((word0(rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(rv0) == Big0 && word1(rv0) == Big1) + goto ovfl; + word0(rv) = Big0; + word1(rv) = Big1; + goto cont; + } + else + word0(rv) += P*Exp_msk1; + } + else { +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + rv0 = rv; + word0(rv) += P*Exp_msk1; + adj = aadj1 * ulp(rv); + rv += adj; +#ifdef IBM + if ((word0(rv) & Exp_mask) < P*Exp_msk1) +#else + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (word0(rv0) == Tiny0 + && word1(rv0) == Tiny1) + goto undfl; + word0(rv) = Tiny0; + word1(rv) = Tiny1; + goto cont; + } + else + word0(rv) -= P*Exp_msk1; + } + else { + adj = aadj1 * ulp(rv); + rv += adj; + } +#else + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj >= 1.) { + aadj1 = (double)(int)(aadj + 0.5); + if (!dsign) + aadj1 = -aadj1; + } + adj = aadj1 * ulp(rv); + rv += adj; +#endif + } + z = word0(rv) & Exp_mask; + if (y == z) { + /* Can we stop now? */ + L = (long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } + cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); + ret: + if (se) + *se = (char *)s; + return sign ? -rv : rv; + } + + static int +quorem +#ifdef KR_headers + (b, S) Bigint *b, *S; +#else + (Bigint *b, Bigint *S) +#endif +{ + int n; + long borrow, y; + unsigned long carry, q, ys; + unsigned long *bx, *bxe, *sx, *sxe; +#ifdef Pack_32 + long z; + unsigned long si, zs; +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG + /*debug*/ if (q > 9) + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + z = (*bx >> 16) - (zs & 0xffff) + borrow; + borrow = z >> 16; + Sign_Extend(borrow, z); + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + *bx++ = y & 0xffff; +#endif + } + while(sx <= sxe); + if (!*bxe) { + bx = b->x; + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + z = (*bx >> 16) - (zs & 0xffff) + borrow; + borrow = z >> 16; + Sign_Extend(borrow, z); + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) + borrow; + borrow = y >> 16; + Sign_Extend(borrow, y); + *bx++ = y & 0xffff; +#endif + } + while(sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; + } + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the long + * calculation. + */ + + char * +dtoa +#ifdef KR_headers + (d, mode, ndigits, decpt, sign, rve) + double d; int mode, ndigits, *decpt, *sign; char **rve; +#else + (double d, int mode, int ndigits, int *decpt, int *sign, char **rve) +#endif +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4-9 should give the same return values as 2-3, i.e., + 4 <= mode <= 9 ==> same return as mode + 2 + (mode & 1). These modes are mainly for + debugging; often they run slower but sometimes + faster than modes 2-3. + 4,5,8,9 ==> left-to-right digit generation. + 6-9 ==> don't try fast floating-point estimate + (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick; + long L; +#ifndef Sudden_Underflow + int denorm; + unsigned long x; +#endif + Bigint *b, *b1, *delta, *mlo, *mhi, *S; + double d2, ds, eps; + char *s, *s0; + static Bigint *result; + static int result_k; + + TEST_ENDIANNESS; + if (result) { + result->k = result_k; + result->maxwds = 1 << result_k; + Bfree(result); + result = 0; + } + + if (word0(d) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(d) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((word0(d) & Exp_mask) == Exp_mask) +#else + if (word0(d) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; +#ifdef IEEE_Arith + if (!word1(d) && !(word0(d) & 0xfffff)) + { + s = "Infinity"; + if (*rve) + *rve = s + 8; + } + else +#endif + { + s = "NaN"; + if (rve) + *rve = s +3; + } + return s; + } +#endif +#ifdef IBM + d += 0; /* normalize */ +#endif + if (!d) { + *decpt = 1; + s = "0"; + if (rve) + *rve = s + 1; + return s; + } + + b = d2b(d, &be, &bbits); + i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#ifndef Sudden_Underflow + if (i) { +#endif + d2 = d; + word0(d2) &= Frac_mask1; + word0(d2) |= Exp_11; +#ifdef IBM + if (j = 11 - hi0bits(word0(d2) & Frac_mask)) + d2 /= 1 << j; +#endif + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32 + : word1(d) << 32 - i; + d2 = x; + word0(d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + + /* Now i is the unbiased base-2 exponent. */ + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = i*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = i*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i) by 0.301029995663981; since |i| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (d < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + try_quick = 1; + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + switch(mode) { + case 0: + case 1: + ilim = ilim1 = -1; + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + /* i is now an upper bound of the number of digits to generate. */ + j = sizeof(unsigned long); + /* The test is <= so as to allow room for the final '\0'. */ + for(result_k = 0; sizeof(Bigint) - sizeof(unsigned long) + j <= i; + j <<= 1) result_k++; + result = Balloc(result_k); + s = s0 = (char *)result; + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + d2 = d; + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + d /= bigtens[n_bigtens-1]; + ieps++; + } + for(; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + d /= ds; + } + else if (j1 = -k) { + d *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + d *= bigtens[i]; + } + } + if (k_check && d < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + d *= 10.; + ieps++; + } + eps = ieps*d + 7.; + word0(eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + d -= 5.; + if (d > eps) + goto one_digit; + if (d < -eps) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + eps = 0.5/tens[ilim-1] - eps; + for(i = 0;;) { + L = (long)d; + d -= L; + *s++ = '0' + (int)L; + if (d < eps) + goto ret1; + if (1. - d < eps) + goto bump_up; + if (++i >= ilim) + break; + eps *= 10.; + d *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ + eps *= tens[ilim-1]; + for(i = 1;; i++, d *= 10.) { + L = (long)d; + d -= L; + *s++ = '0' + (int)L; + if (i == ilim) { + if (d > 0.5 + eps) + goto bump_up; + else if (d < 0.5 - eps) { + while(*--s == '0'); + s++; + goto ret1; + } + break; + } + } +#ifndef No_leftright + } +#endif + fast_failed: + s = s0; + d = d2; + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || d <= 5*ds) + goto no_digits; + goto one_digit; + } + for(i = 1;; i++) { + L = (long)(d / ds); + d -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (d < 0) { + L--; + d += ds; + } +#endif + *s++ = '0' + (int)L; + if (i == ilim) { + d += d; + if (d > ds || d == ds && L & 1) { + bump_up: + while(*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + if (!(d *= 10.)) + break; + } + goto ret1; + } + + m2 = b2; + m5 = b5; + mhi = mlo = 0; + if (leftright) { + if (mode < 2) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + } + else { + j = ilim - 1; + if (m5 >= j) + m5 -= j; + else { + s5 += j -= m5; + b5 += j; + m5 = 0; + } + if ((i = ilim) < 0) { + m2 -= i; + i = 0; + } + } + b2 += i; + s2 += i; + mhi = i2b(1); + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + b1 = mult(mhi, b); + Bfree(b); + b = b1; + } + if (j = b5 - m5) + b = pow5mult(b, j); + } + else + b = pow5mult(b, b5); + } + S = i2b(1); + if (s5 > 0) + S = pow5mult(S, s5); + + /* Check for special case that d is a normalized power of 2. */ + + if (mode < 2) { + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & Exp_mask +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + else + spec_case = 0; + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ +#ifdef Pack_32 + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) + i = 32 - i; +#else + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) + i = 16 - i; +#endif + if (i > 4) { + i -= 4; + b2 += i; + m2 += i; + s2 += i; + } + else if (i < 4) { + i += 28; + b2 += i; + m2 += i; + s2 += i; + } + if (b2 > 0) + b = lshift(b, b2); + if (s2 > 0) + S = lshift(S, s2); + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (leftright) + mhi = multadd(mhi, 10, 0); + ilim = ilim1; + } + } + if (ilim <= 0 && mode > 2) { + if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + /* no digits, fcvt style */ + no_digits: + k = -1 - ndigits; + goto ret; + } + one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) + mhi = lshift(mhi, m2); + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + } + + for(i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); +#ifndef ROUND_BIASED + if (j1 == 0 && !mode && !(word1(d) & 1)) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; + *s++ = dig; + goto ret; + } +#endif + if (j < 0 || j == 0 && !mode +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + ) { + if (j1 > 0) { + b = lshift(b, 1); + j1 = cmp(b, S); + if ((j1 > 0 || j1 == 0 && dig & 1) + && dig++ == '9') + goto round_9_up; + } + *s++ = dig; + goto ret; + } + if (j1 > 0) { + if (dig == '9') { /* possible if i == 1 */ + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } + *s++ = dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (mlo == mhi) + mlo = mhi = multadd(mhi, 10, 0); + else { + mlo = multadd(mlo, 10, 0); + mhi = multadd(mhi, 10, 0); + } + } + } + else + for(i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (i >= ilim) + break; + b = multadd(b, 10, 0); + } + + /* Round off last digit */ + + b = lshift(b, 1); + j = cmp(b, S); + if (j > 0 || j == 0 && dig & 1) { + roundoff: + while(*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { + while(*--s == '0'); + s++; + } + ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + ret1: + Bfree(b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; + } +#endif /* USE_DTOA */ diff --git a/gnu/lib/libg++/iostream/floatio.h b/gnu/lib/libg++/iostream/floatio.h new file mode 100644 index 00000000000..d3d2d0e5201 --- /dev/null +++ b/gnu/lib/libg++/iostream/floatio.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: floatio.h,v 1.1 1995/10/18 08:38:12 deraadt Exp $ + */ + +/* + * Floating point scanf/printf (input/output) definitions. + */ + +/* 11-bit exponent (VAX G floating point) is 308 decimal digits */ +#define MAXEXP 308 +/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */ +#define MAXFRACT 39 diff --git a/gnu/lib/libg++/iostream/fstream.C b/gnu/lib/libg++/iostream/fstream.C new file mode 100644 index 00000000000..9b45573ea03 --- /dev/null +++ b/gnu/lib/libg++/iostream/fstream.C @@ -0,0 +1,65 @@ +// 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 "ioprivate.h" +#include <fstream.h> + +fstreambase::fstreambase() +{ + init(new filebuf()); +} + +fstreambase::fstreambase(int fd) +{ + init(new filebuf(fd)); +} + +fstreambase::fstreambase(const char *name, int mode, int prot) +{ + init(new filebuf()); + if (!rdbuf()->open(name, mode, prot)) + set(ios::badbit); +} + +void fstreambase::open(const char *name, int mode, int prot) +{ + clear(); + if (!rdbuf()->open(name, mode, prot)) + set(ios::badbit); +} + +void fstreambase::close() +{ + if (!rdbuf()->close()) + set(ios::failbit); +} + +#if 0 +static int mode_to_sys(enum open_mode mode) +{ + return O_WRONLY; +} + +static char* fopen_cmd_arg(io_mode i) +{ + return "w"; +} +#endif diff --git a/gnu/lib/libg++/iostream/fstream.h b/gnu/lib/libg++/iostream/fstream.h new file mode 100644 index 00000000000..7395dc8b878 --- /dev/null +++ b/gnu/lib/libg++/iostream/fstream.h @@ -0,0 +1,72 @@ +// 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. +// +// $Id: fstream.h,v 1.1 1995/10/18 08:38:12 deraadt Exp $ + +#ifndef _FSTREAM_H +#define _FSTREAM_H +#ifdef __GNUG__ +#pragma interface +#endif +#include <iostream.h> + +class fstreambase : virtual public ios { + public: + fstreambase(); + fstreambase(int fd); + fstreambase(const char *name, int mode, int prot=0664); + void close(); + filebuf* rdbuf() const { return (filebuf*)_strbuf; } + void open(const char *name, int mode, int prot=0664); + int is_open() const { return rdbuf()->is_open(); } + void setbuf(char *ptr, int len) { rdbuf()->setbuf(ptr, len); } +#ifdef _STREAM_COMPAT + int filedesc() { return rdbuf()->fd(); } + fstreambase& raw() { rdbuf()->setbuf(NULL, 0); return *this; } +#endif +}; + +class ifstream : public fstreambase, public istream { + public: + ifstream() : fstreambase() { } + ifstream(int fd) : fstreambase(fd) { } + ifstream(const char *name, int mode=ios::in, int prot=0664) + : fstreambase(name, mode, prot) { } + void open(const char *name, int mode=ios::in, int prot=0664) + { fstreambase::open(name, mode, prot); } +}; + +class ofstream : public fstreambase, public ostream { + public: + ofstream() : fstreambase() { } + ofstream(int fd) : fstreambase(fd) { } + ofstream(const char *name, int mode=ios::out, int prot=0664) + : fstreambase(name, mode, prot) { } + void open(const char *name, int mode=ios::out, int prot=0664) + { fstreambase::open(name, mode, prot); } +}; + +class fstream : public fstreambase, public iostream { + public: + fstream() : fstreambase() { } + fstream(int fd) : fstreambase(fd) { } + fstream(const char *name, int mode, int prot=0664) + : fstreambase(name, mode, prot) { } + void open(const char *name, int mode, int prot=0664) + { fstreambase::open(name, mode, prot); } +}; +#endif /*!_FSTREAM_H*/ diff --git a/gnu/lib/libg++/iostream/igetline.C b/gnu/lib/libg++/iostream/igetline.C new file mode 100644 index 00000000000..90ed189feaf --- /dev/null +++ b/gnu/lib/libg++/iostream/igetline.C @@ -0,0 +1,135 @@ +// This is part of the iostream library, providing input/output for C++. +// Copyright (C) 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 "iostream.h" +#include <string.h> + +istream& istream::getline(char* buf, int len, char delim) +{ + _gcount = 0; + if (ipfx1()) { + streambuf *sb = rdbuf(); + long count = sb->sgetline(buf, len, delim, -1); + if (count == len-1) + set(ios::failbit); + else { + int ch = sb->sbumpc(); + if (ch == EOF) + set(ios::failbit|ios::eofbit); + else if (ch == (unsigned char)delim) + count++; + else + sb->sungetc(); // Leave delimiter unread. + } + _gcount = count; + } + return *this; +} + +istream& istream::get(char* buf, int len, char delim) +{ + _gcount = 0; + if (ipfx1()) { + streambuf *sbuf = rdbuf(); + long count = sbuf->sgetline(buf, len, delim, -1); + if (count < 0 || (count == 0 && sbuf->sgetc() == EOF)) + set(ios::failbit|ios::eofbit); + else + _gcount = count; + } + return *this; +} + +// This is part of the iostream library, providing input/output for C++. +// Copyright (C) 1992 Free Software Foundation. +// +// 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. + +// from Doug Schmidt + +#define CHUNK_SIZE 512 + +/* Reads an arbitrarily long input line terminated by a user-specified + TERMINATOR. Super-nifty trick using recursion avoids unnecessary calls + to NEW! */ + +char *_sb_readline (streambuf *sb, long& total, char terminator) +{ + char buf[CHUNK_SIZE+1]; + char *ptr; + int ch; + + long count = sb->sgetline(buf, CHUNK_SIZE+1, terminator, -1); + if (count == EOF) + return NULL; + ch = sb->sbumpc(); + long old_total = total; + total += count; + if (ch != EOF && ch != terminator) { + total++; // Include ch in total. + ptr = _sb_readline(sb, total, terminator); + if (ptr) { + memcpy(ptr + old_total, buf, count); + ptr[old_total+count] = ch; + } + return ptr; + } + + if (ptr = new char[total+1]) { + ptr[total] = '\0'; + memcpy(ptr + total - count, buf, count); + return ptr; + } + else + return NULL; +} + +/* Reads an arbitrarily long input line terminated by TERMINATOR. + This routine allocates its own memory, so the user should + only supply the address of a (char *). */ + +istream& istream::gets(char **s, char delim /* = '\n' */) +{ + if (ipfx1()) { + long size = 0; + streambuf *sb = rdbuf(); + *s = _sb_readline (sb, size, delim); + _gcount = *s ? size : 0; + if (sb->_flags & _S_EOF_SEEN) { + set(ios::eofbit); + if (_gcount == 0) + set(ios::failbit); + } + } + else { + _gcount = 0; + *s = NULL; + } + return *this; +} diff --git a/gnu/lib/libg++/iostream/igetsb.C b/gnu/lib/libg++/iostream/igetsb.C new file mode 100644 index 00000000000..a6a2e6315d6 --- /dev/null +++ b/gnu/lib/libg++/iostream/igetsb.C @@ -0,0 +1,48 @@ +// This is part of the iostream library, providing input/output for C++. +// Copyright (C) 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 "ioprivate.h" +#include "iostream.h" + +istream& istream::get(streambuf& sb, char delim /* = '\n' */) +{ + _gcount = 0; + if (ipfx1()) { + register streambuf* isb = rdbuf(); + for (;;) { + int len = isb->egptr() - isb->gptr(); + if (len <= 0) + if (isb->underflow() == EOF) + break; + else + len = isb->egptr() - isb->gptr(); + char *delimp = (char*)memchr((void*)isb->gptr(), delim, len); + if (delimp != NULL) + len = delimp - isb->gptr(); + int written = sb.sputn(isb->gptr(), len); + isb->gbump(written); + _gcount += written; + if (written != len) { + set(ios::failbit); + break; + } + if (delimp != NULL) + break; + } + } + return *this; +} diff --git a/gnu/lib/libg++/iostream/indstream.C b/gnu/lib/libg++/iostream/indstream.C new file mode 100644 index 00000000000..b58e362d4bd --- /dev/null +++ b/gnu/lib/libg++/iostream/indstream.C @@ -0,0 +1,108 @@ +// This is part of the iostream library, providing -*- C++ -*- input/output. +// Copyright (C) 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. + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <indstream.h> + +indirectbuf::indirectbuf(streambuf *get, streambuf *put, int delete_mode) +: streambuf() +{ + _get_stream = get; + _put_stream = put == NULL ? get : put; + _delete_flags = delete_mode; +} + +indirectbuf::~indirectbuf() +{ + if (_delete_flags & ios::in) delete get_stream(); + if (_delete_flags & ios::out) delete put_stream(); +} + +int indirectbuf::xsputn(const char* s, int n) +{ + return put_stream()->sputn(s, n); +} + +int indirectbuf::xsgetn(char* s, int n) +{ + return get_stream()->sgetn(s, n); +} + +int indirectbuf::overflow(int c /* = EOF */) +{ + if (c == EOF) + return put_stream()->overflow(c); + else + return put_stream()->sputc(c); +} + +int indirectbuf::underflow() +{ + return get_stream()->sbumpc(); +} + +streampos indirectbuf::seekoff(streamoff off, _seek_dir dir, int mode) +{ + int ret_val = 0; + int select = mode == 0 ? (ios::in|ios::out) : mode; + streambuf *gbuf = (select & ios::in) ? get_stream() : NULL; + streambuf *pbuf = (select & ios::out) ? put_stream() : NULL; + if (gbuf == pbuf) + ret_val = gbuf->seekoff(off, dir, mode); + else { + if (gbuf) + ret_val = gbuf->seekoff(off, dir, ios::in); + if (pbuf && ret_val != EOF) + ret_val = pbuf->seekoff(off, dir, ios::out); + } + return ret_val; +} + +streampos indirectbuf::seekpos(streampos pos, int mode) +{ + int ret_val = EOF; + int select = mode == 0 ? (ios::in|ios::out) : mode; + streambuf *gbuf = (select & ios::in) ? get_stream() : NULL; + streambuf *pbuf = (select & ios::out) ? put_stream() : NULL; + if (gbuf == pbuf) + ret_val = gbuf->seekpos(pos, mode); + else { + if (gbuf) + ret_val = gbuf->seekpos(pos, ios::in); + if (pbuf && ret_val != EOF) + ret_val = pbuf->seekpos(pos, ios::out); + } + return ret_val; +} + +int indirectbuf::sync() +{ + streambuf *gbuf = get_stream(); + int ret_val = gbuf->sync(); + if (ret_val == EOF) return ret_val; + streambuf *pbuf = put_stream(); + if (pbuf != gbuf) return pbuf->sync(); + else return ret_val; +} + +int indirectbuf::pbackfail(int c) +{ + return get_stream()->sputbackc(c); +} diff --git a/gnu/lib/libg++/iostream/indstream.h b/gnu/lib/libg++/iostream/indstream.h new file mode 100644 index 00000000000..5c3febe6b37 --- /dev/null +++ b/gnu/lib/libg++/iostream/indstream.h @@ -0,0 +1,67 @@ +// This is part of the iostream library, providing -*- C++ -*- input/output. +// Copyright (C) 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. +// +// $Id: indstream.h,v 1.1 1995/10/18 08:38:13 deraadt Exp $ + +#ifndef _INDSTREAM_H +#define _INDSTREAM_H + +#ifdef __GNUG__ +#pragma interface +#endif + +#include <iostream.h> + +// An indirectbuf is one that forwards all of its I/O requests +// to another streambuf. +// All get-related requests are sent to get_stream(). +// All put-related requests are sent to put_stream(). + +// An indirectbuf can be used to implement Common Lisp +// synonym-streams and two-way-streams. +// +// class synonymbuf : public indirectbuf { +// Symbol *sym; +// synonymbuf(Symbol *s) { sym = s; } +// virtual streambuf *lookup_stream(int mode) { +// return coerce_to_streambuf(lookup_value(sym)); } +// }; + +class indirectbuf : public streambuf { + protected: + streambuf *_get_stream; // Optional cache for get_stream(). + streambuf *_put_stream; // Optional cache for put_stream(). + int _delete_flags; + public: + streambuf *get_stream() + { return _get_stream ? _get_stream : lookup_stream(ios::in); } + streambuf *put_stream() + { return _put_stream ? _put_stream : lookup_stream(ios::out); } + virtual streambuf *lookup_stream(int/*mode*/) { return NULL; } // ERROR! + indirectbuf(streambuf *get=NULL, streambuf *put=NULL, int delete_mode=0); + virtual ~indirectbuf(); + virtual int xsputn(const char* s, int n); + virtual int xsgetn(char* s, int n); + virtual int underflow(); + virtual int overflow(int c = EOF); + virtual streampos seekoff(streamoff, _seek_dir, int mode=ios::in|ios::out); + virtual streampos seekpos(streampos pos, int mode = ios::in|ios::out); + virtual int sync(); + virtual int pbackfail(int c); +}; + +#endif /* !_INDSTREAM_H */ diff --git a/gnu/lib/libg++/iostream/iomanip.C b/gnu/lib/libg++/iostream/iomanip.C new file mode 100644 index 00000000000..b2aec86396b --- /dev/null +++ b/gnu/lib/libg++/iostream/iomanip.C @@ -0,0 +1,77 @@ +// -*- C++ -*- +// This is part of the iostream library, providing parametrized manipulators +// Written by Heinz G. Seidl, Copyright (C) 1992 Cygnus Support +// +// 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 + +#include "iomanip.h" + + +// Those functions are called through a pointer, +// thus it does not make sense, to inline them. + +ios & __iomanip_setbase (ios& i, int n) +{ + ios::fmtflags b; + switch (n) + { + case 8: + b = ios::oct; break; + case 10: + b = ios::dec; break; + case 16: + b = ios::hex; break; + default: + b = 0; + } + i.setf(b, ios::basefield); + return i; +} + +ios & __iomanip_setfill (ios& i, int n) +{ + //FIXME if ( i.flags() & ios::widechar ) + i.fill( (char) n); + //FIXME else + //FIXME i.fill( (wchar) n); + return i; +} + +ios & __iomanip_setprecision (ios& i, int n) +{ + i.precision(n); + return i; +} +ios & __iomanip_setw (ios& i, int n) +{ + i.width(n); + return i; +} + +ios & __iomanip_setiosflags (ios& i, ios::fmtflags n) +{ + i.setf(n,n); + return i; +} + +ios & __iomanip_resetiosflags (ios& i, ios::fmtflags n) +{ + i.setf(0,n); + return i; +} diff --git a/gnu/lib/libg++/iostream/iomanip.h b/gnu/lib/libg++/iostream/iomanip.h new file mode 100644 index 00000000000..25589a3f9f1 --- /dev/null +++ b/gnu/lib/libg++/iostream/iomanip.h @@ -0,0 +1,152 @@ +// -*- C++ -*- +// This is part of the iostream library, providing parametrized manipulators +// Written by Heinz G. Seidl, Copyright (C) 1992 Cygnus Support +// +// 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. +// +// $Id: iomanip.h,v 1.1 1995/10/18 08:38:13 deraadt Exp $ + +#ifndef _IOMANIP_H +// +// Not specifying `pragma interface' causes the compiler to emit the +// template definitions in the files, where they are used. +// +//#ifdef __GNUG__ +//#pragma interface +//#endif +#define _IOMANIP_H + +#include <_G_config.h> + +#ifndef _G_NO_TEMPLATES + +#include <iostream.h> + +//----------------------------------------------------------------------------- +// Parametrized Manipulators as specified by ANSI draft +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Stream Manipulators +//----------------------------------------------------------------------------- +// +template<class TP> class smanip; // TP = Type Param + +template<class TP> class sapp { + ios& (*_f)(ios&, TP); +public: + sapp(ios& (*f)(ios&, TP)) : _f(f) {} + // + smanip<TP> operator()(TP a) + { return smanip<TP>(_f, a); } +}; + +template <class TP> class smanip { + ios& (*_f)(ios&, TP); + TP _a; +public: + smanip(ios& (*f)(ios&, TP), TP a) : _f(f), _a(a) {} + // + friend + istream& operator>>(istream& i, const smanip<TP>& m); + friend + ostream& operator<<(ostream& o, const smanip<TP>& m); +}; + +template<class TP> +inline istream& operator>>(istream& i, const smanip<TP>& m) + { (*m._f)(i, m._a); return i; } + +template<class TP> +inline ostream& operator<<(ostream& o, const smanip<TP>& m) + { (*m._f)(o, m._a); return o;} + +//----------------------------------------------------------------------------- +// Input-Stream Manipulators +//----------------------------------------------------------------------------- +// +template<class TP> class imanip; + +template<class TP> class iapp { + istream& (*_f)(istream&, TP); +public: + iapp(ostream& (*f)(istream&,TP)) : _f(f) {} + // + imanip<TP> operator()(TP a) + { return imanip<TP>(_f, a); } +}; + +template <class TP> class imanip { + istream& (*_f)(istream&, TP); + TP _a; +public: + imanip(istream& (*f)(istream&, TP), TP a) : _f(f), _a(a) {} + // + friend + istream& operator>>(istream& i, const imanip<TP>& m) + { return (*m._f)( i, m._a); } +}; + + +//----------------------------------------------------------------------------- +// Output-Stream Manipulators +//----------------------------------------------------------------------------- +// +template<class TP> class omanip; + +template<class TP> class oapp { + ostream& (*_f)(ostream&, TP); +public: + oapp(ostream& (*f)(ostream&,TP)) : _f(f) {} + // + omanip<TP> operator()(TP a) + { return omanip<TP>(_f, a); } +}; + +template <class TP> class omanip { + ostream& (*_f)(ostream&, TP); + TP _a; +public: + omanip(ostream& (*f)(ostream&, TP), TP a) : _f(f), _a(a) {} + // + friend + ostream& operator<<(ostream& o, omanip<TP>& m) + { return (*m._f)(o, m._a); } +}; + + +//----------------------------------------------------------------------------- +// Available Manipulators +//----------------------------------------------------------------------------- + +// +// Macro to define an iomanip function, with one argument +// The underlying function is `__iomanip_<name>' +// +#define __DEFINE_IOMANIP_FN1(type,param,function) \ + extern ios& __iomanip_##function (ios&, param); \ + inline type<param> function (param n) \ + { return type<param> (__iomanip_##function, n); } + +__DEFINE_IOMANIP_FN1( smanip, int, setbase) +__DEFINE_IOMANIP_FN1( smanip, int, setfill) +__DEFINE_IOMANIP_FN1( smanip, int, setprecision) +__DEFINE_IOMANIP_FN1( smanip, int, setw) + +__DEFINE_IOMANIP_FN1( smanip, ios::fmtflags, resetiosflags) +__DEFINE_IOMANIP_FN1( smanip, ios::fmtflags, setiosflags) + +#endif /*!_G_NO_TEMPLATES*/ +#endif /*!_IOMANIP_H*/ diff --git a/gnu/lib/libg++/iostream/ioprivate.h b/gnu/lib/libg++/iostream/ioprivate.h new file mode 100644 index 00000000000..b8b00c209b0 --- /dev/null +++ b/gnu/lib/libg++/iostream/ioprivate.h @@ -0,0 +1,66 @@ +// This is part of the iostream library, providing -*- C++ -*- input/output. +// 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. +// +// $Id: ioprivate.h,v 1.1 1995/10/18 08:38:13 deraadt Exp $ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "streambuf.h" +#include <stdarg.h> +#include <stddef.h> + +#define _fstat(x, y) fstat(x,y) +#define _isatty(fd) isatty(fd) + +extern int __cvt_double(double number, register int prec, int flags, + int *signp, int fmtch, char *startp, char *endp); + +/*#define USE_MALLOC_BUF*/ + +#ifndef USE_MALLOC_BUF +#define ALLOC_BUF(size) new char[size] +#define FREE_BUF(ptr) delete [] (ptr) +#else +#define ALLOC_BUF(size) (char*)malloc(size) +#define FREE_BUF(ptr) free(ptr) +#endif + +#define USE_DTOA + +// Advantages: +// - Input gets closest value +// - Output emits string that when read yields identical value. +// - Handles Infinity and NaNs (but not re-readable). +// Disadvantages of dtoa: +// - May not work for all double formats. +// - Big chunck of code. +// - Not reentrant - uses atatic variables freelist, +// result, result_k in dtoa +// (plus initializes p5s, HOWORD, and LOWORD). + +#ifdef USE_DTOA +extern "C" double _Xstrtod(const char *s00, char **se); +#define strtod(s, e) _Xstrtod(s, e) +extern "C" char *dtoa(double d, int mode, int ndigits, + int *decpt, int *sign, char **rve); +extern int __outfloat(double value, streambuf *sb, char mode, + int width, int precision, __fmtflags flags, + char sign_mode, char fill); +#endif + diff --git a/gnu/lib/libg++/iostream/iostream.C b/gnu/lib/libg++/iostream/iostream.C new file mode 100644 index 00000000000..21e26c57475 --- /dev/null +++ b/gnu/lib/libg++/iostream/iostream.C @@ -0,0 +1,783 @@ +// 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. + +#ifdef __GNUG__ +#pragma implementation +#endif +#define _STREAM_COMPAT +#include "ioprivate.h" +#include <iostream.h> +#include <stdio.h> /* Needed for sprintf */ +#include <ctype.h> +#include <limits.h> +#include "floatio.h" + +#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; + _gcount = 0; +} + +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); + _gcount = 0; + } + else { + c = (char)ch; + _gcount = 1; + } + } + return *this; +} + +int istream::peek() +{ + if (!good()) + return EOF; + if (_tie && rdbuf()->in_avail() == 0) + _tie->flush(); + int ch = _strbuf->sgetc(); + if (ch == EOF) + set(ios::eofbit); + return ch; +} + +istream& istream::ignore(int n /* = 1 */, int delim /* = EOF */) +{ + if (ipfx1()) { + register streambuf* sb = _strbuf; + if (delim == EOF) { + _gcount = sb->ignore(n); + return *this; + } + _gcount = 0; + for (;;) { +#if 0 + if (n != MAXINT) // FIXME +#endif + if (--n < 0) + break; + int ch = sb->sbumpc(); + if (ch == EOF) { + set(ios::eofbit|ios::failbit); + break; + } + _gcount++; + if (ch == delim) + break; + } + } + return *this; +} + +istream& istream::read(char *s, int n) +{ + if (ipfx1()) { + _gcount = _strbuf->sgetn(s, n); + if (_gcount != 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& istream::scan(const char *format ...) +{ + if (ipfx0()) { + va_list ap; + va_start(ap, format); + _strbuf->vscan(format, ap, this); + va_end(ap); + } + return *this; +} + +istream& istream::vscan(const char *format, _G_va_list args) +{ + if (ipfx0()) + _strbuf->vscan(format, args, this); + return *this; +} + +istream& istream::operator>>(char& c) +{ + if (ipfx0()) { + int ch = _strbuf->sbumpc(); + if (ch == EOF) + set(ios::eofbit|ios::failbit); + else + c = (char)ch; + } + return *this; +} + +istream& istream::operator>>(char* ptr) +{ + register char *p = ptr; + int w = width(0); + if (ipfx0()) { + register streambuf* sb = _strbuf; + for (;;) + { + int ch = sb->sbumpc(); + if (ch == EOF) + { + set(p == ptr ? (ios::eofbit|ios::failbit) : (ios::eofbit)); + break; + } + else if (isspace(ch)) + { + sb->sputbackc(ch); + break; + } + else if (w == 1) + { + set(ios::failbit); + sb->sputbackc(ch); + break; + } + else *p++ = ch; + w--; + } + } + *p = '\0'; + return *this; +} + +#ifdef __GNUC__ +#define LONGEST long long +#else +#define LONGEST long +#endif + +static int read_int(istream& stream, unsigned LONGEST& 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::basefield)) { + if (ch == '0') { + ch = sb->sbumpc(); + if (ch == EOF) { + 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::basefield) == ios::hex) + base = 16; + else if ((stream.flags() & ios::basefield) == ios::oct) + base = 8; + val = 0; + for (;;) { + if (ch == EOF) + 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) { + sb->sputbackc(ch); + if (ndigits == 0) + goto fail; + else + 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& istream::operator>>(TYPE& i)\ +{\ + unsigned LONGEST val; int neg;\ + if (read_int(*this, val, neg)) {\ + if (neg) val = -val;\ + i = (TYPE)val;\ + }\ + return *this;\ +} + +READ_INT(short) +READ_INT(unsigned short) +READ_INT(int) +READ_INT(unsigned int) +READ_INT(long) +READ_INT(unsigned long) +#ifdef __GNUG__ +READ_INT(long long) +READ_INT(unsigned long long) +#endif + +istream& istream::operator>>(double& x) +{ + if (ipfx0()) + scan("%lg", &x); + return *this; +} + +istream& istream::operator>>(float& x) +{ + if (ipfx0()) + scan("%g", &x); + return *this; +} + +istream& istream::operator>>(register streambuf* sbuf) +{ + if (ipfx0()) { + register streambuf* inbuf = rdbuf(); + // FIXME: Should optimize! + for (;;) { + register int ch = inbuf->sbumpc(); + if (ch == EOF) { + set(ios::eofbit); + break; + } + if (sbuf->sputc(ch) == EOF) { + set(ios::failbit); + break; + } + } + } + return *this; +} + +ostream& ostream::operator<<(char c) +{ + if (opfx()) { +#if 1 + // This is what the cfront implementation does. + _strbuf->sputc(c); +#else + // This is what cfront documentation and current ANSI drafts say. + int w = width(0); + char fill_char = fill(); + 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); + sb->sputc(c); + if (flags() & ios::left) // Left adjustment. + while (--padding >= 0) sb->sputc(fill_char); +#endif + osfx(); + } + return *this; +} + +/* Write VAL on STREAM. + 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. + char *show_base = ""; + int show_base_len = 0; + 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 + do { + *--buf_ptr = (val & 7) + '0'; + val = val >> 3; + } while (val != 0); + if ((stream.flags() & ios::showbase) && (val != 0)) + *--buf_ptr = '0'; + } + else if ((stream.flags() & ios::basefield) == ios::hex) { // Hex + char *xdigs = (stream.flags() & ios::uppercase) ? "0123456789ABCDEF0X" + : "0123456789abcdef0x"; + do { + *--buf_ptr = xdigs[val & 15]; + val = val >> 4; + } while (val != 0); + if ((stream.flags() & ios::showbase) && (val != 0)) { + show_base = xdigs + 16; // Either "0X" or "0x". + show_base_len = 2; + } + } + else { // Decimal +#ifdef __GNUC__ + // Optimization: Only use long long when we need to. + while (val > UINT_MAX) { + *--buf_ptr = (val % 10) + '0'; + val /= 10; + } + // Use more efficient (int) arithmetic for the rest. + register unsigned int ival = (unsigned int)val; +#else + register unsigned LONGEST ival = val; +#endif + do { + *--buf_ptr = (ival % 10) + '0'; + ival /= 10; + } while (ival != 0); + if (sign > 0 && (stream.flags() & ios::showpos)) + show_pos=1; + } + + int buf_len = buf+WRITE_BUF_SIZE - buf_ptr; + int w = stream.width(0); + + // Calculate padding. + int len = buf_len+show_pos; + if (sign < 0) len++; + len += show_base_len; + int padding = len > w ? 0 : w - len; + + // Do actual output. + register streambuf* sbuf = stream.rdbuf(); + ios::fmtflags pad_kind = + stream.flags() & (ios::left|ios::right|ios::internal); + char fill_char = stream.fill(); + if (padding > 0 + && 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('+'); + if (show_base_len) + 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); + stream.osfx(); +} + +ostream& ostream::operator<<(int n) +{ + if (opfx()) { + int sign = 1; + if (n < 0 && (flags() & (ios::oct|ios::hex)) == 0) + n = -n, sign = -1; + write_int(*this, n, sign); + } + return *this; +} + +ostream& ostream::operator<<(unsigned int n) +{ + if (opfx()) + write_int(*this, n, 0); + return *this; +} + + +ostream& ostream::operator<<(long n) +{ + if (opfx()) { + int sign = 1; + if (n < 0 && (flags() & (ios::oct|ios::hex)) == 0) + n = -n, sign = -1; + write_int(*this, n, sign); + } + return *this; +} + +ostream& ostream::operator<<(unsigned long n) +{ + if (opfx()) + write_int(*this, n, 0); + return *this; +} + +#ifdef __GNUG__ +ostream& ostream::operator<<(long long n) +{ + if (opfx()) { + int sign = 1; + if (n < 0 && (flags() & (ios::oct|ios::hex)) == 0) + n = -n, sign = -1; + write_int(*this, n, sign); + } + return *this; +} + + +ostream& ostream::operator<<(unsigned long long n) +{ + if (opfx()) + write_int(*this, n, 0); + return *this; +} +#endif /*__GNUG__*/ + +ostream& ostream::operator<<(double n) +{ + if (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). + int format_char; +#if 0 + if (flags() ios::showpos) sign = '+'; +#endif + if ((flags() & ios::floatfield) == ios::fixed) + format_char = 'f'; + else if ((flags() & ios::floatfield) == ios::scientific) + format_char = flags() & ios::uppercase ? 'E' : 'e'; + else + format_char = flags() & ios::uppercase ? 'G' : 'g'; + + int fpprec = 0; // 'Extra' (suppressed) floating precision. + int prec = precision(); + if (prec > MAXFRACT) { + if (flags() & (ios::fixed|ios::scientific) & ios::showpos) + fpprec = prec - MAXFRACT; + prec = MAXFRACT; + } + else if (prec <= 0 && !(flags() & ios::fixed)) + prec = 6; /* default */ + + // Do actual conversion. +#ifdef USE_DTOA + if (__outfloat(n, rdbuf(), format_char, width(0), + prec, flags(), 0, fill()) < 0) + set(ios::badbit|ios::failbit); // ?? +#else + int negative; + char buf[BUF]; + int sign = '\0'; + char *cp = buf; + *cp = 0; + int size = __cvt_double(n, prec, + 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 = width(0); + if (fieldsize < w) + padding = w - fieldsize; + + // Do actual output. + register streambuf* sbuf = rdbuf(); + register i; + char fill_char = fill(); + ios::fmtflags pad_kind = + 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 (sign) + sbuf->sputc(sign); + 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. + sbuf->sputn(cp, size); + 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); +#endif + osfx(); + } + return *this; +} + +ostream& ostream::operator<<(const char *s) +{ + if (opfx()) { + if (s == NULL) + s = "(null)"; + int len = strlen(s); + int w = width(0); + char fill_char = fill(); + 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); + sbuf->sputn(s, len); + if (flags() & ios::left) // Left adjustment. + while (--padding >= 0) sbuf->sputc(fill_char); + osfx(); + } + return *this; +} + +ostream& ostream::operator<<(const void *p) +{ + if (opfx()) { + form("%p", p); + osfx(); + } + return *this; +} + +ostream& ostream::operator<<(register streambuf* sbuf) +{ + if (opfx()) { + register streambuf* outbuf = rdbuf(); + // FIXME: Should optimize! + for (;;) { + register int ch = sbuf->sbumpc(); + if (ch == EOF) break; + if (outbuf->sputc(ch) == EOF) { + set(ios::badbit); + break; + } + } + osfx(); + } + return *this; +} + +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)) + 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 ...) +{ + if (opfx()) { + va_list ap; + va_start(ap, format); + _strbuf->vform(format, ap); + va_end(ap); + } + return *this; +} + +ostream& ostream::vform(const char *format, _G_va_list args) +{ + if (opfx()) + _strbuf->vform(format, args); + return *this; +} + +ostream& ostream::flush() +{ + if (_strbuf->sync()) + set(ios::badbit); + return *this; +} + +ostream& flush(ostream& outs) +{ + return outs.flush(); +} + +istream& ws(istream& ins) +{ + if (ins.ipfx1()) { + int ch = skip_ws(ins._strbuf); + if (ch == EOF) + ins.set(ios::eofbit); + else + ins._strbuf->sputbackc(ch); + } + return ins; +} + +// 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 istream::_skip_ws() +{ + int ch = skip_ws(_strbuf); + if (ch == EOF) { + set(ios::eofbit|ios::failbit); + return 0; + } + else { + _strbuf->sputbackc(ch); + return 1; + } +} + +ostream& ends(ostream& outs) +{ + outs.put('\0'); + return outs; +} + +ostream& endl(ostream& outs) +{ + return flush(outs.put('\n')); +} + +ostream& ostream::write(const char *s, int 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); + } +} + +iostream::iostream(streambuf* sb, ostream* tied) : ios(sb, tied) +{ + _flags |= ios::dont_close; + _gcount = 0; +} + +// 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 != NULL) + _strbuf->sync(); + _flags |= ios::dont_close; + _strbuf = NULL; + _state = badbit; +} + +int istream::skip(int i) +{ + int old = (_flags & ios::skipws) != 0; + if (i) + _flags |= ios::skipws; + else + _flags &= ~ios::skipws; + return old; +} +#endif diff --git a/gnu/lib/libg++/iostream/iostream.h b/gnu/lib/libg++/iostream/iostream.h new file mode 100644 index 00000000000..d6742721524 --- /dev/null +++ b/gnu/lib/libg++/iostream/iostream.h @@ -0,0 +1,228 @@ +// This is part of the iostream library, providing -*- C++ -*- input/output. +// 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. +// +// $Id: iostream.h,v 1.1 1995/10/18 08:38:13 deraadt Exp $ + +#ifndef _IOSTREAM_H +#ifdef __GNUG__ +#pragma interface +#endif +#define _IOSTREAM_H + +#include <streambuf.h> + +class istream; class ostream; +typedef ios& (*__manip)(ios&); +typedef istream& (*__imanip)(istream&); +typedef ostream& (*__omanip)(ostream&); + +extern istream& ws(istream& ins); +extern ostream& flush(ostream& outs); +extern ostream& endl(ostream& outs); +extern ostream& ends(ostream& outs); + +class ostream : virtual public ios +{ + // NOTE: If fields are changed, you must fix _fake_ostream in stdstreams.C! + void do_osfx(); + public: + ostream() { } + ostream(streambuf* sb, ostream* tied=NULL); + int opfx() { + if (!good()) return 0; else { if (_tie) _tie->flush(); return 1;} } + void osfx() { if (flags() & (ios::unitbuf|ios::stdio)) + do_osfx(); } + streambuf* ostreambuf() const { return _strbuf; } + ostream& flush(); + ostream& put(char c) { _strbuf->sputc(c); return *this; } + ostream& put(unsigned char c) { return put((char)c); } + + ostream& write(const char *s, int n); + ostream& write(const unsigned char *s, int n) { return write((const char*)s, n);} +#ifndef _G_BROKEN_SIGNED_CHAR + ostream& put(signed char c) { return put((char)c); } + ostream& write(const signed char *s, int n) { return write((const char*)s, n);} +#endif + ostream& write(const void *s, int n) { return write((const char*)s, n);} + ostream& seekp(streampos); + ostream& seekp(streamoff, _seek_dir); + streampos tellp(); + ostream& form(const char *format ...); + ostream& vform(const char *format, _G_va_list args); + + ostream& operator<<(char c); + ostream& operator<<(unsigned char c) { return (*this) << (char)c; } +#ifndef _G_BROKEN_SIGNED_CHAR + ostream& operator<<(signed char c) { return (*this) << (char)c; } +#endif + ostream& operator<<(const char *s); + ostream& operator<<(const unsigned char *s) + { return (*this) << (const char*)s; } +#ifndef _G_BROKEN_SIGNED_CHAR + ostream& operator<<(const signed char *s) + { return (*this) << (const char*)s; } +#endif + ostream& operator<<(const void *p); + ostream& operator<<(int n); + ostream& operator<<(unsigned int n); + ostream& operator<<(long n); + ostream& operator<<(unsigned long n); +#ifdef __GNUG__ + ostream& operator<<(long long n); + ostream& operator<<(unsigned long long n); +#endif + ostream& operator<<(short n) {return operator<<((int)n);} + ostream& operator<<(unsigned short n) {return operator<<((unsigned int)n);} + ostream& operator<<(double n); + ostream& operator<<(float n) { return operator<<((double)n); } + ostream& operator<<(__omanip func) { return (*func)(*this); } + ostream& operator<<(__manip func) {(*func)(*this); return *this;} + ostream& operator<<(streambuf*); +}; + +class istream : virtual public ios +{ + // NOTE: If fields are changed, you must fix _fake_istream in stdstreams.C! + _G_ssize_t _gcount; + + int _skip_ws(); + public: + istream() { _gcount = 0; } + istream(streambuf* sb, ostream*tied=NULL); + streambuf* istreambuf() const { return _strbuf; } + istream& get(char* ptr, int len, char delim = '\n'); + istream& get(unsigned char* ptr, int len, char delim = '\n') + { return get((char*)ptr, len, delim); } + istream& get(char& c); + istream& get(unsigned char& c) { return get((char&)c); } + istream& getline(char* ptr, int len, char delim = '\n'); + istream& getline(unsigned char* ptr, int len, char delim = '\n') + { return getline((char*)ptr, len, delim); } +#ifndef _G_BROKEN_SIGNED_CHAR + istream& get(signed char& c) { return get((char&)c); } + istream& get(signed char* ptr, int len, char delim = '\n') + { return get((char*)ptr, len, delim); } + istream& getline(signed char* ptr, int len, char delim = '\n') + { return getline((char*)ptr, len, delim); } +#endif + istream& read(char *ptr, int n); + istream& read(unsigned char *ptr, int n) { return read((char*)ptr, n); } +#ifndef _G_BROKEN_SIGNED_CHAR + istream& read(signed char *ptr, int n) { return read((char*)ptr, n); } +#endif + istream& read(void *ptr, int n) { return read((char*)ptr, n); } + istream& get(streambuf& sb, char delim = '\n'); + istream& gets(char **s, char delim = '\n'); + int ipfx(int need) { + if (!good()) { set(ios::failbit); return 0; } + else { + if (_tie && (need == 0 || rdbuf()->in_avail() < need)) _tie->flush(); + if (!need && (flags() & ios::skipws)) return _skip_ws(); + else return 1; + } + } + int ipfx0() { // Optimized version of ipfx(0). + if (!good()) { set(ios::failbit); return 0; } + else { + if (_tie) _tie->flush(); + if (flags() & ios::skipws) return _skip_ws(); + else return 1; + } + } + int ipfx1() { // Optimized version of ipfx(1). + if (!good()) { set(ios::failbit); return 0; } + else { + if (_tie && rdbuf()->in_avail() == 0) _tie->flush(); + return 1; + } + } + void isfx() { } + int get() { if (!ipfx1()) return EOF; + else { int ch = _strbuf->sbumpc(); + if (ch == EOF) set(ios::eofbit); + return ch; + } } + int peek(); + _G_ssize_t gcount() { return _gcount; } + istream& ignore(int n=1, int delim = EOF); + istream& seekg(streampos); + istream& seekg(streamoff, _seek_dir); + streampos tellg(); + istream& putback(char ch) { + if (good() && _strbuf->sputbackc(ch) == EOF) clear(ios::badbit); + return *this;} + istream& unget() { + if (good() && _strbuf->sungetc() == EOF) clear(ios::badbit); + return *this;} + istream& scan(const char *format ...); + istream& vscan(const char *format, _G_va_list args); +#ifdef _STREAM_COMPAT + istream& unget(char ch) { return putback(ch); } + int skip(int i); +#endif + + istream& operator>>(char*); + istream& operator>>(unsigned char* p) { return operator>>((char*)p); } +#ifndef _G_BROKEN_SIGNED_CHAR + istream& operator>>(signed char*p) { return operator>>((char*)p); } +#endif + istream& operator>>(char& c); + istream& operator>>(unsigned char& c) {return operator>>((char&)c);} +#ifndef _G_BROKEN_SIGNED_CHAR + istream& operator>>(signed char& c) {return operator>>((char&)c);} +#endif + istream& operator>>(int&); + istream& operator>>(long&); +#ifdef __GNUG__ + istream& operator>>(long long&); +#endif + istream& operator>>(short&); + istream& operator>>(unsigned int&); + istream& operator>>(unsigned long&); +#ifdef __GNUG__ + istream& operator>>(unsigned long long&); +#endif + istream& operator>>(unsigned short&); + istream& operator>>(float&); + istream& operator>>(double&); + istream& operator>>( __manip func) {(*func)(*this); return *this;} + istream& operator>>(__imanip func) { return (*func)(*this); } + istream& operator>>(streambuf*); +}; + + +class iostream : public istream, public ostream +{ + _G_ssize_t _gcount; + public: + iostream() { _gcount = 0; } + iostream(streambuf* sb, ostream*tied=NULL); +}; + +extern istream cin; +extern ostream cout, cerr, clog; // clog->rdbuf() == cerr->rdbuf() + +struct Iostream_init { } ; // Compatibility hack for AT&T library. + +inline ios& dec(ios& i) +{ i.setf(ios::dec, ios::dec|ios::hex|ios::oct); return i; } +inline ios& hex(ios& i) +{ i.setf(ios::hex, ios::dec|ios::hex|ios::oct); return i; } +inline ios& oct(ios& i) +{ i.setf(ios::oct, ios::dec|ios::hex|ios::oct); return i; } + +#endif /*!_IOSTREAM_H*/ diff --git a/gnu/lib/libg++/iostream/makebuf.C b/gnu/lib/libg++/iostream/makebuf.C new file mode 100644 index 00000000000..592f59ec396 --- /dev/null +++ b/gnu/lib/libg++/iostream/makebuf.C @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +// Modified for GNU iostream by Per Bothner 1991. + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "%W% (Berkeley) %G%"; +#endif /* LIBC_SCCS and not lint */ + +#include "ioprivate.h" +#include "fstream.h" +#include <sys/types.h> +#include <sys/stat.h> + +/* + * Allocate a file buffer, or switch to unbuffered I/O. + * Per the ANSI C standard, ALL tty devices default to line buffered. + * + * As a side effect, we set __SOPT or __SNPT (en/dis-able fseek + * optimisation) right after the _fstat() that finds the buffer size. + */ +int filebuf::doallocate() +{ + register size_t size, couldbetty; + register char *p; + struct stat st; + + if (fd() < 0 || _fstat(fd(), &st) < 0) { + couldbetty = 0; + size = _G_BUFSIZ; +#if 0 + /* do not try to optimise fseek() */ + fp->_flags |= __SNPT; +#endif + } else { + couldbetty = S_ISCHR(st.st_mode); +#if _G_HAVE_ST_BLKSIZE + size = st.st_blksize <= 0 ? _G_BUFSIZ : st.st_blksize; +#else + size = _G_BUFSIZ; +#endif + } +#ifdef USE_MALLOC_BUF + if ((p = malloc(size)) == NULL) { + unbuffered(1); +// fp->_bf._base = fp->_p = fp->_nbuf; +// fp->_bf._size = 1; + return EOF; + } +#else + p = ALLOC_BUF(size); +#endif + setb(p, p+size, 1); + if (couldbetty && _isatty(fd())) + _flags |= _S_LINE_BUF; + return 1; +} diff --git a/gnu/lib/libg++/iostream/outfloat.C b/gnu/lib/libg++/iostream/outfloat.C new file mode 100644 index 00000000000..c677844b839 --- /dev/null +++ b/gnu/lib/libg++/iostream/outfloat.C @@ -0,0 +1,183 @@ +// This is part of the iostream library, providing input/output for C++. +// Copyright (C) 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 "ioprivate.h" + +// Format floating-point number and print them. +// Return number of chars printed, or EOF on error. + +// sign_mode == '+' : print "-" or "+" +// sign_mode == ' ' : print "-" or " " +// sign_mode == '\0' : print "-' or "" + +int __outfloat(double value, streambuf *sb, char type, + int width, int precision, ios::fmtflags flags, + char sign_mode, char fill) +{ + int count = 0; +#define PUT(x) do {if (sb->sputc(x) < 0) goto error; count++;} while (0) +#define PUTN(p, n) \ + do {int _n=n; count+=_n; if (sb->sputn(p,_n) != _n) goto error;} while(0) +#define PADN(fill, n) \ + do {int _n = n; count+=_n; if (sb->padn(fill, _n) < 0) goto error;} while (0) + ios::fmtflags pad_kind = flags & (ios::left|ios::right|ios::internal); + int skip_zeroes = 0; + int show_dot = (flags & ios::showpoint) != 0; + int decpt; + int sign; + int mode; +#define EBUF_SIZE 12 +#define EBUF_END &ebuf[EBUF_SIZE] + char ebuf[EBUF_SIZE]; + char *end; + int exp = 0; + switch (type) { + case 'f': + mode = 3; + break; + case 'e': + case 'E': + exp = type; + mode = 2; + if (precision != 999) + precision++; // Add one to include digit before decimal point. + break; + case 'g': + case 'G': + exp = type == 'g' ? 'e' : 'E'; + if (precision == 0) precision = 1; + if (!(flags & ios::showpoint)) + skip_zeroes = 1; + type = 'g'; + mode = 2; + break; + } + /* Do the actual convension */ + if (precision == 999 && mode != 3) + mode = 0; + char *p = dtoa(value, mode, precision, &decpt, &sign, &end); + register int i; + int useful_digits = end-p; + char *exponent_start = EBUF_END; + if (mode == 0) + precision = useful_digits; + // Check if we need to emit an exponent. + if (mode != 3 && decpt != 9999) { + i = decpt - 1; + if ((type != 'g' && type != 'F') || i < -4 || i >= precision) { + // Print the exponent into ebuf. + // We write ebuf in reverse order (right-to-left). + char sign; + if (i >= 0) + sign = '+'; + else + sign = '-', i = -i; + /* Note: ANSI requires at least 2 exponent digits. */ + do { + *--exponent_start = (i % 10) + '0'; + i /= 10; + } while (i >= 10); + *--exponent_start = i + '0'; + *--exponent_start = sign; + *--exponent_start = exp; + } + } + int exponent_size = EBUF_END - exponent_start; + if (mode == 1) + precision = 1; + /* If we print an exponent, always show just one digit before point. */ + if (exponent_size) + decpt = 1; + if (decpt == 9999) { // Infinity or NaN + decpt = useful_digits; + precision = 0; + show_dot = 0; + } + + // dtoa truncates trailing zeroes. Set the variable trailing_zeroes to + // the number of 0's we have to add (after the decimal point). + int trailing_zeroes = 0; + if (skip_zeroes) + trailing_zeroes = 0; + else if (type == 'f') + trailing_zeroes = useful_digits <= decpt ? precision + : precision-(useful_digits-decpt); + else if (exponent_size) // 'e' 'E' or 'g' format using exponential notation. + trailing_zeroes = precision - useful_digits; + else // 'g' format not using exponential notation. + trailing_zeroes = useful_digits <= decpt ? precision - decpt + : precision-useful_digits; + if (trailing_zeroes < 0) trailing_zeroes = 0; + + if (trailing_zeroes != 0 || useful_digits > decpt) + show_dot = 1; + int print_sign; + if (sign_mode == 0) + print_sign = sign ? '-' : 0; + else if (sign_mode == '+') + print_sign = sign ? '-' : '+'; + else /* if (sign_mode == ' ') */ + print_sign = sign ? '-' : ' '; + + // Calculate the width (before padding). + int unpadded_width = + (print_sign != 0) + trailing_zeroes + exponent_size + show_dot + + useful_digits + + (decpt > useful_digits ? decpt - useful_digits + : decpt > 0 ? 0 : 1 - decpt); + + int padding = width > unpadded_width ? width - unpadded_width : 0; + if (padding > 0 + && pad_kind != (ios::fmtflags)ios::left + && pad_kind != (ios::fmtflags)ios::internal) // Default (right) adjust. + PADN(fill, padding); + if (print_sign) + PUT(print_sign); + if (pad_kind == (ios::fmtflags)ios::internal && padding > 0) + PADN(fill, padding); + if (decpt > 0) { + if (useful_digits >= decpt) + PUTN(p, decpt); + else { + PUTN(p, useful_digits); + PADN('0', decpt-useful_digits); + } + if (show_dot) { + PUT('.'); + // Print digits after the decimal point. + if (useful_digits > decpt) + PUTN(p + decpt, useful_digits-decpt); + } + } + else { + PUT('0'); + if (show_dot) { + PUT('.'); + PADN('0', -decpt); + // Print digits after the decimal point. + PUTN(p, useful_digits); + } + } + PADN('0', trailing_zeroes); + if (exponent_size) + PUTN(exponent_start, exponent_size); + if (pad_kind == (ios::fmtflags)ios::left && padding > 0) // Left adjustment + PADN(fill, padding); + return count; + error: + return EOF; +} diff --git a/gnu/lib/libg++/iostream/parsestream.C b/gnu/lib/libg++/iostream/parsestream.C new file mode 100644 index 00000000000..49135da7709 --- /dev/null +++ b/gnu/lib/libg++/iostream/parsestream.C @@ -0,0 +1,307 @@ +// 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 +#include "ioprivate.h" +#include "parsestream.h" + +streambuf* parsebuf::setbuf(char*, int) +{ + return NULL; +} + +int parsebuf::tell_in_line() +{ + return 0; +} + +int parsebuf::pbackfail(int c) +{ + if (c == EOF) + return 0; + if (seekoff(-1, ios::cur) == EOF) + return EOF; + return (unsigned char)c; +} + +char* parsebuf::current_line() { return NULL; } + +streampos parsebuf::seekoff(streamoff offset, _seek_dir dir, int) +{ + // Make offset relative to line start. + switch (dir) { + case ios::beg: + offset -= pos_at_line_start; + break; + case ios::cur: + offset += tell_in_line(); + break; + default: + return EOF; + } + if (offset < -1) + return EOF; + if (offset > _line_length + 1) + return EOF; + return seek_in_line(offset) + pos_at_line_start; +} + +// string_parsebuf invariants: +// The reserve ares (base() .. ebuf()) is always the entire string. +// The get area (eback() .. egptr()) is the extended current line +// (i.e. with the '\n' at either end, if these exist). + +string_parsebuf::string_parsebuf(char *buf, int len, + int delete_at_close /* = 0*/) +: parsebuf() +{ + setb(buf, buf+len, delete_at_close); + register char *ptr = buf; + while (ptr < ebuf() && *ptr != '\n') ptr++; + _line_length = ptr - buf; + setg(buf, buf, ptr); +} + +int string_parsebuf::underflow() +{ + register char* ptr = egptr(); // Point to end of current_line + do { + int i = right() - ptr; + if (i <= 0) + return EOF; + ptr++; i--; // Skip '\n'. + char *line_start = ptr; + while (ptr < right() && *ptr == '\n') ptr++; + setg(line_start-1, line_start, ptr + (ptr < right())); + pos_at_line_start = line_start - left(); + _line_length = ptr - line_start; + __line_number++; + } while (gptr() == ptr); + return *gptr(); +} + +char* string_parsebuf::current_line() +{ + char *ptr = eback(); + if (__line_number > 0) + ptr++; // Skip '\n' at end of previous line. + return ptr; +} + +int string_parsebuf::tell_in_line() +{ + int offset = gptr() - eback(); + if (__line_number > 0) + offset--; + return offset; +} + +int string_parsebuf::seek_in_line(int i) +{ + int delta = i - tell_in_line(); + gbump(delta); // FIXME: Needs error (bounds) checking! + return i; +} + +static const char NewLine[1] = { '\n' }; + +general_parsebuf::general_parsebuf(streambuf *buf, int delete_arg_buf) + : parsebuf() +{ + delete_buf = delete_arg_buf; + sbuf = buf; + int buf_size = 128; + char* buffer = ALLOC_BUF(buf_size); + setb(buffer, buffer+buf_size, 1); +// setg(buffer, buffer, buffer); +} + +general_parsebuf::~general_parsebuf() +{ + if (delete_buf) + delete sbuf; +} + +int general_parsebuf::underflow() +{ + register char *ptr = base(); + int has_newline = eback() < gptr() && gptr()[-1] == '\n'; + if (has_newline) + *ptr++ = '\n'; + register streambuf *sb = sbuf; + register int ch; + for (;;) { + ch = sb->sbumpc(); + if (ch == EOF) + break; + if (ptr == ebuf()) { + int old_size = ebuf() - base(); + char *new_buffer = new char[old_size * 2]; + memcpy(new_buffer, base(), old_size); + setb(new_buffer, new_buffer + 2 * old_size, 1); + ptr = new_buffer + old_size; + } + *ptr++ = ch; + if (ch == '\n') + break; + } + char *cur_pos = base() + has_newline; + pos_at_line_start += _line_length + 1; + _line_length = ptr - cur_pos; + if (ch != EOF || _line_length > 0) + __line_number++; + setg(base(), cur_pos, ptr); + return ptr == cur_pos ? EOF : cur_pos[0]; +} + +char* general_parsebuf::current_line() +{ + char* ret = base(); + if (__line_number > 1) + ret++; // Move past '\n' from end of previous line. + return ret; +} + +int general_parsebuf::tell_in_line() +{ + int off = gptr() - base(); + if (__line_number > 1) + off--; // Subtract 1 for '\n' from end of previous line. + return off; +} + +int general_parsebuf::seek_in_line(int i) +{ + if (__line_number == 0) + (void)general_parsebuf::underflow(); + if (__line_number > 1) + i++; // Add 1 for '\n' from end of previous line. + if (i < 0) i = 0; + int len = egptr() - eback(); + if (i > len) i = len; + setg(base(), base() + i, egptr()); + return i; +} + +func_parsebuf::func_parsebuf(CharReader func, void *argm) : parsebuf() +{ + read_func = func; + arg = argm; + buf_start = NULL; + buf_end = NULL; + setb((char*)NewLine, (char*)NewLine+1, 0); + setg((char*)NewLine, (char*)NewLine+1, (char*)NewLine+1); + backed_up_to_newline = 0; +} + +int func_parsebuf::tell_in_line() +{ + if (buf_start == NULL) + return 0; + if (egptr() != (char*)NewLine+1) + // Get buffer was line buffer. + return gptr() - buf_start; + if (backed_up_to_newline) + return -1; // Get buffer is '\n' preceding current line. + // Get buffer is '\n' following current line. + return (buf_end - buf_start) + (gptr() - (char*)NewLine); +} + +char* func_parsebuf::current_line() +{ + return buf_start; +} + +int func_parsebuf::seek_in_line(int i) +{ + if (i < 0) { + // Back up to preceding '\n'. + if (i < -1) i = -1; + backed_up_to_newline = 1; + setg((char*)NewLine, (char*)NewLine+(i+1), (char*)NewLine+1); + return i; + } + backed_up_to_newline = 0; + int line_length = buf_end-buf_start; + if (i <= line_length) { + setg(buf_start, buf_start+i, buf_end); + return i; + } + i -= line_length; + if (i > 0) i = 1; + setg((char*)NewLine, (char*)NewLine+i, (char*)NewLine+1); + return line_length + i; +} + +int func_parsebuf::underflow() +{ + retry: + if (gptr() < egptr()) + return *gptr(); + if (gptr() != (char*)NewLine+1) { + // Get buffer was line buffer. Move to following '\n'. + setg((char*)NewLine, (char*)NewLine, (char*)NewLine+1); + return *gptr(); + } + if (backed_up_to_newline) + // Get buffer was '\n' preceding current line. Move to current line. + backed_up_to_newline = 0; + else { + // Get buffer was '\n' following current line. Read new line. + if (buf_start) free(buf_start); + char *str = (*read_func)(arg); + buf_start = str; + if (str == NULL) + return EOF; + // Initially, _line_length == -1, so pos_at_line_start becomes 0. + pos_at_line_start += _line_length + 1; + _line_length = strlen(str); + buf_end = str + _line_length; + __line_number++; + } + setg(buf_start, buf_start, buf_end); + goto retry; +} + +#if 0 +size_t parsebuf::line_length() +{ + if (current_line_length == (size_t)(-1)) // Initial value; + (void)sgetc(); + return current_line_length; +} +#endif + +int parsebuf::seek_in_line(int i) +{ +#if 1 + abort(); + return 0; // Suppress warning. +#else + if (i > 0) { + size_t len = line_length(); + if ((unsigned)i > len) i = len; + } + else if (i < -1) i = -1; + int new_pos = seekoff(pos_at_line_start + i, ios::beg); + if (new_pos == EOF) + return tell_in_line(); + else return new_pos - pos_at_line_start; +#endif +} diff --git a/gnu/lib/libg++/iostream/parsestream.h b/gnu/lib/libg++/iostream/parsestream.h new file mode 100644 index 00000000000..95c1242928a --- /dev/null +++ b/gnu/lib/libg++/iostream/parsestream.h @@ -0,0 +1,147 @@ +// This is part of the iostream library, providing -*- C++ -*- input/output. +// 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. +// +// $Id: parsestream.h,v 1.1 1995/10/18 08:38:13 deraadt Exp $ + +#ifndef PARSESTREAM_H +#define PARSESTREAM_H +#ifdef __GNUG__ +#pragma interface +#endif +#include "streambuf.h" + +// A parsebuf is a streambuf optimized for scanning text files. +// It keeps track of line and column numbers. +// It is guaranteed to remember the entire current line, +// as well the '\n'-s on either side of it (if they exist). +// You can arbitrarily seek (or unget) within this extended line. +// Other backward seeks are not supported. +// Normal read semantics are supported (and hence istream operators like >>). + +class parsebuf : public backupbuf { + protected: + _G_fpos_t pos_at_line_start; + long _line_length; + unsigned long __line_number; + char *buf_start; + char *buf_end; + + public: + parsebuf *chain; + + // Return column number (raw - don't handle tabs etc). + // Retult can be -1, meaning: at '\n' before current line. + virtual int tell_in_line(); + + // seek to (raw) column I in current line. + // Result is new (raw) column position - differs from I if unable to seek. + // Seek to -1 tries to seek to before previous LF. + virtual int seek_in_line(int i); + + // Note: there is no "current line" initially, until something is read. + + // Current line number, starting with 0. + // If tell_in_line()==-1, then line number of next line. + int line_number() { return __line_number; } + + // Length of current line, not counting either '\n'. + int line_length() { return _line_length; } + // Current line - not a copy, so file ops may trash it. + virtual char* current_line(); + virtual streampos seekoff(streamoff, _seek_dir, int mode=ios::in|ios::out); + virtual streambuf* setbuf(char* p, int len); + protected: + parsebuf() : backupbuf() { chain= NULL; + __line_number = 0; pos_at_line_start = 0; _line_length = -1; } + virtual int pbackfail(int c); +}; + +// A string_parsebuf is a parsebuf whose source is a fixed string. + +class string_parsebuf : public parsebuf { + public: + int do_delete; + string_parsebuf(char *str, int len, int delete_at_close=0); + virtual int underflow(); + virtual char* current_line(); + virtual int seek_in_line(int i); + virtual int tell_in_line(); + char *left() const { return base(); } + char *right() const { return ebuf(); } +// streampos seekoff(streamoff, _seek_dir, int); +}; + +// A func_parsebuf calls a given function to get new input. +// Each call returns an entire NUL-terminated line (without the '\n'). +// That line has been allocated with malloc(), not new. +// The interface is tailored to the GNU readline library. +// Example: +// char* DoReadLine(void* arg) +// { +// char *line = readline((char*)arg); /* 'arg' is used as prompt. */ +// if line == NULL) { putc('\n', stderr); return NULL; } +// if (line[0] != '\0') add_history(line); +// return line; +// } +// char PromptBuffer[100] = "> "; +// func_parsebuf my_stream(DoReadLine, PromptBuffer); + +typedef char *(*CharReader)(void *arg); +class istream; + +class func_parsebuf : public parsebuf { + public: + void *arg; + CharReader read_func; + int backed_up_to_newline; + func_parsebuf(CharReader func, void *argm = NULL); + int underflow(); + virtual int tell_in_line(); + virtual int seek_in_line(int i); + virtual char* current_line(); +}; + +// A general_parsebuf is a parsebuf which gets its input from some +// other streambuf. It explicitly buffers up an entire line. + +class general_parsebuf : public parsebuf { + public: + streambuf *sbuf; + int delete_buf; // Delete sbuf when destroying this. + general_parsebuf(streambuf *buf, int delete_arg_buf = 0); + int underflow(); + virtual int tell_in_line(); + virtual int seek_in_line(int i); + ~general_parsebuf(); + virtual char* current_line(); +}; + +#if 0 +class parsestream : public istream { + streammarker marks[2]; + short _first; // of the two marks; either 0 or 1 + int _lineno; + int first() { return _first; } + int second() { return 1-_first; } + int line_length() { marks[second].delta(marks[first]); } + int line_length() { marks[second].delta(marks[first]); } + int seek_in_line(int i); + int tell_in_line(); + int line_number(); +}; +#endif +#endif /*!defined(PARSESTREAM_H)*/ diff --git a/gnu/lib/libg++/iostream/procbuf.C b/gnu/lib/libg++/iostream/procbuf.C new file mode 100644 index 00000000000..842cd3c41e2 --- /dev/null +++ b/gnu/lib/libg++/iostream/procbuf.C @@ -0,0 +1,126 @@ +// This is part of the iostream library, providing input/output for C++. +// Copyright (C) 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. + +#define _POSIX_SOURCE +#include "ioprivate.h" +#include "procbuf.h" +#include <signal.h> +#include <unistd.h> +#include <sys/wait.h> + + +#ifndef FORK +#define FORK vfork +#ifndef __NetBSD__ +extern "C" _G_pid_t vfork(void); +#else +extern "C" int vfork(void); +#endif +#endif + +procbuf::procbuf(const char *command, int mode) : filebuf() +{ + open(command, mode); +} + +procbuf *procbuf::open(const char *command, int mode) +{ + int read_or_write; + if (is_open()) + return NULL; + int pipe_fds[2]; + int parent_end, child_end; + if (::pipe(pipe_fds) < 0) + return NULL; + if (mode == ios::in) { + parent_end = pipe_fds[0]; + child_end = pipe_fds[1]; + read_or_write = _S_NO_WRITES; + } + else { + parent_end = pipe_fds[1]; + child_end = pipe_fds[0]; + read_or_write = _S_NO_READS; + } + _pid = FORK(); + if (_pid == 0) { + ::close(parent_end); + int child_std_end = mode == ios::in ? 1 : 0; + if (child_end != child_std_end) { + ::dup2(child_end, child_std_end); + ::close(child_end); + } + ::execl("/bin/sh", "sh", "-c", command, NULL); + ::_exit(127); + } + ::close(child_end); + if (_pid < 0) { + ::close(parent_end); + return NULL; + } + _fb._fileno = parent_end; + xsetflags(read_or_write, _S_NO_READS|_S_NO_WRITES); + return this; +} + +/* #define USE_SIGMASK */ + +int procbuf::sys_close() +{ + _G_pid_t wait_pid; + int status = filebuf::sys_close(); + if (status < 0) + return status; + int wstatus; +#if defined(SIG_BLOCK) && defined(SIG_SETMASK) + sigset_t set, oset; + sigemptyset (&set); + sigaddset (&set, SIGINT); + sigaddset (&set, SIGQUIT); + sigaddset (&set, SIGHUP); + sigprocmask (SIG_BLOCK, &set, &oset); +#else +#ifdef USE_SIGMASK + int mask = sigblock(sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGHUP)); +#else + typedef void (*void_func)(int); + void_func intsave = (void_func)signal(SIGINT, SIG_IGN); + void_func quitsave = (void_func)signal(SIGQUIT, SIG_IGN); + void_func hupsave = (void_func)signal(SIGHUP, SIG_IGN); +#endif +#endif + while ((wait_pid = wait(&wstatus)) != _pid && wait_pid != -1) { } +#if defined(SIG_BLOCK) && defined(SIG_SETMASK) + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); +#else +#ifdef USE_SIGMASK + (void) sigsetmask(mask); +#else + signal(SIGINT, intsave); + signal(SIGQUIT, quitsave); + signal(SIGHUP, hupsave); +#endif +#endif + if (wait_pid == -1) + return -1; + return 0; +} + +procbuf::~procbuf() +{ + close(); +} diff --git a/gnu/lib/libg++/iostream/procbuf.h b/gnu/lib/libg++/iostream/procbuf.h new file mode 100644 index 00000000000..1100fcfc792 --- /dev/null +++ b/gnu/lib/libg++/iostream/procbuf.h @@ -0,0 +1,31 @@ +// This is part of the iostream library, providing input/output for C++. +// Copyright (C) 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. +// +// $Id: procbuf.h,v 1.1 1995/10/18 08:38:13 deraadt Exp $ + +#include <streambuf.h> + +class procbuf : public filebuf { + _G_pid_t _pid; + public: + procbuf() : filebuf() { } + procbuf(const char *command, int mode); + procbuf* open(const char *command, int mode); + procbuf *close() { return (procbuf*)filebuf::close(); } + virtual int sys_close(); + ~procbuf(); +}; diff --git a/gnu/lib/libg++/iostream/sbufvform.C b/gnu/lib/libg++/iostream/sbufvform.C new file mode 100644 index 00000000000..533fd719d09 --- /dev/null +++ b/gnu/lib/libg++/iostream/sbufvform.C @@ -0,0 +1,856 @@ +/* + * Copyright (c) 1990 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "%W% (Berkeley) %G%"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Actual printf innards. + * + * This code is large and complicated... + */ + +#include <sys/types.h> +#include "ioprivate.h" +#include <string.h> +#include <stdarg.h> + +/* + * Define FLOATING_POINT to get floating point. + */ +#ifndef NO_FLOATING_POINT +#define FLOATING_POINT +#endif + +/* end of configuration stuff */ + + +/* + * Helper class and function for `fprintf to unbuffered': creates a + * temporary buffer. We only work on write-only files; this avoids + * worries about ungetc buffers and so forth. + */ + +class help_streambuf : public backupbuf { + public: + char *buffer; + int buf_size; + streambuf *sb; + help_streambuf(streambuf *sbuf, char *buf, int n) { + sb = sbuf; buffer = buf; buf_size = n; + setp(buffer, buffer+buf_size); } + ~help_streambuf(); + virtual int overflow(int c = EOF); +}; + +int help_streambuf::overflow(int c) +{ + int used = pptr() - pbase(); + if (used) { + sb->sputn(pbase(), used); + pbump(-used); + } + if (c == EOF || buf_size == 0) + return sb->overflow(c); + return sputc(c); +} +help_streambuf::~help_streambuf() +{ + int used = pptr() - pbase(); + if (used) { + sb->sputn(pbase(), used); + pbump(-used); + } +} + +int help_vform(streambuf *sb, char const *fmt0, va_list ap) +{ + char buf[_G_BUFSIZ]; + help_streambuf helper(sb, buf, _G_BUFSIZ); + return helper.vform(fmt0, ap); +} + +#ifdef FLOATING_POINT + +#include "floatio.h" +#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ +#define DEFPREC 6 +extern "C" double modf(double, double*); + +#else /* no FLOATING_POINT */ + +#define BUF 40 + +#endif /* FLOATING_POINT */ + + +/* + * Macros for converting digits to letters and vice versa + */ +#define to_digit(c) ((c) - '0') +#define is_digit(c) ((unsigned)to_digit(c) <= 9) +#define to_char(n) ((n) + '0') + +/* + * Flags used during conversion. + */ +#define LONGINT 0x01 /* long integer */ +#define LONGDBL 0x02 /* long double; unimplemented */ +#define SHORTINT 0x04 /* short integer */ +#define ALT 0x08 /* alternate form */ +#define LADJUST 0x10 /* left adjustment */ +#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ +#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ + +int streambuf::vform(char const *fmt0, _G_va_list ap) +{ + register const char *fmt; /* format string */ + register int ch; /* character from fmt */ + register int n; /* handy integer (short term usage) */ + register char *cp; /* handy char pointer (short term usage) */ + const char *fmark; /* for remembering a place in fmt */ + register int flags; /* flags as above */ + int ret; /* return value accumulator */ + int width; /* width from format (%8d), or 0 */ + int prec; /* precision from format (%.3d), or -1 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ +#ifdef FLOATING_POINT + int softsign; /* temporary negative sign for floats */ + double _double; /* double precision arguments %[eEfgG] */ +#ifndef USE_DTOA + int fpprec; /* `extra' floating precision in [eEfgG] */ +#endif +#endif + unsigned long _ulong; /* integer arguments %[diouxX] */ + enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ + int dprec; /* a copy of prec if [diouxX], 0 otherwise */ + int dpad; /* extra 0 padding needed for integers */ + int fieldsz; /* field size expanded by sign, dpad etc */ + // The initialization of 'size' is to suppress a warning that + // 'size' might be used unitialized. It seems gcc can't + // quite grok this spaghetti code ... + int size = 0; /* size of converted field or string */ + char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ + char ox[2]; /* space for 0x hex-prefix */ + + /* + * Choose PADSIZE to trade efficiency vs size. If larger + * printf fields occur frequently, increase PADSIZE (and make + * the initialisers below longer). + */ +#define PADSIZE 16 /* pad chunk size */ + static char const blanks[PADSIZE] = + {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; + static char const zeroes[PADSIZE] = + {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; + + /* + * BEWARE, these `goto error' on error, and PAD uses `n'. + */ +#define PRINT(ptr, len) \ + do { if (sputn(ptr, len) != len) goto error; } while (0) +#if 1 +#define PAD_SP(howmany) if (padn(' ', howmany) < 0) goto error; +#define PAD_0(howmany) if (padn('0', howmany) < 0) goto error; +#else +#define PAD(howmany, with) { \ + if ((n = (howmany)) > 0) { \ + while (n > PADSIZE) { \ + PRINT(with, PADSIZE); \ + n -= PADSIZE; \ + } \ + PRINT(with, n); \ + } \ +} +#define PAD_SP(howmany) PAD(howmany, blanks) +#define PAD_0(howmany) PAD(howmany, zeroes) +#endif + + /* + * To extend shorts properly, we need both signed and unsigned + * argument extraction methods. + */ +#define SARG() \ + (flags&LONGINT ? va_arg(ap, long) : \ + flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ + (long)va_arg(ap, int)) +#define UARG() \ + (flags&LONGINT ? va_arg(ap, unsigned long) : \ + flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \ + (unsigned long)va_arg(ap, unsigned int)) + + /* optimise cerr (and other unbuffered Unix files) */ + if (unbuffered()) + return help_vform(this, fmt0, ap); + + fmt = fmt0; + ret = 0; + + /* + * Scan the format for conversions (`%' character). + */ + for (;;) { + for (fmark = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) + /* void */; + if ((n = fmt - fmark) != 0) { + PRINT(fmark, n); + ret += n; + } + if (ch == '\0') + goto done; + fmt++; /* skip over '%' */ + + flags = 0; + dprec = 0; +#if defined(FLOATING_POINT) && !defined (USE_DTOA) + fpprec = 0; +#endif + width = 0; + prec = -1; + sign = '\0'; + +rflag: ch = *fmt++; +reswitch: switch (ch) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = va_arg(ap, int)) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + flags &= ~ZEROPAD; /* '-' disables '0' */ + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if ((ch = *fmt++) == '*') { + n = va_arg(ap, int); + prec = n < 0 ? -1 : n; + goto rflag; + } + n = 0; + while (is_digit(ch)) { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } + prec = n < 0 ? -1 : n; + goto reswitch; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + if (!(flags & LADJUST)) + flags |= ZEROPAD; /* '-' disables '0' */ + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } while (is_digit(ch)); + width = n; + goto reswitch; +#ifdef FLOATING_POINT + case 'L': + flags |= LONGDBL; + goto rflag; +#endif + case 'h': + flags |= SHORTINT; + goto rflag; + case 'l': + flags |= LONGINT; + goto rflag; + case 'c': + *(cp = buf) = va_arg(ap, int); + size = 1; + sign = '\0'; + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + _ulong = SARG(); + if ((long)_ulong < 0) { + _ulong = -_ulong; + sign = '-'; + } + base = DEC; + goto number; +#ifdef FLOATING_POINT + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + _double = va_arg(ap, double); +#ifdef USE_DTOA + { + ios::fmtflags fmt_flags = 0; + int fill = ' '; + if (flags & ALT) + fmt_flags |= ios::showpoint; + if (flags & LADJUST) + fmt_flags |= ios::left; + else if (flags & ZEROPAD) + fmt_flags |= ios::internal, fill = '0'; + n = __outfloat(_double, this, ch, width, + prec < 0 ? DEFPREC : prec, + fmt_flags, sign, fill); + if (n < 0) + goto error; + ret += n; + } + // CHECK ERROR! + continue; +#else + /* + * don't do unrealistic precision; just pad it with + * zeroes later, so buffer size stays rational. + */ + if (prec > MAXFRACT) { + if ((ch != 'g' && ch != 'G') || (flags&ALT)) + fpprec = prec - MAXFRACT; + prec = MAXFRACT; + } else if (prec == -1) + prec = DEFPREC; + // __cvt_double may have to round up before the + // "start" of its buffer, i.e. + // ``intf("%.2f", (double)9.999);''; + // if the first character is still NUL, it did. + // softsign avoids negative 0 if _double < 0 but + // no significant digits will be shown. + cp = buf; + *cp = '\0'; + size = __cvt_double(_double, prec, flags, &softsign, + ch, cp, buf + sizeof(buf)); + if (softsign) + sign = '-'; + if (*cp == '\0') + cp++; + break; +#endif +#endif /* FLOATING_POINT */ + case 'n': + if (flags & LONGINT) + *va_arg(ap, long *) = ret; + else if (flags & SHORTINT) + *va_arg(ap, short *) = ret; + else + *va_arg(ap, int *) = ret; + continue; /* no output */ + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + _ulong = UARG(); + base = OCT; + goto nosign; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + /* NOSTRICT */ + _ulong = (unsigned long)va_arg(ap, void *); + base = HEX; + flags |= HEXPREFIX; + ch = 'x'; + goto nosign; + case 's': + if ((cp = va_arg(ap, char *)) == NULL) + cp = "(null)"; + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p = (char*)memchr(cp, 0, prec); + + if (p != NULL) { + size = p - cp; + if (size > prec) + size = prec; + } else + size = prec; + } else + size = strlen(cp); + sign = '\0'; + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + _ulong = UARG(); + base = DEC; + goto nosign; + case 'X': + case 'x': + _ulong = UARG(); + base = HEX; + /* leading 0x/X only if non-zero */ + if (flags & ALT && _ulong != 0) + flags |= HEXPREFIX; + + /* unsigned conversions */ +nosign: sign = '\0'; + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + cp = buf + BUF; + if (_ulong != 0 || prec != 0) { + char *xdigs; /* digits for [xX] conversion */ + /* + * unsigned mod is hard, and unsigned mod + * by a constant is easier than that by + * a variable; hence this switch. + */ + switch (base) { + case OCT: + do { + *--cp = to_char(_ulong & 7); + _ulong >>= 3; + } while (_ulong); + /* handle octal leading 0 */ + if (flags & ALT && *cp != '0') + *--cp = '0'; + break; + + case DEC: + /* many numbers are 1 digit */ + while (_ulong >= 10) { + *--cp = to_char(_ulong % 10); + _ulong /= 10; + } + *--cp = to_char(_ulong); + break; + + case HEX: + if (ch == 'X') + xdigs = "0123456789ABCDEF"; + else /* ch == 'x' || ch == 'p' */ + xdigs = "0123456789abcdef"; + do { + *--cp = xdigs[_ulong & 15]; + _ulong >>= 4; + } while (_ulong); + break; + + default: + cp = "bug in vform: bad base"; + goto skipsize; + } + } + size = buf + BUF - cp; + skipsize: + break; + default: /* "%?" prints ?, unless ? is NUL */ + if (ch == '\0') + goto done; + /* pretend it was %c with argument ch */ + cp = buf; + *cp = ch; + size = 1; + sign = '\0'; + break; + } + + /* + * All reasonable formats wind up here. At this point, + * `cp' points to a string which (if not flags&LADJUST) + * should be padded out to `width' places. If + * flags&ZEROPAD, it should first be prefixed by any + * sign or other prefix; otherwise, it should be blank + * padded before the prefix is emitted. After any + * left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print + * the string proper, then emit zeroes required by any + * leftover floating precision; finally, if LADJUST, + * pad with blanks. + */ + + /* + * compute actual size, so we know how much to pad. + */ +#if defined(FLOATING_POINT) && !defined (USE_DTOA) + fieldsz = size + fpprec; +#else + fieldsz = size; +#endif + dpad = dprec - size; + if (dpad < 0) + dpad = 0; + + if (sign) + fieldsz++; + else if (flags & HEXPREFIX) + fieldsz += 2; + fieldsz += dpad; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0) + PAD_SP(width - fieldsz); + + /* prefix */ + if (sign) { + PRINT(&sign, 1); + } else if (flags & HEXPREFIX) { + ox[0] = '0'; + ox[1] = ch; + PRINT(ox, 2); + } + + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + PAD_0(width - fieldsz); + + /* leading zeroes from decimal precision */ + PAD_0(dpad); + + /* the string or number proper */ + PRINT(cp, size); + +#if defined(FLOATING_POINT) && !defined (USE_DTOA) + /* trailing f.p. zeroes */ + PAD_0(fpprec); +#endif + + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + PAD_SP(width - fieldsz); + + /* finally, adjust ret */ + ret += width > fieldsz ? width : fieldsz; + + } +done: + return ret; +error: + return EOF; + /* NOTREACHED */ +} + +#if defined(FLOATING_POINT) && !defined(USE_DTOA) + +static char *exponent(register char *p, register int exp, int fmtch) +{ + register char *t; + char expbuf[MAXEXP]; + + *p++ = fmtch; + if (exp < 0) { + exp = -exp; + *p++ = '-'; + } + else + *p++ = '+'; + t = expbuf + MAXEXP; + if (exp > 9) { + do { + *--t = to_char(exp % 10); + } while ((exp /= 10) > 9); + *--t = to_char(exp); + for (; t < expbuf + MAXEXP; *p++ = *t++); + } + else { + *p++ = '0'; + *p++ = to_char(exp); + } + return (p); +} + +static char * round(double fract, int *exp, + register char *start, register char *end, + char ch, int *signp) +{ + double tmp; + + if (fract) + (void)modf(fract * 10, &tmp); + else + tmp = to_digit(ch); + if (tmp > 4) + for (;; --end) { + if (*end == '.') + --end; + if (++*end <= '9') + break; + *end = '0'; + if (end == start) { + if (exp) { /* e/E; increment exponent */ + *end = '1'; + ++*exp; + } + else { /* f; add extra digit */ + *--end = '1'; + --start; + } + break; + } + } + /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ + else if (*signp == '-') + for (;; --end) { + if (*end == '.') + --end; + if (*end != '0') + break; + if (end == start) + *signp = 0; + } + return (start); +} + +int __cvt_double(double number, register int prec, int flags, int *signp, + int fmtch, char *startp, char *endp) +{ + register char *p, *t; + register double fract; + int dotrim = 0, expcnt, gformat = 0; + double integer, tmp; + + expcnt = 0; + if (number < 0) { + number = -number; + *signp = '-'; + } else + *signp = 0; + + fract = modf(number, &integer); + + /* get an extra slot for rounding. */ + t = ++startp; + + /* + * get integer portion of number; put into the end of the buffer; the + * .01 is added for modf(356.0 / 10, &integer) returning .59999999... + */ + for (p = endp - 1; integer; ++expcnt) { + tmp = modf(integer / 10, &integer); + *p-- = to_char((int)((tmp + .01) * 10)); + } + switch (fmtch) { + case 'f': + case 'F': + /* reverse integer into beginning of buffer */ + if (expcnt) + for (; ++p < endp; *t++ = *p); + else + *t++ = '0'; + /* + * if precision required or alternate flag set, add in a + * decimal point. + */ + if (prec || flags&ALT) + *t++ = '.'; + /* if requires more precision and some fraction left */ + if (fract) { + if (prec) + do { + fract = modf(fract * 10, &tmp); + *t++ = to_char((int)tmp); + } while (--prec && fract); + if (fract) + startp = round(fract, (int *)NULL, startp, + t - 1, (char)0, signp); + } + for (; prec--; *t++ = '0'); + break; + case 'e': + case 'E': +eformat: if (expcnt) { + *t++ = *++p; + if (prec || flags&ALT) + *t++ = '.'; + /* if requires more precision and some integer left */ + for (; prec && ++p < endp; --prec) + *t++ = *p; + /* + * if done precision and more of the integer component, + * round using it; adjust fract so we don't re-round + * later. + */ + if (!prec && ++p < endp) { + fract = 0; + startp = round((double)0, &expcnt, startp, + t - 1, *p, signp); + } + /* adjust expcnt for digit in front of decimal */ + --expcnt; + } + /* until first fractional digit, decrement exponent */ + else if (fract) { + /* adjust expcnt for digit in front of decimal */ + for (expcnt = -1;; --expcnt) { + fract = modf(fract * 10, &tmp); + if (tmp) + break; + } + *t++ = to_char((int)tmp); + if (prec || flags&ALT) + *t++ = '.'; + } + else { + *t++ = '0'; + if (prec || flags&ALT) + *t++ = '.'; + } + /* if requires more precision and some fraction left */ + if (fract) { + if (prec) + do { + fract = modf(fract * 10, &tmp); + *t++ = to_char((int)tmp); + } while (--prec && fract); + if (fract) + startp = round(fract, &expcnt, startp, + t - 1, (char)0, signp); + } + /* if requires more precision */ + for (; prec--; *t++ = '0'); + + /* unless alternate flag, trim any g/G format trailing 0's */ + if (gformat && !(flags&ALT)) { + while (t > startp && *--t == '0'); + if (*t == '.') + --t; + ++t; + } + t = exponent(t, expcnt, fmtch); + break; + case 'g': + case 'G': + /* a precision of 0 is treated as a precision of 1. */ + if (!prec) + ++prec; + /* + * ``The style used depends on the value converted; style e + * will be used only if the exponent resulting from the + * conversion is less than -4 or greater than the precision.'' + * -- ANSI X3J11 + */ + if (expcnt > prec || (!expcnt && fract && fract < .0001)) { + /* + * g/G format counts "significant digits, not digits of + * precision; for the e/E format, this just causes an + * off-by-one problem, i.e. g/G considers the digit + * before the decimal point significant and e/E doesn't + * count it as precision. + */ + --prec; + fmtch -= 2; /* G->E, g->e */ + gformat = 1; + goto eformat; + } + /* + * reverse integer into beginning of buffer, + * note, decrement precision + */ + if (expcnt) + for (; ++p < endp; *t++ = *p, --prec); + else + *t++ = '0'; + /* + * if precision required or alternate flag set, add in a + * decimal point. If no digits yet, add in leading 0. + */ + if (prec || flags&ALT) { + dotrim = 1; + *t++ = '.'; + } + else + dotrim = 0; + /* if requires more precision and some fraction left */ + if (fract) { + if (prec) { + /* If no integer part, don't count initial + * zeros as significant digits. */ + do { + fract = modf(fract * 10, &tmp); + *t++ = to_char((int)tmp); + } while(!tmp && !expcnt); + while (--prec && fract) { + fract = modf(fract * 10, &tmp); + *t++ = to_char((int)tmp); + } + } + if (fract) + startp = round(fract, (int *)NULL, startp, + t - 1, (char)0, signp); + } + /* alternate format, adds 0's for precision, else trim 0's */ + if (flags&ALT) + for (; prec--; *t++ = '0'); + else if (dotrim) { + while (t > startp && *--t == '0'); + if (*t != '.') + ++t; + } + } + return (t - startp); +} + +#endif /* defined(FLOATING_POINT) && !defined(USE_DTOA) */ + +int streambuf::form(char const *format ...) +{ + va_list ap; + va_start(ap, format); + int count = vform(format, ap); + va_end(ap); + return count; +} diff --git a/gnu/lib/libg++/iostream/sbufvscan.C b/gnu/lib/libg++/iostream/sbufvscan.C new file mode 100644 index 00000000000..3c7d29a8c78 --- /dev/null +++ b/gnu/lib/libg++/iostream/sbufvscan.C @@ -0,0 +1,746 @@ +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +// Extensively hacked for GNU iostream by Per Bothner 1991, 1992. +// Changes copyright Per Bothner 1992. + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "%W% (Berkeley) %G%"; +#endif /* LIBC_SCCS and not lint */ + +#include <ioprivate.h> +#include <ctype.h> +#ifndef NO_STDARG +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#ifndef NO_FLOATING_POINT +#define FLOATING_POINT +#endif + +#ifdef FLOATING_POINT +#include "floatio.h" +#define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */ +#else +#define BUF 40 +#endif + +/* + * Flags used during conversion. + */ +#define LONG 0x01 /* l: long or double */ +#define LONGDBL 0x02 /* L: long double; unimplemented */ +#define SHORT 0x04 /* h: short */ +#define SUPPRESS 0x08 /* suppress assignment */ +#define POINTER 0x10 /* weird %p pointer (`fake hex') */ +#define NOSKIP 0x20 /* do not skip blanks */ + +/* + * The following are used in numeric conversions only: + * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; + * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. + */ +#define SIGNOK 0x40 /* +/- is (still) legal */ +#define NDIGITS 0x80 /* no digits detected */ + +#define DPTOK 0x100 /* (float) decimal point is still legal */ +#define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */ + +#define PFXOK 0x100 /* 0x prefix is (still) legal */ +#define NZDIGITS 0x200 /* no zero digits detected */ + +/* + * Conversion types. + */ +#define CT_CHAR 0 /* %c conversion */ +#define CT_CCL 1 /* %[...] conversion */ +#define CT_STRING 2 /* %s conversion */ +#define CT_INT 3 /* integer, i.e., strtol or strtoul */ +#define CT_FLOAT 4 /* floating, i.e., strtod */ + +#define u_char unsigned char +#define u_long unsigned long + +extern "C" u_long strtoul(const char*, char**, int); +static const u_char *__sccl(register char *tab, register const u_char *fmt); + +// If state is non-NULL, set failbit and/or eofbit as appropriate. + +int streambuf::vscan(char const *fmt0, + _G_va_list ap, + ios *stream /* = NULL */) +{ + register const u_char *fmt = (const u_char *)fmt0; + register int c; /* character from format, or conversion */ + register size_t width; /* field width, or 0 */ + register char *p; /* points into all kinds of strings */ + register int n; /* handy integer */ + register int flags; /* flags as defined above */ + register char *p0; /* saves original value of p when necessary */ + int nassigned; /* number of fields assigned */ + int nread; /* number of characters consumed from fp */ + // Assignments to base and ccfn are just to suppress warnings from gcc. + int base = 0; /* base argument to strtol/strtoul */ + typedef u_long (*strtoulfn)(const char*, char**, int); + strtoulfn ccfn = 0; + // conversion function (strtol/strtoul) + char ccltab[256]; /* character class table for %[...] */ + char buf[BUF]; /* buffer for numeric conversions */ + int seen_eof = 0; + + /* `basefix' is used to avoid `if' tests in the integer scanner */ + static short basefix[17] = + { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + + nassigned = 0; + nread = 0; + for (;;) { + c = *fmt++; + if (c == 0) + goto done; + if (isspace(c)) { + for (;;) { + c = sbumpc(); + if (c == EOF) + goto eof_failure; + if (!isspace(c)) { + sputbackc(c); + break; + } + nread++; + } + continue; + } + if (c != '%') + goto literal; + width = 0; + flags = 0; + /* + * switch on the format. continue if done; + * break once format type is derived. + */ +again: c = *fmt++; + switch (c) { + case '%': +literal: + n = sbumpc(); + if (n == EOF) + goto eof_failure; + if (n != c) { + sputbackc(n); + goto match_failure; + } + nread++; + continue; + + case '*': + flags |= SUPPRESS; + goto again; + case 'l': + flags |= LONG; + goto again; + case 'L': + flags |= LONGDBL; + goto again; + case 'h': + flags |= SHORT; + goto again; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + width = width * 10 + c - '0'; + goto again; + + /* + * Conversions. + * Those marked `compat' are for 4.[123]BSD compatibility. + * + * (According to ANSI, E and X formats are supposed + * to the same as e and x. Sorry about that.) + */ + case 'D': /* compat */ + flags |= LONG; + /* FALLTHROUGH */ + case 'd': + c = CT_INT; + ccfn = (strtoulfn)strtol; + base = 10; + break; + + case 'i': + c = CT_INT; + ccfn = (strtoulfn)strtol; + base = 0; + break; + + case 'O': /* compat */ + flags |= LONG; + /* FALLTHROUGH */ + case 'o': + c = CT_INT; + ccfn = strtoul; + base = 8; + break; + + case 'u': + c = CT_INT; + ccfn = strtoul; + base = 10; + break; + + case 'X': + case 'x': + flags |= PFXOK; /* enable 0x prefixing */ + c = CT_INT; + ccfn = strtoul; + base = 16; + break; + +#ifdef FLOATING_POINT + case 'E': case 'F': + case 'e': case 'f': case 'g': + c = CT_FLOAT; + break; +#endif + + case 's': + c = CT_STRING; + break; + + case '[': + fmt = __sccl(ccltab, fmt); + flags |= NOSKIP; + c = CT_CCL; + break; + + case 'c': + flags |= NOSKIP; + c = CT_CHAR; + break; + + case 'p': /* pointer format is like hex */ + flags |= POINTER | PFXOK; + c = CT_INT; + ccfn = strtoul; + base = 16; + break; + + case 'n': + if (flags & SUPPRESS) /* ??? */ + continue; + if (flags & SHORT) + *va_arg(ap, short *) = nread; + else if (flags & LONG) + *va_arg(ap, long *) = nread; + else + *va_arg(ap, int *) = nread; + continue; + + /* + * Disgusting backwards compatibility hacks. XXX + */ + case '\0': /* compat */ + nassigned = EOF; + goto done; + + default: /* compat */ + if (isupper(c)) + flags |= LONG; + c = CT_INT; + ccfn = (strtoulfn)strtol; + base = 10; + break; + } + + /* + * We have a conversion that requires input. + */ + if (sgetc() == EOF) + goto eof_failure; + + /* + * Consume leading white space, except for formats + * that suppress this. + */ + if ((flags & NOSKIP) == 0) { + n = (unsigned char)*_gptr; + while (isspace(n)) { + _gptr++; + nread++; + n = sgetc(); + if (n == EOF) + goto eof_failure; + } + // Note that there is at least one character in + // the buffer, so conversions that do not set NOSKIP + // can no longer result in an input failure. + } + + /* + * Do the conversion. + */ + switch (c) { + + case CT_CHAR: + /* scan arbitrary characters (sets NOSKIP) */ + if (width == 0) // FIXME! + width = 1; + if (flags & SUPPRESS) { + size_t sum = 0; + for (;;) { + if ((n = _egptr - _gptr) < (int)width) { + sum += n; + width -= n; + _gptr += n; + if (underflow() == EOF) + if (sum == 0) + goto eof_failure; + else { + seen_eof++; + break; + } + } else { + sum += width; + _gptr += width; + break; + } + } + nread += sum; + } else { + size_t r = sgetn((char*)va_arg(ap, char*), + width); + if (r != width) + goto eof_failure; + nread += r; + nassigned++; + } + break; + + case CT_CCL: + /* scan a (nonempty) character class (sets NOSKIP) */ + if (width == 0) + width = ~0; /* `infinity' */ + /* take only those things in the class */ + if (flags & SUPPRESS) { + n = 0; + while (ccltab[(unsigned char)*_gptr]) { + n++, _gptr++; + if (--width == 0) + break; + if (sgetc() == EOF) { + if (n == 0) + goto eof_failure; + seen_eof++; + break; + } + } + if (n == 0) + goto match_failure; + } else { + p0 = p = va_arg(ap, char *); + while (ccltab[(unsigned char)*_gptr]) { + *p++ = *_gptr++; + if (--width == 0) + break; + if (sgetc() == EOF) { + if (p == p0) + goto eof_failure; + seen_eof++; + break; + } + } + n = p - p0; + if (n == 0) + goto match_failure; + *p = 0; + nassigned++; + } + nread += n; + break; + + case CT_STRING: + /* like CCL, but zero-length string OK, & no NOSKIP */ + if (width == 0) + width = ~0; + if (flags & SUPPRESS) { + n = 0; + while (!isspace((unsigned char)*_gptr)) { + n++, _gptr++; + if (--width == 0) + break; + if (sgetc() == EOF) { + seen_eof++; + break; + } + } + nread += n; + } else { + p0 = p = va_arg(ap, char *); + while (!isspace((unsigned char)*_gptr)) { + *p++ = *_gptr++; + if (--width == 0) + break; + if (sgetc() == EOF) { + seen_eof++; + break; + } + } + *p = 0; + nread += p - p0; + nassigned++; + } + continue; + + case CT_INT: + /* scan an integer as if by strtol/strtoul */ + if (width == 0 || width > sizeof(buf) - 1) + width = sizeof(buf) - 1; + flags |= SIGNOK | NDIGITS | NZDIGITS; + for (p = buf; width; width--) { + c = (unsigned char)*_gptr; + /* + * Switch on the character; `goto ok' + * if we accept it as a part of number. + */ + switch (c) { + + /* + * The digit 0 is always legal, but is + * special. For %i conversions, if no + * digits (zero or nonzero) have been + * scanned (only signs), we will have + * base==0. In that case, we should set + * it to 8 and enable 0x prefixing. + * Also, if we have not scanned zero digits + * before this, do not turn off prefixing + * (someone else will turn it off if we + * have scanned any nonzero digits). + */ + case '0': + if (base == 0) { + base = 8; + flags |= PFXOK; + } + if (flags & NZDIGITS) + flags &= ~(SIGNOK|NZDIGITS|NDIGITS); + else + flags &= ~(SIGNOK|PFXOK|NDIGITS); + goto ok; + + /* 1 through 7 always legal */ + case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + base = basefix[base]; + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + + /* digits 8 and 9 ok iff decimal or hex */ + case '8': case '9': + base = basefix[base]; + if (base <= 8) + break; /* not legal here */ + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + + /* letters ok iff hex */ + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + /* no need to fix base here */ + if (base <= 10) + break; /* not legal here */ + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + + /* sign ok only as first character */ + case '+': case '-': + if (flags & SIGNOK) { + flags &= ~SIGNOK; + goto ok; + } + break; + + /* x ok iff flag still set & 2nd char */ + case 'x': case 'X': + if (flags & PFXOK && p == buf + 1) { + base = 16; /* if %i */ + flags &= ~PFXOK; + goto ok; + } + break; + } + + /* + * If we got here, c is not a legal character + * for a number. Stop accumulating digits. + */ + break; + ok: + /* + * c is legal: store it and look at the next. + */ + *p++ = c; + _gptr++; + if (sgetc() == EOF) { + seen_eof++; + break; /* EOF */ + } + } + /* + * If we had only a sign, it is no good; push + * back the sign. If the number ends in `x', + * it was [sign] '0' 'x', so push back the x + * and treat it as [sign] '0'. + */ + if (flags & NDIGITS) { + if (p > buf) + (void) sputbackc(*(u_char *)--p); + goto match_failure; + } + c = ((u_char *)p)[-1]; + if (c == 'x' || c == 'X') { + --p; + (void) sputbackc(c); + } + if ((flags & SUPPRESS) == 0) { + u_long res; + + *p = 0; + res = (*ccfn)(buf, (char **)NULL, base); + if (flags & POINTER) + *va_arg(ap, void **) = (void *)res; + else if (flags & SHORT) + *va_arg(ap, short *) = res; + else if (flags & LONG) + *va_arg(ap, long *) = res; + else + *va_arg(ap, int *) = res; + nassigned++; + } + nread += p - buf; + break; + +#ifdef FLOATING_POINT + case CT_FLOAT: + /* scan a floating point number as if by strtod */ + if (width == 0 || width > sizeof(buf) - 1) + width = sizeof(buf) - 1; + flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; + for (p = buf; width; width--) { + c = (unsigned char)*_gptr; + /* + * This code mimicks the integer conversion + * code, but is much simpler. + */ + switch (c) { + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + flags &= ~(SIGNOK | NDIGITS); + goto fok; + + case '+': case '-': + if (flags & SIGNOK) { + flags &= ~SIGNOK; + goto fok; + } + break; + case '.': + if (flags & DPTOK) { + flags &= ~(SIGNOK | DPTOK); + goto fok; + } + break; + case 'e': case 'E': + /* no exponent without some digits */ + if ((flags&(NDIGITS|EXPOK)) == EXPOK) { + flags = + (flags & ~(EXPOK|DPTOK)) | + SIGNOK | NDIGITS; + goto fok; + } + break; + } + break; + fok: + *p++ = c; + _gptr++; + if (sgetc() == EOF) { + seen_eof++; + break; /* EOF */ + } + } + /* + * If no digits, might be missing exponent digits + * (just give back the exponent) or might be missing + * regular digits, but had sign and/or decimal point. + */ + if (flags & NDIGITS) { + if (flags & EXPOK) { + /* no digits at all */ + while (p > buf) + sputbackc(*(u_char *)--p); + goto match_failure; + } + /* just a bad exponent (e and maybe sign) */ + c = *(u_char *)--p; + if (c != 'e' && c != 'E') { + (void)sputbackc(c);/* sign */ + c = *(u_char *)--p; + } + (void) sputbackc(c); + } + if ((flags & SUPPRESS) == 0) { + double res; + *p = 0; +#ifdef USE_DTOA + res = strtod(buf, NULL); +#else + res = atof(buf); +#endif + if (flags & LONG) + *va_arg(ap, double *) = res; + else + *va_arg(ap, float *) = res; + nassigned++; + } + nread += p - buf; + break; +#endif /* FLOATING_POINT */ + } + } +eof_failure: + seen_eof++; +input_failure: + if (nassigned == 0) + nassigned = -1; +match_failure: + if (stream) + stream->set(ios::failbit); +done: + if (stream && seen_eof) + stream->set(ios::eofbit); + return (nassigned); +} + +/* + * Fill in the given table from the scanset at the given format + * (just after `['). Return a pointer to the character past the + * closing `]'. The table has a 1 wherever characters should be + * considered part of the scanset. + */ +static const u_char *__sccl(register char *tab, register const u_char *fmt) +{ + register int c, n, v; + + /* first `clear' the whole table */ + c = *fmt++; /* first char hat => negated scanset */ + if (c == '^') { + v = 1; /* default => accept */ + c = *fmt++; /* get new first char */ + } else + v = 0; /* default => reject */ + /* should probably use memset here */ + for (n = 0; n < 256; n++) + tab[n] = v; + if (c == 0) + return (fmt - 1);/* format ended before closing ] */ + + /* + * Now set the entries corresponding to the actual scanset + * to the opposite of the above. + * + * The first character may be ']' (or '-') without being special; + * the last character may be '-'. + */ + v = 1 - v; + for (;;) { + tab[c] = v; /* take character c */ +doswitch: + n = *fmt++; /* and examine the next */ + switch (n) { + + case 0: /* format ended too soon */ + return (fmt - 1); + + case '-': + /* + * A scanset of the form + * [01+-] + * is defined as `the digit 0, the digit 1, + * the character +, the character -', but + * the effect of a scanset such as + * [a-zA-Z0-9] + * is implementation defined. The V7 Unix + * scanf treats `a-z' as `the letters a through + * z', but treats `a-a' as `the letter a, the + * character -, and the letter a'. + * + * For compatibility, the `-' is not considerd + * to define a range if the character following + * it is either a close bracket (required by ANSI) + * or is not numerically greater than the character + * we just stored in the table (c). + */ + n = *fmt; + if (n == ']' || n < c) { + c = '-'; + break; /* resume the for(;;) */ + } + fmt++; + do { /* fill in the range */ + tab[++c] = v; + } while (c < n); +#if 1 /* XXX another disgusting compatibility hack */ + /* + * Alas, the V7 Unix scanf also treats formats + * such as [a-c-e] as `the letters a through e'. + * This too is permitted by the standard.... + */ + goto doswitch; +#else + c = *fmt++; + if (c == 0) + return (fmt - 1); + if (c == ']') + return (fmt); +#endif + break; + + case ']': /* end of scanset */ + return (fmt); + + default: /* just another character */ + c = n; + break; + } + } + /* NOTREACHED */ +} + +int streambuf::scan(char const *format ...) +{ + va_list ap; + va_start(ap, format); + int count = vscan(format, ap); + va_end(ap); + return count; +} diff --git a/gnu/lib/libg++/iostream/sgetline.C b/gnu/lib/libg++/iostream/sgetline.C new file mode 100644 index 00000000000..04745969223 --- /dev/null +++ b/gnu/lib/libg++/iostream/sgetline.C @@ -0,0 +1,64 @@ +// 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. + +#include "ioprivate.h" + +// Algorithm based on that used by Berkeley pre-4.4 fgets implementation. + +// Read chars into buf (of size n), until delim is seen. +// Return number of chars read (at most n-1). +// If extract_delim < 0, leave delimiter unread. +// If extract_delim > 0, insert delim in output. + +long streambuf::sgetline(char* buf, size_t n, char delim, int extract_delim) +{ + register char *ptr = buf; + if (n <= 0) + return EOF; + n--; // Leave space for final '\0'. + do { + int len = egptr() - gptr(); + if (len <= 0) + if (underflow() == EOF) + break; + else + len = egptr() - gptr(); + if (len >= (int)n) + len = n; + char *t = (char*)memchr((void*)_gptr, delim, len); + if (t != NULL) { + size_t old_len = ptr-buf; + len = t - _gptr; + if (extract_delim >= 0) { + t++; + old_len++; + if (extract_delim > 0) + len++; + } + memcpy((void*)ptr, (void*)_gptr, len); + ptr[len] = 0; + _gptr = t; + return old_len + len; + } + memcpy((void*)ptr, (void*)_gptr, len); + _gptr += len; + ptr += len; + n -= len; + } while (n != 0); + *ptr = 0; + return ptr - buf; +} diff --git a/gnu/lib/libg++/iostream/stdiostream.C b/gnu/lib/libg++/iostream/stdiostream.C new file mode 100644 index 00000000000..960a9a4a60f --- /dev/null +++ b/gnu/lib/libg++/iostream/stdiostream.C @@ -0,0 +1,112 @@ +// This is part of the iostream library, providing -*- C++ -*- input/output. +// Copyright (C) 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. + +#ifdef __GNUG__ +#pragma implementation +#endif + +#include <stdiostream.h> + +// A stdiobuf is "tied" to a FILE object (as used by the stdio package). +// Thus a stdiobuf is always synchronized with the corresponding FILE, +// though at the cost of some overhead. (If you use the implementation +// of stdio supplied with this library, you don't need stdiobufs.) +// This implementation inherits from filebuf, but implement the virtual +// functions sys_read/..., using the stdio functions fread/... instead +// of the low-level read/... system calls. This has the advantage that +// we get all of the nice filebuf semantics automatically, though +// with some overhead. + + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +stdiobuf::stdiobuf(FILE *f) : filebuf(fileno(f)) +{ + _file = f; + // Turn off buffer in stdiobuf. Instead, rely on buffering in (FILE). + // Thus the stdiobuf will be synchronized with the FILE. + setbuf(NULL, 0); +} + +_G_ssize_t stdiobuf::sys_read(char* buf, size_t size) +{ + return fread(buf, 1, size, _file); +} + +_G_ssize_t stdiobuf::sys_write(const void *buf, long n) +{ + _G_ssize_t count = fwrite(buf, 1, n, _file); + if (_fb._offset >= 0) + _fb._offset += n; + return count; +} + +_G_fpos_t stdiobuf::sys_seek(_G_fpos_t offset, _seek_dir dir) +{ + // Normally, equivalent to: fdir=dir + int fdir = + (dir == ios::beg) ? SEEK_SET : + (dir == ios::cur) ? SEEK_CUR : + (dir == ios::end) ? SEEK_END : + dir; + return fseek(_file, offset, fdir); +} + +int stdiobuf::sys_close() +{ + int status = fclose(_file); + _file = NULL; + return status; +} + +int stdiobuf::sync() +{ + if (filebuf::sync() == EOF) + return EOF; + if (!(xflags() & _S_NO_WRITES)) + if (fflush(_file)) + return EOF; +#if 0 + // This loses when writing to a pipe. + if (fseek(_file, 0, SEEK_CUR) == EOF) + return EOF; +#endif + return 0; +} + +int stdiobuf::overflow(int c /* = EOF*/) +{ + if (filebuf::overflow(c) == EOF) + return EOF; + if (c != EOF) + return c; + return fflush(_file); +} + +int stdiobuf::xsputn(const char* s, int n) +{ + // The filebuf implementation of sputn loses. + return streambuf::xsputn(s, n); +} diff --git a/gnu/lib/libg++/iostream/stdiostream.h b/gnu/lib/libg++/iostream/stdiostream.h new file mode 100644 index 00000000000..9e397b7eed9 --- /dev/null +++ b/gnu/lib/libg++/iostream/stdiostream.h @@ -0,0 +1,45 @@ +// This is part of the iostream library, providing -*- C++ -*- input/output. +// Copyright (C) 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. +// +// $Id: stdiostream.h,v 1.1 1995/10/18 08:38:14 deraadt Exp $ + +#ifndef _STDIOSTREAM_H +#define _STDIOSTREAM_H + +#ifdef __GNUG__ +#pragma interface +#endif + +#include <streambuf.h> +#include <stdio.h> + +class stdiobuf : public filebuf { + protected: + FILE *_file; + public: + FILE* stdiofile() const { return _file; } + stdiobuf(FILE *f); + virtual _G_ssize_t sys_read(char* buf, _G_size_t size); + virtual _G_fpos_t sys_seek(_G_fpos_t, _seek_dir); + virtual _G_ssize_t sys_write(const void*, long); + virtual int sys_close(); + virtual int sync(); + virtual int overflow(int c = EOF); + virtual int xsputn(const char* s, int n); +}; + +#endif /* !_STDIOSTREAM_H */ diff --git a/gnu/lib/libg++/iostream/stdstrbufs.C b/gnu/lib/libg++/iostream/stdstrbufs.C new file mode 100644 index 00000000000..2ae80fa9c41 --- /dev/null +++ b/gnu/lib/libg++/iostream/stdstrbufs.C @@ -0,0 +1,113 @@ +// This is part of the iostream library, providing input/output for C++. +// Copyright (C) 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 "ioprivate.h" +#include <stdio.h> + +// This file defines the standard streambufs, corresponding to cin, cout, cerr. +// We define two sets: +// +// __std_filebuf_0, __std_filebuf_1, __std_filebuf_2 are filebufs using +// file descriptor 0/1/2. +// +// __stdin_stdiobuf, __stdout_stdiobuf, __stderr_stdiobuf are stdiostreams +// pointing to stdin, stdout, stderr. + + +// To avoid problems depending on constructor order (and for +// efficiency) the standard streambufs (and streams) are +// constructed statically using C-style '{ ... }' initializers. +// Since you're not allowed to do this for structs that +// have virtuals, we define fake streambuf and stream classes +// that don't have any C++-isms, and initialize those. +// To initialize the vtable field of the standard filebufs, +// we use the expression 'vt_filebuf' which must evaluate to +// (the address of) the virtual function table for the +// filebuf class. + +#if _G_NAMES_HAVE_UNDERSCORE +#define UNDERSCORE "_" +#else +#define UNDERSCORE "" +#endif + +// First define the filebuf-based objects. + +#if !defined(vt_filebuf) +#ifndef __GNUG__ +// This works for cfront. +#define vt_filebuf __vtbl__7filebuf +extern char vt_filebuf[1]; +#elif _G_DOLLAR_IN_LABEL +extern char vt_filebuf[1] asm(UNDERSCORE "_vt$filebuf"); +#else +extern char vt_filebuf[1] asm(UNDERSCORE "_vt.filebuf"); +#endif +#endif /* !defined(vt_filebuf) */ + +struct _fake_filebuf { + struct __streambuf s; + char* vtable; + struct __file_fields f; +}; + +#define FILEBUF_LITERAL(CHAIN, FLAGS) \ + { _IO_MAGIC+_S_LINKED+_S_IS_FILEBUF+_S_IS_BACKUPBUF+FLAGS, \ + 0, 0, 0, 0, 0, 0, 0, 0, CHAIN, 0, 0, 0, 0, 0} + +#define DEF_FILEBUF(NAME, FD, CHAIN, FLAGS) \ + _fake_filebuf NAME = {FILEBUF_LITERAL(CHAIN, FLAGS), vt_filebuf, {FD}}; + +DEF_FILEBUF(__std_filebuf_0, 0, 0, _S_NO_WRITES); +DEF_FILEBUF(__std_filebuf_1, 1, (streambuf*)&__std_filebuf_0, _S_NO_READS); +DEF_FILEBUF(__std_filebuf_2, 2, (streambuf*)&__std_filebuf_1, + _S_NO_READS+_S_UNBUFFERED); + +// Nest define the stdiobuf-bases objects. + +#if !defined(vt_stdiobuf) +#ifndef __GNUG__ +// This works for cfront. +#define vt_stdiobuf __vtbl__8stdiobuf +extern char vt_stdiobuf[1]; +#elif _G_DOLLAR_IN_LABEL +extern char vt_stdiobuf[1] asm(UNDERSCORE "_vt$stdiobuf"); +#else +extern char vt_stdiobuf[1] asm(UNDERSCORE "_vt.stdiobuf"); +#endif +#endif /* !defined(vt_stdiobuf) */ + +struct _fake_stdiobuf { + struct __streambuf s; + char* vtable; + struct __file_fields f; + FILE *_f; +}; + +#define DEF_STDIOBUF(NAME, FILE, FD, CHAIN, FLAGS) \ + _fake_stdiobuf NAME[1] = {{ \ + FILEBUF_LITERAL(CHAIN, (FLAGS)|_S_UNBUFFERED),\ + vt_stdiobuf, {FD}, FILE}}; + +DEF_STDIOBUF(__stdin_stdiobuf, stdin, 0, (streambuf*)&__std_filebuf_2, + _S_NO_WRITES); +DEF_STDIOBUF(__stdout_stdiobuf, stdout, 1, (streambuf*)__stdin_stdiobuf, + _S_NO_READS); +DEF_STDIOBUF(__stderr_stdiobuf, stderr, 2, (streambuf*)__stdout_stdiobuf, + _S_NO_READS); + +streambuf* streambuf::_list_all = (streambuf*)__stderr_stdiobuf; diff --git a/gnu/lib/libg++/iostream/stdstreams.C b/gnu/lib/libg++/iostream/stdstreams.C new file mode 100644 index 00000000000..991371a1077 --- /dev/null +++ b/gnu/lib/libg++/iostream/stdstreams.C @@ -0,0 +1,145 @@ +// This is part of the iostream library, providing input/output for C++. +// Copyright (C) 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 "ioprivate.h" + +// The ANSI draft requires that operations on cin/cout/cerr can be +// mixed with operations on stdin/stdout/stderr on a character by +// character basis. This normally requires that the streambuf's +// used by cin/cout/cerr be stdiostreams. However, if the stdio +// implementation is the one that is built using this library, +// then we don't need to, since in that case stdin/stdout/stderr +// are identical to &__std_filebuf_0/&__std_filebuf_1/&__std_filebuf_2. + +#ifdef _STDIO_USES_IOSTREAM +#define USE_FILEBUF +#endif + +#ifdef NAMES_HAVE_UNDERSCORE +#define UNDERSCORE "_" +#else +#define UNDERSCORE "" +#endif + +#ifdef USE_FILEBUF +#define CIN_SBUF __std_filebuf_0 +#define COUT_SBUF __std_filebuf_1 +#define CERR_SBUF __std_filebuf_2 +static int use_stdiobuf = 0; +#else +#define CIN_SBUF __stdin_stdiobuf +#define COUT_SBUF __stdout_stdiobuf +#define CERR_SBUF __stderr_stdiobuf +static int use_stdiobuf = 1; +#endif + +struct _fake_filebuf; +extern _fake_filebuf __std_filebuf_0, __std_filebuf_1, __std_filebuf_2; +struct _fake_stdiobuf; +extern _fake_stdiobuf __stdin_stdiobuf, __stdout_stdiobuf, __stderr_stdiobuf; + +#define cin CIN +#define cout COUT +#define cerr CERR +#define clog CLOG +#include "iostream.h" +#undef cin +#undef cout +#undef cerr +#undef clog + +#ifdef __GNUC__ +#define PAD 0 /* g++ allows 0-length arrays. */ +#else +#define PAD 1 +#endif +struct _fake_istream { + struct myfields { +#ifdef __GNUC__ + _ios_fields *vb; /* pointer to virtual base class ios */ + _G_ssize_t _gcount; +#else + /* This is supposedly correct for cfront. */ + _G_ssize_t _gcount; + void *vptr; + _ios_fields *vb; /* pointer to virtual base class ios */ +#endif + } mine; + _ios_fields base; + char filler[sizeof(struct istream)-sizeof(struct _ios_fields)+PAD]; +}; +struct _fake_ostream { + struct myfields { +#ifndef __GNUC__ + void *vptr; +#endif + _ios_fields *vb; /* pointer to virtual base class ios */ + } mine; + _ios_fields base; + char filler[sizeof(struct ostream)-sizeof(struct _ios_fields)+PAD]; +}; + +#define STD_STR(SBUF, TIE, EXTRA_FLAGS) \ + (streambuf*)&SBUF, TIE, 0, ios::dont_close|ios::skipws|EXTRA_FLAGS, ' ',0,0,6 + +#ifdef __GNUC__ +#define OSTREAM_DEF(TYPE, NAME, SBUF, TIE, EXTRA_FLAGS) \ + TYPE NAME = { {&NAME.base}, {STD_STR(SBUF, TIE, EXTRA_FLAGS) }}; +#define ISTREAM_DEF(TYPE, NAME, SBUF, TIE, EXTRA_FLAGS) \ + TYPE NAME = { {&NAME.base}, {STD_STR(SBUF, TIE, EXTRA_FLAGS) }}; +#else +#define OSTREAM_DEF(TYPE, NAME, SBUF, TIE, EXTRA_FLAGS) \ + TYPE NAME = { {0, &NAME.base}, {STD_STR(SBUF, TIE, EXTRA_FLAGS) }}; +#define ISTREAM_DEF(TYPE, NAME, SBUF, TIE, EXTRA_FLAGS) \ + TYPE NAME = { {0, 0, &NAME.base}, {STD_STR(SBUF, TIE, EXTRA_FLAGS) }}; +#endif + +OSTREAM_DEF(_fake_ostream, cout, COUT_SBUF, NULL, 0) +OSTREAM_DEF(_fake_ostream, cerr, CERR_SBUF, (ostream*)&cout, ios::unitbuf) +ISTREAM_DEF(_fake_istream, cin, CIN_SBUF, (ostream*)&cout, 0) + +/* Only for (partial) compatibility with AT&T's library. */ +OSTREAM_DEF(_fake_ostream, clog, CERR_SBUF, (ostream*)&cout, 0) + +// Switches between using __std_filebuf_{0,1,2} and +// __std{in,out,err}_stdiobuf for standard streams. This is +// normally not needed, but is provided for AT&T compatibility. + +int ios::sync_with_stdio(int new_state) +{ +#ifdef _STDIO_USES_IOSTREAM + // It is always synced. + return 0; +#else + if (new_state == use_stdiobuf) // The usual case now. + return use_stdiobuf; + if (new_state) { + cout.base._strbuf = (streambuf*)&__stdout_stdiobuf; + cin.base._strbuf = (streambuf*)&__stdin_stdiobuf; + cerr.base._strbuf = (streambuf*)&__stderr_stdiobuf; + clog.base._strbuf = (streambuf*)&__stderr_stdiobuf; + } else { + cout.base._strbuf = (streambuf*)&__std_filebuf_1; + cin.base._strbuf = (streambuf*)&__std_filebuf_0; + cerr.base._strbuf = (streambuf*)&__std_filebuf_2; + clog.base._strbuf = (streambuf*)&__std_filebuf_2; + } + int old_state = use_stdiobuf; + use_stdiobuf = new_state; + return old_state; +#endif +} diff --git a/gnu/lib/libg++/iostream/stream.C b/gnu/lib/libg++/iostream/stream.C new file mode 100644 index 00000000000..5ee6bbeb5a5 --- /dev/null +++ b/gnu/lib/libg++/iostream/stream.C @@ -0,0 +1,120 @@ +#include <stdarg.h> +#include "ioprivate.h" +#include "stream.h" +#include "strstream.h" + +static char Buffer[_G_BUFSIZ]; +#define EndBuffer (Buffer+_G_BUFSIZ) +static char* next_chunk = Buffer; // Start of available part of Buffer. + +char* form(const char* format, ...) +{ + int space_left = EndBuffer - next_chunk; + // If less that 25% of the space is available start over. + if (space_left < (_G_BUFSIZ>>2)) + next_chunk = Buffer; + char* buf = next_chunk; + + strstreambuf stream(buf, EndBuffer-buf-1, buf); + va_list ap; + va_start(ap, format); + int count = stream.vform(format, ap); + va_end(ap); + stream.sputc(0); + next_chunk = buf + stream.pcount(); + return buf; +} + +#define u_long unsigned long + +static char* itoa(unsigned long i, int size, int neg, int base) +{ + // Conservative estimate: If base==2, might need 8 characters + // for each input byte, but normally 3 is plenty. + int needed = size ? size + : (base >= 8 ? 3 : 8) * sizeof(unsigned long) + 2; + int space_left = EndBuffer - next_chunk; + if (space_left <= needed) + next_chunk = Buffer; // start over. + + char* buf = next_chunk; + + register char* ptr = buf+needed+1; + next_chunk = ptr; + + if (needed < (2+neg) || ptr > EndBuffer) + return NULL; + *--ptr = 0; + + if (i == 0) + *--ptr = '0'; + while (i != 0 && ptr > buf) { + int ch = i % base; + i = i / base; + if (ch >= 10) + ch += 'a' - 10; + else + ch += '0'; + *--ptr = ch; + } + if (neg) + *--ptr = '-'; + if (size == 0) + return ptr; + while (ptr > buf) + *--ptr = ' '; + return buf; +} + +char* dec(long i, int len /* = 0 */) +{ + if (i >= 0) return itoa((unsigned long)i, len, 0, 10); + else return itoa((unsigned long)(-i), len, 1, 10); +} +char* dec(int i, int len /* = 0 */) +{ + if (i >= 0) return itoa((unsigned long)i, len, 0, 10); + else return itoa((unsigned long)(-i), len, 1, 10); +} +char* dec(unsigned long i, int len /* = 0 */) +{ + return itoa(i, len, 0, 10); +} +char* dec(unsigned int i, int len /* = 0 */) +{ + return itoa(i, len, 0, 10); +} + +char* hex(long i, int len /* = 0 */) +{ + return itoa((unsigned long)i, len, 0, 16); +} +char* hex(int i, int len /* = 0 */) +{ + return itoa((unsigned long)i, len, 0, 16); +} +char* hex(unsigned long i, int len /* = 0 */) +{ + return itoa(i, len, 0, 16); +} +char* hex(unsigned int i, int len /* = 0 */) +{ + return itoa(i, len, 0, 16); +} + +char* oct(long i, int len /* = 0 */) +{ + return itoa((unsigned long)i, len, 0, 8); +} +char* oct(int i, int len /* = 0 */) +{ + return itoa((unsigned long)i, len, 0, 8); +} +char* oct(unsigned long i, int len /* = 0 */) +{ + return itoa(i, len, 0, 8); +} +char* oct(unsigned int i, int len /* = 0 */) +{ + return itoa(i, len, 0, 8); +} diff --git a/gnu/lib/libg++/iostream/stream.h b/gnu/lib/libg++/iostream/stream.h new file mode 100644 index 00000000000..5f87b7eef77 --- /dev/null +++ b/gnu/lib/libg++/iostream/stream.h @@ -0,0 +1,33 @@ +// $Id: stream.h,v 1.1 1995/10/18 08:38:14 deraadt Exp $ + +#ifndef _COMPAT_STREAM_H +#define _COMPAT_STREAM_H + +// Compatibility with old library. + +#define _STREAM_COMPAT +#include <iostream.h> + +extern char* form(const char*, ...); + +extern char* dec(long, int=0); +extern char* dec(int, int=0); +extern char* dec(unsigned long, int=0); +extern char* dec(unsigned int, int=0); + +extern char* hex(long, int=0); +extern char* hex(int, int=0); +extern char* hex(unsigned long, int=0); +extern char* hex(unsigned int, int=0); + +extern char* oct(long, int=0); +extern char* oct(int, int=0); +extern char* oct(unsigned long, int=0); +extern char* oct(unsigned int, int=0); + +char* chr(char ch, int width = 0); +char* str(const char* s, int width = 0); + +inline istream& WS(istream& str) { return ws(str); } + +#endif /* !_COMPAT_STREAM_H */ diff --git a/gnu/lib/libg++/iostream/streambuf.C b/gnu/lib/libg++/iostream/streambuf.C new file mode 100644 index 00000000000..0038f39190e --- /dev/null +++ b/gnu/lib/libg++/iostream/streambuf.C @@ -0,0 +1,666 @@ +// 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. + +#define _STREAM_COMPAT +#ifdef __GNUG__ +#pragma implementation +#endif +#include "ioprivate.h" +#include <string.h> + +void streambuf::_un_link() +{ + if (_flags & _S_LINKED) { + streambuf **f; + for (f = &_list_all; *f != NULL; f = &(*f)->xchain()) { + if (*f == this) { + *f = xchain(); + break; + } + } + _flags &= ~_S_LINKED; + } +} + +void streambuf::_link_in() +{ + if ((_flags & _S_LINKED) == 0) { + _flags |= _S_LINKED; + xchain() = _list_all; + _list_all = this; + } +} + +// Return minimum _pos markers +// Assumes the current get area is the main get area. +int streambuf::_least_marker() +{ + int least_so_far = _egptr - _eback; + for (register streammarker *mark = _markers; + mark != NULL; mark = mark->_next) + if (mark->_pos < least_so_far) + least_so_far = mark->_pos; + return least_so_far; +} + +// Switch current get area from backup buffer to (start of) main get area. + +void streambuf::switch_to_main_get_area() +{ + char *tmp; + _flags &= ~_S_IN_BACKUP; + // Swap _egptr and _other_egptr. + tmp= _egptr; _egptr= _other_egptr; _other_egptr= tmp; + // Swap _eback and _other_gbase. + tmp= _eback; _eback = _other_gbase; _other_gbase = tmp; + _gptr = _eback; +} + +// Switch current get area from main get area to (end of) backup area. + +void streambuf::switch_to_backup_area() +{ + char *tmp; + _flags |= _S_IN_BACKUP; + // Swap _egptr and _other_egptr. + tmp = _egptr; _egptr = _other_egptr; _other_egptr = tmp; + // Swap _gbase and _other_gbase. + tmp = _eback; _eback = _other_gbase; _other_gbase = tmp; + _gptr = _egptr; +} + +int streambuf::switch_to_get_mode() +{ + if (_pptr > _pbase) + if (overflow(EOF) == EOF) + return EOF; + if (in_backup()) { + _eback = _aux_limit; + } + else { + _eback = _base; + if (_pptr > _egptr) + _egptr = _pptr; + } + _gptr = _pptr; + + setp(_gptr, _gptr); + + _flags &= ~_S_CURRENTLY_PUTTING; + return 0; +} + +void streambuf::free_backup_area() +{ + if (in_backup()) + switch_to_main_get_area(); // Just in case. + delete [] _other_gbase; + _other_gbase = NULL; + _other_egptr = NULL; + _aux_limit = NULL; +} + +#if 0 +int streambuf::switch_to_put_mode() +{ + _pbase = _gptr; + _pptr = _gptr; + _epptr = in_backup() ? _egptr : _ebuf; // wrong if line- or un-buffered? + + _gptr = _egptr; + _eback = _egptr; + + _flags |= _S_CURRENTLY_PUTTING; + return 0; +} +#endif + +#ifdef _G_FRIEND_BUG +int __underflow(register streambuf *sb) { return __UNDERFLOW(sb); } +int __UNDERFLOW(register streambuf *sb) +#else +int __underflow(register streambuf *sb) +#endif +{ + if (sb->put_mode()) + if (sb->switch_to_get_mode() == EOF) return EOF; + if (sb->_gptr < sb->_egptr) + return *(unsigned char*)sb->_gptr; + if (sb->in_backup()) { + sb->switch_to_main_get_area(); + if (sb->_gptr < sb->_egptr) + return *sb->_gptr; + } + if (sb->have_markers()) { + // Append [_gbase.._egptr] to backup area. + int least_mark = sb->_least_marker(); + // needed_size is how much space we need in the backup area. + int needed_size = (sb->_egptr - sb->_eback) - least_mark; + int current_Bsize = sb->_other_egptr - sb->_other_gbase; + int avail; // Extra space available for future expansion. + if (needed_size > current_Bsize) { + avail = 0; // 100 ?? FIXME + char *new_buffer = new char[avail+needed_size]; + if (least_mark < 0) { + memcpy(new_buffer + avail, + sb->_other_egptr + least_mark, + -least_mark); + memcpy(new_buffer +avail - least_mark, + sb->_eback, + sb->_egptr - sb->_eback); + } + else + memcpy(new_buffer + avail, + sb->_eback + least_mark, + needed_size); + delete [] sb->_other_gbase; + sb->_other_gbase = new_buffer; + sb->_other_egptr = new_buffer + avail + needed_size; + } + else { + avail = current_Bsize - needed_size; + if (least_mark < 0) { + memmove(sb->_other_gbase + avail, + sb->_other_egptr + least_mark, + -least_mark); + memcpy(sb->_other_gbase + avail - least_mark, + sb->_eback, + sb->_egptr - sb->_eback); + } + else if (needed_size > 0) + memcpy(sb->_other_gbase + avail, + sb->_eback + least_mark, + needed_size); + } + // FIXME: Dubious arithmetic if pointers are NULL + sb->_aux_limit = sb->_other_gbase + avail; + // Adjust all the streammarkers. + int delta = sb->_egptr - sb->_eback; + for (register streammarker *mark = sb->_markers; + mark != NULL; mark = mark->_next) + mark->_pos -= delta; + } + else if (sb->have_backup()) + sb->free_backup_area(); + return sb->underflow(); +} + +#ifdef _G_FRIEND_BUG +int __overflow(register streambuf *sb, int c) { return __OVERFLOW(sb, c); } +int __OVERFLOW(register streambuf *sb, int c) +#else +int __overflow(streambuf* sb, int c) +#endif +{ + return sb->overflow(c); +} + +int streambuf::xsputn(register const char* s, int n) +{ + if (n <= 0) + return 0; + register int more = n; + for (;;) { + int count = _epptr - _pptr; // Space available. + if (count > 0) { + if (count > more) + count = more; + if (count > 20) { + memcpy(_pptr, s, count); + s += count; + _pptr += count; + } + else if (count <= 0) + count = 0; + else { + register char *p = _pptr; + for (register int i = count; --i >= 0; ) *p++ = *s++; + _pptr = p; + } + more -= count; + } + if (more == 0 || __overflow(this, (unsigned char)*s++) == EOF) + break; + more--; + } + return n - more; +} + +int streambuf::padn(char pad, int count) +{ +#define PADSIZE 16 + static char const blanks[PADSIZE] = + {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; + static char const zeroes[PADSIZE] = + {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; + char padbuf[PADSIZE]; + const char *padptr; + register int i; + + if (pad == ' ') + padptr = blanks; + else if (pad == '0') + padptr = zeroes; + else { + for (i = PADSIZE; --i >= 0; ) padbuf[i] = pad; + padptr = padbuf; + } + for (i = count; i >= PADSIZE; i -= PADSIZE) + if (sputn(padptr, PADSIZE) != PADSIZE) + return EOF; + if (i > 0 && sputn(padptr, i) != i) + return EOF; + return pad; +} + +int streambuf::xsgetn(char* s, int n) +{ + register int more = n; + for (;;) { + int count = _egptr - _gptr; // Data available. + if (count > 0) { + if (count > more) + count = more; + if (count > 20) { + memcpy(s, _gptr, count); + s += count; + _gptr += count; + } + else if (count <= 0) + count = 0; + else { + register char *p = _gptr; + for (register int i = count; --i >= 0; ) *s++ = *p++; + _gptr = p; + } + more -= count; + } + if (more == 0 || __underflow(this) == EOF) + break; + } + return n - more; +} + +int streambuf::ignore(int n) +{ + register int more = n; + for (;;) { + int count = _egptr - _gptr; // Data available. + if (count > 0) { + if (count > more) + count = more; + _gptr += count; + more -= count; + } + if (more == 0 || __underflow(this) == EOF) + break; + } + return n - more; +} + +int streambuf::sync() +{ + if (gptr() == egptr() && pptr() == pbase()) + return 0; + return EOF; +} + +int streambuf::pbackfail(int c) +{ + if (_gptr > _eback) + _gptr--; + else if (seekoff(-1, ios::cur, ios::in) == EOF) + return EOF; + if (c != EOF && *_gptr != c) + *_gptr = c; + return (unsigned char)c; +} + +streambuf* streambuf::setbuf(char* p, int len) +{ + if (sync() == EOF) + return NULL; + if (p == NULL || len == 0) { + unbuffered(1); + setb(_shortbuf, _shortbuf+1, 0); + } + else { + unbuffered(0); + setb(p, p+len, 0); + } + setp(0, 0); + setg(0, 0, 0); + return this; +} + +streampos streambuf::seekpos(streampos pos, int mode) +{ + return seekoff(pos, ios::beg, mode); +} + +void streambuf::setb(char* b, char* eb, int a) +{ + if (_base && !(_flags & _S_USER_BUF)) + FREE_BUF(_base); + _base = b; + _ebuf = eb; + if (a) + _flags &= ~_S_USER_BUF; + else + _flags |= _S_USER_BUF; +} + +int streambuf::doallocate() +{ + char *buf = ALLOC_BUF(_G_BUFSIZ); + if (buf == NULL) + return EOF; + setb(buf, buf+_G_BUFSIZ, 1); + return 1; +} + +void streambuf::doallocbuf() +{ + if (base() || (!unbuffered() && doallocate() != EOF)) return; + setb(_shortbuf, _shortbuf+1, 0); +} + +streambuf::streambuf(int flags) +{ + _flags = _IO_MAGIC|flags; + _base = NULL; + _ebuf = NULL; + _eback = NULL; + _gptr = NULL; + _egptr = NULL; + _pbase = NULL; + _pptr = NULL; + _epptr = NULL; + _chain = NULL; // Not necessary. + + _other_gbase = NULL; + _aux_limit = NULL; + _other_egptr = NULL; + _markers = NULL; + _cur_column = 0; +} + +streambuf::~streambuf() +{ + if (_base && !(_flags & _S_USER_BUF)) + FREE_BUF(_base); + + for (register streammarker *mark = _markers; + mark != NULL; mark = mark->_next) + mark->_sbuf = NULL; + +} + +streampos +streambuf::seekoff(streamoff, _seek_dir, int mode /*=ios::in|ios::out*/) +{ + return EOF; +} + +int streambuf::sputbackc(char c) +{ + if (_gptr > _eback && (unsigned char)_gptr[-1] == (unsigned char)c) { + _gptr--; + return (unsigned char)c; + } + return pbackfail(c); +} + +int streambuf::sungetc() +{ + if (_gptr > _eback) { + _gptr--; + return (unsigned char)*_gptr; + } + else + return pbackfail(EOF); +} + +#if 0 /* Work in progress */ +void streambuf::collumn(int c) +{ + if (c == -1) + _collumn = -1; + else + _collumn = c - (_pptr - _pbase); +} +#endif + + +int streambuf::get_column() +{ + if (_cur_column) + return __adjust_column(_cur_column - 1, pbase(), pptr() - pbase()); + return -1; +} + +int streambuf::set_column(int i) +{ + _cur_column = i+1; + return 0; +} + +int streambuf::flush_all() +{ + int result = 0; + for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain()) + if (sb->overflow(EOF) == EOF) + result = EOF; + return result; +} + +void streambuf::flush_all_linebuffered() +{ + for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain()) + if (sb->linebuffered()) + sb->overflow(EOF); +} + +int backupbuf::underflow() +{ + return EOF; +} + +int backupbuf::overflow(int c) +{ + return EOF; +} + +streammarker::streammarker(streambuf *sb) +{ + _sbuf = sb; + if (!(sb->xflags() & _S_IS_BACKUPBUF)) { + set_streampos(sb->seekoff(0, ios::cur, ios::in)); + _next = 0; + } + else { + if (sb->put_mode()) + sb->switch_to_get_mode(); + if (((backupbuf*)sb)->in_backup()) + set_offset(sb->_gptr - sb->_egptr); + else + set_offset(sb->_gptr - sb->_eback); + + // Should perhaps sort the chain? + _next = ((backupbuf*)sb)->_markers; + ((backupbuf*)sb)->_markers = this; + } +} + +streammarker::~streammarker() +{ + if (saving()) { + // Unlink from sb's chain. + register streammarker **ptr = &((backupbuf*)_sbuf)->_markers; + for (; ; ptr = &(*ptr)->_next) + if (*ptr == NULL) + break; + else if (*ptr == this) { + *ptr = _next; + return; + } + } +#if 0 + if _sbuf has a backup area that is no longer needed, should we delete + it now, or wait until underflow()? +#endif +} + +#define BAD_DELTA EOF + +int streammarker::delta(streammarker& other_mark) +{ + if (_sbuf != other_mark._sbuf) + return BAD_DELTA; + if (saving() && other_mark.saving()) + return _pos - other_mark._pos; + else if (!saving() && !other_mark.saving()) + return _spos - other_mark._spos; + else + return BAD_DELTA; +} + +int streammarker::delta() +{ + if (_sbuf == NULL) + return BAD_DELTA; + if (saving()) { + int cur_pos; + if (_sbuf->in_backup()) + cur_pos = _sbuf->_gptr - _sbuf->_egptr; + else + cur_pos = _sbuf->_gptr - _sbuf->_eback; + return _pos - cur_pos; + } + else { + if (_spos == EOF) + return BAD_DELTA; + int cur_pos = _sbuf->seekoff(0, ios::cur); + if (cur_pos == EOF) + return BAD_DELTA; + return _pos - cur_pos; + } +} + +int streambuf::seekmark(streammarker& mark, int delta /* = 0 */) +{ + if (mark._sbuf != this) + return EOF; + if (!mark.saving()) { + return seekpos(mark._spos, ios::in); + } + else if (mark._pos >= 0) { + if (in_backup()) + switch_to_main_get_area(); + _gptr = _eback + mark._pos; + } + else { + if (!in_backup()) + switch_to_backup_area(); + _gptr = _egptr + mark._pos; + } + return 0; +} + +void streambuf::unsave_markers() +{ + register streammarker *mark =_markers; + if (_markers) { + streampos offset = seekoff(0, ios::cur, ios::in); + if (offset != EOF) { + offset += eGptr() - Gbase(); + for ( ; mark != NULL; mark = mark->_next) + mark->set_streampos(mark->_pos + offset); + } + else { + for ( ; mark != NULL; mark = mark->_next) + mark->set_streampos(EOF); + } + _markers = 0; + } + + free_backup_area(); +} + +int backupbuf::pbackfail(int c) +{ + if (_gptr <= _eback) { + // Need to handle a filebuf in write mode (switch to read mode). FIXME! + + if (have_backup() && !in_backup()) { + switch_to_backup_area(); + } + if (!have_backup()) { + // No backup buffer: allocate one. + // Use short buffer, if unused? (probably not) FIXME + int backup_size = 128; + _other_gbase = new char [backup_size]; + _other_egptr = _other_gbase + backup_size; + _aux_limit = _other_egptr; + switch_to_backup_area(); + } + else if (gptr() <= eback()) { + // Increase size of existing backup buffer. + size_t new_size; + size_t old_size = egptr() - eback(); + new_size = 2 * old_size; + char* new_buf = new char [new_size]; + memcpy(new_buf+(new_size-old_size), eback(), old_size); + delete [] eback(); + setg(new_buf, new_buf+(new_size-old_size), new_buf+new_size); + _aux_limit = _gptr; + } + } + _gptr--; + if (c != EOF && *_gptr != c) + *_gptr = c; + return (unsigned char)*_gptr; +} + +unsigned __adjust_column(unsigned start, const char *line, int count) +{ + register const char *ptr = line + count; + while (ptr > line) + if (*--ptr == '\n') + return line + count - ptr - 1; + return start + count; +} + +int ios::readable() { return !(rdbuf()->_flags & _S_NO_READS); } +int ios::writable() { return !(rdbuf()->_flags & _S_NO_WRITES); } +int ios::is_open() { return rdbuf() + && (rdbuf()->_flags & _S_NO_READS+_S_NO_WRITES) + != _S_NO_READS+_S_NO_WRITES; } + +#if defined(linux) +#define IO_CLEANUP ; +#endif + +#ifdef IO_CLEANUP + IO_CLEANUP +#else +struct __io_defs { + __io_defs() { } + ~__io_defs() { streambuf::flush_all(); } +}; +__io_defs io_defs__; +#endif diff --git a/gnu/lib/libg++/iostream/streambuf.h b/gnu/lib/libg++/iostream/streambuf.h new file mode 100644 index 00000000000..6beaeb6284c --- /dev/null +++ b/gnu/lib/libg++/iostream/streambuf.h @@ -0,0 +1,497 @@ +// This is part of the iostream library, providing -*- C++ -*- input/output. +// 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. +// +// $Id: streambuf.h,v 1.1 1995/10/18 08:38:14 deraadt Exp $ + +#ifndef _STREAMBUF_H +#define _STREAMBUF_H +#ifdef __GNUG__ +#pragma interface +#endif + +/* #define _G_IO_THROW */ /* Not implemented: ios::failure */ + +#include <_G_config.h> +#ifdef _G_NEED_STDARG_H +#include <stdarg.h> +#endif + +#ifndef EOF +#define EOF (-1) +#endif +#ifndef NULL +#ifdef __GNUC__ +#define NULL ((void*)0) +#else +#define NULL (0) +#endif +#endif + +class ostream; class streambuf; class backupbuf; + +// In case some header files defines these as macros. +#undef open +#undef close + +#ifdef _G_FRIEND_BUG +extern int __UNDERFLOW(streambuf*); +extern int __OVERFLOW(streambuf*, int); +#endif +extern "C" int __underflow(streambuf*); +extern "C" int __overflow(streambuf*, int); + +typedef _G_off_t streamoff; +typedef _G_off_t streampos; // Should perhaps be _G_fpos_t ? + +typedef unsigned long __fmtflags; +typedef unsigned char __iostate; + +struct _ios_fields { // The data members of an ios. + streambuf *_strbuf; + ostream* _tie; + int _width; + __fmtflags _flags; + _G_wchar_t _fill; + __iostate _state; + __iostate _exceptions; + int _precision; +}; + +#define _IOS_GOOD 0 +#define _IOS_EOF 1 +#define _IOS_FAIL 2 +#define _IOS_BAD 4 + +#define _IOS_INPUT 1 +#define _IOS_OUTPUT 2 +#define _IOS_ATEND 4 +#define _IOS_APPEND 8 +#define _IOS_TRUNC 16 +#define _IOS_NOCREATE 32 +#define _IOS_NOREPLACE 64 +#define _IOS_BIN 128 + +#ifdef _STREAM_COMPAT +enum state_value { + _good = _IOS_GOOD, + _eof = _IOS_EOF, + _fail = _IOS_FAIL, + _bad = _IOS_BAD }; +enum open_mode { + input = _IOS_INPUT, + output = _IOS_OUTPUT, + atend = _IOS_ATEND, + append = _IOS_APPEND }; +#endif + +class ios : public _ios_fields { + public: + typedef __fmtflags fmtflags; + typedef int iostate; + typedef int openmode; + typedef int streamsize; + enum io_state { + goodbit = _IOS_GOOD, + eofbit = _IOS_EOF, + failbit = _IOS_FAIL, + badbit = _IOS_BAD }; + enum open_mode { + in = _IOS_INPUT, + out = _IOS_OUTPUT, + ate = _IOS_ATEND, + app = _IOS_APPEND, + trunc = _IOS_TRUNC, + nocreate = _IOS_NOCREATE, + noreplace = _IOS_NOREPLACE, + bin = _IOS_BIN }; + enum seek_dir { beg, cur, end}; + // ANSI: typedef enum seek_dir seekdir; etc + enum { skipws=01, left=02, right=04, internal=010, + dec=020, oct=040, hex=0100, + showbase=0200, showpoint=0400, uppercase=01000, showpos=02000, + scientific=04000, fixed=010000, unitbuf=020000, stdio=040000, + dont_close=0100000 //Don't delete streambuf on stream destruction + }; + enum { // Masks. + basefield=dec+oct+hex, + floatfield = scientific+fixed, + adjustfield = left+right+internal + }; + +#ifdef _G_IO_THROW + class failure : public xmsg { + ios* _stream; + public: + failure(ios* stream) { _stream = stream; } + failure(string cause, ios* stream) { _stream = stream; } + ios* rdios() const { return _stream; } + }; +#endif + + ostream* tie() const { return _tie; } + ostream* tie(ostream* val) { ostream* save=_tie; _tie=val; return save; } + + // Methods to change the format state. + _G_wchar_t fill() const { return (_G_wchar_t)_fill; } + _G_wchar_t fill(_G_wchar_t newf) + {_G_wchar_t oldf = (_G_wchar_t)_fill; _fill = (char)newf; return oldf;} + fmtflags flags() const { return _flags; } + fmtflags flags(fmtflags new_val) { + fmtflags old_val = _flags; _flags = new_val; return old_val; } + int precision() const { return _precision; } + int precision(int newp) { + unsigned short oldp = _precision; _precision = (unsigned short)newp; + return oldp; } + fmtflags setf(fmtflags val) { + fmtflags oldbits = _flags; + _flags |= val; return oldbits; } + fmtflags setf(fmtflags val, fmtflags mask) { + fmtflags oldbits = _flags; + _flags = (_flags & ~mask) | (val & mask); return oldbits; } + fmtflags unsetf(fmtflags mask) { + fmtflags oldbits = _flags & mask; + _flags &= ~mask; return oldbits; } + int width() const { return _width; } + int width(int val) { int save = _width; _width = val; return save; } + +#ifdef _G_IO_THROW + void _throw_failure() { throw new ios::failure(this); } +#else + void _throw_failure() { } +#endif + + streambuf* rdbuf() const { return _strbuf; } + void clear(iostate state = 0) { + _state = _strbuf ? state : state|badbit; + if (_state & _exceptions) _throw_failure(); } + void set(iostate flag) { _state |= flag; + if (_state & _exceptions) _throw_failure(); } + void setstate(iostate flag) { _state |= flag; // ANSI + if (_state & _exceptions) _throw_failure(); } + int good() const { return _state == 0; } + int eof() const { return _state & ios::eofbit; } + int fail() const { return _state & (ios::badbit|ios::failbit); } + int bad() const { return _state & ios::badbit; } + iostate rdstate() const { return _state; } + operator void*() const { return fail() ? (void*)0 : (void*)(-1); } + int operator!() const { return fail(); } + iostate exceptions() const { return _exceptions; } + void exceptions(iostate enable) { + _exceptions = enable; + if (_state & _exceptions) _throw_failure(); } + + static int sync_with_stdio(int on); + static void sync_with_stdio() { sync_with_stdio(1); } + +#ifdef _STREAM_COMPAT + void unset(state_value flag) { _state &= ~flag; } + void close(); + int is_open(); + int readable(); + int writable(); +#endif + + // Used to initialize standard streams. Not needed in this implementation. + class Init { + public: + Init () { } + }; + + protected: + ios(streambuf* sb = 0, ostream* tie = 0); + virtual ~ios(); + void init(streambuf* sb) { _state=0; _strbuf=sb; } +}; + +#if __GNUG__==1 +typedef int _seek_dir; +#else +typedef ios::seek_dir _seek_dir; +#endif + +// Magic numbers and bits for the _flags field. +// The magic numbers use the high-order bits of _flags; +// the remaining bits are abailable for variable flags. +// Note: The magic numbers must all be negative if stdio +// emulation is desired. + +#define _IO_MAGIC 0xFBAD0000 /* Magic number */ +#define _OLD_STDIO_MAGIC 0xFABC0000 /* Emulate old stdio. */ +#define _IO_MAGIC_MASK 0xFFFF0000 +#define _S_USER_BUF 1 /* User owns buffer; don't delete it on close. */ +#define _S_UNBUFFERED 2 +#define _S_NO_READS 4 /* Reading not allowed */ +#define _S_NO_WRITES 8 /* Writing not allowd */ +#define _S_EOF_SEEN 0x10 +#define _S_ERR_SEEN 0x20 +#define _S_DELETE_DONT_CLOSE 0x40 +#define _S_LINKED 0x80 // Set if linked (using _chain) to streambuf::_list_all. +#define _S_IN_BACKUP 0x100 +#define _S_LINE_BUF 0x200 +#define _S_TIED_PUT_GET 0x400 // Set if put and get pointer logicly tied. +#define _S_CURRENTLY_PUTTING 0x800 +#define _S_IS_APPENDING 0x1000 +#define _S_IS_BACKUPBUF 0x4000 +#define _S_IS_FILEBUF 0x8000 + +// A streammarker remembers a position in a buffer. +// You are guaranteed to be able to seek back to it if it is saving(). +class streammarker { + friend class streambuf; +#ifdef _G_FRIEND_BUG + friend int __UNDERFLOW(streambuf*); +#else + friend int __underflow(streambuf*); +#endif + struct streammarker *_next; // Only if saving() + streambuf *_sbuf; // Only valid if saving(). + streampos _spos; // -2: means that _pos is valid. + void set_streampos(streampos sp) { _spos = sp; } + void set_offset(int offset) { _pos = offset; _spos = (streampos)(-2); } + // If _pos >= 0, it points to _buf->Gbase()+_pos. + // if _pos < 0, it points to _buf->eBptr()+_pos. + int _pos; + public: + streammarker(streambuf *sb); + ~streammarker(); + int saving() { return _spos == -2; } + int delta(streammarker&); + int delta(); +}; + +struct __streambuf { + // NOTE: If this is changed, also change __FILE in stdio/stdio.h! + int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ + char* _gptr; /* Current get pointer */ + char* _egptr; /* End of get area. */ + char* _eback; /* Start of putback+get area. */ + char* _pbase; /* Start of put area. */ + char* _pptr; /* Current put pointer. */ + char* _epptr; /* End of put area. */ + char* _base; /* Start of reserve area. */ + char* _ebuf; /* End of reserve area. */ + struct streambuf *_chain; + + // The following fields are used to support backing up and undo. + friend class streammarker; + char *_other_gbase; // Pointer to start of non-current get area. + char *_aux_limit; // Pointer to first valid character of backup area, + char *_other_egptr; // Pointer to end of non-current get area. + streammarker *_markers; + +#define __HAVE_COLUMN /* temporary */ + // 1+column number of pbase(); 0 is unknown. + unsigned short _cur_column; + char _unused; + char _shortbuf[1]; +}; + +extern unsigned __adjust_column(unsigned start, const char *line, int count); + +struct streambuf : public __streambuf { + friend class ios; + friend class istream; + friend class ostream; + friend class streammarker; +#ifdef _G_FRIEND_BUG + friend int __UNDERFLOW(streambuf*); +#else + friend int __underflow(streambuf*); +#endif + protected: + static streambuf* _list_all; /* List of open streambufs. */ + streambuf*& xchain() { return _chain; } + void _un_link(); + void _link_in(); + char* gptr() const { return _gptr; } + char* pptr() const { return _pptr; } + char* egptr() const { return _egptr; } + char* epptr() const { return _epptr; } + char* pbase() const { return _pbase; } + char* eback() const { return _eback; } + char* base() const { return _base; } + char* ebuf() const { return _ebuf; } + int blen() const { return _ebuf - _base; } + void xput_char(char c) { *_pptr++ = c; } + int xflags() { return _flags; } + int xflags(int f) { int fl = _flags; _flags = f; return fl; } + void xsetflags(int f) { _flags |= f; } + void xsetflags(int f, int mask) { _flags = (_flags & ~mask) | (f & mask); } + void gbump(int n) { _gptr += n; } + void pbump(int n) { _pptr += n; } + void setb(char* b, char* eb, int a=0); + void setp(char* p, char* ep) { _pbase=_pptr=p; _epptr=ep; } + void setg(char* eb, char* g, char *eg) { _eback=eb; _gptr=g; _egptr=eg; } + char *shortbuf() { return _shortbuf; } + + int in_backup() { return _flags & _S_IN_BACKUP; } + // The start of the main get area: FIXME: wrong for write-mode filebuf? + char *Gbase() { return in_backup() ? _other_gbase : _eback; } + // The end of the main get area: + char *eGptr() { return in_backup() ? _other_egptr : _egptr; } + // The start of the backup area: + char *Bbase() { return in_backup() ? _eback : _other_gbase; } + char *Bptr() { return _aux_limit; } + // The end of the backup area: + char *eBptr() { return in_backup() ? _egptr : _other_egptr; } + char *Nbase() { return _other_gbase; } + char *eNptr() { return _other_egptr; } + int have_backup() { return _other_gbase != NULL; } + int have_markers() { return _markers != NULL; } + int _least_marker(); + void switch_to_main_get_area(); + void switch_to_backup_area(); + void free_backup_area(); + void unsave_markers(); // Make all streammarkers !saving(). + int put_mode() { return _flags & _S_CURRENTLY_PUTTING; } + int switch_to_get_mode(); + + streambuf(int flags=0); + public: + static int flush_all(); + static void flush_all_linebuffered(); // Flush all line buffered files. + virtual int underflow() = 0; // Leave public for now + virtual int overflow(int c = EOF) = 0; // Leave public for now + virtual int doallocate(); + virtual streampos seekoff(streamoff, _seek_dir, int mode=ios::in|ios::out); + virtual streampos seekpos(streampos pos, int mode = ios::in|ios::out); + int seekmark(streammarker& mark, int delta = 0); + int sputbackc(char c); + int sungetc(); + virtual ~streambuf(); + int unbuffered() { return _flags & _S_UNBUFFERED ? 1 : 0; } + int linebuffered() { return _flags & _S_LINE_BUF ? 1 : 0; } + void unbuffered(int i) + { if (i) _flags |= _S_UNBUFFERED; else _flags &= ~_S_UNBUFFERED; } + void linebuffered(int i) + { if (i) _flags |= _S_LINE_BUF; else _flags &= ~_S_LINE_BUF; } + int allocate() { // For AT&T compatibility + if (base() || unbuffered()) return 0; + else return doallocate(); } + // Allocate a buffer if needed; use _shortbuf if appropriate. + void allocbuf() { if (base() == NULL) doallocbuf(); } + void doallocbuf(); + virtual int sync(); + virtual int pbackfail(int c); + virtual streambuf* setbuf(char* p, int len); + int in_avail() { return _egptr - _gptr; } + int out_waiting() { return _pptr - _pbase; } + virtual int xsputn(const char* s, int n); + int sputn(const char* s, int n) { return xsputn(s, n); } + int padn(char pad, int n); // Emit 'n' copies of 'pad'. + virtual int xsgetn(char* s, int n); + int sgetn(char* s, int n) { return xsgetn(s, n); } + int ignore(int); + virtual int get_column(); + virtual int set_column(int); + long sgetline(char* buf, _G_size_t n, char delim, int putback_delim); + int sbumpc() { + if (_gptr >= _egptr && __underflow(this) == EOF) return EOF; + else return *(unsigned char*)_gptr++; } + int sgetc() { + if (_gptr >= _egptr && __underflow(this) == EOF) return EOF; + else return *(unsigned char*)_gptr; } + int snextc() { + if (_gptr >= _egptr && __underflow(this) == EOF) return EOF; + else return _gptr++, sgetc(); } + int sputc(int c) { + if (_pptr >= _epptr) return __overflow(this, (unsigned char)c); + else return *_pptr++ = c, (unsigned char)c; } + void stossc() { if (_gptr < _egptr) _gptr++; } + int vscan(char const *fmt0, _G_va_list ap, ios* stream = NULL); + int scan(char const *fmt0 ...); + int vform(char const *fmt0, _G_va_list ap); + int form(char const *fmt0 ...); +#if 0 /* Work in progress */ + int collumn(); // Current collumn number (of put pointer). -1 is unknown. + void collumn(int c); // Set collumn number of put pointer to c. +#endif +}; + +// A backupbuf is a streambuf with full backup and savepoints on reading. +// All standard streambufs in the GNU iostream library are backupbufs. + +// A backupbuf may have two get area: +// - The main get area, and (sometimes) the putback area. +// Whichever one of these contains the gptr is the current get area; +// the other one is the non-current get area. + +class backupbuf : public streambuf { + friend class streammarker; + protected: + backupbuf(int flags=0) : streambuf(flags|_S_IS_BACKUPBUF) { } + public: + virtual int pbackfail(int c); + virtual int underflow(); + virtual int overflow(int c = EOF); +}; + +struct __file_fields { + short _fileno; + int _blksize; + _G_off_t _offset; +// char* _save_gptr; char* _save_egptr; +}; + +class filebuf : public backupbuf { + protected: + struct __file_fields _fb; + void init(); + public: + static const int openprot; // Non-ANSI AT&T-ism: Default open protection. + filebuf(); + filebuf(int fd); + filebuf(int fd, char* p, int len); + ~filebuf(); + filebuf* attach(int fd); + filebuf* open(const char *filename, const char *mode); + filebuf* open(const char *filename, ios::openmode mode, int prot = 0664); + virtual int underflow(); + virtual int overflow(int c = EOF); + int is_open() const { return _fb._fileno >= 0; } + int fd() const { return is_open() ? _fb._fileno : EOF; } + filebuf* close(); + virtual int doallocate(); + virtual streampos seekoff(streamoff, _seek_dir, int mode=ios::in|ios::out); + virtual streambuf* setbuf(char* p, int len); + int xsputn(const char* s, int n); + int xsgetn(char* s, int n); + virtual int sync(); + protected: // See documentation in filebuf.C. +// virtual int pbackfail(int c); + int is_reading() { return eback() != egptr(); } + char* cur_ptr() { return is_reading() ? gptr() : pptr(); } + /* System's idea of pointer */ + char* file_ptr() { return eGptr(); } + int do_write(const char *data, int to_do); + int do_flush() { return do_write(_pbase, _pptr-_pbase); } + // Low-level operations (Usually invoke system calls.) + virtual _G_ssize_t sys_read(char* buf, _G_size_t size); + virtual _G_fpos_t sys_seek(_G_fpos_t, _seek_dir); + virtual _G_ssize_t sys_write(const void*, long); + virtual int sys_stat(void*); // Actually, a (struct stat*) + virtual int sys_close(); +}; + +inline ios::ios(streambuf* sb /* = 0 */, ostream* tie_to /* = 0 */) { + _state = sb ? ios::goodbit : ios::badbit; _exceptions=0; + _strbuf=sb; _tie = tie_to; _width=0; _fill=' '; + _flags=ios::skipws|ios::dec; _precision=6; } +inline ios::~ios() { + if (!(_flags & (unsigned int)ios::dont_close)) delete _strbuf; } + +#endif /* _STREAMBUF_H */ diff --git a/gnu/lib/libg++/iostream/strstream.C b/gnu/lib/libg++/iostream/strstream.C new file mode 100644 index 00000000000..d5a57137d52 --- /dev/null +++ b/gnu/lib/libg++/iostream/strstream.C @@ -0,0 +1,237 @@ +// 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 +#include "ioprivate.h" +#include <strstream.h> + +static void* default_alloc(_G_size_t size) +{ + return (void*)new char[size]; +} + +static void default_free(void* ptr) +{ + delete [] (char*)ptr; +} + +istrstream::istrstream(const char *cp, int n) +{ + init(new strstreambuf(cp, n)); +} + +ostrstream::ostrstream() +{ + init(new strstreambuf()); +} + +strstreambase::strstreambase(char *cp, int n, int mode) +{ + char *pstart; + if (mode == ios::app || mode == ios::ate) + pstart = cp + strlen(cp); + else + pstart = cp; + init(new strstreambuf(cp, n, pstart)); +} + +char *strstreambuf::str() +{ + freeze(1); + return base(); +} + +_G_size_t strstreambuf::pcount() +{ + _G_size_t put_len = pptr() - pbase(); + if (put_len < _len) put_len = _len; + return put_len; +} + +int strstreambuf::overflow(int c /* = EOF */) +{ + const int flush_only = c == EOF; + if (_flags & _S_NO_WRITES) + return flush_only ? 0 : EOF; + size_t pos = pptr() - pbase(); + size_t get_pos = gptr() - pbase(); + if (pos > _len) _len = pos; + if (pos >= blen() + flush_only) { + char *new_buf; + size_t new_size = 2 * blen(); + if (frozen()) /* not allowed to enlarge */ + return EOF; + new_buf = (char*)(*_allocate_buffer)(new_size); + memcpy(new_buf, base(), blen()); + if (new_buf == NULL) { +// __ferror(fp) = 1; + return EOF; + } +#if 0 + if (lenp == &_len) /* use '\0'-filling */ + memset(new_buf + pos, 0, blen() - pos); +#endif + if (_base) { + (*_free_buffer)(_base); + _base = NULL; // So setb() won't try to delete _base. + } + setb(new_buf, new_buf + new_size, 1); + } + + setp(base(), ebuf()); + pbump(pos); + setg(base(), base() + get_pos, base() + _len); + if (!flush_only) { + *pptr() = (unsigned char) c; + pbump(1); + } + return c; +} + +int strstreambuf::underflow() +{ + size_t ppos = pptr() - pbase(); + if (ppos > _len) _len = ppos; + setg(base(), gptr(), base() + _len); + if (gptr() < egptr()) + return *gptr(); + else + return EOF; +} + + +void strstreambuf::init_dynamic(_alloc_type alloc, _free_type free, + int initial_size) + +{ + _len = 0; + if (initial_size < 16) + initial_size = 16; + _allocate_buffer = alloc ? alloc : default_alloc; + _free_buffer = free ? free : default_free; + char * buf = (char*)(*_allocate_buffer)(initial_size); + setb(buf, buf + initial_size, 1); + setp(buf, buf + initial_size); + setg(buf, buf, buf); +} + +void strstreambuf::init_static(char *ptr, int size, char *pstart) +{ + if (size == 0) + size = strlen(ptr); + else if (size < 0) { + // If size is negative 'the characters are assumed to + // continue indefinitely.' This is kind of messy ... +#if 1 + size = 512; + // Try increasing powers of 2, as long as we don't wrap around. + // This can lose in pathological cases (ptr near the end + // of the address space). A better solution might be to + // adjust the size on underflow/overflow. FIXME. + for (int s; s = 2*size, s > 0 && ptr + s > ptr && s < 0x4000000L; ) + size = s; + size = s; +#else + // The following semi-portable kludge assumes that + // sizeof(unsigned long) == sizeof(char*). Hence, + // (unsigned long)(-1) should be the largest possible address. + unsigned long highest = (unsigned long)(-1); + // Pointers are signed on some brain-damaged systems, in + // which case we divide by two to get the maximum signed address. + if ((char*)highest < ptr) + highest >>= 1; + size = (char*)highest - ptr; +#endif + } + setb(ptr, ptr+size); + if (pstart) { + setp(ptr, ebuf()); + pbump(pstart-ptr); + setg(ptr, ptr, pstart); + } + else { + setp(ptr, ptr); + setg(ptr, ptr, ebuf()); + } + _len = egptr() - ptr; +} + +void strstreambuf::init_static (const char *ptr, int size) +{ + init_static((char*)ptr, size, NULL); + xsetflags(_S_NO_WRITES); +} + +strstreambuf::~strstreambuf() +{ + if (_base && !(_flags & _S_USER_BUF)) + (_free_buffer)(_base); + _base = NULL; +} + +streampos strstreambuf::seekoff(streamoff off, _seek_dir dir, + int mode /*=ios::in|ios::out*/) +{ + size_t cur_size = pcount(); + streampos new_pos = EOF; + + // Move the get pointer, if requested. + if (mode & ios::in) { + switch (dir) { + case ios::end: + off += cur_size; + break; + case ios::cur: + off += gptr() - pbase(); + break; + default: /*case ios::beg: */ + break; + } + if (off < 0 || (size_t)off > cur_size) + return EOF; + setg(base(), base() + off, base() + cur_size); + new_pos = off; + } + + // Move the put pointer, if requested. + if (mode & ios::out) { + switch (dir) { + case ios::end: + off += cur_size; + break; + case ios::cur: + off += pptr() - pbase(); + break; + default: /*case ios::beg: */ + break; + } + if (off < 0 || (size_t)off > cur_size) + return EOF; + pbump(base() + off - pptr()); + new_pos = off; + } + return new_pos; +} + +int strstreambuf::pbackfail(int c) +{ + if ((_flags & _S_NO_WRITES) && c != EOF) + return EOF; + return backupbuf::pbackfail(c); +} diff --git a/gnu/lib/libg++/iostream/strstream.h b/gnu/lib/libg++/iostream/strstream.h new file mode 100644 index 00000000000..9302a60ee59 --- /dev/null +++ b/gnu/lib/libg++/iostream/strstream.h @@ -0,0 +1,105 @@ +// This is part of the iostream library, providing -*- C++ -*- input/output. +// 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. +// +// $Id: strstream.h,v 1.1 1995/10/18 08:38:14 deraadt Exp $ + +#ifndef __STRSTREAM_H +#define __STRSTREAM_H +#ifdef __GNUG__ +#pragma interface +#endif +#include <iostream.h> + +class strstreambuf : public backupbuf { + _G_size_t _len; // The current length is max(_len, _pptr-_pbase). + typedef void *(*_alloc_type)(_G_size_t); + typedef void (*_free_type)(void*); + _alloc_type _allocate_buffer; + _free_type _free_buffer; + void init_dynamic(_alloc_type alloc, _free_type free, + int initial_size = 128); + void init_static(char *ptr, int size, char *pstart); + void init_static(const char *ptr, int size); + protected: + int is_static() const { return _allocate_buffer == (_alloc_type)0; } + virtual int overflow(int = EOF); + virtual int underflow(); + virtual int pbackfail(int c); + public: + virtual ~strstreambuf(); + strstreambuf() { init_dynamic(0, 0); } + strstreambuf(int initial_size) { init_dynamic(0, 0, initial_size); } + strstreambuf(void *(*alloc)(_G_size_t), void (*free)(void*)) + { init_dynamic(alloc, free); } + strstreambuf(char *ptr, int size, char *pstart = NULL) + { init_static(ptr, size, pstart); } + strstreambuf(unsigned char *ptr, int size, unsigned char *pstart = NULL) + { init_static((char*)ptr, size, (char*)pstart); } + strstreambuf(const char *ptr, int size) + { init_static(ptr, size); } + strstreambuf(const unsigned char *ptr, int size) + { init_static((const char*)ptr, size); } +#ifndef _G_BROKEN_SIGNED_CHAR + strstreambuf(signed char *ptr, int size, signed char *pstart = NULL) + { init_static((char*)ptr, size, (char*)pstart); } + strstreambuf(const signed char *ptr, int size) + { init_static((const char*)ptr, size); } +#endif + // Note: frozen() is always true if is_static(). + int frozen() { return _flags & _S_USER_BUF ? 1 : 0; } + void freeze(int n=1) + { if (!is_static()) + { if (n) _flags |= _S_USER_BUF; else _flags &= ~_S_USER_BUF; } } + _G_size_t pcount(); + char *str(); + virtual streampos seekoff(streamoff, _seek_dir, int mode=ios::in|ios::out); +}; + +class strstreambase : virtual public ios { + public: + strstreambuf* rdbuf() { return (strstreambuf*)_strbuf; } + protected: + strstreambase() { } + strstreambase(char *cp, int n, int mode=ios::out); +}; + +class istrstream : public strstreambase, public istream { + public: + istrstream(const char*, int=0); +}; + +class ostrstream : public strstreambase, public ostream { + public: + ostrstream(); + ostrstream(char *cp, int n, int mode=ios::out) :strstreambase(cp,n,mode){} + _G_size_t pcount() { return ((strstreambuf*)_strbuf)->pcount(); } + char *str() { return ((strstreambuf*)_strbuf)->str(); } + void freeze(int n = 1) { ((strstreambuf*)_strbuf)->freeze(n); } + int frozen() { return ((strstreambuf*)_strbuf)->frozen(); } +}; + +class strstream : public strstreambase, public iostream { + public: + strstream() : strstreambase() { init(new strstreambuf()); } + strstream(char *cp, int n, int mode=ios::out) :strstreambase(cp,n,mode){} + _G_size_t pcount() { return ((strstreambuf*)_strbuf)->pcount(); } + char *str() { return ((strstreambuf*)_strbuf)->str(); } + void freeze(int n = 1) { ((strstreambuf*)_strbuf)->freeze(n); } + int frozen() { return ((strstreambuf*)_strbuf)->frozen(); } +}; + +#endif /*!__STRSTREAM_H*/ |