Replaced all raw std::hex uses for integers outside of IoManip code.
Also fixed std::ostream flags restoration in AsHex printing code.
Also fixed or polished a few level-2+ debugs() statements.
Also added AsHex unit tests.
$(COMPAT_LIB) \
$(XTRA_LIBS)
tests_testEventLoop_LDFLAGS = $(LIBADD_DL)
+
+check_PROGRAMS += tests/testIoManip
+tests_testIoManip_SOURCES = \
+ tests/testIoManip.cc
+nodist_tests_testIoManip_SOURCES = \
+ tests/stub_SBuf.cc \
+ tests/stub_debug.cc \
+ tests/stub_libmem.cc \
+ tests/stub_libtime.cc
+tests_testIoManip_LDADD = \
+ base/libbase.la \
+ $(LIBCPPUNIT_LIBS) \
+ $(COMPAT_LIB) \
+ $(XTRA_LIBS)
+tests_testIoManip_LDFLAGS = $(LIBADD_DL)
for (const auto &m : marks) {
if (m.matches(connmark)) {
- debugs(28, 5, "found " << m << " matching " << asHex(connmark));
+ debugs(28, 5, "found " << m << " matching 0x" << asHex(connmark));
return 1;
}
- debugs(28, 7, "skipped " << m << " mismatching " << asHex(connmark));
+ debugs(28, 7, "skipped " << m << " mismatching 0x" << asHex(connmark));
}
} else {
debugs(28, 7, "fails: no client connection");
#include "squid.h"
#include "acl/Checklist.h"
#include "acl/TimeData.h"
+#include "base/IoManip.h"
#include "cache_cf.h"
#include "ConfigParser.h"
#include "debug/Stream.h"
while (data) {
debugs(28, 3, "aclMatchTime: checking " << t << " in " <<
data->start << "-" << data->stop << ", weekbits=" <<
- std::hex << data->weekbits);
+ asHex(data->weekbits));
if (t >= data->start && t <= data->stop && (data->weekbits & (1 << tm.tm_wday)))
return 1;
* OpenSSL libraries linked into openldap. See http://www.openssl.org/
*/
#include "squid.h"
+#include "base/IoManip.h"
#include "helper/protocol_defines.h"
#include "rfc1738.h"
#include "util.h"
case '(':
case ')':
case '\\':
- str << '\\' << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(c);
+ str << '\\' << asHex(c).minDigits(2);
break;
default:
str << c;
#include <iostream>
#include <iomanip>
+#include <optional>
+
+/// \section Custom manipulator tuning methods
+///
+/// Our convenience manipulator/wrapper classes often have methods that tune
+/// their "printing" effects (e.g., AsHex::minDigits()). STL streams also have
+/// manipulators that tune how subsequent operator "<<" parameters are printed
+/// (e.g., std::setw()). The calling code can also print various decorations
+/// (i.e. prefixes and suffixes). The following principles are useful when
+/// deciding what manipulator methods to add and how to implement them:
+///
+/// \li Add a manipulator method if callers would otherwise have to restore
+/// stream format after calling the manipulator. For example, AsHex::toUpper()
+/// frees callers from doing `std::uppercase << asHex(n) << std::nouppercase`.
+///
+/// \li Add a manipulator method if callers would otherwise have to use
+/// conditionals to get the same effect. For example, AsList::prefixedBy() frees
+/// callers from doing `(c.empty() ? "" : "/") << asList(c)`.
+///
+/// \li Add a manipulator method if callers would otherwise have to repeat a
+/// combination of actions to get the right effect. For example,
+/// AsList::minDigits() prevents duplication of the following caller code:
+/// `std::setfill('0') << std::setw(8) << asHex(n)`.
+///
+/// \li Avoid adding a manipulator method that can be _fully_ replaced with a
+/// _single_ caller item. For example, do not add AsX::foo() if callers can do
+/// `bar << asX(y)` or `asX(y) << bar` and get exactly the same effect.
+///
+/// \li Manipulators should honor existing stream formatting to the extent
+/// possible (e.g., AsHex honors std::uppercase by default).
/// Safely prints an object pointed to by the given pointer: [label]<object>
/// Prints nothing at all if the pointer is nil.
return os;
}
-/// std::ostream manipulator to print integers as hex numbers prefixed by 0x
+/// std::ostream manipulator to print integers and alike as hex numbers.
+/// Normally used through the asHex() convenience function.
template <class Integer>
class AsHex
{
public:
+ // Without this assertion, asHex(pointer) and AsHex(3.14) compile, but their
+ // caller is likely confused about the actual argument type and expects
+ // different output. Enum values are not integral types but arguably do not
+ // cause similar problems.
+ static_assert(std::is_integral<Integer>::value || std::is_enum<Integer>::value);
+
explicit AsHex(const Integer n): io_manip(n) {}
+
+ /// Sets the minimum number of digits to print. If the integer has fewer
+ /// digits than the given width, then we also print leading zero(s).
+ /// Otherwise, this method has no effect.
+ auto &minDigits(const size_t w) { forcePadding = w; return *this; }
+
+ /// Print hex digits in upper (or, with a false parameter value, lower) case.
+ auto &upperCase(const bool u = true) { forceCase = u; return *this; }
+
Integer io_manip; ///< the integer to print
+
+ /// \copydoc minDigits()
+ /// The default is to use stream's field width and stream's fill character.
+ std::optional<size_t> forcePadding;
+
+ /// \copydoc upperCase()
+ /// The default is to use stream's std::uppercase flag.
+ std::optional<bool> forceCase;
};
template <class Integer>
operator <<(std::ostream &os, const AsHex<Integer> number)
{
const auto oldFlags = os.flags();
- os << std::hex << std::showbase << number.io_manip;
- os.setf(oldFlags);
+ const auto oldFill = os.fill();
+
+ if (number.forceCase)
+ os << (*number.forceCase ? std::uppercase : std::nouppercase);
+
+ if (number.forcePadding) {
+ os.width(*number.forcePadding);
+ os.fill('0');
+ }
+
+ // When Integer is smaller than int, the unary plus converts the stored
+ // value into an equivalent integer because C++ "arithmetic operators do not
+ // accept types smaller than int as arguments, and integral promotions are
+ // automatically applied". For larger integer types, plus is a no-op.
+ os << std::hex << +number.io_manip;
+
+ os.fill(oldFill);
+ os.flags(oldFlags);
return os;
}
void
RandomUuid::print(std::ostream &os) const
{
- const auto savedFlags = os.flags();
- const auto savedFill = os.fill('0');
-
- os << std::hex;
-
os <<
- std::setw(8) << timeLow << '-' <<
- std::setw(4) << timeMid << '-' <<
- std::setw(4) << timeHiAndVersion << '-' <<
- std::setw(2) << +clockSeqHiAndReserved << std::setw(2) << +clockSeqLow << '-';
+ asHex(timeLow).minDigits(8) << '-' <<
+ asHex(timeMid).minDigits(4) << '-' <<
+ asHex(timeHiAndVersion).minDigits(4) << '-' <<
+ asHex(clockSeqHiAndReserved).minDigits(2) <<
+ asHex(clockSeqLow).minDigits(2) << '-';
for (size_t i = 0; i < sizeof(node); ++i)
- os << std::setw(2) << +node[i];
-
- os.fill(savedFill);
- os.flags(savedFlags);
+ os << asHex(node[i]).minDigits(2);
}
bool
#if USE_DEVPOLL
+#include "base/IoManip.h"
#include "comm/Loops.h"
#include "fd.h"
#include "fde.h"
5,
DEBUG_DEVPOLL ? 0 : 8,
"got FD " << fd
- << ",events=" << std::hex << do_poll.dp_fds[i].revents
- << ",monitoring=" << devpoll_state[fd].state
+ << ",events=" << asHex(do_poll.dp_fds[i].revents)
+ << ",monitoring=" << asHex(devpoll_state[fd].state)
<< ",F->read_handler=" << F->read_handler
<< ",F->write_handler=" << F->write_handler
);
#if USE_EPOLL
#include "base/CodeContext.h"
+#include "base/IoManip.h"
#include "comm/Loops.h"
#include "fde.h"
#include "globals.h"
F = &fd_table[fd];
CodeContext::Reset(F->codeContext);
debugs(5, DEBUG_EPOLL ? 0 : 8, "got FD " << fd << " events=" <<
- std::hex << cevents->events << " monitoring=" << F->epoll_state <<
+ asHex(cevents->events) << " monitoring=" << asHex(F->epoll_state) <<
" F->read_handler=" << F->read_handler << " F->write_handler=" << F->write_handler);
// TODO: add EPOLLPRI??
#include "squid.h"
#include "base/CodeContext.h"
#include "base/InstanceId.h"
+#include "base/IoManip.h"
#include "base/Random.h"
#include "base/RunnersRegistry.h"
#include "comm.h"
return;
}
- debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex << message->id << ", " << std::dec << n << " answers");
+ debugs(78, 3, "idnsGrokReply: QID 0x" << asHex(message->id) << ", " << n << " answers");
idns_query *q = idnsFindQuery(message->id);
}
debugs(78, 3, "idnsCheckQueue: ID " << q->xact_id <<
- " QID 0x" << std::hex << std::setfill('0') <<
- std::setw(4) << q->query_id << ": timeout" );
+ " QID 0x" << asHex(q->query_id).minDigits(4) << ": timeout");
dlinkDelete(&q->lru, &lru_list);
q->pending = 0;
idnsSendQuery(q);
} else {
debugs(78, 2, "idnsCheckQueue: ID " << q->xact_id <<
- " QID 0x" << std::hex << q->query_id <<
- " : giving up after " << std::dec << q->nsends << " tries and " <<
+ " QID 0x" << asHex(q->query_id) <<
+ ": giving up after " << q->nsends << " tries and " <<
std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
if (q->rcode != 0)
q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max);
debugs(78, 3, "buf is " << q->sz << " bytes for " << q->name <<
- ", id = 0x" << std::hex << q->query_id);
+ ", id = 0x" << asHex(q->query_id));
if (!q->sz) {
delete q;
return;
}
debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
- ", id = 0x" << std::hex << q->query_id);
+ ", id = 0x" << asHex(q->query_id));
idnsCheckMDNS(q);
idnsStartQuery(q, callback, data);
}
debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
- ", id = 0x" << std::hex << q->query_id);
+ ", id = 0x" << asHex(q->query_id));
q->permit_mdns = Config.onoff.dns_mdns;
idnsStartQuery(q, callback, data);
#ifndef _SQUID_SRC_ERROR_EXCEPTIONERRORDETAIL_H
#define _SQUID_SRC_ERROR_EXCEPTIONERRORDETAIL_H
+#include "base/IoManip.h"
#include "error/Detail.h"
#include "sbuf/SBuf.h"
#include "sbuf/Stream.h"
/* ErrorDetail API */
SBuf brief() const override {
- return ToSBuf("exception=", std::hex, exceptionId);
+ return ToSBuf("exception=", asHex(exceptionId));
}
SBuf verbose(const HttpRequestPointer &) const override {
- return ToSBuf("Exception (ID=", std::hex, exceptionId, ')');
+ return ToSBuf("Exception (ID=", asHex(exceptionId), ')');
}
private:
#if USE_SQUID_EUI
+#include "base/IoManip.h"
#include "debug/Stream.h"
#include "eui/Eui48.h"
#include "globals.h"
* Solaris code by R. Gancarz <radekg@solaris.elektrownia-lagisza.com.pl>
*/
+/// I/O manipulator to print EUI48 addresses
+template <typename HardwareAddress>
+class AsEui48 {
+public:
+ /// caller is responsible for the passed address storage lifetime
+ explicit AsEui48(const HardwareAddress * const a): hardwareAddress(a) {}
+ const HardwareAddress * const hardwareAddress;
+};
+
+template <typename HardwareAddress>
+static std::ostream &
+operator <<(std::ostream &os, const AsEui48<HardwareAddress> &manipulator)
+{
+ const auto &ha = *manipulator.hardwareAddress;
+ os <<
+ asHex(ha.sa_data[0] & 0xff).minDigits(2) << ':' <<
+ asHex(ha.sa_data[1] & 0xff).minDigits(2) << ':' <<
+ asHex(ha.sa_data[2] & 0xff).minDigits(2) << ':' <<
+ asHex(ha.sa_data[3] & 0xff).minDigits(2) << ':' <<
+ asHex(ha.sa_data[4] & 0xff).minDigits(2) << ':' <<
+ asHex(ha.sa_data[5] & 0xff).minDigits(2);
+ return os;
+}
+
bool
Eui::Eui48::decode(const char *asc)
{
return false;
}
- debugs(28, 4, "id=" << (void*)this << " got address "<< std::setfill('0') << std::hex <<
- std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
+ debugs(28, 4, "id=" << static_cast<void*>(this) << " got address " << AsEui48(&arpReq.arp_ha));
set(arpReq.arp_ha.sa_data, 6);
return true;
continue;
}
- debugs(28, 4, "id=" << (void*)this << " got address "<< std::setfill('0') << std::hex <<
- std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff) << " on "<<
- std::setfill(' ') << ifr->ifr_name);
+ debugs(28, 4, "id=" << static_cast<void*>(this) << " got address " << AsEui48(&arpReq.arp_ha) <<
+ " on " << ifr->ifr_name);
set(arpReq.arp_ha.sa_data, 6);
return false;
}
- debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
- std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
+ debugs(28, 4, "Got address " << AsEui48(&arpReq.arp_ha));
set(arpReq.arp_ha.sa_data, 6);
return true;
return false;
}
- debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
- std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
+ debugs(28, 4, "Got address " << AsEui48(&arpReq.arp_ha));
set(arpReq.arp_ha.sa_data, 6);
return true;
return false;
}
- debugs(28, 4, "Got address "<< std::setfill('0') << std::hex <<
- std::setw(2) << (arpReq.arp_ha.sa_data[0] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[1] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[2] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[3] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[4] & 0xff) << ":" <<
- std::setw(2) << (arpReq.arp_ha.sa_data[5] & 0xff));
+ debugs(28, 4, "Got address " << AsEui48(&arpReq.arp_ha));
set(arpReq.arp_ha.sa_data, 6);
return true;
/* DEBUG: section 47 Store Directory Routines */
#include "squid.h"
+#include "base/IoManip.h"
#include "cache_cf.h"
#include "CollapsedForwarding.h"
#include "ConfigOption.h"
sio->writeableAnchor_ = slot;
debugs(47,5, "dir " << index << " created new filen " <<
- std::setfill('0') << std::hex << std::uppercase << std::setw(8) <<
- sio->swap_filen << std::dec << " starting at " <<
+ asHex(sio->swap_filen).upperCase().minDigits(8) << " starting at " <<
diskOffset(sio->swap_filen));
sio->file(theFile);
sio->writeableAnchor_ = update.fresh.anchor;
debugs(47,5, "dir " << index << " updating filen " <<
- std::setfill('0') << std::hex << std::uppercase << std::setw(8) <<
- sio->swap_filen << std::dec << " starting at " <<
+ asHex(sio->swap_filen).upperCase().minDigits(8) << " starting at " <<
diskOffset(sio->swap_filen));
sio->file(theFile);
sio->file(theFile);
debugs(47,5, "dir " << index << " has old filen: " <<
- std::setfill('0') << std::hex << std::uppercase << std::setw(8) <<
- sio->swap_filen);
+ asHex(sio->swap_filen).upperCase().minDigits(8));
// When StoreEntry::swap_filen for e was set by our anchorEntry(), e had a
// public key, but it could have gone private since then (while keeping the
/* DEBUG: section 47 Store Directory Routines */
#include "squid.h"
+#include "base/IoManip.h"
#include "fs_io.h"
#include "globals.h"
#include "RebuildState.h"
swapData.swap_filen &= 0x00FFFFFF;
debugs(47, 3, swap_log_op_str[(int) swapData.op] << " " <<
- storeKeyText(swapData.key) << " "<< std::setfill('0') <<
- std::hex << std::uppercase << std::setw(8) <<
- swapData.swap_filen);
+ storeKeyText(swapData.key) << " " <<
+ asHex(swapData.swap_filen).upperCase().minDigits(8));
if (swapData.op == SWAP_LOG_ADD) {
(void) 0;
int fd = -1;
int dirs_opened = 0;
debugs(47, 3, "flag=" << flags.init << ", " <<
- sd->index << ": /"<< std::setfill('0') << std::hex <<
- std::uppercase << std::setw(2) << curlvl1 << "/" << std::setw(2) <<
- curlvl2);
+ sd->index << ": /" <<
+ asHex(curlvl1).upperCase().minDigits(2) << "/" <<
+ asHex(curlvl2).upperCase().minDigits(2));
if (done)
return -2;
}
if (!UFSSwapDir::FilenoBelongsHere(fn, sd->index, curlvl1, curlvl2)) {
- debugs(47, 3, std::setfill('0') <<
- std::hex << std::uppercase << std::setw(8) << fn <<
- " does not belong in " << std::dec << sd->index << "/" <<
- curlvl1 << "/" << curlvl2);
-
+ debugs(47, 3, asHex(fn).upperCase().minDigits(8) <<
+ " does not belong in " << sd->index << "/" <<
+ asHex(curlvl1).upperCase().minDigits(2) << "/" <<
+ asHex(curlvl2).upperCase().minDigits(2));
continue;
}
/* DEBUG: section 79 Storage Manager UFS Interface */
#include "squid.h"
+#include "base/IoManip.h"
#include "DiskIO/DiskFile.h"
#include "DiskIO/DiskIOStrategy.h"
#include "DiskIO/ReadRequest.h"
{
if (opening) {
opening = false;
- debugs(79, 3, "UFSStoreState::ioCompletedNotification: dirno " <<
- swap_dirn << ", fileno "<< std::setfill('0') << std::hex <<
- std::setw(8) << swap_filen << " status "<< std::setfill(' ') <<
- std::dec << theFile->error());
+ debugs(79, 3, "opening: dirno " << swap_dirn <<
+ ", fileno " << asHex(swap_filen).minDigits(8) <<
+ " status " << theFile->error());
assert (FILE_MODE(mode) == O_RDONLY);
openDone();
if (creating) {
creating = false;
- debugs(79, 3, "UFSStoreState::ioCompletedNotification: dirno " <<
- swap_dirn << ", fileno "<< std::setfill('0') << std::hex <<
- std::setw(8) << swap_filen << " status "<< std::setfill(' ') <<
- std::dec << theFile->error());
+ debugs(79, 3, "creating: dirno " << swap_dirn <<
+ ", fileno " << asHex(swap_filen).minDigits(8) <<
+ " status " << theFile->error());
openDone();
}
assert (!(closing ||opening));
- debugs(79, 3, "diskd::ioCompleted: dirno " << swap_dirn << ", fileno "<<
- std::setfill('0') << std::hex << std::setw(8) << swap_filen <<
- " status "<< std::setfill(' ') << std::dec << theFile->error());
+ debugs(79, 3, "error: dirno " << swap_dirn <<
+ ", fileno " << asHex(swap_filen).minDigits(8) <<
+ " status " << theFile->error());
/* Ok, notification past open means an error has occurred */
assert (theFile->error());
Fs::Ufs::UFSStoreState::closeCompleted()
{
assert (closing);
- debugs(79, 3, "UFSStoreState::closeCompleted: dirno " << swap_dirn <<
- ", fileno "<< std::setfill('0') << std::hex << std::setw(8) <<
- swap_filen << " status "<< std::setfill(' ') << std::dec <<
- theFile->error());
+ debugs(79, 3, "dirno " << swap_dirn <<
+ ", fileno " << asHex(swap_filen).minDigits(8) <<
+ " status " << theFile->error());
if (theFile->error()) {
debugs(79,3, "theFile->error() ret " << theFile->error());
void
Fs::Ufs::UFSStoreState::close(int)
{
- debugs(79, 3, "UFSStoreState::close: dirno " << swap_dirn << ", fileno "<<
- std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
+ // TODO: De-duplicate position printing Fs::Ufs code and fix upperCase() inconsistency.
+ debugs(79, 3, "dirno " << swap_dirn <<
+ ", fileno " << asHex(swap_filen).upperCase().minDigits(8));
tryClosing(); // UFS does not distinguish different closure types
}
read.callback = aCallback;
read.callback_data = cbdataReference(aCallbackData);
- debugs(79, 3, "UFSStoreState::read_: dirno " << swap_dirn << ", fileno "<<
- std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
+ debugs(79, 3, "dirno " << swap_dirn <<
+ ", fileno " << asHex(swap_filen).minDigits(8));
offset_ = aOffset;
read_buf = buf;
reading = true;
bool
Fs::Ufs::UFSStoreState::write(char const *buf, size_t size, off_t aOffset, FREE * free_func)
{
- debugs(79, 3, "UFSStoreState::write: dirn " << swap_dirn << ", fileno "<<
- std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
+ debugs(79, 3, "dirno " << swap_dirn <<
+ ", fileno " << asHex(swap_filen).minDigits(8));
if (theFile->error()) {
debugs(79, DBG_IMPORTANT, "ERROR: avoid write on theFile with error");
{
assert (result.getRaw());
reading = false;
- debugs(79, 3, "UFSStoreState::readCompleted: dirno " << swap_dirn <<
- ", fileno "<< std::setfill('0') << std::hex << std::setw(8) <<
- swap_filen << " len "<< std::setfill(' ') << std::dec << len);
+ debugs(79, 3, "dirno " << swap_dirn <<
+ ", fileno " << asHex(swap_filen).minDigits(8) <<
+ " len " << len);
if (len > 0)
offset_ += len;
void
Fs::Ufs::UFSStoreState::writeCompleted(int, size_t len, RefCount<WriteRequest>)
{
- debugs(79, 3, "dirno " << swap_dirn << ", fileno " <<
- std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen <<
+ debugs(79, 3, "dirno " << swap_dirn <<
+ ", fileno " << asHex(swap_filen).upperCase().minDigits(8) <<
", len " << len);
/*
* DPW 2006-05-24
#include "squid.h"
+#include "base/IoManip.h"
#include "DiskIO/DiskIOStrategy.h"
#include "UFSStoreState.h"
#include "UFSStrategy.h"
StoreIOState::STIOCB * aCallback, void *callback_data)
{
assert (((UFSSwapDir *)SD)->IO == this);
- debugs(79, 3, "fileno "<< std::setfill('0') << std::hex
- << std::uppercase << std::setw(8) << e->swap_filen);
+ debugs(79, 3, "fileno " << asHex(e->swap_filen).upperCase().minDigits(8));
/* to consider: make createstate a private UFSStrategy call */
StoreIOState::Pointer sio = createState (SD, e, aCallback, callback_data);
assert (((UFSSwapDir *)SD)->IO == this);
/* Allocate a number */
sfileno filn = ((UFSSwapDir *)SD)->mapBitAllocate();
- debugs(79, 3, "fileno "<< std::setfill('0') <<
- std::hex << std::uppercase << std::setw(8) << filn);
+ debugs(79, 3, "fileno " << asHex(filn).upperCase().minDigits(8));
/* Shouldn't we handle a 'bitmap full' error here? */
#define CLEAN_BUF_SZ 16384
#include "squid.h"
+#include "base/IoManip.h"
#include "base/Random.h"
#include "cache_cf.h"
#include "ConfigOption.h"
void
Fs::Ufs::UFSSwapDir::dumpEntry(StoreEntry &e) const
{
- debugs(47, DBG_CRITICAL, "FILENO "<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << e.swap_filen);
- debugs(47, DBG_CRITICAL, "PATH " << fullPath(e.swap_filen, nullptr) );
+ debugs(47, DBG_CRITICAL, "FILENO " << asHex(e.swap_filen).upperCase().minDigits(8) <<
+ ", PATH " << fullPath(e.swap_filen, nullptr));
e.dump(0);
}
int)
{
StoreEntry *e = nullptr;
- debugs(47, 5, storeKeyText(key) <<
- ", fileno="<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << file_number);
+ debugs(47, 5, storeKeyText(key) << ", fileno=" << asHex(file_number).upperCase().minDigits(8));
/* if you call this you'd better be sure file_number is not
* already in use! */
e = new StoreEntry();
void
Fs::Ufs::UFSSwapDir::unlinkFile(sfileno f)
{
- debugs(79, 3, "unlinking fileno " << std::setfill('0') <<
- std::hex << std::uppercase << std::setw(8) << f << " '" <<
+ debugs(79, 3, "unlinking fileno " << asHex(f).upperCase().minDigits(8) << " '" <<
fullPath(f,nullptr) << "'");
/* commonUfsDirMapBitReset(this, f); */
IO->unlinkFile(fullPath(f,nullptr));
k = 10;
for (n = 0; n < k; ++n) {
- debugs(36, 3, "Cleaning file "<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << files[n]);
+ debugs(36, 3, "Cleaning file " << asHex(files[n]).upperCase().minDigits(8));
SBuf p2(p1);
p2.appendf("/%08X", files[n]);
safeunlink(p2.c_str(), 0);
{
auto *mark = static_cast<nfmark_t *>(connmark);
*mark = nfct_get_attr_u32(ct, ATTR_MARK);
- debugs(17, 3, asHex(*mark));
+ debugs(17, 3, "mark=0x" << asHex(*mark));
return NFCT_CB_CONTINUE;
}
/* DEBUG: section 54 Interprocess Communication */
#include "squid.h"
+#include "base/IoManip.h"
#include "ipc/StoreMap.h"
#include "sbuf/SBuf.h"
#include "SquidConfig.h"
" expires=" << anchor.basics.expires << "\n" <<
" lastmod=" << anchor.basics.lastmod << "\n" <<
" refcount=" << anchor.basics.refcount << "\n" <<
- " flags=0x" << std::hex << anchor.basics.flags << std::dec << "\n" <<
+ " flags=0x" << asHex(anchor.basics.flags) << "\n" <<
" start=" << anchor.start << "\n" <<
" splicingPoint=" << anchor.splicingPoint << "\n" <<
" lock=" << anchor.lock << "\n" <<
/* DEBUG: section 14 IP Cache */
#include "squid.h"
+#include "base/IoManip.h"
#include "CacheManager.h"
#include "cbdata.h"
#include "debug/Messages.h"
{
ipcache_entry *i = nullptr;
assert(name);
- debugs(14, 3, "ipcache_gethostbyname: '" << name << "', flags=" << std::hex << flags);
+ debugs(14, 3, "'" << name << "', flags=" << asHex(flags));
++IpcacheStats.requests;
i = ipcache_get(name);
#if USE_OPENSSL
/// Extract and remember errors stored internally by the TLS library.
if ((lib_error_no = ERR_get_error())) {
- debugs(83, 7, "got " << asHex(lib_error_no));
+ debugs(83, 7, "got 0x" << asHex(lib_error_no));
// more errors may be stacked
// TODO: Save/detail all stacked errors by always flushing stale ones.
ForgetErrors();
#if USE_OPENSSL
// TODO: Log ERR_error_string_n() instead, despite length, whitespace?
// Example: `error:1408F09C:SSL routines:ssl3_get_record:http request`.
- os << "+TLS_LIB_ERR=" << std::hex << std::uppercase << lib_error_no << std::nouppercase << std::dec;
+ os << "+TLS_LIB_ERR=" << asHex(lib_error_no).upperCase();
#elif USE_GNUTLS
os << '+' << gnutls_strerror_name(lib_error_no);
#endif
/* handle unsupported versions */
const uint16_t vRaw = (vMajor << 8) | vMinor;
- debugs(83, 7, "unsupported: " << asHex(vRaw));
+ debugs(83, 7, "unsupported: 0x" << asHex(vRaw));
if (beStrict)
- throw TextException(ToSBuf("unsupported TLS version: ", asHex(vRaw)), Here());
+ throw TextException(ToSBuf("unsupported TLS version: 0x", asHex(vRaw)), Here());
// else hide unsupported version details from the caller behind PROTO_NONE
return AnyP::ProtocolVersion();
}
#include "squid.h"
#include "anyp/PortCfg.h"
+#include "base/IoManip.h"
#include "base/Packable.h"
#include "cache_cf.h"
#include "error/SysErrorDetail.h"
int codes;
if (DH_check(dhp, &codes) == 0) {
if (codes) {
- debugs(83, DBG_IMPORTANT, "WARNING: Failed to verify DH parameters '" << dhParamsFile << "' (" << std::hex << codes << ")");
+ debugs(83, DBG_IMPORTANT, "WARNING: Failed to verify DH parameters '" << dhParamsFile << "' (" << asHex(codes) << ")");
DH_free(dhp);
dhp = nullptr;
}
/* DEBUG: section 83 SSL accelerator support */
#include "squid.h"
+#include "base/IoManip.h"
#include "ssl/support.h"
/* support.cc says this is needed */
// else if (where & SSL_CB_HANDSHAKE_DONE)
// debugs(83, 9, "SSL connection established");
- debugs(83, 7, "FD " << fd_ << " now: 0x" << std::hex << where << std::dec << ' ' <<
+ debugs(83, 7, "FD " << fd_ << " now: 0x" << asHex(where) << ' ' <<
SSL_state_string(ssl) << " (" << SSL_state_string_long(ssl) << ")");
}
{
unsigned int reported = 0; // efficiently marks ForgetErrors() call boundary
while (const auto errorToForget = ERR_get_error())
- os << Debug::Extra << "OpenSSL-saved error #" << (++reported) << ": " << asHex(errorToForget);
+ os << Debug::Extra << "OpenSSL-saved error #" << (++reported) << ": 0x" << asHex(errorToForget);
return os;
}
#include "squid.h"
#include "base/AsyncCbdataCalls.h"
+#include "base/IoManip.h"
#include "base/PackableStream.h"
#include "base/TextException.h"
#include "CacheDigest.h"
{
debugs(88, 3, "attaching entry with key " << getMD5Text() << " : " <<
swapStatusStr[status] << " " << dirn << " " <<
- std::hex << std::setw(8) << std::setfill('0') <<
- std::uppercase << fno);
+ asHex(fno).upperCase().minDigits(8));
checkDisk();
swap_dirn = dirn;
swap_filen = fno;
/* DEBUG: section 47 Store Directory Routines */
#include "squid.h"
+#include "base/IoManip.h"
#include "cache_cf.h"
#include "ConfigParser.h"
#include "debug/Messages.h"
swap_log_op_str[op] << " " <<
e->getMD5Text() << " " <<
e->swap_dirn << " " <<
- std::hex << std::uppercase << std::setfill('0') << std::setw(8) << e->swap_filen);
+ asHex(e->swap_filen).upperCase().minDigits(8));
e->disk().logEntry(*e, op);
}
/* DEBUG: section 20 Storage Manager Swapout Functions */
#include "squid.h"
+#include "base/IoManip.h"
#include "cbdata.h"
#include "CollapsedForwarding.h"
#include "globals.h"
* metadata there is to store
*/
debugs(20, 5, "storeSwapOutStart: Begin SwapOut '" << e->url() << "' to dirno " <<
- e->swap_dirn << ", fileno " << std::hex << std::setw(8) << std::setfill('0') <<
- std::uppercase << e->swap_filen);
+ e->swap_dirn << ", fileno " << asHex(e->swap_filen).upperCase().minDigits(8));
/* If we start swapping out objects with OutOfBand Metadata,
* then this code needs changing
*/
// if object_size is still unknown, the entry was probably aborted
if (errflag || e->objectLen() < 0) {
debugs(20, 2, "storeSwapOutFileClosed: dirno " << e->swap_dirn << ", swapfile " <<
- std::hex << std::setw(8) << std::setfill('0') << std::uppercase <<
- e->swap_filen << ", errflag=" << errflag);
+ asHex(e->swap_filen).upperCase().minDigits(8) <<
+ ", errflag=" << errflag);
if (errflag == DISK_NO_SPACE_LEFT) {
/* TODO: this should be handle by the link from store IO to
} else {
/* swapping complete */
debugs(20, 3, "storeSwapOutFileClosed: SwapOut complete: '" << e->url() << "' to " <<
- e->swap_dirn << ", " << std::hex << std::setw(8) << std::setfill('0') <<
- std::uppercase << e->swap_filen);
+ e->swap_dirn << ", " << asHex(e->swap_filen).upperCase().minDigits(8));
debugs(20, 5, "swap_file_sz = " <<
e->objectLen() << " + " << mem->swap_hdr_sz);
--- /dev/null
+/*
+ * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "base/IoManip.h"
+#include "compat/cppunit.h"
+#include "unitTestMain.h"
+
+#include <cstdint>
+#include <limits>
+#include <sstream>
+
+class TestIoManip: public CPPUNIT_NS::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestIoManip);
+ CPPUNIT_TEST(testAsHex);
+ CPPUNIT_TEST_SUITE_END();
+
+protected:
+ void testAsHex();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( TestIoManip );
+
+/// resets the given stream, including any formatting
+static void
+resetStream(std::ostringstream &dirty)
+{
+ std::ostringstream clean;
+ dirty.swap(clean);
+}
+
+/// returns the result of printing the given manipulator
+template <typename Integer>
+static std::string
+toStdString(const AsHex<Integer> &manipulator)
+{
+ std::ostringstream os;
+ os << manipulator;
+ return os.str();
+}
+
+void
+TestIoManip::testAsHex()
+{
+ // basic values
+ CPPUNIT_ASSERT_EQUAL(std::string("0"), toStdString(asHex(0)));
+ CPPUNIT_ASSERT_EQUAL(std::string("123abc"), toStdString(asHex(0x123abc)));
+
+ // large values
+ CPPUNIT_ASSERT_EQUAL(std::string("7fffffffffffffff"), toStdString(asHex(std::numeric_limits<int64_t>::max())));
+ CPPUNIT_ASSERT_EQUAL(std::string("ffffffffffffffff"), toStdString(asHex(std::numeric_limits<uint64_t>::max())));
+
+ // negative values
+ // C++ defines printing with std::hex in terms of calling std::printf() with
+ // %x (or %X) conversion specifier; printf(%x) interprets its value argument
+ // as an unsigned integer, making it impossible for std::hex to print
+ // negative values as negative hex integers. AsHex has the same limitation.
+ CPPUNIT_ASSERT_EQUAL(std::string("80000000"), toStdString(asHex(std::numeric_limits<int32_t>::min())));
+
+ // integer and integer-like types that std::ostream formats specially by default
+ CPPUNIT_ASSERT_EQUAL(std::string("0"), toStdString(asHex(false)));
+ CPPUNIT_ASSERT_EQUAL(std::string("1"), toStdString(asHex(true)));
+ CPPUNIT_ASSERT_EQUAL(std::string("5a"), toStdString(asHex('Z')));
+ CPPUNIT_ASSERT_EQUAL(std::string("77"), toStdString(asHex(int8_t(0x77))));
+ CPPUNIT_ASSERT_EQUAL(std::string("ff"), toStdString(asHex(uint8_t(0xFF))));
+
+ // other interesting integer-like types we may want to print
+ enum { enumValue = 0xABCD };
+ CPPUNIT_ASSERT_EQUAL(std::string("abcd"), toStdString(asHex(enumValue)));
+ struct { uint8_t bitField:2; } s;
+ s.bitField = 3; // TODO: Convert to default initializer after switching to C++20.
+ CPPUNIT_ASSERT_EQUAL(std::string("3"), toStdString(asHex(s.bitField)));
+
+ // padding with zeros works
+ CPPUNIT_ASSERT_EQUAL(std::string("1"), toStdString(asHex(1).minDigits(1)));
+ CPPUNIT_ASSERT_EQUAL(std::string("01"), toStdString(asHex(1).minDigits(2)));
+ CPPUNIT_ASSERT_EQUAL(std::string("001"), toStdString(asHex(1).minDigits(3)));
+
+ // padding with zeros works even for zero values
+ CPPUNIT_ASSERT_EQUAL(std::string("0000"), toStdString(asHex(0).minDigits(4)));
+
+ // minDigits() does not truncate
+ CPPUNIT_ASSERT_EQUAL(std::string("1"), toStdString(asHex(0x1).minDigits(0)));
+ CPPUNIT_ASSERT_EQUAL(std::string("12"), toStdString(asHex(0x12).minDigits(1)));
+ CPPUNIT_ASSERT_EQUAL(std::string("123"), toStdString(asHex(0x123).minDigits(2)));
+
+ // upperCase() forces uppercase
+ CPPUNIT_ASSERT_EQUAL(std::string("A"), toStdString(asHex(0xA).upperCase()));
+ CPPUNIT_ASSERT_EQUAL(std::string("1A2B"), toStdString(asHex(0x1a2b).upperCase(true)));
+
+ std::ostringstream ss;
+
+ // upperCase(false) forces lowercase
+ ss << std::uppercase << asHex(0xABC).upperCase(false);
+ CPPUNIT_ASSERT_EQUAL(std::string("abc"), ss.str());
+ resetStream(ss);
+
+ // a combination of formatting options
+ CPPUNIT_ASSERT_EQUAL(std::string("01A"), toStdString(asHex(0x1A).upperCase().minDigits(3)));
+
+ // Test the effects of stream formatting flags on AsHex printing and the
+ // effects of AsHex printing on stream formatting flags.
+
+ // upperCase() effects are not leaked into the stream
+ ss << asHex(0xa0).upperCase() << asHex(0xa0);
+ CPPUNIT_ASSERT_EQUAL(std::string("A0a0"), ss.str());
+ resetStream(ss);
+
+ // original std::showbase is honored
+ ss << std::showbase << asHex(1);
+ CPPUNIT_ASSERT_EQUAL(std::string("0x1"), ss.str());
+ resetStream(ss);
+
+ // original std::uppercase is honored
+ ss << std::uppercase << std::hex << 0xA << asHex(0xB) << 0xC;
+ CPPUNIT_ASSERT_EQUAL(std::string("ABC"), ss.str());
+ resetStream(ss);
+
+ // original std::uppercase is preserved
+ ss << std::uppercase << std::hex << 0xA << asHex(0xB).upperCase(false) << 0xC;
+ CPPUNIT_ASSERT_EQUAL(std::string("AbC"), ss.str());
+ resetStream(ss);
+
+ // original std::oct is preserved
+ ss << std::oct << 9 << asHex(0xA) << 11;
+ CPPUNIT_ASSERT_EQUAL(std::string("11a13"), ss.str());
+ resetStream(ss);
+
+ // original std::setw() is honored
+ ss << std::setw(4) << asHex(0x1);
+ CPPUNIT_ASSERT_EQUAL(std::string(" 1"), ss.str());
+ resetStream(ss);
+
+ // original std::setw() is consumed (by the printed number)
+ ss << std::setw(4) << asHex(0x1) << 2;
+ CPPUNIT_ASSERT_EQUAL(std::string(" 12"), ss.str());
+ resetStream(ss);
+
+ // original std::setfill() is honored
+ ss << std::setfill('.') << std::setw(4) << asHex(0x2);
+ CPPUNIT_ASSERT_EQUAL(std::string("...2"), ss.str());
+ resetStream(ss);
+
+ // original std::setfill() is preserved
+ ss << std::setfill('.') << asHex(0x3).minDigits(2) << std::setw(4) << 4;
+ CPPUNIT_ASSERT_EQUAL(std::string("03...4"), ss.str());
+ resetStream(ss);
+}
+
+int
+main(int argc, char *argv[])
+{
+ return TestProgram().run(argc, argv);
+}
+