aboutsummaryrefslogtreecommitdiff
path: root/src/bufio/writer.c
blob: 07573d5757def85caf7e3e4e0bda444975a6862c (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
#include "impl.h"

struct bufio·Writer
{
    io·Writer w;
    Buffer    buf;
};

// Constructor/destructor.

bufio·Writer*
bufio·newwriter(io·Writer w)
{
    bufio·Writer* bw = newbuffer(offsetof(bufio·Writer, buf), 0);
    bw->w            = w;
    bw->buf.pos      = bw->buf.base;

    return bw;
}

error
bufio·freewriter(bufio·Writer* w)
{
    free(w);

    return 0;
}

// Write will write n bytes from the input buffer into the storage buffer.
// Returns the actual number of bytes written.
int
bufio·write(bufio·Writer* w, byte* buf, int count)
{
    int   remain = count;
    byte* wtr    = buf;

    int n, nw;
    while (remain > 0) {
        int bdiff = w->buf.end - w->buf.pos;
        n         = (bdiff > remain) ? remain : bdiff;
        if (!n) {
            if (w->buf.eof) break;
            nw = w->w.write(w->w.impl, buf, count);
            if (nw < w->buf.size) {
                w->buf.eof = 1;
                return BUF·err;
            }
            w->buf.off += nw;
            w->buf.pos = w->buf.base;
        }
        memmove(w->buf.pos, wtr, n);
        wtr += n;
        w->buf.pos += n;
        remain -= n;
    }

    return count - remain;
}

error
bufio·put(bufio·Writer* w, byte c)
{
    int diff;
putbyte:
    diff = w->buf.end - w->buf.pos;
    if (diff) {
        *w->buf.pos++ = c;
        return 0;
    }
    if (bufio·flush(w) != BUF·err) goto putbyte;

    return BUF·err;
}

error
bufio·flush(bufio·Writer* w)
{
    int active = (w->buf.eof == 0);

    int n, nw;
    if (active && w) {
        n = w->buf.pos - w->buf.base;
        if (!n) return 0;

        nw = w->w.write(w->w.impl, w->buf.base, n);
        if (nw == n) {
            w->buf.off += n;
            return 0;
        }
        w->buf.eof = 1;
        w->buf.pos = w->buf.end;
    }

    return BUF·err;
}