mass reformat

This commit is contained in:
Eric Mertens 2025-01-25 15:45:31 -08:00
parent fd4612d385
commit 093515c3ec
17 changed files with 659 additions and 311 deletions

232
.clang-format Normal file
View File

@ -0,0 +1,232 @@
---
Language: Cpp
# BasedOnStyle: WebKit
AccessModifierOffset: -4
AlignAfterOpenBracket: BlockIndent
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseColons: false
AlignEscapedNewlines: Right
AlignOperands: DontAlign
AlignTrailingComments:
Kind: Never
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterExternBlock: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: All
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Custom
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ColumnLimit: 0
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros: []
IfMacros: []
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: ".*"
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: "(Test)?$"
IncludeIsMainSourceRegex: ""
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
KeepEmptyLinesAtEOF: false
LambdaBodyIndentation: Signature
LineEnding: LF
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 1
NamespaceIndentation: Inner
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Left
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: true
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros: []
StatementMacros: []
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros: []

View File

@ -12,11 +12,11 @@ namespace {
using namespace std::literals;
Connection::Connection(boost::asio::io_context & io)
: stream_{io}
, watchdog_timer_{io}
, write_posted_{false}
, stalled_{false}
Connection::Connection(boost::asio::io_context &io)
: stream_{io}
, watchdog_timer_{io}
, write_posted_{false}
, stalled_{false}
{
}
@ -24,28 +24,32 @@ auto Connection::write_buffers() -> void
{
std::vector<boost::asio::const_buffer> buffers;
buffers.reserve(write_strings_.size());
for (auto const& elt : write_strings_)
for (const auto &elt : write_strings_)
{
buffers.push_back(boost::asio::buffer(elt));
}
boost::asio::async_write(
stream_,
buffers,
[this, strings = std::move(write_strings_)](boost::system::error_code const& error, std::size_t)
{
if (not error) {
if (write_strings_.empty()) {
[this, strings = std::move(write_strings_)](const boost::system::error_code &error, std::size_t) {
if (not error)
{
if (write_strings_.empty())
{
write_posted_ = false;
} else {
}
else
{
write_buffers();
}
}
});
}
);
write_strings_.clear();
}
auto Connection::connect(
boost::asio::io_context & io,
boost::asio::io_context &io,
std::string host,
std::string port
) -> boost::asio::awaitable<void>
@ -53,29 +57,28 @@ auto Connection::connect(
using namespace std::placeholders;
// keep connection alive while coroutine is active
auto const self = shared_from_this();
const auto self = shared_from_this();
{
auto resolver = boost::asio::ip::tcp::resolver{io};
auto const endpoints = co_await resolver.async_resolve(host, port, boost::asio::use_awaitable);
auto const endpoint = co_await boost::asio::async_connect(stream_, endpoints, boost::asio::use_awaitable);
BOOST_LOG_TRIVIAL(debug) << "CONNECTED: " << endpoint;
const auto endpoints = co_await resolver.async_resolve(host, port, boost::asio::use_awaitable);
const auto endpoint = co_await boost::asio::async_connect(stream_, endpoints, boost::asio::use_awaitable);
BOOST_LOG_TRIVIAL(debug) << "CONNECTED: " << endpoint;
sig_connect();
}
// Start the queue writer after connection
watchdog();
for(LineBuffer buffer{32'768};;)
for (LineBuffer buffer{32'768};;)
{
boost::system::error_code error;
auto const n = co_await stream_.async_read_some(buffer.get_buffer(), boost::asio::redirect_error(boost::asio::use_awaitable, error));
const auto n = co_await stream_.async_read_some(buffer.get_buffer(), boost::asio::redirect_error(boost::asio::use_awaitable, error));
if (error)
{
break;
}
buffer.add_bytes(n, [this](char * line) {
buffer.add_bytes(n, [this](char *line) {
BOOST_LOG_TRIVIAL(debug) << "RECV: " << line;
watchdog_activity();
dispatch_line(line);
@ -84,14 +87,15 @@ auto Connection::connect(
watchdog_timer_.cancel();
stream_.close();
BOOST_LOG_TRIVIAL(debug) << "DISCONNECTED";
sig_disconnect();
}
auto Connection::watchdog() -> void
{
watchdog_timer_.expires_after(watchdog_duration);
watchdog_timer_.async_wait([this](auto const& error)
{
watchdog_timer_.async_wait([this](const auto &error) {
if (not error)
{
if (stalled_)
@ -118,15 +122,17 @@ auto Connection::watchdog_activity() -> void
/// Parse IRC message line and dispatch it to the ircmsg slot.
auto Connection::dispatch_line(char *line) -> void
{
auto const msg = parse_irc_message(line);
auto const recognized = IrcCommandHash::in_word_set(msg.command.data(), msg.command.size());
auto const command
const auto msg = parse_irc_message(line);
const auto recognized = IrcCommandHash::in_word_set(msg.command.data(), msg.command.size());
const auto command
= recognized
&& recognized->min_args <= msg.args.size()
&& recognized->max_args >= msg.args.size()
? recognized->command : IrcCommand::UNKNOWN;
&& recognized->min_args <= msg.args.size()
&& recognized->max_args >= msg.args.size()
? recognized->command
: IrcCommand::UNKNOWN;
switch (command) {
switch (command)
{
// Respond to pings immediate and discard
case IrcCommand::PING:
@ -145,7 +151,8 @@ auto Connection::dispatch_line(char *line) -> void
// Server notice generate snote events but not IRC command events
case IrcCommand::NOTICE:
if (auto match = snoteCore.match(msg)) {
if (auto match = snoteCore.match(msg))
{
sig_snote(*match);
break;
}
@ -156,7 +163,6 @@ auto Connection::dispatch_line(char *line) -> void
sig_ircmsg(command, msg);
break;
}
}
auto Connection::write_line(std::string message) -> void
@ -165,9 +171,10 @@ auto Connection::write_line(std::string message) -> void
message += "\r\n";
write_strings_.push_back(std::move(message));
if (not write_posted_) {
if (not write_posted_)
{
write_posted_ = true;
boost::asio::post(stream_.get_executor(), [weak = weak_from_this()](){
boost::asio::post(stream_.get_executor(), [weak = weak_from_this()]() {
if (auto self = weak.lock())
{
self->write_buffers();
@ -181,8 +188,7 @@ auto Connection::close() -> void
stream_.close();
}
static
auto is_invalid_last(char x) -> bool
static auto is_invalid_last(char x) -> bool
{
return x == '\0' || x == '\r' || x == '\n';
}
@ -261,7 +267,8 @@ auto Connection::send_authenticate(std::string_view message) -> void
auto Connection::on_authenticate(const std::string_view chunk) -> void
{
if (chunk != "+"sv) {
if (chunk != "+"sv)
{
authenticate_buffer_ += chunk;
}
@ -275,7 +282,9 @@ auto Connection::on_authenticate(const std::string_view chunk) -> void
{
decoded.resize(len);
sig_authenticate(decoded);
} else {
}
else
{
BOOST_LOG_TRIVIAL(debug) << "Invalid AUTHENTICATE base64"sv;
send_authenticate("*"sv); // abort SASL
}
@ -300,9 +309,10 @@ auto Connection::send_authenticate_encoded(std::string_view body) -> void
std::string encoded(mybase64::encoded_size(body.size()), 0);
mybase64::encode(body, encoded.data());
for (size_t lo = 0; lo < encoded.size(); lo += 400) {
for (size_t lo = 0; lo < encoded.size(); lo += 400)
{
const auto hi = std::min(lo + 400, encoded.size());
const std::string_view chunk { encoded.begin() + lo, encoded.begin() + hi };
const std::string_view chunk{encoded.begin() + lo, encoded.begin() + hi};
send_authenticate(chunk);
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "ircmsg.hpp"
#include "irc_command.hpp"
#include "ircmsg.hpp"
#include "snote.hpp"
#include <boost/asio.hpp>
@ -27,7 +27,7 @@ private:
std::string authenticate_buffer_;
auto write_buffers() -> void;
auto dispatch_line(char * line) -> void;
auto dispatch_line(char *line) -> void;
static constexpr std::chrono::seconds watchdog_duration = std::chrono::seconds{30};
auto watchdog() -> void;
@ -40,10 +40,10 @@ private:
auto write_irc(std::string) -> void;
auto write_irc(std::string, std::string_view) -> void;
template <typename... Args>
auto write_irc(std::string front, std::string_view next, Args ...rest) -> void;
auto write_irc(std::string front, std::string_view next, Args... rest) -> void;
public:
Connection(boost::asio::io_context & io);
Connection(boost::asio::io_context &io);
boost::signals2::signal<void()> sig_connect;
boost::signals2::signal<void()> sig_disconnect;
@ -51,12 +51,13 @@ public:
boost::signals2::signal<void(SnoteMatch &)> sig_snote;
boost::signals2::signal<void(std::string_view)> sig_authenticate;
auto get_executor() -> boost::asio::any_io_executor {
auto get_executor() -> boost::asio::any_io_executor
{
return stream_.get_executor();
}
auto connect(
boost::asio::io_context & io,
boost::asio::io_context &io,
std::string host,
std::string port
) -> boost::asio::awaitable<void>;
@ -81,16 +82,15 @@ public:
};
template <typename... Args>
auto Connection::write_irc(std::string front, std::string_view next, Args ...rest) -> void
auto Connection::write_irc(std::string front, std::string_view next, Args... rest) -> void
{
auto const is_invalid = [](char const x) -> bool
{
const auto is_invalid = [](const char x) -> bool {
return x == '\0' || x == '\r' || x == '\n' || x == ' ';
};
if (next.empty()
|| next.front() == ':'
|| next.end() != std::find_if(next.begin(), next.end(), is_invalid))
|| next.front() == ':'
|| next.end() != std::find_if(next.begin(), next.end(), is_invalid))
{
throw std::runtime_error{"bad irc argument"};
}

View File

@ -1,21 +1,20 @@
#include "irc_coroutine.hpp"
auto irc_coroutine::is_running() -> bool {
auto irc_coroutine::is_running() -> bool
{
return promise().connection_ != nullptr;
}
auto irc_coroutine::exception() -> std::exception_ptr {
auto irc_coroutine::exception() -> std::exception_ptr
{
return promise().exception_;
}
auto irc_coroutine::start(Connection& connection) -> void {
auto irc_coroutine::start(Connection &connection) -> void
{
promise().connection_ = connection.shared_from_this();
resume();
}
void wait_ircmsg::stop() {
ircmsg_slot_.disconnect();
}
void wait_ircmsg::stop() { ircmsg_slot_.disconnect(); }
void wait_timeout::stop() {
timer_.reset();
}
void wait_timeout::stop() { timer_.reset(); }

View File

@ -11,7 +11,8 @@
struct irc_promise;
/// A coroutine that can co_await on various IRC events
struct irc_coroutine : std::coroutine_handle<irc_promise> {
struct irc_coroutine : std::coroutine_handle<irc_promise>
{
using promise_type = irc_promise;
/// Start the coroutine and associate it with a specific connection.
@ -44,22 +45,25 @@ struct irc_promise
auto final_suspend() noexcept -> std::suspend_always { return {}; }
// Normal termination
auto return_void() -> void {
auto return_void() -> void
{
connection_.reset();
}
// Abnormal termination - remember the exception
auto unhandled_exception() -> void {
auto unhandled_exception() -> void
{
connection_.reset();
exception_ = std::current_exception();
}
};
template<typename ... Ts>
template <typename... Ts>
class Wait;
/// Argument to a Wait that expects one or more IRC messages
class wait_ircmsg {
class wait_ircmsg
{
// Vector of commands this wait is expecting. Leave empty to accept all messages.
std::vector<IrcCommand> want_cmds_;
@ -69,26 +73,38 @@ class wait_ircmsg {
public:
using result_type = std::pair<IrcCommand, const IrcMsg &>;
wait_ircmsg(std::initializer_list<IrcCommand> want_cmds) : want_cmds_{want_cmds} {}
wait_ircmsg(std::initializer_list<IrcCommand> want_cmds)
: want_cmds_{want_cmds}
{
}
template <size_t I, typename... Ts> auto start(Wait<Ts...>& command) -> void;
template <size_t I, typename... Ts>
auto start(Wait<Ts...> &command) -> void;
auto stop() -> void;
};
class wait_timeout {
class wait_timeout
{
std::optional<boost::asio::steady_timer> timer_;
std::chrono::milliseconds timeout_;
public:
struct result_type {};
wait_timeout(std::chrono::milliseconds timeout) : timeout_{timeout} {}
struct result_type
{
};
wait_timeout(std::chrono::milliseconds timeout)
: timeout_{timeout}
{
}
template <size_t I, typename... Ts> auto start(Wait<Ts...>& command) -> void;
template <size_t I, typename... Ts>
auto start(Wait<Ts...> &command) -> void;
auto stop() -> void;
};
template<typename ... Ts>
class Wait {
template <typename... Ts>
class Wait
{
// State associated with each wait mode
std::tuple<Ts...> modes_;
@ -105,31 +121,39 @@ class Wait {
boost::signals2::scoped_connection disconnect_slot_;
template <size_t I>
auto start_mode() -> void {
auto start_mode() -> void
{
std::get<I>(modes_).template start<I, Ts...>(*this);
}
template <std::size_t... Indices>
auto start_modes(std::index_sequence<Indices...>) -> void {
auto start_modes(std::index_sequence<Indices...>) -> void
{
(start_mode<Indices>(), ...);
}
template <std::size_t... Indices>
auto stop_modes(std::index_sequence<Indices...>) -> void {
auto stop_modes(std::index_sequence<Indices...>) -> void
{
(std::get<Indices>(modes_).stop(), ...);
}
public:
Wait(Ts &&...modes) : modes_{std::forward<Ts>(modes)...} {}
Wait(Ts &&...modes)
: modes_{std::forward<Ts>(modes)...}
{
}
// Get the connection that this coroutine was started with.
auto get_connection() const -> Connection & {
auto get_connection() const -> Connection &
{
return *handle_.promise().connection_;
}
// Store a successful result and resume the coroutine
template <size_t I, typename... Args>
auto complete(Args &&...args) -> void {
auto complete(Args &&...args) -> void
{
result_.emplace(std::in_place_index<I>, std::forward<Args>(args)...);
handle_.resume();
}
@ -148,23 +172,22 @@ template <size_t I, typename... Ts>
auto wait_ircmsg::start(Wait<Ts...> &command) -> void
{
ircmsg_slot_ = command.get_connection().sig_ircmsg.connect([this, &command](auto cmd, auto &msg) {
auto const wanted =
want_cmds_.empty() ||
std::find(want_cmds_.begin(), want_cmds_.end(), cmd) != want_cmds_.end();
if (wanted) {
const auto wanted = want_cmds_.empty() || std::find(want_cmds_.begin(), want_cmds_.end(), cmd) != want_cmds_.end();
if (wanted)
{
command.template complete<I>(cmd, msg);
}
});
}
template <size_t I, typename... Ts>
auto wait_timeout::start(Wait<Ts...>& command) -> void
auto wait_timeout::start(Wait<Ts...> &command) -> void
{
timer_.emplace(command.get_connection().get_executor());
timer_->expires_after(timeout_);
timer_->async_wait([this, &command](auto const& error)
{
if (not error) {
timer_->async_wait([this, &command](const auto &error) {
if (not error)
{
timer_.reset();
command.template complete<I>();
}
@ -176,7 +199,7 @@ auto Wait<Ts...>::await_suspend(std::coroutine_handle<irc_promise> handle) -> vo
{
handle_ = handle;
auto const tuple_size = std::tuple_size_v<decltype(modes_)>;
const auto tuple_size = std::tuple_size_v<decltype(modes_)>;
start_modes(std::make_index_sequence<tuple_size>{});
disconnect_slot_ = get_connection().sig_disconnect.connect([this]() {
@ -187,14 +210,17 @@ auto Wait<Ts...>::await_suspend(std::coroutine_handle<irc_promise> handle) -> vo
template <typename... Ts>
auto Wait<Ts...>::await_resume() -> std::variant<typename Ts::result_type...>
{
auto const tuple_size = std::tuple_size_v<decltype(modes_)>;
const auto tuple_size = std::tuple_size_v<decltype(modes_)>;
stop_modes(std::make_index_sequence<tuple_size>{});
disconnect_slot_.disconnect();
if (result_) {
if (result_)
{
return std::move(*result_);
} else {
}
else
{
throw std::runtime_error{"connection terminated"};
}
}

View File

@ -4,56 +4,68 @@
#include "ircmsg.hpp"
namespace {
class Parser {
char* msg_;
class Parser
{
char *msg_;
inline static char empty[1];
inline void trim() {
while (*msg_ == ' ') msg_++;
inline void trim()
{
while (*msg_ == ' ')
msg_++;
}
public:
Parser(char* msg) : msg_(msg) {
if (msg_ == nullptr) {
Parser(char *msg)
: msg_(msg)
{
if (msg_ == nullptr)
{
msg_ = empty;
} else {
}
else
{
trim();
}
}
char* word() {
auto const start = msg_;
while (*msg_ != '\0' && *msg_ != ' ') msg_++;
if (*msg_ != '\0') { // prepare for next token
char *word()
{
const auto start = msg_;
while (*msg_ != '\0' && *msg_ != ' ')
msg_++;
if (*msg_ != '\0')
{ // prepare for next token
*msg_++ = '\0';
trim();
}
return start;
}
bool match(char c) {
if (c == *msg_) {
bool match(char c)
{
if (c == *msg_)
{
msg_++;
return true;
}
return false;
}
bool isempty() const {
return *msg_ == '\0';
}
bool isempty() const { return *msg_ == '\0'; }
char const* peek() {
return msg_;
}
const char *peek() { return msg_; }
};
std::string_view unescape_tag_value(char* const val)
std::string_view unescape_tag_value(char *const val)
{
// only start copying at the first escape character
// skip everything before that
auto cursor = strchr(val, '\\');
if (cursor == nullptr) { return {val}; }
if (cursor == nullptr)
{
return {val};
}
auto write = cursor;
for (; *cursor; cursor++)
@ -63,12 +75,23 @@ std::string_view unescape_tag_value(char* const val)
cursor++;
switch (*cursor)
{
default : *write++ = *cursor; break;
case ':' : *write++ = ';' ; break;
case 's' : *write++ = ' ' ; break;
case 'r' : *write++ = '\r' ; break;
case 'n' : *write++ = '\n' ; break;
case '\0': return {val, write};
default:
*write++ = *cursor;
break;
case ':':
*write++ = ';';
break;
case 's':
*write++ = ' ';
break;
case 'r':
*write++ = '\r';
break;
case 'n':
*write++ = '\n';
break;
case '\0':
return {val, write};
}
}
else
@ -81,50 +104,61 @@ std::string_view unescape_tag_value(char* const val)
} // namespace
auto parse_irc_tags(char* str) -> std::vector<irctag>
auto parse_irc_tags(char *str) -> std::vector<irctag>
{
std::vector<irctag> tags;
do {
do
{
auto val = strsep(&str, ";");
auto key = strsep(&val, "=");
if ('\0' == *key) {
if ('\0' == *key)
{
throw irc_parse_error(irc_error_code::MISSING_TAG);
}
if (nullptr == val) {
if (nullptr == val)
{
tags.emplace_back(key, "");
} else {
tags.emplace_back(std::string_view{key, val-1}, unescape_tag_value(val));
}
} while(nullptr != str);
else
{
tags.emplace_back(std::string_view{key, val - 1}, unescape_tag_value(val));
}
}
while (nullptr != str);
return tags;
}
auto parse_irc_message(char* msg) -> IrcMsg
auto parse_irc_message(char *msg) -> IrcMsg
{
Parser p {msg};
Parser p{msg};
IrcMsg out;
/* MESSAGE TAGS */
if (p.match('@')) {
if (p.match('@'))
{
out.tags = parse_irc_tags(p.word());
}
/* MESSAGE SOURCE */
if (p.match(':')) {
if (p.match(':'))
{
out.source = p.word();
}
/* MESSAGE COMMANDS */
out.command = p.word();
if (out.command.empty()) {
if (out.command.empty())
{
throw irc_parse_error{irc_error_code::MISSING_COMMAND};
}
/* MESSAGE ARGUMENTS */
while (!p.isempty()) {
if (p.match(':')) {
while (!p.isempty())
{
if (p.match(':'))
{
out.args.push_back(p.peek());
break;
}
@ -134,16 +168,19 @@ auto parse_irc_message(char* msg) -> IrcMsg
return out;
}
auto IrcMsg::hassource() const -> bool
{
return source.data() != nullptr;
}
auto IrcMsg::hassource() const -> bool { return source.data() != nullptr; }
auto operator<<(std::ostream& out, irc_error_code code) -> std::ostream&
auto operator<<(std::ostream &out, irc_error_code code) -> std::ostream &
{
switch(code) {
case irc_error_code::MISSING_COMMAND: out << "MISSING COMMAND"; return out;
case irc_error_code::MISSING_TAG: out << "MISSING TAG"; return out;
default: return out;
switch (code)
{
case irc_error_code::MISSING_COMMAND:
out << "MISSING COMMAND";
return out;
case irc_error_code::MISSING_TAG:
out << "MISSING TAG";
return out;
default:
return out;
}
}

View File

@ -9,9 +9,13 @@ struct irctag
std::string_view key;
std::string_view val;
irctag(std::string_view key, std::string_view val) : key{key}, val{val} {}
irctag(std::string_view key, std::string_view val)
: key{key}
, val{val}
{
}
friend auto operator==(irctag const&, irctag const&) -> bool = default;
friend auto operator==(const irctag &, const irctag &) -> bool = default;
};
struct IrcMsg
@ -24,30 +28,38 @@ struct IrcMsg
IrcMsg() = default;
IrcMsg(
std::vector<irctag> && tags,
std::vector<irctag> &&tags,
std::string_view source,
std::string_view command,
std::vector<std::string_view> && args)
: tags(std::move(tags)),
args(std::move(args)),
source{source},
command{command} {}
std::vector<std::string_view> &&args
)
: tags(std::move(tags))
, args(std::move(args))
, source{source}
, command{command}
{
}
bool hassource() const;
bool hassource() const;
friend bool operator==(IrcMsg const&, IrcMsg const&) = default;
friend bool operator==(const IrcMsg &, const IrcMsg &) = default;
};
enum class irc_error_code {
enum class irc_error_code
{
MISSING_TAG,
MISSING_COMMAND,
};
auto operator<<(std::ostream& out, irc_error_code) -> std::ostream&;
auto operator<<(std::ostream &out, irc_error_code) -> std::ostream &;
struct irc_parse_error : public std::exception {
struct irc_parse_error : public std::exception
{
irc_error_code code;
irc_parse_error(irc_error_code code) : code(code) {}
irc_parse_error(irc_error_code code)
: code(code)
{
}
};
/**
@ -57,6 +69,6 @@ struct irc_parse_error : public std::exception {
*
* Returns zero for success, non-zero for parse error.
*/
auto parse_irc_message(char* msg) -> IrcMsg;
auto parse_irc_message(char *msg) -> IrcMsg;
auto parse_irc_tags(char* msg) -> std::vector<irctag>;
auto parse_irc_tags(char *msg) -> std::vector<irctag>;

View File

@ -34,7 +34,11 @@ public:
*
* @param n Buffer size
*/
LineBuffer(std::size_t n) : buffer(n), end_{buffer.begin()} {}
LineBuffer(std::size_t n)
: buffer(n)
, end_{buffer.begin()}
{
}
/**
* @brief Get the available buffer space
@ -60,7 +64,7 @@ public:
*/
auto add_bytes(std::size_t n, std::invocable<char *> auto line_cb) -> void
{
auto const start = end_;
const auto start = end_;
std::advance(end_, n);
// new data is now located in [start, end_)

View File

@ -13,11 +13,11 @@
using namespace std::chrono_literals;
auto start(boost::asio::io_context & io, Settings const& settings) -> void
auto start(boost::asio::io_context &io, const Settings &settings) -> void
{
auto const connection = std::make_shared<Connection>(io);
const auto connection = std::make_shared<Connection>(io);
auto const selfThread = SelfThread::start(*connection);
const auto selfThread = SelfThread::start(*connection);
RegistrationThread::start(*connection, settings, selfThread);
connection->sig_snote.connect([](auto &match) {
@ -29,22 +29,21 @@ auto start(boost::asio::io_context & io, Settings const& settings) -> void
});
boost::asio::co_spawn(
io,
connection->connect(io, settings.host, settings.service),
[&io, &settings](std::exception_ptr e)
{
io, connection->connect(io, settings.host, settings.service),
[&io, &settings](std::exception_ptr e) {
auto timer = std::make_shared<boost::asio::steady_timer>(io);
timer->expires_after(5s);
timer->async_wait([&io, &settings, timer](auto) {
start(io, settings);
});
});
timer->async_wait(
[&io, &settings, timer](auto) { start(io, settings); }
);
}
);
}
auto get_settings() -> Settings
{
if (auto config_stream = std::ifstream {"config.toml"})
if (auto config_stream = std::ifstream{"config.toml"})
{
return Settings::from_stream(config_stream);
}
@ -57,7 +56,7 @@ auto get_settings() -> Settings
auto main() -> int
{
auto const settings = get_settings();
const auto settings = get_settings();
auto io = boost::asio::io_context{};
start(io, settings);
io.run();

View File

@ -9,7 +9,7 @@
#include <unordered_set>
RegistrationThread::RegistrationThread(
Connection& connection,
Connection &connection,
const Settings &settings,
std::shared_ptr<SelfThread> self
)
@ -22,7 +22,10 @@ RegistrationThread::RegistrationThread(
auto RegistrationThread::on_connect() -> void
{
connection_.send_cap_ls();
connection_.send_pass(settings_.password);
if (not settings_.password.empty())
{
connection_.send_pass(settings_.password);
}
connection_.send_user(settings_.username, settings_.realname);
connection_.send_nick(settings_.nickname);
}
@ -30,7 +33,7 @@ auto RegistrationThread::on_connect() -> void
auto RegistrationThread::send_req() -> void
{
std::string request;
std::vector<char const*> want {
std::vector<const char *> want{
"account-notify",
"account-tag",
"batch",
@ -46,11 +49,12 @@ auto RegistrationThread::send_req() -> void
"solanum.chat/realhost",
};
if (settings_.sasl_mechanism == "PLAIN") {
if (not settings_.sasl_mechanism.empty())
{
want.push_back("sasl");
}
for (auto const cap : want)
for (const auto cap : want)
{
if (caps.contains(cap))
{
@ -73,7 +77,7 @@ auto RegistrationThread::send_req() -> void
}
}
auto RegistrationThread::on_msg_cap_ack(IrcMsg const& msg) -> void
auto RegistrationThread::on_msg_cap_ack(const IrcMsg &msg) -> void
{
auto in = std::istringstream{std::string{msg.args[2]}};
std::for_each(
@ -87,26 +91,31 @@ auto RegistrationThread::on_msg_cap_ack(IrcMsg const& msg) -> void
{
message_handle_.disconnect();
if (settings_.sasl_mechanism.empty()) {
if (settings_.sasl_mechanism.empty())
{
connection_.send_cap_end();
} else {
}
else
{
self_->start_sasl(std::make_unique<SaslPlain>(settings_.sasl_authcid, settings_.sasl_authzid, settings_.sasl_password));
connection_.sig_ircmsg.connect_extended([thread = shared_from_this()](auto &slot, auto cmd, auto &msg) {
switch (cmd) {
default: break;
case IrcCommand::RPL_SASLSUCCESS:
case IrcCommand::ERR_SASLFAIL:
thread->connection_.send_cap_end();
slot.disconnect();
switch (cmd)
{
default:
break;
case IrcCommand::RPL_SASLSUCCESS:
case IrcCommand::ERR_SASLFAIL:
thread->connection_.send_cap_end();
slot.disconnect();
}
});
}
}
}
auto RegistrationThread::on_msg_cap_ls(IrcMsg const& msg) -> void
auto RegistrationThread::on_msg_cap_ls(const IrcMsg &msg) -> void
{
std::string_view const* kvs;
const std::string_view *kvs;
bool last;
if (3 == msg.args.size())
@ -130,14 +139,14 @@ auto RegistrationThread::on_msg_cap_ls(IrcMsg const& msg) -> void
std::istream_iterator<std::string>{in},
std::istream_iterator<std::string>{},
[this](std::string x) {
auto const eq = x.find('=');
const auto eq = x.find('=');
if (eq == x.npos)
{
caps.emplace(x, std::string{});
}
else
{
caps.emplace(std::string{x, 0, eq}, std::string{x, eq+1, x.npos});
caps.emplace(std::string{x, 0, eq}, std::string{x, eq + 1, x.npos});
}
}
);
@ -150,17 +159,16 @@ auto RegistrationThread::on_msg_cap_ls(IrcMsg const& msg) -> void
}
auto RegistrationThread::start(
Connection& connection,
Connection &connection,
const Settings &settings,
std::shared_ptr<SelfThread> self
) -> std::shared_ptr<RegistrationThread>
{
auto const thread = std::make_shared<RegistrationThread>(connection, std::move(settings), std::move(self));
const auto thread = std::make_shared<RegistrationThread>(connection, std::move(settings), std::move(self));
thread->listen_for_cap_ls();
thread->connect_handle_ = connection.sig_connect.connect([thread]()
{
thread->connect_handle_ = connection.sig_connect.connect([thread]() {
thread->connect_handle_.disconnect();
thread->on_connect();
});
@ -170,8 +178,7 @@ auto RegistrationThread::start(
auto RegistrationThread::listen_for_cap_ack() -> void
{
message_handle_ = connection_.sig_ircmsg.connect([thread = shared_from_this()](IrcCommand cmd, IrcMsg const& msg)
{
message_handle_ = connection_.sig_ircmsg.connect([thread = shared_from_this()](IrcCommand cmd, const IrcMsg &msg) {
if (IrcCommand::CAP == cmd && msg.args.size() >= 2 && "ACK" == msg.args[1])
{
thread->on_msg_cap_ack(msg);
@ -181,11 +188,15 @@ auto RegistrationThread::listen_for_cap_ack() -> void
auto RegistrationThread::listen_for_cap_ls() -> void
{
message_handle_ = connection_.sig_ircmsg.connect([thread = shared_from_this()](IrcCommand cmd, IrcMsg const& msg)
{
message_handle_ = connection_.sig_ircmsg.connect([thread = shared_from_this()](IrcCommand cmd, const IrcMsg &msg) {
if (IrcCommand::CAP == cmd && msg.args.size() >= 2 && "LS" == msg.args[1])
{
thread->on_msg_cap_ls(msg);
}
else if (IrcCommand::RPL_WELCOME == cmd)
{
// Server doesn't support CAP negotiation
thread->message_handle_.disconnect();
}
});
}

View File

@ -1,8 +1,8 @@
#pragma once
#include "connection.hpp"
#include "settings.hpp"
#include "self_thread.hpp"
#include "settings.hpp"
#include <memory>
#include <string>
@ -11,7 +11,7 @@
class RegistrationThread : public std::enable_shared_from_this<RegistrationThread>
{
Connection& connection_;
Connection &connection_;
const Settings &settings_;
std::shared_ptr<SelfThread> self_;
@ -23,21 +23,21 @@ class RegistrationThread : public std::enable_shared_from_this<RegistrationThrea
auto on_connect() -> void;
auto send_req() -> void;
auto on_msg_cap_ls(IrcMsg const& msg) -> void;
auto on_msg_cap_ack(IrcMsg const& msg) -> void;
auto on_msg_cap_ls(const IrcMsg &msg) -> void;
auto on_msg_cap_ack(const IrcMsg &msg) -> void;
auto listen_for_cap_ack() -> void;
auto listen_for_cap_ls() -> void;
public:
RegistrationThread(
Connection& connection_,
Connection &connection_,
const Settings &,
std::shared_ptr<SelfThread> self
);
static auto start(
Connection& connection,
Connection &connection,
const Settings &,
std::shared_ptr<SelfThread> self
) -> std::shared_ptr<RegistrationThread>;

View File

@ -7,10 +7,6 @@
#include <string>
#include <string_view>
#include "event.hpp"
struct Connection;
class SaslMechanism
{
public:

View File

@ -9,12 +9,12 @@
using namespace std::literals;
auto SelfThread::on_welcome(IrcMsg const& irc) -> void
auto SelfThread::on_welcome(const IrcMsg &irc) -> void
{
nickname_ = irc.args[0];
}
auto SelfThread::on_nick(IrcMsg const& irc) -> void
auto SelfThread::on_nick(const IrcMsg &irc) -> void
{
if (is_my_mask(irc.source))
{
@ -22,12 +22,12 @@ auto SelfThread::on_nick(IrcMsg const& irc) -> void
}
}
auto SelfThread::on_umodeis(IrcMsg const& irc) -> void
auto SelfThread::on_umodeis(const IrcMsg &irc) -> void
{
mode_ = irc.args[1];
}
auto SelfThread::on_join(IrcMsg const& irc) -> void
auto SelfThread::on_join(const IrcMsg &irc) -> void
{
if (is_my_mask(irc.source))
{
@ -35,7 +35,7 @@ auto SelfThread::on_join(IrcMsg const& irc) -> void
}
}
auto SelfThread::on_kick(IrcMsg const& irc) -> void
auto SelfThread::on_kick(const IrcMsg &irc) -> void
{
if (is_my_nick(irc.args[1]))
{
@ -43,7 +43,7 @@ auto SelfThread::on_kick(IrcMsg const& irc) -> void
}
}
auto SelfThread::on_part(IrcMsg const& irc) -> void
auto SelfThread::on_part(const IrcMsg &irc) -> void
{
if (is_my_mask(irc.source))
{
@ -51,12 +51,12 @@ auto SelfThread::on_part(IrcMsg const& irc) -> void
}
}
auto SelfThread::on_mode(IrcMsg const& irc) -> void
auto SelfThread::on_mode(const IrcMsg &irc) -> void
{
if (is_my_nick(irc.args[0]))
{
auto polarity = true;
for (char const c : irc.args[1])
for (const char c : irc.args[1])
{
switch (c)
{
@ -73,7 +73,7 @@ auto SelfThread::on_mode(IrcMsg const& irc) -> void
}
else
{
auto const ix = mode_.find(c);
const auto ix = mode_.find(c);
if (ix != std::string::npos)
{
mode_.erase(ix, 1);
@ -87,42 +87,64 @@ auto SelfThread::on_mode(IrcMsg const& irc) -> void
auto SelfThread::on_isupport(const IrcMsg &msg) -> void
{
auto const hi = msg.args.size() - 1;
const auto hi = msg.args.size() - 1;
for (int i = 1; i < hi; ++i)
{
auto &entry = msg.args[i];
// Leading minus means to stop support
if (entry.starts_with("-")) {
auto const key = std::string{entry.substr(1)};
if (auto cursor = isupport_.find(key); cursor != isupport_.end()) {
if (entry.starts_with("-"))
{
const auto key = std::string{entry.substr(1)};
if (auto cursor = isupport_.find(key); cursor != isupport_.end())
{
isupport_.erase(cursor);
}
} else if (auto const cursor = entry.find('='); cursor != entry.npos) {
isupport_.emplace(entry.substr(0, cursor), entry.substr(cursor+1));
} else {
}
else if (const auto cursor = entry.find('='); cursor != entry.npos)
{
isupport_.emplace(entry.substr(0, cursor), entry.substr(cursor + 1));
}
else
{
isupport_.emplace(entry, std::string{});
}
}
}
auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
auto SelfThread::start(Connection &connection) -> std::shared_ptr<SelfThread>
{
auto thread = std::make_shared<SelfThread>(connection);
connection.sig_ircmsg.connect([thread](auto cmd, auto& msg)
{
connection.sig_ircmsg.connect([thread](auto cmd, auto &msg) {
switch (cmd)
{
case IrcCommand::JOIN: thread->on_join(msg); break;
case IrcCommand::KICK: thread->on_kick(msg); break;
case IrcCommand::MODE: thread->on_mode(msg); break;
case IrcCommand::NICK: thread->on_nick(msg); break;
case IrcCommand::PART: thread->on_part(msg); break;
case IrcCommand::RPL_ISUPPORT: thread->on_isupport(msg); break;
case IrcCommand::RPL_UMODEIS: thread->on_umodeis(msg); break;
case IrcCommand::RPL_WELCOME: thread->on_welcome(msg); break;
default: break;
case IrcCommand::JOIN:
thread->on_join(msg);
break;
case IrcCommand::KICK:
thread->on_kick(msg);
break;
case IrcCommand::MODE:
thread->on_mode(msg);
break;
case IrcCommand::NICK:
thread->on_nick(msg);
break;
case IrcCommand::PART:
thread->on_part(msg);
break;
case IrcCommand::RPL_ISUPPORT:
thread->on_isupport(msg);
break;
case IrcCommand::RPL_UMODEIS:
thread->on_umodeis(msg);
break;
case IrcCommand::RPL_WELCOME:
thread->on_welcome(msg);
break;
default:
break;
}
});
@ -133,17 +155,17 @@ auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
return thread;
}
auto SelfThread::get_my_nickname() const -> std::string const&
auto SelfThread::get_my_nickname() const -> const std::string &
{
return nickname_;
}
auto SelfThread::get_my_mode() const -> std::string const&
auto SelfThread::get_my_mode() const -> const std::string &
{
return mode_;
}
auto SelfThread::get_my_channels() const -> std::unordered_set<std::string> const&
auto SelfThread::get_my_channels() const -> const std::unordered_set<std::string> &
{
return channels_;
}
@ -155,7 +177,7 @@ auto SelfThread::is_my_nick(std::string_view nick) const -> bool
auto SelfThread::is_my_mask(std::string_view mask) const -> bool
{
auto const bang = mask.find('!');
const auto bang = mask.find('!');
return bang != std::string_view::npos && nickname_ == mask.substr(0, bang);
}
@ -168,7 +190,8 @@ auto SelfThread::on_authenticate(const std::string_view body) -> void
return;
}
if (auto reply = sasl_mechanism_->step(body)) {
if (auto reply = sasl_mechanism_->step(body))
{
connection_.send_authenticate_encoded(*reply);
@ -182,7 +205,8 @@ auto SelfThread::on_authenticate(const std::string_view body) -> void
auto SelfThread::start_sasl(std::unique_ptr<SaslMechanism> mechanism) -> void
{
if (sasl_mechanism_) {
if (sasl_mechanism_)
{
connection_.send_authenticate("*"sv); // abort SASL
}

View File

@ -15,7 +15,7 @@ struct IrcMsg;
*/
class SelfThread
{
Connection& connection_;
Connection &connection_;
std::string nickname_;
std::string mode_;
@ -26,27 +26,29 @@ class SelfThread
std::unique_ptr<SaslMechanism> sasl_mechanism_;
auto on_welcome(IrcMsg const& irc) -> void;
auto on_isupport(IrcMsg const& irc) -> void;
auto on_nick(IrcMsg const& irc) -> void;
auto on_umodeis(IrcMsg const& irc) -> void;
auto on_join(IrcMsg const& irc) -> void;
auto on_kick(IrcMsg const& irc) -> void;
auto on_part(IrcMsg const& irc) -> void;
auto on_mode(IrcMsg const& irc) -> void;
auto on_welcome(const IrcMsg &irc) -> void;
auto on_isupport(const IrcMsg &irc) -> void;
auto on_nick(const IrcMsg &irc) -> void;
auto on_umodeis(const IrcMsg &irc) -> void;
auto on_join(const IrcMsg &irc) -> void;
auto on_kick(const IrcMsg &irc) -> void;
auto on_part(const IrcMsg &irc) -> void;
auto on_mode(const IrcMsg &irc) -> void;
auto on_authenticate(std::string_view) -> void;
public:
SelfThread(Connection& connection) : connection_{connection} {}
static auto start(Connection&) -> std::shared_ptr<SelfThread>;
SelfThread(Connection &connection)
: connection_{connection}
{
}
static auto start(Connection &) -> std::shared_ptr<SelfThread>;
auto start_sasl(std::unique_ptr<SaslMechanism> mechanism) -> void;
auto get_my_nickname() const -> std::string const&;
auto get_my_mode() const -> std::string const&;
auto get_my_channels() const -> std::unordered_set<std::string> const&;
auto get_my_nickname() const -> const std::string &;
auto get_my_mode() const -> const std::string &;
auto get_my_channels() const -> const std::unordered_set<std::string> &;
auto is_my_nick(std::string_view nick) const -> bool;
auto is_my_mask(std::string_view nick) const -> bool;
};

View File

@ -3,12 +3,12 @@
#define TOML_ENABLE_FORMATTERS 0
#include <toml++/toml.hpp>
auto Settings::from_stream(std::istream & in) -> Settings
auto Settings::from_stream(std::istream &in) -> Settings
{
auto const config = toml::parse(in);
const auto config = toml::parse(in);
return Settings{
.host = config["host"].value_or(std::string{}),
.service = config["service"].value_or(std::string{}),
.host = config["host"].value_or(std::string{}),
.service = config["service"].value_or(std::string{}),
.password = config["password"].value_or(std::string{}),
.username = config["username"].value_or(std::string{}),
.realname = config["realname"].value_or(std::string{}),

View File

@ -1,7 +1,7 @@
#pragma once
#include <string>
#include <istream>
#include <string>
struct Settings
{
@ -17,6 +17,5 @@ struct Settings
std::string sasl_authzid;
std::string sasl_password;
static auto from_stream(std::istream & in) -> Settings;
static auto from_stream(std::istream &in) -> Settings;
};

View File

@ -17,20 +17,19 @@ namespace {
struct SnotePattern
{
SnotePattern(SnoteTag tag, char const* expression, unsigned flags = 0)
: tag{tag}
, expression{expression}
, regex{expression, std::regex_constants::ECMAScript | std::regex_constants::optimize}
SnotePattern(SnoteTag tag, const char *expression, unsigned flags = 0)
: tag{tag}
, expression{expression}
, regex{expression, std::regex_constants::ECMAScript | std::regex_constants::optimize}
{
}
SnoteTag tag;
char const* expression;
const char *expression;
std::regex regex;
};
SnotePattern static const patterns[] =
{
const SnotePattern static patterns[] = {
{SnoteTag::ClientConnecting,
R"(^Client connecting: ([^ ]+) \(([^@ ]+)@([^) ]+)\) \[(.*)\] \{([^ ]*)\} <([^ ]*)> \[(.*)\]$)"},
@ -77,10 +76,10 @@ SnotePattern static const patterns[] =
"^\x02([^ ]+)\x02 set vhost ([^ ]+) on the \x02MARKED\x02 account ([^ ]+).$"},
};
static auto setup_database() -> hs_database_t*
static auto setup_database() -> hs_database_t *
{
auto const n = std::size(patterns);
std::vector<char const*> expressions;
const auto n = std::size(patterns);
std::vector<const char *> expressions;
std::vector<unsigned> flags(n, HS_FLAG_SINGLEMATCH);
std::vector<unsigned> ids;
@ -93,21 +92,20 @@ static auto setup_database() -> hs_database_t*
ids.push_back(i);
}
hs_database_t* db;
hs_database_t *db;
hs_compile_error *error;
hs_platform_info_t *platform = nullptr; // target current platform
switch (hs_compile_multi(expressions.data(), flags.data(), ids.data(), expressions.size(), HS_MODE_BLOCK, platform, &db, &error))
{
case HS_COMPILER_ERROR:
{
std::string msg = error->message;
hs_free_compile_error(error);
throw std::runtime_error{std::move(msg)};
}
case HS_SUCCESS:
break;
default:
abort();
case HS_COMPILER_ERROR: {
std::string msg = error->message;
hs_free_compile_error(error);
throw std::runtime_error{std::move(msg)};
}
case HS_SUCCESS:
break;
default:
abort();
}
return db;
}
@ -118,7 +116,7 @@ SnoteCore::SnoteCore()
{
db_.reset(setup_database());
hs_scratch_t* scratch = nullptr;
hs_scratch_t *scratch = nullptr;
if (HS_SUCCESS != hs_alloc_scratch(db_.get(), &scratch))
{
abort();
@ -128,30 +126,29 @@ SnoteCore::SnoteCore()
auto SnoteCore::match(const IrcMsg &msg) -> std::optional<SnoteMatch>
{
static char const* const prefix = "*** Notice -- ";
static const char *const prefix = "*** Notice -- ";
auto& args = msg.args;
if ("*" != args[0] || !args[1].starts_with(prefix)) {
auto &args = msg.args;
if ("*" != args[0] || !args[1].starts_with(prefix))
{
return std::nullopt;
}
auto const message = args[1].substr(strlen(prefix));
const auto message = args[1].substr(strlen(prefix));
unsigned match_id;
auto cb = [&match_id](unsigned id, unsigned long long, unsigned long long, unsigned) -> int
{
auto cb = [&match_id](unsigned id, unsigned long long, unsigned long long, unsigned) -> int {
match_id = id;
return 1; // stop scanning
};
auto const scan_result =
hs_scan(
db_.get(),
message.data(), message.size(),
0, // no flags
scratch_.get(),
CCallback<decltype(cb)>::invoke, &cb
);
const auto scan_result = hs_scan(
db_.get(),
message.data(), message.size(),
0, // no flags
scratch_.get(),
CCallback<decltype(cb)>::invoke, &cb
);
switch (scan_result)
{
@ -159,9 +156,8 @@ auto SnoteCore::match(const IrcMsg &msg) -> std::optional<SnoteMatch>
BOOST_LOG_TRIVIAL(warning) << "Unknown snote: " << message;
return std::nullopt;
case HS_SCAN_TERMINATED:
{
auto& pattern = patterns[match_id];
case HS_SCAN_TERMINATED: {
auto &pattern = patterns[match_id];
return SnoteMatch{pattern.tag, pattern.regex, message};
}
@ -170,14 +166,15 @@ auto SnoteCore::match(const IrcMsg &msg) -> std::optional<SnoteMatch>
}
}
auto SnoteMatch::get_results() -> std::match_results<std::string_view::const_iterator> const&
auto SnoteMatch::get_results() -> const std::match_results<std::string_view::const_iterator> &
{
if (auto results = std::get_if<1>(&components_)) {
if (auto results = std::get_if<1>(&components_))
{
return *results;
}
auto [regex, message] = std::get<0>(components_);
auto& results = components_.emplace<1>();
auto &results = components_.emplace<1>();
if (not std::regex_match(message.begin(), message.end(), results, regex))
{
// something went wrong - hyperscan disagrees with std::regex
@ -186,7 +183,7 @@ auto SnoteMatch::get_results() -> std::match_results<std::string_view::const_ite
return results;
}
auto SnoteCore::DbDeleter::operator()(hs_database_t * db) const -> void
auto SnoteCore::DbDeleter::operator()(hs_database_t *db) const -> void
{
if (HS_SUCCESS != hs_free_database(db))
{
@ -194,7 +191,7 @@ auto SnoteCore::DbDeleter::operator()(hs_database_t * db) const -> void
}
}
auto SnoteCore::ScratchDeleter::operator()(hs_scratch_t * scratch) const -> void
auto SnoteCore::ScratchDeleter::operator()(hs_scratch_t *scratch) const -> void
{
if (HS_SUCCESS != hs_free_scratch(scratch))
{