summaryrefslogtreecommitdiff
path: root/gnu/lib/libg++/iostream
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/lib/libg++/iostream')
-rw-r--r--gnu/lib/libg++/iostream/PlotFile.C130
-rw-r--r--gnu/lib/libg++/iostream/PlotFile.h120
-rw-r--r--gnu/lib/libg++/iostream/SFile.C58
-rw-r--r--gnu/lib/libg++/iostream/SFile.h48
-rw-r--r--gnu/lib/libg++/iostream/editbuf.C707
-rw-r--r--gnu/lib/libg++/iostream/editbuf.h175
-rw-r--r--gnu/lib/libg++/iostream/filebuf.C580
-rw-r--r--gnu/lib/libg++/iostream/floatconv.C2416
-rw-r--r--gnu/lib/libg++/iostream/floatio.h27
-rw-r--r--gnu/lib/libg++/iostream/fstream.C65
-rw-r--r--gnu/lib/libg++/iostream/fstream.h72
-rw-r--r--gnu/lib/libg++/iostream/igetline.C135
-rw-r--r--gnu/lib/libg++/iostream/igetsb.C48
-rw-r--r--gnu/lib/libg++/iostream/indstream.C108
-rw-r--r--gnu/lib/libg++/iostream/indstream.h67
-rw-r--r--gnu/lib/libg++/iostream/iomanip.C77
-rw-r--r--gnu/lib/libg++/iostream/iomanip.h152
-rw-r--r--gnu/lib/libg++/iostream/ioprivate.h66
-rw-r--r--gnu/lib/libg++/iostream/iostream.C783
-rw-r--r--gnu/lib/libg++/iostream/iostream.h228
-rw-r--r--gnu/lib/libg++/iostream/makebuf.C71
-rw-r--r--gnu/lib/libg++/iostream/outfloat.C183
-rw-r--r--gnu/lib/libg++/iostream/parsestream.C307
-rw-r--r--gnu/lib/libg++/iostream/parsestream.h147
-rw-r--r--gnu/lib/libg++/iostream/procbuf.C126
-rw-r--r--gnu/lib/libg++/iostream/procbuf.h31
-rw-r--r--gnu/lib/libg++/iostream/sbufvform.C856
-rw-r--r--gnu/lib/libg++/iostream/sbufvscan.C746
-rw-r--r--gnu/lib/libg++/iostream/sgetline.C64
-rw-r--r--gnu/lib/libg++/iostream/stdiostream.C112
-rw-r--r--gnu/lib/libg++/iostream/stdiostream.h45
-rw-r--r--gnu/lib/libg++/iostream/stdstrbufs.C113
-rw-r--r--gnu/lib/libg++/iostream/stdstreams.C145
-rw-r--r--gnu/lib/libg++/iostream/stream.C120
-rw-r--r--gnu/lib/libg++/iostream/stream.h33
-rw-r--r--gnu/lib/libg++/iostream/streambuf.C666
-rw-r--r--gnu/lib/libg++/iostream/streambuf.h497
-rw-r--r--gnu/lib/libg++/iostream/strstream.C237
-rw-r--r--gnu/lib/libg++/iostream/strstream.h105
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*/