173 lines
4.8 KiB
C++
173 lines
4.8 KiB
C++
/**
|
|
* ctlseqs.hh - C++ wrapper for the ctlseqs library
|
|
*
|
|
* Copyright (C) 2020 CismonX <admin@cismon.net>
|
|
*
|
|
* This file is part of the ctlseqs library.
|
|
*
|
|
* This library is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this library. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef CTLSEQS_HH_
|
|
#define CTLSEQS_HH_
|
|
|
|
#include "ctlseqs.h"
|
|
|
|
#include <chrono>
|
|
#include <new>
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
|
|
namespace ctlseqs {
|
|
|
|
// Control sequence matcher
|
|
class matcher final {
|
|
|
|
ctlseqs_matcher *const matcher_;
|
|
|
|
friend class reader;
|
|
|
|
public:
|
|
|
|
matcher(matcher const &matcher) = delete;
|
|
|
|
matcher() : matcher_(ctlseqs_matcher_init()) {
|
|
if (matcher_ == nullptr) {
|
|
throw std::bad_alloc();
|
|
}
|
|
}
|
|
|
|
void patterns(std::vector<char const *> const &patterns) {
|
|
ctlseqs_matcher_opts opts { patterns.data(), patterns.size() };
|
|
switch (ctlseqs_matcher_setopt(matcher_, &opts)) {
|
|
case CTLSEQS_NOMEM:
|
|
throw std::bad_alloc();
|
|
}
|
|
}
|
|
|
|
~matcher() {
|
|
ctlseqs_matcher_free(matcher_);
|
|
}
|
|
};
|
|
|
|
// Buffer for parsed sequence
|
|
template <std::size_t N>
|
|
class buffer final {
|
|
|
|
ctlseqs_value buffer_[N];
|
|
|
|
public:
|
|
|
|
// Get string value
|
|
char const *str(std::size_t idx) const {
|
|
return buffer_[idx].str;
|
|
}
|
|
|
|
// Get integer value by index
|
|
unsigned long num(std::size_t idx) const {
|
|
return buffer_[idx].num;
|
|
}
|
|
};
|
|
|
|
// Control sequence reader
|
|
class reader final {
|
|
|
|
ctlseqs_reader *const reader_;
|
|
|
|
ctlseqs_value *buffer_;
|
|
size_t maxlen_;
|
|
int fd_;
|
|
bool no_poll_;
|
|
bool retain_partial_;
|
|
bool options_modified_;
|
|
|
|
ssize_t setopt_and_read(matcher const &matcher, int timeout) {
|
|
if (options_modified_) {
|
|
unsigned flags = retain_partial_ * CTLSEQS_READER_RETAIN_PARTIAL | no_poll_ * CTLSEQS_READER_NO_POLL;
|
|
ctlseqs_reader_opts opts { buffer_, maxlen_, fd_, flags };
|
|
switch (ctlseqs_reader_setopt(reader_, &opts)) {
|
|
case CTLSEQS_NOMEM:
|
|
throw std::bad_alloc();
|
|
}
|
|
options_modified_ = false;
|
|
}
|
|
ssize_t retval = ctlseqs_read(reader_, matcher.matcher_, timeout);
|
|
switch (retval) {
|
|
case CTLSEQS_ERROR:
|
|
throw std::runtime_error("read failed");
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
public:
|
|
|
|
reader(reader const &reader) = delete;
|
|
|
|
reader() : reader_(ctlseqs_reader_init()) {
|
|
if (reader_ == nullptr) {
|
|
throw std::bad_alloc();
|
|
}
|
|
}
|
|
|
|
// Set buffer for parsed message
|
|
template <std::size_t N>
|
|
void buffer(buffer<N> const &buffer) {
|
|
buffer_ = reinterpret_cast<ctlseqs_value *>(&buffer);
|
|
options_modified_ = true;
|
|
}
|
|
|
|
// Set file descriptor to read from
|
|
void fd(int fd) {
|
|
fd_ = fd;
|
|
options_modified_ = true;
|
|
}
|
|
|
|
// Set maximum read size
|
|
void maxlen(std::size_t maxlen) {
|
|
maxlen_ = maxlen;
|
|
options_modified_ = true;
|
|
}
|
|
|
|
// Do not poll() before read()
|
|
void no_poll(bool enabled = true) {
|
|
no_poll_ = enabled;
|
|
options_modified_ = true;
|
|
}
|
|
|
|
// Retain data after a partial match
|
|
void retain_partial(bool enabled = true) {
|
|
retain_partial_ = enabled;
|
|
options_modified_ = true;
|
|
}
|
|
|
|
// Read without timemout
|
|
ssize_t read(matcher const &matcher) {
|
|
return setopt_and_read(matcher, -1);
|
|
}
|
|
|
|
// Read with timeout
|
|
template <typename R, typename P>
|
|
ssize_t read(matcher const &matcher, std::chrono::duration<R, P> timeout) {
|
|
int timeout_millis = std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count();
|
|
return setopt_and_read(matcher.matcher_, timeout_millis);
|
|
}
|
|
|
|
~reader() {
|
|
ctlseqs_reader_free(reader_);
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif // !CTLSEQS_HH_
|