summaryrefslogtreecommitdiff
path: root/gnu/lib/libg++/iostream/streambuf.h
blob: 6beaeb6284c8feffc73ee563bbebbc4125291d8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
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 */