1/* This is part of libio/iostream, providing -*- C++ -*- input/output.
2Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation
3
4This file is part of the GNU IO Library.  This library is free
5software; you can redistribute it and/or modify it under the
6terms of the GNU General Public License as published by the
7Free Software Foundation; either version 2, or (at your option)
8any later version.
9
10This library is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this library; see the file COPYING.  If not, write to the Free
17Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19As a special exception, if you link this library with files
20compiled with a GNU compiler to produce an executable, this does not cause
21the resulting executable to be covered by the GNU General Public License.
22This exception does not however invalidate any other reasons why
23the executable file might be covered by the GNU General Public License. */
24
25/* Written by Per Bothner (bothner@cygnus.com). */
26
27#define _STREAM_COMPAT
28#ifdef __GNUG__
29#pragma implementation
30#endif
31#include "iostreamP.h"
32#include <string.h>
33#include <stdarg.h>
34#include <errno.h>
35#ifndef errno
36extern int errno;
37#endif
38
39void streambuf::_un_link() { _IO_un_link(reinterpret_cast<_IO_FILE_plus*>(this)); }
40
41void streambuf::_link_in() { _IO_link_in(reinterpret_cast<_IO_FILE_plus*>(this)); }
42
43int streambuf::switch_to_get_mode()
44{ return _IO_switch_to_get_mode(this); }
45
46void streambuf::free_backup_area()
47{ _IO_free_backup_area(this); }
48
49#if 0
50int streambuf::switch_to_put_mode()
51{ return _IO_:switch_to_put_mode(this); }
52#endif
53
54int __overflow(streambuf* sb, int c)
55{
56    return sb->overflow(c);
57}
58
59int streambuf::underflow()
60{ return EOF; }
61
62int streambuf::uflow()
63{ return _IO_default_uflow (this); }
64
65int streambuf::overflow(int /* = EOF */)
66{ return EOF; }
67
68streamsize streambuf::xsputn(register const char* s, streamsize n)
69{ return _IO_default_xsputn(this, s, n); }
70
71streamsize streambuf::xsgetn(char* s, streamsize n)
72{ return _IO_default_xsgetn(this, s, n); }
73
74int streambuf::ignore(int n)
75{
76    register int more = n;
77    for (;;) {
78	int count = _IO_read_end - _IO_read_ptr; // Data available.
79	if (count > 0) {
80	    if (count > more)
81		count = more;
82	    _IO_read_ptr += count;
83	    more -= count;
84	}
85	if (more == 0 || __underflow(this) == EOF)
86	    break;
87    }
88    return n - more;
89}
90
91int streambuf::sync()
92{
93  return 0;
94}
95
96int streambuf::pbackfail(int c)
97{
98  return _IO_default_pbackfail(this, c);
99}
100
101streambuf* streambuf::setbuf(char* p, int len)
102{
103    if (sync() == EOF)
104	return NULL;
105    if (p == NULL || len == 0) {
106	unbuffered(1);
107	setb(_shortbuf, _shortbuf+1, 0);
108    }
109    else {
110	unbuffered(0);
111	setb(p, p+len, 0);
112    }
113    setp(0, 0);
114    setg(0, 0, 0);
115    return this;
116}
117
118streampos streambuf::seekpos(streampos pos, int mode)
119{
120    return seekoff(pos, ios::beg, mode);
121}
122
123streampos streambuf::sseekpos(streampos pos, int mode)
124{
125  return _IO_seekpos (this, pos, mode);
126}
127
128void streambuf::setb(char* b, char* eb, int a)
129{ _IO_setb(this, b, eb, a); }
130
131int streambuf::doallocate() { return _IO_default_doallocate(this); }
132
133void streambuf::doallocbuf() { _IO_doallocbuf(this); }
134
135#if !_IO_UNIFIED_JUMPTABLES
136/* The following are jump table entries that just call the virtual method */
137
138static int _IO_sb_overflow(_IO_FILE *fp, int c)
139{ return ((streambuf*)fp)->overflow(c); }
140static int _IO_sb_underflow(_IO_FILE *fp)
141{ return ((streambuf*)fp)->underflow(); }
142static _IO_size_t _IO_sb_xsputn(_IO_FILE *fp, const void *s, _IO_size_t n)
143{ return ((streambuf*)fp)->xsputn((const char*)s, n); }
144static _IO_size_t _IO_sb_xsgetn(_IO_FILE *fp, void *s, _IO_size_t n)
145{ return ((streambuf*)fp)->xsgetn((char*)s, n); }
146static int _IO_sb_close(_IO_FILE *fp)
147{ return ((streambuf*)fp)->sys_close(); }
148static int _IO_sb_stat(_IO_FILE *fp, void *b)
149{ return ((streambuf*)fp)->sys_stat(b); }
150static int _IO_sb_doallocate(_IO_FILE *fp)
151{ return ((streambuf*)fp)->doallocate(); }
152
153static _IO_pos_t _IO_sb_seekoff(_IO_FILE *fp, _IO_off_t pos, int dir, int mode)
154{
155  return ((streambuf*)fp)->seekoff(pos, (ios::seek_dir)dir, mode);
156}
157
158static _IO_pos_t _IO_sb_seekpos(_IO_FILE *fp, _IO_pos_t pos, int mode)
159{
160  return ((streambuf*)fp)->seekpos(pos, mode);
161}
162
163static int _IO_sb_pbackfail(_IO_FILE *fp, int ch)
164{ return ((streambuf*)fp)->pbackfail(ch); }
165static void _IO_sb_finish(_IO_FILE *fp, int)
166{ ((streambuf*)fp)->~streambuf(); }
167static _IO_ssize_t _IO_sb_read(_IO_FILE *fp, void *buf, _IO_ssize_t n)
168{ return ((streambuf*)fp)->sys_read((char*)buf, n); }
169static _IO_ssize_t _IO_sb_write(_IO_FILE *fp, const void *buf, _IO_ssize_t n)
170{ return ((streambuf*)fp)->sys_write((const char*)buf, n); }
171static int _IO_sb_sync(_IO_FILE *fp)
172{ return ((streambuf*)fp)->sync(); }
173static _IO_pos_t _IO_sb_seek(_IO_FILE *fp, _IO_off_t off, int dir)
174{ return ((streambuf*)fp)->sys_seek(off, (_seek_dir)dir); }
175static _IO_FILE* _IO_sb_setbuf(_IO_FILE *fp, char *buf, _IO_ssize_t n)
176{ return ((streambuf*)fp)->setbuf(buf, n); }
177
178/* This callbacks in this jumptable just call the corresponding
179   virtual function, so that C functions can access (potentially user-defined)
180   streambuf-derived objects.
181   Contrast the builtinbuf class, which does the converse:  Allow
182   C++ virtual calls to be used on _IO_FILE objects that are builtin
183   (or defined by C code). */
184
185
186struct _IO_jump_t _IO_streambuf_jumps = {
187  JUMP_INIT_DUMMY,
188  JUMP_INIT(finish, _IO_sb_finish),
189  JUMP_INIT(overflow, _IO_sb_overflow),
190  JUMP_INIT(underflow, _IO_sb_underflow),
191  JUMP_INIT(uflow, _IO_default_uflow),
192  JUMP_INIT(pbackfail, _IO_sb_pbackfail),
193  JUMP_INIT(xsputn, _IO_sb_xsputn),
194  JUMP_INIT(xsgetn, _IO_sb_xsgetn),
195  JUMP_INIT(seekoff, _IO_sb_seekoff),
196  JUMP_INIT(seekpos, _IO_sb_seekpos),
197  JUMP_INIT(setbuf, _IO_sb_setbuf),
198  JUMP_INIT(sync, _IO_sb_sync),
199  JUMP_INIT(doallocate, _IO_sb_doallocate),
200  JUMP_INIT(read, _IO_sb_read),
201  JUMP_INIT(write, _IO_sb_write),
202  JUMP_INIT(seek, _IO_sb_seek),
203  JUMP_INIT(close, _IO_sb_close),
204  JUMP_INIT(stat, _IO_sb_stat)
205};
206#endif
207
208streambuf::streambuf(int flags)
209{
210#ifdef _IO_MTSAFE_IO
211  _lock = new _IO_lock_t;
212#endif
213  _IO_init(this, flags);
214#if !_IO_UNIFIED_JUMPTABLES
215  _jumps = &_IO_streambuf_jumps;
216#endif
217}
218
219streambuf::~streambuf()
220{
221  _IO_default_finish(this,0);
222#ifdef _IO_MTSAFE_IO
223  if (this != _IO_stdin && this != _IO_stdout && this != _IO_stderr)
224    delete _lock;
225#endif
226}
227
228streampos
229streambuf::seekoff(streamoff, _seek_dir, int /*=ios::in|ios::out*/)
230{
231    return EOF;
232}
233
234streampos
235streambuf::sseekoff(streamoff o , _seek_dir d, int m /*=ios::in|ios::out*/)
236{
237  return _IO_seekoff (this, o, d, m);
238}
239
240int streambuf::sputbackc(char c)
241{
242  return _IO_sputbackc(this, c);
243}
244
245int streambuf::sungetc()
246{
247  return _IO_sungetc(this);
248}
249
250#if 0 /* Work in progress */
251void streambuf::collumn(int c)
252{
253    if (c == -1)
254	_collumn = -1;
255    else
256	_collumn = c - (_IO_write_ptr - _IO_write_base);
257}
258#endif
259
260
261int streambuf::get_column()
262{
263    if (_cur_column)
264	return _IO_adjust_column(_cur_column - 1, pbase(), pptr() - pbase());
265    return -1;
266}
267
268int streambuf::set_column(int i)
269{
270    _cur_column = i+1;
271    return 0;
272}
273
274int streambuf::flush_all() { return _IO_flush_all (); }
275
276void streambuf::flush_all_linebuffered()
277{ _IO_flush_all_linebuffered(); }
278
279int streambuf::sys_stat(void *)
280{
281#ifdef EIO
282  errno = EIO;
283#endif
284  return -1;
285}
286
287streamsize streambuf::sys_read(char* /*buf*/, streamsize /*size*/)
288{
289  return 0;
290}
291
292streamsize streambuf::sys_write(const char* /*buf*/, streamsize /*size*/)
293{
294  return 0;
295}
296
297streampos streambuf::sys_seek(streamoff, _seek_dir)
298{
299  return EOF;
300}
301
302int streambuf::sys_close() { return 0; /* Suceess; do nothing */ }
303
304#if _G_IO_IO_FILE_VERSION == 0x20001
305int streambuf::showmanyc()
306{
307  return -1;
308}
309
310void streambuf::imbue(void *)
311{
312}
313#endif
314
315streammarker::streammarker(streambuf *sb)
316{
317  _IO_init_marker(this, sb);
318}
319
320streammarker::~streammarker()
321{
322  _IO_remove_marker(this);
323}
324
325#define BAD_DELTA EOF
326
327int streammarker::delta(streammarker& other_mark)
328{
329  return _IO_marker_difference(this, &other_mark);
330}
331
332int streammarker::delta()
333{
334  return _IO_marker_delta(this);
335}
336
337int streambuf::seekmark(streammarker& mark, int delta /* = 0 */)
338{
339  return _IO_seekmark(this, &mark, delta);
340}
341
342void streambuf::unsave_markers()
343{
344  _IO_unsave_markers(this);
345}
346
347int ios::readable() { return !(rdbuf()->_flags & _IO_NO_READS); }
348int ios::writable() { return !(rdbuf()->_flags & _IO_NO_WRITES); }
349int ios::is_open() { return rdbuf()
350			 && (rdbuf()->_flags & _IO_NO_READS+_IO_NO_WRITES)
351			     != _IO_NO_READS+_IO_NO_WRITES; }
352
353#if defined(linux)
354#define IO_CLEANUP
355#endif
356
357#ifdef IO_CLEANUP
358  IO_CLEANUP
359#else
360struct __io_defs {
361    ~__io_defs() { _IO_cleanup (); }
362};
363__io_defs io_defs__;
364#endif
365