2018-07-19 16:04:20 -04:00
|
|
|
/***********************************************************************************************************************************
|
2018-08-14 14:21:53 -04:00
|
|
|
IO Write Interface
|
2018-07-19 16:04:20 -04:00
|
|
|
***********************************************************************************************************************************/
|
2019-04-26 08:08:23 -04:00
|
|
|
#include "build.auto.h"
|
|
|
|
|
2018-10-07 17:50:10 +01:00
|
|
|
#include <string.h>
|
|
|
|
|
2018-07-19 16:04:20 -04:00
|
|
|
#include "common/debug.h"
|
2018-08-14 14:21:53 -04:00
|
|
|
#include "common/io/io.h"
|
2018-09-15 21:07:00 -04:00
|
|
|
#include "common/io/write.intern.h"
|
2018-07-19 16:04:20 -04:00
|
|
|
#include "common/log.h"
|
|
|
|
#include "common/memContext.h"
|
2019-05-03 18:52:54 -04:00
|
|
|
#include "common/object.h"
|
2018-07-19 16:04:20 -04:00
|
|
|
|
|
|
|
/***********************************************************************************************************************************
|
2018-08-14 14:21:53 -04:00
|
|
|
Object type
|
2018-07-19 16:04:20 -04:00
|
|
|
***********************************************************************************************************************************/
|
|
|
|
struct IoWrite
|
|
|
|
{
|
2019-05-03 15:46:15 -04:00
|
|
|
MemContext *memContext; // Mem context
|
2018-07-19 16:04:20 -04:00
|
|
|
void *driver; // Driver object
|
2018-09-15 21:07:00 -04:00
|
|
|
IoWriteInterface interface; // Driver interface
|
2018-07-24 21:08:27 -04:00
|
|
|
IoFilterGroup *filterGroup; // IO filters
|
2018-08-14 14:21:53 -04:00
|
|
|
Buffer *output; // Output buffer
|
2018-07-24 21:08:27 -04:00
|
|
|
|
2018-08-14 14:21:53 -04:00
|
|
|
#ifdef DEBUG
|
2019-04-20 11:25:04 -04:00
|
|
|
bool filterGroupSet; // Was an IoFilterGroup set?
|
2018-08-14 14:21:53 -04:00
|
|
|
bool opened; // Has the io been opened?
|
|
|
|
bool closed; // Has the io been closed?
|
|
|
|
#endif
|
2018-07-19 16:04:20 -04:00
|
|
|
};
|
|
|
|
|
2019-05-03 18:52:54 -04:00
|
|
|
OBJECT_DEFINE_FREE(IO_WRITE);
|
|
|
|
|
2018-07-19 16:04:20 -04:00
|
|
|
/***********************************************************************************************************************************
|
2018-08-14 14:21:53 -04:00
|
|
|
New object
|
2018-07-19 16:04:20 -04:00
|
|
|
***********************************************************************************************************************************/
|
|
|
|
IoWrite *
|
2018-09-15 21:07:00 -04:00
|
|
|
ioWriteNew(void *driver, IoWriteInterface interface)
|
2018-07-19 16:04:20 -04:00
|
|
|
{
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
2019-01-28 22:33:29 +02:00
|
|
|
FUNCTION_LOG_PARAM_P(VOID, driver);
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_PARAM(IO_WRITE_INTERFACE, interface);
|
|
|
|
FUNCTION_LOG_END();
|
2018-07-19 16:04:20 -04:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
ASSERT(driver != NULL);
|
|
|
|
ASSERT(interface.write != NULL);
|
2018-07-19 16:04:20 -04:00
|
|
|
|
2018-11-15 16:25:46 -05:00
|
|
|
IoWrite *this = NULL;
|
|
|
|
|
|
|
|
MEM_CONTEXT_NEW_BEGIN("IoWrite")
|
|
|
|
{
|
|
|
|
this = memNew(sizeof(IoWrite));
|
|
|
|
this->memContext = memContextCurrent();
|
|
|
|
this->driver = driver;
|
|
|
|
this->interface = interface;
|
|
|
|
this->output = bufNew(ioBufferSize());
|
|
|
|
}
|
|
|
|
MEM_CONTEXT_NEW_END();
|
2018-07-19 16:04:20 -04:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_RETURN(IO_WRITE, this);
|
2018-07-19 16:04:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Open the IO
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
void
|
|
|
|
ioWriteOpen(IoWrite *this)
|
|
|
|
{
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
|
|
FUNCTION_LOG_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_LOG_END();
|
2018-07-19 16:04:20 -04:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
ASSERT(this != NULL);
|
|
|
|
ASSERT(!this->opened && !this->closed);
|
2018-07-19 16:04:20 -04:00
|
|
|
|
2018-09-15 21:07:00 -04:00
|
|
|
if (this->interface.open != NULL)
|
|
|
|
this->interface.open(this->driver);
|
2018-07-19 16:04:20 -04:00
|
|
|
|
2018-08-14 14:21:53 -04:00
|
|
|
// If no filter group exists create one to do buffering
|
|
|
|
if (this->filterGroup == NULL)
|
2019-06-13 12:44:40 -04:00
|
|
|
{
|
|
|
|
MEM_CONTEXT_BEGIN(this->memContext)
|
|
|
|
{
|
|
|
|
this->filterGroup = ioFilterGroupNew();
|
|
|
|
}
|
|
|
|
MEM_CONTEXT_END();
|
|
|
|
}
|
2018-08-14 14:21:53 -04:00
|
|
|
|
|
|
|
ioFilterGroupOpen(this->filterGroup);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
this->opened = true;
|
|
|
|
#endif
|
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
2018-07-19 16:04:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************************************************************************
|
2018-08-14 14:21:53 -04:00
|
|
|
Write data to IO and process filters
|
2018-07-19 16:04:20 -04:00
|
|
|
***********************************************************************************************************************************/
|
|
|
|
void
|
|
|
|
ioWrite(IoWrite *this, const Buffer *buffer)
|
|
|
|
{
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
|
|
FUNCTION_LOG_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_LOG_PARAM(BUFFER, buffer);
|
|
|
|
FUNCTION_LOG_END();
|
2018-07-19 16:04:20 -04:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
ASSERT(this != NULL);
|
|
|
|
ASSERT(this->opened && !this->closed);
|
2018-07-19 16:04:20 -04:00
|
|
|
|
|
|
|
// Only write if there is data to write
|
2018-08-14 14:21:53 -04:00
|
|
|
if (buffer != NULL && bufUsed(buffer) > 0)
|
2018-07-19 16:04:20 -04:00
|
|
|
{
|
2018-08-14 14:21:53 -04:00
|
|
|
do
|
|
|
|
{
|
|
|
|
ioFilterGroupProcess(this->filterGroup, buffer, this->output);
|
|
|
|
|
|
|
|
// Write data if the buffer is full
|
|
|
|
if (bufRemains(this->output) == 0)
|
|
|
|
{
|
2018-09-15 21:07:00 -04:00
|
|
|
this->interface.write(this->driver, this->output);
|
2018-08-14 14:21:53 -04:00
|
|
|
bufUsedZero(this->output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (ioFilterGroupInputSame(this->filterGroup));
|
2018-07-19 16:04:20 -04:00
|
|
|
}
|
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
2018-07-19 16:04:20 -04:00
|
|
|
}
|
|
|
|
|
2018-10-07 17:50:10 +01:00
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Write linefeed-terminated string
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
void
|
2019-04-22 18:46:29 -04:00
|
|
|
ioWriteLine(IoWrite *this, const Buffer *buffer)
|
|
|
|
{
|
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
|
|
FUNCTION_LOG_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_LOG_PARAM(BUFFER, buffer);
|
|
|
|
FUNCTION_LOG_END();
|
|
|
|
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
ASSERT(buffer != NULL);
|
|
|
|
|
|
|
|
ioWrite(this, buffer);
|
|
|
|
ioWrite(this, LF_BUF);
|
|
|
|
|
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Write string
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
void
|
|
|
|
ioWriteStr(IoWrite *this, const String *string)
|
|
|
|
{
|
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
|
|
FUNCTION_LOG_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_LOG_PARAM(STRING, string);
|
|
|
|
FUNCTION_LOG_END();
|
|
|
|
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
ASSERT(string != NULL);
|
|
|
|
|
|
|
|
ioWrite(this, BUFSTR(string));
|
|
|
|
|
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Write linefeed-terminated string
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
void
|
|
|
|
ioWriteStrLine(IoWrite *this, const String *string)
|
2018-10-07 17:50:10 +01:00
|
|
|
{
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
|
|
FUNCTION_LOG_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_LOG_PARAM(STRING, string);
|
|
|
|
FUNCTION_LOG_END();
|
2018-10-07 17:50:10 +01:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
ASSERT(this != NULL);
|
|
|
|
ASSERT(string != NULL);
|
2018-10-07 17:50:10 +01:00
|
|
|
|
2019-04-20 08:16:17 -04:00
|
|
|
ioWrite(this, BUFSTR(string));
|
|
|
|
ioWrite(this, LF_BUF);
|
2018-10-07 17:50:10 +01:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
2018-10-07 17:50:10 +01:00
|
|
|
}
|
|
|
|
|
2018-11-14 08:53:42 -05:00
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Flush any data in the output buffer
|
|
|
|
|
|
|
|
This does not end writing and if there are filters that are not done it might not have the intended effect.
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
void
|
|
|
|
ioWriteFlush(IoWrite *this)
|
|
|
|
{
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
|
|
FUNCTION_LOG_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_LOG_END();
|
2018-11-14 08:53:42 -05:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
ASSERT(this != NULL);
|
|
|
|
ASSERT(this->opened && !this->closed);
|
2019-04-20 11:25:04 -04:00
|
|
|
ASSERT(!this->filterGroupSet);
|
2018-11-14 08:53:42 -05:00
|
|
|
|
|
|
|
if (bufUsed(this->output) > 0)
|
|
|
|
{
|
|
|
|
this->interface.write(this->driver, this->output);
|
|
|
|
bufUsedZero(this->output);
|
|
|
|
}
|
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
2018-11-14 08:53:42 -05:00
|
|
|
}
|
|
|
|
|
2018-07-19 16:04:20 -04:00
|
|
|
/***********************************************************************************************************************************
|
2018-08-14 14:21:53 -04:00
|
|
|
Close the IO and write any additional data that has not been written yet
|
2018-07-19 16:04:20 -04:00
|
|
|
***********************************************************************************************************************************/
|
|
|
|
void
|
|
|
|
ioWriteClose(IoWrite *this)
|
|
|
|
{
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
|
|
FUNCTION_LOG_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_LOG_END();
|
2018-07-19 16:04:20 -04:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
ASSERT(this != NULL);
|
|
|
|
ASSERT(this->opened && !this->closed);
|
2018-07-19 16:04:20 -04:00
|
|
|
|
2018-08-14 14:21:53 -04:00
|
|
|
// Flush remaining data
|
|
|
|
do
|
|
|
|
{
|
|
|
|
ioFilterGroupProcess(this->filterGroup, NULL, this->output);
|
|
|
|
|
|
|
|
// Write data if the buffer is full or if this is the last buffer to be written
|
|
|
|
if (bufRemains(this->output) == 0 || (ioFilterGroupDone(this->filterGroup) && bufUsed(this->output) > 0))
|
|
|
|
{
|
2018-09-15 21:07:00 -04:00
|
|
|
this->interface.write(this->driver, this->output);
|
2018-08-14 14:21:53 -04:00
|
|
|
bufUsedZero(this->output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (!ioFilterGroupDone(this->filterGroup));
|
|
|
|
|
2018-07-24 21:08:27 -04:00
|
|
|
// Close the filter group and gather results
|
2018-08-14 14:21:53 -04:00
|
|
|
ioFilterGroupClose(this->filterGroup);
|
2018-07-24 21:08:27 -04:00
|
|
|
|
|
|
|
// Close the driver if there is a close function
|
2018-09-15 21:07:00 -04:00
|
|
|
if (this->interface.close != NULL)
|
|
|
|
this->interface.close(this->driver);
|
2018-07-19 16:04:20 -04:00
|
|
|
|
2018-08-14 14:21:53 -04:00
|
|
|
#ifdef DEBUG
|
|
|
|
this->closed = true;
|
|
|
|
#endif
|
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_RETURN_VOID();
|
2018-07-19 16:04:20 -04:00
|
|
|
}
|
|
|
|
|
2019-05-02 17:52:24 -04:00
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Interface for the write object
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
void *
|
|
|
|
ioWriteDriver(IoWrite *this)
|
|
|
|
{
|
|
|
|
FUNCTION_TEST_BEGIN();
|
|
|
|
FUNCTION_TEST_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_TEST_END();
|
|
|
|
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
|
|
|
|
FUNCTION_TEST_RETURN(this->driver);
|
|
|
|
}
|
|
|
|
|
2018-07-24 21:08:27 -04:00
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Get/set filters
|
|
|
|
|
|
|
|
Filters must be set before open and cannot be reset.
|
|
|
|
***********************************************************************************************************************************/
|
2019-06-04 12:56:04 -04:00
|
|
|
IoFilterGroup *
|
2018-07-24 21:08:27 -04:00
|
|
|
ioWriteFilterGroup(const IoWrite *this)
|
|
|
|
{
|
|
|
|
FUNCTION_TEST_BEGIN();
|
|
|
|
FUNCTION_TEST_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_TEST_END();
|
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
ASSERT(this != NULL);
|
|
|
|
|
2019-01-28 15:06:28 +02:00
|
|
|
FUNCTION_TEST_RETURN(this->filterGroup);
|
2018-07-24 21:08:27 -04:00
|
|
|
}
|
|
|
|
|
2019-06-07 10:35:44 -04:00
|
|
|
IoWrite *
|
2018-07-24 21:08:27 -04:00
|
|
|
ioWriteFilterGroupSet(IoWrite *this, IoFilterGroup *filterGroup)
|
|
|
|
{
|
2019-01-21 17:41:59 +02:00
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
|
|
FUNCTION_LOG_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_LOG_PARAM(IO_FILTER_GROUP, filterGroup);
|
|
|
|
FUNCTION_LOG_END();
|
2018-07-24 21:08:27 -04:00
|
|
|
|
2019-01-21 17:41:59 +02:00
|
|
|
ASSERT(this != NULL);
|
|
|
|
ASSERT(filterGroup != NULL);
|
|
|
|
ASSERT(this->filterGroup == NULL);
|
|
|
|
ASSERT(!this->opened && !this->closed);
|
2018-07-24 21:08:27 -04:00
|
|
|
|
2019-04-20 11:25:04 -04:00
|
|
|
// Track whether a filter group was set to prevent flush() from being called later
|
|
|
|
#ifdef DEBUG
|
|
|
|
this->filterGroupSet = true;
|
|
|
|
#endif
|
|
|
|
|
2019-06-04 12:56:04 -04:00
|
|
|
this->filterGroup = ioFilterGroupMove(filterGroup, this->memContext);
|
2018-07-24 21:08:27 -04:00
|
|
|
|
2019-06-07 10:35:44 -04:00
|
|
|
FUNCTION_LOG_RETURN(IO_WRITE, this);
|
2018-07-24 21:08:27 -04:00
|
|
|
}
|
2018-11-15 16:25:46 -05:00
|
|
|
|
2019-04-29 14:54:49 -04:00
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Handle (file descriptor) for the write object
|
|
|
|
|
|
|
|
No all write objects have a handle and -1 will be returned in that case.
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
int
|
|
|
|
ioWriteHandle(const IoWrite *this)
|
|
|
|
{
|
|
|
|
FUNCTION_LOG_BEGIN(logLevelTrace);
|
|
|
|
FUNCTION_LOG_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_LOG_END();
|
|
|
|
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
|
|
|
|
FUNCTION_LOG_RETURN(INT, this->interface.handle == NULL ? -1 : this->interface.handle(this->driver));
|
|
|
|
}
|
|
|
|
|
2019-05-02 17:52:24 -04:00
|
|
|
/***********************************************************************************************************************************
|
|
|
|
Interface for the write object
|
|
|
|
***********************************************************************************************************************************/
|
|
|
|
const IoWriteInterface *
|
|
|
|
ioWriteInterface(const IoWrite *this)
|
|
|
|
{
|
|
|
|
FUNCTION_TEST_BEGIN();
|
|
|
|
FUNCTION_TEST_PARAM(IO_WRITE, this);
|
|
|
|
FUNCTION_TEST_END();
|
|
|
|
|
|
|
|
ASSERT(this != NULL);
|
|
|
|
|
|
|
|
FUNCTION_TEST_RETURN(&this->interface);
|
|
|
|
}
|