/** * ctlseqs.hh - C++ wrapper for the ctlseqs library * * Copyright (C) 2020 CismonX * * 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 . */ #ifndef CTLSEQS_HH_ #define CTLSEQS_HH_ #include "ctlseqs.h" #include #include #include #include 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 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 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 void buffer(buffer const &buffer) { buffer_ = reinterpret_cast(&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 ssize_t read(matcher const &matcher, std::chrono::duration timeout) { int timeout_millis = std::chrono::duration_cast(timeout).count(); return setopt_and_read(matcher.matcher_, timeout_millis); } ~reader() { ctlseqs_reader_free(reader_); } }; } #endif // !CTLSEQS_HH_