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