ctlseqs/src/ctlseqs.hh

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_