113481Sgiacomo.travaglini@arm.com// Copyright 2007, Google Inc.
213481Sgiacomo.travaglini@arm.com// All rights reserved.
313481Sgiacomo.travaglini@arm.com//
413481Sgiacomo.travaglini@arm.com// Redistribution and use in source and binary forms, with or without
513481Sgiacomo.travaglini@arm.com// modification, are permitted provided that the following conditions are
613481Sgiacomo.travaglini@arm.com// met:
713481Sgiacomo.travaglini@arm.com//
813481Sgiacomo.travaglini@arm.com//     * Redistributions of source code must retain the above copyright
913481Sgiacomo.travaglini@arm.com// notice, this list of conditions and the following disclaimer.
1013481Sgiacomo.travaglini@arm.com//     * Redistributions in binary form must reproduce the above
1113481Sgiacomo.travaglini@arm.com// copyright notice, this list of conditions and the following disclaimer
1213481Sgiacomo.travaglini@arm.com// in the documentation and/or other materials provided with the
1313481Sgiacomo.travaglini@arm.com// distribution.
1413481Sgiacomo.travaglini@arm.com//     * Neither the name of Google Inc. nor the names of its
1513481Sgiacomo.travaglini@arm.com// contributors may be used to endorse or promote products derived from
1613481Sgiacomo.travaglini@arm.com// this software without specific prior written permission.
1713481Sgiacomo.travaglini@arm.com//
1813481Sgiacomo.travaglini@arm.com// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1913481Sgiacomo.travaglini@arm.com// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2013481Sgiacomo.travaglini@arm.com// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2113481Sgiacomo.travaglini@arm.com// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2213481Sgiacomo.travaglini@arm.com// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2313481Sgiacomo.travaglini@arm.com// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2413481Sgiacomo.travaglini@arm.com// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2513481Sgiacomo.travaglini@arm.com// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2613481Sgiacomo.travaglini@arm.com// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2713481Sgiacomo.travaglini@arm.com// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2813481Sgiacomo.travaglini@arm.com// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2913481Sgiacomo.travaglini@arm.com//
3013481Sgiacomo.travaglini@arm.com// Author: wan@google.com (Zhanyong Wan)
3113481Sgiacomo.travaglini@arm.com
3213481Sgiacomo.travaglini@arm.com// Google Test - The Google C++ Testing Framework
3313481Sgiacomo.travaglini@arm.com//
3413481Sgiacomo.travaglini@arm.com// This file implements a universal value printer that can print a
3513481Sgiacomo.travaglini@arm.com// value of any type T:
3613481Sgiacomo.travaglini@arm.com//
3713481Sgiacomo.travaglini@arm.com//   void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
3813481Sgiacomo.travaglini@arm.com//
3913481Sgiacomo.travaglini@arm.com// It uses the << operator when possible, and prints the bytes in the
4013481Sgiacomo.travaglini@arm.com// object otherwise.  A user can override its behavior for a class
4113481Sgiacomo.travaglini@arm.com// type Foo by defining either operator<<(::std::ostream&, const Foo&)
4213481Sgiacomo.travaglini@arm.com// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
4313481Sgiacomo.travaglini@arm.com// defines Foo.
4413481Sgiacomo.travaglini@arm.com
4513481Sgiacomo.travaglini@arm.com#include "gtest/gtest-printers.h"
4613481Sgiacomo.travaglini@arm.com#include <ctype.h>
4713481Sgiacomo.travaglini@arm.com#include <stdio.h>
4813481Sgiacomo.travaglini@arm.com#include <cwchar>
4913481Sgiacomo.travaglini@arm.com#include <ostream>  // NOLINT
5013481Sgiacomo.travaglini@arm.com#include <string>
5113481Sgiacomo.travaglini@arm.com#include "gtest/internal/gtest-port.h"
5213481Sgiacomo.travaglini@arm.com
5313481Sgiacomo.travaglini@arm.comnamespace testing {
5413481Sgiacomo.travaglini@arm.com
5513481Sgiacomo.travaglini@arm.comnamespace {
5613481Sgiacomo.travaglini@arm.com
5713481Sgiacomo.travaglini@arm.comusing ::std::ostream;
5813481Sgiacomo.travaglini@arm.com
5913481Sgiacomo.travaglini@arm.com// Prints a segment of bytes in the given object.
6013481Sgiacomo.travaglini@arm.comGTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
6113481Sgiacomo.travaglini@arm.comGTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
6213481Sgiacomo.travaglini@arm.comGTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
6313481Sgiacomo.travaglini@arm.comvoid PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
6413481Sgiacomo.travaglini@arm.com                                size_t count, ostream* os) {
6513481Sgiacomo.travaglini@arm.com  char text[5] = "";
6613481Sgiacomo.travaglini@arm.com  for (size_t i = 0; i != count; i++) {
6713481Sgiacomo.travaglini@arm.com    const size_t j = start + i;
6813481Sgiacomo.travaglini@arm.com    if (i != 0) {
6913481Sgiacomo.travaglini@arm.com      // Organizes the bytes into groups of 2 for easy parsing by
7013481Sgiacomo.travaglini@arm.com      // human.
7113481Sgiacomo.travaglini@arm.com      if ((j % 2) == 0)
7213481Sgiacomo.travaglini@arm.com        *os << ' ';
7313481Sgiacomo.travaglini@arm.com      else
7413481Sgiacomo.travaglini@arm.com        *os << '-';
7513481Sgiacomo.travaglini@arm.com    }
7613481Sgiacomo.travaglini@arm.com    GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
7713481Sgiacomo.travaglini@arm.com    *os << text;
7813481Sgiacomo.travaglini@arm.com  }
7913481Sgiacomo.travaglini@arm.com}
8013481Sgiacomo.travaglini@arm.com
8113481Sgiacomo.travaglini@arm.com// Prints the bytes in the given value to the given ostream.
8213481Sgiacomo.travaglini@arm.comvoid PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
8313481Sgiacomo.travaglini@arm.com                              ostream* os) {
8413481Sgiacomo.travaglini@arm.com  // Tells the user how big the object is.
8513481Sgiacomo.travaglini@arm.com  *os << count << "-byte object <";
8613481Sgiacomo.travaglini@arm.com
8713481Sgiacomo.travaglini@arm.com  const size_t kThreshold = 132;
8813481Sgiacomo.travaglini@arm.com  const size_t kChunkSize = 64;
8913481Sgiacomo.travaglini@arm.com  // If the object size is bigger than kThreshold, we'll have to omit
9013481Sgiacomo.travaglini@arm.com  // some details by printing only the first and the last kChunkSize
9113481Sgiacomo.travaglini@arm.com  // bytes.
9213481Sgiacomo.travaglini@arm.com  // TODO(wan): let the user control the threshold using a flag.
9313481Sgiacomo.travaglini@arm.com  if (count < kThreshold) {
9413481Sgiacomo.travaglini@arm.com    PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
9513481Sgiacomo.travaglini@arm.com  } else {
9613481Sgiacomo.travaglini@arm.com    PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os);
9713481Sgiacomo.travaglini@arm.com    *os << " ... ";
9813481Sgiacomo.travaglini@arm.com    // Rounds up to 2-byte boundary.
9913481Sgiacomo.travaglini@arm.com    const size_t resume_pos = (count - kChunkSize + 1)/2*2;
10013481Sgiacomo.travaglini@arm.com    PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os);
10113481Sgiacomo.travaglini@arm.com  }
10213481Sgiacomo.travaglini@arm.com  *os << ">";
10313481Sgiacomo.travaglini@arm.com}
10413481Sgiacomo.travaglini@arm.com
10513481Sgiacomo.travaglini@arm.com}  // namespace
10613481Sgiacomo.travaglini@arm.com
10713481Sgiacomo.travaglini@arm.comnamespace internal2 {
10813481Sgiacomo.travaglini@arm.com
10913481Sgiacomo.travaglini@arm.com// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
11013481Sgiacomo.travaglini@arm.com// given object.  The delegation simplifies the implementation, which
11113481Sgiacomo.travaglini@arm.com// uses the << operator and thus is easier done outside of the
11213481Sgiacomo.travaglini@arm.com// ::testing::internal namespace, which contains a << operator that
11313481Sgiacomo.travaglini@arm.com// sometimes conflicts with the one in STL.
11413481Sgiacomo.travaglini@arm.comvoid PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
11513481Sgiacomo.travaglini@arm.com                          ostream* os) {
11613481Sgiacomo.travaglini@arm.com  PrintBytesInObjectToImpl(obj_bytes, count, os);
11713481Sgiacomo.travaglini@arm.com}
11813481Sgiacomo.travaglini@arm.com
11913481Sgiacomo.travaglini@arm.com}  // namespace internal2
12013481Sgiacomo.travaglini@arm.com
12113481Sgiacomo.travaglini@arm.comnamespace internal {
12213481Sgiacomo.travaglini@arm.com
12313481Sgiacomo.travaglini@arm.com// Depending on the value of a char (or wchar_t), we print it in one
12413481Sgiacomo.travaglini@arm.com// of three formats:
12513481Sgiacomo.travaglini@arm.com//   - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
12613481Sgiacomo.travaglini@arm.com//   - as a hexidecimal escape sequence (e.g. '\x7F'), or
12713481Sgiacomo.travaglini@arm.com//   - as a special escape sequence (e.g. '\r', '\n').
12813481Sgiacomo.travaglini@arm.comenum CharFormat {
12913481Sgiacomo.travaglini@arm.com  kAsIs,
13013481Sgiacomo.travaglini@arm.com  kHexEscape,
13113481Sgiacomo.travaglini@arm.com  kSpecialEscape
13213481Sgiacomo.travaglini@arm.com};
13313481Sgiacomo.travaglini@arm.com
13413481Sgiacomo.travaglini@arm.com// Returns true if c is a printable ASCII character.  We test the
13513481Sgiacomo.travaglini@arm.com// value of c directly instead of calling isprint(), which is buggy on
13613481Sgiacomo.travaglini@arm.com// Windows Mobile.
13713481Sgiacomo.travaglini@arm.cominline bool IsPrintableAscii(wchar_t c) {
13813481Sgiacomo.travaglini@arm.com  return 0x20 <= c && c <= 0x7E;
13913481Sgiacomo.travaglini@arm.com}
14013481Sgiacomo.travaglini@arm.com
14113481Sgiacomo.travaglini@arm.com// Prints a wide or narrow char c as a character literal without the
14213481Sgiacomo.travaglini@arm.com// quotes, escaping it when necessary; returns how c was formatted.
14313481Sgiacomo.travaglini@arm.com// The template argument UnsignedChar is the unsigned version of Char,
14413481Sgiacomo.travaglini@arm.com// which is the type of c.
14513481Sgiacomo.travaglini@arm.comtemplate <typename UnsignedChar, typename Char>
14613481Sgiacomo.travaglini@arm.comstatic CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
14713481Sgiacomo.travaglini@arm.com  switch (static_cast<wchar_t>(c)) {
14813481Sgiacomo.travaglini@arm.com    case L'\0':
14913481Sgiacomo.travaglini@arm.com      *os << "\\0";
15013481Sgiacomo.travaglini@arm.com      break;
15113481Sgiacomo.travaglini@arm.com    case L'\'':
15213481Sgiacomo.travaglini@arm.com      *os << "\\'";
15313481Sgiacomo.travaglini@arm.com      break;
15413481Sgiacomo.travaglini@arm.com    case L'\\':
15513481Sgiacomo.travaglini@arm.com      *os << "\\\\";
15613481Sgiacomo.travaglini@arm.com      break;
15713481Sgiacomo.travaglini@arm.com    case L'\a':
15813481Sgiacomo.travaglini@arm.com      *os << "\\a";
15913481Sgiacomo.travaglini@arm.com      break;
16013481Sgiacomo.travaglini@arm.com    case L'\b':
16113481Sgiacomo.travaglini@arm.com      *os << "\\b";
16213481Sgiacomo.travaglini@arm.com      break;
16313481Sgiacomo.travaglini@arm.com    case L'\f':
16413481Sgiacomo.travaglini@arm.com      *os << "\\f";
16513481Sgiacomo.travaglini@arm.com      break;
16613481Sgiacomo.travaglini@arm.com    case L'\n':
16713481Sgiacomo.travaglini@arm.com      *os << "\\n";
16813481Sgiacomo.travaglini@arm.com      break;
16913481Sgiacomo.travaglini@arm.com    case L'\r':
17013481Sgiacomo.travaglini@arm.com      *os << "\\r";
17113481Sgiacomo.travaglini@arm.com      break;
17213481Sgiacomo.travaglini@arm.com    case L'\t':
17313481Sgiacomo.travaglini@arm.com      *os << "\\t";
17413481Sgiacomo.travaglini@arm.com      break;
17513481Sgiacomo.travaglini@arm.com    case L'\v':
17613481Sgiacomo.travaglini@arm.com      *os << "\\v";
17713481Sgiacomo.travaglini@arm.com      break;
17813481Sgiacomo.travaglini@arm.com    default:
17913481Sgiacomo.travaglini@arm.com      if (IsPrintableAscii(c)) {
18013481Sgiacomo.travaglini@arm.com        *os << static_cast<char>(c);
18113481Sgiacomo.travaglini@arm.com        return kAsIs;
18213481Sgiacomo.travaglini@arm.com      } else {
18313481Sgiacomo.travaglini@arm.com        *os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
18413481Sgiacomo.travaglini@arm.com        return kHexEscape;
18513481Sgiacomo.travaglini@arm.com      }
18613481Sgiacomo.travaglini@arm.com  }
18713481Sgiacomo.travaglini@arm.com  return kSpecialEscape;
18813481Sgiacomo.travaglini@arm.com}
18913481Sgiacomo.travaglini@arm.com
19013481Sgiacomo.travaglini@arm.com// Prints a wchar_t c as if it's part of a string literal, escaping it when
19113481Sgiacomo.travaglini@arm.com// necessary; returns how c was formatted.
19213481Sgiacomo.travaglini@arm.comstatic CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
19313481Sgiacomo.travaglini@arm.com  switch (c) {
19413481Sgiacomo.travaglini@arm.com    case L'\'':
19513481Sgiacomo.travaglini@arm.com      *os << "'";
19613481Sgiacomo.travaglini@arm.com      return kAsIs;
19713481Sgiacomo.travaglini@arm.com    case L'"':
19813481Sgiacomo.travaglini@arm.com      *os << "\\\"";
19913481Sgiacomo.travaglini@arm.com      return kSpecialEscape;
20013481Sgiacomo.travaglini@arm.com    default:
20113481Sgiacomo.travaglini@arm.com      return PrintAsCharLiteralTo<wchar_t>(c, os);
20213481Sgiacomo.travaglini@arm.com  }
20313481Sgiacomo.travaglini@arm.com}
20413481Sgiacomo.travaglini@arm.com
20513481Sgiacomo.travaglini@arm.com// Prints a char c as if it's part of a string literal, escaping it when
20613481Sgiacomo.travaglini@arm.com// necessary; returns how c was formatted.
20713481Sgiacomo.travaglini@arm.comstatic CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
20813481Sgiacomo.travaglini@arm.com  return PrintAsStringLiteralTo(
20913481Sgiacomo.travaglini@arm.com      static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
21013481Sgiacomo.travaglini@arm.com}
21113481Sgiacomo.travaglini@arm.com
21213481Sgiacomo.travaglini@arm.com// Prints a wide or narrow character c and its code.  '\0' is printed
21313481Sgiacomo.travaglini@arm.com// as "'\\0'", other unprintable characters are also properly escaped
21413481Sgiacomo.travaglini@arm.com// using the standard C++ escape sequence.  The template argument
21513481Sgiacomo.travaglini@arm.com// UnsignedChar is the unsigned version of Char, which is the type of c.
21613481Sgiacomo.travaglini@arm.comtemplate <typename UnsignedChar, typename Char>
21713481Sgiacomo.travaglini@arm.comvoid PrintCharAndCodeTo(Char c, ostream* os) {
21813481Sgiacomo.travaglini@arm.com  // First, print c as a literal in the most readable form we can find.
21913481Sgiacomo.travaglini@arm.com  *os << ((sizeof(c) > 1) ? "L'" : "'");
22013481Sgiacomo.travaglini@arm.com  const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
22113481Sgiacomo.travaglini@arm.com  *os << "'";
22213481Sgiacomo.travaglini@arm.com
22313481Sgiacomo.travaglini@arm.com  // To aid user debugging, we also print c's code in decimal, unless
22413481Sgiacomo.travaglini@arm.com  // it's 0 (in which case c was printed as '\\0', making the code
22513481Sgiacomo.travaglini@arm.com  // obvious).
22613481Sgiacomo.travaglini@arm.com  if (c == 0)
22713481Sgiacomo.travaglini@arm.com    return;
22813481Sgiacomo.travaglini@arm.com  *os << " (" << static_cast<int>(c);
22913481Sgiacomo.travaglini@arm.com
23013481Sgiacomo.travaglini@arm.com  // For more convenience, we print c's code again in hexidecimal,
23113481Sgiacomo.travaglini@arm.com  // unless c was already printed in the form '\x##' or the code is in
23213481Sgiacomo.travaglini@arm.com  // [1, 9].
23313481Sgiacomo.travaglini@arm.com  if (format == kHexEscape || (1 <= c && c <= 9)) {
23413481Sgiacomo.travaglini@arm.com    // Do nothing.
23513481Sgiacomo.travaglini@arm.com  } else {
23613481Sgiacomo.travaglini@arm.com    *os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
23713481Sgiacomo.travaglini@arm.com  }
23813481Sgiacomo.travaglini@arm.com  *os << ")";
23913481Sgiacomo.travaglini@arm.com}
24013481Sgiacomo.travaglini@arm.com
24113481Sgiacomo.travaglini@arm.comvoid PrintTo(unsigned char c, ::std::ostream* os) {
24213481Sgiacomo.travaglini@arm.com  PrintCharAndCodeTo<unsigned char>(c, os);
24313481Sgiacomo.travaglini@arm.com}
24413481Sgiacomo.travaglini@arm.comvoid PrintTo(signed char c, ::std::ostream* os) {
24513481Sgiacomo.travaglini@arm.com  PrintCharAndCodeTo<unsigned char>(c, os);
24613481Sgiacomo.travaglini@arm.com}
24713481Sgiacomo.travaglini@arm.com
24813481Sgiacomo.travaglini@arm.com// Prints a wchar_t as a symbol if it is printable or as its internal
24913481Sgiacomo.travaglini@arm.com// code otherwise and also as its code.  L'\0' is printed as "L'\\0'".
25013481Sgiacomo.travaglini@arm.comvoid PrintTo(wchar_t wc, ostream* os) {
25113481Sgiacomo.travaglini@arm.com  PrintCharAndCodeTo<wchar_t>(wc, os);
25213481Sgiacomo.travaglini@arm.com}
25313481Sgiacomo.travaglini@arm.com
25413481Sgiacomo.travaglini@arm.com// Prints the given array of characters to the ostream.  CharType must be either
25513481Sgiacomo.travaglini@arm.com// char or wchar_t.
25613481Sgiacomo.travaglini@arm.com// The array starts at begin, the length is len, it may include '\0' characters
25713481Sgiacomo.travaglini@arm.com// and may not be NUL-terminated.
25813481Sgiacomo.travaglini@arm.comtemplate <typename CharType>
25913481Sgiacomo.travaglini@arm.comGTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
26013481Sgiacomo.travaglini@arm.comGTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
26113481Sgiacomo.travaglini@arm.comGTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
26213481Sgiacomo.travaglini@arm.comstatic void PrintCharsAsStringTo(
26313481Sgiacomo.travaglini@arm.com    const CharType* begin, size_t len, ostream* os) {
26413481Sgiacomo.travaglini@arm.com  const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
26513481Sgiacomo.travaglini@arm.com  *os << kQuoteBegin;
26613481Sgiacomo.travaglini@arm.com  bool is_previous_hex = false;
26713481Sgiacomo.travaglini@arm.com  for (size_t index = 0; index < len; ++index) {
26813481Sgiacomo.travaglini@arm.com    const CharType cur = begin[index];
26913481Sgiacomo.travaglini@arm.com    if (is_previous_hex && IsXDigit(cur)) {
27013481Sgiacomo.travaglini@arm.com      // Previous character is of '\x..' form and this character can be
27113481Sgiacomo.travaglini@arm.com      // interpreted as another hexadecimal digit in its number. Break string to
27213481Sgiacomo.travaglini@arm.com      // disambiguate.
27313481Sgiacomo.travaglini@arm.com      *os << "\" " << kQuoteBegin;
27413481Sgiacomo.travaglini@arm.com    }
27513481Sgiacomo.travaglini@arm.com    is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
27613481Sgiacomo.travaglini@arm.com  }
27713481Sgiacomo.travaglini@arm.com  *os << "\"";
27813481Sgiacomo.travaglini@arm.com}
27913481Sgiacomo.travaglini@arm.com
28013481Sgiacomo.travaglini@arm.com// Prints a (const) char/wchar_t array of 'len' elements, starting at address
28113481Sgiacomo.travaglini@arm.com// 'begin'.  CharType must be either char or wchar_t.
28213481Sgiacomo.travaglini@arm.comtemplate <typename CharType>
28313481Sgiacomo.travaglini@arm.comGTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
28413481Sgiacomo.travaglini@arm.comGTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
28513481Sgiacomo.travaglini@arm.comGTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
28613481Sgiacomo.travaglini@arm.comstatic void UniversalPrintCharArray(
28713481Sgiacomo.travaglini@arm.com    const CharType* begin, size_t len, ostream* os) {
28813481Sgiacomo.travaglini@arm.com  // The code
28913481Sgiacomo.travaglini@arm.com  //   const char kFoo[] = "foo";
29013481Sgiacomo.travaglini@arm.com  // generates an array of 4, not 3, elements, with the last one being '\0'.
29113481Sgiacomo.travaglini@arm.com  //
29213481Sgiacomo.travaglini@arm.com  // Therefore when printing a char array, we don't print the last element if
29313481Sgiacomo.travaglini@arm.com  // it's '\0', such that the output matches the string literal as it's
29413481Sgiacomo.travaglini@arm.com  // written in the source code.
29513481Sgiacomo.travaglini@arm.com  if (len > 0 && begin[len - 1] == '\0') {
29613481Sgiacomo.travaglini@arm.com    PrintCharsAsStringTo(begin, len - 1, os);
29713481Sgiacomo.travaglini@arm.com    return;
29813481Sgiacomo.travaglini@arm.com  }
29913481Sgiacomo.travaglini@arm.com
30013481Sgiacomo.travaglini@arm.com  // If, however, the last element in the array is not '\0', e.g.
30113481Sgiacomo.travaglini@arm.com  //    const char kFoo[] = { 'f', 'o', 'o' };
30213481Sgiacomo.travaglini@arm.com  // we must print the entire array.  We also print a message to indicate
30313481Sgiacomo.travaglini@arm.com  // that the array is not NUL-terminated.
30413481Sgiacomo.travaglini@arm.com  PrintCharsAsStringTo(begin, len, os);
30513481Sgiacomo.travaglini@arm.com  *os << " (no terminating NUL)";
30613481Sgiacomo.travaglini@arm.com}
30713481Sgiacomo.travaglini@arm.com
30813481Sgiacomo.travaglini@arm.com// Prints a (const) char array of 'len' elements, starting at address 'begin'.
30913481Sgiacomo.travaglini@arm.comvoid UniversalPrintArray(const char* begin, size_t len, ostream* os) {
31013481Sgiacomo.travaglini@arm.com  UniversalPrintCharArray(begin, len, os);
31113481Sgiacomo.travaglini@arm.com}
31213481Sgiacomo.travaglini@arm.com
31313481Sgiacomo.travaglini@arm.com// Prints a (const) wchar_t array of 'len' elements, starting at address
31413481Sgiacomo.travaglini@arm.com// 'begin'.
31513481Sgiacomo.travaglini@arm.comvoid UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
31613481Sgiacomo.travaglini@arm.com  UniversalPrintCharArray(begin, len, os);
31713481Sgiacomo.travaglini@arm.com}
31813481Sgiacomo.travaglini@arm.com
31913481Sgiacomo.travaglini@arm.com// Prints the given C string to the ostream.
32013481Sgiacomo.travaglini@arm.comvoid PrintTo(const char* s, ostream* os) {
32113481Sgiacomo.travaglini@arm.com  if (s == NULL) {
32213481Sgiacomo.travaglini@arm.com    *os << "NULL";
32313481Sgiacomo.travaglini@arm.com  } else {
32413481Sgiacomo.travaglini@arm.com    *os << ImplicitCast_<const void*>(s) << " pointing to ";
32513481Sgiacomo.travaglini@arm.com    PrintCharsAsStringTo(s, strlen(s), os);
32613481Sgiacomo.travaglini@arm.com  }
32713481Sgiacomo.travaglini@arm.com}
32813481Sgiacomo.travaglini@arm.com
32913481Sgiacomo.travaglini@arm.com// MSVC compiler can be configured to define whar_t as a typedef
33013481Sgiacomo.travaglini@arm.com// of unsigned short. Defining an overload for const wchar_t* in that case
33113481Sgiacomo.travaglini@arm.com// would cause pointers to unsigned shorts be printed as wide strings,
33213481Sgiacomo.travaglini@arm.com// possibly accessing more memory than intended and causing invalid
33313481Sgiacomo.travaglini@arm.com// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
33413481Sgiacomo.travaglini@arm.com// wchar_t is implemented as a native type.
33513481Sgiacomo.travaglini@arm.com#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
33613481Sgiacomo.travaglini@arm.com// Prints the given wide C string to the ostream.
33713481Sgiacomo.travaglini@arm.comvoid PrintTo(const wchar_t* s, ostream* os) {
33813481Sgiacomo.travaglini@arm.com  if (s == NULL) {
33913481Sgiacomo.travaglini@arm.com    *os << "NULL";
34013481Sgiacomo.travaglini@arm.com  } else {
34113481Sgiacomo.travaglini@arm.com    *os << ImplicitCast_<const void*>(s) << " pointing to ";
34213481Sgiacomo.travaglini@arm.com    PrintCharsAsStringTo(s, std::wcslen(s), os);
34313481Sgiacomo.travaglini@arm.com  }
34413481Sgiacomo.travaglini@arm.com}
34513481Sgiacomo.travaglini@arm.com#endif  // wchar_t is native
34613481Sgiacomo.travaglini@arm.com
34713481Sgiacomo.travaglini@arm.com// Prints a ::string object.
34813481Sgiacomo.travaglini@arm.com#if GTEST_HAS_GLOBAL_STRING
34913481Sgiacomo.travaglini@arm.comvoid PrintStringTo(const ::string& s, ostream* os) {
35013481Sgiacomo.travaglini@arm.com  PrintCharsAsStringTo(s.data(), s.size(), os);
35113481Sgiacomo.travaglini@arm.com}
35213481Sgiacomo.travaglini@arm.com#endif  // GTEST_HAS_GLOBAL_STRING
35313481Sgiacomo.travaglini@arm.com
35413481Sgiacomo.travaglini@arm.comvoid PrintStringTo(const ::std::string& s, ostream* os) {
35513481Sgiacomo.travaglini@arm.com  PrintCharsAsStringTo(s.data(), s.size(), os);
35613481Sgiacomo.travaglini@arm.com}
35713481Sgiacomo.travaglini@arm.com
35813481Sgiacomo.travaglini@arm.com// Prints a ::wstring object.
35913481Sgiacomo.travaglini@arm.com#if GTEST_HAS_GLOBAL_WSTRING
36013481Sgiacomo.travaglini@arm.comvoid PrintWideStringTo(const ::wstring& s, ostream* os) {
36113481Sgiacomo.travaglini@arm.com  PrintCharsAsStringTo(s.data(), s.size(), os);
36213481Sgiacomo.travaglini@arm.com}
36313481Sgiacomo.travaglini@arm.com#endif  // GTEST_HAS_GLOBAL_WSTRING
36413481Sgiacomo.travaglini@arm.com
36513481Sgiacomo.travaglini@arm.com#if GTEST_HAS_STD_WSTRING
36613481Sgiacomo.travaglini@arm.comvoid PrintWideStringTo(const ::std::wstring& s, ostream* os) {
36713481Sgiacomo.travaglini@arm.com  PrintCharsAsStringTo(s.data(), s.size(), os);
36813481Sgiacomo.travaglini@arm.com}
36913481Sgiacomo.travaglini@arm.com#endif  // GTEST_HAS_STD_WSTRING
37013481Sgiacomo.travaglini@arm.com
37113481Sgiacomo.travaglini@arm.com}  // namespace internal
37213481Sgiacomo.travaglini@arm.com
37313481Sgiacomo.travaglini@arm.com}  // namespace testing
374