Skip to content

Commit

Permalink
Allow pcn_log to be split in multiple lines
Browse files Browse the repository at this point in the history
This commit fixes a "bug" in the pcn_log function that did not allow
to split the pcn_log body into multiple lines, for example by putting
the text and the parameters in different lines.
It uses an improved regex function to check the end of the
pcn_log function and replace it with the correct version so that
compilation errors can be avoided.

Fixes: #1 (pcn_log cannot be split in multiple lines)
Signed-off-by: Sebastiano Miano <mianosebastiano@gmail.com>
  • Loading branch information
sebymiano committed Feb 1, 2019
1 parent 4b505ec commit 1fa9d1d
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 6 deletions.
1 change: 0 additions & 1 deletion Documentation/developers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ Two special format specifiers are available:
Please note the the custom specifiers spec the data to be in network byte order while standard specifiers expects it to be in host by order.

Current limitations:
- The whole call to `pcn_log` should be on the same line
- Cannot be used inside a macro
- Maximum 4 arguments are allowed

Expand Down
37 changes: 32 additions & 5 deletions src/polycubed/src/datapath_log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,20 +199,47 @@ void DatapathLog::stop() {
}
}

std::string DatapathLog::replace_string(std::string& subject, const std::string& search, const std::string& replace) {
size_t start_pos = 0;
while((start_pos = subject.find(search, start_pos)) != std::string::npos) {
subject.replace(start_pos, search.length(), replace);
start_pos += replace.length(); // Handles case where 'to' is a substring of 'from'
}
return subject;
}

// matches all C++ comments
// https://stackoverflow.com/questions/36454069/how-to-remove-c-style-comments-from-code
static std::regex regComments(R"***((?:\/\/(?:\\\n|[^\n])*)|(?:\/\*[\s\S]*?\*\/)|((?:R"([^(\\\s]{0,16})\([^)]*\)\2")|(?:@"[^"]*?")|(?:"(?:\?\?'|\\\\|\\"|\\\n|[^"])*?")|(?:'(?:\\\\|\\'|\\\n|[^'])*?')))***");

// matches all calls to pcn_log(ctx, ...)
static std::regex regN(R"***(pcn_log\(([\s\S]+?)\)\s*;)***");
static std::regex regN(R"***(pcn_log\s*\(([\s\S]+?)\)\s*;)***");
static std::regex regNewLine(R"***(/(\r\n)+|\r+|\n+|\t+/i)***");
static std::regex regAddSpaces(R"***( +)***");

static std::regex regNPkt(R"***(pcn_pkt_log\s*\(([\s\S]+?)\)\s*;)***");

std::string DatapathLog::dp_callback(const std::smatch& m) {
std::string match = std::regex_replace(m.str(1), regNewLine, "");
match = std::regex_replace(match, regAddSpaces, " ");
std::string new_string = std::string(REPLACE_BASE);
new_string = DatapathLog::replace_string(new_string, "$1", match);
return new_string;
}

static std::regex regNPkt(R"***(pcn_pkt_log\(([\s\S]+?)\)\s*;)***");
std::string DatapathLog::dp_callback_pkt(const std::smatch& m) {
std::string match = std::regex_replace(m.str(1), regNewLine, "");
match = std::regex_replace(match, regAddSpaces, " ");
std::string new_string = std::string(REPLACE_BASE_PKT);
new_string = DatapathLog::replace_string(new_string, "$1", match);
return new_string;
}

std::string DatapathLog::parse_log(const std::string &code) {
// remove all comments from the code before going on
auto code1 = regex_replace(code, regComments, "$1");
auto code2 = std::regex_replace(code1, regN, REPLACE_BASE);
auto code3 = std::regex_replace(code2, regNPkt, REPLACE_BASE_PKT);
auto code1 = std::regex_replace(code, regComments, "$1");
auto code2 = std::regex_replace_cb(code1, regN, DatapathLog::dp_callback);
auto code3 = std::regex_replace_cb(code2, regNPkt, DatapathLog::dp_callback_pkt);
return BASE_CODE + code3;
}

Expand Down
58 changes: 58 additions & 0 deletions src/polycubed/src/datapath_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#include <functional>
#include <thread>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <string>
#include <regex>

#include <api/BPF.h>
#include <spdlog/spdlog.h>
Expand All @@ -42,6 +47,9 @@ class DatapathLog {
void stop();

static void call_back_proxy(void *cb_cookie, void *data, int data_size);
static std::string replace_string(std::string& subject, const std::string& search, const std::string& replace);
static std::string dp_callback(const std::smatch& m);
static std::string dp_callback_pkt(const std::smatch& m);

// replaces all the log calls to the code that does it
std::string parse_log(const std::string &code);
Expand All @@ -60,3 +68,53 @@ class DatapathLog {

} // namespace polycubed
} // namespace polycube

// Based on solution proposed in: https://stackoverflow.com/questions/22617209/regex-replace-with-callback-in-c11
namespace std
{

template<class BidirIt, class Traits, class CharT, class UnaryFunction>
std::basic_string<CharT> regex_replace_cb(BidirIt first, BidirIt last,
const std::basic_regex<CharT,Traits>& re, UnaryFunction f)
{
std::basic_string<CharT> s;

typename std::match_results<BidirIt>::difference_type
positionOfLastMatch = 0;
auto endOfLastMatch = first;

auto callback = [&](const std::match_results<BidirIt>& match)
{
auto positionOfThisMatch = match.position(0);
auto diff = positionOfThisMatch - positionOfLastMatch;

auto startOfThisMatch = endOfLastMatch;
std::advance(startOfThisMatch, diff);

s.append(endOfLastMatch, startOfThisMatch);
s.append(f(match));

auto lengthOfMatch = match.length(0);

positionOfLastMatch = positionOfThisMatch + lengthOfMatch;

endOfLastMatch = startOfThisMatch;
std::advance(endOfLastMatch, lengthOfMatch);
};

std::regex_iterator<BidirIt> begin(first, last, re), end;
std::for_each(begin, end, callback);

s.append(endOfLastMatch, last);

return s;
}

template<class Traits, class CharT, class UnaryFunction>
std::string regex_replace_cb(const std::string& s,
const std::basic_regex<CharT,Traits>& re, UnaryFunction f)
{
return regex_replace_cb(s.cbegin(), s.cend(), re, f);
}

} // namespace std

0 comments on commit 1fa9d1d

Please sign in to comment.