1 /***********************************************************************************************************************************
2 IO Write Interface
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5
6 #include <string.h>
7
8 #include "common/debug.h"
9 #include "common/io/io.h"
10 #include "common/io/write.h"
11 #include "common/log.h"
12 #include "common/memContext.h"
13
14 /***********************************************************************************************************************************
15 Object type
16 ***********************************************************************************************************************************/
17 struct IoWrite
18 {
19 IoWritePub pub; // Publicly accessible variables
20 void *driver; // Driver object
21 IoWriteInterface interface; // Driver interface
22 Buffer *output; // Output buffer
23
24 #ifdef DEBUG
25 bool filterGroupSet; // Were filters set?
26 bool opened; // Has the io been opened?
27 bool closed; // Has the io been closed?
28 #endif
29 };
30
31 /**********************************************************************************************************************************/
32 IoWrite *
ioWriteNew(void * driver,IoWriteInterface interface)33 ioWriteNew(void *driver, IoWriteInterface interface)
34 {
35 FUNCTION_LOG_BEGIN(logLevelTrace);
36 FUNCTION_LOG_PARAM_P(VOID, driver);
37 FUNCTION_LOG_PARAM(IO_WRITE_INTERFACE, interface);
38 FUNCTION_LOG_END();
39
40 ASSERT(driver != NULL);
41 ASSERT(interface.write != NULL);
42
43 IoWrite *this = NULL;
44
45 MEM_CONTEXT_NEW_BEGIN("IoWrite")
46 {
47 this = memNew(sizeof(IoWrite));
48
49 *this = (IoWrite)
50 {
51 .pub =
52 {
53 .memContext = memContextCurrent(),
54 .filterGroup = ioFilterGroupNew(),
55 },
56 .driver = driver,
57 .interface = interface,
58 .output = bufNew(ioBufferSize()),
59 };
60 }
61 MEM_CONTEXT_NEW_END();
62
63 FUNCTION_LOG_RETURN(IO_WRITE, this);
64 }
65
66 /**********************************************************************************************************************************/
67 void
ioWriteOpen(IoWrite * this)68 ioWriteOpen(IoWrite *this)
69 {
70 FUNCTION_LOG_BEGIN(logLevelTrace);
71 FUNCTION_LOG_PARAM(IO_WRITE, this);
72 FUNCTION_LOG_END();
73
74 ASSERT(this != NULL);
75 ASSERT(!this->opened && !this->closed);
76
77 if (this->interface.open != NULL)
78 this->interface.open(this->driver);
79
80 // Track whether filters were added to prevent flush() from being called later since flush() won't work with most filters
81 #ifdef DEBUG
82 this->filterGroupSet = ioFilterGroupSize(this->pub.filterGroup) > 0;
83 #endif
84
85 // Open the filter group
86 ioFilterGroupOpen(this->pub.filterGroup);
87
88 #ifdef DEBUG
89 this->opened = true;
90 #endif
91
92 FUNCTION_LOG_RETURN_VOID();
93 }
94
95 /**********************************************************************************************************************************/
96 void
ioWrite(IoWrite * this,const Buffer * buffer)97 ioWrite(IoWrite *this, const Buffer *buffer)
98 {
99 FUNCTION_LOG_BEGIN(logLevelTrace);
100 FUNCTION_LOG_PARAM(IO_WRITE, this);
101 FUNCTION_LOG_PARAM(BUFFER, buffer);
102 FUNCTION_LOG_END();
103
104 ASSERT(this != NULL);
105 ASSERT(this->opened && !this->closed);
106
107 // Only write if there is data to write
108 if (buffer != NULL && !bufEmpty(buffer))
109 {
110 do
111 {
112 ioFilterGroupProcess(this->pub.filterGroup, buffer, this->output);
113
114 // Write data if the buffer is full
115 if (bufRemains(this->output) == 0)
116 {
117 this->interface.write(this->driver, this->output);
118 bufUsedZero(this->output);
119 }
120 }
121 while (ioFilterGroupInputSame(this->pub.filterGroup));
122 }
123
124 FUNCTION_LOG_RETURN_VOID();
125 }
126
127 /**********************************************************************************************************************************/
128 void
ioWriteLine(IoWrite * this,const Buffer * buffer)129 ioWriteLine(IoWrite *this, const Buffer *buffer)
130 {
131 FUNCTION_LOG_BEGIN(logLevelTrace);
132 FUNCTION_LOG_PARAM(IO_WRITE, this);
133 FUNCTION_LOG_PARAM(BUFFER, buffer);
134 FUNCTION_LOG_END();
135
136 ASSERT(this != NULL);
137 ASSERT(buffer != NULL);
138
139 ioWrite(this, buffer);
140 ioWrite(this, LF_BUF);
141
142 FUNCTION_LOG_RETURN_VOID();
143 }
144
145 /**********************************************************************************************************************************/
146 bool
ioWriteReady(IoWrite * this,IoWriteReadyParam param)147 ioWriteReady(IoWrite *this, IoWriteReadyParam param)
148 {
149 FUNCTION_LOG_BEGIN(logLevelTrace);
150 FUNCTION_LOG_PARAM(IO_WRITE, this);
151 FUNCTION_LOG_PARAM(BOOL, param.error);
152 FUNCTION_LOG_END();
153
154 ASSERT(this != NULL);
155
156 bool result = true;
157
158 if (this->interface.ready != NULL)
159 result = this->interface.ready(this->driver, param.error);
160
161 FUNCTION_LOG_RETURN(BOOL, result);
162 }
163
164 /**********************************************************************************************************************************/
165 void
ioWriteStr(IoWrite * this,const String * string)166 ioWriteStr(IoWrite *this, const String *string)
167 {
168 FUNCTION_LOG_BEGIN(logLevelTrace);
169 FUNCTION_LOG_PARAM(IO_WRITE, this);
170 FUNCTION_LOG_PARAM(STRING, string);
171 FUNCTION_LOG_END();
172
173 ASSERT(this != NULL);
174 ASSERT(string != NULL);
175
176 ioWrite(this, BUFSTR(string));
177
178 FUNCTION_LOG_RETURN_VOID();
179 }
180
181 /**********************************************************************************************************************************/
182 void
ioWriteStrLine(IoWrite * this,const String * string)183 ioWriteStrLine(IoWrite *this, const String *string)
184 {
185 FUNCTION_LOG_BEGIN(logLevelTrace);
186 FUNCTION_LOG_PARAM(IO_WRITE, this);
187 FUNCTION_LOG_PARAM(STRING, string);
188 FUNCTION_LOG_END();
189
190 ASSERT(this != NULL);
191 ASSERT(string != NULL);
192
193 ioWrite(this, BUFSTR(string));
194 ioWrite(this, LF_BUF);
195
196 FUNCTION_LOG_RETURN_VOID();
197 }
198
199 /**********************************************************************************************************************************/
200 void
ioWriteFlush(IoWrite * this)201 ioWriteFlush(IoWrite *this)
202 {
203 FUNCTION_LOG_BEGIN(logLevelTrace);
204 FUNCTION_LOG_PARAM(IO_WRITE, this);
205 FUNCTION_LOG_END();
206
207 ASSERT(this != NULL);
208 ASSERT(this->opened && !this->closed);
209 ASSERT(!this->filterGroupSet);
210
211 if (!bufEmpty(this->output))
212 {
213 this->interface.write(this->driver, this->output);
214 bufUsedZero(this->output);
215 }
216
217 FUNCTION_LOG_RETURN_VOID();
218 }
219
220 /**********************************************************************************************************************************/
221 void
ioWriteClose(IoWrite * this)222 ioWriteClose(IoWrite *this)
223 {
224 FUNCTION_LOG_BEGIN(logLevelTrace);
225 FUNCTION_LOG_PARAM(IO_WRITE, this);
226 FUNCTION_LOG_END();
227
228 ASSERT(this != NULL);
229 ASSERT(this->opened && !this->closed);
230
231 // Flush remaining data
232 do
233 {
234 ioFilterGroupProcess(this->pub.filterGroup, NULL, this->output);
235
236 // Write data if the buffer is full or if this is the last buffer to be written
237 if (bufRemains(this->output) == 0 || (ioFilterGroupDone(this->pub.filterGroup) && !bufEmpty(this->output)))
238 {
239 this->interface.write(this->driver, this->output);
240 bufUsedZero(this->output);
241 }
242 }
243 while (!ioFilterGroupDone(this->pub.filterGroup));
244
245 // Close the filter group and gather results
246 ioFilterGroupClose(this->pub.filterGroup);
247
248 // Close the driver if there is a close function
249 if (this->interface.close != NULL)
250 this->interface.close(this->driver);
251
252 #ifdef DEBUG
253 this->closed = true;
254 #endif
255
256 FUNCTION_LOG_RETURN_VOID();
257 }
258
259 /**********************************************************************************************************************************/
260 int
ioWriteFd(const IoWrite * this)261 ioWriteFd(const IoWrite *this)
262 {
263 FUNCTION_LOG_BEGIN(logLevelTrace);
264 FUNCTION_LOG_PARAM(IO_WRITE, this);
265 FUNCTION_LOG_END();
266
267 ASSERT(this != NULL);
268
269 FUNCTION_LOG_RETURN(INT, this->interface.fd == NULL ? -1 : this->interface.fd(this->driver));
270 }
271