Rune - Further Object abstraction work
[rune.git] / classes / stdio / fwrite.d
1 # STDIO/FWRITE.D - output
2 #
3 # (c)Copyright 2020-2021, Matthew Dillon, All Rights Reserved.
4 #    See the COPYRIGHT file at the base of the Rune distribution.
5
6 public method
7 ssize_t
8 File.fwrite(void *buf, usize_t bytes)
9 {
10     ssize_t r = 0;
11
12     # If a regular file requires a flush prior to turn-around to
13     # ensure that any read-back sees the write.
14     #
15     if (this->flags & F_ISREG) {
16         if ((this->flags & F_OUT) == 0) {
17             this->flags |= F_OUT;
18             this->in.base = 0;
19             this->in.index = 0;
20         }
21     }
22
23     /*
24      * If unbuffered just write the data directly
25      * (we are guarenteed to be flushed and it doesn't
26      * matter if we are in input mode).
27      */
28     while (this->mode == File.M_NONE) {
29         ssize_t n = this->efd.write1(buf, bytes);
30         if (n <= 0L) {
31             if (n < 0 && this->efd.error == Sys.EINTR)
32                 continue;
33             return r;               # early return
34         }
35         buf = (string_rw_p)buf + n;
36         r += n;
37         bytes -= (usize_t)n;
38         this->pos += (off_t)n;
39     }
40
41     /*
42      * If we need an output buffer create one
43      */
44     if (this->out.buf == NULL) {
45         this->out.initbuf();
46     }
47
48     /*
49      * Copy to the buffer until the buffer is full
50      */
51     while (bytes != 0L) {
52         usize_t n = this->out.size - this->out.index;
53
54         if (n == 0L) {
55             if (this->fflush() < 0)
56                 break;
57             continue;
58         }
59         if (n > bytes)
60             n = bytes;
61         Sys.bcopy((string_rw_p)buf + r, &this->out.buf[this->out.index], n);
62         r += (ssize_t)n;
63         bytes -= n;
64         this->pos += (off_t)n;
65         this->out.index += (usize_t)n;
66     }
67
68     /*
69      * Line mode flush
70      */
71     if (this->mode == File.M_LINE &&
72         this->out.index != 0L &&
73         this->out.buf[this->out.index - 1L] == '\n'
74     ) {
75         int r2;
76
77         if ((r2 = this->fflush()) < 0)
78             r = (ssize_t)r2;
79     }
80     return(r);
81 }
82
83 public method
84 int
85 File.fputc(char c)
86 {
87     if (this->mode == File.M_NONE) {
88         if (this->efd.write(&c, 1) == 1L) {
89             ++this->pos;
90             return(0);
91         }
92         return(-1);
93     }
94
95     /*
96      * If we need an output buffer create one
97      */
98     if (this->out.buf == NULL)
99         this->out.initbuf();
100
101     /*
102      * Copy data to buffer
103      */
104     if (this->out.index == this->out.size) {
105         if (this->fflush() < 0)
106             return(-1);
107     }
108     this->out.buf[this->out.index] = c;
109     ++this->out.index;
110     ++this->pos;
111
112     /*
113      * Line mode flush
114      */
115     if (this->mode == File.M_LINE && c == '\n')
116         return(this->fflush());
117     else
118         return(0);
119 }
120
121 public method
122 int
123 File.fflush()
124 {
125     usize_t r = 0;
126
127     if (this->out.index != 0L) {
128         while (r != this->out.index) {
129             ssize_t n;
130
131             n = this->efd.write(&this->out.buf[0] + r,
132                               this->out.index - r);
133             if (n < 0L)
134                 return((int)n);
135             r += (usize_t)n;
136         }
137         if (r != 0L && r != this->out.index) {
138             Sys.bcopy(&this->out.buf[r], &this->out.buf[0], this->out.index - r);
139         }
140         this->out.index -= r;
141     }
142     return(0);
143 }