summaryrefslogtreecommitdiff
path: root/reference/C/CONTRIB/SNIP/mystream.cpp
blob: 47767282f36377244360e5bbc53d6a846d980dec (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
// Mystream.cpp
// Implementation of ios interface classes for Myio
//
// Written by David L. Nugent
//

# include <iostream.h>
# include "Mystream.h"
# if defined(_MSC_VER)
#  include <memory.h>
# else
#  include <stdlib.h>
# endif

    // Mystreambuf constructor
    // This simply initialises the base class streambuf
    // (it is initially empty with no buffer allocated)
    // and register the Myio object
    // Note: we _could_ set the stream unbuffered here,
    // which is useful for stdio handles, so that the
    // streambuf functions overflow() and underflow()
    // get called on every character rather than when
    // the streambuf buffer is full

Mystreambuf::Mystreambuf (Myio * mPtr)
    : streambuf (), mptr(mPtr)
{
//  unbuffered(1);  // Uncomment to make unbuffered
}

    // Mystreambuf()
    // Called when streambuf owned buffer is full
    // or when stream is flushed
    // Our job here is to empty the streambuf
    // write buffer and reset the 'put' pointers.

int
Mystreambuf::overflow (int c)
{
    int written;

        // Handle unbuffered stream

    if (unbuffered())       // Handle the simple case first
    {
        if (c == EOF)   // Special case, this only flushes
            return 0;
        char ch = char(c);  // Write the byte directly
        written = mptr->write (&ch, 1);
        return (written) ? c : EOF;
    }

        // Handle buffered stream

    if (!base())        // Need to allocate a buffer
        allocate();

    if (base())         // Test for memory allocation error
    {
        char * ep = base() + (blen() / 2);
        if (!pbase())   // Set put pointers if not set up
            setp (base(), ep);
        int bytes = pptr() - pbase();   // Bytes to write
        if (bytes)
        {
            written = mptr->write (pbase(), bytes);
            if (!written)
                return EOF;
            bytes += written;
            if (bytes)  // Some is still waiting to be written
                memcpy (base(), base() + written, bytes);
        }
        setp (base() + bytes, ep);  // Reset 'put' pointers
        return (c == EOF) ? 0 : sputc (c);  // Put pending chr in buf
    }
    return EOF;
}

    //
    // underflow() indicates that the input queue
    // is empty and needs more data
    //

int
Mystreambuf::underflow (void)
{
    int bytes;

        // Handle an unbuffered stream

    if (unbuffered())
    {
        bytes = mptr->read (&_back[1], 1);
        if (!bytes)
        {
            setg (0, 0, 0);
            return EOF;
        }
        setg (_back, _back + 1, _back + 2);
        return (unsigned char)_back[1];
    }

        // Handle a buffered stream

    if (!base())        // Need to allocate a buffer
        allocate();

    if (base())
    {
        char * gp = base() + blen() / 2;
        if (gptr() >= egptr())
        {                   // Read into the buffer from stream
            overflow ();    // Flush output in case we need it
            bytes = mptr->read (gp + 1, blen() / 2 - 1);
            setg (gp, gp + 1, gp + bytes + 1);
        }
        if (gptr() < egptr())   // Get from buffer
            return (unsigned char) *gptr();
    }
    return EOF;
}

    //
    // sync() needs to empty both put and get
    // buffered. It will do this by calling
    // overflow and simply resetting the get
    // pointers to their default location.
    //

int
Mystreambuf::sync (void)
{
    if (!unbuffered())
    {
        overflow ();                // Force output
        char * gp = base();
        setp (gp, gp + blen() / 2);
        gp = base() + blen() / 2;
        setg (0, 0, 0);
    }
    return 0;
}