|
|
|
|
|
|
|
|
*/ |
|
|
*/ |
|
|
void put(char const *ptr, size_t nBytes); |
|
|
void put(char const *ptr, size_t nBytes); |
|
|
|
|
|
|
|
|
/** Check whether specified data is present in the buffer. |
|
|
|
|
|
|
|
|
|
|
|
This method check whether the specified data is present in |
|
|
|
|
|
the buffer, and provides the number of characters before the |
|
|
|
|
|
specified data. |
|
|
|
|
|
|
|
|
|
|
|
@param[in] delimiter is the specified data. |
|
|
|
|
|
|
|
|
|
|
|
@param[out] nBytesBefore is the number of bytes before the |
|
|
|
|
|
specified data. |
|
|
|
|
|
|
|
|
|
|
|
@returns true if the delimiter is present in the buffer, |
|
|
|
|
|
false otherwise. |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
template<type U> |
|
|
|
|
|
bool checkForDelimiter(U &delimiter, size_t &nbytesBefore) { |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Get bytes from the buffer. |
|
|
/** Get bytes from the buffer. |
|
|
|
|
|
|
|
|
This method gets the specified number of bytes from the |
|
|
This method gets the specified number of bytes from the |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Check whether specified data is present in the buffer. |
|
|
|
|
|
|
|
|
|
|
|
This method check whether the specified data is present in |
|
|
|
|
|
the buffer, and provides the number of characters before the |
|
|
|
|
|
specified data. |
|
|
|
|
|
|
|
|
|
|
|
The type U must have the following methods: |
|
|
|
|
|
|
|
|
|
|
|
<ol> |
|
|
|
|
|
|
|
|
|
|
|
<li>Methods required by CircularBuffer::match().</li> |
|
|
|
|
|
|
|
|
|
|
|
<li>size().</li> |
|
|
|
|
|
|
|
|
|
|
|
</ol> |
|
|
|
|
|
|
|
|
|
|
|
Both std::vector<char> and std::string can be used for T. |
|
|
|
|
|
|
|
|
|
|
|
@param[in] data is the specified data. |
|
|
|
|
|
|
|
|
|
|
|
@param[out] nBytesBefore is the number of bytes before the |
|
|
|
|
|
specified data. |
|
|
|
|
|
|
|
|
|
|
|
@returns true if the data is present in the buffer, false |
|
|
|
|
|
otherwise. |
|
|
|
|
|
|
|
|
|
|
|
@see CircularBuffer::match(). |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
template<typename U> |
|
|
|
|
|
bool dataIsPresent(U const &data, size_t &nBytesBefore) const { |
|
|
|
|
|
|
|
|
|
|
|
size_t iLocalBegin = iBegin; |
|
|
|
|
|
|
|
|
|
|
|
if (nUsed() < data.size()) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
size_t nToCheck = nUsed() - data.size() + 1; |
|
|
|
|
|
for (nBytesBefore = 0; nBytesBefore < nToCheck; nBytesBefore++) { |
|
|
|
|
|
|
|
|
|
|
|
if (match(data, iLocalBegin)) { |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
nextIndex(iLocalBegin); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
|
|
|
|
|
|
/** Increment the index. |
|
|
/** Increment the index. |
|
|
|
|
|
|
|
|
index = 0; |
|
|
index = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Check whether the specified data is in the buffer. |
|
|
|
|
|
|
|
|
|
|
|
This method checks whether the specified data is present in |
|
|
|
|
|
the buffer starting at the specified location. |
|
|
|
|
|
|
|
|
|
|
|
The type U must have the following methods: |
|
|
|
|
|
|
|
|
|
|
|
<ol> |
|
|
|
|
|
|
|
|
|
|
|
<li>operator[].</li> |
|
|
|
|
|
|
|
|
|
|
|
<li>size().</li> |
|
|
|
|
|
|
|
|
|
|
|
</ol> |
|
|
|
|
|
|
|
|
|
|
|
@param[in] data is the specified data. |
|
|
|
|
|
|
|
|
|
|
|
@param[in] index is the index of the buffer to start |
|
|
|
|
|
checking for the specified data. |
|
|
|
|
|
|
|
|
|
|
|
@returns true if the specified data is in the buffer, false |
|
|
|
|
|
otherwise. |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
template<typename U> |
|
|
|
|
|
bool match(U &data, size_t indx) const { |
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < data.size(); i++) { |
|
|
|
|
|
|
|
|
|
|
|
if (iEnd == indx) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
if (data[i] != buffer[indx]) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
nextIndex(indx); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/// Buffer to hold data. |
|
|
/// Buffer to hold data. |
|
|
std::vector<char> buffer; |
|
|
std::vector<char> buffer; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li>size().</li> |
|
|
<li>size().</li> |
|
|
|
|
|
|
|
|
|
|
|
<li>clear().</li> |
|
|
|
|
|
|
|
|
|
|
|
</ol> |
|
|
|
|
|
|
|
|
|
|
|
The type U must have the following methods: |
|
|
|
|
|
|
|
|
|
|
|
<ol> |
|
|
|
|
|
|
|
|
|
|
|
<li>Methods required by CircularBuffer::dataIsPresent().</li> |
|
|
|
|
|
|
|
|
|
|
|
<li>size().</li> |
|
|
|
|
|
|
|
|
|
|
|
<li>empty().</li> |
|
|
|
|
|
|
|
|
</ol> |
|
|
</ol> |
|
|
|
|
|
|
|
|
Both std::vector<char> and std::string can be used for T and U. |
|
|
Both std::vector<char> and std::string can be used for T and U. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@see CircularBuffer::getAndErase(). |
|
|
@see CircularBuffer::getAndErase(). |
|
|
|
|
|
|
|
|
|
|
|
@see CircularBuffer::dataIsPresent(). |
|
|
|
|
|
|
|
|
*/ |
|
|
*/ |
|
|
template<typename T, typename U> |
|
|
template<typename T, typename U> |
|
|
bool readDelimited(T &data, U &delimiter) { |
|
|
|
|
|
|
|
|
bool readDelimited(T &data, U const &delimiter) { |
|
|
|
|
|
|
|
|
if (!isRunning()) { |
|
|
if (!isRunning()) { |
|
|
throw std::logic_error("No child process is running."); |
|
|
throw std::logic_error("No child process is running."); |
|
|
|
|
|
|
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Empty delimiter always matches. |
|
|
|
|
|
if (delimiter.empty()) { |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(readBufferMutex); |
|
|
std::lock_guard<std::mutex> lock(readBufferMutex); |
|
|
|
|
|
|
|
|
size_t nBytesToRead = nBytes; |
|
|
|
|
|
|
|
|
size_t nBytesToRead; |
|
|
|
|
|
|
|
|
if (nBytesToRead > readBuffer.nUsed()) { |
|
|
|
|
|
nBytesToRead = readBuffer.nUsed(); |
|
|
|
|
|
|
|
|
// Check for the presence of the delimiter. |
|
|
|
|
|
if (!readBuffer.dataIsPresent(delimiter, nBytesToRead)) { |
|
|
|
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
readBuffer.getAndErase(data, nBytesToRead); |
|
|
|
|
|
|
|
|
|
|
|
return data.size(); |
|
|
|
|
|
|
|
|
// Read the data. |
|
|
|
|
|
if (nBytesToRead > 0) { |
|
|
|
|
|
readBuffer.getAndErase(data, nBytesToRead); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Discard the delimiter. |
|
|
|
|
|
T temp; |
|
|
|
|
|
|
|
|
|
|
|
readBuffer.getAndErase(temp, delimiter.size()); |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Non-blocking request to get data up to a delimiter read from |
|
|
|
|
|
the child. |
|
|
|
|
|
|
|
|
|
|
|
This method check whether the specified delimiter is in the |
|
|
|
|
|
data received from the child. |
|
|
|
|
|
|
|
|
|
|
|
This method attempts to get data up to and not including a |
|
|
|
|
|
specified delimiter from the input buffer containing data |
|
|
|
|
|
received from the child. The data that is provided and the |
|
|
|
|
|
delimiter are erased from the input buffer. |
|
|
|
|
|
|
|
|
|
|
|
The type T must have the following methods: |
|
|
|
|
|
|
|
|
|
|
|
<ol> |
|
|
|
|
|
|
|
|
|
|
|
<li>Methods required by CircularBuffer::getAndErase().</li> |
|
|
|
|
|
|
|
|
|
|
|
<li>size().</li> |
|
|
|
|
|
|
|
|
|
|
|
<li>clear().</li> |
|
|
|
|
|
|
|
|
|
|
|
</ol> |
|
|
|
|
|
|
|
|
|
|
|
Both std::vector<char> and std::string can be used for T. |
|
|
|
|
|
|
|
|
|
|
|
@param[out] data contains the copied data. |
|
|
|
|
|
|
|
|
|
|
|
@param[in] delimiter contains the delimiter. |
|
|
|
|
|
|
|
|
|
|
|
@returns the number of bytes copied. |
|
|
|
|
|
|
|
|
|
|
|
@see CircularBuffer::getAndErase(). |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
template<typename T> |
|
|
|
|
|
bool readDelimited(T &data, char const *delimiter) { |
|
|
|
|
|
return readDelimited(data, std::string(delimiter)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** Check whether the child process is running. |
|
|
/** Check whether the child process is running. |
|
|
|
|
|
|
|
|
\returns True if the child process is running, false |
|
|
\returns True if the child process is running, false |
|
|
|
|
|
|
|
|
*/ |
|
|
*/ |
|
|
void run(); |
|
|
void run(); |
|
|
|
|
|
|
|
|
/** Non-blocking request to get data read from the child. |
|
|
|
|
|
|
|
|
|
|
|
This method attempts to get up to a specified number of bytes |
|
|
|
|
|
of data from the input buffer containing data received from |
|
|
|
|
|
the child. The data that is provided is erased from the input |
|
|
|
|
|
buffer. |
|
|
|
|
|
|
|
|
|
|
|
@param[in, out] dataPtr points to the memory that receives the |
|
|
|
|
|
data. |
|
|
|
|
|
|
|
|
|
|
|
@param[in] nBytes is the number of bytes to attempt to copy. |
|
|
|
|
|
|
|
|
|
|
|
@returns the number of bytes copied. |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
size_t read(char *const dataPtr, size_t nBytes); |
|
|
|
|
|
|
|
|
|
|
|
/// Reader thread object. |
|
|
/// Reader thread object. |
|
|
std::thread readerThread; |
|
|
std::thread readerThread; |
|
|
|
|
|
|