// bdlb_print.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BDLB_PRINT #define INCLUDED_BDLB_PRINT #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide platform-independent stream utilities. // //@CLASSES: // bdlb::Print: namespace for procedures on streams // bdlb::PrintStringHexDumper: create/print hex buffers, multi-line // bdlb::PrintStringSingleLineHexDumper: create/print hex buffers, single line // //@DESCRIPTION: This component provides a namespace, 'bdlb::Print', containing // utility functions for formatting data to 'bsl::ostream' objects. These // functions provide several variations of hexadecimal format, allow // platform-independent representation of 'void *' pointers, and can help with // the indentation of hierarchical data. // // This component also provides two helper classes, // 'bdlb::PrintStringHexDumper' and 'bdlb::PrintStringSingleLineHexDumper', // that define 'operator<<' so they can be used in chains of '<<' operations. // The 'bdlb::PrintStringHexDumper' class produces formatted, possibly // multi-line output, whereas the 'bdlb::PrintStringSingleLineHexDumper' class // produces a simple sequence of hexadecimal digits (and no newline). // ///'xxd'-Compatible 'hexDump' /// - - - - - - - - - - - - - // The output generated by the 'hexDump' functions is not 'xxd'-compatible (see // 'http://gd.tuwien.ac.at/linuxcommand.org/man_pages/xxd1.html'). The // following perl script is provided that will convert 'hexDump' output into // 'xxd'-compatible form. Run the script with a file containing the 'hexDump' // output as the first argument. //.. // #!/usr/bin/perl -w // // use strict; // // my $num = 0; // while (<>) { // next if (!$_); // my $str = $_; // next if !($str =~ s/^[^:]*?:\s*//); // my $h = sprintf("%08X",$num); // $str =~ s/(\S{4})([\S\W]{4})\s?([\S\W]{4})([\S\W]{4})\s?([\S\W]{4})? // ([\S\W]{4})?\s?([\S\W]{4})?([\S\W]{4})?/$1 $2 $3 $4 $5 $6 $7 $8/; // $str =~ s/\s \|([^|]+)\|.*$/ $1/; // print "$h: "; // print $str; // $num = $num + 16; // } //.. // ///Usage ///----- // In this section we show intended usage of this component. // ///Example 1: Using 'printPtr' ///- - - - - - - - - - - - - - // The default output produced from pointer values is non-standard across // vendor platforms. The 'printPtr' method addresses this inconsistency by // always producing a consistent format for a given pointer size: //.. // const void *a = reinterpret_cast<void *>(0x0); // const void *b = reinterpret_cast<void *>(0xf2ff); // const void *c = reinterpret_cast<void *>(0x0123); // const void *d = reinterpret_cast<void *>(0xf1f2abc9); // // bsl::ostringstream out1; // // bdlb::Print::printPtr(out1, a); out1 << endl; // bdlb::Print::printPtr(out1, b); out1 << endl; // bdlb::Print::printPtr(out1, c); out1 << endl; // bdlb::Print::printPtr(out1, d); out1 << endl; // // assert("0" "\n" // "f2ff" "\n" // "123" "\n" // "f1f2abc9" "\n" == out1.str()); //.. // ///Example 2: Using the Helper Classes ///- - - - - - - - - - - - - - - - - - // The two helper classes allow users to stream a hexadecimal representation // of a sequence of bytes into an output stream. // // The 'bdlb::PrintStringHexDumper' provides a formatted, possibly multi-line // representation: //.. // char buf[] = "abcdefghijklmnopqrstuvwxyz"; // // bsl::ostringstream out2a; // out2a << bdlb::PrintStringHexDumper(buf, sizeof buf); // // assert( // " 0: 61626364 65666768 696A6B6C 6D6E6F70 |abcdefghijklmnop|\n" // " 16: 71727374 75767778 797A00 |qrstuvwxyz. |\n" // == out2a.str()); // // bsl::ostringstream out2b; // out2b << bdlb::PrintStringSingleLineHexDumper(buf, sizeof buf); //.. // The 'bdlb::PrintStringSingleLineHexDumper' provides a simple, single-line // representation. //.. // assert("6162636465666768696A6B6C6D6E6F707172737475767778797A00" // == out2b.str()); //.. #include <bdlscm_version.h> #include <bsls_assert.h> #include <bsls_review.h> #include <bsl_ostream.h> #include <bsl_utility.h> namespace BloombergLP { namespace bdlb { // ============ // struct Print // ============ struct Print { // Provide a namespace for the interface to a suite of procedural stream // operations. // CLASS METHODS static bsl::ostream& indent(bsl::ostream& stream, int level, int spacesPerLevel = 4); // Emit to the specified output 'stream' the number of spaces (' ') // equal to the absolute value of the product of the specified 'level' // and 'spacesPerLevel' or, if 'level' is negative, nothing at all. // Return a reference providing modifiable access to 'stream'. The // behavior is undefined unless the absolute value of the product of // the specified 'level' and 'spacesPerLevel' is representable as // 'int'. static bsl::ostream& newlineAndIndent(bsl::ostream& stream, int level, int spacesPerLevel = 4); // Emit to the specified 'stream' a newline ('\n') followed by the // number of spaces (' ') equal to the absolute value of the product // of the specified 'level' and 'spacesPerLevel' or, if // 'spacesPerLevel' is negative, emit a single space (and *no* // newline). Return a reference providing modifiable access to // 'stream'. The behavior is undefined unless the absolute value of // the product of the specified 'level' and 'spacesPerLevel' is // representable as 'int'. static void printPtr(bsl::ostream& stream, const void *value); // Print to the specified 'stream' the specified pointer 'value' in a // standard format. The output is in hexadecimal format with a maximum // length of '2 * sizeof(void *)'. The output does not have leading // zeros and is not preceded by '0x'. The hexadecimal digits ('a' to // 'f', inclusive) are expressed in lower case. static bsl::ostream& printString(bsl::ostream& stream, const char *string, int length, bool escapeBackSlash = false); // Print to the specified 'stream' the specified 'string' of the // specified 'length' and return a reference providing modifiable // access to 'stream'. If the optionally specified 'escapeBackSlash' // flag is 'true', then all occurrences of the backslash character // ('\') in the 'string' are escaped (i.e., expanded to "\\") when // written to the 'stream'. Note that non-printable characters in // 'string' will be printed in their hexadecimal representation // ('\xHH'). If 'stream' is not valid on entry, this operation has no // effect. The behavior is undefined unless '0 <= length'. static bsl::ostream& hexDump(bsl::ostream& stream, const char *buffer, int length); // Print in hexadecimal format the contents of the specified 'buffer' // of the specified 'length' to the specified 'stream', and return a // reference providing modifiable access to 'stream'. The behavior is // undefined unless '0 <= length'. static bsl::ostream& hexDump(bsl::ostream& stream, bsl::pair<const char *, int > *buffers, int numBuffers); // Print to the specified 'stream' the specified 'numBuffers' buffers // supplied by specified 'buffers' in a hexadecimal representation (16 // chars per line) followed by the ASCII representation. Return a // reference providing modifiable access to 'stream'. The array of // buffers are supplied as a 'bsl::pair<const char*, int> *' where the // first element is a pointer to the data, and the second element is // the length of the buffer. The behavior is undefined unless // '0 <= numBuffers'. Note that the contents of the buffers are // concatenated and boundaries between buffers are not demarcated. template <class INPUT_ITERATOR> static bsl::ostream& singleLineHexDump(bsl::ostream& stream, INPUT_ITERATOR begin, INPUT_ITERATOR end); // Print to the specified 'stream' the uppercase hex encoding of the // byte sequence defined by the specified 'begin' and 'end' iterators // of the parameterized 'INPUT_ITERATOR' type, and return a reference // providing modifiable access to 'stream'. Note that 'INPUT_ITERATOR' // need not be random-access, i.e., it need support only increment // ('++') and equality comparison ('=='). See the non-template version // of this function if insulation and/or code bloat are a concern. static bsl::ostream& singleLineHexDump(bsl::ostream& stream, const char *begin, const char *end); // Print to the specified 'stream' the uppercase hex encoding of the // byte sequence defined by the specified 'begin' and 'end' iterators // into the specified 'stream', and return a reference providing // modifiable access to 'stream'. This function insulates clients from // its implementation, but unlike the member template version (above), // requires random access iterators of type 'const char *'. The // behavior is undefined unless both 'begin' and 'end' refer to the // same block of contiguous memory, and 'begin <= end'. static bsl::ostream& singleLineHexDump(bsl::ostream& stream, const char *buffer, int length); // Print to the specified 'stream' the contents of the specified // 'buffer' having the specified 'length' on a single line, and return // a reference to the modifiable 'stream'. The behavior is undefined // unless '0 <= length'. }; // =========================== // struct PrintStringHexDumper // =========================== struct PrintStringHexDumper { // Utility for hex dumping a blob to standard output streams. This class // has 'operator<<' defined for it, so it can be used as follows: //.. // bsl::vector<char> blob; // blob.resize(1024); // // // ... fill up the blob with some data ... // // bsl::cout << PrintStringHexDumper(blob.data(), blob.size()) // << bsl::endl; //.. // DATA const char *d_data_p; int d_length; // CREATORS PrintStringHexDumper(const char *data, int length); // Create a 'PrintStringHexDumper' object that can insert to an output // stream a formated (possibly multi-lined) hexadecimal representation // the specified 'data' of the specified 'length'. }; // FREE OPERATORS inline bsl::ostream& operator<<(bsl::ostream& stream, const PrintStringHexDumper& rhs); // Hex dump the data referenced by the specified 'rhs' to the specified // 'stream'. // ===================================== // struct PrintStringSingleLineHexDumper // ===================================== struct PrintStringSingleLineHexDumper { // Utility for hex dumping a string with no extra formatting to standard // output streams. This class has 'operator<<' defined for it, so it can // be used as follows: //.. // bsl::string str; // // // ... fill up the str with some data ... // // bsl::cout // << PrintStringSingleLineHexDumper(str.c_str(), str.size()) // << bsl::endl; //.. // DATA const char *d_data_p; int d_length; // CREATORS PrintStringSingleLineHexDumper(const char *data, int length); // Create a 'PrintStringSingleLineHexDumper' object that can insert to // an output stream a single-line hexadecimal representation the // specified 'data' of the specified 'length'. }; // FREE OPERATORS inline bsl::ostream& operator<<(bsl::ostream& stream, const PrintStringSingleLineHexDumper& rhs); // Hex dump the data referenced by the specified 'rhs' to the specified // 'stream'. // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ------------ // struct Print // ------------ // CLASS METHODS template <class INPUT_ITERATOR> bsl::ostream& Print::singleLineHexDump(bsl::ostream& stream, INPUT_ITERATOR begin, INPUT_ITERATOR end) { enum { k_LOCAL_BUF_SIZE = 512 }; static const char HEX[] = "0123456789ABCDEF"; char buf[k_LOCAL_BUF_SIZE]; unsigned int offset = 0; for (; begin != end; ++begin) { if (offset >= (k_LOCAL_BUF_SIZE - 1)) { stream.write(buf, offset); offset = 0; } const unsigned char c = *begin; buf[offset++] = HEX[(c >> 4) & 0xF]; buf[offset++] = HEX[c & 0xF]; } if (offset != 0) { stream.write(buf, offset); } return stream; } inline bsl::ostream& Print::singleLineHexDump(bsl::ostream& stream, const char *buffer, int length) { BSLS_REVIEW(buffer); BSLS_REVIEW(0 <= length); return singleLineHexDump(stream, buffer, buffer + length); } // --------------------------- // struct PrintStringHexDumper // --------------------------- // CREATORS inline PrintStringHexDumper::PrintStringHexDumper(const char *data, int length) : d_data_p(data) , d_length(length) { BSLS_REVIEW(data); BSLS_REVIEW(0 <= length); } } // close package namespace // FREE OPERATORS inline bsl::ostream& bdlb::operator<<(bsl::ostream& stream, const PrintStringHexDumper& rhs) { return Print::hexDump(stream, rhs.d_data_p, rhs.d_length); } namespace bdlb { // ------------------------------------- // struct PrintStringSingleLineHexDumper // ------------------------------------- // CREATORS inline PrintStringSingleLineHexDumper::PrintStringSingleLineHexDumper( const char *data, int length) : d_data_p(data) , d_length(length) { BSLS_REVIEW(data); BSLS_REVIEW(0 <= length); } } // close package namespace // FREE OPERATORS inline bsl::ostream& bdlb::operator<<(bsl::ostream& stream, const PrintStringSingleLineHexDumper& rhs) { return Print::singleLineHexDump(stream, rhs.d_data_p, rhs.d_length); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2015 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------