From 8bace31b3db612d7c5ad7fd01b46f4c2c8a3a7e3 Mon Sep 17 00:00:00 2001 From: Charles Cabergs Date: Mon, 22 Sep 2025 08:53:55 +0000 Subject: [PATCH] Update zmq::message_t::str with max_size (#665) * Update zmq::message_t::str with an argument to set the maximum message size to put in a debug string * Fix std::min on Windows and move byte variable to a lower scope --------- Co-authored-by: Charles Cabergs --- tests/message.cpp | 18 ++++++++++++++++++ zmq.hpp | 43 ++++++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/tests/message.cpp b/tests/message.cpp index 23718bd..645d806 100644 --- a/tests/message.cpp +++ b/tests/message.cpp @@ -196,6 +196,24 @@ TEST_CASE("message to string", "[message]") #endif } +TEST_CASE("message to debug string", "[message]") +{ + const zmq::message_t a; + const zmq::message_t b("Foo", 3); + const zmq::message_t c("ascii\x01\x02\x03%%%\x04\x05\x06###", 17); + const zmq::message_t d("\x01\x02\x03|||", 6); + CHECK(a.str() == "zmq::message_t [size 000] ()"); + CHECK(b.str() == "zmq::message_t [size 003] (Foo)"); + CHECK(c.str() == "zmq::message_t [size 017] (ascii 010203 %%% 040506 ###)"); + CHECK(d.str() == "zmq::message_t [size 006] (010203 |||)"); + // With max_size + CHECK(a.str(100) == "zmq::message_t [size 000] ()"); + CHECK(b.str(2) == "zmq::message_t [size 003] (Fo... too big to print)"); + CHECK(c.str(10) + == "zmq::message_t [size 017] (ascii 010203 %%... too big to print)"); + CHECK(d.str(2) == "zmq::message_t [size 006] (0102... too big to print)"); +} + #if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0) TEST_CASE("message routing id persists", "[message]") { diff --git a/zmq.hpp b/zmq.hpp index cfd8e92..ad0509e 100644 --- a/zmq.hpp +++ b/zmq.hpp @@ -691,39 +691,40 @@ class message_t * Use to_string() or to_string_view() for * interpreting the message as a string. */ - std::string str() const + std::string str(size_t max_size = 1000) const { // Partly mutuated from the same method in zmq::multipart_t std::stringstream os; const unsigned char *msg_data = this->data(); - unsigned char byte; - size_t size = this->size(); + size_t size_to_print = (std::min)(this->size(), max_size); int is_ascii[2] = {0, 0}; + // Set is_ascii for the first character + if (size_to_print > 0) + is_ascii[0] = (*msg_data >= 32 && *msg_data < 127); os << "zmq::message_t [size " << std::dec << std::setw(3) - << std::setfill('0') << size << "] ("; - // Totally arbitrary - if (size >= 1000) { - os << "... too big to print)"; - } else { - while (size--) { - byte = *msg_data++; + << std::setfill('0') << this->size() << "] ("; + while (size_to_print--) { + const unsigned char byte = *msg_data++; - is_ascii[1] = (byte >= 32 && byte < 127); - if (is_ascii[1] != is_ascii[0]) - os << " "; // Separate text/non text + is_ascii[1] = (byte >= 32 && byte < 127); + if (is_ascii[1] != is_ascii[0]) + os << " "; // Separate text/non text - if (is_ascii[1]) { - os << byte; - } else { - os << std::hex << std::uppercase << std::setw(2) - << std::setfill('0') << static_cast(byte); - } - is_ascii[0] = is_ascii[1]; + if (is_ascii[1]) { + os << byte; + } else { + os << std::hex << std::uppercase << std::setw(2) << std::setfill('0') + << static_cast(byte); } - os << ")"; + is_ascii[0] = is_ascii[1]; } + // Elide the rest if the message is too large + if (max_size < this->size()) + os << "... too big to print)"; + else + os << ")"; return os.str(); }