+ doPrint(kColorMap[color]);
+}
+
+void SymbolizePrinter::println(uintptr_t address,
+ const SymbolizedFrame& frame) {
+ print(address, frame);
+ doPrint("\n");
+}
+
+void SymbolizePrinter::printTerse(uintptr_t address,
+ const SymbolizedFrame& frame) {
+ if (frame.found && frame.name && frame.name[0] != '\0') {
+ char demangledBuf[2048] = {0};
+ demangle(frame.name, demangledBuf, sizeof(demangledBuf));
+ doPrint(demangledBuf[0] == '\0' ? frame.name : demangledBuf);
+ } else {
+ // Can't use sprintf, not async-signal-safe
+ static_assert(sizeof(uintptr_t) <= 8, "huge uintptr_t?");
+ char buf[] = "0x0000000000000000";
+ char* end = buf + sizeof(buf) - 1 - (16 - 2 * sizeof(uintptr_t));
+ char* p = end;
+ *p-- = '\0';
+ while (address != 0) {
+ *p-- = kHexChars[address & 0xf];
+ address >>= 4;
+ }
+ doPrint(StringPiece(buf, end));
+ }
+}
+
+void SymbolizePrinter::println(const uintptr_t* addresses,
+ const SymbolizedFrame* frames,
+ size_t frameCount) {
+ for (size_t i = 0; i < frameCount; ++i) {
+ println(addresses[i], frames[i]);
+ }
+}
+
+namespace {
+
+int getFD(const std::ios& stream) {
+#ifdef __GNUC__
+ std::streambuf* buf = stream.rdbuf();
+ using namespace __gnu_cxx;
+
+ {
+ auto sbuf = dynamic_cast<stdio_sync_filebuf<char>*>(buf);
+ if (sbuf) {
+ return fileno(sbuf->file());
+ }
+ }
+ {
+ auto sbuf = dynamic_cast<stdio_filebuf<char>*>(buf);
+ if (sbuf) {
+ return sbuf->fd();
+ }
+ }
+#endif // __GNUC__
+ return -1;
+}
+
+bool isColorfulTty(int options, int fd) {
+ if ((options & SymbolizePrinter::TERSE) != 0 ||
+ (options & SymbolizePrinter::COLOR_IF_TTY) == 0 ||
+ fd < 0 || !::isatty(fd)) {
+ return false;
+ }
+ auto term = ::getenv("TERM");
+ return !(term == nullptr || term[0] == '\0' || strcmp(term, "dumb") == 0);
+}
+
+} // anonymous namespace
+
+OStreamSymbolizePrinter::OStreamSymbolizePrinter(std::ostream& out, int options)
+ : SymbolizePrinter(options, isColorfulTty(options, getFD(out))),
+ out_(out) {